blob: 6e22d6903083402d92fdf356f2e747afe83baad7 [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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"
44#include "MagickCore/blob.h"
45#include "MagickCore/cache.h"
cristy52010022011-10-21 18:07:37 +000046#include "MagickCore/cache-private.h"
cristy4c08aed2011-07-01 19:47:50 +000047#include "MagickCore/client.h"
48#include "MagickCore/color.h"
49#include "MagickCore/colorspace.h"
50#include "MagickCore/composite.h"
51#include "MagickCore/constitute.h"
52#include "MagickCore/decorate.h"
53#include "MagickCore/delegate.h"
54#include "MagickCore/display.h"
55#include "MagickCore/display-private.h"
cristyc53413d2011-11-17 13:04:26 +000056#include "MagickCore/distort.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/draw.h"
58#include "MagickCore/effect.h"
59#include "MagickCore/enhance.h"
60#include "MagickCore/exception.h"
61#include "MagickCore/exception-private.h"
62#include "MagickCore/fx.h"
63#include "MagickCore/geometry.h"
64#include "MagickCore/image.h"
65#include "MagickCore/image-private.h"
66#include "MagickCore/list.h"
67#include "MagickCore/log.h"
68#include "MagickCore/magick.h"
69#include "MagickCore/memory_.h"
70#include "MagickCore/monitor.h"
71#include "MagickCore/monitor-private.h"
72#include "MagickCore/montage.h"
73#include "MagickCore/option.h"
74#include "MagickCore/paint.h"
75#include "MagickCore/pixel.h"
76#include "MagickCore/pixel-accessor.h"
77#include "MagickCore/PreRvIcccm.h"
78#include "MagickCore/property.h"
79#include "MagickCore/quantum.h"
80#include "MagickCore/quantum-private.h"
81#include "MagickCore/resize.h"
82#include "MagickCore/resource_.h"
83#include "MagickCore/shear.h"
84#include "MagickCore/segment.h"
cristy7497f482011-12-08 01:57:31 +000085#include "MagickCore/statistic.h"
cristy4c08aed2011-07-01 19:47:50 +000086#include "MagickCore/string_.h"
87#include "MagickCore/string-private.h"
88#include "MagickCore/transform.h"
89#include "MagickCore/threshold.h"
90#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000091#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000092#include "MagickCore/version.h"
93#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000094#include "MagickCore/widget-private.h"
95#include "MagickCore/xwindow.h"
cristy4c08aed2011-07-01 19:47:50 +000096#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000097
98#if defined(MAGICKCORE_X11_DELEGATE)
99/*
100 Define declarations.
101*/
cristy49e2d862010-11-12 02:50:30 +0000102#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
cristy3ed852e2009-09-05 21:47:34 +0000103
104/*
105 Constant declarations.
106*/
107static const unsigned char
108 HighlightBitmap[8] =
109 {
110 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
111 },
cristydd05beb2010-11-21 21:23:39 +0000112 OpaqueBitmap[8] =
113 {
114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
115 },
cristy3ed852e2009-09-05 21:47:34 +0000116 ShadowBitmap[8] =
117 {
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
119 };
120
121static const char
122 *PageSizes[] =
123 {
124 "Letter",
125 "Tabloid",
126 "Ledger",
127 "Legal",
128 "Statement",
129 "Executive",
130 "A3",
131 "A4",
132 "A5",
133 "B4",
134 "B5",
135 "Folio",
136 "Quarto",
137 "10x14",
138 (char *) NULL
139 };
140
141/*
142 Help widget declarations.
143*/
144static const char
145 *ImageAnnotateHelp[] =
146 {
147 "In annotate mode, the Command widget has these options:",
148 "",
149 " Font Name",
150 " fixed",
151 " variable",
152 " 5x8",
153 " 6x10",
154 " 7x13bold",
155 " 8x13bold",
156 " 9x15bold",
157 " 10x20",
158 " 12x24",
159 " Browser...",
160 " Font Color",
161 " black",
162 " blue",
163 " cyan",
164 " green",
165 " gray",
166 " red",
167 " magenta",
168 " yellow",
169 " white",
170 " transparent",
171 " Browser...",
172 " Font Color",
173 " black",
174 " blue",
175 " cyan",
176 " green",
177 " gray",
178 " red",
179 " magenta",
180 " yellow",
181 " white",
182 " transparent",
183 " Browser...",
184 " Rotate Text",
185 " -90",
186 " -45",
187 " -30",
188 " 0",
189 " 30",
190 " 45",
191 " 90",
192 " 180",
193 " Dialog...",
194 " Help",
195 " Dismiss",
196 "",
197 "Choose a font name from the Font Name sub-menu. Additional",
198 "font names can be specified with the font browser. You can",
199 "change the menu names by setting the X resources font1",
200 "through font9.",
201 "",
202 "Choose a font color from the Font Color sub-menu.",
203 "Additional font colors can be specified with the color",
204 "browser. You can change the menu colors by setting the X",
205 "resources pen1 through pen9.",
206 "",
207 "If you select the color browser and press Grab, you can",
208 "choose the font color by moving the pointer to the desired",
209 "color on the screen and press any button.",
210 "",
211 "If you choose to rotate the text, choose Rotate Text from the",
212 "menu and select an angle. Typically you will only want to",
213 "rotate one line of text at a time. Depending on the angle you",
214 "choose, subsequent lines may end up overwriting each other.",
215 "",
216 "Choosing a font and its color is optional. The default font",
217 "is fixed and the default color is black. However, you must",
218 "choose a location to begin entering text and press button 1.",
219 "An underscore character will appear at the location of the",
220 "pointer. The cursor changes to a pencil to indicate you are",
221 "in text mode. To exit immediately, press Dismiss.",
222 "",
223 "In text mode, any key presses will display the character at",
224 "the location of the underscore and advance the underscore",
225 "cursor. Enter your text and once completed press Apply to",
226 "finish your image annotation. To correct errors press BACK",
227 "SPACE. To delete an entire line of text, press DELETE. Any",
228 "text that exceeds the boundaries of the image window is",
229 "automagically continued onto the next line.",
230 "",
231 "The actual color you request for the font is saved in the",
232 "image. However, the color that appears in your image window",
233 "may be different. For example, on a monochrome screen the",
234 "text will appear black or white even if you choose the color",
235 "red as the font color. However, the image saved to a file",
236 "with -write is written with red lettering. To assure the",
237 "correct color text in the final image, any PseudoClass image",
238 "is promoted to DirectClass (see miff(5)). To force a",
239 "PseudoClass image to remain PseudoClass, use -colors.",
240 (char *) NULL,
241 },
242 *ImageChopHelp[] =
243 {
244 "In chop mode, the Command widget has these options:",
245 "",
246 " Direction",
247 " horizontal",
248 " vertical",
249 " Help",
250 " Dismiss",
251 "",
252 "If the you choose the horizontal direction (this the",
253 "default), the area of the image between the two horizontal",
254 "endpoints of the chop line is removed. Otherwise, the area",
255 "of the image between the two vertical endpoints of the chop",
256 "line is removed.",
257 "",
258 "Select a location within the image window to begin your chop,",
259 "press and hold any button. Next, move the pointer to",
260 "another location in the image. As you move a line will",
261 "connect the initial location and the pointer. When you",
262 "release the button, the area within the image to chop is",
263 "determined by which direction you choose from the Command",
264 "widget.",
265 "",
266 "To cancel the image chopping, move the pointer back to the",
267 "starting point of the line and release the button.",
268 (char *) NULL,
269 },
270 *ImageColorEditHelp[] =
271 {
272 "In color edit mode, the Command widget has these options:",
273 "",
274 " Method",
275 " point",
276 " replace",
277 " floodfill",
278 " filltoborder",
279 " reset",
280 " Pixel Color",
281 " black",
282 " blue",
283 " cyan",
284 " green",
285 " gray",
286 " red",
287 " magenta",
288 " yellow",
289 " white",
290 " Browser...",
291 " Border Color",
292 " black",
293 " blue",
294 " cyan",
295 " green",
296 " gray",
297 " red",
298 " magenta",
299 " yellow",
300 " white",
301 " Browser...",
302 " Fuzz",
303 " 0%",
304 " 2%",
305 " 5%",
306 " 10%",
307 " 15%",
308 " Dialog...",
309 " Undo",
310 " Help",
311 " Dismiss",
312 "",
313 "Choose a color editing method from the Method sub-menu",
314 "of the Command widget. The point method recolors any pixel",
315 "selected with the pointer until the button is released. The",
316 "replace method recolors any pixel that matches the color of",
317 "the pixel you select with a button press. Floodfill recolors",
318 "any pixel that matches the color of the pixel you select with",
319 "a button press and is a neighbor. Whereas filltoborder recolors",
320 "any neighbor pixel that is not the border color. Finally reset",
321 "changes the entire image to the designated color.",
322 "",
323 "Next, choose a pixel color from the Pixel Color sub-menu.",
324 "Additional pixel colors can be specified with the color",
325 "browser. You can change the menu colors by setting the X",
326 "resources pen1 through pen9.",
327 "",
328 "Now press button 1 to select a pixel within the image window",
329 "to change its color. Additional pixels may be recolored as",
330 "prescribed by the method you choose.",
331 "",
332 "If the Magnify widget is mapped, it can be helpful in positioning",
333 "your pointer within the image (refer to button 2).",
334 "",
335 "The actual color you request for the pixels is saved in the",
336 "image. However, the color that appears in your image window",
337 "may be different. For example, on a monochrome screen the",
338 "pixel will appear black or white even if you choose the",
339 "color red as the pixel color. However, the image saved to a",
340 "file with -write is written with red pixels. To assure the",
341 "correct color text in the final image, any PseudoClass image",
342 "is promoted to DirectClass (see miff(5)). To force a",
343 "PseudoClass image to remain PseudoClass, use -colors.",
344 (char *) NULL,
345 },
346 *ImageCompositeHelp[] =
347 {
348 "First a widget window is displayed requesting you to enter an",
349 "image name. Press Composite, Grab or type a file name.",
350 "Press Cancel if you choose not to create a composite image.",
351 "When you choose Grab, move the pointer to the desired window",
352 "and press any button.",
353 "",
354 "If the Composite image does not have any matte information,",
355 "you are informed and the file browser is displayed again.",
356 "Enter the name of a mask image. The image is typically",
357 "grayscale and the same size as the composite image. If the",
358 "image is not grayscale, it is converted to grayscale and the",
359 "resulting intensities are used as matte information.",
360 "",
361 "A small window appears showing the location of the cursor in",
362 "the image window. You are now in composite mode. To exit",
363 "immediately, press Dismiss. In composite mode, the Command",
364 "widget has these options:",
365 "",
366 " Operators",
367 " Over",
368 " In",
369 " Out",
370 " Atop",
371 " Xor",
372 " Plus",
373 " Minus",
374 " Add",
375 " Subtract",
376 " Difference",
377 " Multiply",
378 " Bumpmap",
379 " Copy",
380 " CopyRed",
381 " CopyGreen",
382 " CopyBlue",
383 " CopyOpacity",
384 " Clear",
385 " Dissolve",
386 " Displace",
387 " Help",
388 " Dismiss",
389 "",
390 "Choose a composite operation from the Operators sub-menu of",
391 "the Command widget. How each operator behaves is described",
392 "below. Image window is the image currently displayed on",
393 "your X server and image is the image obtained with the File",
394 "Browser widget.",
395 "",
396 "Over The result is the union of the two image shapes,",
397 " with image obscuring image window in the region of",
398 " overlap.",
399 "",
400 "In The result is simply image cut by the shape of",
401 " image window. None of the image data of image",
402 " window is in the result.",
403 "",
404 "Out The resulting image is image with the shape of",
405 " image window cut out.",
406 "",
407 "Atop The result is the same shape as image image window,",
408 " with image obscuring image window where the image",
409 " shapes overlap. Note this differs from over",
410 " because the portion of image outside image window's",
411 " shape does not appear in the result.",
412 "",
413 "Xor The result is the image data from both image and",
414 " image window that is outside the overlap region.",
415 " The overlap region is blank.",
416 "",
417 "Plus The result is just the sum of the image data.",
418 " Output values are cropped to QuantumRange (no overflow).",
419 "",
420 "Minus The result of image - image window, with underflow",
421 " cropped to zero.",
422 "",
423 "Add The result of image + image window, with overflow",
424 " wrapping around (mod 256).",
425 "",
426 "Subtract The result of image - image window, with underflow",
427 " wrapping around (mod 256). The add and subtract",
428 " operators can be used to perform reversible",
429 " transformations.",
430 "",
431 "Difference",
432 " The result of abs(image - image window). This",
433 " useful for comparing two very similar images.",
434 "",
435 "Multiply",
436 " The result of image * image window. This",
437 " useful for the creation of drop-shadows.",
438 "",
439 "Bumpmap The result of surface normals from image * image",
440 " window.",
441 "",
442 "Copy The resulting image is image window replaced with",
443 " image. Here the matte information is ignored.",
444 "",
445 "CopyRed The red layer of the image window is replace with",
446 " the red layer of the image. The other layers are",
447 " untouched.",
448 "",
449 "CopyGreen",
450 " The green layer of the image window is replace with",
451 " the green layer of the image. The other layers are",
452 " untouched.",
453 "",
454 "CopyBlue The blue layer of the image window is replace with",
455 " the blue layer of the image. The other layers are",
456 " untouched.",
457 "",
458 "CopyOpacity",
459 " The matte layer of the image window is replace with",
460 " the matte layer of the image. The other layers are",
461 " untouched.",
462 "",
463 "The image compositor requires a matte, or alpha channel in",
464 "the image for some operations. This extra channel usually",
465 "defines a mask which represents a sort of a cookie-cutter",
466 "for the image. This the case when matte is opaque (full",
467 "coverage) for pixels inside the shape, zero outside, and",
468 "between 0 and QuantumRange on the boundary. If image does not",
469 "have a matte channel, it is initialized with 0 for any pixel",
470 "matching in color to pixel location (0,0), otherwise QuantumRange.",
471 "",
472 "If you choose Dissolve, the composite operator becomes Over. The",
473 "image matte channel percent transparency is initialized to factor.",
474 "The image window is initialized to (100-factor). Where factor is the",
475 "value you specify in the Dialog widget.",
476 "",
477 "Displace shifts the image pixels as defined by a displacement",
478 "map. With this option, image is used as a displacement map.",
479 "Black, within the displacement map, is a maximum positive",
480 "displacement. White is a maximum negative displacement and",
481 "middle gray is neutral. The displacement is scaled to determine",
482 "the pixel shift. By default, the displacement applies in both the",
483 "horizontal and vertical directions. However, if you specify a mask,",
484 "image is the horizontal X displacement and mask the vertical Y",
485 "displacement.",
486 "",
487 "Note that matte information for image window is not retained",
488 "for colormapped X server visuals (e.g. StaticColor,",
489 "StaticColor, GrayScale, PseudoColor). Correct compositing",
490 "behavior may require a TrueColor or DirectColor visual or a",
491 "Standard Colormap.",
492 "",
493 "Choosing a composite operator is optional. The default",
494 "operator is replace. However, you must choose a location to",
495 "composite your image and press button 1. Press and hold the",
496 "button before releasing and an outline of the image will",
497 "appear to help you identify your location.",
498 "",
499 "The actual colors of the composite image is saved. However,",
500 "the color that appears in image window may be different.",
501 "For example, on a monochrome screen image window will appear",
502 "black or white even though your composited image may have",
503 "many colors. If the image is saved to a file it is written",
504 "with the correct colors. To assure the correct colors are",
505 "saved in the final image, any PseudoClass image is promoted",
506 "to DirectClass (see miff(5)). To force a PseudoClass image",
507 "to remain PseudoClass, use -colors.",
508 (char *) NULL,
509 },
510 *ImageCutHelp[] =
511 {
512 "In cut mode, the Command widget has these options:",
513 "",
514 " Help",
515 " Dismiss",
516 "",
517 "To define a cut region, press button 1 and drag. The",
518 "cut region is defined by a highlighted rectangle that",
519 "expands or contracts as it follows the pointer. Once you",
520 "are satisfied with the cut region, release the button.",
521 "You are now in rectify mode. In rectify mode, the Command",
522 "widget has these options:",
523 "",
524 " Cut",
525 " Help",
526 " Dismiss",
527 "",
528 "You can make adjustments by moving the pointer to one of the",
529 "cut rectangle corners, pressing a button, and dragging.",
530 "Finally, press Cut to commit your copy region. To",
531 "exit without cutting the image, press Dismiss.",
532 (char *) NULL,
533 },
534 *ImageCopyHelp[] =
535 {
536 "In copy mode, the Command widget has these options:",
537 "",
538 " Help",
539 " Dismiss",
540 "",
541 "To define a copy region, press button 1 and drag. The",
542 "copy region is defined by a highlighted rectangle that",
543 "expands or contracts as it follows the pointer. Once you",
544 "are satisfied with the copy region, release the button.",
545 "You are now in rectify mode. In rectify mode, the Command",
546 "widget has these options:",
547 "",
548 " Copy",
549 " Help",
550 " Dismiss",
551 "",
552 "You can make adjustments by moving the pointer to one of the",
553 "copy rectangle corners, pressing a button, and dragging.",
554 "Finally, press Copy to commit your copy region. To",
555 "exit without copying the image, press Dismiss.",
556 (char *) NULL,
557 },
558 *ImageCropHelp[] =
559 {
560 "In crop mode, the Command widget has these options:",
561 "",
562 " Help",
563 " Dismiss",
564 "",
565 "To define a cropping region, press button 1 and drag. The",
566 "cropping region is defined by a highlighted rectangle that",
567 "expands or contracts as it follows the pointer. Once you",
568 "are satisfied with the cropping region, release the button.",
569 "You are now in rectify mode. In rectify mode, the Command",
570 "widget has these options:",
571 "",
572 " Crop",
573 " Help",
574 " Dismiss",
575 "",
576 "You can make adjustments by moving the pointer to one of the",
577 "cropping rectangle corners, pressing a button, and dragging.",
578 "Finally, press Crop to commit your cropping region. To",
579 "exit without cropping the image, press Dismiss.",
580 (char *) NULL,
581 },
582 *ImageDrawHelp[] =
583 {
584 "The cursor changes to a crosshair to indicate you are in",
585 "draw mode. To exit immediately, press Dismiss. In draw mode,",
586 "the Command widget has these options:",
587 "",
588 " Element",
589 " point",
590 " line",
591 " rectangle",
592 " fill rectangle",
593 " circle",
594 " fill circle",
595 " ellipse",
596 " fill ellipse",
597 " polygon",
598 " fill polygon",
599 " Color",
600 " black",
601 " blue",
602 " cyan",
603 " green",
604 " gray",
605 " red",
606 " magenta",
607 " yellow",
608 " white",
609 " transparent",
610 " Browser...",
611 " Stipple",
612 " Brick",
613 " Diagonal",
614 " Scales",
615 " Vertical",
616 " Wavy",
617 " Translucent",
618 " Opaque",
619 " Open...",
620 " Width",
621 " 1",
622 " 2",
623 " 4",
624 " 8",
625 " 16",
626 " Dialog...",
627 " Undo",
628 " Help",
629 " Dismiss",
630 "",
631 "Choose a drawing primitive from the Element sub-menu.",
632 "",
633 "Choose a color from the Color sub-menu. Additional",
634 "colors can be specified with the color browser.",
635 "",
636 "If you choose the color browser and press Grab, you can",
637 "select the color by moving the pointer to the desired",
638 "color on the screen and press any button. The transparent",
639 "color updates the image matte channel and is useful for",
640 "image compositing.",
641 "",
642 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
643 "Additional stipples can be specified with the file browser.",
644 "Stipples obtained from the file browser must be on disk in the",
645 "X11 bitmap format.",
646 "",
647 "Choose a width, if appropriate, from the Width sub-menu. To",
648 "choose a specific width select the Dialog widget.",
649 "",
650 "Choose a point in the Image window and press button 1 and",
651 "hold. Next, move the pointer to another location in the",
652 "image. As you move, a line connects the initial location and",
653 "the pointer. When you release the button, the image is",
654 "updated with the primitive you just drew. For polygons, the",
655 "image is updated when you press and release the button without",
656 "moving the pointer.",
657 "",
658 "To cancel image drawing, move the pointer back to the",
659 "starting point of the line and release the button.",
660 (char *) NULL,
661 },
662 *DisplayHelp[] =
663 {
664 "BUTTONS",
665 " The effects of each button press is described below. Three",
666 " buttons are required. If you have a two button mouse,",
667 " button 1 and 3 are returned. Press ALT and button 3 to",
668 " simulate button 2.",
669 "",
670 " 1 Press this button to map or unmap the Command widget.",
671 "",
672 " 2 Press and drag to define a region of the image to",
673 " magnify.",
674 "",
675 " 3 Press and drag to choose from a select set of commands.",
676 " This button behaves differently if the image being",
677 " displayed is a visual image directory. Here, choose a",
678 " particular tile of the directory and press this button and",
679 " drag to select a command from a pop-up menu. Choose from",
680 " these menu items:",
681 "",
682 " Open",
683 " Next",
684 " Former",
685 " Delete",
686 " Update",
687 "",
688 " If you choose Open, the image represented by the tile is",
689 " displayed. To return to the visual image directory, choose",
690 " Next from the Command widget. Next and Former moves to the",
691 " next or former image respectively. Choose Delete to delete",
692 " a particular image tile. Finally, choose Update to",
693 " synchronize all the image tiles with their respective",
694 " images.",
695 "",
696 "COMMAND WIDGET",
697 " The Command widget lists a number of sub-menus and commands.",
698 " They are",
699 "",
700 " File",
701 " Open...",
702 " Next",
703 " Former",
704 " Select...",
705 " Save...",
706 " Print...",
707 " Delete...",
708 " New...",
709 " Visual Directory...",
710 " Quit",
711 " Edit",
712 " Undo",
713 " Redo",
714 " Cut",
715 " Copy",
716 " Paste",
717 " View",
718 " Half Size",
719 " Original Size",
720 " Double Size",
721 " Resize...",
722 " Apply",
723 " Refresh",
724 " Restore",
725 " Transform",
726 " Crop",
727 " Chop",
728 " Flop",
729 " Flip",
730 " Rotate Right",
731 " Rotate Left",
732 " Rotate...",
733 " Shear...",
734 " Roll...",
735 " Trim Edges",
736 " Enhance",
737 " Brightness...",
738 " Saturation...",
739 " Hue...",
740 " Gamma...",
741 " Sharpen...",
742 " Dull",
743 " Contrast Stretch...",
744 " Sigmoidal Contrast...",
745 " Normalize",
746 " Equalize",
747 " Negate",
748 " Grayscale",
749 " Map...",
750 " Quantize...",
751 " Effects",
752 " Despeckle",
753 " Emboss",
754 " Reduce Noise",
755 " Add Noise",
756 " Sharpen...",
757 " Blur...",
758 " Threshold...",
759 " Edge Detect...",
760 " Spread...",
761 " Shade...",
762 " Painting...",
763 " Segment...",
764 " F/X",
765 " Solarize...",
766 " Sepia Tone...",
767 " Swirl...",
768 " Implode...",
769 " Vignette...",
770 " Wave...",
771 " Oil Painting...",
772 " Charcoal Drawing...",
773 " Image Edit",
774 " Annotate...",
775 " Draw...",
776 " Color...",
777 " Matte...",
778 " Composite...",
779 " Add Border...",
780 " Add Frame...",
781 " Comment...",
782 " Launch...",
783 " Region of Interest...",
784 " Miscellany",
785 " Image Info",
786 " Zoom Image",
787 " Show Preview...",
788 " Show Histogram",
789 " Show Matte",
790 " Background...",
791 " Slide Show",
792 " Preferences...",
793 " Help",
794 " Overview",
795 " Browse Documentation",
796 " About Display",
797 "",
798 " Menu items with a indented triangle have a sub-menu. They",
799 " are represented above as the indented items. To access a",
800 " sub-menu item, move the pointer to the appropriate menu and",
801 " press a button and drag. When you find the desired sub-menu",
802 " item, release the button and the command is executed. Move",
803 " the pointer away from the sub-menu if you decide not to",
804 " execute a particular command.",
805 "",
806 "KEYBOARD ACCELERATORS",
807 " Accelerators are one or two key presses that effect a",
808 " particular command. The keyboard accelerators that",
809 " display(1) understands is:",
810 "",
811 " Ctl+O Press to open an image from a file.",
812 "",
813 " space Press to display the next image.",
814 "",
815 " If the image is a multi-paged document such as a Postscript",
816 " document, you can skip ahead several pages by preceding",
817 " this command with a number. For example to display the",
818 " third page beyond the current page, press 3<space>.",
819 "",
820 " backspace Press to display the former image.",
821 "",
822 " If the image is a multi-paged document such as a Postscript",
823 " document, you can skip behind several pages by preceding",
824 " this command with a number. For example to display the",
825 " third page preceding the current page, press 3<backspace>.",
826 "",
827 " Ctl+S Press to write the image to a file.",
828 "",
829 " Ctl+P Press to print the image to a Postscript printer.",
830 "",
831 " Ctl+D Press to delete an image file.",
832 "",
833 " Ctl+N Press to create a blank canvas.",
834 "",
835 " Ctl+Q Press to discard all images and exit program.",
836 "",
837 " Ctl+Z Press to undo last image transformation.",
838 "",
839 " Ctl+R Press to redo last image transformation.",
840 "",
841 " Ctl+X Press to cut a region of the image.",
842 "",
843 " Ctl+C Press to copy a region of the image.",
844 "",
845 " Ctl+V Press to paste a region to the image.",
846 "",
847 " < Press to half the image size.",
848 "",
849 " - Press to return to the original image size.",
850 "",
851 " > Press to double the image size.",
852 "",
853 " % Press to resize the image to a width and height you",
854 " specify.",
855 "",
856 "Cmd-A Press to make any image transformations permanent."
857 "",
858 " By default, any image size transformations are applied",
859 " to the original image to create the image displayed on",
860 " the X server. However, the transformations are not",
861 " permanent (i.e. the original image does not change",
862 " size only the X image does). For example, if you",
863 " press > the X image will appear to double in size,",
864 " but the original image will in fact remain the same size.",
865 " To force the original image to double in size, press >",
866 " followed by Cmd-A.",
867 "",
868 " @ Press to refresh the image window.",
869 "",
870 " C Press to cut out a rectangular region of the image.",
871 "",
872 " [ Press to chop the image.",
873 "",
874 " H Press to flop image in the horizontal direction.",
875 "",
876 " V Press to flip image in the vertical direction.",
877 "",
878 " / Press to rotate the image 90 degrees clockwise.",
879 "",
880 " \\ Press to rotate the image 90 degrees counter-clockwise.",
881 "",
882 " * Press to rotate the image the number of degrees you",
883 " specify.",
884 "",
885 " S Press to shear the image the number of degrees you",
886 " specify.",
887 "",
888 " R Press to roll the image.",
889 "",
890 " T Press to trim the image edges.",
891 "",
892 " Shft-H Press to vary the image hue.",
893 "",
894 " Shft-S Press to vary the color saturation.",
895 "",
896 " Shft-L Press to vary the color brightness.",
897 "",
898 " Shft-G Press to gamma correct the image.",
899 "",
900 " Shft-C Press to sharpen the image contrast.",
901 "",
902 " Shft-Z Press to dull the image contrast.",
903 "",
904 " = Press to perform histogram equalization on the image.",
905 "",
906 " Shft-N Press to perform histogram normalization on the image.",
907 "",
908 " Shft-~ Press to negate the colors of the image.",
909 "",
910 " . Press to convert the image colors to gray.",
911 "",
912 " Shft-# Press to set the maximum number of unique colors in the",
913 " image.",
914 "",
915 " F2 Press to reduce the speckles in an image.",
916 "",
917 " F3 Press to eliminate peak noise from an image.",
918 "",
919 " F4 Press to add noise to an image.",
920 "",
921 " F5 Press to sharpen an image.",
922 "",
923 " F6 Press to delete an image file.",
924 "",
925 " F7 Press to threshold the image.",
926 "",
927 " F8 Press to detect edges within an image.",
928 "",
929 " F9 Press to emboss an image.",
930 "",
931 " F10 Press to displace pixels by a random amount.",
932 "",
933 " F11 Press to negate all pixels above the threshold level.",
934 "",
935 " F12 Press to shade the image using a distant light source.",
936 "",
937 " F13 Press to lighten or darken image edges to create a 3-D effect.",
938 "",
939 " F14 Press to segment the image by color.",
940 "",
941 " Meta-S Press to swirl image pixels about the center.",
942 "",
943 " Meta-I Press to implode image pixels about the center.",
944 "",
cristycee97112010-05-28 00:44:52 +0000945 " Meta-W Press to alter an image along a sine wave.",
cristy3ed852e2009-09-05 21:47:34 +0000946 "",
947 " Meta-P Press to simulate an oil painting.",
948 "",
949 " Meta-C Press to simulate a charcoal drawing.",
950 "",
951 " Alt-A Press to annotate the image with text.",
952 "",
953 " Alt-D Press to draw on an image.",
954 "",
955 " Alt-P Press to edit an image pixel color.",
956 "",
957 " Alt-M Press to edit the image matte information.",
958 "",
959 " Alt-V Press to composite the image with another.",
960 "",
961 " Alt-B Press to add a border to the image.",
962 "",
963 " Alt-F Press to add an ornamental border to the image.",
964 "",
965 " Alt-Shft-!",
966 " Press to add an image comment.",
967 "",
968 " Ctl-A Press to apply image processing techniques to a region",
969 " of interest.",
970 "",
971 " Shft-? Press to display information about the image.",
972 "",
973 " Shft-+ Press to map the zoom image window.",
974 "",
975 " Shft-P Press to preview an image enhancement, effect, or f/x.",
976 "",
977 " F1 Press to display helpful information about display(1).",
978 "",
979 " Find Press to browse documentation about ImageMagick.",
980 "",
981 " 1-9 Press to change the level of magnification.",
982 "",
983 " Use the arrow keys to move the image one pixel up, down,",
984 " left, or right within the magnify window. Be sure to first",
985 " map the magnify window by pressing button 2.",
986 "",
987 " Press ALT and one of the arrow keys to trim off one pixel",
988 " from any side of the image.",
989 (char *) NULL,
990 },
991 *ImageMatteEditHelp[] =
992 {
993 "Matte information within an image is useful for some",
994 "operations such as image compositing (See IMAGE",
995 "COMPOSITING). This extra channel usually defines a mask",
996 "which represents a sort of a cookie-cutter for the image.",
997 "This the case when matte is opaque (full coverage) for",
998 "pixels inside the shape, zero outside, and between 0 and",
999 "QuantumRange on the boundary.",
1000 "",
1001 "A small window appears showing the location of the cursor in",
1002 "the image window. You are now in matte edit mode. To exit",
1003 "immediately, press Dismiss. In matte edit mode, the Command",
1004 "widget has these options:",
1005 "",
1006 " Method",
1007 " point",
1008 " replace",
1009 " floodfill",
1010 " filltoborder",
1011 " reset",
1012 " Border Color",
1013 " black",
1014 " blue",
1015 " cyan",
1016 " green",
1017 " gray",
1018 " red",
1019 " magenta",
1020 " yellow",
1021 " white",
1022 " Browser...",
1023 " Fuzz",
1024 " 0%",
1025 " 2%",
1026 " 5%",
1027 " 10%",
1028 " 15%",
1029 " Dialog...",
1030 " Matte",
1031 " Opaque",
1032 " Transparent",
1033 " Dialog...",
1034 " Undo",
1035 " Help",
1036 " Dismiss",
1037 "",
1038 "Choose a matte editing method from the Method sub-menu of",
1039 "the Command widget. The point method changes the matte value",
1040 "of any pixel selected with the pointer until the button is",
1041 "is released. The replace method changes the matte value of",
1042 "any pixel that matches the color of the pixel you select with",
1043 "a button press. Floodfill changes the matte value of any pixel",
1044 "that matches the color of the pixel you select with a button",
1045 "press and is a neighbor. Whereas filltoborder changes the matte",
1046 "value any neighbor pixel that is not the border color. Finally",
1047 "reset changes the entire image to the designated matte value.",
1048 "",
1049 "Choose Matte Value and pick Opaque or Transarent. For other values",
1050 "select the Dialog entry. Here a dialog appears requesting a matte",
1051 "value. The value you select is assigned as the opacity value of the",
1052 "selected pixel or pixels.",
1053 "",
1054 "Now, press any button to select a pixel within the image",
1055 "window to change its matte value.",
1056 "",
1057 "If the Magnify widget is mapped, it can be helpful in positioning",
1058 "your pointer within the image (refer to button 2).",
1059 "",
1060 "Matte information is only valid in a DirectClass image.",
1061 "Therefore, any PseudoClass image is promoted to DirectClass",
1062 "(see miff(5)). Note that matte information for PseudoClass",
1063 "is not retained for colormapped X server visuals (e.g.",
1064 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1065 "immediately save your image to a file (refer to Write).",
1066 "Correct matte editing behavior may require a TrueColor or",
1067 "DirectColor visual or a Standard Colormap.",
1068 (char *) NULL,
1069 },
1070 *ImagePanHelp[] =
1071 {
1072 "When an image exceeds the width or height of the X server",
1073 "screen, display maps a small panning icon. The rectangle",
1074 "within the panning icon shows the area that is currently",
1075 "displayed in the image window. To pan about the image,",
1076 "press any button and drag the pointer within the panning",
1077 "icon. The pan rectangle moves with the pointer and the",
1078 "image window is updated to reflect the location of the",
1079 "rectangle within the panning icon. When you have selected",
1080 "the area of the image you wish to view, release the button.",
1081 "",
1082 "Use the arrow keys to pan the image one pixel up, down,",
1083 "left, or right within the image window.",
1084 "",
1085 "The panning icon is withdrawn if the image becomes smaller",
1086 "than the dimensions of the X server screen.",
1087 (char *) NULL,
1088 },
1089 *ImagePasteHelp[] =
1090 {
1091 "A small window appears showing the location of the cursor in",
1092 "the image window. You are now in paste mode. To exit",
1093 "immediately, press Dismiss. In paste mode, the Command",
1094 "widget has these options:",
1095 "",
1096 " Operators",
1097 " over",
1098 " in",
1099 " out",
1100 " atop",
1101 " xor",
1102 " plus",
1103 " minus",
1104 " add",
1105 " subtract",
1106 " difference",
1107 " replace",
1108 " Help",
1109 " Dismiss",
1110 "",
1111 "Choose a composite operation from the Operators sub-menu of",
1112 "the Command widget. How each operator behaves is described",
1113 "below. Image window is the image currently displayed on",
1114 "your X server and image is the image obtained with the File",
1115 "Browser widget.",
1116 "",
1117 "Over The result is the union of the two image shapes,",
1118 " with image obscuring image window in the region of",
1119 " overlap.",
1120 "",
1121 "In The result is simply image cut by the shape of",
1122 " image window. None of the image data of image",
1123 " window is in the result.",
1124 "",
1125 "Out The resulting image is image with the shape of",
1126 " image window cut out.",
1127 "",
1128 "Atop The result is the same shape as image image window,",
1129 " with image obscuring image window where the image",
1130 " shapes overlap. Note this differs from over",
1131 " because the portion of image outside image window's",
1132 " shape does not appear in the result.",
1133 "",
1134 "Xor The result is the image data from both image and",
1135 " image window that is outside the overlap region.",
1136 " The overlap region is blank.",
1137 "",
1138 "Plus The result is just the sum of the image data.",
1139 " Output values are cropped to QuantumRange (no overflow).",
1140 " This operation is independent of the matte",
1141 " channels.",
1142 "",
1143 "Minus The result of image - image window, with underflow",
1144 " cropped to zero.",
1145 "",
1146 "Add The result of image + image window, with overflow",
1147 " wrapping around (mod 256).",
1148 "",
1149 "Subtract The result of image - image window, with underflow",
1150 " wrapping around (mod 256). The add and subtract",
1151 " operators can be used to perform reversible",
1152 " transformations.",
1153 "",
1154 "Difference",
1155 " The result of abs(image - image window). This",
1156 " useful for comparing two very similar images.",
1157 "",
1158 "Copy The resulting image is image window replaced with",
1159 " image. Here the matte information is ignored.",
1160 "",
1161 "CopyRed The red layer of the image window is replace with",
1162 " the red layer of the image. The other layers are",
1163 " untouched.",
1164 "",
1165 "CopyGreen",
1166 " The green layer of the image window is replace with",
1167 " the green layer of the image. The other layers are",
1168 " untouched.",
1169 "",
1170 "CopyBlue The blue layer of the image window is replace with",
1171 " the blue layer of the image. The other layers are",
1172 " untouched.",
1173 "",
1174 "CopyOpacity",
1175 " The matte layer of the image window is replace with",
1176 " the matte layer of the image. The other layers are",
1177 " untouched.",
1178 "",
1179 "The image compositor requires a matte, or alpha channel in",
1180 "the image for some operations. This extra channel usually",
1181 "defines a mask which represents a sort of a cookie-cutter",
1182 "for the image. This the case when matte is opaque (full",
1183 "coverage) for pixels inside the shape, zero outside, and",
1184 "between 0 and QuantumRange on the boundary. If image does not",
1185 "have a matte channel, it is initialized with 0 for any pixel",
1186 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1187 "",
1188 "Note that matte information for image window is not retained",
1189 "for colormapped X server visuals (e.g. StaticColor,",
1190 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1191 "behavior may require a TrueColor or DirectColor visual or a",
1192 "Standard Colormap.",
1193 "",
1194 "Choosing a composite operator is optional. The default",
1195 "operator is replace. However, you must choose a location to",
1196 "paste your image and press button 1. Press and hold the",
1197 "button before releasing and an outline of the image will",
1198 "appear to help you identify your location.",
1199 "",
1200 "The actual colors of the pasted image is saved. However,",
1201 "the color that appears in image window may be different.",
1202 "For example, on a monochrome screen image window will appear",
1203 "black or white even though your pasted image may have",
1204 "many colors. If the image is saved to a file it is written",
1205 "with the correct colors. To assure the correct colors are",
1206 "saved in the final image, any PseudoClass image is promoted",
1207 "to DirectClass (see miff(5)). To force a PseudoClass image",
1208 "to remain PseudoClass, use -colors.",
1209 (char *) NULL,
1210 },
1211 *ImageROIHelp[] =
1212 {
1213 "In region of interest mode, the Command widget has these",
1214 "options:",
1215 "",
1216 " Help",
1217 " Dismiss",
1218 "",
1219 "To define a region of interest, press button 1 and drag.",
1220 "The region of interest is defined by a highlighted rectangle",
1221 "that expands or contracts as it follows the pointer. Once",
1222 "you are satisfied with the region of interest, release the",
1223 "button. You are now in apply mode. In apply mode the",
1224 "Command widget has these options:",
1225 "",
1226 " File",
1227 " Save...",
1228 " Print...",
1229 " Edit",
1230 " Undo",
1231 " Redo",
1232 " Transform",
1233 " Flop",
1234 " Flip",
1235 " Rotate Right",
1236 " Rotate Left",
1237 " Enhance",
1238 " Hue...",
1239 " Saturation...",
1240 " Brightness...",
1241 " Gamma...",
1242 " Spiff",
1243 " Dull",
1244 " Contrast Stretch",
1245 " Sigmoidal Contrast...",
1246 " Normalize",
1247 " Equalize",
1248 " Negate",
1249 " Grayscale",
1250 " Map...",
1251 " Quantize...",
1252 " Effects",
1253 " Despeckle",
1254 " Emboss",
1255 " Reduce Noise",
1256 " Sharpen...",
1257 " Blur...",
1258 " Threshold...",
1259 " Edge Detect...",
1260 " Spread...",
1261 " Shade...",
1262 " Raise...",
1263 " Segment...",
1264 " F/X",
1265 " Solarize...",
1266 " Sepia Tone...",
1267 " Swirl...",
1268 " Implode...",
1269 " Vignette...",
1270 " Wave...",
1271 " Oil Painting...",
1272 " Charcoal Drawing...",
1273 " Miscellany",
1274 " Image Info",
1275 " Zoom Image",
1276 " Show Preview...",
1277 " Show Histogram",
1278 " Show Matte",
1279 " Help",
1280 " Dismiss",
1281 "",
1282 "You can make adjustments to the region of interest by moving",
1283 "the pointer to one of the rectangle corners, pressing a",
1284 "button, and dragging. Finally, choose an image processing",
1285 "technique from the Command widget. You can choose more than",
1286 "one image processing technique to apply to an area.",
1287 "Alternatively, you can move the region of interest before",
1288 "applying another image processing technique. To exit, press",
1289 "Dismiss.",
1290 (char *) NULL,
1291 },
1292 *ImageRotateHelp[] =
1293 {
1294 "In rotate mode, the Command widget has these options:",
1295 "",
1296 " Pixel Color",
1297 " black",
1298 " blue",
1299 " cyan",
1300 " green",
1301 " gray",
1302 " red",
1303 " magenta",
1304 " yellow",
1305 " white",
1306 " Browser...",
1307 " Direction",
1308 " horizontal",
1309 " vertical",
1310 " Help",
1311 " Dismiss",
1312 "",
1313 "Choose a background color from the Pixel Color sub-menu.",
1314 "Additional background colors can be specified with the color",
1315 "browser. You can change the menu colors by setting the X",
1316 "resources pen1 through pen9.",
1317 "",
1318 "If you choose the color browser and press Grab, you can",
1319 "select the background color by moving the pointer to the",
1320 "desired color on the screen and press any button.",
1321 "",
1322 "Choose a point in the image window and press this button and",
1323 "hold. Next, move the pointer to another location in the",
1324 "image. As you move a line connects the initial location and",
1325 "the pointer. When you release the button, the degree of",
1326 "image rotation is determined by the slope of the line you",
1327 "just drew. The slope is relative to the direction you",
1328 "choose from the Direction sub-menu of the Command widget.",
1329 "",
1330 "To cancel the image rotation, move the pointer back to the",
1331 "starting point of the line and release the button.",
1332 (char *) NULL,
1333 };
1334
1335/*
1336 Enumeration declarations.
1337*/
1338typedef enum
1339{
1340 CopyMode,
1341 CropMode,
1342 CutMode
1343} ClipboardMode;
1344
1345typedef enum
1346{
1347 OpenCommand,
1348 NextCommand,
1349 FormerCommand,
1350 SelectCommand,
1351 SaveCommand,
1352 PrintCommand,
1353 DeleteCommand,
1354 NewCommand,
1355 VisualDirectoryCommand,
1356 QuitCommand,
1357 UndoCommand,
1358 RedoCommand,
1359 CutCommand,
1360 CopyCommand,
1361 PasteCommand,
1362 HalfSizeCommand,
1363 OriginalSizeCommand,
1364 DoubleSizeCommand,
1365 ResizeCommand,
1366 ApplyCommand,
1367 RefreshCommand,
1368 RestoreCommand,
1369 CropCommand,
1370 ChopCommand,
1371 FlopCommand,
1372 FlipCommand,
1373 RotateRightCommand,
1374 RotateLeftCommand,
1375 RotateCommand,
1376 ShearCommand,
1377 RollCommand,
1378 TrimCommand,
1379 HueCommand,
1380 SaturationCommand,
1381 BrightnessCommand,
1382 GammaCommand,
1383 SpiffCommand,
1384 DullCommand,
1385 ContrastStretchCommand,
1386 SigmoidalContrastCommand,
1387 NormalizeCommand,
1388 EqualizeCommand,
1389 NegateCommand,
1390 GrayscaleCommand,
1391 MapCommand,
1392 QuantizeCommand,
1393 DespeckleCommand,
1394 EmbossCommand,
1395 ReduceNoiseCommand,
1396 AddNoiseCommand,
1397 SharpenCommand,
1398 BlurCommand,
1399 ThresholdCommand,
1400 EdgeDetectCommand,
1401 SpreadCommand,
1402 ShadeCommand,
1403 RaiseCommand,
1404 SegmentCommand,
1405 SolarizeCommand,
1406 SepiaToneCommand,
1407 SwirlCommand,
1408 ImplodeCommand,
1409 VignetteCommand,
1410 WaveCommand,
1411 OilPaintCommand,
1412 CharcoalDrawCommand,
1413 AnnotateCommand,
1414 DrawCommand,
1415 ColorCommand,
1416 MatteCommand,
1417 CompositeCommand,
1418 AddBorderCommand,
1419 AddFrameCommand,
1420 CommentCommand,
1421 LaunchCommand,
1422 RegionofInterestCommand,
1423 ROIHelpCommand,
1424 ROIDismissCommand,
1425 InfoCommand,
1426 ZoomCommand,
1427 ShowPreviewCommand,
1428 ShowHistogramCommand,
1429 ShowMatteCommand,
1430 BackgroundCommand,
1431 SlideShowCommand,
1432 PreferencesCommand,
1433 HelpCommand,
1434 BrowseDocumentationCommand,
1435 VersionCommand,
1436 SaveToUndoBufferCommand,
1437 FreeBuffersCommand,
1438 NullCommand
1439} CommandType;
1440
1441typedef enum
1442{
1443 AnnotateNameCommand,
1444 AnnotateFontColorCommand,
1445 AnnotateBackgroundColorCommand,
1446 AnnotateRotateCommand,
1447 AnnotateHelpCommand,
1448 AnnotateDismissCommand,
1449 TextHelpCommand,
1450 TextApplyCommand,
1451 ChopDirectionCommand,
1452 ChopHelpCommand,
1453 ChopDismissCommand,
1454 HorizontalChopCommand,
1455 VerticalChopCommand,
1456 ColorEditMethodCommand,
1457 ColorEditColorCommand,
1458 ColorEditBorderCommand,
1459 ColorEditFuzzCommand,
1460 ColorEditUndoCommand,
1461 ColorEditHelpCommand,
1462 ColorEditDismissCommand,
1463 CompositeOperatorsCommand,
1464 CompositeDissolveCommand,
1465 CompositeDisplaceCommand,
1466 CompositeHelpCommand,
1467 CompositeDismissCommand,
1468 CropHelpCommand,
1469 CropDismissCommand,
1470 RectifyCopyCommand,
1471 RectifyHelpCommand,
1472 RectifyDismissCommand,
1473 DrawElementCommand,
1474 DrawColorCommand,
1475 DrawStippleCommand,
1476 DrawWidthCommand,
1477 DrawUndoCommand,
1478 DrawHelpCommand,
1479 DrawDismissCommand,
1480 MatteEditMethod,
1481 MatteEditBorderCommand,
1482 MatteEditFuzzCommand,
1483 MatteEditValueCommand,
1484 MatteEditUndoCommand,
1485 MatteEditHelpCommand,
1486 MatteEditDismissCommand,
1487 PasteOperatorsCommand,
1488 PasteHelpCommand,
1489 PasteDismissCommand,
1490 RotateColorCommand,
1491 RotateDirectionCommand,
1492 RotateCropCommand,
1493 RotateSharpenCommand,
1494 RotateHelpCommand,
1495 RotateDismissCommand,
1496 HorizontalRotateCommand,
1497 VerticalRotateCommand,
1498 TileLoadCommand,
1499 TileNextCommand,
1500 TileFormerCommand,
1501 TileDeleteCommand,
1502 TileUpdateCommand
1503} ModeType;
1504
1505/*
1506 Stipples.
1507*/
1508#define BricksWidth 20
1509#define BricksHeight 20
1510#define DiagonalWidth 16
1511#define DiagonalHeight 16
1512#define HighlightWidth 8
1513#define HighlightHeight 8
cristydd05beb2010-11-21 21:23:39 +00001514#define OpaqueWidth 8
1515#define OpaqueHeight 8
cristy3ed852e2009-09-05 21:47:34 +00001516#define ScalesWidth 16
1517#define ScalesHeight 16
1518#define ShadowWidth 8
1519#define ShadowHeight 8
1520#define VerticalWidth 16
1521#define VerticalHeight 16
1522#define WavyWidth 16
1523#define WavyHeight 16
1524
1525/*
1526 Constant declaration.
1527*/
1528static const int
1529 RoiDelta = 8;
1530
1531static const unsigned char
1532 BricksBitmap[] =
1533 {
1534 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1535 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1537 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1538 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1539 },
1540 DiagonalBitmap[] =
1541 {
1542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1543 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1544 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1545 },
1546 ScalesBitmap[] =
1547 {
1548 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1549 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1550 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1551 },
1552 VerticalBitmap[] =
1553 {
1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1557 },
1558 WavyBitmap[] =
1559 {
1560 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1561 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1562 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1563 };
1564
1565/*
1566 Function prototypes.
1567*/
1568static CommandType
1569 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
cristy051718b2011-08-28 22:49:25 +00001570 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001571
1572static Image
1573 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
cristy051718b2011-08-28 22:49:25 +00001574 Image **,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001575 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
cristy051718b2011-08-28 22:49:25 +00001576 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1577 ExceptionInfo *),
1578 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1579 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001580
1581static MagickBooleanType
cristy051718b2011-08-28 22:49:25 +00001582 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1583 ExceptionInfo *),
1584 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1585 ExceptionInfo *),
1586 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1587 ExceptionInfo *),
1588 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1589 ExceptionInfo *),
1590 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1591 ExceptionInfo *),
1592 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1593 ExceptionInfo *),
1594 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1595 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1596 ExceptionInfo *),
1597 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1598 ExceptionInfo *),
1599 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1600 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1601 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1602 ExceptionInfo *),
1603 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1604 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1605 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001606
1607static void
1608 XDrawPanRectangle(Display *,XWindows *),
cristy051718b2011-08-28 22:49:25 +00001609 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1610 ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001611 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy051718b2011-08-28 22:49:25 +00001612 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001613 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001614 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
cristy6710d842011-10-20 23:23:00 +00001615 const KeySym,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001616 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
cristy6710d842011-10-20 23:23:00 +00001617 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001618 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1619
1620/*
1621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1622% %
1623% %
1624% %
1625% D i s p l a y I m a g e s %
1626% %
1627% %
1628% %
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630%
1631% DisplayImages() displays an image sequence to any X window screen. It
1632% returns a value other than 0 if successful. Check the exception member
1633% of image to determine the reason for any failure.
1634%
1635% The format of the DisplayImages method is:
1636%
1637% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001638% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001639%
1640% A description of each parameter follows:
1641%
1642% o image_info: the image info.
1643%
1644% o image: the image.
1645%
cristy051718b2011-08-28 22:49:25 +00001646% o exception: return any errors or warnings in this structure.
1647%
cristy3ed852e2009-09-05 21:47:34 +00001648*/
1649MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001650 Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001651{
1652 char
1653 *argv[1];
1654
1655 Display
1656 *display;
1657
1658 Image
1659 *image;
1660
cristybb503372010-05-27 20:51:26 +00001661 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001662 i;
1663
cristybb503372010-05-27 20:51:26 +00001664 size_t
cristy3ed852e2009-09-05 21:47:34 +00001665 state;
1666
1667 XrmDatabase
1668 resource_database;
1669
1670 XResourceInfo
1671 resource_info;
1672
1673 assert(image_info != (const ImageInfo *) NULL);
1674 assert(image_info->signature == MagickSignature);
1675 assert(images != (Image *) NULL);
1676 assert(images->signature == MagickSignature);
1677 if (images->debug != MagickFalse)
1678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1679 display=XOpenDisplay(image_info->server_name);
1680 if (display == (Display *) NULL)
1681 {
cristy051718b2011-08-28 22:49:25 +00001682 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1683 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001684 return(MagickFalse);
1685 }
cristy051718b2011-08-28 22:49:25 +00001686 if (exception->severity != UndefinedException)
1687 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00001688 (void) XSetErrorHandler(XError);
1689 resource_database=XGetResourceDatabase(display,GetClientName());
1690 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1691 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1692 if (image_info->page != (char *) NULL)
1693 resource_info.image_geometry=AcquireString(image_info->page);
1694 resource_info.immutable=MagickTrue;
1695 argv[0]=AcquireString(GetClientName());
1696 state=DefaultState;
1697 for (i=0; (state & ExitState) == 0; i++)
1698 {
cristybb503372010-05-27 20:51:26 +00001699 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
cristy3ed852e2009-09-05 21:47:34 +00001700 break;
1701 image=GetImageFromList(images,i % GetImageListLength(images));
cristy051718b2011-08-28 22:49:25 +00001702 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00001703 }
cristye42f6582012-02-11 17:59:50 +00001704 (void) SetErrorHandler((ErrorHandler) NULL);
1705 (void) SetWarningHandler((WarningHandler) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001706 argv[0]=DestroyString(argv[0]);
1707 (void) XCloseDisplay(display);
1708 XDestroyResourceInfo(&resource_info);
cristy051718b2011-08-28 22:49:25 +00001709 if (exception->severity != UndefinedException)
cristy3ed852e2009-09-05 21:47:34 +00001710 return(MagickFalse);
1711 return(MagickTrue);
1712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% R e m o t e D i s p l a y C o m m a n d %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
1725% RemoteDisplayCommand() encourages a remote display program to display the
1726% specified image filename.
1727%
1728% The format of the RemoteDisplayCommand method is:
1729%
1730% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1731% const char *window,const char *filename,ExceptionInfo *exception)
1732%
1733% A description of each parameter follows:
1734%
1735% o image_info: the image info.
1736%
1737% o window: Specifies the name or id of an X window.
1738%
1739% o filename: the name of the image filename to display.
1740%
1741% o exception: return any errors or warnings in this structure.
1742%
1743*/
1744MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1745 const char *window,const char *filename,ExceptionInfo *exception)
1746{
1747 Display
1748 *display;
1749
1750 MagickStatusType
1751 status;
1752
1753 assert(image_info != (const ImageInfo *) NULL);
1754 assert(image_info->signature == MagickSignature);
1755 assert(filename != (char *) NULL);
1756 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1757 display=XOpenDisplay(image_info->server_name);
1758 if (display == (Display *) NULL)
1759 {
1760 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1761 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1762 return(MagickFalse);
1763 }
1764 (void) XSetErrorHandler(XError);
1765 status=XRemoteCommand(display,window,filename);
1766 (void) XCloseDisplay(display);
1767 return(status != 0 ? MagickTrue : MagickFalse);
1768}
1769
1770/*
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772% %
1773% %
1774% %
1775+ X A n n o t a t e E d i t I m a g e %
1776% %
1777% %
1778% %
1779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780%
1781% XAnnotateEditImage() annotates the image with text.
1782%
1783% The format of the XAnnotateEditImage method is:
1784%
1785% MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001786% XResourceInfo *resource_info,XWindows *windows,Image *image,
1787% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001788%
1789% A description of each parameter follows:
1790%
1791% o display: Specifies a connection to an X server; returned from
1792% XOpenDisplay.
1793%
1794% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1795%
1796% o windows: Specifies a pointer to a XWindows structure.
1797%
1798% o image: the image; returned from ReadImage.
1799%
1800*/
1801
cristybb503372010-05-27 20:51:26 +00001802static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001803{
1804 if (x > y)
1805 return(x);
1806 return(y);
1807}
1808
cristybb503372010-05-27 20:51:26 +00001809static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001810{
1811 if (x < y)
1812 return(x);
1813 return(y);
1814}
1815
1816static MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001817 XResourceInfo *resource_info,XWindows *windows,Image *image,
1818 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001819{
1820 static const char
1821 *AnnotateMenu[] =
1822 {
1823 "Font Name",
1824 "Font Color",
1825 "Box Color",
1826 "Rotate Text",
1827 "Help",
1828 "Dismiss",
1829 (char *) NULL
1830 },
1831 *TextMenu[] =
1832 {
1833 "Help",
1834 "Apply",
1835 (char *) NULL
1836 };
1837
1838 static const ModeType
1839 AnnotateCommands[] =
1840 {
1841 AnnotateNameCommand,
1842 AnnotateFontColorCommand,
1843 AnnotateBackgroundColorCommand,
1844 AnnotateRotateCommand,
1845 AnnotateHelpCommand,
1846 AnnotateDismissCommand
1847 },
1848 TextCommands[] =
1849 {
1850 TextHelpCommand,
1851 TextApplyCommand
1852 };
1853
1854 static MagickBooleanType
1855 transparent_box = MagickTrue,
1856 transparent_pen = MagickFalse;
1857
1858 static MagickRealType
1859 degrees = 0.0;
1860
1861 static unsigned int
1862 box_id = MaxNumberPens-2,
1863 font_id = 0,
1864 pen_id = 0;
1865
1866 char
1867 command[MaxTextExtent],
1868 text[MaxTextExtent];
1869
1870 const char
1871 *ColorMenu[MaxNumberPens+1];
1872
1873 Cursor
1874 cursor;
1875
1876 GC
1877 annotate_context;
1878
1879 int
1880 id,
1881 pen_number,
1882 status,
1883 x,
1884 y;
1885
1886 KeySym
1887 key_symbol;
1888
1889 register char
1890 *p;
1891
cristybb503372010-05-27 20:51:26 +00001892 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001893 i;
1894
1895 unsigned int
1896 height,
1897 width;
1898
cristybb503372010-05-27 20:51:26 +00001899 size_t
cristy3ed852e2009-09-05 21:47:34 +00001900 state;
1901
1902 XAnnotateInfo
1903 *annotate_info,
1904 *previous_info;
1905
1906 XColor
1907 color;
1908
1909 XFontStruct
1910 *font_info;
1911
1912 XEvent
1913 event,
1914 text_event;
1915
1916 /*
1917 Map Command widget.
1918 */
1919 (void) CloneString(&windows->command.name,"Annotate");
1920 windows->command.data=4;
1921 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1922 (void) XMapRaised(display,windows->command.id);
1923 XClientMessage(display,windows->image.id,windows->im_protocols,
1924 windows->im_update_widget,CurrentTime);
1925 /*
1926 Track pointer until button 1 is pressed.
1927 */
1928 XQueryPosition(display,windows->image.id,&x,&y);
1929 (void) XSelectInput(display,windows->image.id,
1930 windows->image.attributes.event_mask | PointerMotionMask);
1931 cursor=XCreateFontCursor(display,XC_left_side);
1932 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1933 state=DefaultState;
1934 do
1935 {
1936 if (windows->info.mapped != MagickFalse)
1937 {
1938 /*
1939 Display pointer position.
1940 */
cristyb51dff52011-05-19 16:55:47 +00001941 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00001942 x+windows->image.x,y+windows->image.y);
1943 XInfoWidget(display,windows,text);
1944 }
1945 /*
1946 Wait for next event.
1947 */
cristy6710d842011-10-20 23:23:00 +00001948 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00001949 if (event.xany.window == windows->command.id)
1950 {
1951 /*
1952 Select a command from the Command widget.
1953 */
1954 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1955 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1956 if (id < 0)
1957 continue;
1958 switch (AnnotateCommands[id])
1959 {
1960 case AnnotateNameCommand:
1961 {
1962 const char
1963 *FontMenu[MaxNumberFonts];
1964
1965 int
1966 font_number;
1967
1968 /*
1969 Initialize menu selections.
1970 */
1971 for (i=0; i < MaxNumberFonts; i++)
1972 FontMenu[i]=resource_info->font_name[i];
1973 FontMenu[MaxNumberFonts-2]="Browser...";
1974 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1975 /*
1976 Select a font name from the pop-up menu.
1977 */
1978 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1979 (const char **) FontMenu,command);
1980 if (font_number < 0)
1981 break;
1982 if (font_number == (MaxNumberFonts-2))
1983 {
1984 static char
1985 font_name[MaxTextExtent] = "fixed";
1986
1987 /*
1988 Select a font name from a browser.
1989 */
1990 resource_info->font_name[font_number]=font_name;
1991 XFontBrowserWidget(display,windows,"Select",font_name);
1992 if (*font_name == '\0')
1993 break;
1994 }
1995 /*
1996 Initialize font info.
1997 */
1998 font_info=XLoadQueryFont(display,resource_info->font_name[
1999 font_number]);
2000 if (font_info == (XFontStruct *) NULL)
2001 {
2002 XNoticeWidget(display,windows,"Unable to load font:",
2003 resource_info->font_name[font_number]);
2004 break;
2005 }
2006 font_id=(unsigned int) font_number;
2007 (void) XFreeFont(display,font_info);
2008 break;
2009 }
2010 case AnnotateFontColorCommand:
2011 {
2012 /*
2013 Initialize menu selections.
2014 */
2015 for (i=0; i < (int) (MaxNumberPens-2); i++)
2016 ColorMenu[i]=resource_info->pen_colors[i];
2017 ColorMenu[MaxNumberPens-2]="transparent";
2018 ColorMenu[MaxNumberPens-1]="Browser...";
2019 ColorMenu[MaxNumberPens]=(const char *) NULL;
2020 /*
2021 Select a pen color from the pop-up menu.
2022 */
2023 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2024 (const char **) ColorMenu,command);
2025 if (pen_number < 0)
2026 break;
2027 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2028 MagickFalse;
2029 if (transparent_pen != MagickFalse)
2030 break;
2031 if (pen_number == (MaxNumberPens-1))
2032 {
2033 static char
2034 color_name[MaxTextExtent] = "gray";
2035
2036 /*
2037 Select a pen color from a dialog.
2038 */
2039 resource_info->pen_colors[pen_number]=color_name;
2040 XColorBrowserWidget(display,windows,"Select",color_name);
2041 if (*color_name == '\0')
2042 break;
2043 }
2044 /*
2045 Set pen color.
2046 */
2047 (void) XParseColor(display,windows->map_info->colormap,
2048 resource_info->pen_colors[pen_number],&color);
2049 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2050 (unsigned int) MaxColors,&color);
2051 windows->pixel_info->pen_colors[pen_number]=color;
2052 pen_id=(unsigned int) pen_number;
2053 break;
2054 }
2055 case AnnotateBackgroundColorCommand:
2056 {
2057 /*
2058 Initialize menu selections.
2059 */
2060 for (i=0; i < (int) (MaxNumberPens-2); i++)
2061 ColorMenu[i]=resource_info->pen_colors[i];
2062 ColorMenu[MaxNumberPens-2]="transparent";
2063 ColorMenu[MaxNumberPens-1]="Browser...";
2064 ColorMenu[MaxNumberPens]=(const char *) NULL;
2065 /*
2066 Select a pen color from the pop-up menu.
2067 */
2068 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2069 (const char **) ColorMenu,command);
2070 if (pen_number < 0)
2071 break;
2072 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2073 MagickFalse;
2074 if (transparent_box != MagickFalse)
2075 break;
2076 if (pen_number == (MaxNumberPens-1))
2077 {
2078 static char
2079 color_name[MaxTextExtent] = "gray";
2080
2081 /*
2082 Select a pen color from a dialog.
2083 */
2084 resource_info->pen_colors[pen_number]=color_name;
2085 XColorBrowserWidget(display,windows,"Select",color_name);
2086 if (*color_name == '\0')
2087 break;
2088 }
2089 /*
2090 Set pen color.
2091 */
2092 (void) XParseColor(display,windows->map_info->colormap,
2093 resource_info->pen_colors[pen_number],&color);
2094 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2095 (unsigned int) MaxColors,&color);
2096 windows->pixel_info->pen_colors[pen_number]=color;
2097 box_id=(unsigned int) pen_number;
2098 break;
2099 }
2100 case AnnotateRotateCommand:
2101 {
2102 int
2103 entry;
2104
2105 static char
2106 angle[MaxTextExtent] = "30.0";
2107
2108 static const char
2109 *RotateMenu[] =
2110 {
2111 "-90",
2112 "-45",
2113 "-30",
2114 "0",
2115 "30",
2116 "45",
2117 "90",
2118 "180",
2119 "Dialog...",
2120 (char *) NULL,
2121 };
2122
2123 /*
2124 Select a command from the pop-up menu.
2125 */
2126 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2127 command);
2128 if (entry < 0)
2129 break;
2130 if (entry != 8)
2131 {
cristydbdd0e32011-11-04 23:29:40 +00002132 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002133 break;
2134 }
2135 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2136 angle);
2137 if (*angle == '\0')
2138 break;
cristydbdd0e32011-11-04 23:29:40 +00002139 degrees=StringToDouble(angle,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002140 break;
2141 }
2142 case AnnotateHelpCommand:
2143 {
2144 XTextViewWidget(display,resource_info,windows,MagickFalse,
2145 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2146 break;
2147 }
2148 case AnnotateDismissCommand:
2149 {
2150 /*
2151 Prematurely exit.
2152 */
2153 state|=EscapeState;
2154 state|=ExitState;
2155 break;
2156 }
2157 default:
2158 break;
2159 }
2160 continue;
2161 }
2162 switch (event.type)
2163 {
2164 case ButtonPress:
2165 {
2166 if (event.xbutton.button != Button1)
2167 break;
2168 if (event.xbutton.window != windows->image.id)
2169 break;
2170 /*
2171 Change to text entering mode.
2172 */
2173 x=event.xbutton.x;
2174 y=event.xbutton.y;
2175 state|=ExitState;
2176 break;
2177 }
2178 case ButtonRelease:
2179 break;
2180 case Expose:
2181 break;
2182 case KeyPress:
2183 {
2184 if (event.xkey.window != windows->image.id)
2185 break;
2186 /*
2187 Respond to a user key press.
2188 */
2189 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2190 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2191 switch ((int) key_symbol)
2192 {
2193 case XK_Escape:
2194 case XK_F20:
2195 {
2196 /*
2197 Prematurely exit.
2198 */
2199 state|=EscapeState;
2200 state|=ExitState;
2201 break;
2202 }
2203 case XK_F1:
2204 case XK_Help:
2205 {
2206 XTextViewWidget(display,resource_info,windows,MagickFalse,
2207 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2208 break;
2209 }
2210 default:
2211 {
2212 (void) XBell(display,0);
2213 break;
2214 }
2215 }
2216 break;
2217 }
2218 case MotionNotify:
2219 {
2220 /*
2221 Map and unmap Info widget as cursor crosses its boundaries.
2222 */
2223 x=event.xmotion.x;
2224 y=event.xmotion.y;
2225 if (windows->info.mapped != MagickFalse)
2226 {
2227 if ((x < (int) (windows->info.x+windows->info.width)) &&
2228 (y < (int) (windows->info.y+windows->info.height)))
2229 (void) XWithdrawWindow(display,windows->info.id,
2230 windows->info.screen);
2231 }
2232 else
2233 if ((x > (int) (windows->info.x+windows->info.width)) ||
2234 (y > (int) (windows->info.y+windows->info.height)))
2235 (void) XMapWindow(display,windows->info.id);
2236 break;
2237 }
2238 default:
2239 break;
2240 }
2241 } while ((state & ExitState) == 0);
2242 (void) XSelectInput(display,windows->image.id,
2243 windows->image.attributes.event_mask);
2244 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2245 if ((state & EscapeState) != 0)
2246 return(MagickTrue);
2247 /*
2248 Set font info and check boundary conditions.
2249 */
2250 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2251 if (font_info == (XFontStruct *) NULL)
2252 {
2253 XNoticeWidget(display,windows,"Unable to load font:",
2254 resource_info->font_name[font_id]);
2255 font_info=windows->font_info;
2256 }
2257 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2258 x=(int) windows->image.width-font_info->max_bounds.width;
2259 if (y < (int) (font_info->ascent+font_info->descent))
2260 y=(int) font_info->ascent+font_info->descent;
2261 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2262 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2263 return(MagickFalse);
2264 /*
2265 Initialize annotate structure.
2266 */
cristy73bd4a52010-10-05 11:24:23 +00002267 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002268 if (annotate_info == (XAnnotateInfo *) NULL)
2269 return(MagickFalse);
2270 XGetAnnotateInfo(annotate_info);
2271 annotate_info->x=x;
2272 annotate_info->y=y;
2273 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2274 annotate_info->stencil=OpaqueStencil;
2275 else
2276 if (transparent_box == MagickFalse)
2277 annotate_info->stencil=BackgroundStencil;
2278 else
2279 annotate_info->stencil=ForegroundStencil;
2280 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2281 annotate_info->degrees=degrees;
2282 annotate_info->font_info=font_info;
2283 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002284 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
cristy3ed852e2009-09-05 21:47:34 +00002285 sizeof(*annotate_info->text));
2286 if (annotate_info->text == (char *) NULL)
2287 return(MagickFalse);
2288 /*
2289 Create cursor and set graphic context.
2290 */
2291 cursor=XCreateFontCursor(display,XC_pencil);
2292 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2293 annotate_context=windows->image.annotate_context;
2294 (void) XSetFont(display,annotate_context,font_info->fid);
2295 (void) XSetBackground(display,annotate_context,
2296 windows->pixel_info->pen_colors[box_id].pixel);
2297 (void) XSetForeground(display,annotate_context,
2298 windows->pixel_info->pen_colors[pen_id].pixel);
2299 /*
2300 Begin annotating the image with text.
2301 */
2302 (void) CloneString(&windows->command.name,"Text");
2303 windows->command.data=0;
2304 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2305 state=DefaultState;
2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2307 text_event.xexpose.width=(int) font_info->max_bounds.width;
2308 text_event.xexpose.height=font_info->max_bounds.ascent+
2309 font_info->max_bounds.descent;
2310 p=annotate_info->text;
2311 do
2312 {
2313 /*
2314 Display text cursor.
2315 */
2316 *p='\0';
2317 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2318 /*
2319 Wait for next event.
2320 */
cristy6710d842011-10-20 23:23:00 +00002321 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002322 if (event.xany.window == windows->command.id)
2323 {
2324 /*
2325 Select a command from the Command widget.
2326 */
2327 (void) XSetBackground(display,annotate_context,
2328 windows->pixel_info->background_color.pixel);
2329 (void) XSetForeground(display,annotate_context,
2330 windows->pixel_info->foreground_color.pixel);
2331 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2332 (void) XSetBackground(display,annotate_context,
2333 windows->pixel_info->pen_colors[box_id].pixel);
2334 (void) XSetForeground(display,annotate_context,
2335 windows->pixel_info->pen_colors[pen_id].pixel);
2336 if (id < 0)
2337 continue;
2338 switch (TextCommands[id])
2339 {
2340 case TextHelpCommand:
2341 {
2342 XTextViewWidget(display,resource_info,windows,MagickFalse,
2343 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2344 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2345 break;
2346 }
2347 case TextApplyCommand:
2348 {
2349 /*
2350 Finished annotating.
2351 */
2352 annotate_info->width=(unsigned int) XTextWidth(font_info,
2353 annotate_info->text,(int) strlen(annotate_info->text));
2354 XRefreshWindow(display,&windows->image,&text_event);
2355 state|=ExitState;
2356 break;
2357 }
2358 default:
2359 break;
2360 }
2361 continue;
2362 }
2363 /*
2364 Erase text cursor.
2365 */
2366 text_event.xexpose.x=x;
2367 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2368 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2369 (unsigned int) text_event.xexpose.width,(unsigned int)
2370 text_event.xexpose.height,MagickFalse);
2371 XRefreshWindow(display,&windows->image,&text_event);
2372 switch (event.type)
2373 {
2374 case ButtonPress:
2375 {
2376 if (event.xbutton.window != windows->image.id)
2377 break;
2378 if (event.xbutton.button == Button2)
2379 {
2380 /*
2381 Request primary selection.
2382 */
2383 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2384 windows->image.id,CurrentTime);
2385 break;
2386 }
2387 break;
2388 }
2389 case Expose:
2390 {
2391 if (event.xexpose.count == 0)
2392 {
2393 XAnnotateInfo
2394 *text_info;
2395
2396 /*
2397 Refresh Image window.
2398 */
2399 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2400 text_info=annotate_info;
2401 while (text_info != (XAnnotateInfo *) NULL)
2402 {
2403 if (annotate_info->stencil == ForegroundStencil)
2404 (void) XDrawString(display,windows->image.id,annotate_context,
2405 text_info->x,text_info->y,text_info->text,
2406 (int) strlen(text_info->text));
2407 else
2408 (void) XDrawImageString(display,windows->image.id,
2409 annotate_context,text_info->x,text_info->y,text_info->text,
2410 (int) strlen(text_info->text));
2411 text_info=text_info->previous;
2412 }
2413 (void) XDrawString(display,windows->image.id,annotate_context,
2414 x,y,"_",1);
2415 }
2416 break;
2417 }
2418 case KeyPress:
2419 {
2420 int
2421 length;
2422
2423 if (event.xkey.window != windows->image.id)
2424 break;
2425 /*
2426 Respond to a user key press.
2427 */
2428 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2429 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2430 *(command+length)='\0';
2431 if (((event.xkey.state & ControlMask) != 0) ||
2432 ((event.xkey.state & Mod1Mask) != 0))
2433 state|=ModifierState;
2434 if ((state & ModifierState) != 0)
2435 switch ((int) key_symbol)
2436 {
2437 case XK_u:
2438 case XK_U:
2439 {
2440 key_symbol=DeleteCommand;
2441 break;
2442 }
2443 default:
2444 break;
2445 }
2446 switch ((int) key_symbol)
2447 {
2448 case XK_BackSpace:
2449 {
2450 /*
2451 Erase one character.
2452 */
2453 if (p == annotate_info->text)
2454 {
2455 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2456 break;
2457 else
2458 {
2459 /*
2460 Go to end of the previous line of text.
2461 */
2462 annotate_info=annotate_info->previous;
2463 p=annotate_info->text;
2464 x=annotate_info->x+annotate_info->width;
2465 y=annotate_info->y;
2466 if (annotate_info->width != 0)
2467 p+=strlen(annotate_info->text);
2468 break;
2469 }
2470 }
2471 p--;
2472 x-=XTextWidth(font_info,p,1);
2473 text_event.xexpose.x=x;
2474 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2475 XRefreshWindow(display,&windows->image,&text_event);
2476 break;
2477 }
2478 case XK_bracketleft:
2479 {
2480 key_symbol=XK_Escape;
2481 break;
2482 }
2483 case DeleteCommand:
2484 {
2485 /*
2486 Erase the entire line of text.
2487 */
2488 while (p != annotate_info->text)
2489 {
2490 p--;
2491 x-=XTextWidth(font_info,p,1);
2492 text_event.xexpose.x=x;
2493 XRefreshWindow(display,&windows->image,&text_event);
2494 }
2495 break;
2496 }
2497 case XK_Escape:
2498 case XK_F20:
2499 {
2500 /*
2501 Finished annotating.
2502 */
2503 annotate_info->width=(unsigned int) XTextWidth(font_info,
2504 annotate_info->text,(int) strlen(annotate_info->text));
2505 XRefreshWindow(display,&windows->image,&text_event);
2506 state|=ExitState;
2507 break;
2508 }
2509 default:
2510 {
2511 /*
2512 Draw a single character on the Image window.
2513 */
2514 if ((state & ModifierState) != 0)
2515 break;
2516 if (*command == '\0')
2517 break;
2518 *p=(*command);
2519 if (annotate_info->stencil == ForegroundStencil)
2520 (void) XDrawString(display,windows->image.id,annotate_context,
2521 x,y,p,1);
2522 else
2523 (void) XDrawImageString(display,windows->image.id,
2524 annotate_context,x,y,p,1);
2525 x+=XTextWidth(font_info,p,1);
2526 p++;
2527 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2528 break;
2529 }
2530 case XK_Return:
2531 case XK_KP_Enter:
2532 {
2533 /*
2534 Advance to the next line of text.
2535 */
2536 *p='\0';
2537 annotate_info->width=(unsigned int) XTextWidth(font_info,
2538 annotate_info->text,(int) strlen(annotate_info->text));
2539 if (annotate_info->next != (XAnnotateInfo *) NULL)
2540 {
2541 /*
2542 Line of text already exists.
2543 */
2544 annotate_info=annotate_info->next;
2545 x=annotate_info->x;
2546 y=annotate_info->y;
2547 p=annotate_info->text;
2548 break;
2549 }
2550 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2551 sizeof(*annotate_info->next));
2552 if (annotate_info->next == (XAnnotateInfo *) NULL)
2553 return(MagickFalse);
2554 *annotate_info->next=(*annotate_info);
2555 annotate_info->next->previous=annotate_info;
2556 annotate_info=annotate_info->next;
2557 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002558 windows->image.width/MagickMax((ssize_t)
2559 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002560 if (annotate_info->text == (char *) NULL)
2561 return(MagickFalse);
2562 annotate_info->y+=annotate_info->height;
2563 if (annotate_info->y > (int) windows->image.height)
2564 annotate_info->y=(int) annotate_info->height;
2565 annotate_info->next=(XAnnotateInfo *) NULL;
2566 x=annotate_info->x;
2567 y=annotate_info->y;
2568 p=annotate_info->text;
2569 break;
2570 }
2571 }
2572 break;
2573 }
2574 case KeyRelease:
2575 {
2576 /*
2577 Respond to a user key release.
2578 */
2579 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2580 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2581 state&=(~ModifierState);
2582 break;
2583 }
2584 case SelectionNotify:
2585 {
2586 Atom
2587 type;
2588
2589 int
2590 format;
2591
2592 unsigned char
2593 *data;
2594
cristyf2faecf2010-05-28 19:19:36 +00002595 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002596 after,
2597 length;
2598
2599 /*
2600 Obtain response from primary selection.
2601 */
2602 if (event.xselection.property == (Atom) None)
2603 break;
2604 status=XGetWindowProperty(display,event.xselection.requestor,
cristyecd0ab52010-05-30 14:59:20 +00002605 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
cristy3ed852e2009-09-05 21:47:34 +00002606 &type,&format,&length,&after,&data);
2607 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2608 (length == 0))
2609 break;
2610 /*
2611 Annotate Image window with primary selection.
2612 */
cristybb503372010-05-27 20:51:26 +00002613 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002614 {
2615 if ((char) data[i] != '\n')
2616 {
2617 /*
2618 Draw a single character on the Image window.
2619 */
2620 *p=(char) data[i];
2621 (void) XDrawString(display,windows->image.id,annotate_context,
2622 x,y,p,1);
2623 x+=XTextWidth(font_info,p,1);
2624 p++;
2625 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2626 continue;
2627 }
2628 /*
2629 Advance to the next line of text.
2630 */
2631 *p='\0';
2632 annotate_info->width=(unsigned int) XTextWidth(font_info,
2633 annotate_info->text,(int) strlen(annotate_info->text));
2634 if (annotate_info->next != (XAnnotateInfo *) NULL)
2635 {
2636 /*
2637 Line of text already exists.
2638 */
2639 annotate_info=annotate_info->next;
2640 x=annotate_info->x;
2641 y=annotate_info->y;
2642 p=annotate_info->text;
2643 continue;
2644 }
2645 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2646 sizeof(*annotate_info->next));
2647 if (annotate_info->next == (XAnnotateInfo *) NULL)
2648 return(MagickFalse);
2649 *annotate_info->next=(*annotate_info);
2650 annotate_info->next->previous=annotate_info;
2651 annotate_info=annotate_info->next;
2652 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002653 windows->image.width/MagickMax((ssize_t)
2654 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002655 if (annotate_info->text == (char *) NULL)
2656 return(MagickFalse);
2657 annotate_info->y+=annotate_info->height;
2658 if (annotate_info->y > (int) windows->image.height)
2659 annotate_info->y=(int) annotate_info->height;
2660 annotate_info->next=(XAnnotateInfo *) NULL;
2661 x=annotate_info->x;
2662 y=annotate_info->y;
2663 p=annotate_info->text;
2664 }
2665 (void) XFree((void *) data);
2666 break;
2667 }
2668 default:
2669 break;
2670 }
2671 } while ((state & ExitState) == 0);
2672 (void) XFreeCursor(display,cursor);
2673 /*
2674 Annotation is relative to image configuration.
2675 */
2676 width=(unsigned int) image->columns;
2677 height=(unsigned int) image->rows;
2678 x=0;
2679 y=0;
2680 if (windows->image.crop_geometry != (char *) NULL)
2681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2682 /*
2683 Initialize annotated image.
2684 */
2685 XSetCursorState(display,windows,MagickTrue);
2686 XCheckRefreshWindows(display,windows);
2687 while (annotate_info != (XAnnotateInfo *) NULL)
2688 {
2689 if (annotate_info->width == 0)
2690 {
2691 /*
2692 No text on this line-- go to the next line of text.
2693 */
2694 previous_info=annotate_info->previous;
2695 annotate_info->text=(char *)
2696 RelinquishMagickMemory(annotate_info->text);
2697 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2698 annotate_info=previous_info;
2699 continue;
2700 }
2701 /*
2702 Determine pixel index for box and pen color.
2703 */
2704 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2705 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002706 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002707 if (windows->pixel_info->pixels[i] ==
2708 windows->pixel_info->pen_colors[box_id].pixel)
2709 {
2710 windows->pixel_info->box_index=(unsigned short) i;
2711 break;
2712 }
2713 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2714 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002715 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002716 if (windows->pixel_info->pixels[i] ==
2717 windows->pixel_info->pen_colors[pen_id].pixel)
2718 {
2719 windows->pixel_info->pen_index=(unsigned short) i;
2720 break;
2721 }
2722 /*
2723 Define the annotate geometry string.
2724 */
2725 annotate_info->x=(int)
2726 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2727 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2728 windows->image.y)/windows->image.ximage->height;
cristyb51dff52011-05-19 16:55:47 +00002729 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00002730 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2731 height*annotate_info->height/windows->image.ximage->height,
2732 annotate_info->x+x,annotate_info->y+y);
2733 /*
2734 Annotate image with text.
2735 */
cristy7c3af952011-10-20 16:04:16 +00002736 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image,
2737 exception);
cristy3ed852e2009-09-05 21:47:34 +00002738 if (status == 0)
2739 return(MagickFalse);
2740 /*
2741 Free up memory.
2742 */
2743 previous_info=annotate_info->previous;
2744 annotate_info->text=DestroyString(annotate_info->text);
2745 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2746 annotate_info=previous_info;
2747 }
2748 (void) XSetForeground(display,annotate_context,
2749 windows->pixel_info->foreground_color.pixel);
2750 (void) XSetBackground(display,annotate_context,
2751 windows->pixel_info->background_color.pixel);
2752 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2753 XSetCursorState(display,windows,MagickFalse);
2754 (void) XFreeFont(display,font_info);
2755 /*
2756 Update image configuration.
2757 */
cristy6710d842011-10-20 23:23:00 +00002758 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00002759 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002760 return(MagickTrue);
2761}
2762
2763/*
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765% %
2766% %
2767% %
2768+ X B a c k g r o u n d I m a g e %
2769% %
2770% %
2771% %
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773%
2774% XBackgroundImage() displays the image in the background of a window.
2775%
2776% The format of the XBackgroundImage method is:
2777%
2778% MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002779% XResourceInfo *resource_info,XWindows *windows,Image **image,
2780% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002781%
2782% A description of each parameter follows:
2783%
2784% o display: Specifies a connection to an X server; returned from
2785% XOpenDisplay.
2786%
2787% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2788%
2789% o windows: Specifies a pointer to a XWindows structure.
2790%
2791% o image: the image.
2792%
cristy051718b2011-08-28 22:49:25 +00002793% o exception: return any errors or warnings in this structure.
2794%
cristy3ed852e2009-09-05 21:47:34 +00002795*/
2796static MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002797 XResourceInfo *resource_info,XWindows *windows,Image **image,
2798 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002799{
2800#define BackgroundImageTag "Background/Image"
2801
2802 int
2803 status;
2804
2805 static char
2806 window_id[MaxTextExtent] = "root";
2807
2808 XResourceInfo
2809 background_resources;
2810
2811 /*
2812 Put image in background.
2813 */
2814 status=XDialogWidget(display,windows,"Background",
2815 "Enter window id (id 0x00 selects window with pointer):",window_id);
2816 if (*window_id == '\0')
2817 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002818 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2819 exception);
cristy3ed852e2009-09-05 21:47:34 +00002820 XInfoWidget(display,windows,BackgroundImageTag);
2821 XSetCursorState(display,windows,MagickTrue);
2822 XCheckRefreshWindows(display,windows);
2823 background_resources=(*resource_info);
2824 background_resources.window_id=window_id;
2825 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
cristy051718b2011-08-28 22:49:25 +00002826 status=XDisplayBackgroundImage(display,&background_resources,*image,
2827 exception);
cristy3ed852e2009-09-05 21:47:34 +00002828 if (status != MagickFalse)
2829 XClientMessage(display,windows->image.id,windows->im_protocols,
2830 windows->im_retain_colors,CurrentTime);
2831 XSetCursorState(display,windows,MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002832 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2833 exception);
cristy3ed852e2009-09-05 21:47:34 +00002834 return(MagickTrue);
2835}
2836
2837/*
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839% %
2840% %
2841% %
2842+ X C h o p I m a g e %
2843% %
2844% %
2845% %
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847%
2848% XChopImage() chops the X image.
2849%
2850% The format of the XChopImage method is:
2851%
2852% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00002853% XWindows *windows,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002854%
2855% A description of each parameter follows:
2856%
2857% o display: Specifies a connection to an X server; returned from
2858% XOpenDisplay.
2859%
2860% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2861%
2862% o windows: Specifies a pointer to a XWindows structure.
2863%
2864% o image: the image.
2865%
cristy051718b2011-08-28 22:49:25 +00002866% o exception: return any errors or warnings in this structure.
2867%
cristy3ed852e2009-09-05 21:47:34 +00002868*/
2869static MagickBooleanType XChopImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002870 XResourceInfo *resource_info,XWindows *windows,Image **image,
2871 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002872{
2873 static const char
2874 *ChopMenu[] =
2875 {
2876 "Direction",
2877 "Help",
2878 "Dismiss",
2879 (char *) NULL
2880 };
2881
2882 static ModeType
2883 direction = HorizontalChopCommand;
2884
2885 static const ModeType
2886 ChopCommands[] =
2887 {
2888 ChopDirectionCommand,
2889 ChopHelpCommand,
2890 ChopDismissCommand
2891 },
2892 DirectionCommands[] =
2893 {
2894 HorizontalChopCommand,
2895 VerticalChopCommand
2896 };
2897
2898 char
2899 text[MaxTextExtent];
2900
2901 Image
2902 *chop_image;
2903
2904 int
2905 id,
2906 x,
2907 y;
2908
2909 MagickRealType
2910 scale_factor;
2911
2912 RectangleInfo
2913 chop_info;
2914
2915 unsigned int
2916 distance,
2917 height,
2918 width;
2919
cristybb503372010-05-27 20:51:26 +00002920 size_t
cristy3ed852e2009-09-05 21:47:34 +00002921 state;
2922
2923 XEvent
2924 event;
2925
2926 XSegment
2927 segment_info;
2928
2929 /*
2930 Map Command widget.
2931 */
2932 (void) CloneString(&windows->command.name,"Chop");
2933 windows->command.data=1;
2934 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2935 (void) XMapRaised(display,windows->command.id);
2936 XClientMessage(display,windows->image.id,windows->im_protocols,
2937 windows->im_update_widget,CurrentTime);
2938 /*
2939 Track pointer until button 1 is pressed.
2940 */
2941 XQueryPosition(display,windows->image.id,&x,&y);
2942 (void) XSelectInput(display,windows->image.id,
2943 windows->image.attributes.event_mask | PointerMotionMask);
2944 state=DefaultState;
2945 do
2946 {
2947 if (windows->info.mapped != MagickFalse)
2948 {
2949 /*
2950 Display pointer position.
2951 */
cristyb51dff52011-05-19 16:55:47 +00002952 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00002953 x+windows->image.x,y+windows->image.y);
2954 XInfoWidget(display,windows,text);
2955 }
2956 /*
2957 Wait for next event.
2958 */
cristy6710d842011-10-20 23:23:00 +00002959 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002960 if (event.xany.window == windows->command.id)
2961 {
2962 /*
2963 Select a command from the Command widget.
2964 */
2965 id=XCommandWidget(display,windows,ChopMenu,&event);
2966 if (id < 0)
2967 continue;
2968 switch (ChopCommands[id])
2969 {
2970 case ChopDirectionCommand:
2971 {
2972 char
2973 command[MaxTextExtent];
2974
2975 static const char
2976 *Directions[] =
2977 {
2978 "horizontal",
2979 "vertical",
2980 (char *) NULL,
2981 };
2982
2983 /*
2984 Select a command from the pop-up menu.
2985 */
2986 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2987 if (id >= 0)
2988 direction=DirectionCommands[id];
2989 break;
2990 }
2991 case ChopHelpCommand:
2992 {
2993 XTextViewWidget(display,resource_info,windows,MagickFalse,
2994 "Help Viewer - Image Chop",ImageChopHelp);
2995 break;
2996 }
2997 case ChopDismissCommand:
2998 {
2999 /*
3000 Prematurely exit.
3001 */
3002 state|=EscapeState;
3003 state|=ExitState;
3004 break;
3005 }
3006 default:
3007 break;
3008 }
3009 continue;
3010 }
3011 switch (event.type)
3012 {
3013 case ButtonPress:
3014 {
3015 if (event.xbutton.button != Button1)
3016 break;
3017 if (event.xbutton.window != windows->image.id)
3018 break;
3019 /*
3020 User has committed to start point of chopping line.
3021 */
3022 segment_info.x1=(short int) event.xbutton.x;
3023 segment_info.x2=(short int) event.xbutton.x;
3024 segment_info.y1=(short int) event.xbutton.y;
3025 segment_info.y2=(short int) event.xbutton.y;
3026 state|=ExitState;
3027 break;
3028 }
3029 case ButtonRelease:
3030 break;
3031 case Expose:
3032 break;
3033 case KeyPress:
3034 {
3035 char
3036 command[MaxTextExtent];
3037
3038 KeySym
3039 key_symbol;
3040
3041 if (event.xkey.window != windows->image.id)
3042 break;
3043 /*
3044 Respond to a user key press.
3045 */
3046 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3047 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3048 switch ((int) key_symbol)
3049 {
3050 case XK_Escape:
3051 case XK_F20:
3052 {
3053 /*
3054 Prematurely exit.
3055 */
3056 state|=EscapeState;
3057 state|=ExitState;
3058 break;
3059 }
3060 case XK_F1:
3061 case XK_Help:
3062 {
3063 (void) XSetFunction(display,windows->image.highlight_context,
3064 GXcopy);
3065 XTextViewWidget(display,resource_info,windows,MagickFalse,
3066 "Help Viewer - Image Chop",ImageChopHelp);
3067 (void) XSetFunction(display,windows->image.highlight_context,
3068 GXinvert);
3069 break;
3070 }
3071 default:
3072 {
3073 (void) XBell(display,0);
3074 break;
3075 }
3076 }
3077 break;
3078 }
3079 case MotionNotify:
3080 {
3081 /*
3082 Map and unmap Info widget as text cursor crosses its boundaries.
3083 */
3084 x=event.xmotion.x;
3085 y=event.xmotion.y;
3086 if (windows->info.mapped != MagickFalse)
3087 {
3088 if ((x < (int) (windows->info.x+windows->info.width)) &&
3089 (y < (int) (windows->info.y+windows->info.height)))
3090 (void) XWithdrawWindow(display,windows->info.id,
3091 windows->info.screen);
3092 }
3093 else
3094 if ((x > (int) (windows->info.x+windows->info.width)) ||
3095 (y > (int) (windows->info.y+windows->info.height)))
3096 (void) XMapWindow(display,windows->info.id);
3097 }
3098 }
3099 } while ((state & ExitState) == 0);
3100 (void) XSelectInput(display,windows->image.id,
3101 windows->image.attributes.event_mask);
3102 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3103 if ((state & EscapeState) != 0)
3104 return(MagickTrue);
3105 /*
3106 Draw line as pointer moves until the mouse button is released.
3107 */
3108 chop_info.width=0;
3109 chop_info.height=0;
3110 chop_info.x=0;
3111 chop_info.y=0;
3112 distance=0;
3113 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3114 state=DefaultState;
3115 do
3116 {
3117 if (distance > 9)
3118 {
3119 /*
3120 Display info and draw chopping line.
3121 */
3122 if (windows->info.mapped == MagickFalse)
3123 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00003124 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00003125 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00003126 chop_info.height,(double) chop_info.x,(double) chop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003127 XInfoWidget(display,windows,text);
3128 XHighlightLine(display,windows->image.id,
3129 windows->image.highlight_context,&segment_info);
3130 }
3131 else
3132 if (windows->info.mapped != MagickFalse)
3133 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3134 /*
3135 Wait for next event.
3136 */
cristy6710d842011-10-20 23:23:00 +00003137 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003138 if (distance > 9)
3139 XHighlightLine(display,windows->image.id,
3140 windows->image.highlight_context,&segment_info);
3141 switch (event.type)
3142 {
3143 case ButtonPress:
3144 {
3145 segment_info.x2=(short int) event.xmotion.x;
3146 segment_info.y2=(short int) event.xmotion.y;
3147 break;
3148 }
3149 case ButtonRelease:
3150 {
3151 /*
3152 User has committed to chopping line.
3153 */
3154 segment_info.x2=(short int) event.xbutton.x;
3155 segment_info.y2=(short int) event.xbutton.y;
3156 state|=ExitState;
3157 break;
3158 }
3159 case Expose:
3160 break;
3161 case MotionNotify:
3162 {
3163 segment_info.x2=(short int) event.xmotion.x;
3164 segment_info.y2=(short int) event.xmotion.y;
3165 }
3166 default:
3167 break;
3168 }
3169 /*
3170 Check boundary conditions.
3171 */
3172 if (segment_info.x2 < 0)
3173 segment_info.x2=0;
3174 else
3175 if (segment_info.x2 > windows->image.ximage->width)
3176 segment_info.x2=windows->image.ximage->width;
3177 if (segment_info.y2 < 0)
3178 segment_info.y2=0;
3179 else
3180 if (segment_info.y2 > windows->image.ximage->height)
3181 segment_info.y2=windows->image.ximage->height;
3182 distance=(unsigned int)
3183 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3184 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3185 /*
3186 Compute chopping geometry.
3187 */
3188 if (direction == HorizontalChopCommand)
3189 {
cristybb503372010-05-27 20:51:26 +00003190 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
cristy49e2d862010-11-12 02:50:30 +00003191 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
cristy3ed852e2009-09-05 21:47:34 +00003192 chop_info.height=0;
3193 chop_info.y=0;
3194 if (segment_info.x1 > (int) segment_info.x2)
3195 {
cristybb503372010-05-27 20:51:26 +00003196 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
cristy49e2d862010-11-12 02:50:30 +00003197 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
cristy3ed852e2009-09-05 21:47:34 +00003198 }
3199 }
3200 else
3201 {
3202 chop_info.width=0;
cristybb503372010-05-27 20:51:26 +00003203 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
cristy3ed852e2009-09-05 21:47:34 +00003204 chop_info.x=0;
cristy49e2d862010-11-12 02:50:30 +00003205 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
cristy3ed852e2009-09-05 21:47:34 +00003206 if (segment_info.y1 > segment_info.y2)
3207 {
cristy49e2d862010-11-12 02:50:30 +00003208 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3209 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
cristy3ed852e2009-09-05 21:47:34 +00003210 }
3211 }
3212 } while ((state & ExitState) == 0);
3213 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3215 if (distance <= 9)
3216 return(MagickTrue);
3217 /*
3218 Image chopping is relative to image configuration.
3219 */
cristy051718b2011-08-28 22:49:25 +00003220 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3221 exception);
cristy3ed852e2009-09-05 21:47:34 +00003222 XSetCursorState(display,windows,MagickTrue);
3223 XCheckRefreshWindows(display,windows);
3224 windows->image.window_changes.width=windows->image.ximage->width-
3225 (unsigned int) chop_info.width;
3226 windows->image.window_changes.height=windows->image.ximage->height-
3227 (unsigned int) chop_info.height;
3228 width=(unsigned int) (*image)->columns;
3229 height=(unsigned int) (*image)->rows;
3230 x=0;
3231 y=0;
3232 if (windows->image.crop_geometry != (char *) NULL)
3233 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3234 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3235 chop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00003236 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003237 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3238 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3239 chop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00003240 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003241 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3242 /*
3243 Chop image.
3244 */
cristy051718b2011-08-28 22:49:25 +00003245 chop_image=ChopImage(*image,&chop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003246 XSetCursorState(display,windows,MagickFalse);
3247 if (chop_image == (Image *) NULL)
3248 return(MagickFalse);
3249 *image=DestroyImage(*image);
3250 *image=chop_image;
3251 /*
3252 Update image configuration.
3253 */
cristy6710d842011-10-20 23:23:00 +00003254 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003255 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003256 return(MagickTrue);
3257}
3258
3259/*
3260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3261% %
3262% %
3263% %
3264+ X C o l o r E d i t I m a g e %
3265% %
3266% %
3267% %
3268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3269%
3270% XColorEditImage() allows the user to interactively change the color of one
3271% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3272%
3273% The format of the XColorEditImage method is:
3274%
3275% MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003276% XResourceInfo *resource_info,XWindows *windows,Image **image,
3277% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003278%
3279% A description of each parameter follows:
3280%
3281% o display: Specifies a connection to an X server; returned from
3282% XOpenDisplay.
3283%
3284% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3285%
3286% o windows: Specifies a pointer to a XWindows structure.
3287%
3288% o image: the image; returned from ReadImage.
3289%
cristy051718b2011-08-28 22:49:25 +00003290% o exception: return any errors or warnings in this structure.
3291%
cristy3ed852e2009-09-05 21:47:34 +00003292*/
cristy3ed852e2009-09-05 21:47:34 +00003293static MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003294 XResourceInfo *resource_info,XWindows *windows,Image **image,
3295 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003296{
3297 static const char
3298 *ColorEditMenu[] =
3299 {
3300 "Method",
3301 "Pixel Color",
3302 "Border Color",
3303 "Fuzz",
3304 "Undo",
3305 "Help",
3306 "Dismiss",
3307 (char *) NULL
3308 };
3309
3310 static const ModeType
3311 ColorEditCommands[] =
3312 {
3313 ColorEditMethodCommand,
3314 ColorEditColorCommand,
3315 ColorEditBorderCommand,
3316 ColorEditFuzzCommand,
3317 ColorEditUndoCommand,
3318 ColorEditHelpCommand,
3319 ColorEditDismissCommand
3320 };
3321
3322 static PaintMethod
3323 method = PointMethod;
3324
3325 static unsigned int
3326 pen_id = 0;
3327
3328 static XColor
3329 border_color = { 0, 0, 0, 0, 0, 0 };
3330
3331 char
3332 command[MaxTextExtent],
3333 text[MaxTextExtent];
3334
3335 Cursor
3336 cursor;
3337
cristy3ed852e2009-09-05 21:47:34 +00003338 int
3339 entry,
3340 id,
3341 x,
3342 x_offset,
3343 y,
3344 y_offset;
3345
cristy4c08aed2011-07-01 19:47:50 +00003346 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00003347 *q;
3348
cristybb503372010-05-27 20:51:26 +00003349 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003350 i;
3351
3352 unsigned int
3353 height,
3354 width;
3355
cristybb503372010-05-27 20:51:26 +00003356 size_t
cristy3ed852e2009-09-05 21:47:34 +00003357 state;
3358
3359 XColor
3360 color;
3361
3362 XEvent
3363 event;
3364
3365 /*
3366 Map Command widget.
3367 */
3368 (void) CloneString(&windows->command.name,"Color Edit");
3369 windows->command.data=4;
3370 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3371 (void) XMapRaised(display,windows->command.id);
3372 XClientMessage(display,windows->image.id,windows->im_protocols,
3373 windows->im_update_widget,CurrentTime);
3374 /*
3375 Make cursor.
3376 */
3377 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3378 resource_info->background_color,resource_info->foreground_color);
3379 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3380 /*
3381 Track pointer until button 1 is pressed.
3382 */
3383 XQueryPosition(display,windows->image.id,&x,&y);
3384 (void) XSelectInput(display,windows->image.id,
3385 windows->image.attributes.event_mask | PointerMotionMask);
3386 state=DefaultState;
3387 do
3388 {
3389 if (windows->info.mapped != MagickFalse)
3390 {
3391 /*
3392 Display pointer position.
3393 */
cristyb51dff52011-05-19 16:55:47 +00003394 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00003395 x+windows->image.x,y+windows->image.y);
3396 XInfoWidget(display,windows,text);
3397 }
3398 /*
3399 Wait for next event.
3400 */
cristy6710d842011-10-20 23:23:00 +00003401 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003402 if (event.xany.window == windows->command.id)
3403 {
3404 /*
3405 Select a command from the Command widget.
3406 */
3407 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3408 if (id < 0)
3409 {
3410 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3411 continue;
3412 }
3413 switch (ColorEditCommands[id])
3414 {
3415 case ColorEditMethodCommand:
3416 {
3417 char
3418 **methods;
3419
3420 /*
3421 Select a method from the pop-up menu.
3422 */
cristy042ee782011-04-22 18:48:30 +00003423 methods=(char **) GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00003424 if (methods == (char **) NULL)
3425 break;
3426 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3427 (const char **) methods,command);
3428 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00003429 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00003430 MagickFalse,methods[entry]);
3431 methods=DestroyStringList(methods);
3432 break;
3433 }
3434 case ColorEditColorCommand:
3435 {
3436 const char
3437 *ColorMenu[MaxNumberPens];
3438
3439 int
3440 pen_number;
3441
3442 /*
3443 Initialize menu selections.
3444 */
3445 for (i=0; i < (int) (MaxNumberPens-2); i++)
3446 ColorMenu[i]=resource_info->pen_colors[i];
3447 ColorMenu[MaxNumberPens-2]="Browser...";
3448 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3449 /*
3450 Select a pen color from the pop-up menu.
3451 */
3452 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3453 (const char **) ColorMenu,command);
3454 if (pen_number < 0)
3455 break;
3456 if (pen_number == (MaxNumberPens-2))
3457 {
3458 static char
3459 color_name[MaxTextExtent] = "gray";
3460
3461 /*
3462 Select a pen color from a dialog.
3463 */
3464 resource_info->pen_colors[pen_number]=color_name;
3465 XColorBrowserWidget(display,windows,"Select",color_name);
3466 if (*color_name == '\0')
3467 break;
3468 }
3469 /*
3470 Set pen color.
3471 */
3472 (void) XParseColor(display,windows->map_info->colormap,
3473 resource_info->pen_colors[pen_number],&color);
3474 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3475 (unsigned int) MaxColors,&color);
3476 windows->pixel_info->pen_colors[pen_number]=color;
3477 pen_id=(unsigned int) pen_number;
3478 break;
3479 }
3480 case ColorEditBorderCommand:
3481 {
3482 const char
3483 *ColorMenu[MaxNumberPens];
3484
3485 int
3486 pen_number;
3487
3488 /*
3489 Initialize menu selections.
3490 */
3491 for (i=0; i < (int) (MaxNumberPens-2); i++)
3492 ColorMenu[i]=resource_info->pen_colors[i];
3493 ColorMenu[MaxNumberPens-2]="Browser...";
3494 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3495 /*
3496 Select a pen color from the pop-up menu.
3497 */
3498 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3499 (const char **) ColorMenu,command);
3500 if (pen_number < 0)
3501 break;
3502 if (pen_number == (MaxNumberPens-2))
3503 {
3504 static char
3505 color_name[MaxTextExtent] = "gray";
3506
3507 /*
3508 Select a pen color from a dialog.
3509 */
3510 resource_info->pen_colors[pen_number]=color_name;
3511 XColorBrowserWidget(display,windows,"Select",color_name);
3512 if (*color_name == '\0')
3513 break;
3514 }
3515 /*
3516 Set border color.
3517 */
3518 (void) XParseColor(display,windows->map_info->colormap,
3519 resource_info->pen_colors[pen_number],&border_color);
3520 break;
3521 }
3522 case ColorEditFuzzCommand:
3523 {
3524 static char
3525 fuzz[MaxTextExtent];
3526
3527 static const char
3528 *FuzzMenu[] =
3529 {
3530 "0%",
3531 "2%",
3532 "5%",
3533 "10%",
3534 "15%",
3535 "Dialog...",
3536 (char *) NULL,
3537 };
3538
3539 /*
3540 Select a command from the pop-up menu.
3541 */
3542 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3543 command);
3544 if (entry < 0)
3545 break;
3546 if (entry != 5)
3547 {
cristydbdd0e32011-11-04 23:29:40 +00003548 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy40a08ad2010-02-09 02:27:44 +00003549 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003550 break;
3551 }
3552 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3553 (void) XDialogWidget(display,windows,"Ok",
3554 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3555 if (*fuzz == '\0')
3556 break;
3557 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristy9b34e302011-11-05 02:15:45 +00003558 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3559 1.0);
cristy3ed852e2009-09-05 21:47:34 +00003560 break;
3561 }
3562 case ColorEditUndoCommand:
3563 {
3564 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00003565 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003566 break;
3567 }
3568 case ColorEditHelpCommand:
3569 default:
3570 {
3571 XTextViewWidget(display,resource_info,windows,MagickFalse,
3572 "Help Viewer - Image Annotation",ImageColorEditHelp);
3573 break;
3574 }
3575 case ColorEditDismissCommand:
3576 {
3577 /*
3578 Prematurely exit.
3579 */
3580 state|=EscapeState;
3581 state|=ExitState;
3582 break;
3583 }
3584 }
3585 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3586 continue;
3587 }
3588 switch (event.type)
3589 {
3590 case ButtonPress:
3591 {
3592 if (event.xbutton.button != Button1)
3593 break;
3594 if ((event.xbutton.window != windows->image.id) &&
3595 (event.xbutton.window != windows->magnify.id))
3596 break;
3597 /*
3598 exit loop.
3599 */
3600 x=event.xbutton.x;
3601 y=event.xbutton.y;
3602 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00003603 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003604 state|=UpdateConfigurationState;
3605 break;
3606 }
3607 case ButtonRelease:
3608 {
3609 if (event.xbutton.button != Button1)
3610 break;
3611 if ((event.xbutton.window != windows->image.id) &&
3612 (event.xbutton.window != windows->magnify.id))
3613 break;
3614 /*
3615 Update colormap information.
3616 */
3617 x=event.xbutton.x;
3618 y=event.xbutton.y;
cristy6710d842011-10-20 23:23:00 +00003619 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003620 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003621 XInfoWidget(display,windows,text);
3622 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3623 state&=(~UpdateConfigurationState);
3624 break;
3625 }
3626 case Expose:
3627 break;
3628 case KeyPress:
3629 {
3630 KeySym
3631 key_symbol;
3632
3633 if (event.xkey.window == windows->magnify.id)
3634 {
3635 Window
3636 window;
3637
3638 window=windows->magnify.id;
3639 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3640 }
3641 if (event.xkey.window != windows->image.id)
3642 break;
3643 /*
3644 Respond to a user key press.
3645 */
3646 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3647 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3648 switch ((int) key_symbol)
3649 {
3650 case XK_Escape:
3651 case XK_F20:
3652 {
3653 /*
3654 Prematurely exit.
3655 */
3656 state|=ExitState;
3657 break;
3658 }
3659 case XK_F1:
3660 case XK_Help:
3661 {
3662 XTextViewWidget(display,resource_info,windows,MagickFalse,
3663 "Help Viewer - Image Annotation",ImageColorEditHelp);
3664 break;
3665 }
3666 default:
3667 {
3668 (void) XBell(display,0);
3669 break;
3670 }
3671 }
3672 break;
3673 }
3674 case MotionNotify:
3675 {
3676 /*
3677 Map and unmap Info widget as cursor crosses its boundaries.
3678 */
3679 x=event.xmotion.x;
3680 y=event.xmotion.y;
3681 if (windows->info.mapped != MagickFalse)
3682 {
3683 if ((x < (int) (windows->info.x+windows->info.width)) &&
3684 (y < (int) (windows->info.y+windows->info.height)))
3685 (void) XWithdrawWindow(display,windows->info.id,
3686 windows->info.screen);
3687 }
3688 else
3689 if ((x > (int) (windows->info.x+windows->info.width)) ||
3690 (y > (int) (windows->info.y+windows->info.height)))
3691 (void) XMapWindow(display,windows->info.id);
3692 break;
3693 }
3694 default:
3695 break;
3696 }
3697 if (event.xany.window == windows->magnify.id)
3698 {
3699 x=windows->magnify.x-windows->image.x;
3700 y=windows->magnify.y-windows->image.y;
3701 }
3702 x_offset=x;
3703 y_offset=y;
3704 if ((state & UpdateConfigurationState) != 0)
3705 {
cristy49e2d862010-11-12 02:50:30 +00003706 CacheView
3707 *image_view;
3708
cristy3ed852e2009-09-05 21:47:34 +00003709 int
3710 x,
3711 y;
3712
3713 /*
3714 Pixel edit is relative to image configuration.
3715 */
3716 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3717 MagickTrue);
3718 color=windows->pixel_info->pen_colors[pen_id];
3719 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3720 width=(unsigned int) (*image)->columns;
3721 height=(unsigned int) (*image)->rows;
3722 x=0;
3723 y=0;
3724 if (windows->image.crop_geometry != (char *) NULL)
3725 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3726 &width,&height);
3727 x_offset=(int)
3728 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3729 y_offset=(int)
3730 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3731 if ((x_offset < 0) || (y_offset < 0))
3732 continue;
cristy49e2d862010-11-12 02:50:30 +00003733 if ((x_offset >= (int) (*image)->columns) ||
3734 (y_offset >= (int) (*image)->rows))
cristy3ed852e2009-09-05 21:47:34 +00003735 continue;
cristydb070952012-04-20 14:33:00 +00003736 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003737 switch (method)
3738 {
3739 case PointMethod:
3740 default:
3741 {
3742 /*
3743 Update color information using point algorithm.
3744 */
cristy574cc262011-08-05 01:23:58 +00003745 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003746 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003747 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
cristy574cc262011-08-05 01:23:58 +00003748 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003749 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003750 break;
cristy4c08aed2011-07-01 19:47:50 +00003751 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3752 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3753 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristy051718b2011-08-28 22:49:25 +00003754 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +00003755 break;
3756 }
3757 case ReplaceMethod:
3758 {
cristy101ab702011-10-13 13:06:32 +00003759 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +00003760 pixel,
cristy3ed852e2009-09-05 21:47:34 +00003761 target;
3762
3763 /*
3764 Update color information using replace algorithm.
3765 */
cristyf05d4942012-03-17 16:26:09 +00003766 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
3767 x_offset,(ssize_t) y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003768 if ((*image)->storage_class == DirectClass)
3769 {
cristy49e2d862010-11-12 02:50:30 +00003770 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003771 {
cristy49e2d862010-11-12 02:50:30 +00003772 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3773 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003774 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003775 break;
3776 for (x=0; x < (int) (*image)->columns; x++)
3777 {
cristy101ab702011-10-13 13:06:32 +00003778 GetPixelInfoPixel(*image,q,&pixel);
3779 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy3ed852e2009-09-05 21:47:34 +00003780 {
cristy4c08aed2011-07-01 19:47:50 +00003781 SetPixelRed(*image,ScaleShortToQuantum(
3782 color.red),q);
3783 SetPixelGreen(*image,ScaleShortToQuantum(
3784 color.green),q);
3785 SetPixelBlue(*image,ScaleShortToQuantum(
3786 color.blue),q);
cristy3ed852e2009-09-05 21:47:34 +00003787 }
cristyed231572011-07-14 02:18:59 +00003788 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003789 }
cristy49e2d862010-11-12 02:50:30 +00003790 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003791 break;
3792 }
3793 }
3794 else
3795 {
cristy49e2d862010-11-12 02:50:30 +00003796 for (i=0; i < (ssize_t) (*image)->colors; i++)
cristy101ab702011-10-13 13:06:32 +00003797 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
cristy3ed852e2009-09-05 21:47:34 +00003798 {
cristye42f6582012-02-11 17:59:50 +00003799 (*image)->colormap[i].red=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +00003800 color.red);
cristye42f6582012-02-11 17:59:50 +00003801 (*image)->colormap[i].green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003802 color.green);
cristye42f6582012-02-11 17:59:50 +00003803 (*image)->colormap[i].blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003804 color.blue);
3805 }
cristyea1a8aa2011-10-20 13:24:06 +00003806 (void) SyncImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003807 }
3808 break;
3809 }
3810 case FloodfillMethod:
3811 case FillToBorderMethod:
3812 {
3813 DrawInfo
3814 *draw_info;
3815
cristy4c08aed2011-07-01 19:47:50 +00003816 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003817 target;
3818
3819 /*
3820 Update color information using floodfill algorithm.
3821 */
cristy3aa93752011-12-18 15:54:24 +00003822 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +00003823 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
3824 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003825 if (method == FillToBorderMethod)
3826 {
3827 target.red=(MagickRealType)
3828 ScaleShortToQuantum(border_color.red);
3829 target.green=(MagickRealType)
3830 ScaleShortToQuantum(border_color.green);
3831 target.blue=(MagickRealType)
3832 ScaleShortToQuantum(border_color.blue);
3833 }
3834 draw_info=CloneDrawInfo(resource_info->image_info,
3835 (DrawInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00003836 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3837 AllCompliance,&draw_info->fill,exception);
cristyd42d9952011-07-08 14:21:50 +00003838 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
3839 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
cristy189e84c2011-08-27 18:08:53 +00003840 MagickFalse : MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00003841 draw_info=DestroyDrawInfo(draw_info);
3842 break;
3843 }
3844 case ResetMethod:
3845 {
3846 /*
3847 Update color information using reset algorithm.
3848 */
cristy574cc262011-08-05 01:23:58 +00003849 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003850 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003851 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003852 {
cristy49e2d862010-11-12 02:50:30 +00003853 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3854 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003855 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003856 break;
3857 for (x=0; x < (int) (*image)->columns; x++)
3858 {
cristy4c08aed2011-07-01 19:47:50 +00003859 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3860 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3861 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristyed231572011-07-14 02:18:59 +00003862 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003863 }
cristy49e2d862010-11-12 02:50:30 +00003864 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003865 break;
3866 }
3867 break;
3868 }
3869 }
cristy49e2d862010-11-12 02:50:30 +00003870 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00003871 state&=(~UpdateConfigurationState);
3872 }
3873 } while ((state & ExitState) == 0);
3874 (void) XSelectInput(display,windows->image.id,
3875 windows->image.attributes.event_mask);
3876 XSetCursorState(display,windows,MagickFalse);
3877 (void) XFreeCursor(display,cursor);
3878 return(MagickTrue);
3879}
3880
3881/*
3882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3883% %
3884% %
3885% %
3886+ X C o m p o s i t e I m a g e %
3887% %
3888% %
3889% %
3890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3891%
3892% XCompositeImage() requests an image name from the user, reads the image and
3893% composites it with the X window image at a location the user chooses with
3894% the pointer.
3895%
3896% The format of the XCompositeImage method is:
3897%
3898% MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003899% XResourceInfo *resource_info,XWindows *windows,Image *image,
3900% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003901%
3902% A description of each parameter follows:
3903%
3904% o display: Specifies a connection to an X server; returned from
3905% XOpenDisplay.
3906%
3907% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3908%
3909% o windows: Specifies a pointer to a XWindows structure.
3910%
3911% o image: the image; returned from ReadImage.
3912%
cristy051718b2011-08-28 22:49:25 +00003913% o exception: return any errors or warnings in this structure.
3914%
cristy3ed852e2009-09-05 21:47:34 +00003915*/
3916static MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003917 XResourceInfo *resource_info,XWindows *windows,Image *image,
3918 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003919{
3920 static char
3921 displacement_geometry[MaxTextExtent] = "30x30",
3922 filename[MaxTextExtent] = "\0";
3923
3924 static const char
3925 *CompositeMenu[] =
3926 {
3927 "Operators",
3928 "Dissolve",
3929 "Displace",
3930 "Help",
3931 "Dismiss",
3932 (char *) NULL
3933 };
3934
3935 static CompositeOperator
3936 compose = CopyCompositeOp;
3937
3938 static const ModeType
3939 CompositeCommands[] =
3940 {
3941 CompositeOperatorsCommand,
3942 CompositeDissolveCommand,
3943 CompositeDisplaceCommand,
3944 CompositeHelpCommand,
3945 CompositeDismissCommand
3946 };
3947
3948 char
3949 text[MaxTextExtent];
3950
3951 Cursor
3952 cursor;
3953
3954 Image
3955 *composite_image;
3956
3957 int
3958 entry,
3959 id,
3960 x,
3961 y;
3962
3963 MagickRealType
3964 blend,
3965 scale_factor;
3966
3967 RectangleInfo
3968 highlight_info,
3969 composite_info;
3970
3971 unsigned int
3972 height,
3973 width;
3974
cristybb503372010-05-27 20:51:26 +00003975 size_t
cristy3ed852e2009-09-05 21:47:34 +00003976 state;
3977
3978 XEvent
3979 event;
3980
3981 /*
3982 Request image file name from user.
3983 */
3984 XFileBrowserWidget(display,windows,"Composite",filename);
3985 if (*filename == '\0')
3986 return(MagickTrue);
3987 /*
3988 Read image.
3989 */
3990 XSetCursorState(display,windows,MagickTrue);
3991 XCheckRefreshWindows(display,windows);
3992 (void) CopyMagickString(resource_info->image_info->filename,filename,
3993 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00003994 composite_image=ReadImage(resource_info->image_info,exception);
3995 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00003996 XSetCursorState(display,windows,MagickFalse);
3997 if (composite_image == (Image *) NULL)
3998 return(MagickFalse);
3999 /*
4000 Map Command widget.
4001 */
4002 (void) CloneString(&windows->command.name,"Composite");
4003 windows->command.data=1;
4004 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
4005 (void) XMapRaised(display,windows->command.id);
4006 XClientMessage(display,windows->image.id,windows->im_protocols,
4007 windows->im_update_widget,CurrentTime);
4008 /*
4009 Track pointer until button 1 is pressed.
4010 */
4011 XQueryPosition(display,windows->image.id,&x,&y);
4012 (void) XSelectInput(display,windows->image.id,
4013 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004014 composite_info.x=(ssize_t) windows->image.x+x;
4015 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004016 composite_info.width=0;
4017 composite_info.height=0;
4018 cursor=XCreateFontCursor(display,XC_ul_angle);
4019 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4020 blend=0.0;
4021 state=DefaultState;
4022 do
4023 {
4024 if (windows->info.mapped != MagickFalse)
4025 {
4026 /*
4027 Display pointer position.
4028 */
cristyb51dff52011-05-19 16:55:47 +00004029 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004030 (long) composite_info.x,(long) composite_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004031 XInfoWidget(display,windows,text);
4032 }
4033 highlight_info=composite_info;
4034 highlight_info.x=composite_info.x-windows->image.x;
4035 highlight_info.y=composite_info.y-windows->image.y;
4036 XHighlightRectangle(display,windows->image.id,
4037 windows->image.highlight_context,&highlight_info);
4038 /*
4039 Wait for next event.
4040 */
cristy6710d842011-10-20 23:23:00 +00004041 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004042 XHighlightRectangle(display,windows->image.id,
4043 windows->image.highlight_context,&highlight_info);
4044 if (event.xany.window == windows->command.id)
4045 {
4046 /*
4047 Select a command from the Command widget.
4048 */
4049 id=XCommandWidget(display,windows,CompositeMenu,&event);
4050 if (id < 0)
4051 continue;
4052 switch (CompositeCommands[id])
4053 {
4054 case CompositeOperatorsCommand:
4055 {
4056 char
4057 command[MaxTextExtent],
4058 **operators;
4059
4060 /*
4061 Select a command from the pop-up menu.
4062 */
cristy042ee782011-04-22 18:48:30 +00004063 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +00004064 if (operators == (char **) NULL)
4065 break;
4066 entry=XMenuWidget(display,windows,CompositeMenu[id],
4067 (const char **) operators,command);
4068 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00004069 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +00004070 MagickComposeOptions,MagickFalse,operators[entry]);
4071 operators=DestroyStringList(operators);
4072 break;
4073 }
4074 case CompositeDissolveCommand:
4075 {
4076 static char
4077 factor[MaxTextExtent] = "20.0";
4078
4079 /*
4080 Dissolve the two images a given percent.
4081 */
4082 (void) XSetFunction(display,windows->image.highlight_context,
4083 GXcopy);
4084 (void) XDialogWidget(display,windows,"Dissolve",
4085 "Enter the blend factor (0.0 - 99.9%):",factor);
4086 (void) XSetFunction(display,windows->image.highlight_context,
4087 GXinvert);
4088 if (*factor == '\0')
4089 break;
cristydbdd0e32011-11-04 23:29:40 +00004090 blend=StringToDouble(factor,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004091 compose=DissolveCompositeOp;
4092 break;
4093 }
4094 case CompositeDisplaceCommand:
4095 {
4096 /*
4097 Get horizontal and vertical scale displacement geometry.
4098 */
4099 (void) XSetFunction(display,windows->image.highlight_context,
4100 GXcopy);
4101 (void) XDialogWidget(display,windows,"Displace",
4102 "Enter the horizontal and vertical scale:",displacement_geometry);
4103 (void) XSetFunction(display,windows->image.highlight_context,
4104 GXinvert);
4105 if (*displacement_geometry == '\0')
4106 break;
4107 compose=DisplaceCompositeOp;
4108 break;
4109 }
4110 case CompositeHelpCommand:
4111 {
4112 (void) XSetFunction(display,windows->image.highlight_context,
4113 GXcopy);
4114 XTextViewWidget(display,resource_info,windows,MagickFalse,
4115 "Help Viewer - Image Composite",ImageCompositeHelp);
4116 (void) XSetFunction(display,windows->image.highlight_context,
4117 GXinvert);
4118 break;
4119 }
4120 case CompositeDismissCommand:
4121 {
4122 /*
4123 Prematurely exit.
4124 */
4125 state|=EscapeState;
4126 state|=ExitState;
4127 break;
4128 }
4129 default:
4130 break;
4131 }
4132 continue;
4133 }
4134 switch (event.type)
4135 {
4136 case ButtonPress:
4137 {
4138 if (image->debug != MagickFalse)
4139 (void) LogMagickEvent(X11Event,GetMagickModule(),
4140 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4141 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4142 if (event.xbutton.button != Button1)
4143 break;
4144 if (event.xbutton.window != windows->image.id)
4145 break;
4146 /*
4147 Change cursor.
4148 */
4149 composite_info.width=composite_image->columns;
4150 composite_info.height=composite_image->rows;
4151 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004152 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4153 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004154 break;
4155 }
4156 case ButtonRelease:
4157 {
4158 if (image->debug != MagickFalse)
4159 (void) LogMagickEvent(X11Event,GetMagickModule(),
4160 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4161 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4162 if (event.xbutton.button != Button1)
4163 break;
4164 if (event.xbutton.window != windows->image.id)
4165 break;
4166 if ((composite_info.width != 0) && (composite_info.height != 0))
4167 {
4168 /*
4169 User has selected the location of the composite image.
4170 */
cristy49e2d862010-11-12 02:50:30 +00004171 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4172 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004173 state|=ExitState;
4174 }
4175 break;
4176 }
4177 case Expose:
4178 break;
4179 case KeyPress:
4180 {
4181 char
4182 command[MaxTextExtent];
4183
4184 KeySym
4185 key_symbol;
4186
4187 int
4188 length;
4189
4190 if (event.xkey.window != windows->image.id)
4191 break;
4192 /*
4193 Respond to a user key press.
4194 */
4195 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4196 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4197 *(command+length)='\0';
4198 if (image->debug != MagickFalse)
4199 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00004200 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +00004201 switch ((int) key_symbol)
4202 {
4203 case XK_Escape:
4204 case XK_F20:
4205 {
4206 /*
4207 Prematurely exit.
4208 */
4209 composite_image=DestroyImage(composite_image);
4210 state|=EscapeState;
4211 state|=ExitState;
4212 break;
4213 }
4214 case XK_F1:
4215 case XK_Help:
4216 {
4217 (void) XSetFunction(display,windows->image.highlight_context,
4218 GXcopy);
4219 XTextViewWidget(display,resource_info,windows,MagickFalse,
4220 "Help Viewer - Image Composite",ImageCompositeHelp);
4221 (void) XSetFunction(display,windows->image.highlight_context,
4222 GXinvert);
4223 break;
4224 }
4225 default:
4226 {
4227 (void) XBell(display,0);
4228 break;
4229 }
4230 }
4231 break;
4232 }
4233 case MotionNotify:
4234 {
4235 /*
4236 Map and unmap Info widget as text cursor crosses its boundaries.
4237 */
4238 x=event.xmotion.x;
4239 y=event.xmotion.y;
4240 if (windows->info.mapped != MagickFalse)
4241 {
4242 if ((x < (int) (windows->info.x+windows->info.width)) &&
4243 (y < (int) (windows->info.y+windows->info.height)))
4244 (void) XWithdrawWindow(display,windows->info.id,
4245 windows->info.screen);
4246 }
4247 else
4248 if ((x > (int) (windows->info.x+windows->info.width)) ||
4249 (y > (int) (windows->info.y+windows->info.height)))
4250 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004251 composite_info.x=(ssize_t) windows->image.x+x;
4252 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004253 break;
4254 }
4255 default:
4256 {
4257 if (image->debug != MagickFalse)
4258 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4259 event.type);
4260 break;
4261 }
4262 }
4263 } while ((state & ExitState) == 0);
4264 (void) XSelectInput(display,windows->image.id,
4265 windows->image.attributes.event_mask);
4266 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4267 XSetCursorState(display,windows,MagickFalse);
4268 (void) XFreeCursor(display,cursor);
4269 if ((state & EscapeState) != 0)
4270 return(MagickTrue);
4271 /*
4272 Image compositing is relative to image configuration.
4273 */
4274 XSetCursorState(display,windows,MagickTrue);
4275 XCheckRefreshWindows(display,windows);
4276 width=(unsigned int) image->columns;
4277 height=(unsigned int) image->rows;
4278 x=0;
4279 y=0;
4280 if (windows->image.crop_geometry != (char *) NULL)
4281 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4282 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4283 composite_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00004284 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004285 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4286 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4287 composite_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00004288 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004289 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4290 if ((composite_info.width != composite_image->columns) ||
4291 (composite_info.height != composite_image->rows))
4292 {
4293 Image
4294 *resize_image;
4295
4296 /*
4297 Scale composite image.
4298 */
cristy15b98cd2010-09-12 19:42:50 +00004299 resize_image=ResizeImage(composite_image,composite_info.width,
cristyaa2c16c2012-03-25 22:21:35 +00004300 composite_info.height,composite_image->filter,exception);
cristy3ed852e2009-09-05 21:47:34 +00004301 composite_image=DestroyImage(composite_image);
4302 if (resize_image == (Image *) NULL)
4303 {
4304 XSetCursorState(display,windows,MagickFalse);
4305 return(MagickFalse);
4306 }
4307 composite_image=resize_image;
4308 }
4309 if (compose == DisplaceCompositeOp)
4310 (void) SetImageArtifact(composite_image,"compose:args",
4311 displacement_geometry);
4312 if (blend != 0.0)
4313 {
cristy49e2d862010-11-12 02:50:30 +00004314 CacheView
4315 *image_view;
4316
cristy3ed852e2009-09-05 21:47:34 +00004317 int
4318 y;
4319
4320 Quantum
4321 opacity;
4322
4323 register int
4324 x;
4325
cristy4c08aed2011-07-01 19:47:50 +00004326 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004327 *q;
4328
4329 /*
4330 Create mattes for blending.
4331 */
cristy63240882011-08-05 19:05:27 +00004332 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00004333 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
cristybb503372010-05-27 20:51:26 +00004334 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
cristy574cc262011-08-05 01:23:58 +00004335 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004336 return(MagickFalse);
4337 image->matte=MagickTrue;
cristydb070952012-04-20 14:33:00 +00004338 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00004339 for (y=0; y < (int) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004340 {
cristy49e2d862010-11-12 02:50:30 +00004341 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4342 exception);
cristy4c08aed2011-07-01 19:47:50 +00004343 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004344 break;
4345 for (x=0; x < (int) image->columns; x++)
4346 {
cristy4c08aed2011-07-01 19:47:50 +00004347 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00004348 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004349 }
cristy49e2d862010-11-12 02:50:30 +00004350 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004351 break;
4352 }
cristy49e2d862010-11-12 02:50:30 +00004353 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00004354 }
4355 /*
4356 Composite image with X Image window.
4357 */
cristy39172402012-03-30 13:04:39 +00004358 (void) CompositeImage(image,composite_image,compose,MagickTrue,
cristyfeb3e962012-03-29 17:25:55 +00004359 composite_info.x,composite_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +00004360 composite_image=DestroyImage(composite_image);
4361 XSetCursorState(display,windows,MagickFalse);
4362 /*
4363 Update image configuration.
4364 */
cristy6710d842011-10-20 23:23:00 +00004365 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00004366 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00004367 return(MagickTrue);
4368}
4369
4370/*
4371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4372% %
4373% %
4374% %
4375+ X C o n f i g u r e I m a g e %
4376% %
4377% %
4378% %
4379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380%
4381% XConfigureImage() creates a new X image. It also notifies the window
4382% manager of the new image size and configures the transient widows.
4383%
4384% The format of the XConfigureImage method is:
4385%
4386% MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004387% XResourceInfo *resource_info,XWindows *windows,Image *image,
4388% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004389%
4390% A description of each parameter follows:
4391%
4392% o display: Specifies a connection to an X server; returned from
4393% XOpenDisplay.
4394%
4395% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4396%
4397% o windows: Specifies a pointer to a XWindows structure.
4398%
4399% o image: the image.
4400%
cristy051718b2011-08-28 22:49:25 +00004401% o exception: return any errors or warnings in this structure.
4402%
4403% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00004404%
4405*/
4406static MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004407 XResourceInfo *resource_info,XWindows *windows,Image *image,
4408 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004409{
4410 char
4411 geometry[MaxTextExtent];
4412
cristy3ed852e2009-09-05 21:47:34 +00004413 MagickStatusType
4414 status;
4415
cristybb503372010-05-27 20:51:26 +00004416 size_t
cristy3ed852e2009-09-05 21:47:34 +00004417 mask,
4418 height,
4419 width;
4420
cristy9d314ff2011-03-09 01:30:28 +00004421 ssize_t
4422 x,
4423 y;
4424
cristy3ed852e2009-09-05 21:47:34 +00004425 XSizeHints
4426 *size_hints;
4427
4428 XWindowChanges
4429 window_changes;
4430
4431 /*
4432 Dismiss if window dimensions are zero.
4433 */
4434 width=(unsigned int) windows->image.window_changes.width;
4435 height=(unsigned int) windows->image.window_changes.height;
4436 if (image->debug != MagickFalse)
4437 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00004438 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4439 windows->image.ximage->height,(double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00004440 if ((width*height) == 0)
4441 return(MagickTrue);
4442 x=0;
4443 y=0;
4444 /*
4445 Resize image to fit Image window dimensions.
4446 */
4447 XSetCursorState(display,windows,MagickTrue);
4448 (void) XFlush(display);
4449 if (((int) width != windows->image.ximage->width) ||
4450 ((int) height != windows->image.ximage->height))
4451 image->taint=MagickTrue;
4452 windows->magnify.x=(int)
4453 width*windows->magnify.x/windows->image.ximage->width;
4454 windows->magnify.y=(int)
4455 height*windows->magnify.y/windows->image.ximage->height;
4456 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4457 windows->image.y=(int)
4458 (height*windows->image.y/windows->image.ximage->height);
4459 status=XMakeImage(display,resource_info,&windows->image,image,
cristy051718b2011-08-28 22:49:25 +00004460 (unsigned int) width,(unsigned int) height,exception);
cristy3ed852e2009-09-05 21:47:34 +00004461 if (status == MagickFalse)
4462 XNoticeWidget(display,windows,"Unable to configure X image:",
4463 windows->image.name);
4464 /*
4465 Notify window manager of the new configuration.
4466 */
4467 if (resource_info->image_geometry != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00004468 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
cristy3ed852e2009-09-05 21:47:34 +00004469 resource_info->image_geometry);
4470 else
cristyb51dff52011-05-19 16:55:47 +00004471 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +00004472 XDisplayWidth(display,windows->image.screen),
4473 XDisplayHeight(display,windows->image.screen));
4474 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4475 window_changes.width=(int) width;
4476 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4477 window_changes.width=XDisplayWidth(display,windows->image.screen);
4478 window_changes.height=(int) height;
4479 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4480 window_changes.height=XDisplayHeight(display,windows->image.screen);
cristybb503372010-05-27 20:51:26 +00004481 mask=(size_t) (CWWidth | CWHeight);
cristy3ed852e2009-09-05 21:47:34 +00004482 if (resource_info->backdrop)
4483 {
4484 mask|=CWX | CWY;
4485 window_changes.x=(int)
4486 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4487 window_changes.y=(int)
4488 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4489 }
4490 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4491 (unsigned int) mask,&window_changes);
4492 (void) XClearWindow(display,windows->image.id);
4493 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4494 /*
4495 Update Magnify window configuration.
4496 */
4497 if (windows->magnify.mapped != MagickFalse)
cristy6710d842011-10-20 23:23:00 +00004498 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00004499 windows->pan.crop_geometry=windows->image.crop_geometry;
4500 XBestIconSize(display,&windows->pan,image);
4501 while (((windows->pan.width << 1) < MaxIconSize) &&
4502 ((windows->pan.height << 1) < MaxIconSize))
4503 {
4504 windows->pan.width<<=1;
4505 windows->pan.height<<=1;
4506 }
4507 if (windows->pan.geometry != (char *) NULL)
4508 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4509 &windows->pan.width,&windows->pan.height);
4510 window_changes.width=(int) windows->pan.width;
4511 window_changes.height=(int) windows->pan.height;
4512 size_hints=XAllocSizeHints();
4513 if (size_hints != (XSizeHints *) NULL)
4514 {
4515 /*
4516 Set new size hints.
4517 */
4518 size_hints->flags=PSize | PMinSize | PMaxSize;
4519 size_hints->width=window_changes.width;
4520 size_hints->height=window_changes.height;
4521 size_hints->min_width=size_hints->width;
4522 size_hints->min_height=size_hints->height;
4523 size_hints->max_width=size_hints->width;
4524 size_hints->max_height=size_hints->height;
4525 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4526 (void) XFree((void *) size_hints);
4527 }
4528 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4529 (unsigned int) (CWWidth | CWHeight),&window_changes);
4530 /*
4531 Update icon window configuration.
4532 */
4533 windows->icon.crop_geometry=windows->image.crop_geometry;
4534 XBestIconSize(display,&windows->icon,image);
4535 window_changes.width=(int) windows->icon.width;
4536 window_changes.height=(int) windows->icon.height;
4537 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4538 (unsigned int) (CWWidth | CWHeight),&window_changes);
4539 XSetCursorState(display,windows,MagickFalse);
4540 return(status != 0 ? MagickTrue : MagickFalse);
4541}
4542
4543/*
4544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545% %
4546% %
4547% %
4548+ X C r o p I m a g e %
4549% %
4550% %
4551% %
4552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553%
4554% XCropImage() allows the user to select a region of the image and crop, copy,
4555% or cut it. For copy or cut, the image can subsequently be composited onto
4556% the image with XPasteImage.
4557%
4558% The format of the XCropImage method is:
4559%
4560% MagickBooleanType XCropImage(Display *display,
4561% XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004562% const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004563%
4564% A description of each parameter follows:
4565%
4566% o display: Specifies a connection to an X server; returned from
4567% XOpenDisplay.
4568%
4569% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4570%
4571% o windows: Specifies a pointer to a XWindows structure.
4572%
4573% o image: the image; returned from ReadImage.
4574%
4575% o mode: This unsigned value specified whether the image should be
4576% cropped, copied, or cut.
4577%
cristy051718b2011-08-28 22:49:25 +00004578% o exception: return any errors or warnings in this structure.
4579%
cristy3ed852e2009-09-05 21:47:34 +00004580*/
4581static MagickBooleanType XCropImage(Display *display,
4582 XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004583 const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004584{
4585 static const char
4586 *CropModeMenu[] =
4587 {
4588 "Help",
4589 "Dismiss",
4590 (char *) NULL
4591 },
4592 *RectifyModeMenu[] =
4593 {
4594 "Crop",
4595 "Help",
4596 "Dismiss",
4597 (char *) NULL
4598 };
4599
4600 static const ModeType
4601 CropCommands[] =
4602 {
4603 CropHelpCommand,
4604 CropDismissCommand
4605 },
4606 RectifyCommands[] =
4607 {
4608 RectifyCopyCommand,
4609 RectifyHelpCommand,
4610 RectifyDismissCommand
4611 };
4612
cristy49e2d862010-11-12 02:50:30 +00004613 CacheView
4614 *image_view;
4615
cristy3ed852e2009-09-05 21:47:34 +00004616 char
4617 command[MaxTextExtent],
4618 text[MaxTextExtent];
4619
4620 Cursor
4621 cursor;
4622
cristy3ed852e2009-09-05 21:47:34 +00004623 int
4624 id,
4625 x,
4626 y;
4627
4628 KeySym
4629 key_symbol;
4630
4631 Image
4632 *crop_image;
4633
4634 MagickRealType
4635 scale_factor;
4636
4637 RectangleInfo
4638 crop_info,
4639 highlight_info;
4640
cristy4c08aed2011-07-01 19:47:50 +00004641 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004642 *q;
4643
4644 unsigned int
4645 height,
4646 width;
4647
cristybb503372010-05-27 20:51:26 +00004648 size_t
cristy3ed852e2009-09-05 21:47:34 +00004649 state;
4650
4651 XEvent
4652 event;
4653
4654 /*
4655 Map Command widget.
4656 */
4657 switch (mode)
4658 {
4659 case CopyMode:
4660 {
4661 (void) CloneString(&windows->command.name,"Copy");
4662 break;
4663 }
4664 case CropMode:
4665 {
4666 (void) CloneString(&windows->command.name,"Crop");
4667 break;
4668 }
4669 case CutMode:
4670 {
4671 (void) CloneString(&windows->command.name,"Cut");
4672 break;
4673 }
4674 }
4675 RectifyModeMenu[0]=windows->command.name;
4676 windows->command.data=0;
4677 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4678 (void) XMapRaised(display,windows->command.id);
4679 XClientMessage(display,windows->image.id,windows->im_protocols,
4680 windows->im_update_widget,CurrentTime);
4681 /*
4682 Track pointer until button 1 is pressed.
4683 */
4684 XQueryPosition(display,windows->image.id,&x,&y);
4685 (void) XSelectInput(display,windows->image.id,
4686 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004687 crop_info.x=(ssize_t) windows->image.x+x;
4688 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004689 crop_info.width=0;
4690 crop_info.height=0;
4691 cursor=XCreateFontCursor(display,XC_fleur);
4692 state=DefaultState;
4693 do
4694 {
4695 if (windows->info.mapped != MagickFalse)
4696 {
4697 /*
4698 Display pointer position.
4699 */
cristyb51dff52011-05-19 16:55:47 +00004700 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004701 (long) crop_info.x,(long) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004702 XInfoWidget(display,windows,text);
4703 }
4704 /*
4705 Wait for next event.
4706 */
cristy6710d842011-10-20 23:23:00 +00004707 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004708 if (event.xany.window == windows->command.id)
4709 {
4710 /*
4711 Select a command from the Command widget.
4712 */
4713 id=XCommandWidget(display,windows,CropModeMenu,&event);
4714 if (id < 0)
4715 continue;
4716 switch (CropCommands[id])
4717 {
4718 case CropHelpCommand:
4719 {
4720 switch (mode)
4721 {
4722 case CopyMode:
4723 {
4724 XTextViewWidget(display,resource_info,windows,MagickFalse,
4725 "Help Viewer - Image Copy",ImageCopyHelp);
4726 break;
4727 }
4728 case CropMode:
4729 {
4730 XTextViewWidget(display,resource_info,windows,MagickFalse,
4731 "Help Viewer - Image Crop",ImageCropHelp);
4732 break;
4733 }
4734 case CutMode:
4735 {
4736 XTextViewWidget(display,resource_info,windows,MagickFalse,
4737 "Help Viewer - Image Cut",ImageCutHelp);
4738 break;
4739 }
4740 }
4741 break;
4742 }
4743 case CropDismissCommand:
4744 {
4745 /*
4746 Prematurely exit.
4747 */
4748 state|=EscapeState;
4749 state|=ExitState;
4750 break;
4751 }
4752 default:
4753 break;
4754 }
4755 continue;
4756 }
4757 switch (event.type)
4758 {
4759 case ButtonPress:
4760 {
4761 if (event.xbutton.button != Button1)
4762 break;
4763 if (event.xbutton.window != windows->image.id)
4764 break;
4765 /*
4766 Note first corner of cropping rectangle-- exit loop.
4767 */
4768 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004769 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4770 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004771 state|=ExitState;
4772 break;
4773 }
4774 case ButtonRelease:
4775 break;
4776 case Expose:
4777 break;
4778 case KeyPress:
4779 {
4780 if (event.xkey.window != windows->image.id)
4781 break;
4782 /*
4783 Respond to a user key press.
4784 */
4785 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4786 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4787 switch ((int) key_symbol)
4788 {
4789 case XK_Escape:
4790 case XK_F20:
4791 {
4792 /*
4793 Prematurely exit.
4794 */
4795 state|=EscapeState;
4796 state|=ExitState;
4797 break;
4798 }
4799 case XK_F1:
4800 case XK_Help:
4801 {
4802 switch (mode)
4803 {
4804 case CopyMode:
4805 {
4806 XTextViewWidget(display,resource_info,windows,MagickFalse,
4807 "Help Viewer - Image Copy",ImageCopyHelp);
4808 break;
4809 }
4810 case CropMode:
4811 {
4812 XTextViewWidget(display,resource_info,windows,MagickFalse,
4813 "Help Viewer - Image Crop",ImageCropHelp);
4814 break;
4815 }
4816 case CutMode:
4817 {
4818 XTextViewWidget(display,resource_info,windows,MagickFalse,
4819 "Help Viewer - Image Cut",ImageCutHelp);
4820 break;
4821 }
4822 }
4823 break;
4824 }
4825 default:
4826 {
4827 (void) XBell(display,0);
4828 break;
4829 }
4830 }
4831 break;
4832 }
4833 case MotionNotify:
4834 {
4835 if (event.xmotion.window != windows->image.id)
4836 break;
4837 /*
4838 Map and unmap Info widget as text cursor crosses its boundaries.
4839 */
4840 x=event.xmotion.x;
4841 y=event.xmotion.y;
4842 if (windows->info.mapped != MagickFalse)
4843 {
4844 if ((x < (int) (windows->info.x+windows->info.width)) &&
4845 (y < (int) (windows->info.y+windows->info.height)))
4846 (void) XWithdrawWindow(display,windows->info.id,
4847 windows->info.screen);
4848 }
4849 else
4850 if ((x > (int) (windows->info.x+windows->info.width)) ||
4851 (y > (int) (windows->info.y+windows->info.height)))
4852 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004853 crop_info.x=(ssize_t) windows->image.x+x;
4854 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004855 break;
4856 }
4857 default:
4858 break;
4859 }
4860 } while ((state & ExitState) == 0);
4861 (void) XSelectInput(display,windows->image.id,
4862 windows->image.attributes.event_mask);
4863 if ((state & EscapeState) != 0)
4864 {
4865 /*
4866 User want to exit without cropping.
4867 */
4868 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4869 (void) XFreeCursor(display,cursor);
4870 return(MagickTrue);
4871 }
4872 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4873 do
4874 {
4875 /*
4876 Size rectangle as pointer moves until the mouse button is released.
4877 */
4878 x=(int) crop_info.x;
4879 y=(int) crop_info.y;
4880 crop_info.width=0;
4881 crop_info.height=0;
4882 state=DefaultState;
4883 do
4884 {
4885 highlight_info=crop_info;
4886 highlight_info.x=crop_info.x-windows->image.x;
4887 highlight_info.y=crop_info.y-windows->image.y;
4888 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4889 {
4890 /*
4891 Display info and draw cropping rectangle.
4892 */
4893 if (windows->info.mapped == MagickFalse)
4894 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00004895 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004896 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004897 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004898 XInfoWidget(display,windows,text);
4899 XHighlightRectangle(display,windows->image.id,
4900 windows->image.highlight_context,&highlight_info);
4901 }
4902 else
4903 if (windows->info.mapped != MagickFalse)
4904 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4905 /*
4906 Wait for next event.
4907 */
cristy6710d842011-10-20 23:23:00 +00004908 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004909 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4910 XHighlightRectangle(display,windows->image.id,
4911 windows->image.highlight_context,&highlight_info);
4912 switch (event.type)
4913 {
4914 case ButtonPress:
4915 {
cristy49e2d862010-11-12 02:50:30 +00004916 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4917 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004918 break;
4919 }
4920 case ButtonRelease:
4921 {
4922 /*
4923 User has committed to cropping rectangle.
4924 */
cristy49e2d862010-11-12 02:50:30 +00004925 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4926 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004927 XSetCursorState(display,windows,MagickFalse);
4928 state|=ExitState;
4929 windows->command.data=0;
4930 (void) XCommandWidget(display,windows,RectifyModeMenu,
4931 (XEvent *) NULL);
4932 break;
4933 }
4934 case Expose:
4935 break;
4936 case MotionNotify:
4937 {
cristy49e2d862010-11-12 02:50:30 +00004938 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4939 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00004940 }
4941 default:
4942 break;
4943 }
4944 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4945 ((state & ExitState) != 0))
4946 {
4947 /*
4948 Check boundary conditions.
4949 */
4950 if (crop_info.x < 0)
4951 crop_info.x=0;
4952 else
cristy49e2d862010-11-12 02:50:30 +00004953 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4954 crop_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004955 if ((int) crop_info.x < x)
4956 crop_info.width=(unsigned int) (x-crop_info.x);
4957 else
4958 {
4959 crop_info.width=(unsigned int) (crop_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00004960 crop_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00004961 }
4962 if (crop_info.y < 0)
4963 crop_info.y=0;
4964 else
cristy49e2d862010-11-12 02:50:30 +00004965 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4966 crop_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004967 if ((int) crop_info.y < y)
4968 crop_info.height=(unsigned int) (y-crop_info.y);
4969 else
4970 {
4971 crop_info.height=(unsigned int) (crop_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00004972 crop_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00004973 }
4974 }
4975 } while ((state & ExitState) == 0);
4976 /*
4977 Wait for user to grab a corner of the rectangle or press return.
4978 */
4979 state=DefaultState;
4980 (void) XMapWindow(display,windows->info.id);
4981 do
4982 {
4983 if (windows->info.mapped != MagickFalse)
4984 {
4985 /*
4986 Display pointer position.
4987 */
cristyb51dff52011-05-19 16:55:47 +00004988 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004989 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004990 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004991 XInfoWidget(display,windows,text);
4992 }
4993 highlight_info=crop_info;
4994 highlight_info.x=crop_info.x-windows->image.x;
4995 highlight_info.y=crop_info.y-windows->image.y;
4996 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4997 {
4998 state|=EscapeState;
4999 state|=ExitState;
5000 break;
5001 }
5002 XHighlightRectangle(display,windows->image.id,
5003 windows->image.highlight_context,&highlight_info);
cristy6710d842011-10-20 23:23:00 +00005004 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00005005 if (event.xany.window == windows->command.id)
5006 {
5007 /*
5008 Select a command from the Command widget.
5009 */
5010 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5011 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
5012 (void) XSetFunction(display,windows->image.highlight_context,
5013 GXinvert);
5014 XHighlightRectangle(display,windows->image.id,
5015 windows->image.highlight_context,&highlight_info);
5016 if (id >= 0)
5017 switch (RectifyCommands[id])
5018 {
5019 case RectifyCopyCommand:
5020 {
5021 state|=ExitState;
5022 break;
5023 }
5024 case RectifyHelpCommand:
5025 {
5026 (void) XSetFunction(display,windows->image.highlight_context,
5027 GXcopy);
5028 switch (mode)
5029 {
5030 case CopyMode:
5031 {
5032 XTextViewWidget(display,resource_info,windows,MagickFalse,
5033 "Help Viewer - Image Copy",ImageCopyHelp);
5034 break;
5035 }
5036 case CropMode:
5037 {
5038 XTextViewWidget(display,resource_info,windows,MagickFalse,
5039 "Help Viewer - Image Crop",ImageCropHelp);
5040 break;
5041 }
5042 case CutMode:
5043 {
5044 XTextViewWidget(display,resource_info,windows,MagickFalse,
5045 "Help Viewer - Image Cut",ImageCutHelp);
5046 break;
5047 }
5048 }
5049 (void) XSetFunction(display,windows->image.highlight_context,
5050 GXinvert);
5051 break;
5052 }
5053 case RectifyDismissCommand:
5054 {
5055 /*
5056 Prematurely exit.
5057 */
5058 state|=EscapeState;
5059 state|=ExitState;
5060 break;
5061 }
5062 default:
5063 break;
5064 }
5065 continue;
5066 }
5067 XHighlightRectangle(display,windows->image.id,
5068 windows->image.highlight_context,&highlight_info);
5069 switch (event.type)
5070 {
5071 case ButtonPress:
5072 {
5073 if (event.xbutton.button != Button1)
5074 break;
5075 if (event.xbutton.window != windows->image.id)
5076 break;
5077 x=windows->image.x+event.xbutton.x;
5078 y=windows->image.y+event.xbutton.y;
5079 if ((x < (int) (crop_info.x+RoiDelta)) &&
5080 (x > (int) (crop_info.x-RoiDelta)) &&
5081 (y < (int) (crop_info.y+RoiDelta)) &&
5082 (y > (int) (crop_info.y-RoiDelta)))
5083 {
cristybb503372010-05-27 20:51:26 +00005084 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5085 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005086 state|=UpdateConfigurationState;
5087 break;
5088 }
5089 if ((x < (int) (crop_info.x+RoiDelta)) &&
5090 (x > (int) (crop_info.x-RoiDelta)) &&
5091 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5092 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5093 {
cristybb503372010-05-27 20:51:26 +00005094 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
cristy3ed852e2009-09-05 21:47:34 +00005095 state|=UpdateConfigurationState;
5096 break;
5097 }
5098 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5099 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5100 (y < (int) (crop_info.y+RoiDelta)) &&
5101 (y > (int) (crop_info.y-RoiDelta)))
5102 {
cristybb503372010-05-27 20:51:26 +00005103 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005104 state|=UpdateConfigurationState;
5105 break;
5106 }
5107 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5108 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5109 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5110 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5111 {
5112 state|=UpdateConfigurationState;
5113 break;
5114 }
5115 }
5116 case ButtonRelease:
5117 {
5118 if (event.xbutton.window == windows->pan.id)
5119 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5120 (highlight_info.y != crop_info.y-windows->image.y))
5121 XHighlightRectangle(display,windows->image.id,
5122 windows->image.highlight_context,&highlight_info);
5123 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5124 event.xbutton.time);
5125 break;
5126 }
5127 case Expose:
5128 {
5129 if (event.xexpose.window == windows->image.id)
5130 if (event.xexpose.count == 0)
5131 {
5132 event.xexpose.x=(int) highlight_info.x;
5133 event.xexpose.y=(int) highlight_info.y;
5134 event.xexpose.width=(int) highlight_info.width;
5135 event.xexpose.height=(int) highlight_info.height;
5136 XRefreshWindow(display,&windows->image,&event);
5137 }
5138 if (event.xexpose.window == windows->info.id)
5139 if (event.xexpose.count == 0)
5140 XInfoWidget(display,windows,text);
5141 break;
5142 }
5143 case KeyPress:
5144 {
5145 if (event.xkey.window != windows->image.id)
5146 break;
5147 /*
5148 Respond to a user key press.
5149 */
5150 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5151 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5152 switch ((int) key_symbol)
5153 {
5154 case XK_Escape:
5155 case XK_F20:
5156 state|=EscapeState;
5157 case XK_Return:
5158 {
5159 state|=ExitState;
5160 break;
5161 }
5162 case XK_Home:
5163 case XK_KP_Home:
5164 {
cristy49e2d862010-11-12 02:50:30 +00005165 crop_info.x=(ssize_t) (windows->image.width/2L-
5166 crop_info.width/2L);
5167 crop_info.y=(ssize_t) (windows->image.height/2L-
5168 crop_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +00005169 break;
5170 }
5171 case XK_Left:
5172 case XK_KP_Left:
5173 {
5174 crop_info.x--;
5175 break;
5176 }
5177 case XK_Up:
5178 case XK_KP_Up:
5179 case XK_Next:
5180 {
5181 crop_info.y--;
5182 break;
5183 }
5184 case XK_Right:
5185 case XK_KP_Right:
5186 {
5187 crop_info.x++;
5188 break;
5189 }
5190 case XK_Prior:
5191 case XK_Down:
5192 case XK_KP_Down:
5193 {
5194 crop_info.y++;
5195 break;
5196 }
5197 case XK_F1:
5198 case XK_Help:
5199 {
5200 (void) XSetFunction(display,windows->image.highlight_context,
5201 GXcopy);
5202 switch (mode)
5203 {
5204 case CopyMode:
5205 {
5206 XTextViewWidget(display,resource_info,windows,MagickFalse,
5207 "Help Viewer - Image Copy",ImageCopyHelp);
5208 break;
5209 }
5210 case CropMode:
5211 {
5212 XTextViewWidget(display,resource_info,windows,MagickFalse,
5213 "Help Viewer - Image Cropg",ImageCropHelp);
5214 break;
5215 }
5216 case CutMode:
5217 {
5218 XTextViewWidget(display,resource_info,windows,MagickFalse,
5219 "Help Viewer - Image Cutg",ImageCutHelp);
5220 break;
5221 }
5222 }
5223 (void) XSetFunction(display,windows->image.highlight_context,
5224 GXinvert);
5225 break;
5226 }
5227 default:
5228 {
5229 (void) XBell(display,0);
5230 break;
5231 }
5232 }
5233 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5234 event.xkey.time);
5235 break;
5236 }
5237 case KeyRelease:
5238 break;
5239 case MotionNotify:
5240 {
5241 if (event.xmotion.window != windows->image.id)
5242 break;
5243 /*
5244 Map and unmap Info widget as text cursor crosses its boundaries.
5245 */
5246 x=event.xmotion.x;
5247 y=event.xmotion.y;
5248 if (windows->info.mapped != MagickFalse)
5249 {
5250 if ((x < (int) (windows->info.x+windows->info.width)) &&
5251 (y < (int) (windows->info.y+windows->info.height)))
5252 (void) XWithdrawWindow(display,windows->info.id,
5253 windows->info.screen);
5254 }
5255 else
5256 if ((x > (int) (windows->info.x+windows->info.width)) ||
5257 (y > (int) (windows->info.y+windows->info.height)))
5258 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00005259 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5260 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00005261 break;
5262 }
5263 case SelectionRequest:
5264 {
5265 XSelectionEvent
5266 notify;
5267
5268 XSelectionRequestEvent
5269 *request;
5270
5271 /*
5272 Set primary selection.
5273 */
cristyb51dff52011-05-19 16:55:47 +00005274 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005275 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00005276 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005277 request=(&(event.xselectionrequest));
5278 (void) XChangeProperty(request->display,request->requestor,
5279 request->property,request->target,8,PropModeReplace,
5280 (unsigned char *) text,(int) strlen(text));
5281 notify.type=SelectionNotify;
5282 notify.display=request->display;
5283 notify.requestor=request->requestor;
5284 notify.selection=request->selection;
5285 notify.target=request->target;
5286 notify.time=request->time;
5287 if (request->property == None)
5288 notify.property=request->target;
5289 else
5290 notify.property=request->property;
5291 (void) XSendEvent(request->display,request->requestor,False,0,
5292 (XEvent *) &notify);
5293 }
5294 default:
5295 break;
5296 }
5297 if ((state & UpdateConfigurationState) != 0)
5298 {
5299 (void) XPutBackEvent(display,&event);
5300 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5301 break;
5302 }
5303 } while ((state & ExitState) == 0);
5304 } while ((state & ExitState) == 0);
5305 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5306 XSetCursorState(display,windows,MagickFalse);
5307 if ((state & EscapeState) != 0)
5308 return(MagickTrue);
5309 if (mode == CropMode)
5310 if (((int) crop_info.width != windows->image.ximage->width) ||
5311 ((int) crop_info.height != windows->image.ximage->height))
5312 {
5313 /*
5314 Reconfigure Image window as defined by cropping rectangle.
5315 */
5316 XSetCropGeometry(display,windows,&crop_info,image);
5317 windows->image.window_changes.width=(int) crop_info.width;
5318 windows->image.window_changes.height=(int) crop_info.height;
cristy051718b2011-08-28 22:49:25 +00005319 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005320 return(MagickTrue);
5321 }
5322 /*
5323 Copy image before applying image transforms.
5324 */
5325 XSetCursorState(display,windows,MagickTrue);
5326 XCheckRefreshWindows(display,windows);
5327 width=(unsigned int) image->columns;
5328 height=(unsigned int) image->rows;
5329 x=0;
5330 y=0;
5331 if (windows->image.crop_geometry != (char *) NULL)
5332 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5333 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5334 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00005335 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005336 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5337 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5338 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00005339 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005340 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +00005341 crop_image=CropImage(image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00005342 XSetCursorState(display,windows,MagickFalse);
5343 if (crop_image == (Image *) NULL)
5344 return(MagickFalse);
5345 if (resource_info->copy_image != (Image *) NULL)
5346 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5347 resource_info->copy_image=crop_image;
5348 if (mode == CopyMode)
5349 {
cristy051718b2011-08-28 22:49:25 +00005350 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005351 return(MagickTrue);
5352 }
5353 /*
5354 Cut image.
5355 */
cristy574cc262011-08-05 01:23:58 +00005356 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005357 return(MagickFalse);
5358 image->matte=MagickTrue;
cristydb070952012-04-20 14:33:00 +00005359 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00005360 for (y=0; y < (int) crop_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00005361 {
cristy49e2d862010-11-12 02:50:30 +00005362 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5363 crop_info.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00005364 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005365 break;
5366 for (x=0; x < (int) crop_info.width; x++)
5367 {
cristy4c08aed2011-07-01 19:47:50 +00005368 SetPixelAlpha(image,TransparentAlpha,q);
cristyed231572011-07-14 02:18:59 +00005369 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00005370 }
cristy49e2d862010-11-12 02:50:30 +00005371 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005372 break;
5373 }
cristy49e2d862010-11-12 02:50:30 +00005374 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00005375 /*
5376 Update image configuration.
5377 */
cristy6710d842011-10-20 23:23:00 +00005378 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00005379 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005380 return(MagickTrue);
5381}
5382
5383/*
5384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5385% %
5386% %
5387% %
5388+ X D r a w I m a g e %
5389% %
5390% %
5391% %
5392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5393%
5394% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5395% the image.
5396%
5397% The format of the XDrawEditImage method is:
5398%
5399% MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005400% XResourceInfo *resource_info,XWindows *windows,Image **image,
5401% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005402%
5403% A description of each parameter follows:
5404%
5405% o display: Specifies a connection to an X server; returned from
5406% XOpenDisplay.
5407%
5408% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5409%
5410% o windows: Specifies a pointer to a XWindows structure.
5411%
5412% o image: the image.
5413%
cristy051718b2011-08-28 22:49:25 +00005414% o exception: return any errors or warnings in this structure.
5415%
cristy3ed852e2009-09-05 21:47:34 +00005416*/
5417static MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005418 XResourceInfo *resource_info,XWindows *windows,Image **image,
5419 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005420{
5421 static const char
5422 *DrawMenu[] =
5423 {
5424 "Element",
5425 "Color",
5426 "Stipple",
5427 "Width",
5428 "Undo",
5429 "Help",
5430 "Dismiss",
5431 (char *) NULL
5432 };
5433
5434 static ElementType
5435 element = PointElement;
5436
5437 static const ModeType
5438 DrawCommands[] =
5439 {
5440 DrawElementCommand,
5441 DrawColorCommand,
5442 DrawStippleCommand,
5443 DrawWidthCommand,
5444 DrawUndoCommand,
5445 DrawHelpCommand,
5446 DrawDismissCommand
5447 };
5448
5449 static Pixmap
5450 stipple = (Pixmap) NULL;
5451
5452 static unsigned int
5453 pen_id = 0,
5454 line_width = 1;
5455
5456 char
5457 command[MaxTextExtent],
5458 text[MaxTextExtent];
5459
5460 Cursor
5461 cursor;
5462
5463 int
5464 entry,
5465 id,
5466 number_coordinates,
5467 x,
5468 y;
5469
5470 MagickRealType
5471 degrees;
5472
5473 MagickStatusType
5474 status;
5475
5476 RectangleInfo
5477 rectangle_info;
5478
5479 register int
5480 i;
5481
5482 unsigned int
5483 distance,
5484 height,
5485 max_coordinates,
5486 width;
5487
cristybb503372010-05-27 20:51:26 +00005488 size_t
cristy3ed852e2009-09-05 21:47:34 +00005489 state;
5490
5491 Window
5492 root_window;
5493
5494 XDrawInfo
5495 draw_info;
5496
5497 XEvent
5498 event;
5499
5500 XPoint
5501 *coordinate_info;
5502
5503 XSegment
5504 line_info;
5505
5506 /*
5507 Allocate polygon info.
5508 */
5509 max_coordinates=2048;
5510 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5511 sizeof(*coordinate_info));
5512 if (coordinate_info == (XPoint *) NULL)
5513 {
cristy051718b2011-08-28 22:49:25 +00005514 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00005515 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5516 return(MagickFalse);
5517 }
5518 /*
5519 Map Command widget.
5520 */
5521 (void) CloneString(&windows->command.name,"Draw");
5522 windows->command.data=4;
5523 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5524 (void) XMapRaised(display,windows->command.id);
5525 XClientMessage(display,windows->image.id,windows->im_protocols,
5526 windows->im_update_widget,CurrentTime);
5527 /*
5528 Wait for first button press.
5529 */
5530 root_window=XRootWindow(display,XDefaultScreen(display));
5531 draw_info.stencil=OpaqueStencil;
5532 status=MagickTrue;
5533 cursor=XCreateFontCursor(display,XC_tcross);
5534 for ( ; ; )
5535 {
5536 XQueryPosition(display,windows->image.id,&x,&y);
5537 (void) XSelectInput(display,windows->image.id,
5538 windows->image.attributes.event_mask | PointerMotionMask);
5539 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5540 state=DefaultState;
5541 do
5542 {
5543 if (windows->info.mapped != MagickFalse)
5544 {
5545 /*
5546 Display pointer position.
5547 */
cristyb51dff52011-05-19 16:55:47 +00005548 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00005549 x+windows->image.x,y+windows->image.y);
5550 XInfoWidget(display,windows,text);
5551 }
5552 /*
5553 Wait for next event.
5554 */
cristy6710d842011-10-20 23:23:00 +00005555 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00005556 if (event.xany.window == windows->command.id)
5557 {
5558 /*
5559 Select a command from the Command widget.
5560 */
5561 id=XCommandWidget(display,windows,DrawMenu,&event);
5562 if (id < 0)
5563 continue;
5564 switch (DrawCommands[id])
5565 {
5566 case DrawElementCommand:
5567 {
5568 static const char
5569 *Elements[] =
5570 {
5571 "point",
5572 "line",
5573 "rectangle",
5574 "fill rectangle",
5575 "circle",
5576 "fill circle",
5577 "ellipse",
5578 "fill ellipse",
5579 "polygon",
5580 "fill polygon",
5581 (char *) NULL,
5582 };
5583
5584 /*
5585 Select a command from the pop-up menu.
5586 */
5587 element=(ElementType) (XMenuWidget(display,windows,
5588 DrawMenu[id],Elements,command)+1);
5589 break;
5590 }
5591 case DrawColorCommand:
5592 {
5593 const char
5594 *ColorMenu[MaxNumberPens+1];
5595
5596 int
5597 pen_number;
5598
5599 MagickBooleanType
5600 transparent;
5601
5602 XColor
5603 color;
5604
5605 /*
5606 Initialize menu selections.
5607 */
5608 for (i=0; i < (int) (MaxNumberPens-2); i++)
5609 ColorMenu[i]=resource_info->pen_colors[i];
5610 ColorMenu[MaxNumberPens-2]="transparent";
5611 ColorMenu[MaxNumberPens-1]="Browser...";
5612 ColorMenu[MaxNumberPens]=(char *) NULL;
5613 /*
5614 Select a pen color from the pop-up menu.
5615 */
5616 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5617 (const char **) ColorMenu,command);
5618 if (pen_number < 0)
5619 break;
5620 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5621 MagickFalse;
5622 if (transparent != MagickFalse)
5623 {
5624 draw_info.stencil=TransparentStencil;
5625 break;
5626 }
5627 if (pen_number == (MaxNumberPens-1))
5628 {
5629 static char
5630 color_name[MaxTextExtent] = "gray";
5631
5632 /*
5633 Select a pen color from a dialog.
5634 */
5635 resource_info->pen_colors[pen_number]=color_name;
5636 XColorBrowserWidget(display,windows,"Select",color_name);
5637 if (*color_name == '\0')
5638 break;
5639 }
5640 /*
5641 Set pen color.
5642 */
5643 (void) XParseColor(display,windows->map_info->colormap,
5644 resource_info->pen_colors[pen_number],&color);
5645 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5646 (unsigned int) MaxColors,&color);
5647 windows->pixel_info->pen_colors[pen_number]=color;
5648 pen_id=(unsigned int) pen_number;
5649 draw_info.stencil=OpaqueStencil;
5650 break;
5651 }
5652 case DrawStippleCommand:
5653 {
5654 Image
5655 *stipple_image;
5656
5657 ImageInfo
5658 *image_info;
5659
5660 int
5661 status;
5662
5663 static char
5664 filename[MaxTextExtent] = "\0";
5665
5666 static const char
5667 *StipplesMenu[] =
5668 {
5669 "Brick",
5670 "Diagonal",
5671 "Scales",
5672 "Vertical",
5673 "Wavy",
5674 "Translucent",
5675 "Opaque",
5676 (char *) NULL,
5677 (char *) NULL,
5678 };
5679
5680 /*
5681 Select a command from the pop-up menu.
5682 */
5683 StipplesMenu[7]="Open...";
5684 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5685 command);
5686 if (entry < 0)
5687 break;
5688 if (stipple != (Pixmap) NULL)
5689 (void) XFreePixmap(display,stipple);
5690 stipple=(Pixmap) NULL;
cristy3ed852e2009-09-05 21:47:34 +00005691 if (entry != 7)
5692 {
5693 switch (entry)
5694 {
5695 case 0:
5696 {
5697 stipple=XCreateBitmapFromData(display,root_window,
5698 (char *) BricksBitmap,BricksWidth,BricksHeight);
5699 break;
5700 }
5701 case 1:
5702 {
5703 stipple=XCreateBitmapFromData(display,root_window,
5704 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5705 break;
5706 }
5707 case 2:
5708 {
5709 stipple=XCreateBitmapFromData(display,root_window,
5710 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5711 break;
5712 }
5713 case 3:
5714 {
5715 stipple=XCreateBitmapFromData(display,root_window,
5716 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5717 break;
5718 }
5719 case 4:
5720 {
5721 stipple=XCreateBitmapFromData(display,root_window,
5722 (char *) WavyBitmap,WavyWidth,WavyHeight);
5723 break;
5724 }
5725 case 5:
cristy3ed852e2009-09-05 21:47:34 +00005726 {
5727 stipple=XCreateBitmapFromData(display,root_window,
5728 (char *) HighlightBitmap,HighlightWidth,
5729 HighlightHeight);
5730 break;
5731 }
cristydd05beb2010-11-21 21:23:39 +00005732 case 6:
5733 default:
5734 {
5735 stipple=XCreateBitmapFromData(display,root_window,
5736 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5737 break;
5738 }
cristy3ed852e2009-09-05 21:47:34 +00005739 }
5740 break;
5741 }
5742 XFileBrowserWidget(display,windows,"Stipple",filename);
5743 if (*filename == '\0')
5744 break;
5745 /*
5746 Read image.
5747 */
5748 XSetCursorState(display,windows,MagickTrue);
5749 XCheckRefreshWindows(display,windows);
5750 image_info=AcquireImageInfo();
5751 (void) CopyMagickString(image_info->filename,filename,
5752 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00005753 stipple_image=ReadImage(image_info,exception);
5754 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00005755 XSetCursorState(display,windows,MagickFalse);
5756 if (stipple_image == (Image *) NULL)
5757 break;
5758 (void) AcquireUniqueFileResource(filename);
cristyb51dff52011-05-19 16:55:47 +00005759 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00005760 "xbm:%s",filename);
cristy051718b2011-08-28 22:49:25 +00005761 (void) WriteImage(image_info,stipple_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005762 stipple_image=DestroyImage(stipple_image);
5763 image_info=DestroyImageInfo(image_info);
5764 status=XReadBitmapFile(display,root_window,filename,&width,
5765 &height,&stipple,&x,&y);
5766 (void) RelinquishUniqueFileResource(filename);
5767 if ((status != BitmapSuccess) != 0)
5768 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5769 filename);
5770 break;
5771 }
5772 case DrawWidthCommand:
5773 {
5774 static char
5775 width[MaxTextExtent] = "0";
5776
5777 static const char
5778 *WidthsMenu[] =
5779 {
5780 "1",
5781 "2",
5782 "4",
5783 "8",
5784 "16",
5785 "Dialog...",
5786 (char *) NULL,
5787 };
5788
5789 /*
5790 Select a command from the pop-up menu.
5791 */
5792 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5793 command);
5794 if (entry < 0)
5795 break;
5796 if (entry != 5)
5797 {
cristydd05beb2010-11-21 21:23:39 +00005798 line_width=(unsigned int) StringToUnsignedLong(
5799 WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005800 break;
5801 }
5802 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5803 width);
5804 if (*width == '\0')
5805 break;
cristye27293e2009-12-18 02:53:20 +00005806 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005807 break;
5808 }
5809 case DrawUndoCommand:
5810 {
5811 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00005812 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005813 break;
5814 }
5815 case DrawHelpCommand:
5816 {
5817 XTextViewWidget(display,resource_info,windows,MagickFalse,
5818 "Help Viewer - Image Rotation",ImageDrawHelp);
5819 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5820 break;
5821 }
5822 case DrawDismissCommand:
5823 {
5824 /*
5825 Prematurely exit.
5826 */
5827 state|=EscapeState;
5828 state|=ExitState;
5829 break;
5830 }
5831 default:
5832 break;
5833 }
5834 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5835 continue;
5836 }
5837 switch (event.type)
5838 {
5839 case ButtonPress:
5840 {
5841 if (event.xbutton.button != Button1)
5842 break;
5843 if (event.xbutton.window != windows->image.id)
5844 break;
5845 /*
5846 exit loop.
5847 */
5848 x=event.xbutton.x;
5849 y=event.xbutton.y;
5850 state|=ExitState;
5851 break;
5852 }
5853 case ButtonRelease:
5854 break;
5855 case Expose:
5856 break;
5857 case KeyPress:
5858 {
5859 KeySym
5860 key_symbol;
5861
5862 if (event.xkey.window != windows->image.id)
5863 break;
5864 /*
5865 Respond to a user key press.
5866 */
5867 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5868 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5869 switch ((int) key_symbol)
5870 {
5871 case XK_Escape:
5872 case XK_F20:
5873 {
5874 /*
5875 Prematurely exit.
5876 */
5877 state|=EscapeState;
5878 state|=ExitState;
5879 break;
5880 }
5881 case XK_F1:
5882 case XK_Help:
5883 {
5884 XTextViewWidget(display,resource_info,windows,MagickFalse,
5885 "Help Viewer - Image Rotation",ImageDrawHelp);
5886 break;
5887 }
5888 default:
5889 {
5890 (void) XBell(display,0);
5891 break;
5892 }
5893 }
5894 break;
5895 }
5896 case MotionNotify:
5897 {
5898 /*
5899 Map and unmap Info widget as text cursor crosses its boundaries.
5900 */
5901 x=event.xmotion.x;
5902 y=event.xmotion.y;
5903 if (windows->info.mapped != MagickFalse)
5904 {
5905 if ((x < (int) (windows->info.x+windows->info.width)) &&
5906 (y < (int) (windows->info.y+windows->info.height)))
5907 (void) XWithdrawWindow(display,windows->info.id,
5908 windows->info.screen);
5909 }
5910 else
5911 if ((x > (int) (windows->info.x+windows->info.width)) ||
5912 (y > (int) (windows->info.y+windows->info.height)))
5913 (void) XMapWindow(display,windows->info.id);
5914 break;
5915 }
5916 }
5917 } while ((state & ExitState) == 0);
5918 (void) XSelectInput(display,windows->image.id,
5919 windows->image.attributes.event_mask);
5920 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5921 if ((state & EscapeState) != 0)
5922 break;
5923 /*
5924 Draw element as pointer moves until the button is released.
5925 */
5926 distance=0;
5927 degrees=0.0;
5928 line_info.x1=x;
5929 line_info.y1=y;
5930 line_info.x2=x;
5931 line_info.y2=y;
cristy49e2d862010-11-12 02:50:30 +00005932 rectangle_info.x=(ssize_t) x;
5933 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00005934 rectangle_info.width=0;
5935 rectangle_info.height=0;
5936 number_coordinates=1;
5937 coordinate_info->x=x;
5938 coordinate_info->y=y;
5939 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5940 state=DefaultState;
5941 do
5942 {
5943 switch (element)
5944 {
5945 case PointElement:
5946 default:
5947 {
5948 if (number_coordinates > 1)
5949 {
5950 (void) XDrawLines(display,windows->image.id,
5951 windows->image.highlight_context,coordinate_info,
5952 number_coordinates,CoordModeOrigin);
cristyb51dff52011-05-19 16:55:47 +00005953 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00005954 coordinate_info[number_coordinates-1].x,
5955 coordinate_info[number_coordinates-1].y);
5956 XInfoWidget(display,windows,text);
5957 }
5958 break;
5959 }
5960 case LineElement:
5961 {
5962 if (distance > 9)
5963 {
5964 /*
5965 Display angle of the line.
5966 */
5967 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5968 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00005969 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005970 (double) degrees);
5971 XInfoWidget(display,windows,text);
5972 XHighlightLine(display,windows->image.id,
5973 windows->image.highlight_context,&line_info);
5974 }
5975 else
5976 if (windows->info.mapped != MagickFalse)
5977 (void) XWithdrawWindow(display,windows->info.id,
5978 windows->info.screen);
5979 break;
5980 }
5981 case RectangleElement:
5982 case FillRectangleElement:
5983 {
5984 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5985 {
5986 /*
5987 Display info and draw drawing rectangle.
5988 */
cristyb51dff52011-05-19 16:55:47 +00005989 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005990 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005991 (double) rectangle_info.height,(double) rectangle_info.x,
5992 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005993 XInfoWidget(display,windows,text);
5994 XHighlightRectangle(display,windows->image.id,
5995 windows->image.highlight_context,&rectangle_info);
5996 }
5997 else
5998 if (windows->info.mapped != MagickFalse)
5999 (void) XWithdrawWindow(display,windows->info.id,
6000 windows->info.screen);
6001 break;
6002 }
6003 case CircleElement:
6004 case FillCircleElement:
6005 case EllipseElement:
6006 case FillEllipseElement:
6007 {
6008 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6009 {
6010 /*
6011 Display info and draw drawing rectangle.
6012 */
cristyb51dff52011-05-19 16:55:47 +00006013 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00006014 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00006015 (double) rectangle_info.height,(double) rectangle_info.x,
6016 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006017 XInfoWidget(display,windows,text);
6018 XHighlightEllipse(display,windows->image.id,
6019 windows->image.highlight_context,&rectangle_info);
6020 }
6021 else
6022 if (windows->info.mapped != MagickFalse)
6023 (void) XWithdrawWindow(display,windows->info.id,
6024 windows->info.screen);
6025 break;
6026 }
6027 case PolygonElement:
6028 case FillPolygonElement:
6029 {
6030 if (number_coordinates > 1)
6031 (void) XDrawLines(display,windows->image.id,
6032 windows->image.highlight_context,coordinate_info,
6033 number_coordinates,CoordModeOrigin);
6034 if (distance > 9)
6035 {
6036 /*
6037 Display angle of the line.
6038 */
6039 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6040 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00006041 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00006042 (double) degrees);
6043 XInfoWidget(display,windows,text);
6044 XHighlightLine(display,windows->image.id,
6045 windows->image.highlight_context,&line_info);
6046 }
6047 else
6048 if (windows->info.mapped != MagickFalse)
6049 (void) XWithdrawWindow(display,windows->info.id,
6050 windows->info.screen);
6051 break;
6052 }
6053 }
6054 /*
6055 Wait for next event.
6056 */
cristy6710d842011-10-20 23:23:00 +00006057 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00006058 switch (element)
6059 {
6060 case PointElement:
6061 default:
6062 {
6063 if (number_coordinates > 1)
6064 (void) XDrawLines(display,windows->image.id,
6065 windows->image.highlight_context,coordinate_info,
6066 number_coordinates,CoordModeOrigin);
6067 break;
6068 }
6069 case LineElement:
6070 {
6071 if (distance > 9)
6072 XHighlightLine(display,windows->image.id,
6073 windows->image.highlight_context,&line_info);
6074 break;
6075 }
6076 case RectangleElement:
6077 case FillRectangleElement:
6078 {
6079 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6080 XHighlightRectangle(display,windows->image.id,
6081 windows->image.highlight_context,&rectangle_info);
6082 break;
6083 }
6084 case CircleElement:
6085 case FillCircleElement:
6086 case EllipseElement:
6087 case FillEllipseElement:
6088 {
6089 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6090 XHighlightEllipse(display,windows->image.id,
6091 windows->image.highlight_context,&rectangle_info);
6092 break;
6093 }
6094 case PolygonElement:
6095 case FillPolygonElement:
6096 {
6097 if (number_coordinates > 1)
6098 (void) XDrawLines(display,windows->image.id,
6099 windows->image.highlight_context,coordinate_info,
6100 number_coordinates,CoordModeOrigin);
6101 if (distance > 9)
6102 XHighlightLine(display,windows->image.id,
6103 windows->image.highlight_context,&line_info);
6104 break;
6105 }
6106 }
6107 switch (event.type)
6108 {
6109 case ButtonPress:
6110 break;
6111 case ButtonRelease:
6112 {
6113 /*
6114 User has committed to element.
6115 */
6116 line_info.x2=event.xbutton.x;
6117 line_info.y2=event.xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00006118 rectangle_info.x=(ssize_t) event.xbutton.x;
6119 rectangle_info.y=(ssize_t) event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00006120 coordinate_info[number_coordinates].x=event.xbutton.x;
6121 coordinate_info[number_coordinates].y=event.xbutton.y;
6122 if (((element != PolygonElement) &&
6123 (element != FillPolygonElement)) || (distance <= 9))
6124 {
6125 state|=ExitState;
6126 break;
6127 }
6128 number_coordinates++;
6129 if (number_coordinates < (int) max_coordinates)
6130 {
6131 line_info.x1=event.xbutton.x;
6132 line_info.y1=event.xbutton.y;
6133 break;
6134 }
6135 max_coordinates<<=1;
6136 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6137 max_coordinates,sizeof(*coordinate_info));
6138 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006139 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00006140 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6141 break;
6142 }
6143 case Expose:
6144 break;
6145 case MotionNotify:
6146 {
6147 if (event.xmotion.window != windows->image.id)
6148 break;
6149 if (element != PointElement)
6150 {
6151 line_info.x2=event.xmotion.x;
6152 line_info.y2=event.xmotion.y;
cristy49e2d862010-11-12 02:50:30 +00006153 rectangle_info.x=(ssize_t) event.xmotion.x;
6154 rectangle_info.y=(ssize_t) event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00006155 break;
6156 }
6157 coordinate_info[number_coordinates].x=event.xbutton.x;
6158 coordinate_info[number_coordinates].y=event.xbutton.y;
6159 number_coordinates++;
6160 if (number_coordinates < (int) max_coordinates)
6161 break;
6162 max_coordinates<<=1;
6163 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6164 max_coordinates,sizeof(*coordinate_info));
6165 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006166 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00006167 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6168 break;
6169 }
6170 default:
6171 break;
6172 }
6173 /*
6174 Check boundary conditions.
6175 */
6176 if (line_info.x2 < 0)
6177 line_info.x2=0;
6178 else
6179 if (line_info.x2 > (int) windows->image.width)
6180 line_info.x2=(short) windows->image.width;
6181 if (line_info.y2 < 0)
6182 line_info.y2=0;
6183 else
6184 if (line_info.y2 > (int) windows->image.height)
6185 line_info.y2=(short) windows->image.height;
6186 distance=(unsigned int)
6187 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6188 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6189 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6190 ((state & ExitState) != 0))
6191 {
6192 if (rectangle_info.x < 0)
6193 rectangle_info.x=0;
6194 else
cristy49e2d862010-11-12 02:50:30 +00006195 if (rectangle_info.x > (ssize_t) windows->image.width)
cristybb503372010-05-27 20:51:26 +00006196 rectangle_info.x=(ssize_t) windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +00006197 if ((int) rectangle_info.x < x)
6198 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6199 else
6200 {
6201 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00006202 rectangle_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00006203 }
6204 if (rectangle_info.y < 0)
6205 rectangle_info.y=0;
6206 else
cristy49e2d862010-11-12 02:50:30 +00006207 if (rectangle_info.y > (ssize_t) windows->image.height)
cristybb503372010-05-27 20:51:26 +00006208 rectangle_info.y=(ssize_t) windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +00006209 if ((int) rectangle_info.y < y)
6210 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6211 else
6212 {
6213 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00006214 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00006215 }
6216 }
6217 } while ((state & ExitState) == 0);
6218 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6219 if ((element == PointElement) || (element == PolygonElement) ||
6220 (element == FillPolygonElement))
6221 {
6222 /*
6223 Determine polygon bounding box.
6224 */
cristy49e2d862010-11-12 02:50:30 +00006225 rectangle_info.x=(ssize_t) coordinate_info->x;
6226 rectangle_info.y=(ssize_t) coordinate_info->y;
cristy3ed852e2009-09-05 21:47:34 +00006227 x=coordinate_info->x;
6228 y=coordinate_info->y;
6229 for (i=1; i < number_coordinates; i++)
6230 {
6231 if (coordinate_info[i].x > x)
6232 x=coordinate_info[i].x;
6233 if (coordinate_info[i].y > y)
6234 y=coordinate_info[i].y;
cristy49e2d862010-11-12 02:50:30 +00006235 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6236 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6237 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6238 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
cristy3ed852e2009-09-05 21:47:34 +00006239 }
cristybb503372010-05-27 20:51:26 +00006240 rectangle_info.width=(size_t) (x-rectangle_info.x);
6241 rectangle_info.height=(size_t) (y-rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006242 for (i=0; i < number_coordinates; i++)
6243 {
6244 coordinate_info[i].x-=rectangle_info.x;
6245 coordinate_info[i].y-=rectangle_info.y;
6246 }
6247 }
6248 else
6249 if (distance <= 9)
6250 continue;
6251 else
6252 if ((element == RectangleElement) ||
6253 (element == CircleElement) || (element == EllipseElement))
6254 {
6255 rectangle_info.width--;
6256 rectangle_info.height--;
6257 }
6258 /*
6259 Drawing is relative to image configuration.
6260 */
6261 draw_info.x=(int) rectangle_info.x;
6262 draw_info.y=(int) rectangle_info.y;
6263 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
cristy051718b2011-08-28 22:49:25 +00006264 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006265 width=(unsigned int) (*image)->columns;
6266 height=(unsigned int) (*image)->rows;
6267 x=0;
6268 y=0;
6269 if (windows->image.crop_geometry != (char *) NULL)
6270 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6271 draw_info.x+=windows->image.x-(line_width/2);
6272 if (draw_info.x < 0)
6273 draw_info.x=0;
6274 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6275 draw_info.y+=windows->image.y-(line_width/2);
6276 if (draw_info.y < 0)
6277 draw_info.y=0;
6278 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6279 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6280 if (draw_info.width > (unsigned int) (*image)->columns)
6281 draw_info.width=(unsigned int) (*image)->columns;
6282 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6283 if (draw_info.height > (unsigned int) (*image)->rows)
6284 draw_info.height=(unsigned int) (*image)->rows;
cristyb51dff52011-05-19 16:55:47 +00006285 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00006286 width*draw_info.width/windows->image.ximage->width,
6287 height*draw_info.height/windows->image.ximage->height,
6288 draw_info.x+x,draw_info.y+y);
6289 /*
6290 Initialize drawing attributes.
6291 */
6292 draw_info.degrees=0.0;
6293 draw_info.element=element;
6294 draw_info.stipple=stipple;
6295 draw_info.line_width=line_width;
6296 draw_info.line_info=line_info;
6297 if (line_info.x1 > (int) (line_width/2))
6298 draw_info.line_info.x1=(short) line_width/2;
6299 if (line_info.y1 > (int) (line_width/2))
6300 draw_info.line_info.y1=(short) line_width/2;
6301 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6302 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6303 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6304 {
6305 draw_info.line_info.x2=(-draw_info.line_info.x2);
6306 draw_info.line_info.y2=(-draw_info.line_info.y2);
6307 }
6308 if (draw_info.line_info.x2 < 0)
6309 {
6310 draw_info.line_info.x2=(-draw_info.line_info.x2);
6311 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6312 }
6313 if (draw_info.line_info.y2 < 0)
6314 {
6315 draw_info.line_info.y2=(-draw_info.line_info.y2);
6316 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6317 }
6318 draw_info.rectangle_info=rectangle_info;
cristy49e2d862010-11-12 02:50:30 +00006319 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006320 draw_info.rectangle_info.x=(ssize_t) line_width/2;
cristy49e2d862010-11-12 02:50:30 +00006321 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006322 draw_info.rectangle_info.y=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006323 draw_info.number_coordinates=(unsigned int) number_coordinates;
6324 draw_info.coordinate_info=coordinate_info;
6325 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6326 /*
6327 Draw element on image.
6328 */
6329 XSetCursorState(display,windows,MagickTrue);
6330 XCheckRefreshWindows(display,windows);
cristy6710d842011-10-20 23:23:00 +00006331 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006332 XSetCursorState(display,windows,MagickFalse);
6333 /*
6334 Update image colormap and return to image drawing.
6335 */
cristy6710d842011-10-20 23:23:00 +00006336 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006337 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006338 }
6339 XSetCursorState(display,windows,MagickFalse);
6340 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6341 return(status != 0 ? MagickTrue : MagickFalse);
6342}
6343
6344/*
6345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6346% %
6347% %
6348% %
6349+ X D r a w P a n R e c t a n g l e %
6350% %
6351% %
6352% %
6353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6354%
6355% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6356% displays a zoom image and the rectangle shows which portion of the image is
6357% displayed in the Image window.
6358%
6359% The format of the XDrawPanRectangle method is:
6360%
6361% XDrawPanRectangle(Display *display,XWindows *windows)
6362%
6363% A description of each parameter follows:
6364%
6365% o display: Specifies a connection to an X server; returned from
6366% XOpenDisplay.
6367%
6368% o windows: Specifies a pointer to a XWindows structure.
6369%
6370*/
6371static void XDrawPanRectangle(Display *display,XWindows *windows)
6372{
6373 MagickRealType
6374 scale_factor;
6375
6376 RectangleInfo
6377 highlight_info;
6378
6379 /*
6380 Determine dimensions of the panning rectangle.
6381 */
6382 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
cristy49e2d862010-11-12 02:50:30 +00006383 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006384 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6385 scale_factor=(MagickRealType)
6386 windows->pan.height/windows->image.ximage->height;
cristy49e2d862010-11-12 02:50:30 +00006387 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006388 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6389 /*
6390 Display the panning rectangle.
6391 */
6392 (void) XClearWindow(display,windows->pan.id);
6393 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6394 &highlight_info);
6395}
6396
6397/*
6398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6399% %
6400% %
6401% %
6402+ X I m a g e C a c h e %
6403% %
6404% %
6405% %
6406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6407%
6408% XImageCache() handles the creation, manipulation, and destruction of the
6409% image cache (undo and redo buffers).
6410%
6411% The format of the XImageCache method is:
6412%
6413% void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006414% XWindows *windows,const CommandType command,Image **image,
6415% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006416%
6417% A description of each parameter follows:
6418%
6419% o display: Specifies a connection to an X server; returned from
6420% XOpenDisplay.
6421%
6422% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6423%
6424% o windows: Specifies a pointer to a XWindows structure.
6425%
6426% o command: Specifies a command to perform.
6427%
cristya9a86bb2011-01-13 01:11:00 +00006428% o image: the image; XImageCache may transform the image and return a new
6429% image pointer.
cristy3ed852e2009-09-05 21:47:34 +00006430%
cristy051718b2011-08-28 22:49:25 +00006431% o exception: return any errors or warnings in this structure.
6432%
cristy3ed852e2009-09-05 21:47:34 +00006433*/
6434static void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006435 XWindows *windows,const CommandType command,Image **image,
6436 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006437{
6438 Image
6439 *cache_image;
6440
6441 static Image
6442 *redo_image = (Image *) NULL,
6443 *undo_image = (Image *) NULL;
6444
6445 switch (command)
6446 {
6447 case FreeBuffersCommand:
6448 {
6449 /*
6450 Free memory from the undo and redo cache.
6451 */
6452 while (undo_image != (Image *) NULL)
6453 {
6454 cache_image=undo_image;
6455 undo_image=GetPreviousImageInList(undo_image);
6456 cache_image->list=DestroyImage(cache_image->list);
6457 cache_image=DestroyImage(cache_image);
6458 }
6459 undo_image=NewImageList();
6460 if (redo_image != (Image *) NULL)
6461 redo_image=DestroyImage(redo_image);
6462 redo_image=NewImageList();
6463 return;
6464 }
6465 case UndoCommand:
6466 {
cristya9a86bb2011-01-13 01:11:00 +00006467 char
6468 image_geometry[MaxTextExtent];
6469
cristy3ed852e2009-09-05 21:47:34 +00006470 /*
6471 Undo the last image transformation.
6472 */
6473 if (undo_image == (Image *) NULL)
6474 {
6475 (void) XBell(display,0);
6476 return;
6477 }
6478 cache_image=undo_image;
6479 undo_image=GetPreviousImageInList(undo_image);
6480 windows->image.window_changes.width=(int) cache_image->columns;
6481 windows->image.window_changes.height=(int) cache_image->rows;
cristyb51dff52011-05-19 16:55:47 +00006482 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristya9a86bb2011-01-13 01:11:00 +00006483 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00006484 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6485 exception);
cristy3ed852e2009-09-05 21:47:34 +00006486 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00006487 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6488 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00006489 windows->image.crop_geometry=cache_image->geometry;
6490 if (redo_image != (Image *) NULL)
6491 redo_image=DestroyImage(redo_image);
6492 redo_image=(*image);
6493 *image=cache_image->list;
6494 cache_image=DestroyImage(cache_image);
6495 if (windows->image.orphan != MagickFalse)
6496 return;
cristy6710d842011-10-20 23:23:00 +00006497 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006498 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006499 return;
6500 }
6501 case CutCommand:
6502 case PasteCommand:
6503 case ApplyCommand:
6504 case HalfSizeCommand:
6505 case OriginalSizeCommand:
6506 case DoubleSizeCommand:
6507 case ResizeCommand:
6508 case TrimCommand:
6509 case CropCommand:
6510 case ChopCommand:
6511 case FlipCommand:
6512 case FlopCommand:
6513 case RotateRightCommand:
6514 case RotateLeftCommand:
6515 case RotateCommand:
6516 case ShearCommand:
6517 case RollCommand:
6518 case NegateCommand:
6519 case ContrastStretchCommand:
6520 case SigmoidalContrastCommand:
6521 case NormalizeCommand:
6522 case EqualizeCommand:
6523 case HueCommand:
6524 case SaturationCommand:
6525 case BrightnessCommand:
6526 case GammaCommand:
6527 case SpiffCommand:
6528 case DullCommand:
6529 case GrayscaleCommand:
6530 case MapCommand:
6531 case QuantizeCommand:
6532 case DespeckleCommand:
6533 case EmbossCommand:
6534 case ReduceNoiseCommand:
6535 case AddNoiseCommand:
6536 case SharpenCommand:
6537 case BlurCommand:
6538 case ThresholdCommand:
6539 case EdgeDetectCommand:
6540 case SpreadCommand:
6541 case ShadeCommand:
6542 case RaiseCommand:
6543 case SegmentCommand:
6544 case SolarizeCommand:
6545 case SepiaToneCommand:
6546 case SwirlCommand:
6547 case ImplodeCommand:
6548 case VignetteCommand:
6549 case WaveCommand:
6550 case OilPaintCommand:
6551 case CharcoalDrawCommand:
6552 case AnnotateCommand:
6553 case AddBorderCommand:
6554 case AddFrameCommand:
6555 case CompositeCommand:
6556 case CommentCommand:
6557 case LaunchCommand:
6558 case RegionofInterestCommand:
6559 case SaveToUndoBufferCommand:
6560 case RedoCommand:
6561 {
6562 Image
6563 *previous_image;
6564
cristybb503372010-05-27 20:51:26 +00006565 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00006566 bytes;
6567
cristy101ab702011-10-13 13:06:32 +00006568 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
cristy3ed852e2009-09-05 21:47:34 +00006569 if (undo_image != (Image *) NULL)
6570 {
6571 /*
cristya9a86bb2011-01-13 01:11:00 +00006572 Ensure the undo cache has enough memory available.
cristy3ed852e2009-09-05 21:47:34 +00006573 */
6574 previous_image=undo_image;
6575 while (previous_image != (Image *) NULL)
6576 {
6577 bytes+=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006578 sizeof(PixelInfo);
cristybb503372010-05-27 20:51:26 +00006579 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006580 {
6581 previous_image=GetPreviousImageInList(previous_image);
6582 continue;
6583 }
6584 bytes-=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006585 sizeof(PixelInfo);
cristy3ed852e2009-09-05 21:47:34 +00006586 if (previous_image == undo_image)
6587 undo_image=NewImageList();
6588 else
6589 previous_image->next->previous=NewImageList();
6590 break;
6591 }
6592 while (previous_image != (Image *) NULL)
6593 {
6594 /*
6595 Delete any excess memory from undo cache.
6596 */
6597 cache_image=previous_image;
6598 previous_image=GetPreviousImageInList(previous_image);
6599 cache_image->list=DestroyImage(cache_image->list);
6600 cache_image=DestroyImage(cache_image);
6601 }
6602 }
cristybb503372010-05-27 20:51:26 +00006603 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006604 break;
6605 /*
6606 Save image before transformations are applied.
6607 */
cristy9950d572011-10-01 18:22:35 +00006608 cache_image=AcquireImage((ImageInfo *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +00006609 if (cache_image == (Image *) NULL)
6610 break;
6611 XSetCursorState(display,windows,MagickTrue);
6612 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00006613 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00006614 XSetCursorState(display,windows,MagickFalse);
6615 if (cache_image->list == (Image *) NULL)
6616 {
6617 cache_image=DestroyImage(cache_image);
6618 break;
6619 }
cristybb503372010-05-27 20:51:26 +00006620 cache_image->columns=(size_t) windows->image.ximage->width;
6621 cache_image->rows=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006622 cache_image->geometry=windows->image.crop_geometry;
6623 if (windows->image.crop_geometry != (char *) NULL)
6624 {
6625 cache_image->geometry=AcquireString((char *) NULL);
6626 (void) CopyMagickString(cache_image->geometry,
6627 windows->image.crop_geometry,MaxTextExtent);
6628 }
6629 if (undo_image == (Image *) NULL)
6630 {
6631 undo_image=cache_image;
6632 break;
6633 }
6634 undo_image->next=cache_image;
6635 undo_image->next->previous=undo_image;
6636 undo_image=undo_image->next;
6637 break;
6638 }
6639 default:
6640 break;
6641 }
6642 if (command == RedoCommand)
6643 {
6644 /*
6645 Redo the last image transformation.
6646 */
6647 if (redo_image == (Image *) NULL)
6648 {
6649 (void) XBell(display,0);
6650 return;
6651 }
6652 windows->image.window_changes.width=(int) redo_image->columns;
6653 windows->image.window_changes.height=(int) redo_image->rows;
6654 if (windows->image.crop_geometry != (char *) NULL)
6655 windows->image.crop_geometry=(char *)
6656 RelinquishMagickMemory(windows->image.crop_geometry);
6657 windows->image.crop_geometry=redo_image->geometry;
6658 *image=DestroyImage(*image);
6659 *image=redo_image;
6660 redo_image=NewImageList();
6661 if (windows->image.orphan != MagickFalse)
6662 return;
cristy6710d842011-10-20 23:23:00 +00006663 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006664 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006665 return;
6666 }
6667 if (command != InfoCommand)
6668 return;
6669 /*
6670 Display image info.
6671 */
6672 XSetCursorState(display,windows,MagickTrue);
6673 XCheckRefreshWindows(display,windows);
cristy6710d842011-10-20 23:23:00 +00006674 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006675 XSetCursorState(display,windows,MagickFalse);
6676}
6677
6678/*
6679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6680% %
6681% %
6682% %
6683+ X I m a g e W i n d o w C o m m a n d %
6684% %
6685% %
6686% %
6687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6688%
6689% XImageWindowCommand() makes a transform to the image or Image window as
6690% specified by a user menu button or keyboard command.
6691%
cristy051718b2011-08-28 22:49:25 +00006692% The format of the XImageWindowCommand method is:
cristy3ed852e2009-09-05 21:47:34 +00006693%
6694% CommandType XImageWindowCommand(Display *display,
6695% XResourceInfo *resource_info,XWindows *windows,
cristy051718b2011-08-28 22:49:25 +00006696% const MagickStatusType state,KeySym key_symbol,Image **image,
6697% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006698%
6699% A description of each parameter follows:
6700%
6701% o nexus: Method XImageWindowCommand returns an image when the
6702% user chooses 'Open Image' from the command menu. Otherwise a null
6703% image is returned.
6704%
6705% o display: Specifies a connection to an X server; returned from
6706% XOpenDisplay.
6707%
6708% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6709%
6710% o windows: Specifies a pointer to a XWindows structure.
6711%
6712% o state: key mask.
6713%
6714% o key_symbol: Specifies a command to perform.
6715%
cristy051718b2011-08-28 22:49:25 +00006716% o image: the image; XImageWIndowCommand may transform the image and
6717% return a new image pointer.
6718%
6719% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00006720%
6721*/
6722static CommandType XImageWindowCommand(Display *display,
6723 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
cristy051718b2011-08-28 22:49:25 +00006724 KeySym key_symbol,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006725{
6726 static char
6727 delta[MaxTextExtent] = "";
6728
6729 static const char
6730 Digits[] = "01234567890";
6731
6732 static KeySym
6733 last_symbol = XK_0;
6734
6735 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6736 {
6737 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6738 {
6739 *delta='\0';
6740 resource_info->quantum=1;
6741 }
6742 last_symbol=key_symbol;
6743 delta[strlen(delta)+1]='\0';
6744 delta[strlen(delta)]=Digits[key_symbol-XK_0];
cristyf2f27272009-12-17 14:48:46 +00006745 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006746 return(NullCommand);
6747 }
6748 last_symbol=key_symbol;
6749 if (resource_info->immutable)
6750 {
6751 /*
6752 Virtual image window has a restricted command set.
6753 */
6754 switch (key_symbol)
6755 {
6756 case XK_question:
6757 return(InfoCommand);
6758 case XK_p:
6759 case XK_Print:
6760 return(PrintCommand);
6761 case XK_space:
6762 return(NextCommand);
6763 case XK_q:
6764 case XK_Escape:
6765 return(QuitCommand);
6766 default:
6767 break;
6768 }
6769 return(NullCommand);
6770 }
6771 switch ((int) key_symbol)
6772 {
6773 case XK_o:
6774 {
6775 if ((state & ControlMask) == 0)
6776 break;
6777 return(OpenCommand);
6778 }
6779 case XK_space:
6780 return(NextCommand);
6781 case XK_BackSpace:
6782 return(FormerCommand);
6783 case XK_s:
6784 {
6785 if ((state & Mod1Mask) != 0)
6786 return(SwirlCommand);
6787 if ((state & ControlMask) == 0)
6788 return(ShearCommand);
6789 return(SaveCommand);
6790 }
6791 case XK_p:
6792 case XK_Print:
6793 {
6794 if ((state & Mod1Mask) != 0)
6795 return(OilPaintCommand);
6796 if ((state & Mod4Mask) != 0)
6797 return(ColorCommand);
6798 if ((state & ControlMask) == 0)
6799 return(NullCommand);
6800 return(PrintCommand);
6801 }
6802 case XK_d:
6803 {
6804 if ((state & Mod4Mask) != 0)
6805 return(DrawCommand);
6806 if ((state & ControlMask) == 0)
6807 return(NullCommand);
6808 return(DeleteCommand);
6809 }
6810 case XK_Select:
6811 {
6812 if ((state & ControlMask) == 0)
6813 return(NullCommand);
6814 return(SelectCommand);
6815 }
6816 case XK_n:
6817 {
6818 if ((state & ControlMask) == 0)
6819 return(NullCommand);
6820 return(NewCommand);
6821 }
6822 case XK_q:
6823 case XK_Escape:
6824 return(QuitCommand);
6825 case XK_z:
6826 case XK_Undo:
6827 {
6828 if ((state & ControlMask) == 0)
6829 return(NullCommand);
6830 return(UndoCommand);
6831 }
6832 case XK_r:
6833 case XK_Redo:
6834 {
6835 if ((state & ControlMask) == 0)
6836 return(RollCommand);
6837 return(RedoCommand);
6838 }
6839 case XK_x:
6840 {
6841 if ((state & ControlMask) == 0)
6842 return(NullCommand);
6843 return(CutCommand);
6844 }
6845 case XK_c:
6846 {
6847 if ((state & Mod1Mask) != 0)
6848 return(CharcoalDrawCommand);
6849 if ((state & ControlMask) == 0)
6850 return(CropCommand);
6851 return(CopyCommand);
6852 }
6853 case XK_v:
6854 case XK_Insert:
6855 {
6856 if ((state & Mod4Mask) != 0)
6857 return(CompositeCommand);
6858 if ((state & ControlMask) == 0)
6859 return(FlipCommand);
6860 return(PasteCommand);
6861 }
6862 case XK_less:
6863 return(HalfSizeCommand);
6864 case XK_minus:
6865 return(OriginalSizeCommand);
6866 case XK_greater:
6867 return(DoubleSizeCommand);
6868 case XK_percent:
6869 return(ResizeCommand);
6870 case XK_at:
6871 return(RefreshCommand);
6872 case XK_bracketleft:
6873 return(ChopCommand);
6874 case XK_h:
6875 return(FlopCommand);
6876 case XK_slash:
6877 return(RotateRightCommand);
6878 case XK_backslash:
6879 return(RotateLeftCommand);
6880 case XK_asterisk:
6881 return(RotateCommand);
6882 case XK_t:
6883 return(TrimCommand);
6884 case XK_H:
6885 return(HueCommand);
6886 case XK_S:
6887 return(SaturationCommand);
6888 case XK_L:
6889 return(BrightnessCommand);
6890 case XK_G:
6891 return(GammaCommand);
6892 case XK_C:
6893 return(SpiffCommand);
6894 case XK_Z:
6895 return(DullCommand);
6896 case XK_N:
6897 return(NormalizeCommand);
6898 case XK_equal:
6899 return(EqualizeCommand);
6900 case XK_asciitilde:
6901 return(NegateCommand);
6902 case XK_period:
6903 return(GrayscaleCommand);
6904 case XK_numbersign:
6905 return(QuantizeCommand);
6906 case XK_F2:
6907 return(DespeckleCommand);
6908 case XK_F3:
6909 return(EmbossCommand);
6910 case XK_F4:
6911 return(ReduceNoiseCommand);
6912 case XK_F5:
6913 return(AddNoiseCommand);
6914 case XK_F6:
6915 return(SharpenCommand);
6916 case XK_F7:
6917 return(BlurCommand);
6918 case XK_F8:
6919 return(ThresholdCommand);
6920 case XK_F9:
6921 return(EdgeDetectCommand);
6922 case XK_F10:
6923 return(SpreadCommand);
6924 case XK_F11:
6925 return(ShadeCommand);
6926 case XK_F12:
6927 return(RaiseCommand);
6928 case XK_F13:
6929 return(SegmentCommand);
6930 case XK_i:
6931 {
6932 if ((state & Mod1Mask) == 0)
6933 return(NullCommand);
6934 return(ImplodeCommand);
6935 }
6936 case XK_w:
6937 {
6938 if ((state & Mod1Mask) == 0)
6939 return(NullCommand);
6940 return(WaveCommand);
6941 }
6942 case XK_m:
6943 {
6944 if ((state & Mod4Mask) == 0)
6945 return(NullCommand);
6946 return(MatteCommand);
6947 }
6948 case XK_b:
6949 {
6950 if ((state & Mod4Mask) == 0)
6951 return(NullCommand);
6952 return(AddBorderCommand);
6953 }
6954 case XK_f:
6955 {
6956 if ((state & Mod4Mask) == 0)
6957 return(NullCommand);
6958 return(AddFrameCommand);
6959 }
6960 case XK_exclam:
6961 {
6962 if ((state & Mod4Mask) == 0)
6963 return(NullCommand);
6964 return(CommentCommand);
6965 }
6966 case XK_a:
6967 {
6968 if ((state & Mod1Mask) != 0)
6969 return(ApplyCommand);
6970 if ((state & Mod4Mask) != 0)
6971 return(AnnotateCommand);
6972 if ((state & ControlMask) == 0)
6973 return(NullCommand);
6974 return(RegionofInterestCommand);
6975 }
6976 case XK_question:
6977 return(InfoCommand);
6978 case XK_plus:
6979 return(ZoomCommand);
6980 case XK_P:
6981 {
6982 if ((state & ShiftMask) == 0)
6983 return(NullCommand);
6984 return(ShowPreviewCommand);
6985 }
6986 case XK_Execute:
6987 return(LaunchCommand);
6988 case XK_F1:
6989 return(HelpCommand);
6990 case XK_Find:
6991 return(BrowseDocumentationCommand);
6992 case XK_Menu:
6993 {
6994 (void) XMapRaised(display,windows->command.id);
6995 return(NullCommand);
6996 }
6997 case XK_Next:
6998 case XK_Prior:
6999 case XK_Home:
7000 case XK_KP_Home:
7001 {
7002 XTranslateImage(display,windows,*image,key_symbol);
7003 return(NullCommand);
7004 }
7005 case XK_Up:
7006 case XK_KP_Up:
7007 case XK_Down:
7008 case XK_KP_Down:
7009 case XK_Left:
7010 case XK_KP_Left:
7011 case XK_Right:
7012 case XK_KP_Right:
7013 {
7014 if ((state & Mod1Mask) != 0)
7015 {
7016 RectangleInfo
7017 crop_info;
7018
7019 /*
7020 Trim one pixel from edge of image.
7021 */
7022 crop_info.x=0;
7023 crop_info.y=0;
cristybb503372010-05-27 20:51:26 +00007024 crop_info.width=(size_t) windows->image.ximage->width;
7025 crop_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007026 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
7027 {
7028 if (resource_info->quantum >= (int) crop_info.height)
7029 resource_info->quantum=(int) crop_info.height-1;
7030 crop_info.height-=resource_info->quantum;
7031 }
7032 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
7033 {
7034 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
7035 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
7036 crop_info.y+=resource_info->quantum;
7037 crop_info.height-=resource_info->quantum;
7038 }
7039 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7040 {
7041 if (resource_info->quantum >= (int) crop_info.width)
7042 resource_info->quantum=(int) crop_info.width-1;
7043 crop_info.width-=resource_info->quantum;
7044 }
7045 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7046 {
7047 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7048 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7049 crop_info.x+=resource_info->quantum;
7050 crop_info.width-=resource_info->quantum;
7051 }
7052 if ((int) (windows->image.x+windows->image.width) >
7053 (int) crop_info.width)
7054 windows->image.x=(int) (crop_info.width-windows->image.width);
7055 if ((int) (windows->image.y+windows->image.height) >
7056 (int) crop_info.height)
7057 windows->image.y=(int) (crop_info.height-windows->image.height);
7058 XSetCropGeometry(display,windows,&crop_info,*image);
7059 windows->image.window_changes.width=(int) crop_info.width;
7060 windows->image.window_changes.height=(int) crop_info.height;
7061 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
cristy051718b2011-08-28 22:49:25 +00007062 (void) XConfigureImage(display,resource_info,windows,*image,
7063 exception);
cristy3ed852e2009-09-05 21:47:34 +00007064 return(NullCommand);
7065 }
7066 XTranslateImage(display,windows,*image,key_symbol);
7067 return(NullCommand);
7068 }
7069 default:
7070 return(NullCommand);
7071 }
7072 return(NullCommand);
7073}
7074
7075/*
7076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7077% %
7078% %
7079% %
7080+ X M a g i c k C o m m a n d %
7081% %
7082% %
7083% %
7084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7085%
7086% XMagickCommand() makes a transform to the image or Image window as
7087% specified by a user menu button or keyboard command.
7088%
7089% The format of the XMagickCommand method is:
7090%
7091% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007092% XWindows *windows,const CommandType command,Image **image,
7093% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007094%
7095% A description of each parameter follows:
7096%
cristy3ed852e2009-09-05 21:47:34 +00007097% o display: Specifies a connection to an X server; returned from
7098% XOpenDisplay.
7099%
7100% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7101%
7102% o windows: Specifies a pointer to a XWindows structure.
7103%
7104% o command: Specifies a command to perform.
7105%
cristy051718b2011-08-28 22:49:25 +00007106% o image: the image; XMagickCommand may transform the image and return a
7107% new image pointer.
7108%
7109% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00007110%
7111*/
7112static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007113 XWindows *windows,const CommandType command,Image **image,
7114 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007115{
7116 char
7117 filename[MaxTextExtent],
7118 geometry[MaxTextExtent],
7119 modulate_factors[MaxTextExtent];
7120
7121 GeometryInfo
7122 geometry_info;
7123
7124 Image
7125 *nexus;
7126
7127 ImageInfo
7128 *image_info;
7129
7130 int
7131 x,
7132 y;
7133
7134 MagickStatusType
7135 flags,
7136 status;
7137
7138 QuantizeInfo
7139 quantize_info;
7140
7141 RectangleInfo
7142 page_geometry;
7143
7144 register int
7145 i;
7146
7147 static char
7148 color[MaxTextExtent] = "gray";
7149
7150 unsigned int
7151 height,
7152 width;
7153
7154 /*
7155 Process user command.
7156 */
7157 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007158 XImageCache(display,resource_info,windows,command,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007159 nexus=NewImageList();
7160 windows->image.window_changes.width=windows->image.ximage->width;
7161 windows->image.window_changes.height=windows->image.ximage->height;
7162 image_info=CloneImageInfo(resource_info->image_info);
7163 SetGeometryInfo(&geometry_info);
7164 GetQuantizeInfo(&quantize_info);
7165 switch (command)
7166 {
7167 case OpenCommand:
7168 {
7169 /*
7170 Load image.
7171 */
7172 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7173 break;
7174 }
7175 case NextCommand:
7176 {
7177 /*
7178 Display next image.
7179 */
7180 for (i=0; i < resource_info->quantum; i++)
7181 XClientMessage(display,windows->image.id,windows->im_protocols,
7182 windows->im_next_image,CurrentTime);
7183 break;
7184 }
7185 case FormerCommand:
7186 {
7187 /*
7188 Display former image.
7189 */
7190 for (i=0; i < resource_info->quantum; i++)
7191 XClientMessage(display,windows->image.id,windows->im_protocols,
7192 windows->im_former_image,CurrentTime);
7193 break;
7194 }
7195 case SelectCommand:
7196 {
7197 int
7198 status;
7199
7200 /*
7201 Select image.
7202 */
7203 status=chdir(resource_info->home_directory);
7204 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00007205 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7206 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +00007207 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7208 break;
7209 }
7210 case SaveCommand:
7211 {
7212 /*
7213 Save image.
7214 */
cristy051718b2011-08-28 22:49:25 +00007215 status=XSaveImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007216 if (status == MagickFalse)
7217 {
cristyc663dbd2011-09-16 19:43:14 +00007218 char
7219 message[MaxTextExtent];
7220
7221 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7222 exception->reason != (char *) NULL ? exception->reason : "",
7223 exception->description != (char *) NULL ? exception->description :
7224 "");
7225 XNoticeWidget(display,windows,"Unable to save file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007226 break;
7227 }
7228 break;
7229 }
7230 case PrintCommand:
7231 {
7232 /*
7233 Print image.
7234 */
cristy051718b2011-08-28 22:49:25 +00007235 status=XPrintImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007236 if (status == MagickFalse)
7237 {
cristyc663dbd2011-09-16 19:43:14 +00007238 char
7239 message[MaxTextExtent];
7240
7241 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7242 exception->reason != (char *) NULL ? exception->reason : "",
7243 exception->description != (char *) NULL ? exception->description :
7244 "");
7245 XNoticeWidget(display,windows,"Unable to print file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007246 break;
7247 }
7248 break;
7249 }
7250 case DeleteCommand:
7251 {
7252 static char
7253 filename[MaxTextExtent] = "\0";
7254
7255 /*
7256 Delete image file.
7257 */
7258 XFileBrowserWidget(display,windows,"Delete",filename);
7259 if (*filename == '\0')
7260 break;
cristy18c6c272011-09-23 14:40:37 +00007261 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00007262 if (status != MagickFalse)
7263 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7264 break;
7265 }
7266 case NewCommand:
7267 {
7268 int
7269 status;
7270
7271 static char
7272 color[MaxTextExtent] = "gray",
7273 geometry[MaxTextExtent] = "640x480";
7274
7275 static const char
7276 *format = "gradient";
7277
7278 /*
7279 Query user for canvas geometry.
7280 */
7281 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7282 geometry);
7283 if (*geometry == '\0')
7284 break;
7285 if (status == 0)
7286 format="xc";
7287 XColorBrowserWidget(display,windows,"Select",color);
7288 if (*color == '\0')
7289 break;
7290 /*
7291 Create canvas.
7292 */
cristyb51dff52011-05-19 16:55:47 +00007293 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007294 "%s:%s",format,color);
7295 (void) CloneString(&image_info->size,geometry);
cristy051718b2011-08-28 22:49:25 +00007296 nexus=ReadImage(image_info,exception);
7297 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007298 XClientMessage(display,windows->image.id,windows->im_protocols,
7299 windows->im_next_image,CurrentTime);
7300 break;
7301 }
7302 case VisualDirectoryCommand:
7303 {
7304 /*
7305 Visual Image directory.
7306 */
cristy051718b2011-08-28 22:49:25 +00007307 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00007308 break;
7309 }
7310 case QuitCommand:
7311 {
7312 /*
7313 exit program.
7314 */
7315 if (resource_info->confirm_exit == MagickFalse)
7316 XClientMessage(display,windows->image.id,windows->im_protocols,
7317 windows->im_exit,CurrentTime);
7318 else
7319 {
7320 int
7321 status;
7322
7323 /*
7324 Confirm program exit.
7325 */
7326 status=XConfirmWidget(display,windows,"Do you really want to exit",
7327 resource_info->client_name);
7328 if (status > 0)
7329 XClientMessage(display,windows->image.id,windows->im_protocols,
7330 windows->im_exit,CurrentTime);
7331 }
7332 break;
7333 }
7334 case CutCommand:
7335 {
7336 /*
7337 Cut image.
7338 */
cristy051718b2011-08-28 22:49:25 +00007339 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00007340 break;
7341 }
7342 case CopyCommand:
7343 {
7344 /*
7345 Copy image.
7346 */
cristy051718b2011-08-28 22:49:25 +00007347 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7348 exception);
cristy3ed852e2009-09-05 21:47:34 +00007349 break;
7350 }
7351 case PasteCommand:
7352 {
7353 /*
7354 Paste image.
7355 */
cristy051718b2011-08-28 22:49:25 +00007356 status=XPasteImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007357 if (status == MagickFalse)
7358 {
7359 XNoticeWidget(display,windows,"Unable to paste X image",
7360 (*image)->filename);
7361 break;
7362 }
7363 break;
7364 }
7365 case HalfSizeCommand:
7366 {
7367 /*
7368 Half image size.
7369 */
7370 windows->image.window_changes.width=windows->image.ximage->width/2;
7371 windows->image.window_changes.height=windows->image.ximage->height/2;
cristy051718b2011-08-28 22:49:25 +00007372 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007373 break;
7374 }
7375 case OriginalSizeCommand:
7376 {
7377 /*
7378 Original image size.
7379 */
7380 windows->image.window_changes.width=(int) (*image)->columns;
7381 windows->image.window_changes.height=(int) (*image)->rows;
cristy051718b2011-08-28 22:49:25 +00007382 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007383 break;
7384 }
7385 case DoubleSizeCommand:
7386 {
7387 /*
7388 Double the image size.
7389 */
7390 windows->image.window_changes.width=windows->image.ximage->width << 1;
7391 windows->image.window_changes.height=windows->image.ximage->height << 1;
cristy051718b2011-08-28 22:49:25 +00007392 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007393 break;
7394 }
7395 case ResizeCommand:
7396 {
7397 int
7398 status;
7399
cristybb503372010-05-27 20:51:26 +00007400 size_t
cristy3ed852e2009-09-05 21:47:34 +00007401 height,
7402 width;
7403
cristy9d314ff2011-03-09 01:30:28 +00007404 ssize_t
7405 x,
7406 y;
7407
cristy3ed852e2009-09-05 21:47:34 +00007408 /*
7409 Resize image.
7410 */
cristybb503372010-05-27 20:51:26 +00007411 width=(size_t) windows->image.ximage->width;
7412 height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007413 x=0;
7414 y=0;
cristyb51dff52011-05-19 16:55:47 +00007415 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
cristye8c25f92010-06-03 00:53:06 +00007416 (double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00007417 status=XDialogWidget(display,windows,"Resize",
7418 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7419 if (*geometry == '\0')
7420 break;
7421 if (status == 0)
7422 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7423 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7424 windows->image.window_changes.width=(int) width;
7425 windows->image.window_changes.height=(int) height;
cristy051718b2011-08-28 22:49:25 +00007426 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007427 break;
7428 }
7429 case ApplyCommand:
7430 {
7431 char
7432 image_geometry[MaxTextExtent];
7433
7434 if ((windows->image.crop_geometry == (char *) NULL) &&
7435 ((int) (*image)->columns == windows->image.ximage->width) &&
7436 ((int) (*image)->rows == windows->image.ximage->height))
7437 break;
7438 /*
7439 Apply size transforms to image.
7440 */
7441 XSetCursorState(display,windows,MagickTrue);
7442 XCheckRefreshWindows(display,windows);
7443 /*
7444 Crop and/or scale displayed image.
7445 */
cristyb51dff52011-05-19 16:55:47 +00007446 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +00007447 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00007448 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7449 exception);
cristy3ed852e2009-09-05 21:47:34 +00007450 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00007451 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7452 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00007453 windows->image.x=0;
7454 windows->image.y=0;
cristy6710d842011-10-20 23:23:00 +00007455 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007456 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007457 break;
7458 }
7459 case RefreshCommand:
7460 {
cristy051718b2011-08-28 22:49:25 +00007461 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007462 break;
7463 }
7464 case RestoreCommand:
7465 {
7466 /*
7467 Restore Image window to its original size.
7468 */
7469 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7470 (windows->image.height == (unsigned int) (*image)->rows) &&
7471 (windows->image.crop_geometry == (char *) NULL))
7472 {
7473 (void) XBell(display,0);
7474 break;
7475 }
7476 windows->image.window_changes.width=(int) (*image)->columns;
7477 windows->image.window_changes.height=(int) (*image)->rows;
7478 if (windows->image.crop_geometry != (char *) NULL)
7479 {
7480 windows->image.crop_geometry=(char *)
7481 RelinquishMagickMemory(windows->image.crop_geometry);
7482 windows->image.crop_geometry=(char *) NULL;
7483 windows->image.x=0;
7484 windows->image.y=0;
7485 }
cristy6710d842011-10-20 23:23:00 +00007486 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007487 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007488 break;
7489 }
7490 case CropCommand:
7491 {
7492 /*
7493 Crop image.
7494 */
cristy051718b2011-08-28 22:49:25 +00007495 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7496 exception);
cristy3ed852e2009-09-05 21:47:34 +00007497 break;
7498 }
7499 case ChopCommand:
7500 {
7501 /*
7502 Chop image.
7503 */
cristy051718b2011-08-28 22:49:25 +00007504 status=XChopImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007505 if (status == MagickFalse)
7506 {
7507 XNoticeWidget(display,windows,"Unable to cut X image",
7508 (*image)->filename);
7509 break;
7510 }
7511 break;
7512 }
7513 case FlopCommand:
7514 {
7515 Image
7516 *flop_image;
7517
7518 /*
7519 Flop image scanlines.
7520 */
7521 XSetCursorState(display,windows,MagickTrue);
7522 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007523 flop_image=FlopImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007524 if (flop_image != (Image *) NULL)
7525 {
7526 *image=DestroyImage(*image);
7527 *image=flop_image;
7528 }
cristy051718b2011-08-28 22:49:25 +00007529 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007530 XSetCursorState(display,windows,MagickFalse);
7531 if (windows->image.crop_geometry != (char *) NULL)
7532 {
7533 /*
7534 Flop crop geometry.
7535 */
7536 width=(unsigned int) (*image)->columns;
7537 height=(unsigned int) (*image)->rows;
7538 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7539 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007540 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007541 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7542 }
7543 if (windows->image.orphan != MagickFalse)
7544 break;
cristy051718b2011-08-28 22:49:25 +00007545 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007546 break;
7547 }
7548 case FlipCommand:
7549 {
7550 Image
7551 *flip_image;
7552
7553 /*
7554 Flip image scanlines.
7555 */
7556 XSetCursorState(display,windows,MagickTrue);
7557 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007558 flip_image=FlipImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007559 if (flip_image != (Image *) NULL)
7560 {
7561 *image=DestroyImage(*image);
7562 *image=flip_image;
7563 }
cristy051718b2011-08-28 22:49:25 +00007564 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007565 XSetCursorState(display,windows,MagickFalse);
7566 if (windows->image.crop_geometry != (char *) NULL)
7567 {
7568 /*
7569 Flip crop geometry.
7570 */
7571 width=(unsigned int) (*image)->columns;
7572 height=(unsigned int) (*image)->rows;
7573 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7574 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007575 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007576 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7577 }
7578 if (windows->image.orphan != MagickFalse)
7579 break;
cristy051718b2011-08-28 22:49:25 +00007580 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007581 break;
7582 }
7583 case RotateRightCommand:
7584 {
7585 /*
7586 Rotate image 90 degrees clockwise.
7587 */
cristy051718b2011-08-28 22:49:25 +00007588 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007589 if (status == MagickFalse)
7590 {
7591 XNoticeWidget(display,windows,"Unable to rotate X image",
7592 (*image)->filename);
7593 break;
7594 }
7595 break;
7596 }
7597 case RotateLeftCommand:
7598 {
7599 /*
7600 Rotate image 90 degrees counter-clockwise.
7601 */
cristy051718b2011-08-28 22:49:25 +00007602 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007603 if (status == MagickFalse)
7604 {
7605 XNoticeWidget(display,windows,"Unable to rotate X image",
7606 (*image)->filename);
7607 break;
7608 }
7609 break;
7610 }
7611 case RotateCommand:
7612 {
7613 /*
7614 Rotate image.
7615 */
cristy051718b2011-08-28 22:49:25 +00007616 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007617 if (status == MagickFalse)
7618 {
7619 XNoticeWidget(display,windows,"Unable to rotate X image",
7620 (*image)->filename);
7621 break;
7622 }
7623 break;
7624 }
7625 case ShearCommand:
7626 {
7627 Image
7628 *shear_image;
7629
7630 static char
7631 geometry[MaxTextExtent] = "45.0x45.0";
7632
7633 /*
7634 Query user for shear color and geometry.
7635 */
7636 XColorBrowserWidget(display,windows,"Select",color);
7637 if (*color == '\0')
7638 break;
7639 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7640 geometry);
7641 if (*geometry == '\0')
7642 break;
7643 /*
7644 Shear image.
7645 */
cristy051718b2011-08-28 22:49:25 +00007646 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7647 exception);
cristy3ed852e2009-09-05 21:47:34 +00007648 XSetCursorState(display,windows,MagickTrue);
7649 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00007650 (void) QueryColorCompliance(color,AllCompliance,
7651 &(*image)->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00007652 flags=ParseGeometry(geometry,&geometry_info);
7653 if ((flags & SigmaValue) == 0)
7654 geometry_info.sigma=geometry_info.rho;
7655 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00007656 exception);
cristy3ed852e2009-09-05 21:47:34 +00007657 if (shear_image != (Image *) NULL)
7658 {
7659 *image=DestroyImage(*image);
7660 *image=shear_image;
7661 }
cristy051718b2011-08-28 22:49:25 +00007662 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007663 XSetCursorState(display,windows,MagickFalse);
7664 if (windows->image.orphan != MagickFalse)
7665 break;
7666 windows->image.window_changes.width=(int) (*image)->columns;
7667 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007668 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007669 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007670 break;
7671 }
7672 case RollCommand:
7673 {
7674 Image
7675 *roll_image;
7676
7677 static char
7678 geometry[MaxTextExtent] = "+2+2";
7679
7680 /*
7681 Query user for the roll geometry.
7682 */
7683 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7684 geometry);
7685 if (*geometry == '\0')
7686 break;
7687 /*
7688 Roll image.
7689 */
cristy051718b2011-08-28 22:49:25 +00007690 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7691 exception);
cristy3ed852e2009-09-05 21:47:34 +00007692 XSetCursorState(display,windows,MagickTrue);
7693 XCheckRefreshWindows(display,windows);
7694 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00007695 exception);
cristy3ed852e2009-09-05 21:47:34 +00007696 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
cristy051718b2011-08-28 22:49:25 +00007697 exception);
cristy3ed852e2009-09-05 21:47:34 +00007698 if (roll_image != (Image *) NULL)
7699 {
7700 *image=DestroyImage(*image);
7701 *image=roll_image;
7702 }
cristy051718b2011-08-28 22:49:25 +00007703 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007704 XSetCursorState(display,windows,MagickFalse);
7705 if (windows->image.orphan != MagickFalse)
7706 break;
7707 windows->image.window_changes.width=(int) (*image)->columns;
7708 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007709 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007710 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007711 break;
7712 }
7713 case TrimCommand:
7714 {
7715 static char
7716 fuzz[MaxTextExtent];
7717
7718 /*
7719 Query user for the fuzz factor.
7720 */
cristyb51dff52011-05-19 16:55:47 +00007721 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007722 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007723 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7724 if (*fuzz == '\0')
7725 break;
cristydbdd0e32011-11-04 23:29:40 +00007726 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007727 /*
7728 Trim image.
7729 */
cristy051718b2011-08-28 22:49:25 +00007730 status=XTrimImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007731 if (status == MagickFalse)
7732 {
7733 XNoticeWidget(display,windows,"Unable to trim X image",
7734 (*image)->filename);
7735 break;
7736 }
7737 break;
7738 }
7739 case HueCommand:
7740 {
7741 static char
7742 hue_percent[MaxTextExtent] = "110";
7743
7744 /*
7745 Query user for percent hue change.
7746 */
7747 (void) XDialogWidget(display,windows,"Apply",
7748 "Enter percent change in image hue (0-200):",hue_percent);
7749 if (*hue_percent == '\0')
7750 break;
7751 /*
7752 Vary the image hue.
7753 */
7754 XSetCursorState(display,windows,MagickTrue);
7755 XCheckRefreshWindows(display,windows);
7756 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7757 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7758 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007759 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007760 XSetCursorState(display,windows,MagickFalse);
7761 if (windows->image.orphan != MagickFalse)
7762 break;
cristy6710d842011-10-20 23:23:00 +00007763 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007764 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007765 break;
7766 }
7767 case SaturationCommand:
7768 {
7769 static char
7770 saturation_percent[MaxTextExtent] = "110";
7771
7772 /*
7773 Query user for percent saturation change.
7774 */
7775 (void) XDialogWidget(display,windows,"Apply",
7776 "Enter percent change in color saturation (0-200):",saturation_percent);
7777 if (*saturation_percent == '\0')
7778 break;
7779 /*
7780 Vary color saturation.
7781 */
7782 XSetCursorState(display,windows,MagickTrue);
7783 XCheckRefreshWindows(display,windows);
7784 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7785 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7786 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007787 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007788 XSetCursorState(display,windows,MagickFalse);
7789 if (windows->image.orphan != MagickFalse)
7790 break;
cristy6710d842011-10-20 23:23:00 +00007791 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007792 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007793 break;
7794 }
7795 case BrightnessCommand:
7796 {
7797 static char
7798 brightness_percent[MaxTextExtent] = "110";
7799
7800 /*
7801 Query user for percent brightness change.
7802 */
7803 (void) XDialogWidget(display,windows,"Apply",
7804 "Enter percent change in color brightness (0-200):",brightness_percent);
7805 if (*brightness_percent == '\0')
7806 break;
7807 /*
7808 Vary the color brightness.
7809 */
7810 XSetCursorState(display,windows,MagickTrue);
7811 XCheckRefreshWindows(display,windows);
7812 (void) CopyMagickString(modulate_factors,brightness_percent,
7813 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007814 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007815 XSetCursorState(display,windows,MagickFalse);
7816 if (windows->image.orphan != MagickFalse)
7817 break;
cristy6710d842011-10-20 23:23:00 +00007818 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007819 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007820 break;
7821 }
7822 case GammaCommand:
7823 {
7824 static char
7825 factor[MaxTextExtent] = "1.6";
7826
7827 /*
7828 Query user for gamma value.
7829 */
7830 (void) XDialogWidget(display,windows,"Gamma",
cristy50fbc382011-07-07 02:19:17 +00007831 "Enter gamma value (e.g. 1.2):",factor);
cristy3ed852e2009-09-05 21:47:34 +00007832 if (*factor == '\0')
7833 break;
7834 /*
7835 Gamma correct image.
7836 */
7837 XSetCursorState(display,windows,MagickTrue);
7838 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007839 (void) GammaImage(*image,atof(factor),exception);
cristy3ed852e2009-09-05 21:47:34 +00007840 XSetCursorState(display,windows,MagickFalse);
7841 if (windows->image.orphan != MagickFalse)
7842 break;
cristy6710d842011-10-20 23:23:00 +00007843 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007844 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007845 break;
7846 }
7847 case SpiffCommand:
7848 {
7849 /*
7850 Sharpen the image contrast.
7851 */
7852 XSetCursorState(display,windows,MagickTrue);
7853 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007854 (void) ContrastImage(*image,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00007855 XSetCursorState(display,windows,MagickFalse);
7856 if (windows->image.orphan != MagickFalse)
7857 break;
cristy6710d842011-10-20 23:23:00 +00007858 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007859 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007860 break;
7861 }
7862 case DullCommand:
7863 {
7864 /*
7865 Dull the image contrast.
7866 */
7867 XSetCursorState(display,windows,MagickTrue);
7868 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007869 (void) ContrastImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007870 XSetCursorState(display,windows,MagickFalse);
7871 if (windows->image.orphan != MagickFalse)
7872 break;
cristy6710d842011-10-20 23:23:00 +00007873 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007874 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007875 break;
7876 }
7877 case ContrastStretchCommand:
7878 {
7879 double
7880 black_point,
7881 white_point;
7882
7883 static char
7884 levels[MaxTextExtent] = "1%";
7885
7886 /*
7887 Query user for gamma value.
7888 */
7889 (void) XDialogWidget(display,windows,"Contrast Stretch",
7890 "Enter black and white points:",levels);
7891 if (*levels == '\0')
7892 break;
7893 /*
7894 Contrast stretch image.
7895 */
7896 XSetCursorState(display,windows,MagickTrue);
7897 XCheckRefreshWindows(display,windows);
7898 flags=ParseGeometry(levels,&geometry_info);
7899 black_point=geometry_info.rho;
7900 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7901 if ((flags & PercentValue) != 0)
7902 {
7903 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7904 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7905 }
7906 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
cristye23ec9d2011-08-16 18:15:40 +00007907 (void) ContrastStretchImage(*image,black_point,white_point,
cristy051718b2011-08-28 22:49:25 +00007908 exception);
cristy3ed852e2009-09-05 21:47:34 +00007909 XSetCursorState(display,windows,MagickFalse);
7910 if (windows->image.orphan != MagickFalse)
7911 break;
cristy6710d842011-10-20 23:23:00 +00007912 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007913 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007914 break;
7915 }
7916 case SigmoidalContrastCommand:
7917 {
cristy9ee60942011-07-06 14:54:38 +00007918 GeometryInfo
7919 geometry_info;
7920
7921 MagickStatusType
7922 flags;
7923
cristy3ed852e2009-09-05 21:47:34 +00007924 static char
7925 levels[MaxTextExtent] = "3x50%";
7926
7927 /*
7928 Query user for gamma value.
7929 */
7930 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7931 "Enter contrast and midpoint:",levels);
7932 if (*levels == '\0')
7933 break;
7934 /*
7935 Contrast stretch image.
7936 */
7937 XSetCursorState(display,windows,MagickTrue);
7938 XCheckRefreshWindows(display,windows);
cristy9ee60942011-07-06 14:54:38 +00007939 flags=ParseGeometry(levels,&geometry_info);
7940 if ((flags & SigmaValue) == 0)
7941 geometry_info.sigma=1.0*QuantumRange/2.0;
7942 if ((flags & PercentValue) != 0)
7943 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7944 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
cristy051718b2011-08-28 22:49:25 +00007945 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00007946 XSetCursorState(display,windows,MagickFalse);
7947 if (windows->image.orphan != MagickFalse)
7948 break;
cristy6710d842011-10-20 23:23:00 +00007949 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007950 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007951 break;
7952 }
7953 case NormalizeCommand:
7954 {
7955 /*
7956 Perform histogram normalization on the image.
7957 */
7958 XSetCursorState(display,windows,MagickTrue);
7959 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007960 (void) NormalizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007961 XSetCursorState(display,windows,MagickFalse);
7962 if (windows->image.orphan != MagickFalse)
7963 break;
cristy6710d842011-10-20 23:23:00 +00007964 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007965 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007966 break;
7967 }
7968 case EqualizeCommand:
7969 {
7970 /*
7971 Perform histogram equalization on the image.
7972 */
7973 XSetCursorState(display,windows,MagickTrue);
7974 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007975 (void) EqualizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007976 XSetCursorState(display,windows,MagickFalse);
7977 if (windows->image.orphan != MagickFalse)
7978 break;
cristy6710d842011-10-20 23:23:00 +00007979 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007980 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007981 break;
7982 }
7983 case NegateCommand:
7984 {
7985 /*
7986 Negate colors in image.
7987 */
7988 XSetCursorState(display,windows,MagickTrue);
7989 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007990 (void) NegateImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007991 XSetCursorState(display,windows,MagickFalse);
7992 if (windows->image.orphan != MagickFalse)
7993 break;
cristy6710d842011-10-20 23:23:00 +00007994 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007995 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007996 break;
7997 }
7998 case GrayscaleCommand:
7999 {
8000 /*
8001 Convert image to grayscale.
8002 */
8003 XSetCursorState(display,windows,MagickTrue);
8004 XCheckRefreshWindows(display,windows);
8005 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
cristy018f07f2011-09-04 21:15:19 +00008006 GrayscaleType : GrayscaleMatteType,exception);
cristy3ed852e2009-09-05 21:47:34 +00008007 XSetCursorState(display,windows,MagickFalse);
8008 if (windows->image.orphan != MagickFalse)
8009 break;
cristy6710d842011-10-20 23:23:00 +00008010 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008011 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008012 break;
8013 }
8014 case MapCommand:
8015 {
8016 Image
8017 *affinity_image;
8018
8019 static char
8020 filename[MaxTextExtent] = "\0";
8021
8022 /*
8023 Request image file name from user.
8024 */
8025 XFileBrowserWidget(display,windows,"Map",filename);
8026 if (*filename == '\0')
8027 break;
8028 /*
8029 Map image.
8030 */
8031 XSetCursorState(display,windows,MagickTrue);
8032 XCheckRefreshWindows(display,windows);
8033 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00008034 affinity_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00008035 if (affinity_image != (Image *) NULL)
8036 {
cristy018f07f2011-09-04 21:15:19 +00008037 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008038 affinity_image=DestroyImage(affinity_image);
8039 }
cristy051718b2011-08-28 22:49:25 +00008040 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008041 XSetCursorState(display,windows,MagickFalse);
8042 if (windows->image.orphan != MagickFalse)
8043 break;
cristy6710d842011-10-20 23:23:00 +00008044 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008045 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008046 break;
8047 }
8048 case QuantizeCommand:
8049 {
8050 int
8051 status;
8052
8053 static char
8054 colors[MaxTextExtent] = "256";
8055
8056 /*
8057 Query user for maximum number of colors.
8058 */
8059 status=XDialogWidget(display,windows,"Quantize",
8060 "Maximum number of colors:",colors);
8061 if (*colors == '\0')
8062 break;
8063 /*
8064 Color reduce the image.
8065 */
8066 XSetCursorState(display,windows,MagickTrue);
8067 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00008068 quantize_info.number_colors=StringToUnsignedLong(colors);
cristy3ed852e2009-09-05 21:47:34 +00008069 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
cristy018f07f2011-09-04 21:15:19 +00008070 (void) QuantizeImage(&quantize_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008071 XSetCursorState(display,windows,MagickFalse);
8072 if (windows->image.orphan != MagickFalse)
8073 break;
cristy6710d842011-10-20 23:23:00 +00008074 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008075 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008076 break;
8077 }
8078 case DespeckleCommand:
8079 {
8080 Image
8081 *despeckle_image;
8082
8083 /*
8084 Despeckle image.
8085 */
8086 XSetCursorState(display,windows,MagickTrue);
8087 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00008088 despeckle_image=DespeckleImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008089 if (despeckle_image != (Image *) NULL)
8090 {
8091 *image=DestroyImage(*image);
8092 *image=despeckle_image;
8093 }
cristy051718b2011-08-28 22:49:25 +00008094 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008095 XSetCursorState(display,windows,MagickFalse);
8096 if (windows->image.orphan != MagickFalse)
8097 break;
cristy6710d842011-10-20 23:23:00 +00008098 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008099 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008100 break;
8101 }
8102 case EmbossCommand:
8103 {
8104 Image
8105 *emboss_image;
8106
8107 static char
8108 radius[MaxTextExtent] = "0.0x1.0";
8109
8110 /*
8111 Query user for emboss radius.
8112 */
8113 (void) XDialogWidget(display,windows,"Emboss",
8114 "Enter the emboss radius and standard deviation:",radius);
8115 if (*radius == '\0')
8116 break;
8117 /*
8118 Reduce noise in the image.
8119 */
8120 XSetCursorState(display,windows,MagickTrue);
8121 XCheckRefreshWindows(display,windows);
8122 flags=ParseGeometry(radius,&geometry_info);
8123 if ((flags & SigmaValue) == 0)
8124 geometry_info.sigma=1.0;
8125 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008126 exception);
cristy3ed852e2009-09-05 21:47:34 +00008127 if (emboss_image != (Image *) NULL)
8128 {
8129 *image=DestroyImage(*image);
8130 *image=emboss_image;
8131 }
cristy051718b2011-08-28 22:49:25 +00008132 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008133 XSetCursorState(display,windows,MagickFalse);
8134 if (windows->image.orphan != MagickFalse)
8135 break;
cristy6710d842011-10-20 23:23:00 +00008136 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008137 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008138 break;
8139 }
8140 case ReduceNoiseCommand:
8141 {
8142 Image
8143 *noise_image;
8144
8145 static char
8146 radius[MaxTextExtent] = "0";
8147
8148 /*
8149 Query user for noise radius.
8150 */
8151 (void) XDialogWidget(display,windows,"Reduce Noise",
8152 "Enter the noise radius:",radius);
8153 if (*radius == '\0')
8154 break;
8155 /*
8156 Reduce noise in the image.
8157 */
8158 XSetCursorState(display,windows,MagickTrue);
8159 XCheckRefreshWindows(display,windows);
8160 flags=ParseGeometry(radius,&geometry_info);
cristy95c38342011-03-18 22:39:51 +00008161 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
cristy051718b2011-08-28 22:49:25 +00008162 geometry_info.rho,(size_t) geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008163 if (noise_image != (Image *) NULL)
8164 {
8165 *image=DestroyImage(*image);
8166 *image=noise_image;
8167 }
cristy051718b2011-08-28 22:49:25 +00008168 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008169 XSetCursorState(display,windows,MagickFalse);
8170 if (windows->image.orphan != MagickFalse)
8171 break;
cristy6710d842011-10-20 23:23:00 +00008172 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008173 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008174 break;
8175 }
8176 case AddNoiseCommand:
8177 {
8178 char
8179 **noises;
8180
8181 Image
8182 *noise_image;
8183
8184 static char
8185 noise_type[MaxTextExtent] = "Gaussian";
8186
8187 /*
8188 Add noise to the image.
8189 */
cristy042ee782011-04-22 18:48:30 +00008190 noises=GetCommandOptions(MagickNoiseOptions);
cristy3ed852e2009-09-05 21:47:34 +00008191 if (noises == (char **) NULL)
8192 break;
8193 XListBrowserWidget(display,windows,&windows->widget,
8194 (const char **) noises,"Add Noise",
8195 "Select a type of noise to add to your image:",noise_type);
8196 noises=DestroyStringList(noises);
8197 if (*noise_type == '\0')
8198 break;
8199 XSetCursorState(display,windows,MagickTrue);
8200 XCheckRefreshWindows(display,windows);
cristy042ee782011-04-22 18:48:30 +00008201 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
cristy9ed1f812011-10-08 02:00:08 +00008202 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00008203 if (noise_image != (Image *) NULL)
8204 {
8205 *image=DestroyImage(*image);
8206 *image=noise_image;
8207 }
cristy051718b2011-08-28 22:49:25 +00008208 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008209 XSetCursorState(display,windows,MagickFalse);
8210 if (windows->image.orphan != MagickFalse)
8211 break;
cristy6710d842011-10-20 23:23:00 +00008212 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008213 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008214 break;
8215 }
8216 case SharpenCommand:
8217 {
8218 Image
8219 *sharp_image;
8220
8221 static char
8222 radius[MaxTextExtent] = "0.0x1.0";
8223
8224 /*
8225 Query user for sharpen radius.
8226 */
8227 (void) XDialogWidget(display,windows,"Sharpen",
8228 "Enter the sharpen radius and standard deviation:",radius);
8229 if (*radius == '\0')
8230 break;
8231 /*
8232 Sharpen image scanlines.
8233 */
8234 XSetCursorState(display,windows,MagickTrue);
8235 XCheckRefreshWindows(display,windows);
8236 flags=ParseGeometry(radius,&geometry_info);
8237 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008238 exception);
cristy3ed852e2009-09-05 21:47:34 +00008239 if (sharp_image != (Image *) NULL)
8240 {
8241 *image=DestroyImage(*image);
8242 *image=sharp_image;
8243 }
cristy051718b2011-08-28 22:49:25 +00008244 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008245 XSetCursorState(display,windows,MagickFalse);
8246 if (windows->image.orphan != MagickFalse)
8247 break;
cristy6710d842011-10-20 23:23:00 +00008248 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008249 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008250 break;
8251 }
8252 case BlurCommand:
8253 {
8254 Image
8255 *blur_image;
8256
8257 static char
8258 radius[MaxTextExtent] = "0.0x1.0";
8259
8260 /*
8261 Query user for blur radius.
8262 */
8263 (void) XDialogWidget(display,windows,"Blur",
8264 "Enter the blur radius and standard deviation:",radius);
8265 if (*radius == '\0')
8266 break;
8267 /*
8268 Blur an image.
8269 */
8270 XSetCursorState(display,windows,MagickTrue);
8271 XCheckRefreshWindows(display,windows);
8272 flags=ParseGeometry(radius,&geometry_info);
8273 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008274 exception);
cristy3ed852e2009-09-05 21:47:34 +00008275 if (blur_image != (Image *) NULL)
8276 {
8277 *image=DestroyImage(*image);
8278 *image=blur_image;
8279 }
cristy051718b2011-08-28 22:49:25 +00008280 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008281 XSetCursorState(display,windows,MagickFalse);
8282 if (windows->image.orphan != MagickFalse)
8283 break;
cristy6710d842011-10-20 23:23:00 +00008284 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008285 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008286 break;
8287 }
8288 case ThresholdCommand:
8289 {
8290 double
8291 threshold;
8292
8293 static char
8294 factor[MaxTextExtent] = "128";
8295
8296 /*
8297 Query user for threshold value.
8298 */
8299 (void) XDialogWidget(display,windows,"Threshold",
8300 "Enter threshold value:",factor);
8301 if (*factor == '\0')
8302 break;
8303 /*
8304 Gamma correct image.
8305 */
8306 XSetCursorState(display,windows,MagickTrue);
8307 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008308 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristye941a752011-10-15 01:52:48 +00008309 (void) BilevelImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008310 XSetCursorState(display,windows,MagickFalse);
8311 if (windows->image.orphan != MagickFalse)
8312 break;
cristy6710d842011-10-20 23:23:00 +00008313 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008314 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008315 break;
8316 }
8317 case EdgeDetectCommand:
8318 {
8319 Image
8320 *edge_image;
8321
8322 static char
8323 radius[MaxTextExtent] = "0";
8324
8325 /*
8326 Query user for edge factor.
8327 */
8328 (void) XDialogWidget(display,windows,"Detect Edges",
8329 "Enter the edge detect radius:",radius);
8330 if (*radius == '\0')
8331 break;
8332 /*
8333 Detect edge in image.
8334 */
8335 XSetCursorState(display,windows,MagickTrue);
8336 XCheckRefreshWindows(display,windows);
8337 flags=ParseGeometry(radius,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008338 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8339 exception);
cristy3ed852e2009-09-05 21:47:34 +00008340 if (edge_image != (Image *) NULL)
8341 {
8342 *image=DestroyImage(*image);
8343 *image=edge_image;
8344 }
cristy051718b2011-08-28 22:49:25 +00008345 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008346 XSetCursorState(display,windows,MagickFalse);
8347 if (windows->image.orphan != MagickFalse)
8348 break;
cristy6710d842011-10-20 23:23:00 +00008349 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008350 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008351 break;
8352 }
8353 case SpreadCommand:
8354 {
8355 Image
8356 *spread_image;
8357
8358 static char
8359 amount[MaxTextExtent] = "2";
8360
8361 /*
8362 Query user for spread amount.
8363 */
8364 (void) XDialogWidget(display,windows,"Spread",
8365 "Enter the displacement amount:",amount);
8366 if (*amount == '\0')
8367 break;
8368 /*
8369 Displace image pixels by a random amount.
8370 */
8371 XSetCursorState(display,windows,MagickTrue);
8372 XCheckRefreshWindows(display,windows);
8373 flags=ParseGeometry(amount,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008374 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8375 exception);
cristy3ed852e2009-09-05 21:47:34 +00008376 if (spread_image != (Image *) NULL)
8377 {
8378 *image=DestroyImage(*image);
8379 *image=spread_image;
8380 }
cristy051718b2011-08-28 22:49:25 +00008381 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008382 XSetCursorState(display,windows,MagickFalse);
8383 if (windows->image.orphan != MagickFalse)
8384 break;
cristy6710d842011-10-20 23:23:00 +00008385 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008386 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008387 break;
8388 }
8389 case ShadeCommand:
8390 {
8391 Image
8392 *shade_image;
8393
8394 int
8395 status;
8396
8397 static char
8398 geometry[MaxTextExtent] = "30x30";
8399
8400 /*
8401 Query user for the shade geometry.
8402 */
8403 status=XDialogWidget(display,windows,"Shade",
8404 "Enter the azimuth and elevation of the light source:",geometry);
8405 if (*geometry == '\0')
8406 break;
8407 /*
8408 Shade image pixels.
8409 */
8410 XSetCursorState(display,windows,MagickTrue);
8411 XCheckRefreshWindows(display,windows);
8412 flags=ParseGeometry(geometry,&geometry_info);
8413 if ((flags & SigmaValue) == 0)
8414 geometry_info.sigma=1.0;
8415 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
cristy051718b2011-08-28 22:49:25 +00008416 geometry_info.rho,geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008417 if (shade_image != (Image *) NULL)
8418 {
8419 *image=DestroyImage(*image);
8420 *image=shade_image;
8421 }
cristy051718b2011-08-28 22:49:25 +00008422 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008423 XSetCursorState(display,windows,MagickFalse);
8424 if (windows->image.orphan != MagickFalse)
8425 break;
cristy6710d842011-10-20 23:23:00 +00008426 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008427 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008428 break;
8429 }
8430 case RaiseCommand:
8431 {
8432 static char
8433 bevel_width[MaxTextExtent] = "10";
8434
8435 /*
8436 Query user for bevel width.
8437 */
8438 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8439 if (*bevel_width == '\0')
8440 break;
8441 /*
8442 Raise an image.
8443 */
cristy051718b2011-08-28 22:49:25 +00008444 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8445 exception);
cristy3ed852e2009-09-05 21:47:34 +00008446 XSetCursorState(display,windows,MagickTrue);
8447 XCheckRefreshWindows(display,windows);
8448 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008449 exception);
8450 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00008451 XSetCursorState(display,windows,MagickFalse);
8452 if (windows->image.orphan != MagickFalse)
8453 break;
cristy6710d842011-10-20 23:23:00 +00008454 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008455 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008456 break;
8457 }
8458 case SegmentCommand:
8459 {
8460 static char
8461 threshold[MaxTextExtent] = "1.0x1.5";
8462
8463 /*
8464 Query user for smoothing threshold.
8465 */
8466 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8467 threshold);
8468 if (*threshold == '\0')
8469 break;
8470 /*
8471 Segment an image.
8472 */
8473 XSetCursorState(display,windows,MagickTrue);
8474 XCheckRefreshWindows(display,windows);
8475 flags=ParseGeometry(threshold,&geometry_info);
8476 if ((flags & SigmaValue) == 0)
8477 geometry_info.sigma=1.0;
cristyd3d9c5d2012-02-15 22:58:57 +00008478 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
cristy018f07f2011-09-04 21:15:19 +00008479 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008480 XSetCursorState(display,windows,MagickFalse);
8481 if (windows->image.orphan != MagickFalse)
8482 break;
cristy6710d842011-10-20 23:23:00 +00008483 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008484 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008485 break;
8486 }
8487 case SepiaToneCommand:
8488 {
8489 double
8490 threshold;
8491
8492 Image
8493 *sepia_image;
8494
8495 static char
8496 factor[MaxTextExtent] = "80%";
8497
8498 /*
8499 Query user for sepia-tone factor.
8500 */
8501 (void) XDialogWidget(display,windows,"Sepia Tone",
8502 "Enter the sepia tone factor (0 - 99.9%):",factor);
8503 if (*factor == '\0')
8504 break;
8505 /*
8506 Sepia tone image pixels.
8507 */
8508 XSetCursorState(display,windows,MagickTrue);
8509 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008510 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy051718b2011-08-28 22:49:25 +00008511 sepia_image=SepiaToneImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008512 if (sepia_image != (Image *) NULL)
8513 {
8514 *image=DestroyImage(*image);
8515 *image=sepia_image;
8516 }
cristy051718b2011-08-28 22:49:25 +00008517 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008518 XSetCursorState(display,windows,MagickFalse);
8519 if (windows->image.orphan != MagickFalse)
8520 break;
cristy6710d842011-10-20 23:23:00 +00008521 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008522 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008523 break;
8524 }
8525 case SolarizeCommand:
8526 {
8527 double
8528 threshold;
8529
8530 static char
8531 factor[MaxTextExtent] = "60%";
8532
8533 /*
8534 Query user for solarize factor.
8535 */
8536 (void) XDialogWidget(display,windows,"Solarize",
8537 "Enter the solarize factor (0 - 99.9%):",factor);
8538 if (*factor == '\0')
8539 break;
8540 /*
8541 Solarize image pixels.
8542 */
8543 XSetCursorState(display,windows,MagickTrue);
8544 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008545 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy5cbc0162011-08-29 00:36:28 +00008546 (void) SolarizeImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008547 XSetCursorState(display,windows,MagickFalse);
8548 if (windows->image.orphan != MagickFalse)
8549 break;
cristy6710d842011-10-20 23:23:00 +00008550 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008551 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008552 break;
8553 }
8554 case SwirlCommand:
8555 {
8556 Image
8557 *swirl_image;
8558
8559 static char
8560 degrees[MaxTextExtent] = "60";
8561
8562 /*
8563 Query user for swirl angle.
8564 */
8565 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8566 degrees);
8567 if (*degrees == '\0')
8568 break;
8569 /*
8570 Swirl image pixels about the center.
8571 */
8572 XSetCursorState(display,windows,MagickTrue);
8573 XCheckRefreshWindows(display,windows);
8574 flags=ParseGeometry(degrees,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008575 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8576 exception);
cristy3ed852e2009-09-05 21:47:34 +00008577 if (swirl_image != (Image *) NULL)
8578 {
8579 *image=DestroyImage(*image);
8580 *image=swirl_image;
8581 }
cristy051718b2011-08-28 22:49:25 +00008582 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008583 XSetCursorState(display,windows,MagickFalse);
8584 if (windows->image.orphan != MagickFalse)
8585 break;
cristy6710d842011-10-20 23:23:00 +00008586 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008587 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008588 break;
8589 }
8590 case ImplodeCommand:
8591 {
8592 Image
8593 *implode_image;
8594
8595 static char
8596 factor[MaxTextExtent] = "0.3";
8597
8598 /*
8599 Query user for implode factor.
8600 */
8601 (void) XDialogWidget(display,windows,"Implode",
8602 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8603 if (*factor == '\0')
8604 break;
8605 /*
8606 Implode image pixels about the center.
8607 */
8608 XSetCursorState(display,windows,MagickTrue);
8609 XCheckRefreshWindows(display,windows);
8610 flags=ParseGeometry(factor,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008611 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8612 exception);
cristy3ed852e2009-09-05 21:47:34 +00008613 if (implode_image != (Image *) NULL)
8614 {
8615 *image=DestroyImage(*image);
8616 *image=implode_image;
8617 }
cristy051718b2011-08-28 22:49:25 +00008618 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008619 XSetCursorState(display,windows,MagickFalse);
8620 if (windows->image.orphan != MagickFalse)
8621 break;
cristy6710d842011-10-20 23:23:00 +00008622 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008623 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008624 break;
8625 }
8626 case VignetteCommand:
8627 {
8628 Image
8629 *vignette_image;
8630
8631 static char
8632 geometry[MaxTextExtent] = "0x20";
8633
8634 /*
8635 Query user for the vignette geometry.
8636 */
8637 (void) XDialogWidget(display,windows,"Vignette",
8638 "Enter the radius, sigma, and x and y offsets:",geometry);
8639 if (*geometry == '\0')
8640 break;
8641 /*
8642 Soften the edges of the image in vignette style
8643 */
8644 XSetCursorState(display,windows,MagickTrue);
8645 XCheckRefreshWindows(display,windows);
8646 flags=ParseGeometry(geometry,&geometry_info);
8647 if ((flags & SigmaValue) == 0)
8648 geometry_info.sigma=1.0;
8649 if ((flags & XiValue) == 0)
8650 geometry_info.xi=0.1*(*image)->columns;
8651 if ((flags & PsiValue) == 0)
8652 geometry_info.psi=0.1*(*image)->rows;
cristyaa2c16c2012-03-25 22:21:35 +00008653 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8654 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8655 exception);
cristy3ed852e2009-09-05 21:47:34 +00008656 if (vignette_image != (Image *) NULL)
8657 {
8658 *image=DestroyImage(*image);
8659 *image=vignette_image;
8660 }
cristy051718b2011-08-28 22:49:25 +00008661 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008662 XSetCursorState(display,windows,MagickFalse);
8663 if (windows->image.orphan != MagickFalse)
8664 break;
cristy6710d842011-10-20 23:23:00 +00008665 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008666 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008667 break;
8668 }
8669 case WaveCommand:
8670 {
8671 Image
8672 *wave_image;
8673
8674 static char
8675 geometry[MaxTextExtent] = "25x150";
8676
8677 /*
8678 Query user for the wave geometry.
8679 */
8680 (void) XDialogWidget(display,windows,"Wave",
8681 "Enter the amplitude and length of the wave:",geometry);
8682 if (*geometry == '\0')
8683 break;
8684 /*
cristycee97112010-05-28 00:44:52 +00008685 Alter an image along a sine wave.
cristy3ed852e2009-09-05 21:47:34 +00008686 */
8687 XSetCursorState(display,windows,MagickTrue);
8688 XCheckRefreshWindows(display,windows);
8689 flags=ParseGeometry(geometry,&geometry_info);
8690 if ((flags & SigmaValue) == 0)
8691 geometry_info.sigma=1.0;
8692 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
cristy5c4e2582011-09-11 19:21:03 +00008693 (*image)->interpolate,exception);
cristy3ed852e2009-09-05 21:47:34 +00008694 if (wave_image != (Image *) NULL)
8695 {
8696 *image=DestroyImage(*image);
8697 *image=wave_image;
8698 }
cristy051718b2011-08-28 22:49:25 +00008699 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008700 XSetCursorState(display,windows,MagickFalse);
8701 if (windows->image.orphan != MagickFalse)
8702 break;
cristy6710d842011-10-20 23:23:00 +00008703 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008704 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008705 break;
8706 }
8707 case OilPaintCommand:
8708 {
8709 Image
8710 *paint_image;
8711
8712 static char
8713 radius[MaxTextExtent] = "0";
8714
8715 /*
8716 Query user for circular neighborhood radius.
8717 */
8718 (void) XDialogWidget(display,windows,"Oil Paint",
8719 "Enter the mask radius:",radius);
8720 if (*radius == '\0')
8721 break;
8722 /*
8723 OilPaint image scanlines.
8724 */
8725 XSetCursorState(display,windows,MagickTrue);
8726 XCheckRefreshWindows(display,windows);
8727 flags=ParseGeometry(radius,&geometry_info);
cristy14973ba2011-08-27 23:48:07 +00008728 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008729 exception);
cristy3ed852e2009-09-05 21:47:34 +00008730 if (paint_image != (Image *) NULL)
8731 {
8732 *image=DestroyImage(*image);
8733 *image=paint_image;
8734 }
cristy051718b2011-08-28 22:49:25 +00008735 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008736 XSetCursorState(display,windows,MagickFalse);
8737 if (windows->image.orphan != MagickFalse)
8738 break;
cristy6710d842011-10-20 23:23:00 +00008739 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008740 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008741 break;
8742 }
8743 case CharcoalDrawCommand:
8744 {
8745 Image
8746 *charcoal_image;
8747
8748 static char
8749 radius[MaxTextExtent] = "0x1";
8750
8751 /*
8752 Query user for charcoal radius.
8753 */
8754 (void) XDialogWidget(display,windows,"Charcoal Draw",
8755 "Enter the charcoal radius and sigma:",radius);
8756 if (*radius == '\0')
8757 break;
8758 /*
8759 Charcoal the image.
8760 */
cristy051718b2011-08-28 22:49:25 +00008761 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8762 exception);
cristy3ed852e2009-09-05 21:47:34 +00008763 XSetCursorState(display,windows,MagickTrue);
8764 XCheckRefreshWindows(display,windows);
8765 flags=ParseGeometry(radius,&geometry_info);
8766 if ((flags & SigmaValue) == 0)
8767 geometry_info.sigma=geometry_info.rho;
8768 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008769 exception);
cristy3ed852e2009-09-05 21:47:34 +00008770 if (charcoal_image != (Image *) NULL)
8771 {
8772 *image=DestroyImage(*image);
8773 *image=charcoal_image;
8774 }
cristy051718b2011-08-28 22:49:25 +00008775 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008776 XSetCursorState(display,windows,MagickFalse);
8777 if (windows->image.orphan != MagickFalse)
8778 break;
cristy6710d842011-10-20 23:23:00 +00008779 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008780 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008781 break;
8782 }
8783 case AnnotateCommand:
8784 {
8785 /*
8786 Annotate the image with text.
8787 */
cristy051718b2011-08-28 22:49:25 +00008788 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008789 if (status == MagickFalse)
8790 {
8791 XNoticeWidget(display,windows,"Unable to annotate X image",
8792 (*image)->filename);
8793 break;
8794 }
8795 break;
8796 }
8797 case DrawCommand:
8798 {
8799 /*
8800 Draw image.
8801 */
cristy051718b2011-08-28 22:49:25 +00008802 status=XDrawEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008803 if (status == MagickFalse)
8804 {
8805 XNoticeWidget(display,windows,"Unable to draw on the X image",
8806 (*image)->filename);
8807 break;
8808 }
8809 break;
8810 }
8811 case ColorCommand:
8812 {
8813 /*
8814 Color edit.
8815 */
cristy051718b2011-08-28 22:49:25 +00008816 status=XColorEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008817 if (status == MagickFalse)
8818 {
8819 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8820 (*image)->filename);
8821 break;
8822 }
8823 break;
8824 }
8825 case MatteCommand:
8826 {
8827 /*
8828 Matte edit.
8829 */
cristy051718b2011-08-28 22:49:25 +00008830 status=XMatteEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008831 if (status == MagickFalse)
8832 {
8833 XNoticeWidget(display,windows,"Unable to matte edit X image",
8834 (*image)->filename);
8835 break;
8836 }
8837 break;
8838 }
8839 case CompositeCommand:
8840 {
8841 /*
8842 Composite image.
8843 */
cristy051718b2011-08-28 22:49:25 +00008844 status=XCompositeImage(display,resource_info,windows,*image,
8845 exception);
cristy3ed852e2009-09-05 21:47:34 +00008846 if (status == MagickFalse)
8847 {
8848 XNoticeWidget(display,windows,"Unable to composite X image",
8849 (*image)->filename);
8850 break;
8851 }
8852 break;
8853 }
8854 case AddBorderCommand:
8855 {
8856 Image
8857 *border_image;
8858
8859 static char
8860 geometry[MaxTextExtent] = "6x6";
8861
8862 /*
8863 Query user for border color and geometry.
8864 */
8865 XColorBrowserWidget(display,windows,"Select",color);
8866 if (*color == '\0')
8867 break;
8868 (void) XDialogWidget(display,windows,"Add Border",
8869 "Enter border geometry:",geometry);
8870 if (*geometry == '\0')
8871 break;
8872 /*
8873 Add a border to the image.
8874 */
cristy051718b2011-08-28 22:49:25 +00008875 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8876 exception);
cristy3ed852e2009-09-05 21:47:34 +00008877 XSetCursorState(display,windows,MagickTrue);
8878 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008879 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
cristy051718b2011-08-28 22:49:25 +00008880 exception);
cristy3ed852e2009-09-05 21:47:34 +00008881 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008882 exception);
cristy633f0c62011-09-15 13:27:36 +00008883 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8884 exception);
cristy3ed852e2009-09-05 21:47:34 +00008885 if (border_image != (Image *) NULL)
8886 {
8887 *image=DestroyImage(*image);
8888 *image=border_image;
8889 }
cristy051718b2011-08-28 22:49:25 +00008890 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008891 XSetCursorState(display,windows,MagickFalse);
8892 if (windows->image.orphan != MagickFalse)
8893 break;
8894 windows->image.window_changes.width=(int) (*image)->columns;
8895 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008896 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008897 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008898 break;
8899 }
8900 case AddFrameCommand:
8901 {
8902 FrameInfo
8903 frame_info;
8904
8905 Image
8906 *frame_image;
8907
8908 static char
8909 geometry[MaxTextExtent] = "6x6";
8910
8911 /*
8912 Query user for frame color and geometry.
8913 */
8914 XColorBrowserWidget(display,windows,"Select",color);
8915 if (*color == '\0')
8916 break;
8917 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8918 geometry);
8919 if (*geometry == '\0')
8920 break;
8921 /*
8922 Surround image with an ornamental border.
8923 */
cristy051718b2011-08-28 22:49:25 +00008924 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8925 exception);
cristy3ed852e2009-09-05 21:47:34 +00008926 XSetCursorState(display,windows,MagickTrue);
8927 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008928 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
cristy051718b2011-08-28 22:49:25 +00008929 exception);
cristy3ed852e2009-09-05 21:47:34 +00008930 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008931 exception);
cristy3ed852e2009-09-05 21:47:34 +00008932 frame_info.width=page_geometry.width;
8933 frame_info.height=page_geometry.height;
8934 frame_info.outer_bevel=page_geometry.x;
8935 frame_info.inner_bevel=page_geometry.y;
cristybb503372010-05-27 20:51:26 +00008936 frame_info.x=(ssize_t) frame_info.width;
8937 frame_info.y=(ssize_t) frame_info.height;
cristy3ed852e2009-09-05 21:47:34 +00008938 frame_info.width=(*image)->columns+2*frame_info.width;
8939 frame_info.height=(*image)->rows+2*frame_info.height;
cristy633f0c62011-09-15 13:27:36 +00008940 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
cristy3ed852e2009-09-05 21:47:34 +00008941 if (frame_image != (Image *) NULL)
8942 {
8943 *image=DestroyImage(*image);
8944 *image=frame_image;
8945 }
cristy051718b2011-08-28 22:49:25 +00008946 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008947 XSetCursorState(display,windows,MagickFalse);
8948 if (windows->image.orphan != MagickFalse)
8949 break;
8950 windows->image.window_changes.width=(int) (*image)->columns;
8951 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008952 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008953 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008954 break;
8955 }
8956 case CommentCommand:
8957 {
8958 const char
8959 *value;
8960
8961 FILE
8962 *file;
8963
8964 int
8965 unique_file;
8966
8967 /*
8968 Edit image comment.
8969 */
8970 unique_file=AcquireUniqueFileResource(image_info->filename);
8971 if (unique_file == -1)
8972 XNoticeWidget(display,windows,"Unable to edit image comment",
8973 image_info->filename);
cristyd15e6592011-10-15 00:13:06 +00008974 value=GetImageProperty(*image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +00008975 if (value == (char *) NULL)
8976 unique_file=close(unique_file)-1;
8977 else
8978 {
8979 register const char
8980 *p;
8981
8982 file=fdopen(unique_file,"w");
8983 if (file == (FILE *) NULL)
8984 {
8985 XNoticeWidget(display,windows,"Unable to edit image comment",
8986 image_info->filename);
8987 break;
8988 }
8989 for (p=value; *p != '\0'; p++)
8990 (void) fputc((int) *p,file);
8991 (void) fputc('\n',file);
8992 (void) fclose(file);
8993 }
8994 XSetCursorState(display,windows,MagickTrue);
8995 XCheckRefreshWindows(display,windows);
8996 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00008997 exception);
cristy3ed852e2009-09-05 21:47:34 +00008998 if (status == MagickFalse)
8999 XNoticeWidget(display,windows,"Unable to edit image comment",
9000 (char *) NULL);
9001 else
9002 {
9003 char
9004 *comment;
9005
cristy051718b2011-08-28 22:49:25 +00009006 comment=FileToString(image_info->filename,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00009007 if (comment != (char *) NULL)
9008 {
cristyd15e6592011-10-15 00:13:06 +00009009 (void) SetImageProperty(*image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +00009010 (*image)->taint=MagickTrue;
9011 }
9012 }
9013 (void) RelinquishUniqueFileResource(image_info->filename);
9014 XSetCursorState(display,windows,MagickFalse);
9015 break;
9016 }
9017 case LaunchCommand:
9018 {
9019 /*
9020 Launch program.
9021 */
9022 XSetCursorState(display,windows,MagickTrue);
9023 XCheckRefreshWindows(display,windows);
9024 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009025 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
cristy3ed852e2009-09-05 21:47:34 +00009026 filename);
cristy051718b2011-08-28 22:49:25 +00009027 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009028 if (status == MagickFalse)
9029 XNoticeWidget(display,windows,"Unable to launch image editor",
9030 (char *) NULL);
9031 else
9032 {
cristy051718b2011-08-28 22:49:25 +00009033 nexus=ReadImage(resource_info->image_info,exception);
9034 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00009035 XClientMessage(display,windows->image.id,windows->im_protocols,
9036 windows->im_next_image,CurrentTime);
9037 }
9038 (void) RelinquishUniqueFileResource(filename);
9039 XSetCursorState(display,windows,MagickFalse);
9040 break;
9041 }
9042 case RegionofInterestCommand:
9043 {
9044 /*
9045 Apply an image processing technique to a region of interest.
9046 */
cristy051718b2011-08-28 22:49:25 +00009047 (void) XROIImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009048 break;
9049 }
9050 case InfoCommand:
9051 break;
9052 case ZoomCommand:
9053 {
9054 /*
9055 Zoom image.
9056 */
9057 if (windows->magnify.mapped != MagickFalse)
9058 (void) XRaiseWindow(display,windows->magnify.id);
9059 else
9060 {
9061 /*
9062 Make magnify image.
9063 */
9064 XSetCursorState(display,windows,MagickTrue);
9065 (void) XMapRaised(display,windows->magnify.id);
9066 XSetCursorState(display,windows,MagickFalse);
9067 }
9068 break;
9069 }
9070 case ShowPreviewCommand:
9071 {
9072 char
9073 **previews;
9074
9075 Image
9076 *preview_image;
9077
9078 static char
9079 preview_type[MaxTextExtent] = "Gamma";
9080
9081 /*
9082 Select preview type from menu.
9083 */
cristy042ee782011-04-22 18:48:30 +00009084 previews=GetCommandOptions(MagickPreviewOptions);
cristy3ed852e2009-09-05 21:47:34 +00009085 if (previews == (char **) NULL)
9086 break;
9087 XListBrowserWidget(display,windows,&windows->widget,
9088 (const char **) previews,"Preview",
9089 "Select an enhancement, effect, or F/X:",preview_type);
9090 previews=DestroyStringList(previews);
9091 if (*preview_type == '\0')
9092 break;
9093 /*
9094 Show image preview.
9095 */
9096 XSetCursorState(display,windows,MagickTrue);
9097 XCheckRefreshWindows(display,windows);
9098 image_info->preview_type=(PreviewType)
cristy042ee782011-04-22 18:48:30 +00009099 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
cristybb503372010-05-27 20:51:26 +00009100 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009101 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009102 (void) SetImageProperty(*image,"label","Preview",exception);
cristy3ed852e2009-09-05 21:47:34 +00009103 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009104 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
cristy3ed852e2009-09-05 21:47:34 +00009105 filename);
cristy051718b2011-08-28 22:49:25 +00009106 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009107 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009108 preview_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009109 (void) RelinquishUniqueFileResource(filename);
9110 if (preview_image == (Image *) NULL)
9111 break;
cristyb51dff52011-05-19 16:55:47 +00009112 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009113 filename);
cristy051718b2011-08-28 22:49:25 +00009114 status=WriteImage(image_info,preview_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009115 preview_image=DestroyImage(preview_image);
9116 if (status == MagickFalse)
9117 XNoticeWidget(display,windows,"Unable to show image preview",
9118 (*image)->filename);
9119 XDelay(display,1500);
9120 XSetCursorState(display,windows,MagickFalse);
9121 break;
9122 }
9123 case ShowHistogramCommand:
9124 {
9125 Image
9126 *histogram_image;
9127
9128 /*
9129 Show image histogram.
9130 */
9131 XSetCursorState(display,windows,MagickTrue);
9132 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009133 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009134 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009135 (void) SetImageProperty(*image,"label","Histogram",exception);
cristy3ed852e2009-09-05 21:47:34 +00009136 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009137 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
cristy3ed852e2009-09-05 21:47:34 +00009138 filename);
cristy051718b2011-08-28 22:49:25 +00009139 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009140 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009141 histogram_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009142 (void) RelinquishUniqueFileResource(filename);
9143 if (histogram_image == (Image *) NULL)
9144 break;
cristyb51dff52011-05-19 16:55:47 +00009145 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009146 "show:%s",filename);
cristy051718b2011-08-28 22:49:25 +00009147 status=WriteImage(image_info,histogram_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009148 histogram_image=DestroyImage(histogram_image);
9149 if (status == MagickFalse)
9150 XNoticeWidget(display,windows,"Unable to show histogram",
9151 (*image)->filename);
9152 XDelay(display,1500);
9153 XSetCursorState(display,windows,MagickFalse);
9154 break;
9155 }
9156 case ShowMatteCommand:
9157 {
9158 Image
9159 *matte_image;
9160
9161 if ((*image)->matte == MagickFalse)
9162 {
9163 XNoticeWidget(display,windows,
9164 "Image does not have any matte information",(*image)->filename);
9165 break;
9166 }
9167 /*
9168 Show image matte.
9169 */
9170 XSetCursorState(display,windows,MagickTrue);
9171 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009172 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009173 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009174 (void) SetImageProperty(*image,"label","Matte",exception);
cristy3ed852e2009-09-05 21:47:34 +00009175 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009176 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
cristy3ed852e2009-09-05 21:47:34 +00009177 filename);
cristy051718b2011-08-28 22:49:25 +00009178 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009179 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009180 matte_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009181 (void) RelinquishUniqueFileResource(filename);
9182 if (matte_image == (Image *) NULL)
9183 break;
cristyb51dff52011-05-19 16:55:47 +00009184 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009185 filename);
cristy051718b2011-08-28 22:49:25 +00009186 status=WriteImage(image_info,matte_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009187 matte_image=DestroyImage(matte_image);
9188 if (status == MagickFalse)
9189 XNoticeWidget(display,windows,"Unable to show matte",
9190 (*image)->filename);
9191 XDelay(display,1500);
9192 XSetCursorState(display,windows,MagickFalse);
9193 break;
9194 }
9195 case BackgroundCommand:
9196 {
9197 /*
9198 Background image.
9199 */
cristy051718b2011-08-28 22:49:25 +00009200 status=XBackgroundImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009201 if (status == MagickFalse)
9202 break;
cristy051718b2011-08-28 22:49:25 +00009203 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009204 if (nexus != (Image *) NULL)
9205 XClientMessage(display,windows->image.id,windows->im_protocols,
9206 windows->im_next_image,CurrentTime);
9207 break;
9208 }
9209 case SlideShowCommand:
9210 {
9211 static char
9212 delay[MaxTextExtent] = "5";
9213
9214 /*
9215 Display next image after pausing.
9216 */
9217 (void) XDialogWidget(display,windows,"Slide Show",
9218 "Pause how many 1/100ths of a second between images:",delay);
9219 if (*delay == '\0')
9220 break;
cristye27293e2009-12-18 02:53:20 +00009221 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009222 XClientMessage(display,windows->image.id,windows->im_protocols,
9223 windows->im_next_image,CurrentTime);
9224 break;
9225 }
9226 case PreferencesCommand:
9227 {
9228 /*
9229 Set user preferences.
9230 */
9231 status=XPreferencesWidget(display,resource_info,windows);
9232 if (status == MagickFalse)
9233 break;
cristy051718b2011-08-28 22:49:25 +00009234 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009235 if (nexus != (Image *) NULL)
9236 XClientMessage(display,windows->image.id,windows->im_protocols,
9237 windows->im_next_image,CurrentTime);
9238 break;
9239 }
9240 case HelpCommand:
9241 {
9242 /*
9243 User requested help.
9244 */
9245 XTextViewWidget(display,resource_info,windows,MagickFalse,
9246 "Help Viewer - Display",DisplayHelp);
9247 break;
9248 }
9249 case BrowseDocumentationCommand:
9250 {
9251 Atom
9252 mozilla_atom;
9253
9254 Window
9255 mozilla_window,
9256 root_window;
9257
9258 /*
9259 Browse the ImageMagick documentation.
9260 */
9261 root_window=XRootWindow(display,XDefaultScreen(display));
9262 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9263 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9264 if (mozilla_window != (Window) NULL)
9265 {
9266 char
9267 command[MaxTextExtent],
9268 *url;
9269
9270 /*
9271 Display documentation using Netscape remote control.
9272 */
9273 url=GetMagickHomeURL();
cristyb51dff52011-05-19 16:55:47 +00009274 (void) FormatLocaleString(command,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009275 "openurl(%s,new-tab)",url);
9276 url=DestroyString(url);
9277 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9278 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9279 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9280 XSetCursorState(display,windows,MagickFalse);
9281 break;
9282 }
9283 XSetCursorState(display,windows,MagickTrue);
9284 XCheckRefreshWindows(display,windows);
9285 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00009286 exception);
cristy3ed852e2009-09-05 21:47:34 +00009287 if (status == MagickFalse)
9288 XNoticeWidget(display,windows,"Unable to browse documentation",
9289 (char *) NULL);
9290 XDelay(display,1500);
9291 XSetCursorState(display,windows,MagickFalse);
9292 break;
9293 }
9294 case VersionCommand:
9295 {
cristybb503372010-05-27 20:51:26 +00009296 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +00009297 GetMagickCopyright());
9298 break;
9299 }
9300 case SaveToUndoBufferCommand:
9301 break;
9302 default:
9303 {
9304 (void) XBell(display,0);
9305 break;
9306 }
9307 }
9308 image_info=DestroyImageInfo(image_info);
9309 return(nexus);
9310}
9311
9312/*
9313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9314% %
9315% %
9316% %
9317+ X M a g n i f y I m a g e %
9318% %
9319% %
9320% %
9321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9322%
9323% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9324% The magnified portion is displayed in a separate window.
9325%
9326% The format of the XMagnifyImage method is:
9327%
cristy6710d842011-10-20 23:23:00 +00009328% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9329% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009330%
9331% A description of each parameter follows:
9332%
9333% o display: Specifies a connection to an X server; returned from
9334% XOpenDisplay.
9335%
9336% o windows: Specifies a pointer to a XWindows structure.
9337%
9338% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9339% the entire image is refreshed.
9340%
cristy6710d842011-10-20 23:23:00 +00009341% o exception: return any errors or warnings in this structure.
9342%
cristy3ed852e2009-09-05 21:47:34 +00009343*/
cristy6710d842011-10-20 23:23:00 +00009344static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9345 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009346{
9347 char
9348 text[MaxTextExtent];
9349
9350 register int
9351 x,
9352 y;
9353
cristybb503372010-05-27 20:51:26 +00009354 size_t
cristy3ed852e2009-09-05 21:47:34 +00009355 state;
9356
9357 /*
9358 Update magnified image until the mouse button is released.
9359 */
9360 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9361 state=DefaultState;
9362 x=event->xbutton.x;
9363 y=event->xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00009364 windows->magnify.x=(int) windows->image.x+x;
9365 windows->magnify.y=(int) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00009366 do
9367 {
9368 /*
9369 Map and unmap Info widget as text cursor crosses its boundaries.
9370 */
9371 if (windows->info.mapped != MagickFalse)
9372 {
9373 if ((x < (int) (windows->info.x+windows->info.width)) &&
9374 (y < (int) (windows->info.y+windows->info.height)))
9375 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9376 }
9377 else
9378 if ((x > (int) (windows->info.x+windows->info.width)) ||
9379 (y > (int) (windows->info.y+windows->info.height)))
9380 (void) XMapWindow(display,windows->info.id);
9381 if (windows->info.mapped != MagickFalse)
9382 {
9383 /*
9384 Display pointer position.
9385 */
cristyb51dff52011-05-19 16:55:47 +00009386 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009387 windows->magnify.x,windows->magnify.y);
9388 XInfoWidget(display,windows,text);
9389 }
9390 /*
9391 Wait for next event.
9392 */
cristy6710d842011-10-20 23:23:00 +00009393 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009394 switch (event->type)
9395 {
9396 case ButtonPress:
9397 break;
9398 case ButtonRelease:
9399 {
9400 /*
9401 User has finished magnifying image.
9402 */
9403 x=event->xbutton.x;
9404 y=event->xbutton.y;
9405 state|=ExitState;
9406 break;
9407 }
9408 case Expose:
9409 break;
9410 case MotionNotify:
9411 {
9412 x=event->xmotion.x;
9413 y=event->xmotion.y;
9414 break;
9415 }
9416 default:
9417 break;
9418 }
9419 /*
9420 Check boundary conditions.
9421 */
9422 if (x < 0)
9423 x=0;
9424 else
9425 if (x >= (int) windows->image.width)
9426 x=(int) windows->image.width-1;
9427 if (y < 0)
9428 y=0;
9429 else
9430 if (y >= (int) windows->image.height)
9431 y=(int) windows->image.height-1;
9432 } while ((state & ExitState) == 0);
9433 /*
9434 Display magnified image.
9435 */
9436 XSetCursorState(display,windows,MagickFalse);
9437}
9438
9439/*
9440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9441% %
9442% %
9443% %
9444+ X M a g n i f y W i n d o w C o m m a n d %
9445% %
9446% %
9447% %
9448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9449%
9450% XMagnifyWindowCommand() moves the image within an Magnify window by one
9451% pixel as specified by the key symbol.
9452%
9453% The format of the XMagnifyWindowCommand method is:
9454%
9455% void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009456% const MagickStatusType state,const KeySym key_symbol,
9457% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009458%
9459% A description of each parameter follows:
9460%
9461% o display: Specifies a connection to an X server; returned from
9462% XOpenDisplay.
9463%
9464% o windows: Specifies a pointer to a XWindows structure.
9465%
9466% o state: key mask.
9467%
9468% o key_symbol: Specifies a KeySym which indicates which side of the image
9469% to trim.
9470%
cristy6710d842011-10-20 23:23:00 +00009471% o exception: return any errors or warnings in this structure.
9472%
cristy3ed852e2009-09-05 21:47:34 +00009473*/
9474static void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009475 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009476{
9477 unsigned int
9478 quantum;
9479
9480 /*
9481 User specified a magnify factor or position.
9482 */
9483 quantum=1;
9484 if ((state & Mod1Mask) != 0)
9485 quantum=10;
9486 switch ((int) key_symbol)
9487 {
9488 case QuitCommand:
9489 {
9490 (void) XWithdrawWindow(display,windows->magnify.id,
9491 windows->magnify.screen);
9492 break;
9493 }
9494 case XK_Home:
9495 case XK_KP_Home:
9496 {
9497 windows->magnify.x=(int) windows->image.width/2;
9498 windows->magnify.y=(int) windows->image.height/2;
9499 break;
9500 }
9501 case XK_Left:
9502 case XK_KP_Left:
9503 {
9504 if (windows->magnify.x > 0)
9505 windows->magnify.x-=quantum;
9506 break;
9507 }
9508 case XK_Up:
9509 case XK_KP_Up:
9510 {
9511 if (windows->magnify.y > 0)
9512 windows->magnify.y-=quantum;
9513 break;
9514 }
9515 case XK_Right:
9516 case XK_KP_Right:
9517 {
9518 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9519 windows->magnify.x+=quantum;
9520 break;
9521 }
9522 case XK_Down:
9523 case XK_KP_Down:
9524 {
9525 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9526 windows->magnify.y+=quantum;
9527 break;
9528 }
9529 case XK_0:
9530 case XK_1:
9531 case XK_2:
9532 case XK_3:
9533 case XK_4:
9534 case XK_5:
9535 case XK_6:
9536 case XK_7:
9537 case XK_8:
9538 case XK_9:
9539 {
9540 windows->magnify.data=(key_symbol-XK_0);
9541 break;
9542 }
9543 case XK_KP_0:
9544 case XK_KP_1:
9545 case XK_KP_2:
9546 case XK_KP_3:
9547 case XK_KP_4:
9548 case XK_KP_5:
9549 case XK_KP_6:
9550 case XK_KP_7:
9551 case XK_KP_8:
9552 case XK_KP_9:
9553 {
9554 windows->magnify.data=(key_symbol-XK_KP_0);
9555 break;
9556 }
9557 default:
9558 break;
9559 }
cristy6710d842011-10-20 23:23:00 +00009560 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00009561}
9562
9563/*
9564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9565% %
9566% %
9567% %
9568+ X M a k e P a n I m a g e %
9569% %
9570% %
9571% %
9572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9573%
9574% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9575% icon window.
9576%
9577% The format of the XMakePanImage method is:
9578%
9579% void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009580% XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009581%
9582% A description of each parameter follows:
9583%
9584% o display: Specifies a connection to an X server; returned from
9585% XOpenDisplay.
9586%
9587% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9588%
9589% o windows: Specifies a pointer to a XWindows structure.
9590%
9591% o image: the image.
9592%
cristy051718b2011-08-28 22:49:25 +00009593% o exception: return any errors or warnings in this structure.
9594%
cristy3ed852e2009-09-05 21:47:34 +00009595*/
9596static void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009597 XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009598{
9599 MagickStatusType
9600 status;
9601
9602 /*
9603 Create and display image for panning icon.
9604 */
9605 XSetCursorState(display,windows,MagickTrue);
9606 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +00009607 windows->pan.x=(int) windows->image.x;
9608 windows->pan.y=(int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +00009609 status=XMakeImage(display,resource_info,&windows->pan,image,
cristy051718b2011-08-28 22:49:25 +00009610 windows->pan.width,windows->pan.height,exception);
cristy3ed852e2009-09-05 21:47:34 +00009611 if (status == MagickFalse)
cristy051718b2011-08-28 22:49:25 +00009612 ThrowXWindowFatalException(ResourceLimitError,
9613 "MemoryAllocationFailed",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00009614 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9615 windows->pan.pixmap);
9616 (void) XClearWindow(display,windows->pan.id);
9617 XDrawPanRectangle(display,windows);
9618 XSetCursorState(display,windows,MagickFalse);
9619}
9620
9621/*
9622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9623% %
9624% %
9625% %
9626+ X M a t t a E d i t I m a g e %
9627% %
9628% %
9629% %
9630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9631%
9632% XMatteEditImage() allows the user to interactively change the Matte channel
9633% of an image. If the image is PseudoClass it is promoted to DirectClass
9634% before the matte information is stored.
9635%
9636% The format of the XMatteEditImage method is:
9637%
9638% MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009639% XResourceInfo *resource_info,XWindows *windows,Image **image,
9640% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009641%
9642% A description of each parameter follows:
9643%
9644% o display: Specifies a connection to an X server; returned from
9645% XOpenDisplay.
9646%
9647% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9648%
9649% o windows: Specifies a pointer to a XWindows structure.
9650%
9651% o image: the image; returned from ReadImage.
9652%
cristy051718b2011-08-28 22:49:25 +00009653% o exception: return any errors or warnings in this structure.
9654%
cristy3ed852e2009-09-05 21:47:34 +00009655*/
9656static MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009657 XResourceInfo *resource_info,XWindows *windows,Image **image,
9658 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009659{
9660 static char
9661 matte[MaxTextExtent] = "0";
9662
9663 static const char
9664 *MatteEditMenu[] =
9665 {
9666 "Method",
9667 "Border Color",
9668 "Fuzz",
9669 "Matte Value",
9670 "Undo",
9671 "Help",
9672 "Dismiss",
9673 (char *) NULL
9674 };
9675
9676 static const ModeType
9677 MatteEditCommands[] =
9678 {
9679 MatteEditMethod,
9680 MatteEditBorderCommand,
9681 MatteEditFuzzCommand,
9682 MatteEditValueCommand,
9683 MatteEditUndoCommand,
9684 MatteEditHelpCommand,
9685 MatteEditDismissCommand
9686 };
9687
9688 static PaintMethod
9689 method = PointMethod;
9690
9691 static XColor
9692 border_color = { 0, 0, 0, 0, 0, 0 };
9693
9694 char
9695 command[MaxTextExtent],
9696 text[MaxTextExtent];
9697
9698 Cursor
9699 cursor;
9700
9701 int
9702 entry,
9703 id,
9704 x,
9705 x_offset,
9706 y,
9707 y_offset;
9708
9709 register int
9710 i;
9711
cristy4c08aed2011-07-01 19:47:50 +00009712 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00009713 *q;
9714
9715 unsigned int
9716 height,
9717 width;
9718
cristybb503372010-05-27 20:51:26 +00009719 size_t
cristy3ed852e2009-09-05 21:47:34 +00009720 state;
9721
9722 XEvent
9723 event;
9724
9725 /*
9726 Map Command widget.
9727 */
9728 (void) CloneString(&windows->command.name,"Matte Edit");
9729 windows->command.data=4;
9730 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9731 (void) XMapRaised(display,windows->command.id);
9732 XClientMessage(display,windows->image.id,windows->im_protocols,
9733 windows->im_update_widget,CurrentTime);
9734 /*
9735 Make cursor.
9736 */
9737 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9738 resource_info->background_color,resource_info->foreground_color);
9739 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9740 /*
9741 Track pointer until button 1 is pressed.
9742 */
9743 XQueryPosition(display,windows->image.id,&x,&y);
9744 (void) XSelectInput(display,windows->image.id,
9745 windows->image.attributes.event_mask | PointerMotionMask);
9746 state=DefaultState;
9747 do
9748 {
9749 if (windows->info.mapped != MagickFalse)
9750 {
9751 /*
9752 Display pointer position.
9753 */
cristyb51dff52011-05-19 16:55:47 +00009754 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009755 x+windows->image.x,y+windows->image.y);
9756 XInfoWidget(display,windows,text);
9757 }
9758 /*
9759 Wait for next event.
9760 */
cristy6710d842011-10-20 23:23:00 +00009761 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009762 if (event.xany.window == windows->command.id)
9763 {
9764 /*
9765 Select a command from the Command widget.
9766 */
9767 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9768 if (id < 0)
9769 {
9770 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9771 continue;
9772 }
9773 switch (MatteEditCommands[id])
9774 {
9775 case MatteEditMethod:
9776 {
9777 char
9778 **methods;
9779
9780 /*
9781 Select a method from the pop-up menu.
9782 */
cristy042ee782011-04-22 18:48:30 +00009783 methods=GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00009784 if (methods == (char **) NULL)
9785 break;
9786 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9787 (const char **) methods,command);
9788 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00009789 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00009790 MagickFalse,methods[entry]);
9791 methods=DestroyStringList(methods);
9792 break;
9793 }
9794 case MatteEditBorderCommand:
9795 {
9796 const char
9797 *ColorMenu[MaxNumberPens];
9798
9799 int
9800 pen_number;
9801
9802 /*
9803 Initialize menu selections.
9804 */
9805 for (i=0; i < (int) (MaxNumberPens-2); i++)
9806 ColorMenu[i]=resource_info->pen_colors[i];
9807 ColorMenu[MaxNumberPens-2]="Browser...";
9808 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9809 /*
9810 Select a pen color from the pop-up menu.
9811 */
9812 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9813 (const char **) ColorMenu,command);
9814 if (pen_number < 0)
9815 break;
9816 if (pen_number == (MaxNumberPens-2))
9817 {
9818 static char
9819 color_name[MaxTextExtent] = "gray";
9820
9821 /*
9822 Select a pen color from a dialog.
9823 */
9824 resource_info->pen_colors[pen_number]=color_name;
9825 XColorBrowserWidget(display,windows,"Select",color_name);
9826 if (*color_name == '\0')
9827 break;
9828 }
9829 /*
9830 Set border color.
9831 */
9832 (void) XParseColor(display,windows->map_info->colormap,
9833 resource_info->pen_colors[pen_number],&border_color);
9834 break;
9835 }
9836 case MatteEditFuzzCommand:
9837 {
9838 static char
9839 fuzz[MaxTextExtent];
9840
9841 static const char
9842 *FuzzMenu[] =
9843 {
9844 "0%",
9845 "2%",
9846 "5%",
9847 "10%",
9848 "15%",
9849 "Dialog...",
9850 (char *) NULL,
9851 };
9852
9853 /*
9854 Select a command from the pop-up menu.
9855 */
9856 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9857 command);
9858 if (entry < 0)
9859 break;
9860 if (entry != 5)
9861 {
cristydbdd0e32011-11-04 23:29:40 +00009862 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy4c08aed2011-07-01 19:47:50 +00009863 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009864 break;
9865 }
9866 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9867 (void) XDialogWidget(display,windows,"Ok",
9868 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9869 if (*fuzz == '\0')
9870 break;
9871 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristy9b34e302011-11-05 02:15:45 +00009872 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9873 1.0);
cristy3ed852e2009-09-05 21:47:34 +00009874 break;
9875 }
9876 case MatteEditValueCommand:
9877 {
9878 static char
9879 message[MaxTextExtent];
9880
9881 static const char
9882 *MatteMenu[] =
9883 {
9884 "Opaque",
9885 "Transparent",
9886 "Dialog...",
9887 (char *) NULL,
9888 };
9889
9890 /*
9891 Select a command from the pop-up menu.
9892 */
9893 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9894 command);
9895 if (entry < 0)
9896 break;
9897 if (entry != 2)
9898 {
cristyb51dff52011-05-19 16:55:47 +00009899 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009900 OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009901 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
cristyb51dff52011-05-19 16:55:47 +00009902 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009903 (Quantum) TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009904 break;
9905 }
cristyb51dff52011-05-19 16:55:47 +00009906 (void) FormatLocaleString(message,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009907 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9908 QuantumRange);
9909 (void) XDialogWidget(display,windows,"Matte",message,matte);
9910 if (*matte == '\0')
9911 break;
9912 break;
9913 }
9914 case MatteEditUndoCommand:
9915 {
9916 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00009917 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009918 break;
9919 }
9920 case MatteEditHelpCommand:
9921 {
9922 XTextViewWidget(display,resource_info,windows,MagickFalse,
9923 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9924 break;
9925 }
9926 case MatteEditDismissCommand:
9927 {
9928 /*
9929 Prematurely exit.
9930 */
9931 state|=EscapeState;
9932 state|=ExitState;
9933 break;
9934 }
9935 default:
9936 break;
9937 }
9938 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9939 continue;
9940 }
9941 switch (event.type)
9942 {
9943 case ButtonPress:
9944 {
9945 if (event.xbutton.button != Button1)
9946 break;
9947 if ((event.xbutton.window != windows->image.id) &&
9948 (event.xbutton.window != windows->magnify.id))
9949 break;
9950 /*
9951 Update matte data.
9952 */
9953 x=event.xbutton.x;
9954 y=event.xbutton.y;
9955 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00009956 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009957 state|=UpdateConfigurationState;
9958 break;
9959 }
9960 case ButtonRelease:
9961 {
9962 if (event.xbutton.button != Button1)
9963 break;
9964 if ((event.xbutton.window != windows->image.id) &&
9965 (event.xbutton.window != windows->magnify.id))
9966 break;
9967 /*
9968 Update colormap information.
9969 */
9970 x=event.xbutton.x;
9971 y=event.xbutton.y;
cristy6710d842011-10-20 23:23:00 +00009972 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00009973 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009974 XInfoWidget(display,windows,text);
9975 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9976 state&=(~UpdateConfigurationState);
9977 break;
9978 }
9979 case Expose:
9980 break;
9981 case KeyPress:
9982 {
9983 char
9984 command[MaxTextExtent];
9985
9986 KeySym
9987 key_symbol;
9988
9989 if (event.xkey.window == windows->magnify.id)
9990 {
9991 Window
9992 window;
9993
9994 window=windows->magnify.id;
9995 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9996 }
9997 if (event.xkey.window != windows->image.id)
9998 break;
9999 /*
10000 Respond to a user key press.
10001 */
10002 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
10003 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10004 switch ((int) key_symbol)
10005 {
10006 case XK_Escape:
10007 case XK_F20:
10008 {
10009 /*
10010 Prematurely exit.
10011 */
10012 state|=ExitState;
10013 break;
10014 }
10015 case XK_F1:
10016 case XK_Help:
10017 {
10018 XTextViewWidget(display,resource_info,windows,MagickFalse,
10019 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10020 break;
10021 }
10022 default:
10023 {
10024 (void) XBell(display,0);
10025 break;
10026 }
10027 }
10028 break;
10029 }
10030 case MotionNotify:
10031 {
10032 /*
10033 Map and unmap Info widget as cursor crosses its boundaries.
10034 */
10035 x=event.xmotion.x;
10036 y=event.xmotion.y;
10037 if (windows->info.mapped != MagickFalse)
10038 {
10039 if ((x < (int) (windows->info.x+windows->info.width)) &&
10040 (y < (int) (windows->info.y+windows->info.height)))
10041 (void) XWithdrawWindow(display,windows->info.id,
10042 windows->info.screen);
10043 }
10044 else
10045 if ((x > (int) (windows->info.x+windows->info.width)) ||
10046 (y > (int) (windows->info.y+windows->info.height)))
10047 (void) XMapWindow(display,windows->info.id);
10048 break;
10049 }
10050 default:
10051 break;
10052 }
10053 if (event.xany.window == windows->magnify.id)
10054 {
10055 x=windows->magnify.x-windows->image.x;
10056 y=windows->magnify.y-windows->image.y;
10057 }
10058 x_offset=x;
10059 y_offset=y;
10060 if ((state & UpdateConfigurationState) != 0)
10061 {
cristy49e2d862010-11-12 02:50:30 +000010062 CacheView
10063 *image_view;
10064
cristy3ed852e2009-09-05 21:47:34 +000010065 int
10066 x,
10067 y;
10068
10069 /*
10070 Matte edit is relative to image configuration.
10071 */
10072 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10073 MagickTrue);
10074 XPutPixel(windows->image.ximage,x_offset,y_offset,
10075 windows->pixel_info->background_color.pixel);
10076 width=(unsigned int) (*image)->columns;
10077 height=(unsigned int) (*image)->rows;
10078 x=0;
10079 y=0;
10080 if (windows->image.crop_geometry != (char *) NULL)
cristy4c08aed2011-07-01 19:47:50 +000010081 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10082 &height);
10083 x_offset=(int) (width*(windows->image.x+x_offset)/
10084 windows->image.ximage->width+x);
10085 y_offset=(int) (height*(windows->image.y+y_offset)/
10086 windows->image.ximage->height+y);
cristy3ed852e2009-09-05 21:47:34 +000010087 if ((x_offset < 0) || (y_offset < 0))
10088 continue;
10089 if ((x_offset >= (int) (*image)->columns) ||
10090 (y_offset >= (int) (*image)->rows))
10091 continue;
cristy574cc262011-08-05 01:23:58 +000010092 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010093 return(MagickFalse);
cristycd515282011-12-27 01:40:49 +000010094 if ((*image)->matte == MagickFalse)
10095 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
cristydb070952012-04-20 14:33:00 +000010096 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010097 switch (method)
10098 {
10099 case PointMethod:
10100 default:
10101 {
10102 /*
10103 Update matte information using point algorithm.
10104 */
cristy49e2d862010-11-12 02:50:30 +000010105 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10106 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010107 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010108 break;
cristy4c08aed2011-07-01 19:47:50 +000010109 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristy49e2d862010-11-12 02:50:30 +000010110 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +000010111 break;
10112 }
10113 case ReplaceMethod:
10114 {
cristy101ab702011-10-13 13:06:32 +000010115 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +000010116 pixel,
cristy3ed852e2009-09-05 21:47:34 +000010117 target;
10118
10119 /*
10120 Update matte information using replace algorithm.
10121 */
cristyf05d4942012-03-17 16:26:09 +000010122 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10123 x_offset,(ssize_t) y_offset,&target,exception);
cristy49e2d862010-11-12 02:50:30 +000010124 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010125 {
cristy49e2d862010-11-12 02:50:30 +000010126 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
cristy051718b2011-08-28 22:49:25 +000010127 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010128 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010129 break;
10130 for (x=0; x < (int) (*image)->columns; x++)
10131 {
cristy101ab702011-10-13 13:06:32 +000010132 GetPixelInfoPixel(*image,q,&pixel);
10133 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy4c08aed2011-07-01 19:47:50 +000010134 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010135 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010136 }
cristy49e2d862010-11-12 02:50:30 +000010137 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010138 break;
10139 }
10140 break;
10141 }
10142 case FloodfillMethod:
10143 case FillToBorderMethod:
10144 {
cristybd5a96c2011-08-21 00:04:26 +000010145 ChannelType
10146 channel_mask;
10147
cristy3ed852e2009-09-05 21:47:34 +000010148 DrawInfo
10149 *draw_info;
10150
cristy4c08aed2011-07-01 19:47:50 +000010151 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000010152 target;
10153
10154 /*
10155 Update matte information using floodfill algorithm.
10156 */
cristy3aa93752011-12-18 15:54:24 +000010157 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +000010158 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10159 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +000010160 if (method == FillToBorderMethod)
10161 {
cristy4c08aed2011-07-01 19:47:50 +000010162 target.red=(MagickRealType) ScaleShortToQuantum(
10163 border_color.red);
10164 target.green=(MagickRealType) ScaleShortToQuantum(
10165 border_color.green);
10166 target.blue=(MagickRealType) ScaleShortToQuantum(
10167 border_color.blue);
cristy3ed852e2009-09-05 21:47:34 +000010168 }
10169 draw_info=CloneDrawInfo(resource_info->image_info,
10170 (DrawInfo *) NULL);
cristye42f6582012-02-11 17:59:50 +000010171 draw_info->fill.alpha=(MagickRealType) ClampToQuantum(
10172 StringToDouble(matte,(char **) NULL));
cristybd5a96c2011-08-21 00:04:26 +000010173 channel_mask=SetPixelChannelMask(*image,AlphaChannel);
cristyd42d9952011-07-08 14:21:50 +000010174 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10175 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
cristy189e84c2011-08-27 18:08:53 +000010176 MagickFalse : MagickTrue,exception);
cristye2a912b2011-12-05 20:02:07 +000010177 (void) SetPixelChannelMapMask(*image,channel_mask);
cristy3ed852e2009-09-05 21:47:34 +000010178 draw_info=DestroyDrawInfo(draw_info);
10179 break;
10180 }
10181 case ResetMethod:
10182 {
10183 /*
10184 Update matte information using reset algorithm.
10185 */
cristy574cc262011-08-05 01:23:58 +000010186 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010187 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +000010188 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010189 {
cristy49e2d862010-11-12 02:50:30 +000010190 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10191 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010192 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010193 break;
10194 for (x=0; x < (int) (*image)->columns; x++)
10195 {
cristy4c08aed2011-07-01 19:47:50 +000010196 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010197 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010198 }
cristy49e2d862010-11-12 02:50:30 +000010199 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010200 break;
10201 }
cristy4c08aed2011-07-01 19:47:50 +000010202 if (StringToLong(matte) == (long) OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +000010203 (*image)->matte=MagickFalse;
10204 break;
10205 }
10206 }
cristy49e2d862010-11-12 02:50:30 +000010207 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000010208 state&=(~UpdateConfigurationState);
10209 }
10210 } while ((state & ExitState) == 0);
10211 (void) XSelectInput(display,windows->image.id,
10212 windows->image.attributes.event_mask);
10213 XSetCursorState(display,windows,MagickFalse);
10214 (void) XFreeCursor(display,cursor);
10215 return(MagickTrue);
10216}
10217
10218/*
10219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10220% %
10221% %
10222% %
10223+ X O p e n I m a g e %
10224% %
10225% %
10226% %
10227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10228%
10229% XOpenImage() loads an image from a file.
10230%
10231% The format of the XOpenImage method is:
10232%
10233% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10234% XWindows *windows,const unsigned int command)
10235%
10236% A description of each parameter follows:
10237%
10238% o display: Specifies a connection to an X server; returned from
10239% XOpenDisplay.
10240%
10241% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10242%
10243% o windows: Specifies a pointer to a XWindows structure.
10244%
10245% o command: A value other than zero indicates that the file is selected
10246% from the command line argument list.
10247%
10248*/
10249static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10250 XWindows *windows,const MagickBooleanType command)
10251{
10252 const MagickInfo
10253 *magick_info;
10254
10255 ExceptionInfo
10256 *exception;
10257
10258 Image
10259 *nexus;
10260
10261 ImageInfo
10262 *image_info;
10263
10264 static char
10265 filename[MaxTextExtent] = "\0";
10266
10267 /*
10268 Request file name from user.
10269 */
10270 if (command == MagickFalse)
10271 XFileBrowserWidget(display,windows,"Open",filename);
10272 else
10273 {
10274 char
10275 **filelist,
10276 **files;
10277
10278 int
10279 count,
10280 status;
10281
10282 register int
10283 i,
10284 j;
10285
10286 /*
10287 Select next image from the command line.
10288 */
10289 status=XGetCommand(display,windows->image.id,&files,&count);
10290 if (status == 0)
10291 {
10292 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10293 return((Image *) NULL);
10294 }
10295 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10296 if (filelist == (char **) NULL)
10297 {
10298 ThrowXWindowFatalException(ResourceLimitError,
10299 "MemoryAllocationFailed","...");
10300 (void) XFreeStringList(files);
10301 return((Image *) NULL);
10302 }
10303 j=0;
10304 for (i=1; i < count; i++)
10305 if (*files[i] != '-')
10306 filelist[j++]=files[i];
10307 filelist[j]=(char *) NULL;
10308 XListBrowserWidget(display,windows,&windows->widget,
10309 (const char **) filelist,"Load","Select Image to Load:",filename);
10310 filelist=(char **) RelinquishMagickMemory(filelist);
10311 (void) XFreeStringList(files);
10312 }
10313 if (*filename == '\0')
10314 return((Image *) NULL);
10315 image_info=CloneImageInfo(resource_info->image_info);
10316 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10317 (void *) NULL);
10318 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10319 exception=AcquireExceptionInfo();
cristyd965a422010-03-03 17:47:35 +000010320 (void) SetImageInfo(image_info,0,exception);
cristy3ed852e2009-09-05 21:47:34 +000010321 if (LocaleCompare(image_info->magick,"X") == 0)
10322 {
10323 char
10324 seconds[MaxTextExtent];
10325
10326 /*
10327 User may want to delay the X server screen grab.
10328 */
10329 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10330 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10331 seconds);
10332 if (*seconds == '\0')
10333 return((Image *) NULL);
cristybb503372010-05-27 20:51:26 +000010334 XDelay(display,(size_t) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010335 }
10336 magick_info=GetMagickInfo(image_info->magick,exception);
10337 if ((magick_info != (const MagickInfo *) NULL) &&
10338 (magick_info->raw != MagickFalse))
10339 {
10340 char
10341 geometry[MaxTextExtent];
10342
10343 /*
10344 Request image size from the user.
10345 */
10346 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10347 if (image_info->size != (char *) NULL)
10348 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10349 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10350 geometry);
10351 (void) CloneString(&image_info->size,geometry);
10352 }
10353 /*
10354 Load the image.
10355 */
10356 XSetCursorState(display,windows,MagickTrue);
10357 XCheckRefreshWindows(display,windows);
10358 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10359 nexus=ReadImage(image_info,exception);
10360 CatchException(exception);
10361 XSetCursorState(display,windows,MagickFalse);
10362 if (nexus != (Image *) NULL)
10363 XClientMessage(display,windows->image.id,windows->im_protocols,
10364 windows->im_next_image,CurrentTime);
10365 else
10366 {
10367 char
10368 *text,
10369 **textlist;
10370
10371 /*
10372 Unknown image format.
10373 */
10374 text=FileToString(filename,~0,exception);
10375 if (text == (char *) NULL)
10376 return((Image *) NULL);
10377 textlist=StringToList(text);
10378 if (textlist != (char **) NULL)
10379 {
10380 char
10381 title[MaxTextExtent];
10382
10383 register int
10384 i;
10385
cristyb51dff52011-05-19 16:55:47 +000010386 (void) FormatLocaleString(title,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000010387 "Unknown format: %s",filename);
10388 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10389 (const char **) textlist);
10390 for (i=0; textlist[i] != (char *) NULL; i++)
10391 textlist[i]=DestroyString(textlist[i]);
10392 textlist=(char **) RelinquishMagickMemory(textlist);
10393 }
10394 text=DestroyString(text);
10395 }
10396 exception=DestroyExceptionInfo(exception);
10397 image_info=DestroyImageInfo(image_info);
10398 return(nexus);
10399}
10400
10401/*
10402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10403% %
10404% %
10405% %
10406+ X P a n I m a g e %
10407% %
10408% %
10409% %
10410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10411%
10412% XPanImage() pans the image until the mouse button is released.
10413%
10414% The format of the XPanImage method is:
10415%
cristy6710d842011-10-20 23:23:00 +000010416% void XPanImage(Display *display,XWindows *windows,XEvent *event,
10417% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010418%
10419% A description of each parameter follows:
10420%
10421% o display: Specifies a connection to an X server; returned from
10422% XOpenDisplay.
10423%
10424% o windows: Specifies a pointer to a XWindows structure.
10425%
10426% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10427% the entire image is refreshed.
10428%
cristy6710d842011-10-20 23:23:00 +000010429% o exception: return any errors or warnings in this structure.
10430%
cristy3ed852e2009-09-05 21:47:34 +000010431*/
cristy6710d842011-10-20 23:23:00 +000010432static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10433 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010434{
10435 char
10436 text[MaxTextExtent];
10437
10438 Cursor
10439 cursor;
10440
10441 MagickRealType
10442 x_factor,
10443 y_factor;
10444
10445 RectangleInfo
10446 pan_info;
10447
cristybb503372010-05-27 20:51:26 +000010448 size_t
cristy3ed852e2009-09-05 21:47:34 +000010449 state;
10450
10451 /*
10452 Define cursor.
10453 */
10454 if ((windows->image.ximage->width > (int) windows->image.width) &&
10455 (windows->image.ximage->height > (int) windows->image.height))
10456 cursor=XCreateFontCursor(display,XC_fleur);
10457 else
10458 if (windows->image.ximage->width > (int) windows->image.width)
10459 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10460 else
10461 if (windows->image.ximage->height > (int) windows->image.height)
10462 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10463 else
10464 cursor=XCreateFontCursor(display,XC_arrow);
10465 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10466 /*
10467 Pan image as pointer moves until the mouse button is released.
10468 */
10469 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10470 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10471 pan_info.width=windows->pan.width*windows->image.width/
10472 windows->image.ximage->width;
10473 pan_info.height=windows->pan.height*windows->image.height/
10474 windows->image.ximage->height;
10475 pan_info.x=0;
10476 pan_info.y=0;
10477 state=UpdateConfigurationState;
10478 do
10479 {
10480 switch (event->type)
10481 {
10482 case ButtonPress:
10483 {
10484 /*
10485 User choose an initial pan location.
10486 */
cristy49e2d862010-11-12 02:50:30 +000010487 pan_info.x=(ssize_t) event->xbutton.x;
10488 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010489 state|=UpdateConfigurationState;
10490 break;
10491 }
10492 case ButtonRelease:
10493 {
10494 /*
10495 User has finished panning the image.
10496 */
cristy49e2d862010-11-12 02:50:30 +000010497 pan_info.x=(ssize_t) event->xbutton.x;
10498 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010499 state|=UpdateConfigurationState | ExitState;
10500 break;
10501 }
10502 case MotionNotify:
10503 {
cristy49e2d862010-11-12 02:50:30 +000010504 pan_info.x=(ssize_t) event->xmotion.x;
10505 pan_info.y=(ssize_t) event->xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000010506 state|=UpdateConfigurationState;
10507 }
10508 default:
10509 break;
10510 }
10511 if ((state & UpdateConfigurationState) != 0)
10512 {
10513 /*
10514 Check boundary conditions.
10515 */
cristy49e2d862010-11-12 02:50:30 +000010516 if (pan_info.x < (ssize_t) (pan_info.width/2))
cristy3ed852e2009-09-05 21:47:34 +000010517 pan_info.x=0;
10518 else
cristy49e2d862010-11-12 02:50:30 +000010519 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
cristy3ed852e2009-09-05 21:47:34 +000010520 if (pan_info.x < 0)
10521 pan_info.x=0;
10522 else
10523 if ((int) (pan_info.x+windows->image.width) >
10524 windows->image.ximage->width)
cristybb503372010-05-27 20:51:26 +000010525 pan_info.x=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010526 (windows->image.ximage->width-windows->image.width);
cristybb503372010-05-27 20:51:26 +000010527 if (pan_info.y < (ssize_t) (pan_info.height/2))
cristy3ed852e2009-09-05 21:47:34 +000010528 pan_info.y=0;
10529 else
cristybb503372010-05-27 20:51:26 +000010530 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
cristy3ed852e2009-09-05 21:47:34 +000010531 if (pan_info.y < 0)
10532 pan_info.y=0;
10533 else
10534 if ((int) (pan_info.y+windows->image.height) >
10535 windows->image.ximage->height)
cristybb503372010-05-27 20:51:26 +000010536 pan_info.y=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010537 (windows->image.ximage->height-windows->image.height);
10538 if ((windows->image.x != (int) pan_info.x) ||
10539 (windows->image.y != (int) pan_info.y))
10540 {
10541 /*
10542 Display image pan offset.
10543 */
10544 windows->image.x=(int) pan_info.x;
10545 windows->image.y=(int) pan_info.y;
cristyb51dff52011-05-19 16:55:47 +000010546 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000010547 windows->image.width,windows->image.height,windows->image.x,
10548 windows->image.y);
10549 XInfoWidget(display,windows,text);
10550 /*
10551 Refresh Image window.
10552 */
10553 XDrawPanRectangle(display,windows);
10554 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10555 }
10556 state&=(~UpdateConfigurationState);
10557 }
10558 /*
10559 Wait for next event.
10560 */
10561 if ((state & ExitState) == 0)
cristy6710d842011-10-20 23:23:00 +000010562 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010563 } while ((state & ExitState) == 0);
10564 /*
10565 Restore cursor.
10566 */
10567 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10568 (void) XFreeCursor(display,cursor);
10569 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10570}
10571
10572/*
10573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10574% %
10575% %
10576% %
10577+ X P a s t e I m a g e %
10578% %
10579% %
10580% %
10581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10582%
10583% XPasteImage() pastes an image previously saved with XCropImage in the X
10584% window image at a location the user chooses with the pointer.
10585%
10586% The format of the XPasteImage method is:
10587%
10588% MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010589% XResourceInfo *resource_info,XWindows *windows,Image *image,
10590% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010591%
10592% A description of each parameter follows:
10593%
10594% o display: Specifies a connection to an X server; returned from
10595% XOpenDisplay.
10596%
10597% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10598%
10599% o windows: Specifies a pointer to a XWindows structure.
10600%
10601% o image: the image; returned from ReadImage.
10602%
cristy051718b2011-08-28 22:49:25 +000010603% o exception: return any errors or warnings in this structure.
10604%
cristy3ed852e2009-09-05 21:47:34 +000010605*/
10606static MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010607 XResourceInfo *resource_info,XWindows *windows,Image *image,
10608 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010609{
10610 static const char
10611 *PasteMenu[] =
10612 {
10613 "Operator",
10614 "Help",
10615 "Dismiss",
10616 (char *) NULL
10617 };
10618
10619 static const ModeType
10620 PasteCommands[] =
10621 {
10622 PasteOperatorsCommand,
10623 PasteHelpCommand,
10624 PasteDismissCommand
10625 };
10626
10627 static CompositeOperator
10628 compose = CopyCompositeOp;
10629
10630 char
10631 text[MaxTextExtent];
10632
10633 Cursor
10634 cursor;
10635
10636 Image
10637 *paste_image;
10638
10639 int
10640 entry,
10641 id,
10642 x,
10643 y;
10644
10645 MagickRealType
10646 scale_factor;
10647
10648 RectangleInfo
10649 highlight_info,
10650 paste_info;
10651
10652 unsigned int
10653 height,
10654 width;
10655
cristybb503372010-05-27 20:51:26 +000010656 size_t
cristy3ed852e2009-09-05 21:47:34 +000010657 state;
10658
10659 XEvent
10660 event;
10661
10662 /*
10663 Copy image.
10664 */
10665 if (resource_info->copy_image == (Image *) NULL)
10666 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +000010667 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000010668 /*
10669 Map Command widget.
10670 */
10671 (void) CloneString(&windows->command.name,"Paste");
10672 windows->command.data=1;
10673 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10674 (void) XMapRaised(display,windows->command.id);
10675 XClientMessage(display,windows->image.id,windows->im_protocols,
10676 windows->im_update_widget,CurrentTime);
10677 /*
10678 Track pointer until button 1 is pressed.
10679 */
10680 XSetCursorState(display,windows,MagickFalse);
10681 XQueryPosition(display,windows->image.id,&x,&y);
10682 (void) XSelectInput(display,windows->image.id,
10683 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000010684 paste_info.x=(ssize_t) windows->image.x+x;
10685 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010686 paste_info.width=0;
10687 paste_info.height=0;
10688 cursor=XCreateFontCursor(display,XC_ul_angle);
10689 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10690 state=DefaultState;
10691 do
10692 {
10693 if (windows->info.mapped != MagickFalse)
10694 {
10695 /*
10696 Display pointer position.
10697 */
cristyb51dff52011-05-19 16:55:47 +000010698 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000010699 (long) paste_info.x,(long) paste_info.y);
cristy3ed852e2009-09-05 21:47:34 +000010700 XInfoWidget(display,windows,text);
10701 }
10702 highlight_info=paste_info;
10703 highlight_info.x=paste_info.x-windows->image.x;
10704 highlight_info.y=paste_info.y-windows->image.y;
10705 XHighlightRectangle(display,windows->image.id,
10706 windows->image.highlight_context,&highlight_info);
10707 /*
10708 Wait for next event.
10709 */
cristy6710d842011-10-20 23:23:00 +000010710 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010711 XHighlightRectangle(display,windows->image.id,
10712 windows->image.highlight_context,&highlight_info);
10713 if (event.xany.window == windows->command.id)
10714 {
10715 /*
10716 Select a command from the Command widget.
10717 */
10718 id=XCommandWidget(display,windows,PasteMenu,&event);
10719 if (id < 0)
10720 continue;
10721 switch (PasteCommands[id])
10722 {
10723 case PasteOperatorsCommand:
10724 {
10725 char
10726 command[MaxTextExtent],
10727 **operators;
10728
10729 /*
10730 Select a command from the pop-up menu.
10731 */
cristy042ee782011-04-22 18:48:30 +000010732 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +000010733 if (operators == (char **) NULL)
10734 break;
10735 entry=XMenuWidget(display,windows,PasteMenu[id],
10736 (const char **) operators,command);
10737 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +000010738 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +000010739 MagickComposeOptions,MagickFalse,operators[entry]);
10740 operators=DestroyStringList(operators);
10741 break;
10742 }
10743 case PasteHelpCommand:
10744 {
10745 XTextViewWidget(display,resource_info,windows,MagickFalse,
10746 "Help Viewer - Image Composite",ImagePasteHelp);
10747 break;
10748 }
10749 case PasteDismissCommand:
10750 {
10751 /*
10752 Prematurely exit.
10753 */
10754 state|=EscapeState;
10755 state|=ExitState;
10756 break;
10757 }
10758 default:
10759 break;
10760 }
10761 continue;
10762 }
10763 switch (event.type)
10764 {
10765 case ButtonPress:
10766 {
10767 if (image->debug != MagickFalse)
10768 (void) LogMagickEvent(X11Event,GetMagickModule(),
10769 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10770 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10771 if (event.xbutton.button != Button1)
10772 break;
10773 if (event.xbutton.window != windows->image.id)
10774 break;
10775 /*
10776 Paste rectangle is relative to image configuration.
10777 */
10778 width=(unsigned int) image->columns;
10779 height=(unsigned int) image->rows;
10780 x=0;
10781 y=0;
10782 if (windows->image.crop_geometry != (char *) NULL)
10783 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10784 &width,&height);
10785 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10786 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10787 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10788 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10789 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000010790 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10791 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010792 break;
10793 }
10794 case ButtonRelease:
10795 {
10796 if (image->debug != MagickFalse)
10797 (void) LogMagickEvent(X11Event,GetMagickModule(),
10798 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10799 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10800 if (event.xbutton.button != Button1)
10801 break;
10802 if (event.xbutton.window != windows->image.id)
10803 break;
10804 if ((paste_info.width != 0) && (paste_info.height != 0))
10805 {
10806 /*
10807 User has selected the location of the paste image.
10808 */
cristy49e2d862010-11-12 02:50:30 +000010809 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10810 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010811 state|=ExitState;
10812 }
10813 break;
10814 }
10815 case Expose:
10816 break;
10817 case KeyPress:
10818 {
10819 char
10820 command[MaxTextExtent];
10821
10822 KeySym
10823 key_symbol;
10824
10825 int
10826 length;
10827
10828 if (event.xkey.window != windows->image.id)
10829 break;
10830 /*
10831 Respond to a user key press.
10832 */
10833 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10834 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10835 *(command+length)='\0';
10836 if (image->debug != MagickFalse)
10837 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000010838 "Key press: 0x%lx (%s)",(long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +000010839 switch ((int) key_symbol)
10840 {
10841 case XK_Escape:
10842 case XK_F20:
10843 {
10844 /*
10845 Prematurely exit.
10846 */
10847 paste_image=DestroyImage(paste_image);
10848 state|=EscapeState;
10849 state|=ExitState;
10850 break;
10851 }
10852 case XK_F1:
10853 case XK_Help:
10854 {
10855 (void) XSetFunction(display,windows->image.highlight_context,
10856 GXcopy);
10857 XTextViewWidget(display,resource_info,windows,MagickFalse,
10858 "Help Viewer - Image Composite",ImagePasteHelp);
10859 (void) XSetFunction(display,windows->image.highlight_context,
10860 GXinvert);
10861 break;
10862 }
10863 default:
10864 {
10865 (void) XBell(display,0);
10866 break;
10867 }
10868 }
10869 break;
10870 }
10871 case MotionNotify:
10872 {
10873 /*
10874 Map and unmap Info widget as text cursor crosses its boundaries.
10875 */
10876 x=event.xmotion.x;
10877 y=event.xmotion.y;
10878 if (windows->info.mapped != MagickFalse)
10879 {
10880 if ((x < (int) (windows->info.x+windows->info.width)) &&
10881 (y < (int) (windows->info.y+windows->info.height)))
10882 (void) XWithdrawWindow(display,windows->info.id,
10883 windows->info.screen);
10884 }
10885 else
10886 if ((x > (int) (windows->info.x+windows->info.width)) ||
10887 (y > (int) (windows->info.y+windows->info.height)))
10888 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000010889 paste_info.x=(ssize_t) windows->image.x+x;
10890 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010891 break;
10892 }
10893 default:
10894 {
10895 if (image->debug != MagickFalse)
10896 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10897 event.type);
10898 break;
10899 }
10900 }
10901 } while ((state & ExitState) == 0);
10902 (void) XSelectInput(display,windows->image.id,
10903 windows->image.attributes.event_mask);
10904 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10905 XSetCursorState(display,windows,MagickFalse);
10906 (void) XFreeCursor(display,cursor);
10907 if ((state & EscapeState) != 0)
10908 return(MagickTrue);
10909 /*
10910 Image pasting is relative to image configuration.
10911 */
10912 XSetCursorState(display,windows,MagickTrue);
10913 XCheckRefreshWindows(display,windows);
10914 width=(unsigned int) image->columns;
10915 height=(unsigned int) image->rows;
10916 x=0;
10917 y=0;
10918 if (windows->image.crop_geometry != (char *) NULL)
10919 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10920 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10921 paste_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000010922 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010923 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10924 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10925 paste_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000010926 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010927 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10928 /*
10929 Paste image with X Image window.
10930 */
cristy39172402012-03-30 13:04:39 +000010931 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
cristyfeb3e962012-03-29 17:25:55 +000010932 paste_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000010933 paste_image=DestroyImage(paste_image);
10934 XSetCursorState(display,windows,MagickFalse);
10935 /*
10936 Update image colormap.
10937 */
cristy6710d842011-10-20 23:23:00 +000010938 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000010939 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010940 return(MagickTrue);
10941}
10942
10943/*
10944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10945% %
10946% %
10947% %
10948+ X P r i n t I m a g e %
10949% %
10950% %
10951% %
10952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10953%
10954% XPrintImage() prints an image to a Postscript printer.
10955%
10956% The format of the XPrintImage method is:
10957%
10958% MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010959% XResourceInfo *resource_info,XWindows *windows,Image *image,
10960% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010961%
10962% A description of each parameter follows:
10963%
10964% o display: Specifies a connection to an X server; returned from
10965% XOpenDisplay.
10966%
10967% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10968%
10969% o windows: Specifies a pointer to a XWindows structure.
10970%
10971% o image: the image.
10972%
cristy051718b2011-08-28 22:49:25 +000010973% o exception: return any errors or warnings in this structure.
10974%
cristy3ed852e2009-09-05 21:47:34 +000010975*/
10976static MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010977 XResourceInfo *resource_info,XWindows *windows,Image *image,
10978 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010979{
10980 char
10981 filename[MaxTextExtent],
10982 geometry[MaxTextExtent];
10983
10984 Image
10985 *print_image;
10986
10987 ImageInfo
10988 *image_info;
10989
10990 MagickStatusType
10991 status;
10992
10993 /*
10994 Request Postscript page geometry from user.
10995 */
10996 image_info=CloneImageInfo(resource_info->image_info);
cristyb51dff52011-05-19 16:55:47 +000010997 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
cristy3ed852e2009-09-05 21:47:34 +000010998 if (image_info->page != (char *) NULL)
10999 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
11000 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
11001 "Select Postscript Page Geometry:",geometry);
11002 if (*geometry == '\0')
11003 return(MagickTrue);
11004 image_info->page=GetPageGeometry(geometry);
11005 /*
11006 Apply image transforms.
11007 */
11008 XSetCursorState(display,windows,MagickTrue);
11009 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000011010 print_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000011011 if (print_image == (Image *) NULL)
11012 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000011013 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000011014 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000011015 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11016 exception);
cristy3ed852e2009-09-05 21:47:34 +000011017 /*
11018 Print image.
11019 */
11020 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +000011021 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
cristy3ed852e2009-09-05 21:47:34 +000011022 filename);
cristy051718b2011-08-28 22:49:25 +000011023 status=WriteImage(image_info,print_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011024 (void) RelinquishUniqueFileResource(filename);
11025 print_image=DestroyImage(print_image);
11026 image_info=DestroyImageInfo(image_info);
11027 XSetCursorState(display,windows,MagickFalse);
11028 return(status != 0 ? MagickTrue : MagickFalse);
11029}
11030
11031/*
11032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11033% %
11034% %
11035% %
11036+ X R O I I m a g e %
11037% %
11038% %
11039% %
11040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11041%
11042% XROIImage() applies an image processing technique to a region of interest.
11043%
11044% The format of the XROIImage method is:
11045%
11046% MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011047% XResourceInfo *resource_info,XWindows *windows,Image **image,
11048% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011049%
11050% A description of each parameter follows:
11051%
11052% o display: Specifies a connection to an X server; returned from
11053% XOpenDisplay.
11054%
11055% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11056%
11057% o windows: Specifies a pointer to a XWindows structure.
11058%
11059% o image: the image; returned from ReadImage.
11060%
cristy051718b2011-08-28 22:49:25 +000011061% o exception: return any errors or warnings in this structure.
11062%
cristy3ed852e2009-09-05 21:47:34 +000011063*/
11064static MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011065 XResourceInfo *resource_info,XWindows *windows,Image **image,
11066 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011067{
11068#define ApplyMenus 7
11069
11070 static const char
11071 *ROIMenu[] =
11072 {
11073 "Help",
11074 "Dismiss",
11075 (char *) NULL
11076 },
11077 *ApplyMenu[] =
11078 {
11079 "File",
11080 "Edit",
11081 "Transform",
11082 "Enhance",
11083 "Effects",
11084 "F/X",
11085 "Miscellany",
11086 "Help",
11087 "Dismiss",
11088 (char *) NULL
11089 },
11090 *FileMenu[] =
11091 {
11092 "Save...",
11093 "Print...",
11094 (char *) NULL
11095 },
11096 *EditMenu[] =
11097 {
11098 "Undo",
11099 "Redo",
11100 (char *) NULL
11101 },
11102 *TransformMenu[] =
11103 {
11104 "Flop",
11105 "Flip",
11106 "Rotate Right",
11107 "Rotate Left",
11108 (char *) NULL
11109 },
11110 *EnhanceMenu[] =
11111 {
11112 "Hue...",
11113 "Saturation...",
11114 "Brightness...",
11115 "Gamma...",
11116 "Spiff",
11117 "Dull",
11118 "Contrast Stretch...",
11119 "Sigmoidal Contrast...",
11120 "Normalize",
11121 "Equalize",
11122 "Negate",
11123 "Grayscale",
11124 "Map...",
11125 "Quantize...",
11126 (char *) NULL
11127 },
11128 *EffectsMenu[] =
11129 {
11130 "Despeckle",
11131 "Emboss",
11132 "Reduce Noise",
11133 "Add Noise",
11134 "Sharpen...",
11135 "Blur...",
11136 "Threshold...",
11137 "Edge Detect...",
11138 "Spread...",
11139 "Shade...",
11140 "Raise...",
11141 "Segment...",
11142 (char *) NULL
11143 },
11144 *FXMenu[] =
11145 {
11146 "Solarize...",
11147 "Sepia Tone...",
11148 "Swirl...",
11149 "Implode...",
11150 "Vignette...",
11151 "Wave...",
11152 "Oil Paint...",
11153 "Charcoal Draw...",
11154 (char *) NULL
11155 },
11156 *MiscellanyMenu[] =
11157 {
11158 "Image Info",
11159 "Zoom Image",
11160 "Show Preview...",
11161 "Show Histogram",
11162 "Show Matte",
11163 (char *) NULL
11164 };
11165
11166 static const char
11167 **Menus[ApplyMenus] =
11168 {
11169 FileMenu,
11170 EditMenu,
11171 TransformMenu,
11172 EnhanceMenu,
11173 EffectsMenu,
11174 FXMenu,
11175 MiscellanyMenu
11176 };
11177
11178 static const CommandType
11179 ApplyCommands[] =
11180 {
11181 NullCommand,
11182 NullCommand,
11183 NullCommand,
11184 NullCommand,
11185 NullCommand,
11186 NullCommand,
11187 NullCommand,
11188 HelpCommand,
11189 QuitCommand
11190 },
11191 FileCommands[] =
11192 {
11193 SaveCommand,
11194 PrintCommand
11195 },
11196 EditCommands[] =
11197 {
11198 UndoCommand,
11199 RedoCommand
11200 },
11201 TransformCommands[] =
11202 {
11203 FlopCommand,
11204 FlipCommand,
11205 RotateRightCommand,
11206 RotateLeftCommand
11207 },
11208 EnhanceCommands[] =
11209 {
11210 HueCommand,
11211 SaturationCommand,
11212 BrightnessCommand,
11213 GammaCommand,
11214 SpiffCommand,
11215 DullCommand,
11216 ContrastStretchCommand,
11217 SigmoidalContrastCommand,
11218 NormalizeCommand,
11219 EqualizeCommand,
11220 NegateCommand,
11221 GrayscaleCommand,
11222 MapCommand,
11223 QuantizeCommand
11224 },
11225 EffectsCommands[] =
11226 {
11227 DespeckleCommand,
11228 EmbossCommand,
11229 ReduceNoiseCommand,
11230 AddNoiseCommand,
11231 SharpenCommand,
11232 BlurCommand,
11233 EdgeDetectCommand,
11234 SpreadCommand,
11235 ShadeCommand,
11236 RaiseCommand,
11237 SegmentCommand
11238 },
11239 FXCommands[] =
11240 {
11241 SolarizeCommand,
11242 SepiaToneCommand,
11243 SwirlCommand,
11244 ImplodeCommand,
11245 VignetteCommand,
11246 WaveCommand,
11247 OilPaintCommand,
11248 CharcoalDrawCommand
11249 },
11250 MiscellanyCommands[] =
11251 {
11252 InfoCommand,
11253 ZoomCommand,
11254 ShowPreviewCommand,
11255 ShowHistogramCommand,
11256 ShowMatteCommand
11257 },
11258 ROICommands[] =
11259 {
11260 ROIHelpCommand,
11261 ROIDismissCommand
11262 };
11263
11264 static const CommandType
11265 *Commands[ApplyMenus] =
11266 {
11267 FileCommands,
11268 EditCommands,
11269 TransformCommands,
11270 EnhanceCommands,
11271 EffectsCommands,
11272 FXCommands,
11273 MiscellanyCommands
11274 };
11275
11276 char
11277 command[MaxTextExtent],
11278 text[MaxTextExtent];
11279
11280 CommandType
11281 command_type;
11282
11283 Cursor
11284 cursor;
11285
11286 Image
11287 *roi_image;
11288
11289 int
11290 entry,
11291 id,
11292 x,
11293 y;
11294
11295 MagickRealType
11296 scale_factor;
11297
11298 MagickProgressMonitor
11299 progress_monitor;
11300
11301 RectangleInfo
11302 crop_info,
11303 highlight_info,
11304 roi_info;
11305
11306 unsigned int
11307 height,
11308 width;
11309
cristybb503372010-05-27 20:51:26 +000011310 size_t
cristy3ed852e2009-09-05 21:47:34 +000011311 state;
11312
11313 XEvent
11314 event;
11315
11316 /*
11317 Map Command widget.
11318 */
11319 (void) CloneString(&windows->command.name,"ROI");
11320 windows->command.data=0;
11321 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11322 (void) XMapRaised(display,windows->command.id);
11323 XClientMessage(display,windows->image.id,windows->im_protocols,
11324 windows->im_update_widget,CurrentTime);
11325 /*
11326 Track pointer until button 1 is pressed.
11327 */
11328 XQueryPosition(display,windows->image.id,&x,&y);
11329 (void) XSelectInput(display,windows->image.id,
11330 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000011331 roi_info.x=(ssize_t) windows->image.x+x;
11332 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011333 roi_info.width=0;
11334 roi_info.height=0;
11335 cursor=XCreateFontCursor(display,XC_fleur);
11336 state=DefaultState;
11337 do
11338 {
11339 if (windows->info.mapped != MagickFalse)
11340 {
11341 /*
11342 Display pointer position.
11343 */
cristyb51dff52011-05-19 16:55:47 +000011344 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000011345 (long) roi_info.x,(long) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011346 XInfoWidget(display,windows,text);
11347 }
11348 /*
11349 Wait for next event.
11350 */
cristy6710d842011-10-20 23:23:00 +000011351 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011352 if (event.xany.window == windows->command.id)
11353 {
11354 /*
11355 Select a command from the Command widget.
11356 */
11357 id=XCommandWidget(display,windows,ROIMenu,&event);
11358 if (id < 0)
11359 continue;
11360 switch (ROICommands[id])
11361 {
11362 case ROIHelpCommand:
11363 {
11364 XTextViewWidget(display,resource_info,windows,MagickFalse,
11365 "Help Viewer - Region of Interest",ImageROIHelp);
11366 break;
11367 }
11368 case ROIDismissCommand:
11369 {
11370 /*
11371 Prematurely exit.
11372 */
11373 state|=EscapeState;
11374 state|=ExitState;
11375 break;
11376 }
11377 default:
11378 break;
11379 }
11380 continue;
11381 }
11382 switch (event.type)
11383 {
11384 case ButtonPress:
11385 {
11386 if (event.xbutton.button != Button1)
11387 break;
11388 if (event.xbutton.window != windows->image.id)
11389 break;
11390 /*
11391 Note first corner of region of interest rectangle-- exit loop.
11392 */
11393 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000011394 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11395 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011396 state|=ExitState;
11397 break;
11398 }
11399 case ButtonRelease:
11400 break;
11401 case Expose:
11402 break;
11403 case KeyPress:
11404 {
11405 KeySym
11406 key_symbol;
11407
11408 if (event.xkey.window != windows->image.id)
11409 break;
11410 /*
11411 Respond to a user key press.
11412 */
11413 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11414 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11415 switch ((int) key_symbol)
11416 {
11417 case XK_Escape:
11418 case XK_F20:
11419 {
11420 /*
11421 Prematurely exit.
11422 */
11423 state|=EscapeState;
11424 state|=ExitState;
11425 break;
11426 }
11427 case XK_F1:
11428 case XK_Help:
11429 {
11430 XTextViewWidget(display,resource_info,windows,MagickFalse,
11431 "Help Viewer - Region of Interest",ImageROIHelp);
11432 break;
11433 }
11434 default:
11435 {
11436 (void) XBell(display,0);
11437 break;
11438 }
11439 }
11440 break;
11441 }
11442 case MotionNotify:
11443 {
11444 /*
11445 Map and unmap Info widget as text cursor crosses its boundaries.
11446 */
11447 x=event.xmotion.x;
11448 y=event.xmotion.y;
11449 if (windows->info.mapped != MagickFalse)
11450 {
11451 if ((x < (int) (windows->info.x+windows->info.width)) &&
11452 (y < (int) (windows->info.y+windows->info.height)))
11453 (void) XWithdrawWindow(display,windows->info.id,
11454 windows->info.screen);
11455 }
11456 else
11457 if ((x > (int) (windows->info.x+windows->info.width)) ||
11458 (y > (int) (windows->info.y+windows->info.height)))
11459 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011460 roi_info.x=(ssize_t) windows->image.x+x;
11461 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011462 break;
11463 }
11464 default:
11465 break;
11466 }
11467 } while ((state & ExitState) == 0);
11468 (void) XSelectInput(display,windows->image.id,
11469 windows->image.attributes.event_mask);
11470 if ((state & EscapeState) != 0)
11471 {
11472 /*
11473 User want to exit without region of interest.
11474 */
11475 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11476 (void) XFreeCursor(display,cursor);
11477 return(MagickTrue);
11478 }
11479 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11480 do
11481 {
11482 /*
11483 Size rectangle as pointer moves until the mouse button is released.
11484 */
11485 x=(int) roi_info.x;
11486 y=(int) roi_info.y;
11487 roi_info.width=0;
11488 roi_info.height=0;
11489 state=DefaultState;
11490 do
11491 {
11492 highlight_info=roi_info;
11493 highlight_info.x=roi_info.x-windows->image.x;
11494 highlight_info.y=roi_info.y-windows->image.y;
11495 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11496 {
11497 /*
11498 Display info and draw region of interest rectangle.
11499 */
11500 if (windows->info.mapped == MagickFalse)
11501 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000011502 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011503 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011504 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011505 XInfoWidget(display,windows,text);
11506 XHighlightRectangle(display,windows->image.id,
11507 windows->image.highlight_context,&highlight_info);
11508 }
11509 else
11510 if (windows->info.mapped != MagickFalse)
11511 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11512 /*
11513 Wait for next event.
11514 */
cristy6710d842011-10-20 23:23:00 +000011515 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011516 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11517 XHighlightRectangle(display,windows->image.id,
11518 windows->image.highlight_context,&highlight_info);
11519 switch (event.type)
11520 {
11521 case ButtonPress:
11522 {
cristy49e2d862010-11-12 02:50:30 +000011523 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11524 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011525 break;
11526 }
11527 case ButtonRelease:
11528 {
11529 /*
11530 User has committed to region of interest rectangle.
11531 */
cristy49e2d862010-11-12 02:50:30 +000011532 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11533 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011534 XSetCursorState(display,windows,MagickFalse);
11535 state|=ExitState;
11536 if (LocaleCompare(windows->command.name,"Apply") == 0)
11537 break;
11538 (void) CloneString(&windows->command.name,"Apply");
11539 windows->command.data=ApplyMenus;
11540 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11541 break;
11542 }
11543 case Expose:
11544 break;
11545 case MotionNotify:
11546 {
cristy49e2d862010-11-12 02:50:30 +000011547 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11548 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011549 }
11550 default:
11551 break;
11552 }
11553 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11554 ((state & ExitState) != 0))
11555 {
11556 /*
11557 Check boundary conditions.
11558 */
11559 if (roi_info.x < 0)
11560 roi_info.x=0;
11561 else
cristy49e2d862010-11-12 02:50:30 +000011562 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11563 roi_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011564 if ((int) roi_info.x < x)
11565 roi_info.width=(unsigned int) (x-roi_info.x);
11566 else
11567 {
11568 roi_info.width=(unsigned int) (roi_info.x-x);
cristy49e2d862010-11-12 02:50:30 +000011569 roi_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +000011570 }
11571 if (roi_info.y < 0)
11572 roi_info.y=0;
11573 else
cristy49e2d862010-11-12 02:50:30 +000011574 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11575 roi_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000011576 if ((int) roi_info.y < y)
11577 roi_info.height=(unsigned int) (y-roi_info.y);
11578 else
11579 {
11580 roi_info.height=(unsigned int) (roi_info.y-y);
cristy49e2d862010-11-12 02:50:30 +000011581 roi_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000011582 }
11583 }
11584 } while ((state & ExitState) == 0);
11585 /*
11586 Wait for user to grab a corner of the rectangle or press return.
11587 */
11588 state=DefaultState;
11589 command_type=NullCommand;
11590 (void) XMapWindow(display,windows->info.id);
11591 do
11592 {
11593 if (windows->info.mapped != MagickFalse)
11594 {
11595 /*
11596 Display pointer position.
11597 */
cristyb51dff52011-05-19 16:55:47 +000011598 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011599 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011600 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011601 XInfoWidget(display,windows,text);
11602 }
11603 highlight_info=roi_info;
11604 highlight_info.x=roi_info.x-windows->image.x;
11605 highlight_info.y=roi_info.y-windows->image.y;
11606 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11607 {
11608 state|=EscapeState;
11609 state|=ExitState;
11610 break;
11611 }
11612 if ((state & UpdateRegionState) != 0)
11613 {
11614 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11615 switch (command_type)
11616 {
11617 case UndoCommand:
11618 case RedoCommand:
11619 {
11620 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011621 image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011622 break;
11623 }
11624 default:
11625 {
11626 /*
11627 Region of interest is relative to image configuration.
11628 */
11629 progress_monitor=SetImageProgressMonitor(*image,
11630 (MagickProgressMonitor) NULL,(*image)->client_data);
11631 crop_info=roi_info;
11632 width=(unsigned int) (*image)->columns;
11633 height=(unsigned int) (*image)->rows;
11634 x=0;
11635 y=0;
11636 if (windows->image.crop_geometry != (char *) NULL)
11637 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11638 &width,&height);
11639 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11640 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000011641 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011642 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11643 scale_factor=(MagickRealType)
11644 height/windows->image.ximage->height;
11645 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000011646 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011647 crop_info.height=(unsigned int)
11648 (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +000011649 roi_image=CropImage(*image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000011650 (void) SetImageProgressMonitor(*image,progress_monitor,
11651 (*image)->client_data);
11652 if (roi_image == (Image *) NULL)
11653 continue;
11654 /*
11655 Apply image processing technique to the region of interest.
11656 */
11657 windows->image.orphan=MagickTrue;
11658 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011659 &roi_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011660 progress_monitor=SetImageProgressMonitor(*image,
11661 (MagickProgressMonitor) NULL,(*image)->client_data);
11662 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011663 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011664 windows->image.orphan=MagickFalse;
cristyfeb3e962012-03-29 17:25:55 +000011665 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
cristy39172402012-03-30 13:04:39 +000011666 MagickTrue,crop_info.x,crop_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000011667 roi_image=DestroyImage(roi_image);
11668 (void) SetImageProgressMonitor(*image,progress_monitor,
11669 (*image)->client_data);
11670 break;
11671 }
11672 }
11673 if (command_type != InfoCommand)
11674 {
cristy6710d842011-10-20 23:23:00 +000011675 XConfigureImageColormap(display,resource_info,windows,*image,
11676 exception);
11677 (void) XConfigureImage(display,resource_info,windows,*image,
11678 exception);
cristy3ed852e2009-09-05 21:47:34 +000011679 }
11680 XCheckRefreshWindows(display,windows);
11681 XInfoWidget(display,windows,text);
11682 (void) XSetFunction(display,windows->image.highlight_context,
11683 GXinvert);
11684 state&=(~UpdateRegionState);
11685 }
11686 XHighlightRectangle(display,windows->image.id,
11687 windows->image.highlight_context,&highlight_info);
cristy6710d842011-10-20 23:23:00 +000011688 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011689 if (event.xany.window == windows->command.id)
11690 {
11691 /*
11692 Select a command from the Command widget.
11693 */
11694 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11695 command_type=NullCommand;
11696 id=XCommandWidget(display,windows,ApplyMenu,&event);
11697 if (id >= 0)
11698 {
11699 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11700 command_type=ApplyCommands[id];
11701 if (id < ApplyMenus)
11702 {
11703 /*
11704 Select a command from a pop-up menu.
11705 */
11706 entry=XMenuWidget(display,windows,ApplyMenu[id],
11707 (const char **) Menus[id],command);
11708 if (entry >= 0)
11709 {
11710 (void) CopyMagickString(command,Menus[id][entry],
11711 MaxTextExtent);
11712 command_type=Commands[id][entry];
11713 }
11714 }
11715 }
11716 (void) XSetFunction(display,windows->image.highlight_context,
11717 GXinvert);
11718 XHighlightRectangle(display,windows->image.id,
11719 windows->image.highlight_context,&highlight_info);
11720 if (command_type == HelpCommand)
11721 {
11722 (void) XSetFunction(display,windows->image.highlight_context,
11723 GXcopy);
11724 XTextViewWidget(display,resource_info,windows,MagickFalse,
11725 "Help Viewer - Region of Interest",ImageROIHelp);
11726 (void) XSetFunction(display,windows->image.highlight_context,
11727 GXinvert);
11728 continue;
11729 }
11730 if (command_type == QuitCommand)
11731 {
11732 /*
11733 exit.
11734 */
11735 state|=EscapeState;
11736 state|=ExitState;
11737 continue;
11738 }
11739 if (command_type != NullCommand)
11740 state|=UpdateRegionState;
11741 continue;
11742 }
11743 XHighlightRectangle(display,windows->image.id,
11744 windows->image.highlight_context,&highlight_info);
11745 switch (event.type)
11746 {
11747 case ButtonPress:
11748 {
11749 x=windows->image.x;
11750 y=windows->image.y;
11751 if (event.xbutton.button != Button1)
11752 break;
11753 if (event.xbutton.window != windows->image.id)
11754 break;
11755 x=windows->image.x+event.xbutton.x;
11756 y=windows->image.y+event.xbutton.y;
11757 if ((x < (int) (roi_info.x+RoiDelta)) &&
11758 (x > (int) (roi_info.x-RoiDelta)) &&
11759 (y < (int) (roi_info.y+RoiDelta)) &&
11760 (y > (int) (roi_info.y-RoiDelta)))
11761 {
cristybb503372010-05-27 20:51:26 +000011762 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11763 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011764 state|=UpdateConfigurationState;
11765 break;
11766 }
11767 if ((x < (int) (roi_info.x+RoiDelta)) &&
11768 (x > (int) (roi_info.x-RoiDelta)) &&
11769 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11770 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11771 {
cristybb503372010-05-27 20:51:26 +000011772 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
cristy3ed852e2009-09-05 21:47:34 +000011773 state|=UpdateConfigurationState;
11774 break;
11775 }
11776 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11777 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11778 (y < (int) (roi_info.y+RoiDelta)) &&
11779 (y > (int) (roi_info.y-RoiDelta)))
11780 {
cristybb503372010-05-27 20:51:26 +000011781 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011782 state|=UpdateConfigurationState;
11783 break;
11784 }
11785 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11786 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11787 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11788 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11789 {
11790 state|=UpdateConfigurationState;
11791 break;
11792 }
11793 }
11794 case ButtonRelease:
11795 {
11796 if (event.xbutton.window == windows->pan.id)
11797 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11798 (highlight_info.y != crop_info.y-windows->image.y))
11799 XHighlightRectangle(display,windows->image.id,
11800 windows->image.highlight_context,&highlight_info);
11801 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11802 event.xbutton.time);
11803 break;
11804 }
11805 case Expose:
11806 {
11807 if (event.xexpose.window == windows->image.id)
11808 if (event.xexpose.count == 0)
11809 {
11810 event.xexpose.x=(int) highlight_info.x;
11811 event.xexpose.y=(int) highlight_info.y;
11812 event.xexpose.width=(int) highlight_info.width;
11813 event.xexpose.height=(int) highlight_info.height;
11814 XRefreshWindow(display,&windows->image,&event);
11815 }
11816 if (event.xexpose.window == windows->info.id)
11817 if (event.xexpose.count == 0)
11818 XInfoWidget(display,windows,text);
11819 break;
11820 }
11821 case KeyPress:
11822 {
11823 KeySym
11824 key_symbol;
11825
11826 if (event.xkey.window != windows->image.id)
11827 break;
11828 /*
11829 Respond to a user key press.
11830 */
11831 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11832 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11833 switch ((int) key_symbol)
11834 {
11835 case XK_Shift_L:
11836 case XK_Shift_R:
11837 break;
11838 case XK_Escape:
11839 case XK_F20:
11840 state|=EscapeState;
11841 case XK_Return:
11842 {
11843 state|=ExitState;
11844 break;
11845 }
11846 case XK_Home:
11847 case XK_KP_Home:
11848 {
cristybb503372010-05-27 20:51:26 +000011849 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
cristy49e2d862010-11-12 02:50:30 +000011850 roi_info.y=(ssize_t) (windows->image.height/2L-
11851 roi_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +000011852 break;
11853 }
11854 case XK_Left:
11855 case XK_KP_Left:
11856 {
11857 roi_info.x--;
11858 break;
11859 }
11860 case XK_Up:
11861 case XK_KP_Up:
11862 case XK_Next:
11863 {
11864 roi_info.y--;
11865 break;
11866 }
11867 case XK_Right:
11868 case XK_KP_Right:
11869 {
11870 roi_info.x++;
11871 break;
11872 }
11873 case XK_Prior:
11874 case XK_Down:
11875 case XK_KP_Down:
11876 {
11877 roi_info.y++;
11878 break;
11879 }
11880 case XK_F1:
11881 case XK_Help:
11882 {
11883 (void) XSetFunction(display,windows->image.highlight_context,
11884 GXcopy);
11885 XTextViewWidget(display,resource_info,windows,MagickFalse,
11886 "Help Viewer - Region of Interest",ImageROIHelp);
11887 (void) XSetFunction(display,windows->image.highlight_context,
11888 GXinvert);
11889 break;
11890 }
11891 default:
11892 {
11893 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011894 event.xkey.state,key_symbol,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011895 if (command_type != NullCommand)
11896 state|=UpdateRegionState;
11897 break;
11898 }
11899 }
11900 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11901 event.xkey.time);
11902 break;
11903 }
11904 case KeyRelease:
11905 break;
11906 case MotionNotify:
11907 {
11908 if (event.xbutton.window != windows->image.id)
11909 break;
11910 /*
11911 Map and unmap Info widget as text cursor crosses its boundaries.
11912 */
11913 x=event.xmotion.x;
11914 y=event.xmotion.y;
11915 if (windows->info.mapped != MagickFalse)
11916 {
11917 if ((x < (int) (windows->info.x+windows->info.width)) &&
11918 (y < (int) (windows->info.y+windows->info.height)))
11919 (void) XWithdrawWindow(display,windows->info.id,
11920 windows->info.screen);
11921 }
11922 else
11923 if ((x > (int) (windows->info.x+windows->info.width)) ||
11924 (y > (int) (windows->info.y+windows->info.height)))
11925 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011926 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11927 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011928 break;
11929 }
11930 case SelectionRequest:
11931 {
11932 XSelectionEvent
11933 notify;
11934
11935 XSelectionRequestEvent
11936 *request;
11937
11938 /*
11939 Set primary selection.
11940 */
cristyb51dff52011-05-19 16:55:47 +000011941 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011942 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011943 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011944 request=(&(event.xselectionrequest));
11945 (void) XChangeProperty(request->display,request->requestor,
11946 request->property,request->target,8,PropModeReplace,
11947 (unsigned char *) text,(int) strlen(text));
11948 notify.type=SelectionNotify;
11949 notify.display=request->display;
11950 notify.requestor=request->requestor;
11951 notify.selection=request->selection;
11952 notify.target=request->target;
11953 notify.time=request->time;
11954 if (request->property == None)
11955 notify.property=request->target;
11956 else
11957 notify.property=request->property;
11958 (void) XSendEvent(request->display,request->requestor,False,0,
11959 (XEvent *) &notify);
11960 }
11961 default:
11962 break;
11963 }
11964 if ((state & UpdateConfigurationState) != 0)
11965 {
11966 (void) XPutBackEvent(display,&event);
11967 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11968 break;
11969 }
11970 } while ((state & ExitState) == 0);
11971 } while ((state & ExitState) == 0);
11972 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11973 XSetCursorState(display,windows,MagickFalse);
11974 if ((state & EscapeState) != 0)
11975 return(MagickTrue);
11976 return(MagickTrue);
11977}
11978
11979/*
11980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11981% %
11982% %
11983% %
11984+ X R o t a t e I m a g e %
11985% %
11986% %
11987% %
11988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11989%
11990% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11991% rotation angle is computed from the slope of a line drawn by the user.
11992%
11993% The format of the XRotateImage method is:
11994%
11995% MagickBooleanType XRotateImage(Display *display,
11996% XResourceInfo *resource_info,XWindows *windows,double degrees,
cristy051718b2011-08-28 22:49:25 +000011997% Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011998%
11999% A description of each parameter follows:
12000%
12001% o display: Specifies a connection to an X server; returned from
12002% XOpenDisplay.
12003%
12004% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12005%
12006% o windows: Specifies a pointer to a XWindows structure.
12007%
12008% o degrees: Specifies the number of degrees to rotate the image.
12009%
12010% o image: the image.
12011%
cristy051718b2011-08-28 22:49:25 +000012012% o exception: return any errors or warnings in this structure.
12013%
cristy3ed852e2009-09-05 21:47:34 +000012014*/
12015static MagickBooleanType XRotateImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012016 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12017 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012018{
12019 static const char
12020 *RotateMenu[] =
12021 {
12022 "Pixel Color",
12023 "Direction",
12024 "Help",
12025 "Dismiss",
12026 (char *) NULL
12027 };
12028
12029 static ModeType
12030 direction = HorizontalRotateCommand;
12031
12032 static const ModeType
12033 DirectionCommands[] =
12034 {
12035 HorizontalRotateCommand,
12036 VerticalRotateCommand
12037 },
12038 RotateCommands[] =
12039 {
12040 RotateColorCommand,
12041 RotateDirectionCommand,
12042 RotateHelpCommand,
12043 RotateDismissCommand
12044 };
12045
12046 static unsigned int
12047 pen_id = 0;
12048
12049 char
12050 command[MaxTextExtent],
12051 text[MaxTextExtent];
12052
12053 Image
12054 *rotate_image;
12055
12056 int
12057 id,
12058 x,
12059 y;
12060
12061 MagickRealType
12062 normalized_degrees;
12063
12064 register int
12065 i;
12066
12067 unsigned int
12068 height,
12069 rotations,
12070 width;
12071
12072 if (degrees == 0.0)
12073 {
12074 unsigned int
12075 distance;
12076
cristybb503372010-05-27 20:51:26 +000012077 size_t
cristy3ed852e2009-09-05 21:47:34 +000012078 state;
12079
12080 XEvent
12081 event;
12082
12083 XSegment
12084 rotate_info;
12085
12086 /*
12087 Map Command widget.
12088 */
12089 (void) CloneString(&windows->command.name,"Rotate");
12090 windows->command.data=2;
12091 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12092 (void) XMapRaised(display,windows->command.id);
12093 XClientMessage(display,windows->image.id,windows->im_protocols,
12094 windows->im_update_widget,CurrentTime);
12095 /*
12096 Wait for first button press.
12097 */
12098 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12099 XQueryPosition(display,windows->image.id,&x,&y);
12100 rotate_info.x1=x;
12101 rotate_info.y1=y;
12102 rotate_info.x2=x;
12103 rotate_info.y2=y;
12104 state=DefaultState;
12105 do
12106 {
12107 XHighlightLine(display,windows->image.id,
12108 windows->image.highlight_context,&rotate_info);
12109 /*
12110 Wait for next event.
12111 */
cristy6710d842011-10-20 23:23:00 +000012112 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012113 XHighlightLine(display,windows->image.id,
12114 windows->image.highlight_context,&rotate_info);
12115 if (event.xany.window == windows->command.id)
12116 {
12117 /*
12118 Select a command from the Command widget.
12119 */
12120 id=XCommandWidget(display,windows,RotateMenu,&event);
12121 if (id < 0)
12122 continue;
12123 (void) XSetFunction(display,windows->image.highlight_context,
12124 GXcopy);
12125 switch (RotateCommands[id])
12126 {
12127 case RotateColorCommand:
12128 {
12129 const char
12130 *ColorMenu[MaxNumberPens];
12131
12132 int
12133 pen_number;
12134
12135 XColor
12136 color;
12137
12138 /*
12139 Initialize menu selections.
12140 */
12141 for (i=0; i < (int) (MaxNumberPens-2); i++)
12142 ColorMenu[i]=resource_info->pen_colors[i];
12143 ColorMenu[MaxNumberPens-2]="Browser...";
12144 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12145 /*
12146 Select a pen color from the pop-up menu.
12147 */
12148 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12149 (const char **) ColorMenu,command);
12150 if (pen_number < 0)
12151 break;
12152 if (pen_number == (MaxNumberPens-2))
12153 {
12154 static char
12155 color_name[MaxTextExtent] = "gray";
12156
12157 /*
12158 Select a pen color from a dialog.
12159 */
12160 resource_info->pen_colors[pen_number]=color_name;
12161 XColorBrowserWidget(display,windows,"Select",color_name);
12162 if (*color_name == '\0')
12163 break;
12164 }
12165 /*
12166 Set pen color.
12167 */
12168 (void) XParseColor(display,windows->map_info->colormap,
12169 resource_info->pen_colors[pen_number],&color);
12170 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12171 (unsigned int) MaxColors,&color);
12172 windows->pixel_info->pen_colors[pen_number]=color;
12173 pen_id=(unsigned int) pen_number;
12174 break;
12175 }
12176 case RotateDirectionCommand:
12177 {
12178 static const char
12179 *Directions[] =
12180 {
12181 "horizontal",
12182 "vertical",
12183 (char *) NULL,
12184 };
12185
12186 /*
12187 Select a command from the pop-up menu.
12188 */
12189 id=XMenuWidget(display,windows,RotateMenu[id],
12190 Directions,command);
12191 if (id >= 0)
12192 direction=DirectionCommands[id];
12193 break;
12194 }
12195 case RotateHelpCommand:
12196 {
12197 XTextViewWidget(display,resource_info,windows,MagickFalse,
12198 "Help Viewer - Image Rotation",ImageRotateHelp);
12199 break;
12200 }
12201 case RotateDismissCommand:
12202 {
12203 /*
12204 Prematurely exit.
12205 */
12206 state|=EscapeState;
12207 state|=ExitState;
12208 break;
12209 }
12210 default:
12211 break;
12212 }
12213 (void) XSetFunction(display,windows->image.highlight_context,
12214 GXinvert);
12215 continue;
12216 }
12217 switch (event.type)
12218 {
12219 case ButtonPress:
12220 {
12221 if (event.xbutton.button != Button1)
12222 break;
12223 if (event.xbutton.window != windows->image.id)
12224 break;
12225 /*
12226 exit loop.
12227 */
12228 (void) XSetFunction(display,windows->image.highlight_context,
12229 GXcopy);
12230 rotate_info.x1=event.xbutton.x;
12231 rotate_info.y1=event.xbutton.y;
12232 state|=ExitState;
12233 break;
12234 }
12235 case ButtonRelease:
12236 break;
12237 case Expose:
12238 break;
12239 case KeyPress:
12240 {
12241 char
12242 command[MaxTextExtent];
12243
12244 KeySym
12245 key_symbol;
12246
12247 if (event.xkey.window != windows->image.id)
12248 break;
12249 /*
12250 Respond to a user key press.
12251 */
12252 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12253 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12254 switch ((int) key_symbol)
12255 {
12256 case XK_Escape:
12257 case XK_F20:
12258 {
12259 /*
12260 Prematurely exit.
12261 */
12262 state|=EscapeState;
12263 state|=ExitState;
12264 break;
12265 }
12266 case XK_F1:
12267 case XK_Help:
12268 {
12269 (void) XSetFunction(display,windows->image.highlight_context,
12270 GXcopy);
12271 XTextViewWidget(display,resource_info,windows,MagickFalse,
12272 "Help Viewer - Image Rotation",ImageRotateHelp);
12273 (void) XSetFunction(display,windows->image.highlight_context,
12274 GXinvert);
12275 break;
12276 }
12277 default:
12278 {
12279 (void) XBell(display,0);
12280 break;
12281 }
12282 }
12283 break;
12284 }
12285 case MotionNotify:
12286 {
12287 rotate_info.x1=event.xmotion.x;
12288 rotate_info.y1=event.xmotion.y;
12289 }
12290 }
12291 rotate_info.x2=rotate_info.x1;
12292 rotate_info.y2=rotate_info.y1;
12293 if (direction == HorizontalRotateCommand)
12294 rotate_info.x2+=32;
12295 else
12296 rotate_info.y2-=32;
12297 } while ((state & ExitState) == 0);
12298 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12299 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12300 if ((state & EscapeState) != 0)
12301 return(MagickTrue);
12302 /*
12303 Draw line as pointer moves until the mouse button is released.
12304 */
12305 distance=0;
12306 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12307 state=DefaultState;
12308 do
12309 {
12310 if (distance > 9)
12311 {
12312 /*
12313 Display info and draw rotation line.
12314 */
12315 if (windows->info.mapped == MagickFalse)
12316 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000012317 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012318 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12319 XInfoWidget(display,windows,text);
12320 XHighlightLine(display,windows->image.id,
12321 windows->image.highlight_context,&rotate_info);
12322 }
12323 else
12324 if (windows->info.mapped != MagickFalse)
12325 (void) XWithdrawWindow(display,windows->info.id,
12326 windows->info.screen);
12327 /*
12328 Wait for next event.
12329 */
cristy6710d842011-10-20 23:23:00 +000012330 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012331 if (distance > 9)
12332 XHighlightLine(display,windows->image.id,
12333 windows->image.highlight_context,&rotate_info);
12334 switch (event.type)
12335 {
12336 case ButtonPress:
12337 break;
12338 case ButtonRelease:
12339 {
12340 /*
12341 User has committed to rotation line.
12342 */
12343 rotate_info.x2=event.xbutton.x;
12344 rotate_info.y2=event.xbutton.y;
12345 state|=ExitState;
12346 break;
12347 }
12348 case Expose:
12349 break;
12350 case MotionNotify:
12351 {
12352 rotate_info.x2=event.xmotion.x;
12353 rotate_info.y2=event.xmotion.y;
12354 }
12355 default:
12356 break;
12357 }
12358 /*
12359 Check boundary conditions.
12360 */
12361 if (rotate_info.x2 < 0)
12362 rotate_info.x2=0;
12363 else
12364 if (rotate_info.x2 > (int) windows->image.width)
12365 rotate_info.x2=(short) windows->image.width;
12366 if (rotate_info.y2 < 0)
12367 rotate_info.y2=0;
12368 else
12369 if (rotate_info.y2 > (int) windows->image.height)
12370 rotate_info.y2=(short) windows->image.height;
12371 /*
12372 Compute rotation angle from the slope of the line.
12373 */
12374 degrees=0.0;
12375 distance=(unsigned int)
12376 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12377 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12378 if (distance > 9)
12379 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12380 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12381 } while ((state & ExitState) == 0);
12382 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12383 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12384 if (distance <= 9)
12385 return(MagickTrue);
12386 }
12387 if (direction == VerticalRotateCommand)
12388 degrees-=90.0;
12389 if (degrees == 0.0)
12390 return(MagickTrue);
12391 /*
12392 Rotate image.
12393 */
12394 normalized_degrees=degrees;
12395 while (normalized_degrees < -45.0)
12396 normalized_degrees+=360.0;
12397 for (rotations=0; normalized_degrees > 45.0; rotations++)
12398 normalized_degrees-=90.0;
12399 if (normalized_degrees != 0.0)
cristy051718b2011-08-28 22:49:25 +000012400 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12401 exception);
cristy3ed852e2009-09-05 21:47:34 +000012402 XSetCursorState(display,windows,MagickTrue);
12403 XCheckRefreshWindows(display,windows);
cristye42f6582012-02-11 17:59:50 +000012404 (*image)->background_color.red=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012405 windows->pixel_info->pen_colors[pen_id].red);
cristye42f6582012-02-11 17:59:50 +000012406 (*image)->background_color.green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012407 windows->pixel_info->pen_colors[pen_id].green);
cristye42f6582012-02-11 17:59:50 +000012408 (*image)->background_color.blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012409 windows->pixel_info->pen_colors[pen_id].blue);
cristy051718b2011-08-28 22:49:25 +000012410 rotate_image=RotateImage(*image,degrees,exception);
cristy3ed852e2009-09-05 21:47:34 +000012411 XSetCursorState(display,windows,MagickFalse);
12412 if (rotate_image == (Image *) NULL)
12413 return(MagickFalse);
12414 *image=DestroyImage(*image);
12415 *image=rotate_image;
12416 if (windows->image.crop_geometry != (char *) NULL)
12417 {
12418 /*
12419 Rotate crop geometry.
12420 */
12421 width=(unsigned int) (*image)->columns;
12422 height=(unsigned int) (*image)->rows;
12423 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12424 switch (rotations % 4)
12425 {
12426 default:
12427 case 0:
12428 break;
12429 case 1:
12430 {
12431 /*
12432 Rotate 90 degrees.
12433 */
cristyb51dff52011-05-19 16:55:47 +000012434 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012435 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12436 (int) height-y,x);
12437 break;
12438 }
12439 case 2:
12440 {
12441 /*
12442 Rotate 180 degrees.
12443 */
cristyb51dff52011-05-19 16:55:47 +000012444 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012445 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12446 break;
12447 }
12448 case 3:
12449 {
12450 /*
12451 Rotate 270 degrees.
12452 */
cristyb51dff52011-05-19 16:55:47 +000012453 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012454 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12455 break;
12456 }
12457 }
12458 }
12459 if (windows->image.orphan != MagickFalse)
12460 return(MagickTrue);
12461 if (normalized_degrees != 0.0)
12462 {
12463 /*
12464 Update image colormap.
12465 */
12466 windows->image.window_changes.width=(int) (*image)->columns;
12467 windows->image.window_changes.height=(int) (*image)->rows;
12468 if (windows->image.crop_geometry != (char *) NULL)
12469 {
12470 /*
12471 Obtain dimensions of image from crop geometry.
12472 */
12473 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12474 &width,&height);
12475 windows->image.window_changes.width=(int) width;
12476 windows->image.window_changes.height=(int) height;
12477 }
cristy6710d842011-10-20 23:23:00 +000012478 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012479 }
12480 else
12481 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12482 {
12483 windows->image.window_changes.width=windows->image.ximage->height;
12484 windows->image.window_changes.height=windows->image.ximage->width;
12485 }
12486 /*
12487 Update image configuration.
12488 */
cristy051718b2011-08-28 22:49:25 +000012489 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012490 return(MagickTrue);
12491}
12492
12493/*
12494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12495% %
12496% %
12497% %
12498+ X S a v e I m a g e %
12499% %
12500% %
12501% %
12502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12503%
12504% XSaveImage() saves an image to a file.
12505%
12506% The format of the XSaveImage method is:
12507%
12508% MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012509% XResourceInfo *resource_info,XWindows *windows,Image *image,
12510% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012511%
12512% A description of each parameter follows:
12513%
12514% o display: Specifies a connection to an X server; returned from
12515% XOpenDisplay.
12516%
12517% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12518%
12519% o windows: Specifies a pointer to a XWindows structure.
12520%
12521% o image: the image.
12522%
cristy051718b2011-08-28 22:49:25 +000012523% o exception: return any errors or warnings in this structure.
12524%
cristy3ed852e2009-09-05 21:47:34 +000012525*/
12526static MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012527 XResourceInfo *resource_info,XWindows *windows,Image *image,
12528 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012529{
12530 char
12531 filename[MaxTextExtent],
12532 geometry[MaxTextExtent];
12533
12534 Image
12535 *save_image;
12536
12537 ImageInfo
12538 *image_info;
12539
12540 MagickStatusType
12541 status;
12542
12543 /*
12544 Request file name from user.
12545 */
12546 if (resource_info->write_filename != (char *) NULL)
12547 (void) CopyMagickString(filename,resource_info->write_filename,
12548 MaxTextExtent);
12549 else
12550 {
12551 char
12552 path[MaxTextExtent];
12553
12554 int
12555 status;
12556
12557 GetPathComponent(image->filename,HeadPath,path);
12558 GetPathComponent(image->filename,TailPath,filename);
cristy0da1d642011-08-29 16:53:16 +000012559 if (*path != '\0')
12560 {
12561 status=chdir(path);
12562 if (status == -1)
12563 (void) ThrowMagickException(exception,GetMagickModule(),
12564 FileOpenError,"UnableToOpenFile","%s",path);
12565 }
cristy3ed852e2009-09-05 21:47:34 +000012566 }
12567 XFileBrowserWidget(display,windows,"Save",filename);
12568 if (*filename == '\0')
12569 return(MagickTrue);
12570 if (IsPathAccessible(filename) != MagickFalse)
12571 {
12572 int
12573 status;
12574
12575 /*
12576 File exists-- seek user's permission before overwriting.
12577 */
12578 status=XConfirmWidget(display,windows,"Overwrite",filename);
12579 if (status <= 0)
12580 return(MagickTrue);
12581 }
12582 image_info=CloneImageInfo(resource_info->image_info);
12583 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012584 (void) SetImageInfo(image_info,1,exception);
cristy3ed852e2009-09-05 21:47:34 +000012585 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12586 (LocaleCompare(image_info->magick,"JPG") == 0))
12587 {
12588 char
12589 quality[MaxTextExtent];
12590
12591 int
12592 status;
12593
12594 /*
12595 Request JPEG quality from user.
12596 */
cristyb51dff52011-05-19 16:55:47 +000012597 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
cristyf2faecf2010-05-28 19:19:36 +000012598 image->quality);
cristy3ed852e2009-09-05 21:47:34 +000012599 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12600 quality);
12601 if (*quality == '\0')
12602 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012603 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012604 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12605 }
12606 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12607 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12608 (LocaleCompare(image_info->magick,"PS") == 0) ||
12609 (LocaleCompare(image_info->magick,"PS2") == 0))
12610 {
12611 char
12612 geometry[MaxTextExtent];
12613
12614 /*
12615 Request page geometry from user.
12616 */
cristyb93d9e72009-09-12 20:02:21 +000012617 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012618 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristyb93d9e72009-09-12 20:02:21 +000012619 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012620 if (image_info->page != (char *) NULL)
12621 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12622 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12623 "Select page geometry:",geometry);
12624 if (*geometry != '\0')
12625 image_info->page=GetPageGeometry(geometry);
12626 }
12627 /*
12628 Apply image transforms.
12629 */
12630 XSetCursorState(display,windows,MagickTrue);
12631 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000012632 save_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000012633 if (save_image == (Image *) NULL)
12634 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000012635 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000012636 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000012637 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12638 exception);
cristy3ed852e2009-09-05 21:47:34 +000012639 /*
12640 Write image.
12641 */
12642 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012643 status=WriteImage(image_info,save_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012644 if (status != MagickFalse)
12645 image->taint=MagickFalse;
12646 save_image=DestroyImage(save_image);
12647 image_info=DestroyImageInfo(image_info);
12648 XSetCursorState(display,windows,MagickFalse);
12649 return(status != 0 ? MagickTrue : MagickFalse);
12650}
12651
12652/*
12653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12654% %
12655% %
12656% %
12657+ X S c r e e n E v e n t %
12658% %
12659% %
12660% %
12661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12662%
12663% XScreenEvent() handles global events associated with the Pan and Magnify
12664% windows.
12665%
12666% The format of the XScreenEvent function is:
12667%
cristy6710d842011-10-20 23:23:00 +000012668% void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12669% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012670%
12671% A description of each parameter follows:
12672%
12673% o display: Specifies a pointer to the Display structure; returned from
12674% XOpenDisplay.
12675%
12676% o windows: Specifies a pointer to a XWindows structure.
12677%
12678% o event: Specifies a pointer to a X11 XEvent structure.
12679%
cristy6710d842011-10-20 23:23:00 +000012680% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +000012681%
12682*/
12683
12684#if defined(__cplusplus) || defined(c_plusplus)
12685extern "C" {
12686#endif
12687
12688static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12689{
12690 register XWindows
12691 *windows;
12692
12693 windows=(XWindows *) data;
12694 if ((event->type == ClientMessage) &&
12695 (event->xclient.window == windows->image.id))
12696 return(MagickFalse);
12697 return(MagickTrue);
12698}
12699
12700#if defined(__cplusplus) || defined(c_plusplus)
12701}
12702#endif
12703
cristy6710d842011-10-20 23:23:00 +000012704static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12705 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012706{
12707 register int
12708 x,
12709 y;
12710
12711 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12712 if (event->xany.window == windows->command.id)
12713 return;
12714 switch (event->type)
12715 {
12716 case ButtonPress:
12717 case ButtonRelease:
12718 {
12719 if ((event->xbutton.button == Button3) &&
12720 (event->xbutton.state & Mod1Mask))
12721 {
12722 /*
12723 Convert Alt-Button3 to Button2.
12724 */
12725 event->xbutton.button=Button2;
12726 event->xbutton.state&=(~Mod1Mask);
12727 }
12728 if (event->xbutton.window == windows->backdrop.id)
12729 {
12730 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12731 event->xbutton.time);
12732 break;
12733 }
12734 if (event->xbutton.window == windows->pan.id)
12735 {
cristy6710d842011-10-20 23:23:00 +000012736 XPanImage(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012737 break;
12738 }
12739 if (event->xbutton.window == windows->image.id)
12740 if (event->xbutton.button == Button2)
12741 {
12742 /*
12743 Update magnified image.
12744 */
12745 x=event->xbutton.x;
12746 y=event->xbutton.y;
12747 if (x < 0)
12748 x=0;
12749 else
12750 if (x >= (int) windows->image.width)
12751 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012752 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012753 if (y < 0)
12754 y=0;
12755 else
12756 if (y >= (int) windows->image.height)
12757 y=(int) (windows->image.height-1);
12758 windows->magnify.y=windows->image.y+y;
12759 if (windows->magnify.mapped == MagickFalse)
12760 (void) XMapRaised(display,windows->magnify.id);
cristy6710d842011-10-20 23:23:00 +000012761 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012762 if (event->type == ButtonRelease)
12763 (void) XWithdrawWindow(display,windows->info.id,
12764 windows->info.screen);
12765 break;
12766 }
12767 break;
12768 }
12769 case ClientMessage:
12770 {
12771 /*
12772 If client window delete message, exit.
12773 */
12774 if (event->xclient.message_type != windows->wm_protocols)
12775 break;
cristyecd0ab52010-05-30 14:59:20 +000012776 if (*event->xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000012777 break;
12778 if (event->xclient.window == windows->magnify.id)
12779 {
12780 (void) XWithdrawWindow(display,windows->magnify.id,
12781 windows->magnify.screen);
12782 break;
12783 }
12784 break;
12785 }
12786 case ConfigureNotify:
12787 {
12788 if (event->xconfigure.window == windows->magnify.id)
12789 {
12790 unsigned int
12791 magnify;
12792
12793 /*
12794 Magnify window has a new configuration.
12795 */
12796 windows->magnify.width=(unsigned int) event->xconfigure.width;
12797 windows->magnify.height=(unsigned int) event->xconfigure.height;
12798 if (windows->magnify.mapped == MagickFalse)
12799 break;
12800 magnify=1;
12801 while ((int) magnify <= event->xconfigure.width)
12802 magnify<<=1;
12803 while ((int) magnify <= event->xconfigure.height)
12804 magnify<<=1;
12805 magnify>>=1;
12806 if (((int) magnify != event->xconfigure.width) ||
12807 ((int) magnify != event->xconfigure.height))
12808 {
12809 XWindowChanges
12810 window_changes;
12811
12812 window_changes.width=(int) magnify;
12813 window_changes.height=(int) magnify;
12814 (void) XReconfigureWMWindow(display,windows->magnify.id,
12815 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12816 &window_changes);
12817 break;
12818 }
cristy6710d842011-10-20 23:23:00 +000012819 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012820 break;
12821 }
12822 break;
12823 }
12824 case Expose:
12825 {
12826 if (event->xexpose.window == windows->image.id)
12827 {
12828 XRefreshWindow(display,&windows->image,event);
12829 break;
12830 }
12831 if (event->xexpose.window == windows->pan.id)
12832 if (event->xexpose.count == 0)
12833 {
12834 XDrawPanRectangle(display,windows);
12835 break;
12836 }
12837 if (event->xexpose.window == windows->magnify.id)
12838 if (event->xexpose.count == 0)
12839 {
cristy6710d842011-10-20 23:23:00 +000012840 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012841 break;
12842 }
12843 break;
12844 }
12845 case KeyPress:
12846 {
12847 char
12848 command[MaxTextExtent];
12849
12850 KeySym
12851 key_symbol;
12852
12853 if (event->xkey.window != windows->magnify.id)
12854 break;
12855 /*
12856 Respond to a user key press.
12857 */
12858 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12859 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
cristy6710d842011-10-20 23:23:00 +000012860 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12861 exception);
cristy3ed852e2009-09-05 21:47:34 +000012862 break;
12863 }
12864 case MapNotify:
12865 {
12866 if (event->xmap.window == windows->magnify.id)
12867 {
12868 windows->magnify.mapped=MagickTrue;
12869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12870 break;
12871 }
12872 if (event->xmap.window == windows->info.id)
12873 {
12874 windows->info.mapped=MagickTrue;
12875 break;
12876 }
12877 break;
12878 }
12879 case MotionNotify:
12880 {
12881 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12882 if (event->xmotion.window == windows->image.id)
12883 if (windows->magnify.mapped != MagickFalse)
12884 {
12885 /*
12886 Update magnified image.
12887 */
12888 x=event->xmotion.x;
12889 y=event->xmotion.y;
12890 if (x < 0)
12891 x=0;
12892 else
12893 if (x >= (int) windows->image.width)
12894 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012895 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012896 if (y < 0)
12897 y=0;
12898 else
12899 if (y >= (int) windows->image.height)
12900 y=(int) (windows->image.height-1);
12901 windows->magnify.y=windows->image.y+y;
cristy6710d842011-10-20 23:23:00 +000012902 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012903 }
12904 break;
12905 }
12906 case UnmapNotify:
12907 {
12908 if (event->xunmap.window == windows->magnify.id)
12909 {
12910 windows->magnify.mapped=MagickFalse;
12911 break;
12912 }
12913 if (event->xunmap.window == windows->info.id)
12914 {
12915 windows->info.mapped=MagickFalse;
12916 break;
12917 }
12918 break;
12919 }
12920 default:
12921 break;
12922 }
12923}
12924
12925/*
12926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12927% %
12928% %
12929% %
12930+ X S e t C r o p G e o m e t r y %
12931% %
12932% %
12933% %
12934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12935%
12936% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12937% and translates it to a cropping geometry relative to the image.
12938%
12939% The format of the XSetCropGeometry method is:
12940%
12941% void XSetCropGeometry(Display *display,XWindows *windows,
12942% RectangleInfo *crop_info,Image *image)
12943%
12944% A description of each parameter follows:
12945%
12946% o display: Specifies a connection to an X server; returned from
12947% XOpenDisplay.
12948%
12949% o windows: Specifies a pointer to a XWindows structure.
12950%
12951% o crop_info: A pointer to a RectangleInfo that defines a region of the
12952% Image window to crop.
12953%
12954% o image: the image.
12955%
12956*/
12957static void XSetCropGeometry(Display *display,XWindows *windows,
12958 RectangleInfo *crop_info,Image *image)
12959{
12960 char
12961 text[MaxTextExtent];
12962
12963 int
12964 x,
12965 y;
12966
12967 MagickRealType
12968 scale_factor;
12969
12970 unsigned int
12971 height,
12972 width;
12973
12974 if (windows->info.mapped != MagickFalse)
12975 {
12976 /*
12977 Display info on cropping rectangle.
12978 */
cristyb51dff52011-05-19 16:55:47 +000012979 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
cristye8c25f92010-06-03 00:53:06 +000012980 (double) crop_info->width,(double) crop_info->height,(double)
12981 crop_info->x,(double) crop_info->y);
cristy3ed852e2009-09-05 21:47:34 +000012982 XInfoWidget(display,windows,text);
12983 }
12984 /*
12985 Cropping geometry is relative to any previous crop geometry.
12986 */
12987 x=0;
12988 y=0;
12989 width=(unsigned int) image->columns;
12990 height=(unsigned int) image->rows;
12991 if (windows->image.crop_geometry != (char *) NULL)
12992 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12993 else
12994 windows->image.crop_geometry=AcquireString((char *) NULL);
12995 /*
12996 Define the crop geometry string from the cropping rectangle.
12997 */
12998 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12999 if (crop_info->x > 0)
13000 x+=(int) (scale_factor*crop_info->x+0.5);
13001 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13002 if (width == 0)
13003 width=1;
13004 scale_factor=(MagickRealType) height/windows->image.ximage->height;
13005 if (crop_info->y > 0)
13006 y+=(int) (scale_factor*crop_info->y+0.5);
13007 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13008 if (height == 0)
13009 height=1;
cristyb51dff52011-05-19 16:55:47 +000013010 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013011 "%ux%u%+d%+d",width,height,x,y);
13012}
13013
13014/*
13015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13016% %
13017% %
13018% %
13019+ X T i l e I m a g e %
13020% %
13021% %
13022% %
13023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13024%
13025% XTileImage() loads or deletes a selected tile from a visual image directory.
13026% The load or delete command is chosen from a menu.
13027%
13028% The format of the XTileImage method is:
13029%
13030% Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013031% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013032%
13033% A description of each parameter follows:
13034%
13035% o tile_image: XTileImage reads or deletes the tile image
13036% and returns it. A null image is returned if an error occurs.
13037%
13038% o display: Specifies a connection to an X server; returned from
13039% XOpenDisplay.
13040%
13041% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13042%
13043% o windows: Specifies a pointer to a XWindows structure.
13044%
13045% o image: the image; returned from ReadImage.
13046%
13047% o event: Specifies a pointer to a XEvent structure. If it is NULL,
13048% the entire image is refreshed.
13049%
cristy051718b2011-08-28 22:49:25 +000013050% o exception: return any errors or warnings in this structure.
13051%
cristy3ed852e2009-09-05 21:47:34 +000013052*/
13053static Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013054 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013055{
13056 static const char
13057 *VerbMenu[] =
13058 {
13059 "Load",
13060 "Next",
13061 "Former",
13062 "Delete",
13063 "Update",
13064 (char *) NULL,
13065 };
13066
13067 static const ModeType
13068 TileCommands[] =
13069 {
13070 TileLoadCommand,
13071 TileNextCommand,
13072 TileFormerCommand,
13073 TileDeleteCommand,
13074 TileUpdateCommand
13075 };
13076
13077 char
13078 command[MaxTextExtent],
13079 filename[MaxTextExtent];
13080
13081 Image
13082 *tile_image;
13083
13084 int
13085 id,
13086 status,
13087 tile,
13088 x,
13089 y;
13090
13091 MagickRealType
13092 scale_factor;
13093
13094 register char
13095 *p,
13096 *q;
13097
13098 register int
13099 i;
13100
13101 unsigned int
13102 height,
13103 width;
13104
13105 /*
13106 Tile image is relative to montage image configuration.
13107 */
13108 x=0;
13109 y=0;
13110 width=(unsigned int) image->columns;
13111 height=(unsigned int) image->rows;
13112 if (windows->image.crop_geometry != (char *) NULL)
13113 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13114 scale_factor=(MagickRealType) width/windows->image.ximage->width;
13115 event->xbutton.x+=windows->image.x;
13116 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13117 scale_factor=(MagickRealType) height/windows->image.ximage->height;
13118 event->xbutton.y+=windows->image.y;
13119 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13120 /*
13121 Determine size and location of each tile in the visual image directory.
13122 */
13123 width=(unsigned int) image->columns;
13124 height=(unsigned int) image->rows;
13125 x=0;
13126 y=0;
13127 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13128 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13129 (event->xbutton.x-x)/width;
13130 if (tile < 0)
13131 {
13132 /*
13133 Button press is outside any tile.
13134 */
13135 (void) XBell(display,0);
13136 return((Image *) NULL);
13137 }
13138 /*
13139 Determine file name from the tile directory.
13140 */
13141 p=image->directory;
13142 for (i=tile; (i != 0) && (*p != '\0'); )
13143 {
13144 if (*p == '\n')
13145 i--;
13146 p++;
13147 }
13148 if (*p == '\0')
13149 {
13150 /*
13151 Button press is outside any tile.
13152 */
13153 (void) XBell(display,0);
13154 return((Image *) NULL);
13155 }
13156 /*
13157 Select a command from the pop-up menu.
13158 */
13159 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13160 if (id < 0)
13161 return((Image *) NULL);
13162 q=p;
13163 while ((*q != '\n') && (*q != '\0'))
13164 q++;
13165 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13166 /*
13167 Perform command for the selected tile.
13168 */
13169 XSetCursorState(display,windows,MagickTrue);
13170 XCheckRefreshWindows(display,windows);
13171 tile_image=NewImageList();
13172 switch (TileCommands[id])
13173 {
13174 case TileLoadCommand:
13175 {
13176 /*
13177 Load tile image.
13178 */
13179 XCheckRefreshWindows(display,windows);
13180 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13181 MaxTextExtent);
13182 (void) CopyMagickString(resource_info->image_info->filename,filename,
13183 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000013184 tile_image=ReadImage(resource_info->image_info,exception);
13185 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000013186 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13187 break;
13188 }
13189 case TileNextCommand:
13190 {
13191 /*
13192 Display next image.
13193 */
13194 XClientMessage(display,windows->image.id,windows->im_protocols,
13195 windows->im_next_image,CurrentTime);
13196 break;
13197 }
13198 case TileFormerCommand:
13199 {
13200 /*
13201 Display former image.
13202 */
13203 XClientMessage(display,windows->image.id,windows->im_protocols,
13204 windows->im_former_image,CurrentTime);
13205 break;
13206 }
13207 case TileDeleteCommand:
13208 {
13209 /*
13210 Delete tile image.
13211 */
13212 if (IsPathAccessible(filename) == MagickFalse)
13213 {
13214 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13215 break;
13216 }
13217 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13218 if (status <= 0)
13219 break;
cristy18c6c272011-09-23 14:40:37 +000013220 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +000013221 if (status != MagickFalse)
13222 {
13223 XNoticeWidget(display,windows,"Unable to delete image file:",
13224 filename);
13225 break;
13226 }
13227 }
13228 case TileUpdateCommand:
13229 {
cristy3ed852e2009-09-05 21:47:34 +000013230 int
13231 x_offset,
13232 y_offset;
13233
cristy101ab702011-10-13 13:06:32 +000013234 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000013235 pixel;
13236
13237 register int
13238 j;
13239
cristy4c08aed2011-07-01 19:47:50 +000013240 register Quantum
cristy3ed852e2009-09-05 21:47:34 +000013241 *s;
13242
13243 /*
13244 Ensure all the images exist.
13245 */
13246 tile=0;
cristy101ab702011-10-13 13:06:32 +000013247 GetPixelInfo(image,&pixel);
cristy3ed852e2009-09-05 21:47:34 +000013248 for (p=image->directory; *p != '\0'; p++)
13249 {
cristyf7c25522010-11-15 01:25:14 +000013250 CacheView
13251 *image_view;
13252
cristy3ed852e2009-09-05 21:47:34 +000013253 q=p;
13254 while ((*q != '\n') && (*q != '\0'))
13255 q++;
13256 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13257 p=q;
13258 if (IsPathAccessible(filename) != MagickFalse)
13259 {
13260 tile++;
13261 continue;
13262 }
13263 /*
13264 Overwrite tile with background color.
13265 */
13266 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13267 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
cristydb070952012-04-20 14:33:00 +000013268 image_view=AcquireAuthenticCacheView(image,exception);
cristyf05d4942012-03-17 16:26:09 +000013269 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000013270 for (i=0; i < (int) height; i++)
13271 {
cristy49e2d862010-11-12 02:50:30 +000013272 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13273 y_offset+i,width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000013274 if (s == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000013275 break;
13276 for (j=0; j < (int) width; j++)
cristy4c08aed2011-07-01 19:47:50 +000013277 {
cristy803640d2011-11-17 02:11:32 +000013278 SetPixelInfoPixel(image,&pixel,s);
cristyed231572011-07-14 02:18:59 +000013279 s+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +000013280 }
cristy49e2d862010-11-12 02:50:30 +000013281 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000013282 break;
13283 }
cristyca1628f2010-11-15 01:17:49 +000013284 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000013285 tile++;
13286 }
13287 windows->image.window_changes.width=(int) image->columns;
13288 windows->image.window_changes.height=(int) image->rows;
cristy6710d842011-10-20 23:23:00 +000013289 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000013290 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013291 break;
13292 }
13293 default:
13294 break;
13295 }
13296 XSetCursorState(display,windows,MagickFalse);
13297 return(tile_image);
13298}
13299
13300/*
13301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13302% %
13303% %
13304% %
13305+ X T r a n s l a t e I m a g e %
13306% %
13307% %
13308% %
13309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13310%
13311% XTranslateImage() translates the image within an Image window by one pixel
13312% as specified by the key symbol. If the image has a `montage string the
13313% translation is respect to the width and height contained within the string.
13314%
13315% The format of the XTranslateImage method is:
13316%
13317% void XTranslateImage(Display *display,XWindows *windows,
13318% Image *image,const KeySym key_symbol)
13319%
13320% A description of each parameter follows:
13321%
13322% o display: Specifies a connection to an X server; returned from
13323% XOpenDisplay.
13324%
13325% o windows: Specifies a pointer to a XWindows structure.
13326%
13327% o image: the image.
13328%
13329% o key_symbol: Specifies a KeySym which indicates which side of the image
13330% to trim.
13331%
13332*/
13333static void XTranslateImage(Display *display,XWindows *windows,
13334 Image *image,const KeySym key_symbol)
13335{
13336 char
13337 text[MaxTextExtent];
13338
13339 int
13340 x,
13341 y;
13342
13343 unsigned int
13344 x_offset,
13345 y_offset;
13346
13347 /*
13348 User specified a pan position offset.
13349 */
13350 x_offset=windows->image.width;
13351 y_offset=windows->image.height;
13352 if (image->montage != (char *) NULL)
13353 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13354 switch ((int) key_symbol)
13355 {
13356 case XK_Home:
13357 case XK_KP_Home:
13358 {
13359 windows->image.x=(int) windows->image.width/2;
13360 windows->image.y=(int) windows->image.height/2;
13361 break;
13362 }
13363 case XK_Left:
13364 case XK_KP_Left:
13365 {
13366 windows->image.x-=x_offset;
13367 break;
13368 }
13369 case XK_Next:
13370 case XK_Up:
13371 case XK_KP_Up:
13372 {
13373 windows->image.y-=y_offset;
13374 break;
13375 }
13376 case XK_Right:
13377 case XK_KP_Right:
13378 {
13379 windows->image.x+=x_offset;
13380 break;
13381 }
13382 case XK_Prior:
13383 case XK_Down:
13384 case XK_KP_Down:
13385 {
13386 windows->image.y+=y_offset;
13387 break;
13388 }
13389 default:
13390 return;
13391 }
13392 /*
13393 Check boundary conditions.
13394 */
13395 if (windows->image.x < 0)
13396 windows->image.x=0;
13397 else
13398 if ((int) (windows->image.x+windows->image.width) >
13399 windows->image.ximage->width)
cristy49e2d862010-11-12 02:50:30 +000013400 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +000013401 if (windows->image.y < 0)
13402 windows->image.y=0;
13403 else
13404 if ((int) (windows->image.y+windows->image.height) >
13405 windows->image.ximage->height)
cristy49e2d862010-11-12 02:50:30 +000013406 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +000013407 /*
13408 Refresh Image window.
13409 */
cristyb51dff52011-05-19 16:55:47 +000013410 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000013411 windows->image.width,windows->image.height,windows->image.x,
13412 windows->image.y);
13413 XInfoWidget(display,windows,text);
13414 XCheckRefreshWindows(display,windows);
13415 XDrawPanRectangle(display,windows);
13416 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13417 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13418}
13419
13420/*
13421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13422% %
13423% %
13424% %
13425+ X T r i m I m a g e %
13426% %
13427% %
13428% %
13429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13430%
13431% XTrimImage() trims the edges from the Image window.
13432%
13433% The format of the XTrimImage method is:
13434%
13435% MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013436% XResourceInfo *resource_info,XWindows *windows,Image *image,
13437% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013438%
13439% A description of each parameter follows:
13440%
13441% o display: Specifies a connection to an X server; returned from
13442% XOpenDisplay.
13443%
13444% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13445%
13446% o windows: Specifies a pointer to a XWindows structure.
13447%
13448% o image: the image.
13449%
cristy051718b2011-08-28 22:49:25 +000013450% o exception: return any errors or warnings in this structure.
13451%
cristy3ed852e2009-09-05 21:47:34 +000013452*/
13453static MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013454 XResourceInfo *resource_info,XWindows *windows,Image *image,
13455 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013456{
13457 RectangleInfo
13458 trim_info;
13459
13460 register int
13461 x,
13462 y;
13463
cristybb503372010-05-27 20:51:26 +000013464 size_t
cristy3ed852e2009-09-05 21:47:34 +000013465 background,
13466 pixel;
13467
13468 /*
13469 Trim edges from image.
13470 */
13471 XSetCursorState(display,windows,MagickTrue);
13472 XCheckRefreshWindows(display,windows);
13473 /*
13474 Crop the left edge.
13475 */
13476 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013477 trim_info.width=(size_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013478 for (x=0; x < windows->image.ximage->width; x++)
13479 {
13480 for (y=0; y < windows->image.ximage->height; y++)
13481 {
13482 pixel=XGetPixel(windows->image.ximage,x,y);
13483 if (pixel != background)
13484 break;
13485 }
13486 if (y < windows->image.ximage->height)
13487 break;
13488 }
cristy49e2d862010-11-12 02:50:30 +000013489 trim_info.x=(ssize_t) x;
13490 if (trim_info.x == (ssize_t) windows->image.ximage->width)
cristy3ed852e2009-09-05 21:47:34 +000013491 {
13492 XSetCursorState(display,windows,MagickFalse);
13493 return(MagickFalse);
13494 }
13495 /*
13496 Crop the right edge.
13497 */
13498 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13499 for (x=windows->image.ximage->width-1; x != 0; x--)
13500 {
13501 for (y=0; y < windows->image.ximage->height; y++)
13502 {
13503 pixel=XGetPixel(windows->image.ximage,x,y);
13504 if (pixel != background)
13505 break;
13506 }
13507 if (y < windows->image.ximage->height)
13508 break;
13509 }
cristybb503372010-05-27 20:51:26 +000013510 trim_info.width=(size_t) (x-trim_info.x+1);
cristy3ed852e2009-09-05 21:47:34 +000013511 /*
13512 Crop the top edge.
13513 */
13514 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013515 trim_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013516 for (y=0; y < windows->image.ximage->height; y++)
13517 {
13518 for (x=0; x < windows->image.ximage->width; x++)
13519 {
13520 pixel=XGetPixel(windows->image.ximage,x,y);
13521 if (pixel != background)
13522 break;
13523 }
13524 if (x < windows->image.ximage->width)
13525 break;
13526 }
cristy49e2d862010-11-12 02:50:30 +000013527 trim_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000013528 /*
13529 Crop the bottom edge.
13530 */
13531 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13532 for (y=windows->image.ximage->height-1; y != 0; y--)
13533 {
13534 for (x=0; x < windows->image.ximage->width; x++)
13535 {
13536 pixel=XGetPixel(windows->image.ximage,x,y);
13537 if (pixel != background)
13538 break;
13539 }
13540 if (x < windows->image.ximage->width)
13541 break;
13542 }
cristybb503372010-05-27 20:51:26 +000013543 trim_info.height=(size_t) y-trim_info.y+1;
cristy3ed852e2009-09-05 21:47:34 +000013544 if (((unsigned int) trim_info.width != windows->image.width) ||
13545 ((unsigned int) trim_info.height != windows->image.height))
13546 {
13547 /*
13548 Reconfigure Image window as defined by the trimming rectangle.
13549 */
13550 XSetCropGeometry(display,windows,&trim_info,image);
13551 windows->image.window_changes.width=(int) trim_info.width;
13552 windows->image.window_changes.height=(int) trim_info.height;
cristy051718b2011-08-28 22:49:25 +000013553 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013554 }
13555 XSetCursorState(display,windows,MagickFalse);
13556 return(MagickTrue);
13557}
13558
13559/*
13560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13561% %
13562% %
13563% %
13564+ X V i s u a l D i r e c t o r y I m a g e %
13565% %
13566% %
13567% %
13568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13569%
13570% XVisualDirectoryImage() creates a Visual Image Directory.
13571%
13572% The format of the XVisualDirectoryImage method is:
13573%
13574% Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013575% XResourceInfo *resource_info,XWindows *windows,
13576% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013577%
13578% A description of each parameter follows:
13579%
cristy3ed852e2009-09-05 21:47:34 +000013580% o display: Specifies a connection to an X server; returned from
13581% XOpenDisplay.
13582%
13583% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13584%
13585% o windows: Specifies a pointer to a XWindows structure.
13586%
cristy051718b2011-08-28 22:49:25 +000013587% o exception: return any errors or warnings in this structure.
13588%
cristy3ed852e2009-09-05 21:47:34 +000013589*/
13590static Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013591 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013592{
13593#define TileImageTag "Scale/Image"
13594#define XClientName "montage"
13595
13596 char
13597 **filelist;
13598
cristy3ed852e2009-09-05 21:47:34 +000013599 Image
13600 *images,
13601 *montage_image,
13602 *next_image,
13603 *thumbnail_image;
13604
13605 ImageInfo
13606 *read_info;
13607
13608 int
13609 number_files;
13610
13611 MagickBooleanType
13612 backdrop;
13613
13614 MagickStatusType
13615 status;
13616
13617 MontageInfo
13618 *montage_info;
13619
13620 RectangleInfo
13621 geometry;
13622
13623 register int
13624 i;
13625
13626 static char
13627 filename[MaxTextExtent] = "\0",
13628 filenames[MaxTextExtent] = "*";
13629
13630 XResourceInfo
13631 background_resources;
13632
13633 /*
13634 Request file name from user.
13635 */
13636 XFileBrowserWidget(display,windows,"Directory",filenames);
13637 if (*filenames == '\0')
13638 return((Image *) NULL);
13639 /*
13640 Expand the filenames.
13641 */
cristy73bd4a52010-10-05 11:24:23 +000013642 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013643 if (filelist == (char **) NULL)
13644 {
13645 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13646 filenames);
13647 return((Image *) NULL);
13648 }
13649 number_files=1;
13650 filelist[0]=filenames;
13651 status=ExpandFilenames(&number_files,&filelist);
13652 if ((status == MagickFalse) || (number_files == 0))
13653 {
13654 if (number_files == 0)
13655 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13656 else
13657 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13658 filenames);
13659 return((Image *) NULL);
13660 }
13661 /*
13662 Set image background resources.
13663 */
13664 background_resources=(*resource_info);
13665 background_resources.window_id=AcquireString("");
cristyb51dff52011-05-19 16:55:47 +000013666 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013667 "0x%lx",windows->image.id);
13668 background_resources.backdrop=MagickTrue;
13669 /*
13670 Read each image and convert them to a tile.
13671 */
13672 backdrop=(windows->visual_info->klass == TrueColor) ||
13673 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13674 read_info=CloneImageInfo(resource_info->image_info);
cristy9ce61202010-11-24 00:38:37 +000013675 (void) SetImageOption(read_info,"jpeg:size","120x120");
13676 (void) CloneString(&read_info->size,DefaultTileGeometry);
cristy3ed852e2009-09-05 21:47:34 +000013677 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13678 (void *) NULL);
13679 images=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +000013680 XSetCursorState(display,windows,MagickTrue);
13681 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +000013682 for (i=0; i < (int) number_files; i++)
cristy3ed852e2009-09-05 21:47:34 +000013683 {
13684 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13685 filelist[i]=DestroyString(filelist[i]);
13686 *read_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +000013687 next_image=ReadImage(read_info,exception);
13688 CatchException(exception);
13689 if (next_image != (Image *) NULL)
13690 {
13691 (void) DeleteImageProperty(next_image,"label");
cristy77619442010-11-24 00:27:23 +000013692 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
cristyd15e6592011-10-15 00:13:06 +000013693 read_info,next_image,DefaultTileLabel,exception),exception);
cristy3ed852e2009-09-05 21:47:34 +000013694 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13695 exception);
13696 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13697 geometry.height,exception);
13698 if (thumbnail_image != (Image *) NULL)
13699 {
13700 next_image=DestroyImage(next_image);
13701 next_image=thumbnail_image;
13702 }
13703 if (backdrop)
13704 {
13705 (void) XDisplayBackgroundImage(display,&background_resources,
cristy051718b2011-08-28 22:49:25 +000013706 next_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013707 XSetCursorState(display,windows,MagickTrue);
13708 }
13709 AppendImageToList(&images,next_image);
13710 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13711 {
13712 MagickBooleanType
13713 proceed;
13714
13715 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13716 (MagickSizeType) number_files);
13717 if (proceed == MagickFalse)
13718 break;
13719 }
13720 }
13721 }
cristy3ed852e2009-09-05 21:47:34 +000013722 filelist=(char **) RelinquishMagickMemory(filelist);
cristy3ed852e2009-09-05 21:47:34 +000013723 if (images == (Image *) NULL)
13724 {
cristy8d52fca2010-11-24 00:45:05 +000013725 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013726 XSetCursorState(display,windows,MagickFalse);
13727 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13728 return((Image *) NULL);
13729 }
13730 /*
13731 Create the Visual Image Directory.
13732 */
cristy8d52fca2010-11-24 00:45:05 +000013733 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13734 montage_info->pointsize=10;
cristy3ed852e2009-09-05 21:47:34 +000013735 if (resource_info->font != (char *) NULL)
13736 (void) CloneString(&montage_info->font,resource_info->font);
13737 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
cristy8d52fca2010-11-24 00:45:05 +000013738 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
cristy051718b2011-08-28 22:49:25 +000013739 images),exception);
cristy3ed852e2009-09-05 21:47:34 +000013740 images=DestroyImageList(images);
cristy8d52fca2010-11-24 00:45:05 +000013741 montage_info=DestroyMontageInfo(montage_info);
13742 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013743 XSetCursorState(display,windows,MagickFalse);
13744 if (montage_image == (Image *) NULL)
13745 return(montage_image);
13746 XClientMessage(display,windows->image.id,windows->im_protocols,
13747 windows->im_next_image,CurrentTime);
13748 return(montage_image);
13749}
13750
13751/*
13752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13753% %
13754% %
13755% %
13756% X D i s p l a y B a c k g r o u n d I m a g e %
13757% %
13758% %
13759% %
13760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13761%
13762% XDisplayBackgroundImage() displays an image in the background of a window.
13763%
13764% The format of the XDisplayBackgroundImage method is:
13765%
13766% MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013767% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013768%
13769% A description of each parameter follows:
13770%
13771% o display: Specifies a connection to an X server; returned from
13772% XOpenDisplay.
13773%
13774% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13775%
13776% o image: the image.
13777%
cristy051718b2011-08-28 22:49:25 +000013778% o exception: return any errors or warnings in this structure.
13779%
cristy3ed852e2009-09-05 21:47:34 +000013780*/
13781MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013782 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013783{
13784 char
13785 geometry[MaxTextExtent],
13786 visual_type[MaxTextExtent];
13787
13788 int
13789 height,
13790 status,
13791 width;
13792
13793 RectangleInfo
13794 geometry_info;
13795
13796 static XPixelInfo
13797 pixel;
13798
13799 static XStandardColormap
13800 *map_info;
13801
13802 static XVisualInfo
13803 *visual_info = (XVisualInfo *) NULL;
13804
13805 static XWindowInfo
13806 window_info;
13807
cristybb503372010-05-27 20:51:26 +000013808 size_t
cristy3ed852e2009-09-05 21:47:34 +000013809 delay;
13810
13811 Window
13812 root_window;
13813
13814 XGCValues
13815 context_values;
13816
13817 XResourceInfo
13818 resources;
13819
13820 XWindowAttributes
13821 window_attributes;
13822
13823 /*
13824 Determine target window.
13825 */
13826 assert(image != (Image *) NULL);
13827 assert(image->signature == MagickSignature);
13828 if (image->debug != MagickFalse)
13829 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13830 resources=(*resource_info);
13831 window_info.id=(Window) NULL;
13832 root_window=XRootWindow(display,XDefaultScreen(display));
13833 if (LocaleCompare(resources.window_id,"root") == 0)
13834 window_info.id=root_window;
13835 else
13836 {
13837 if (isdigit((unsigned char) *resources.window_id) != 0)
13838 window_info.id=XWindowByID(display,root_window,
13839 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13840 if (window_info.id == (Window) NULL)
13841 window_info.id=XWindowByName(display,root_window,resources.window_id);
13842 }
13843 if (window_info.id == (Window) NULL)
13844 {
13845 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13846 resources.window_id);
13847 return(MagickFalse);
13848 }
13849 /*
13850 Determine window visual id.
13851 */
13852 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13853 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13854 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13855 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13856 if (status != 0)
cristyb51dff52011-05-19 16:55:47 +000013857 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
cristy3ed852e2009-09-05 21:47:34 +000013858 XVisualIDFromVisual(window_attributes.visual));
13859 if (visual_info == (XVisualInfo *) NULL)
13860 {
13861 /*
13862 Allocate standard colormap.
13863 */
13864 map_info=XAllocStandardColormap();
13865 if (map_info == (XStandardColormap *) NULL)
13866 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13867 image->filename);
13868 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +000013869 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000013870 /*
13871 Initialize visual info.
13872 */
13873 resources.map_type=(char *) NULL;
13874 resources.visual_type=visual_type;
13875 visual_info=XBestVisualInfo(display,map_info,&resources);
13876 if (visual_info == (XVisualInfo *) NULL)
13877 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13878 resources.visual_type);
13879 /*
13880 Initialize window info.
13881 */
13882 window_info.ximage=(XImage *) NULL;
13883 window_info.matte_image=(XImage *) NULL;
13884 window_info.pixmap=(Pixmap) NULL;
13885 window_info.matte_pixmap=(Pixmap) NULL;
13886 }
13887 /*
13888 Free previous root colors.
13889 */
13890 if (window_info.id == root_window)
13891 (void) XDestroyWindowColors(display,root_window);
13892 /*
13893 Initialize Standard Colormap.
13894 */
13895 resources.colormap=SharedColormap;
cristy6710d842011-10-20 23:23:00 +000013896 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13897 exception);
cristy3ed852e2009-09-05 21:47:34 +000013898 /*
13899 Graphic context superclass.
13900 */
13901 context_values.background=pixel.background_color.pixel;
13902 context_values.foreground=pixel.foreground_color.pixel;
13903 pixel.annotate_context=XCreateGC(display,window_info.id,
cristybb503372010-05-27 20:51:26 +000013904 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000013905 if (pixel.annotate_context == (GC) NULL)
13906 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13907 image->filename);
13908 /*
13909 Initialize Image window attributes.
13910 */
13911 window_info.name=AcquireString("\0");
13912 window_info.icon_name=AcquireString("\0");
13913 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13914 &resources,&window_info);
13915 /*
13916 Create the X image.
13917 */
13918 window_info.width=(unsigned int) image->columns;
13919 window_info.height=(unsigned int) image->rows;
13920 if ((image->columns != window_info.width) ||
13921 (image->rows != window_info.height))
13922 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13923 image->filename);
cristyb51dff52011-05-19 16:55:47 +000013924 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
cristy3ed852e2009-09-05 21:47:34 +000013925 window_attributes.width,window_attributes.height);
13926 geometry_info.width=window_info.width;
13927 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +000013928 geometry_info.x=(ssize_t) window_info.x;
13929 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +000013930 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13931 &geometry_info.width,&geometry_info.height);
13932 window_info.width=(unsigned int) geometry_info.width;
13933 window_info.height=(unsigned int) geometry_info.height;
13934 window_info.x=(int) geometry_info.x;
13935 window_info.y=(int) geometry_info.y;
13936 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
cristy051718b2011-08-28 22:49:25 +000013937 window_info.height,exception);
cristy3ed852e2009-09-05 21:47:34 +000013938 if (status == MagickFalse)
13939 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13940 image->filename);
13941 window_info.x=0;
13942 window_info.y=0;
13943 if (image->debug != MagickFalse)
13944 {
13945 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000013946 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13947 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +000013948 if (image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000013949 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13950 image->colors);
cristy3ed852e2009-09-05 21:47:34 +000013951 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13952 }
13953 /*
13954 Adjust image dimensions as specified by backdrop or geometry options.
13955 */
13956 width=(int) window_info.width;
13957 height=(int) window_info.height;
13958 if (resources.backdrop != MagickFalse)
13959 {
13960 /*
13961 Center image on window.
13962 */
13963 window_info.x=(window_attributes.width/2)-
13964 (window_info.ximage->width/2);
13965 window_info.y=(window_attributes.height/2)-
13966 (window_info.ximage->height/2);
13967 width=window_attributes.width;
13968 height=window_attributes.height;
13969 }
13970 if ((resources.image_geometry != (char *) NULL) &&
13971 (*resources.image_geometry != '\0'))
13972 {
13973 char
13974 default_geometry[MaxTextExtent];
13975
13976 int
13977 flags,
13978 gravity;
13979
13980 XSizeHints
13981 *size_hints;
13982
13983 /*
13984 User specified geometry.
13985 */
13986 size_hints=XAllocSizeHints();
13987 if (size_hints == (XSizeHints *) NULL)
13988 ThrowXWindowFatalException(ResourceLimitFatalError,
13989 "MemoryAllocationFailed",image->filename);
13990 size_hints->flags=0L;
cristyb51dff52011-05-19 16:55:47 +000013991 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
cristy3ed852e2009-09-05 21:47:34 +000013992 width,height);
13993 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13994 default_geometry,window_info.border_width,size_hints,&window_info.x,
13995 &window_info.y,&width,&height,&gravity);
13996 if (flags & (XValue | YValue))
13997 {
13998 width=window_attributes.width;
13999 height=window_attributes.height;
14000 }
14001 (void) XFree((void *) size_hints);
14002 }
14003 /*
14004 Create the X pixmap.
14005 */
14006 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14007 (unsigned int) height,window_info.depth);
14008 if (window_info.pixmap == (Pixmap) NULL)
14009 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14010 image->filename);
14011 /*
14012 Display pixmap on the window.
14013 */
14014 if (((unsigned int) width > window_info.width) ||
14015 ((unsigned int) height > window_info.height))
14016 (void) XFillRectangle(display,window_info.pixmap,
14017 window_info.annotate_context,0,0,(unsigned int) width,
14018 (unsigned int) height);
14019 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14020 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14021 window_info.width,(unsigned int) window_info.height);
14022 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14023 (void) XClearWindow(display,window_info.id);
14024 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14025 XDelay(display,delay == 0UL ? 10UL : delay);
14026 (void) XSync(display,MagickFalse);
14027 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14028}
14029
14030/*
14031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14032% %
14033% %
14034% %
14035+ X D i s p l a y I m a g e %
14036% %
14037% %
14038% %
14039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14040%
14041% XDisplayImage() displays an image via X11. A new image is created and
14042% returned if the user interactively transforms the displayed image.
14043%
14044% The format of the XDisplayImage method is:
14045%
14046% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014047% char **argv,int argc,Image **image,size_t *state,
14048% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014049%
14050% A description of each parameter follows:
14051%
14052% o nexus: Method XDisplayImage returns an image when the
14053% user chooses 'Open Image' from the command menu or picks a tile
14054% from the image directory. Otherwise a null image is returned.
14055%
14056% o display: Specifies a connection to an X server; returned from
14057% XOpenDisplay.
14058%
14059% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14060%
14061% o argv: Specifies the application's argument list.
14062%
14063% o argc: Specifies the number of arguments.
14064%
14065% o image: Specifies an address to an address of an Image structure;
14066%
cristy051718b2011-08-28 22:49:25 +000014067% o exception: return any errors or warnings in this structure.
14068%
cristy3ed852e2009-09-05 21:47:34 +000014069*/
14070MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014071 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014072{
14073#define MagnifySize 256 /* must be a power of 2 */
14074#define MagickMenus 10
14075#define MagickTitle "Commands"
14076
14077 static const char
14078 *CommandMenu[] =
14079 {
14080 "File",
14081 "Edit",
14082 "View",
14083 "Transform",
14084 "Enhance",
14085 "Effects",
14086 "F/X",
14087 "Image Edit",
14088 "Miscellany",
14089 "Help",
14090 (char *) NULL
14091 },
14092 *FileMenu[] =
14093 {
14094 "Open...",
14095 "Next",
14096 "Former",
14097 "Select...",
14098 "Save...",
14099 "Print...",
14100 "Delete...",
14101 "New...",
14102 "Visual Directory...",
14103 "Quit",
14104 (char *) NULL
14105 },
14106 *EditMenu[] =
14107 {
14108 "Undo",
14109 "Redo",
14110 "Cut",
14111 "Copy",
14112 "Paste",
14113 (char *) NULL
14114 },
14115 *ViewMenu[] =
14116 {
14117 "Half Size",
14118 "Original Size",
14119 "Double Size",
14120 "Resize...",
14121 "Apply",
14122 "Refresh",
14123 "Restore",
14124 (char *) NULL
14125 },
14126 *TransformMenu[] =
14127 {
14128 "Crop",
14129 "Chop",
14130 "Flop",
14131 "Flip",
14132 "Rotate Right",
14133 "Rotate Left",
14134 "Rotate...",
14135 "Shear...",
14136 "Roll...",
14137 "Trim Edges",
14138 (char *) NULL
14139 },
14140 *EnhanceMenu[] =
14141 {
14142 "Hue...",
14143 "Saturation...",
14144 "Brightness...",
14145 "Gamma...",
14146 "Spiff",
14147 "Dull",
14148 "Contrast Stretch...",
14149 "Sigmoidal Contrast...",
14150 "Normalize",
14151 "Equalize",
14152 "Negate",
14153 "Grayscale",
14154 "Map...",
14155 "Quantize...",
14156 (char *) NULL
14157 },
14158 *EffectsMenu[] =
14159 {
14160 "Despeckle",
14161 "Emboss",
14162 "Reduce Noise",
14163 "Add Noise...",
14164 "Sharpen...",
14165 "Blur...",
14166 "Threshold...",
14167 "Edge Detect...",
14168 "Spread...",
14169 "Shade...",
14170 "Raise...",
14171 "Segment...",
14172 (char *) NULL
14173 },
14174 *FXMenu[] =
14175 {
14176 "Solarize...",
14177 "Sepia Tone...",
14178 "Swirl...",
14179 "Implode...",
14180 "Vignette...",
14181 "Wave...",
14182 "Oil Paint...",
14183 "Charcoal Draw...",
14184 (char *) NULL
14185 },
14186 *ImageEditMenu[] =
14187 {
14188 "Annotate...",
14189 "Draw...",
14190 "Color...",
14191 "Matte...",
14192 "Composite...",
14193 "Add Border...",
14194 "Add Frame...",
14195 "Comment...",
14196 "Launch...",
14197 "Region of Interest...",
14198 (char *) NULL
14199 },
14200 *MiscellanyMenu[] =
14201 {
14202 "Image Info",
14203 "Zoom Image",
14204 "Show Preview...",
14205 "Show Histogram",
14206 "Show Matte",
14207 "Background...",
14208 "Slide Show...",
14209 "Preferences...",
14210 (char *) NULL
14211 },
14212 *HelpMenu[] =
14213 {
14214 "Overview",
14215 "Browse Documentation",
14216 "About Display",
14217 (char *) NULL
14218 },
14219 *ShortCutsMenu[] =
14220 {
14221 "Next",
14222 "Former",
14223 "Open...",
14224 "Save...",
14225 "Print...",
14226 "Undo",
14227 "Restore",
14228 "Image Info",
14229 "Quit",
14230 (char *) NULL
14231 },
14232 *VirtualMenu[] =
14233 {
14234 "Image Info",
14235 "Print",
14236 "Next",
14237 "Quit",
14238 (char *) NULL
14239 };
14240
14241 static const char
14242 **Menus[MagickMenus] =
14243 {
14244 FileMenu,
14245 EditMenu,
14246 ViewMenu,
14247 TransformMenu,
14248 EnhanceMenu,
14249 EffectsMenu,
14250 FXMenu,
14251 ImageEditMenu,
14252 MiscellanyMenu,
14253 HelpMenu
14254 };
14255
14256 static CommandType
14257 CommandMenus[] =
14258 {
14259 NullCommand,
14260 NullCommand,
14261 NullCommand,
14262 NullCommand,
14263 NullCommand,
14264 NullCommand,
14265 NullCommand,
14266 NullCommand,
14267 NullCommand,
14268 NullCommand,
14269 },
14270 FileCommands[] =
14271 {
14272 OpenCommand,
14273 NextCommand,
14274 FormerCommand,
14275 SelectCommand,
14276 SaveCommand,
14277 PrintCommand,
14278 DeleteCommand,
14279 NewCommand,
14280 VisualDirectoryCommand,
14281 QuitCommand
14282 },
14283 EditCommands[] =
14284 {
14285 UndoCommand,
14286 RedoCommand,
14287 CutCommand,
14288 CopyCommand,
14289 PasteCommand
14290 },
14291 ViewCommands[] =
14292 {
14293 HalfSizeCommand,
14294 OriginalSizeCommand,
14295 DoubleSizeCommand,
14296 ResizeCommand,
14297 ApplyCommand,
14298 RefreshCommand,
14299 RestoreCommand
14300 },
14301 TransformCommands[] =
14302 {
14303 CropCommand,
14304 ChopCommand,
14305 FlopCommand,
14306 FlipCommand,
14307 RotateRightCommand,
14308 RotateLeftCommand,
14309 RotateCommand,
14310 ShearCommand,
14311 RollCommand,
14312 TrimCommand
14313 },
14314 EnhanceCommands[] =
14315 {
14316 HueCommand,
14317 SaturationCommand,
14318 BrightnessCommand,
14319 GammaCommand,
14320 SpiffCommand,
14321 DullCommand,
14322 ContrastStretchCommand,
14323 SigmoidalContrastCommand,
14324 NormalizeCommand,
14325 EqualizeCommand,
14326 NegateCommand,
14327 GrayscaleCommand,
14328 MapCommand,
14329 QuantizeCommand
14330 },
14331 EffectsCommands[] =
14332 {
14333 DespeckleCommand,
14334 EmbossCommand,
14335 ReduceNoiseCommand,
14336 AddNoiseCommand,
14337 SharpenCommand,
14338 BlurCommand,
14339 ThresholdCommand,
14340 EdgeDetectCommand,
14341 SpreadCommand,
14342 ShadeCommand,
14343 RaiseCommand,
14344 SegmentCommand
14345 },
14346 FXCommands[] =
14347 {
14348 SolarizeCommand,
14349 SepiaToneCommand,
14350 SwirlCommand,
14351 ImplodeCommand,
14352 VignetteCommand,
14353 WaveCommand,
14354 OilPaintCommand,
14355 CharcoalDrawCommand
14356 },
14357 ImageEditCommands[] =
14358 {
14359 AnnotateCommand,
14360 DrawCommand,
14361 ColorCommand,
14362 MatteCommand,
14363 CompositeCommand,
14364 AddBorderCommand,
14365 AddFrameCommand,
14366 CommentCommand,
14367 LaunchCommand,
14368 RegionofInterestCommand
14369 },
14370 MiscellanyCommands[] =
14371 {
14372 InfoCommand,
14373 ZoomCommand,
14374 ShowPreviewCommand,
14375 ShowHistogramCommand,
14376 ShowMatteCommand,
14377 BackgroundCommand,
14378 SlideShowCommand,
14379 PreferencesCommand
14380 },
14381 HelpCommands[] =
14382 {
14383 HelpCommand,
14384 BrowseDocumentationCommand,
14385 VersionCommand
14386 },
14387 ShortCutsCommands[] =
14388 {
14389 NextCommand,
14390 FormerCommand,
14391 OpenCommand,
14392 SaveCommand,
14393 PrintCommand,
14394 UndoCommand,
14395 RestoreCommand,
14396 InfoCommand,
14397 QuitCommand
14398 },
14399 VirtualCommands[] =
14400 {
14401 InfoCommand,
14402 PrintCommand,
14403 NextCommand,
14404 QuitCommand
14405 };
14406
14407 static CommandType
14408 *Commands[MagickMenus] =
14409 {
14410 FileCommands,
14411 EditCommands,
14412 ViewCommands,
14413 TransformCommands,
14414 EnhanceCommands,
14415 EffectsCommands,
14416 FXCommands,
14417 ImageEditCommands,
14418 MiscellanyCommands,
14419 HelpCommands
14420 };
14421
14422 char
14423 command[MaxTextExtent],
cristy00976d82011-02-20 20:31:28 +000014424 *directory,
cristy3ed852e2009-09-05 21:47:34 +000014425 geometry[MaxTextExtent],
14426 resource_name[MaxTextExtent];
14427
14428 CommandType
14429 command_type;
14430
14431 Image
14432 *display_image,
14433 *nexus;
14434
14435 int
14436 entry,
14437 id;
14438
14439 KeySym
14440 key_symbol;
14441
14442 MagickStatusType
14443 context_mask,
14444 status;
14445
14446 RectangleInfo
14447 geometry_info;
14448
14449 register int
14450 i;
14451
14452 static char
14453 working_directory[MaxTextExtent];
14454
14455 static XPoint
14456 vid_info;
14457
14458 static XWindowInfo
14459 *magick_windows[MaxXWindows];
14460
14461 static unsigned int
14462 number_windows;
14463
14464 struct stat
14465 attributes;
14466
14467 time_t
14468 timer,
14469 timestamp,
14470 update_time;
14471
14472 unsigned int
14473 height,
14474 width;
14475
cristybb503372010-05-27 20:51:26 +000014476 size_t
cristy3ed852e2009-09-05 21:47:34 +000014477 delay;
14478
14479 WarningHandler
14480 warning_handler;
14481
14482 Window
14483 root_window;
14484
14485 XClassHint
14486 *class_hints;
14487
14488 XEvent
14489 event;
14490
14491 XFontStruct
14492 *font_info;
14493
14494 XGCValues
14495 context_values;
14496
14497 XPixelInfo
14498 *icon_pixel,
14499 *pixel;
14500
14501 XResourceInfo
14502 *icon_resources;
14503
14504 XStandardColormap
14505 *icon_map,
14506 *map_info;
14507
14508 XVisualInfo
14509 *icon_visual,
14510 *visual_info;
14511
14512 XWindowChanges
14513 window_changes;
14514
14515 XWindows
14516 *windows;
14517
14518 XWMHints
14519 *manager_hints;
14520
14521 assert(image != (Image **) NULL);
14522 assert((*image)->signature == MagickSignature);
14523 if ((*image)->debug != MagickFalse)
14524 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14525 display_image=(*image);
14526 warning_handler=(WarningHandler) NULL;
14527 windows=XSetWindows((XWindows *) ~0);
14528 if (windows != (XWindows *) NULL)
14529 {
14530 int
14531 status;
14532
14533 status=chdir(working_directory);
14534 if (status == -1)
cristy051718b2011-08-28 22:49:25 +000014535 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14536 "UnableToOpenFile","%s",working_directory);
cristy3ed852e2009-09-05 21:47:34 +000014537 warning_handler=resource_info->display_warnings ?
14538 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14539 warning_handler=resource_info->display_warnings ?
14540 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14541 }
14542 else
14543 {
14544 /*
14545 Allocate windows structure.
14546 */
14547 resource_info->colors=display_image->colors;
14548 windows=XSetWindows(XInitializeWindows(display,resource_info));
14549 if (windows == (XWindows *) NULL)
14550 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14551 (*image)->filename);
14552 /*
14553 Initialize window id's.
14554 */
14555 number_windows=0;
14556 magick_windows[number_windows++]=(&windows->icon);
14557 magick_windows[number_windows++]=(&windows->backdrop);
14558 magick_windows[number_windows++]=(&windows->image);
14559 magick_windows[number_windows++]=(&windows->info);
14560 magick_windows[number_windows++]=(&windows->command);
14561 magick_windows[number_windows++]=(&windows->widget);
14562 magick_windows[number_windows++]=(&windows->popup);
14563 magick_windows[number_windows++]=(&windows->magnify);
14564 magick_windows[number_windows++]=(&windows->pan);
14565 for (i=0; i < (int) number_windows; i++)
14566 magick_windows[i]->id=(Window) NULL;
14567 vid_info.x=0;
14568 vid_info.y=0;
14569 }
14570 /*
14571 Initialize font info.
14572 */
14573 if (windows->font_info != (XFontStruct *) NULL)
14574 (void) XFreeFont(display,windows->font_info);
14575 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14576 if (windows->font_info == (XFontStruct *) NULL)
14577 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14578 resource_info->font);
14579 /*
14580 Initialize Standard Colormap.
14581 */
14582 map_info=windows->map_info;
14583 icon_map=windows->icon_map;
14584 visual_info=windows->visual_info;
14585 icon_visual=windows->icon_visual;
14586 pixel=windows->pixel_info;
14587 icon_pixel=windows->icon_pixel;
14588 font_info=windows->font_info;
14589 icon_resources=windows->icon_resources;
14590 class_hints=windows->class_hints;
14591 manager_hints=windows->manager_hints;
14592 root_window=XRootWindow(display,visual_info->screen);
14593 nexus=NewImageList();
14594 if (display_image->debug != MagickFalse)
14595 {
14596 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000014597 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14598 (double) display_image->scene,(double) display_image->columns,
14599 (double) display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +000014600 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000014601 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14602 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +000014603 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14604 display_image->magick);
14605 }
14606 XMakeStandardColormap(display,visual_info,resource_info,display_image,
cristy6710d842011-10-20 23:23:00 +000014607 map_info,pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000014608 display_image->taint=MagickFalse;
14609 /*
14610 Initialize graphic context.
14611 */
14612 windows->context.id=(Window) NULL;
14613 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14614 resource_info,&windows->context);
14615 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14616 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14617 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14618 manager_hints->flags=InputHint | StateHint;
14619 manager_hints->input=MagickFalse;
14620 manager_hints->initial_state=WithdrawnState;
14621 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14622 &windows->context);
14623 if (display_image->debug != MagickFalse)
14624 (void) LogMagickEvent(X11Event,GetMagickModule(),
14625 "Window id: 0x%lx (context)",windows->context.id);
14626 context_values.background=pixel->background_color.pixel;
14627 context_values.font=font_info->fid;
14628 context_values.foreground=pixel->foreground_color.pixel;
14629 context_values.graphics_exposures=MagickFalse;
14630 context_mask=(MagickStatusType)
14631 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14632 if (pixel->annotate_context != (GC) NULL)
14633 (void) XFreeGC(display,pixel->annotate_context);
14634 pixel->annotate_context=XCreateGC(display,windows->context.id,
14635 context_mask,&context_values);
14636 if (pixel->annotate_context == (GC) NULL)
14637 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14638 display_image->filename);
14639 context_values.background=pixel->depth_color.pixel;
14640 if (pixel->widget_context != (GC) NULL)
14641 (void) XFreeGC(display,pixel->widget_context);
14642 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14643 &context_values);
14644 if (pixel->widget_context == (GC) NULL)
14645 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14646 display_image->filename);
14647 context_values.background=pixel->foreground_color.pixel;
14648 context_values.foreground=pixel->background_color.pixel;
14649 context_values.plane_mask=context_values.background ^
14650 context_values.foreground;
14651 if (pixel->highlight_context != (GC) NULL)
14652 (void) XFreeGC(display,pixel->highlight_context);
14653 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +000014654 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014655 if (pixel->highlight_context == (GC) NULL)
14656 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14657 display_image->filename);
14658 (void) XDestroyWindow(display,windows->context.id);
14659 /*
14660 Initialize icon window.
14661 */
14662 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14663 icon_resources,&windows->icon);
14664 windows->icon.geometry=resource_info->icon_geometry;
14665 XBestIconSize(display,&windows->icon,display_image);
14666 windows->icon.attributes.colormap=XDefaultColormap(display,
14667 icon_visual->screen);
14668 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14669 manager_hints->flags=InputHint | StateHint;
14670 manager_hints->input=MagickFalse;
14671 manager_hints->initial_state=IconicState;
14672 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14673 &windows->icon);
14674 if (display_image->debug != MagickFalse)
14675 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14676 windows->icon.id);
14677 /*
14678 Initialize graphic context for icon window.
14679 */
14680 if (icon_pixel->annotate_context != (GC) NULL)
14681 (void) XFreeGC(display,icon_pixel->annotate_context);
14682 context_values.background=icon_pixel->background_color.pixel;
14683 context_values.foreground=icon_pixel->foreground_color.pixel;
14684 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +000014685 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014686 if (icon_pixel->annotate_context == (GC) NULL)
14687 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14688 display_image->filename);
14689 windows->icon.annotate_context=icon_pixel->annotate_context;
14690 /*
14691 Initialize Image window.
14692 */
14693 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14694 &windows->image);
14695 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14696 if (resource_info->use_shared_memory == MagickFalse)
14697 windows->image.shared_memory=MagickFalse;
14698 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14699 {
14700 char
14701 *title;
14702
14703 title=InterpretImageProperties(resource_info->image_info,display_image,
cristy018f07f2011-09-04 21:15:19 +000014704 resource_info->title,exception);
cristy3ed852e2009-09-05 21:47:34 +000014705 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14706 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14707 title=DestroyString(title);
14708 }
14709 else
14710 {
14711 char
14712 filename[MaxTextExtent];
14713
14714 /*
14715 Window name is the base of the filename.
14716 */
14717 GetPathComponent(display_image->magick_filename,TailPath,filename);
cristy9a48b172011-09-20 17:41:05 +000014718 if (display_image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +000014719 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy40a08ad2010-02-09 02:27:44 +000014720 "%s: %s",MagickPackageName,filename);
cristy3ed852e2009-09-05 21:47:34 +000014721 else
cristyb51dff52011-05-19 16:55:47 +000014722 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy04d55062011-03-15 18:58:50 +000014723 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14724 (double) display_image->scene,(double) GetImageListLength(
14725 display_image));
cristy3ed852e2009-09-05 21:47:34 +000014726 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14727 }
14728 if (resource_info->immutable)
14729 windows->image.immutable=MagickTrue;
14730 windows->image.use_pixmap=resource_info->use_pixmap;
14731 windows->image.geometry=resource_info->image_geometry;
cristyb51dff52011-05-19 16:55:47 +000014732 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +000014733 XDisplayWidth(display,visual_info->screen),
14734 XDisplayHeight(display,visual_info->screen));
14735 geometry_info.width=display_image->columns;
14736 geometry_info.height=display_image->rows;
14737 geometry_info.x=0;
14738 geometry_info.y=0;
14739 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14740 &geometry_info.width,&geometry_info.height);
14741 windows->image.width=(unsigned int) geometry_info.width;
14742 windows->image.height=(unsigned int) geometry_info.height;
14743 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14744 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14745 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14746 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14747 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14748 resource_info,&windows->backdrop);
14749 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14750 {
14751 /*
14752 Initialize backdrop window.
14753 */
14754 windows->backdrop.x=0;
14755 windows->backdrop.y=0;
cristy40a08ad2010-02-09 02:27:44 +000014756 (void) CloneString(&windows->backdrop.name,"Backdrop");
cristybb503372010-05-27 20:51:26 +000014757 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +000014758 windows->backdrop.width=(unsigned int)
14759 XDisplayWidth(display,visual_info->screen);
14760 windows->backdrop.height=(unsigned int)
14761 XDisplayHeight(display,visual_info->screen);
14762 windows->backdrop.border_width=0;
14763 windows->backdrop.immutable=MagickTrue;
14764 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14765 ButtonReleaseMask;
14766 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14767 StructureNotifyMask;
14768 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14769 manager_hints->icon_window=windows->icon.id;
14770 manager_hints->input=MagickTrue;
14771 manager_hints->initial_state=resource_info->iconic ? IconicState :
14772 NormalState;
14773 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14774 &windows->backdrop);
14775 if (display_image->debug != MagickFalse)
14776 (void) LogMagickEvent(X11Event,GetMagickModule(),
14777 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14778 (void) XMapWindow(display,windows->backdrop.id);
14779 (void) XClearWindow(display,windows->backdrop.id);
14780 if (windows->image.id != (Window) NULL)
14781 {
14782 (void) XDestroyWindow(display,windows->image.id);
14783 windows->image.id=(Window) NULL;
14784 }
14785 /*
14786 Position image in the center the backdrop.
14787 */
14788 windows->image.flags|=USPosition;
14789 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14790 (windows->image.width/2);
14791 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14792 (windows->image.height/2);
14793 }
14794 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14795 manager_hints->icon_window=windows->icon.id;
14796 manager_hints->input=MagickTrue;
14797 manager_hints->initial_state=resource_info->iconic ? IconicState :
14798 NormalState;
14799 if (windows->group_leader.id != (Window) NULL)
14800 {
14801 /*
14802 Follow the leader.
14803 */
14804 manager_hints->flags|=WindowGroupHint;
14805 manager_hints->window_group=windows->group_leader.id;
14806 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14807 if (display_image->debug != MagickFalse)
14808 (void) LogMagickEvent(X11Event,GetMagickModule(),
14809 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14810 }
14811 XMakeWindow(display,
14812 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14813 argv,argc,class_hints,manager_hints,&windows->image);
14814 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14815 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14816 if (windows->group_leader.id != (Window) NULL)
14817 (void) XSetTransientForHint(display,windows->image.id,
14818 windows->group_leader.id);
14819 if (display_image->debug != MagickFalse)
14820 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14821 windows->image.id);
14822 /*
14823 Initialize Info widget.
14824 */
14825 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14826 &windows->info);
14827 (void) CloneString(&windows->info.name,"Info");
14828 (void) CloneString(&windows->info.icon_name,"Info");
14829 windows->info.border_width=1;
14830 windows->info.x=2;
14831 windows->info.y=2;
14832 windows->info.flags|=PPosition;
14833 windows->info.attributes.win_gravity=UnmapGravity;
14834 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14835 StructureNotifyMask;
14836 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14837 manager_hints->input=MagickFalse;
14838 manager_hints->initial_state=NormalState;
14839 manager_hints->window_group=windows->image.id;
14840 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14841 &windows->info);
14842 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14843 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14844 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14845 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14846 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14847 if (windows->image.mapped != MagickFalse)
14848 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14849 if (display_image->debug != MagickFalse)
14850 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14851 windows->info.id);
14852 /*
14853 Initialize Command widget.
14854 */
14855 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14856 resource_info,&windows->command);
14857 windows->command.data=MagickMenus;
14858 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014859 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
cristy3ed852e2009-09-05 21:47:34 +000014860 resource_info->client_name);
14861 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14862 resource_name,"geometry",(char *) NULL);
14863 (void) CloneString(&windows->command.name,MagickTitle);
14864 windows->command.border_width=0;
14865 windows->command.flags|=PPosition;
14866 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14867 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14868 OwnerGrabButtonMask | StructureNotifyMask;
14869 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14870 manager_hints->input=MagickTrue;
14871 manager_hints->initial_state=NormalState;
14872 manager_hints->window_group=windows->image.id;
14873 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14874 &windows->command);
14875 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14876 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14877 HighlightHeight);
14878 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14879 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14880 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14881 if (windows->command.mapped != MagickFalse)
14882 (void) XMapRaised(display,windows->command.id);
14883 if (display_image->debug != MagickFalse)
14884 (void) LogMagickEvent(X11Event,GetMagickModule(),
14885 "Window id: 0x%lx (command)",windows->command.id);
14886 /*
14887 Initialize Widget window.
14888 */
14889 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14890 resource_info,&windows->widget);
cristyb51dff52011-05-19 16:55:47 +000014891 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
cristy3ed852e2009-09-05 21:47:34 +000014892 resource_info->client_name);
14893 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14894 resource_name,"geometry",(char *) NULL);
14895 windows->widget.border_width=0;
14896 windows->widget.flags|=PPosition;
14897 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14898 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14899 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14900 StructureNotifyMask;
14901 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14902 manager_hints->input=MagickTrue;
14903 manager_hints->initial_state=NormalState;
14904 manager_hints->window_group=windows->image.id;
14905 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14906 &windows->widget);
14907 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14908 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14909 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14910 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14911 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14912 if (display_image->debug != MagickFalse)
14913 (void) LogMagickEvent(X11Event,GetMagickModule(),
14914 "Window id: 0x%lx (widget)",windows->widget.id);
14915 /*
14916 Initialize popup window.
14917 */
14918 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14919 resource_info,&windows->popup);
14920 windows->popup.border_width=0;
14921 windows->popup.flags|=PPosition;
14922 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14923 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14924 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14925 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14926 manager_hints->input=MagickTrue;
14927 manager_hints->initial_state=NormalState;
14928 manager_hints->window_group=windows->image.id;
14929 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14930 &windows->popup);
14931 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14932 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14933 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14934 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14935 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14936 if (display_image->debug != MagickFalse)
14937 (void) LogMagickEvent(X11Event,GetMagickModule(),
14938 "Window id: 0x%lx (pop up)",windows->popup.id);
14939 /*
14940 Initialize Magnify window and cursor.
14941 */
14942 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14943 resource_info,&windows->magnify);
14944 if (resource_info->use_shared_memory == MagickFalse)
14945 windows->magnify.shared_memory=MagickFalse;
cristyb51dff52011-05-19 16:55:47 +000014946 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
cristy3ed852e2009-09-05 21:47:34 +000014947 resource_info->client_name);
14948 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14949 resource_name,"geometry",(char *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014950 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
cristy3ed852e2009-09-05 21:47:34 +000014951 resource_info->magnify);
14952 if (windows->magnify.cursor != (Cursor) NULL)
14953 (void) XFreeCursor(display,windows->magnify.cursor);
14954 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14955 map_info->colormap,resource_info->background_color,
14956 resource_info->foreground_color);
14957 if (windows->magnify.cursor == (Cursor) NULL)
14958 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14959 display_image->filename);
14960 windows->magnify.width=MagnifySize;
14961 windows->magnify.height=MagnifySize;
14962 windows->magnify.flags|=PPosition;
14963 windows->magnify.min_width=MagnifySize;
14964 windows->magnify.min_height=MagnifySize;
14965 windows->magnify.width_inc=MagnifySize;
14966 windows->magnify.height_inc=MagnifySize;
14967 windows->magnify.data=resource_info->magnify;
14968 windows->magnify.attributes.cursor=windows->magnify.cursor;
14969 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14970 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14971 StructureNotifyMask;
14972 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14973 manager_hints->input=MagickTrue;
14974 manager_hints->initial_state=NormalState;
14975 manager_hints->window_group=windows->image.id;
14976 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14977 &windows->magnify);
14978 if (display_image->debug != MagickFalse)
14979 (void) LogMagickEvent(X11Event,GetMagickModule(),
14980 "Window id: 0x%lx (magnify)",windows->magnify.id);
14981 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14982 /*
14983 Initialize panning window.
14984 */
14985 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14986 resource_info,&windows->pan);
14987 (void) CloneString(&windows->pan.name,"Pan Icon");
14988 windows->pan.width=windows->icon.width;
14989 windows->pan.height=windows->icon.height;
cristyb51dff52011-05-19 16:55:47 +000014990 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
cristy3ed852e2009-09-05 21:47:34 +000014991 resource_info->client_name);
14992 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14993 resource_name,"geometry",(char *) NULL);
14994 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14995 &windows->pan.width,&windows->pan.height);
14996 windows->pan.flags|=PPosition;
14997 windows->pan.immutable=MagickTrue;
14998 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14999 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15000 StructureNotifyMask;
15001 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15002 manager_hints->input=MagickFalse;
15003 manager_hints->initial_state=NormalState;
15004 manager_hints->window_group=windows->image.id;
15005 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15006 &windows->pan);
15007 if (display_image->debug != MagickFalse)
15008 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15009 windows->pan.id);
15010 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15011 if (windows->info.mapped != MagickFalse)
15012 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15013 if ((windows->image.mapped == MagickFalse) ||
15014 (windows->backdrop.id != (Window) NULL))
15015 (void) XMapWindow(display,windows->image.id);
15016 /*
15017 Set our progress monitor and warning handlers.
15018 */
15019 if (warning_handler == (WarningHandler) NULL)
15020 {
15021 warning_handler=resource_info->display_warnings ?
15022 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15023 warning_handler=resource_info->display_warnings ?
15024 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15025 }
15026 /*
15027 Initialize Image and Magnify X images.
15028 */
15029 windows->image.x=0;
15030 windows->image.y=0;
15031 windows->magnify.shape=MagickFalse;
15032 width=(unsigned int) display_image->columns;
15033 height=(unsigned int) display_image->rows;
15034 if ((display_image->columns != width) || (display_image->rows != height))
15035 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15036 display_image->filename);
15037 status=XMakeImage(display,resource_info,&windows->image,display_image,
cristy051718b2011-08-28 22:49:25 +000015038 width,height,exception);
cristy3ed852e2009-09-05 21:47:34 +000015039 if (status == MagickFalse)
15040 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15041 display_image->filename);
15042 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
cristy051718b2011-08-28 22:49:25 +000015043 windows->magnify.width,windows->magnify.height,exception);
cristy3ed852e2009-09-05 21:47:34 +000015044 if (status == MagickFalse)
15045 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15046 display_image->filename);
15047 if (windows->magnify.mapped != MagickFalse)
15048 (void) XMapRaised(display,windows->magnify.id);
15049 if (windows->pan.mapped != MagickFalse)
15050 (void) XMapRaised(display,windows->pan.id);
15051 windows->image.window_changes.width=(int) display_image->columns;
15052 windows->image.window_changes.height=(int) display_image->rows;
cristy051718b2011-08-28 22:49:25 +000015053 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015054 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15055 (void) XSync(display,MagickFalse);
15056 /*
15057 Respond to events.
15058 */
15059 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15060 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15061 update_time=0;
15062 if (resource_info->update != MagickFalse)
15063 {
15064 MagickBooleanType
15065 status;
15066
15067 /*
15068 Determine when file data was last modified.
15069 */
15070 status=GetPathAttributes(display_image->filename,&attributes);
15071 if (status != MagickFalse)
15072 update_time=attributes.st_mtime;
15073 }
15074 *state&=(~FormerImageState);
15075 *state&=(~MontageImageState);
15076 *state&=(~NextImageState);
15077 do
15078 {
15079 /*
15080 Handle a window event.
15081 */
15082 if (windows->image.mapped != MagickFalse)
15083 if ((display_image->delay != 0) || (resource_info->update != 0))
15084 {
15085 if (timer < time((time_t *) NULL))
15086 {
15087 if (resource_info->update == MagickFalse)
15088 *state|=NextImageState | ExitState;
15089 else
15090 {
15091 MagickBooleanType
15092 status;
15093
15094 /*
15095 Determine if image file was modified.
15096 */
15097 status=GetPathAttributes(display_image->filename,&attributes);
15098 if (status != MagickFalse)
15099 if (update_time != attributes.st_mtime)
15100 {
15101 /*
15102 Redisplay image.
15103 */
cristyb51dff52011-05-19 16:55:47 +000015104 (void) FormatLocaleString(
cristy3ed852e2009-09-05 21:47:34 +000015105 resource_info->image_info->filename,MaxTextExtent,
15106 "%s:%s",display_image->magick,
15107 display_image->filename);
cristy947cb4c2011-10-20 18:41:46 +000015108 nexus=ReadImage(resource_info->image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000015109 if (nexus != (Image *) NULL)
15110 {
15111 nexus=DestroyImage(nexus);
15112 *state|=NextImageState | ExitState;
15113 }
15114 }
15115 delay=display_image->delay/MagickMax(
15116 display_image->ticks_per_second,1L);
15117 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15118 }
15119 }
15120 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15121 {
15122 /*
15123 Do not block if delay > 0.
15124 */
15125 XDelay(display,SuspendTime << 2);
15126 continue;
15127 }
15128 }
15129 timestamp=time((time_t *) NULL);
15130 (void) XNextEvent(display,&event);
15131 if (windows->image.stasis == MagickFalse)
15132 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15133 MagickTrue : MagickFalse;
15134 if (windows->magnify.stasis == MagickFalse)
15135 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15136 MagickTrue : MagickFalse;
15137 if (event.xany.window == windows->command.id)
15138 {
15139 /*
15140 Select a command from the Command widget.
15141 */
15142 id=XCommandWidget(display,windows,CommandMenu,&event);
15143 if (id < 0)
15144 continue;
15145 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15146 command_type=CommandMenus[id];
15147 if (id < MagickMenus)
15148 {
15149 /*
15150 Select a command from a pop-up menu.
15151 */
15152 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15153 command);
15154 if (entry < 0)
15155 continue;
15156 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15157 command_type=Commands[id][entry];
15158 }
15159 if (command_type != NullCommand)
15160 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015161 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015162 continue;
15163 }
15164 switch (event.type)
15165 {
15166 case ButtonPress:
15167 {
15168 if (display_image->debug != MagickFalse)
15169 (void) LogMagickEvent(X11Event,GetMagickModule(),
15170 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15171 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15172 if ((event.xbutton.button == Button3) &&
15173 (event.xbutton.state & Mod1Mask))
15174 {
15175 /*
15176 Convert Alt-Button3 to Button2.
15177 */
15178 event.xbutton.button=Button2;
15179 event.xbutton.state&=(~Mod1Mask);
15180 }
15181 if (event.xbutton.window == windows->backdrop.id)
15182 {
15183 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15184 event.xbutton.time);
15185 break;
15186 }
15187 if (event.xbutton.window == windows->image.id)
15188 {
15189 switch (event.xbutton.button)
15190 {
15191 case Button1:
15192 {
15193 if (resource_info->immutable)
15194 {
15195 /*
15196 Select a command from the Virtual menu.
15197 */
15198 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15199 command);
15200 if (entry >= 0)
15201 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015202 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015203 break;
15204 }
15205 /*
15206 Map/unmap Command widget.
15207 */
15208 if (windows->command.mapped != MagickFalse)
15209 (void) XWithdrawWindow(display,windows->command.id,
15210 windows->command.screen);
15211 else
15212 {
15213 (void) XCommandWidget(display,windows,CommandMenu,
15214 (XEvent *) NULL);
15215 (void) XMapRaised(display,windows->command.id);
15216 }
15217 break;
15218 }
15219 case Button2:
15220 {
15221 /*
15222 User pressed the image magnify button.
15223 */
15224 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
cristy051718b2011-08-28 22:49:25 +000015225 &display_image,exception);
cristy6710d842011-10-20 23:23:00 +000015226 XMagnifyImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015227 break;
15228 }
15229 case Button3:
15230 {
15231 if (resource_info->immutable)
15232 {
15233 /*
15234 Select a command from the Virtual menu.
15235 */
15236 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15237 command);
15238 if (entry >= 0)
15239 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015240 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015241 break;
15242 }
15243 if (display_image->montage != (char *) NULL)
15244 {
15245 /*
15246 Open or delete a tile from a visual image directory.
15247 */
15248 nexus=XTileImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015249 display_image,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015250 if (nexus != (Image *) NULL)
15251 *state|=MontageImageState | NextImageState | ExitState;
cristy49e2d862010-11-12 02:50:30 +000015252 vid_info.x=(short int) windows->image.x;
15253 vid_info.y=(short int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +000015254 break;
15255 }
15256 /*
15257 Select a command from the Short Cuts menu.
15258 */
15259 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15260 command);
15261 if (entry >= 0)
15262 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015263 ShortCutsCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015264 break;
15265 }
15266 case Button4:
15267 {
15268 /*
15269 Wheel up.
15270 */
15271 XTranslateImage(display,windows,*image,XK_Up);
15272 break;
15273 }
15274 case Button5:
15275 {
15276 /*
15277 Wheel down.
15278 */
15279 XTranslateImage(display,windows,*image,XK_Down);
15280 break;
15281 }
15282 default:
15283 break;
15284 }
15285 break;
15286 }
15287 if (event.xbutton.window == windows->magnify.id)
15288 {
15289 int
15290 factor;
15291
15292 static const char
15293 *MagnifyMenu[] =
15294 {
15295 "2",
15296 "4",
15297 "5",
15298 "6",
15299 "7",
15300 "8",
15301 "9",
15302 "3",
15303 (char *) NULL,
15304 };
15305
15306 static KeySym
15307 MagnifyCommands[] =
15308 {
15309 XK_2,
15310 XK_4,
15311 XK_5,
15312 XK_6,
15313 XK_7,
15314 XK_8,
15315 XK_9,
15316 XK_3
15317 };
15318
15319 /*
15320 Select a magnify factor from the pop-up menu.
15321 */
15322 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15323 if (factor >= 0)
cristy6710d842011-10-20 23:23:00 +000015324 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15325 exception);
cristy3ed852e2009-09-05 21:47:34 +000015326 break;
15327 }
15328 if (event.xbutton.window == windows->pan.id)
15329 {
15330 switch (event.xbutton.button)
15331 {
15332 case Button4:
15333 {
15334 /*
15335 Wheel up.
15336 */
15337 XTranslateImage(display,windows,*image,XK_Up);
15338 break;
15339 }
15340 case Button5:
15341 {
15342 /*
15343 Wheel down.
15344 */
15345 XTranslateImage(display,windows,*image,XK_Down);
15346 break;
15347 }
15348 default:
15349 {
cristy6710d842011-10-20 23:23:00 +000015350 XPanImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015351 break;
15352 }
15353 }
15354 break;
15355 }
15356 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15357 1L);
15358 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15359 break;
15360 }
15361 case ButtonRelease:
15362 {
15363 if (display_image->debug != MagickFalse)
15364 (void) LogMagickEvent(X11Event,GetMagickModule(),
15365 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15366 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15367 break;
15368 }
15369 case ClientMessage:
15370 {
15371 if (display_image->debug != MagickFalse)
15372 (void) LogMagickEvent(X11Event,GetMagickModule(),
15373 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
cristyf2faecf2010-05-28 19:19:36 +000015374 event.xclient.message_type,event.xclient.format,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015375 event.xclient.data.l[0]);
15376 if (event.xclient.message_type == windows->im_protocols)
15377 {
cristyecd0ab52010-05-30 14:59:20 +000015378 if (*event.xclient.data.l == (long) windows->im_update_widget)
cristy3ed852e2009-09-05 21:47:34 +000015379 {
15380 (void) CloneString(&windows->command.name,MagickTitle);
15381 windows->command.data=MagickMenus;
15382 (void) XCommandWidget(display,windows,CommandMenu,
15383 (XEvent *) NULL);
15384 break;
15385 }
cristyecd0ab52010-05-30 14:59:20 +000015386 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +000015387 {
15388 /*
15389 Update graphic context and window colormap.
15390 */
15391 for (i=0; i < (int) number_windows; i++)
15392 {
15393 if (magick_windows[i]->id == windows->icon.id)
15394 continue;
15395 context_values.background=pixel->background_color.pixel;
15396 context_values.foreground=pixel->foreground_color.pixel;
15397 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15398 context_mask,&context_values);
15399 (void) XChangeGC(display,magick_windows[i]->widget_context,
15400 context_mask,&context_values);
15401 context_values.background=pixel->foreground_color.pixel;
15402 context_values.foreground=pixel->background_color.pixel;
15403 context_values.plane_mask=context_values.background ^
15404 context_values.foreground;
15405 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +000015406 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +000015407 &context_values);
15408 magick_windows[i]->attributes.background_pixel=
15409 pixel->background_color.pixel;
15410 magick_windows[i]->attributes.border_pixel=
15411 pixel->border_color.pixel;
15412 magick_windows[i]->attributes.colormap=map_info->colormap;
15413 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
cristy49e2d862010-11-12 02:50:30 +000015414 (unsigned long) magick_windows[i]->mask,
15415 &magick_windows[i]->attributes);
cristy3ed852e2009-09-05 21:47:34 +000015416 }
15417 if (windows->pan.mapped != MagickFalse)
15418 {
15419 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15420 windows->pan.pixmap);
15421 (void) XClearWindow(display,windows->pan.id);
15422 XDrawPanRectangle(display,windows);
15423 }
15424 if (windows->backdrop.id != (Window) NULL)
15425 (void) XInstallColormap(display,map_info->colormap);
15426 break;
15427 }
cristyecd0ab52010-05-30 14:59:20 +000015428 if (*event.xclient.data.l == (long) windows->im_former_image)
cristy3ed852e2009-09-05 21:47:34 +000015429 {
15430 *state|=FormerImageState | ExitState;
15431 break;
15432 }
cristyecd0ab52010-05-30 14:59:20 +000015433 if (*event.xclient.data.l == (long) windows->im_next_image)
cristy3ed852e2009-09-05 21:47:34 +000015434 {
15435 *state|=NextImageState | ExitState;
15436 break;
15437 }
cristyecd0ab52010-05-30 14:59:20 +000015438 if (*event.xclient.data.l == (long) windows->im_retain_colors)
cristy3ed852e2009-09-05 21:47:34 +000015439 {
15440 *state|=RetainColorsState;
15441 break;
15442 }
cristyecd0ab52010-05-30 14:59:20 +000015443 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +000015444 {
15445 *state|=ExitState;
15446 break;
15447 }
15448 break;
15449 }
15450 if (event.xclient.message_type == windows->dnd_protocols)
15451 {
15452 Atom
15453 selection,
15454 type;
15455
15456 int
15457 format,
15458 status;
15459
15460 unsigned char
15461 *data;
15462
cristyf2faecf2010-05-28 19:19:36 +000015463 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015464 after,
15465 length;
15466
15467 /*
15468 Display image named by the Drag-and-Drop selection.
15469 */
15470 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15471 break;
15472 selection=XInternAtom(display,"DndSelection",MagickFalse);
cristyecd0ab52010-05-30 14:59:20 +000015473 status=XGetWindowProperty(display,root_window,selection,0L,(long)
cristy3ed852e2009-09-05 21:47:34 +000015474 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15475 &length,&after,&data);
15476 if ((status != Success) || (length == 0))
15477 break;
15478 if (*event.xclient.data.l == 2)
15479 {
15480 /*
15481 Offix DND.
15482 */
15483 (void) CopyMagickString(resource_info->image_info->filename,
15484 (char *) data,MaxTextExtent);
15485 }
15486 else
15487 {
15488 /*
15489 XDND.
15490 */
15491 if (strncmp((char *) data, "file:", 5) != 0)
15492 {
15493 (void) XFree((void *) data);
15494 break;
15495 }
15496 (void) CopyMagickString(resource_info->image_info->filename,
15497 ((char *) data)+5,MaxTextExtent);
15498 }
cristy947cb4c2011-10-20 18:41:46 +000015499 nexus=ReadImage(resource_info->image_info,exception);
15500 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015501 if (nexus != (Image *) NULL)
15502 *state|=NextImageState | ExitState;
15503 (void) XFree((void *) data);
15504 break;
15505 }
15506 /*
15507 If client window delete message, exit.
15508 */
15509 if (event.xclient.message_type != windows->wm_protocols)
15510 break;
cristyecd0ab52010-05-30 14:59:20 +000015511 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000015512 break;
15513 (void) XWithdrawWindow(display,event.xclient.window,
15514 visual_info->screen);
15515 if (event.xclient.window == windows->image.id)
15516 {
15517 *state|=ExitState;
15518 break;
15519 }
15520 if (event.xclient.window == windows->pan.id)
15521 {
15522 /*
15523 Restore original image size when pan window is deleted.
15524 */
15525 windows->image.window_changes.width=windows->image.ximage->width;
15526 windows->image.window_changes.height=windows->image.ximage->height;
15527 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015528 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015529 }
15530 break;
15531 }
15532 case ConfigureNotify:
15533 {
15534 if (display_image->debug != MagickFalse)
15535 (void) LogMagickEvent(X11Event,GetMagickModule(),
15536 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15537 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15538 event.xconfigure.y,event.xconfigure.send_event);
15539 if (event.xconfigure.window == windows->image.id)
15540 {
15541 /*
15542 Image window has a new configuration.
15543 */
15544 if (event.xconfigure.send_event != 0)
15545 {
15546 XWindowChanges
15547 window_changes;
15548
15549 /*
15550 Position the transient windows relative of the Image window.
15551 */
15552 if (windows->command.geometry == (char *) NULL)
15553 if (windows->command.mapped == MagickFalse)
15554 {
15555 windows->command.x=event.xconfigure.x-
15556 windows->command.width-25;
15557 windows->command.y=event.xconfigure.y;
15558 XConstrainWindowPosition(display,&windows->command);
15559 window_changes.x=windows->command.x;
15560 window_changes.y=windows->command.y;
15561 (void) XReconfigureWMWindow(display,windows->command.id,
15562 windows->command.screen,(unsigned int) (CWX | CWY),
15563 &window_changes);
15564 }
15565 if (windows->widget.geometry == (char *) NULL)
15566 if (windows->widget.mapped == MagickFalse)
15567 {
15568 windows->widget.x=event.xconfigure.x+
15569 event.xconfigure.width/10;
15570 windows->widget.y=event.xconfigure.y+
15571 event.xconfigure.height/10;
15572 XConstrainWindowPosition(display,&windows->widget);
15573 window_changes.x=windows->widget.x;
15574 window_changes.y=windows->widget.y;
15575 (void) XReconfigureWMWindow(display,windows->widget.id,
15576 windows->widget.screen,(unsigned int) (CWX | CWY),
15577 &window_changes);
15578 }
15579 if (windows->magnify.geometry == (char *) NULL)
15580 if (windows->magnify.mapped == MagickFalse)
15581 {
15582 windows->magnify.x=event.xconfigure.x+
15583 event.xconfigure.width+25;
15584 windows->magnify.y=event.xconfigure.y;
15585 XConstrainWindowPosition(display,&windows->magnify);
15586 window_changes.x=windows->magnify.x;
15587 window_changes.y=windows->magnify.y;
15588 (void) XReconfigureWMWindow(display,windows->magnify.id,
15589 windows->magnify.screen,(unsigned int) (CWX | CWY),
15590 &window_changes);
15591 }
15592 if (windows->pan.geometry == (char *) NULL)
15593 if (windows->pan.mapped == MagickFalse)
15594 {
15595 windows->pan.x=event.xconfigure.x+
15596 event.xconfigure.width+25;
15597 windows->pan.y=event.xconfigure.y+
15598 windows->magnify.height+50;
15599 XConstrainWindowPosition(display,&windows->pan);
15600 window_changes.x=windows->pan.x;
15601 window_changes.y=windows->pan.y;
15602 (void) XReconfigureWMWindow(display,windows->pan.id,
15603 windows->pan.screen,(unsigned int) (CWX | CWY),
15604 &window_changes);
15605 }
15606 }
cristyecd0ab52010-05-30 14:59:20 +000015607 if ((event.xconfigure.width == (int) windows->image.width) &&
15608 (event.xconfigure.height == (int) windows->image.height))
cristy3ed852e2009-09-05 21:47:34 +000015609 break;
15610 windows->image.width=(unsigned int) event.xconfigure.width;
15611 windows->image.height=(unsigned int) event.xconfigure.height;
15612 windows->image.x=0;
15613 windows->image.y=0;
15614 if (display_image->montage != (char *) NULL)
15615 {
15616 windows->image.x=vid_info.x;
15617 windows->image.y=vid_info.y;
15618 }
cristy34b9f452010-01-06 20:04:29 +000015619 if ((windows->image.mapped != MagickFalse) &&
15620 (windows->image.stasis != MagickFalse))
15621 {
15622 /*
15623 Update image window configuration.
15624 */
15625 windows->image.window_changes.width=event.xconfigure.width;
15626 windows->image.window_changes.height=event.xconfigure.height;
15627 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015628 display_image,exception);
cristy34b9f452010-01-06 20:04:29 +000015629 }
cristy3ed852e2009-09-05 21:47:34 +000015630 /*
15631 Update pan window configuration.
15632 */
15633 if ((event.xconfigure.width < windows->image.ximage->width) ||
15634 (event.xconfigure.height < windows->image.ximage->height))
15635 {
15636 (void) XMapRaised(display,windows->pan.id);
15637 XDrawPanRectangle(display,windows);
15638 }
15639 else
15640 if (windows->pan.mapped != MagickFalse)
15641 (void) XWithdrawWindow(display,windows->pan.id,
15642 windows->pan.screen);
15643 break;
15644 }
15645 if (event.xconfigure.window == windows->magnify.id)
15646 {
15647 unsigned int
15648 magnify;
15649
15650 /*
15651 Magnify window has a new configuration.
15652 */
15653 windows->magnify.width=(unsigned int) event.xconfigure.width;
15654 windows->magnify.height=(unsigned int) event.xconfigure.height;
15655 if (windows->magnify.mapped == MagickFalse)
15656 break;
15657 magnify=1;
15658 while ((int) magnify <= event.xconfigure.width)
15659 magnify<<=1;
15660 while ((int) magnify <= event.xconfigure.height)
15661 magnify<<=1;
15662 magnify>>=1;
15663 if (((int) magnify != event.xconfigure.width) ||
15664 ((int) magnify != event.xconfigure.height))
15665 {
15666 window_changes.width=(int) magnify;
15667 window_changes.height=(int) magnify;
15668 (void) XReconfigureWMWindow(display,windows->magnify.id,
15669 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15670 &window_changes);
15671 break;
15672 }
15673 if ((windows->magnify.mapped != MagickFalse) &&
15674 (windows->magnify.stasis != MagickFalse))
15675 {
15676 status=XMakeImage(display,resource_info,&windows->magnify,
cristy051718b2011-08-28 22:49:25 +000015677 display_image,windows->magnify.width,windows->magnify.height,
15678 exception);
cristy6710d842011-10-20 23:23:00 +000015679 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015680 }
15681 break;
15682 }
15683 if ((windows->magnify.mapped != MagickFalse) &&
15684 (event.xconfigure.window == windows->pan.id))
15685 {
15686 /*
15687 Pan icon window has a new configuration.
15688 */
15689 if (event.xconfigure.send_event != 0)
15690 {
15691 windows->pan.x=event.xconfigure.x;
15692 windows->pan.y=event.xconfigure.y;
15693 }
15694 windows->pan.width=(unsigned int) event.xconfigure.width;
15695 windows->pan.height=(unsigned int) event.xconfigure.height;
15696 break;
15697 }
15698 if (event.xconfigure.window == windows->icon.id)
15699 {
15700 /*
15701 Icon window has a new configuration.
15702 */
15703 windows->icon.width=(unsigned int) event.xconfigure.width;
15704 windows->icon.height=(unsigned int) event.xconfigure.height;
15705 break;
15706 }
15707 break;
15708 }
15709 case DestroyNotify:
15710 {
15711 /*
15712 Group leader has exited.
15713 */
15714 if (display_image->debug != MagickFalse)
15715 (void) LogMagickEvent(X11Event,GetMagickModule(),
15716 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15717 if (event.xdestroywindow.window == windows->group_leader.id)
15718 {
15719 *state|=ExitState;
15720 break;
15721 }
15722 break;
15723 }
15724 case EnterNotify:
15725 {
15726 /*
15727 Selectively install colormap.
15728 */
15729 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15730 if (event.xcrossing.mode != NotifyUngrab)
15731 XInstallColormap(display,map_info->colormap);
15732 break;
15733 }
15734 case Expose:
15735 {
15736 if (display_image->debug != MagickFalse)
15737 (void) LogMagickEvent(X11Event,GetMagickModule(),
15738 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15739 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15740 event.xexpose.y);
15741 /*
15742 Refresh windows that are now exposed.
15743 */
cristy6bee4042010-01-30 15:27:14 +000015744 if ((event.xexpose.window == windows->image.id) &&
15745 (windows->image.mapped != MagickFalse))
15746 {
15747 XRefreshWindow(display,&windows->image,&event);
15748 delay=display_image->delay/MagickMax(
15749 display_image->ticks_per_second,1L);
15750 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15751 break;
15752 }
15753 if ((event.xexpose.window == windows->magnify.id) &&
15754 (windows->magnify.mapped != MagickFalse))
15755 {
cristy6710d842011-10-20 23:23:00 +000015756 XMakeMagnifyImage(display,windows,exception);
cristy6bee4042010-01-30 15:27:14 +000015757 break;
15758 }
cristy3ed852e2009-09-05 21:47:34 +000015759 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015760 {
15761 XDrawPanRectangle(display,windows);
15762 break;
15763 }
cristy3ed852e2009-09-05 21:47:34 +000015764 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015765 {
15766 XRefreshWindow(display,&windows->icon,&event);
15767 break;
15768 }
cristy3ed852e2009-09-05 21:47:34 +000015769 break;
15770 }
15771 case KeyPress:
15772 {
15773 int
15774 length;
15775
15776 /*
15777 Respond to a user key press.
15778 */
15779 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15780 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15781 *(command+length)='\0';
15782 if (display_image->debug != MagickFalse)
15783 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015784 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015785 key_symbol,command);
15786 if (event.xkey.window == windows->image.id)
15787 {
15788 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015789 event.xkey.state,key_symbol,&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015790 if (command_type != NullCommand)
15791 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015792 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015793 }
15794 if (event.xkey.window == windows->magnify.id)
cristy6710d842011-10-20 23:23:00 +000015795 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15796 exception);
cristy3ed852e2009-09-05 21:47:34 +000015797 if (event.xkey.window == windows->pan.id)
15798 {
15799 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15800 (void) XWithdrawWindow(display,windows->pan.id,
15801 windows->pan.screen);
15802 else
15803 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15804 XTextViewWidget(display,resource_info,windows,MagickFalse,
15805 "Help Viewer - Image Pan",ImagePanHelp);
15806 else
15807 XTranslateImage(display,windows,*image,key_symbol);
15808 }
15809 delay=display_image->delay/MagickMax(
15810 display_image->ticks_per_second,1L);
15811 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15812 break;
15813 }
15814 case KeyRelease:
15815 {
15816 /*
15817 Respond to a user key release.
15818 */
15819 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15820 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15821 if (display_image->debug != MagickFalse)
15822 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015823 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +000015824 break;
15825 }
15826 case LeaveNotify:
15827 {
15828 /*
15829 Selectively uninstall colormap.
15830 */
15831 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15832 if (event.xcrossing.mode != NotifyUngrab)
15833 XUninstallColormap(display,map_info->colormap);
15834 break;
15835 }
15836 case MapNotify:
15837 {
15838 if (display_image->debug != MagickFalse)
15839 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15840 event.xmap.window);
15841 if (event.xmap.window == windows->backdrop.id)
15842 {
15843 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15844 CurrentTime);
15845 windows->backdrop.mapped=MagickTrue;
15846 break;
15847 }
15848 if (event.xmap.window == windows->image.id)
15849 {
15850 if (windows->backdrop.id != (Window) NULL)
15851 (void) XInstallColormap(display,map_info->colormap);
15852 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15853 {
15854 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15855 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15856 }
15857 if (((int) windows->image.width < windows->image.ximage->width) ||
15858 ((int) windows->image.height < windows->image.ximage->height))
15859 (void) XMapRaised(display,windows->pan.id);
15860 windows->image.mapped=MagickTrue;
15861 break;
15862 }
15863 if (event.xmap.window == windows->magnify.id)
15864 {
cristy6710d842011-10-20 23:23:00 +000015865 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015866 windows->magnify.mapped=MagickTrue;
15867 (void) XWithdrawWindow(display,windows->info.id,
15868 windows->info.screen);
15869 break;
15870 }
15871 if (event.xmap.window == windows->pan.id)
15872 {
cristy051718b2011-08-28 22:49:25 +000015873 XMakePanImage(display,resource_info,windows,display_image,
15874 exception);
cristy3ed852e2009-09-05 21:47:34 +000015875 windows->pan.mapped=MagickTrue;
15876 break;
15877 }
15878 if (event.xmap.window == windows->info.id)
15879 {
15880 windows->info.mapped=MagickTrue;
15881 break;
15882 }
15883 if (event.xmap.window == windows->icon.id)
15884 {
15885 MagickBooleanType
15886 taint;
15887
15888 /*
15889 Create an icon image.
15890 */
15891 taint=display_image->taint;
15892 XMakeStandardColormap(display,icon_visual,icon_resources,
cristy6710d842011-10-20 23:23:00 +000015893 display_image,icon_map,icon_pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000015894 (void) XMakeImage(display,icon_resources,&windows->icon,
cristy051718b2011-08-28 22:49:25 +000015895 display_image,windows->icon.width,windows->icon.height,
15896 exception);
cristy3ed852e2009-09-05 21:47:34 +000015897 display_image->taint=taint;
15898 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15899 windows->icon.pixmap);
15900 (void) XClearWindow(display,windows->icon.id);
15901 (void) XWithdrawWindow(display,windows->info.id,
15902 windows->info.screen);
15903 windows->icon.mapped=MagickTrue;
15904 break;
15905 }
15906 if (event.xmap.window == windows->command.id)
15907 {
15908 windows->command.mapped=MagickTrue;
15909 break;
15910 }
15911 if (event.xmap.window == windows->popup.id)
15912 {
15913 windows->popup.mapped=MagickTrue;
15914 break;
15915 }
15916 if (event.xmap.window == windows->widget.id)
15917 {
15918 windows->widget.mapped=MagickTrue;
15919 break;
15920 }
15921 break;
15922 }
15923 case MappingNotify:
15924 {
15925 (void) XRefreshKeyboardMapping(&event.xmapping);
15926 break;
15927 }
15928 case NoExpose:
15929 break;
15930 case PropertyNotify:
15931 {
15932 Atom
15933 type;
15934
15935 int
15936 format,
15937 status;
15938
15939 unsigned char
15940 *data;
15941
cristyf2faecf2010-05-28 19:19:36 +000015942 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015943 after,
15944 length;
15945
15946 if (display_image->debug != MagickFalse)
15947 (void) LogMagickEvent(X11Event,GetMagickModule(),
15948 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15949 event.xproperty.atom,event.xproperty.state);
15950 if (event.xproperty.atom != windows->im_remote_command)
15951 break;
15952 /*
15953 Display image named by the remote command protocol.
15954 */
15955 status=XGetWindowProperty(display,event.xproperty.window,
cristyecd0ab52010-05-30 14:59:20 +000015956 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +000015957 AnyPropertyType,&type,&format,&length,&after,&data);
15958 if ((status != Success) || (length == 0))
15959 break;
15960 if (LocaleCompare((char *) data,"-quit") == 0)
15961 {
15962 XClientMessage(display,windows->image.id,windows->im_protocols,
15963 windows->im_exit,CurrentTime);
15964 (void) XFree((void *) data);
15965 break;
15966 }
15967 (void) CopyMagickString(resource_info->image_info->filename,
15968 (char *) data,MaxTextExtent);
15969 (void) XFree((void *) data);
cristy947cb4c2011-10-20 18:41:46 +000015970 nexus=ReadImage(resource_info->image_info,exception);
15971 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015972 if (nexus != (Image *) NULL)
15973 *state|=NextImageState | ExitState;
15974 break;
15975 }
15976 case ReparentNotify:
15977 {
15978 if (display_image->debug != MagickFalse)
15979 (void) LogMagickEvent(X11Event,GetMagickModule(),
15980 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15981 event.xreparent.window);
15982 break;
15983 }
15984 case UnmapNotify:
15985 {
15986 if (display_image->debug != MagickFalse)
15987 (void) LogMagickEvent(X11Event,GetMagickModule(),
15988 "Unmap Notify: 0x%lx",event.xunmap.window);
15989 if (event.xunmap.window == windows->backdrop.id)
15990 {
15991 windows->backdrop.mapped=MagickFalse;
15992 break;
15993 }
15994 if (event.xunmap.window == windows->image.id)
15995 {
15996 windows->image.mapped=MagickFalse;
15997 break;
15998 }
15999 if (event.xunmap.window == windows->magnify.id)
16000 {
16001 windows->magnify.mapped=MagickFalse;
16002 break;
16003 }
16004 if (event.xunmap.window == windows->pan.id)
16005 {
16006 windows->pan.mapped=MagickFalse;
16007 break;
16008 }
16009 if (event.xunmap.window == windows->info.id)
16010 {
16011 windows->info.mapped=MagickFalse;
16012 break;
16013 }
16014 if (event.xunmap.window == windows->icon.id)
16015 {
16016 if (map_info->colormap == icon_map->colormap)
16017 XConfigureImageColormap(display,resource_info,windows,
cristy6710d842011-10-20 23:23:00 +000016018 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016019 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16020 icon_pixel);
16021 windows->icon.mapped=MagickFalse;
16022 break;
16023 }
16024 if (event.xunmap.window == windows->command.id)
16025 {
16026 windows->command.mapped=MagickFalse;
16027 break;
16028 }
16029 if (event.xunmap.window == windows->popup.id)
16030 {
16031 if (windows->backdrop.id != (Window) NULL)
16032 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16033 CurrentTime);
16034 windows->popup.mapped=MagickFalse;
16035 break;
16036 }
16037 if (event.xunmap.window == windows->widget.id)
16038 {
16039 if (windows->backdrop.id != (Window) NULL)
16040 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16041 CurrentTime);
16042 windows->widget.mapped=MagickFalse;
16043 break;
16044 }
16045 break;
16046 }
16047 default:
16048 {
16049 if (display_image->debug != MagickFalse)
16050 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16051 event.type);
16052 break;
16053 }
16054 }
16055 } while (!(*state & ExitState));
16056 if ((*state & ExitState) == 0)
16057 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
cristy051718b2011-08-28 22:49:25 +000016058 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016059 else
16060 if (resource_info->confirm_edit != MagickFalse)
16061 {
16062 /*
16063 Query user if image has changed.
16064 */
16065 if ((resource_info->immutable == MagickFalse) &&
16066 (display_image->taint != MagickFalse))
16067 {
16068 int
16069 status;
16070
16071 status=XConfirmWidget(display,windows,"Your image changed.",
16072 "Do you want to save it");
16073 if (status == 0)
16074 *state&=(~ExitState);
16075 else
16076 if (status > 0)
16077 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
cristy051718b2011-08-28 22:49:25 +000016078 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016079 }
16080 }
16081 if ((windows->visual_info->klass == GrayScale) ||
16082 (windows->visual_info->klass == PseudoColor) ||
16083 (windows->visual_info->klass == DirectColor))
16084 {
16085 /*
16086 Withdraw pan and Magnify window.
16087 */
16088 if (windows->info.mapped != MagickFalse)
16089 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16090 if (windows->magnify.mapped != MagickFalse)
16091 (void) XWithdrawWindow(display,windows->magnify.id,
16092 windows->magnify.screen);
16093 if (windows->command.mapped != MagickFalse)
16094 (void) XWithdrawWindow(display,windows->command.id,
16095 windows->command.screen);
16096 }
16097 if (windows->pan.mapped != MagickFalse)
16098 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16099 if (resource_info->backdrop == MagickFalse)
16100 if (windows->backdrop.mapped)
16101 {
16102 (void) XWithdrawWindow(display,windows->backdrop.id,
16103 windows->backdrop.screen);
16104 (void) XDestroyWindow(display,windows->backdrop.id);
16105 windows->backdrop.id=(Window) NULL;
16106 (void) XWithdrawWindow(display,windows->image.id,
16107 windows->image.screen);
16108 (void) XDestroyWindow(display,windows->image.id);
16109 windows->image.id=(Window) NULL;
16110 }
16111 XSetCursorState(display,windows,MagickTrue);
16112 XCheckRefreshWindows(display,windows);
16113 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16114 *state&=(~ExitState);
16115 if (*state & ExitState)
16116 {
16117 /*
16118 Free Standard Colormap.
16119 */
16120 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16121 if (resource_info->map_type == (char *) NULL)
16122 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16123 /*
16124 Free X resources.
16125 */
16126 if (resource_info->copy_image != (Image *) NULL)
16127 {
16128 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16129 resource_info->copy_image=NewImageList();
16130 }
16131 DestroyXResources();
16132 }
16133 (void) XSync(display,MagickFalse);
16134 /*
16135 Restore our progress monitor and warning handlers.
16136 */
16137 (void) SetErrorHandler(warning_handler);
16138 (void) SetWarningHandler(warning_handler);
16139 /*
16140 Change to home directory.
16141 */
cristy00976d82011-02-20 20:31:28 +000016142 directory=getcwd(working_directory,MaxTextExtent);
16143 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +000016144 {
16145 int
16146 status;
16147
16148 status=chdir(resource_info->home_directory);
16149 if (status == -1)
cristy947cb4c2011-10-20 18:41:46 +000016150 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16151 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +000016152 }
16153 *image=display_image;
16154 return(nexus);
16155}
16156#else
16157
16158/*
16159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16160% %
16161% %
16162% %
16163+ D i s p l a y I m a g e s %
16164% %
16165% %
16166% %
16167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16168%
16169% DisplayImages() displays an image sequence to any X window screen. It
16170% returns a value other than 0 if successful. Check the exception member
16171% of image to determine the reason for any failure.
16172%
16173% The format of the DisplayImages method is:
16174%
16175% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016176% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016177%
16178% A description of each parameter follows:
16179%
16180% o image_info: the image info.
16181%
16182% o image: the image.
16183%
cristy051718b2011-08-28 22:49:25 +000016184% o exception: return any errors or warnings in this structure.
16185%
cristy3ed852e2009-09-05 21:47:34 +000016186*/
16187MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016188 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016189{
16190 assert(image_info != (const ImageInfo *) NULL);
16191 assert(image_info->signature == MagickSignature);
16192 assert(image != (Image *) NULL);
16193 assert(image->signature == MagickSignature);
16194 if (image->debug != MagickFalse)
16195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy051718b2011-08-28 22:49:25 +000016196 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16197 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename);
cristy3ed852e2009-09-05 21:47:34 +000016198 return(MagickFalse);
16199}
16200
16201/*
16202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16203% %
16204% %
16205% %
16206+ R e m o t e D i s p l a y C o m m a n d %
16207% %
16208% %
16209% %
16210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16211%
16212% RemoteDisplayCommand() encourages a remote display program to display the
16213% specified image filename.
16214%
16215% The format of the RemoteDisplayCommand method is:
16216%
16217% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16218% const char *window,const char *filename,ExceptionInfo *exception)
16219%
16220% A description of each parameter follows:
16221%
16222% o image_info: the image info.
16223%
16224% o window: Specifies the name or id of an X window.
16225%
16226% o filename: the name of the image filename to display.
16227%
16228% o exception: return any errors or warnings in this structure.
16229%
16230*/
16231MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16232 const char *window,const char *filename,ExceptionInfo *exception)
16233{
16234 assert(image_info != (const ImageInfo *) NULL);
16235 assert(image_info->signature == MagickSignature);
16236 assert(filename != (char *) NULL);
16237 (void) window;
16238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16239 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16240 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16241 return(MagickFalse);
16242}
16243#endif