blob: cca29f2a9a1e5ab6d4706accda9fc509ee1b94b1 [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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"
46#include "MagickCore/client.h"
47#include "MagickCore/color.h"
48#include "MagickCore/colorspace.h"
49#include "MagickCore/composite.h"
50#include "MagickCore/constitute.h"
51#include "MagickCore/decorate.h"
52#include "MagickCore/delegate.h"
53#include "MagickCore/display.h"
54#include "MagickCore/display-private.h"
55#include "MagickCore/draw.h"
56#include "MagickCore/effect.h"
57#include "MagickCore/enhance.h"
58#include "MagickCore/exception.h"
59#include "MagickCore/exception-private.h"
60#include "MagickCore/fx.h"
61#include "MagickCore/geometry.h"
62#include "MagickCore/image.h"
63#include "MagickCore/image-private.h"
64#include "MagickCore/list.h"
65#include "MagickCore/log.h"
66#include "MagickCore/magick.h"
67#include "MagickCore/memory_.h"
68#include "MagickCore/monitor.h"
69#include "MagickCore/monitor-private.h"
70#include "MagickCore/montage.h"
71#include "MagickCore/option.h"
72#include "MagickCore/paint.h"
73#include "MagickCore/pixel.h"
74#include "MagickCore/pixel-accessor.h"
75#include "MagickCore/PreRvIcccm.h"
76#include "MagickCore/property.h"
77#include "MagickCore/quantum.h"
78#include "MagickCore/quantum-private.h"
79#include "MagickCore/resize.h"
80#include "MagickCore/resource_.h"
81#include "MagickCore/shear.h"
82#include "MagickCore/segment.h"
83#include "MagickCore/string_.h"
84#include "MagickCore/string-private.h"
85#include "MagickCore/transform.h"
86#include "MagickCore/threshold.h"
87#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000088#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000089#include "MagickCore/version.h"
90#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000091#include "MagickCore/widget-private.h"
92#include "MagickCore/xwindow.h"
cristy4c08aed2011-07-01 19:47:50 +000093#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000094
95#if defined(MAGICKCORE_X11_DELEGATE)
96/*
97 Define declarations.
98*/
cristy49e2d862010-11-12 02:50:30 +000099#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
cristy3ed852e2009-09-05 21:47:34 +0000100
101/*
102 Constant declarations.
103*/
104static const unsigned char
105 HighlightBitmap[8] =
106 {
107 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
108 },
cristydd05beb2010-11-21 21:23:39 +0000109 OpaqueBitmap[8] =
110 {
111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
112 },
cristy3ed852e2009-09-05 21:47:34 +0000113 ShadowBitmap[8] =
114 {
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
116 };
117
118static const char
119 *PageSizes[] =
120 {
121 "Letter",
122 "Tabloid",
123 "Ledger",
124 "Legal",
125 "Statement",
126 "Executive",
127 "A3",
128 "A4",
129 "A5",
130 "B4",
131 "B5",
132 "Folio",
133 "Quarto",
134 "10x14",
135 (char *) NULL
136 };
137
138/*
139 Help widget declarations.
140*/
141static const char
142 *ImageAnnotateHelp[] =
143 {
144 "In annotate mode, the Command widget has these options:",
145 "",
146 " Font Name",
147 " fixed",
148 " variable",
149 " 5x8",
150 " 6x10",
151 " 7x13bold",
152 " 8x13bold",
153 " 9x15bold",
154 " 10x20",
155 " 12x24",
156 " Browser...",
157 " Font Color",
158 " black",
159 " blue",
160 " cyan",
161 " green",
162 " gray",
163 " red",
164 " magenta",
165 " yellow",
166 " white",
167 " transparent",
168 " Browser...",
169 " Font Color",
170 " black",
171 " blue",
172 " cyan",
173 " green",
174 " gray",
175 " red",
176 " magenta",
177 " yellow",
178 " white",
179 " transparent",
180 " Browser...",
181 " Rotate Text",
182 " -90",
183 " -45",
184 " -30",
185 " 0",
186 " 30",
187 " 45",
188 " 90",
189 " 180",
190 " Dialog...",
191 " Help",
192 " Dismiss",
193 "",
194 "Choose a font name from the Font Name sub-menu. Additional",
195 "font names can be specified with the font browser. You can",
196 "change the menu names by setting the X resources font1",
197 "through font9.",
198 "",
199 "Choose a font color from the Font Color sub-menu.",
200 "Additional font colors can be specified with the color",
201 "browser. You can change the menu colors by setting the X",
202 "resources pen1 through pen9.",
203 "",
204 "If you select the color browser and press Grab, you can",
205 "choose the font color by moving the pointer to the desired",
206 "color on the screen and press any button.",
207 "",
208 "If you choose to rotate the text, choose Rotate Text from the",
209 "menu and select an angle. Typically you will only want to",
210 "rotate one line of text at a time. Depending on the angle you",
211 "choose, subsequent lines may end up overwriting each other.",
212 "",
213 "Choosing a font and its color is optional. The default font",
214 "is fixed and the default color is black. However, you must",
215 "choose a location to begin entering text and press button 1.",
216 "An underscore character will appear at the location of the",
217 "pointer. The cursor changes to a pencil to indicate you are",
218 "in text mode. To exit immediately, press Dismiss.",
219 "",
220 "In text mode, any key presses will display the character at",
221 "the location of the underscore and advance the underscore",
222 "cursor. Enter your text and once completed press Apply to",
223 "finish your image annotation. To correct errors press BACK",
224 "SPACE. To delete an entire line of text, press DELETE. Any",
225 "text that exceeds the boundaries of the image window is",
226 "automagically continued onto the next line.",
227 "",
228 "The actual color you request for the font is saved in the",
229 "image. However, the color that appears in your image window",
230 "may be different. For example, on a monochrome screen the",
231 "text will appear black or white even if you choose the color",
232 "red as the font color. However, the image saved to a file",
233 "with -write is written with red lettering. To assure the",
234 "correct color text in the final image, any PseudoClass image",
235 "is promoted to DirectClass (see miff(5)). To force a",
236 "PseudoClass image to remain PseudoClass, use -colors.",
237 (char *) NULL,
238 },
239 *ImageChopHelp[] =
240 {
241 "In chop mode, the Command widget has these options:",
242 "",
243 " Direction",
244 " horizontal",
245 " vertical",
246 " Help",
247 " Dismiss",
248 "",
249 "If the you choose the horizontal direction (this the",
250 "default), the area of the image between the two horizontal",
251 "endpoints of the chop line is removed. Otherwise, the area",
252 "of the image between the two vertical endpoints of the chop",
253 "line is removed.",
254 "",
255 "Select a location within the image window to begin your chop,",
256 "press and hold any button. Next, move the pointer to",
257 "another location in the image. As you move a line will",
258 "connect the initial location and the pointer. When you",
259 "release the button, the area within the image to chop is",
260 "determined by which direction you choose from the Command",
261 "widget.",
262 "",
263 "To cancel the image chopping, move the pointer back to the",
264 "starting point of the line and release the button.",
265 (char *) NULL,
266 },
267 *ImageColorEditHelp[] =
268 {
269 "In color edit mode, the Command widget has these options:",
270 "",
271 " Method",
272 " point",
273 " replace",
274 " floodfill",
275 " filltoborder",
276 " reset",
277 " Pixel Color",
278 " black",
279 " blue",
280 " cyan",
281 " green",
282 " gray",
283 " red",
284 " magenta",
285 " yellow",
286 " white",
287 " Browser...",
288 " Border Color",
289 " black",
290 " blue",
291 " cyan",
292 " green",
293 " gray",
294 " red",
295 " magenta",
296 " yellow",
297 " white",
298 " Browser...",
299 " Fuzz",
300 " 0%",
301 " 2%",
302 " 5%",
303 " 10%",
304 " 15%",
305 " Dialog...",
306 " Undo",
307 " Help",
308 " Dismiss",
309 "",
310 "Choose a color editing method from the Method sub-menu",
311 "of the Command widget. The point method recolors any pixel",
312 "selected with the pointer until the button is released. The",
313 "replace method recolors any pixel that matches the color of",
314 "the pixel you select with a button press. Floodfill recolors",
315 "any pixel that matches the color of the pixel you select with",
316 "a button press and is a neighbor. Whereas filltoborder recolors",
317 "any neighbor pixel that is not the border color. Finally reset",
318 "changes the entire image to the designated color.",
319 "",
320 "Next, choose a pixel color from the Pixel Color sub-menu.",
321 "Additional pixel colors can be specified with the color",
322 "browser. You can change the menu colors by setting the X",
323 "resources pen1 through pen9.",
324 "",
325 "Now press button 1 to select a pixel within the image window",
326 "to change its color. Additional pixels may be recolored as",
327 "prescribed by the method you choose.",
328 "",
329 "If the Magnify widget is mapped, it can be helpful in positioning",
330 "your pointer within the image (refer to button 2).",
331 "",
332 "The actual color you request for the pixels is saved in the",
333 "image. However, the color that appears in your image window",
334 "may be different. For example, on a monochrome screen the",
335 "pixel will appear black or white even if you choose the",
336 "color red as the pixel color. However, the image saved to a",
337 "file with -write is written with red pixels. To assure the",
338 "correct color text in the final image, any PseudoClass image",
339 "is promoted to DirectClass (see miff(5)). To force a",
340 "PseudoClass image to remain PseudoClass, use -colors.",
341 (char *) NULL,
342 },
343 *ImageCompositeHelp[] =
344 {
345 "First a widget window is displayed requesting you to enter an",
346 "image name. Press Composite, Grab or type a file name.",
347 "Press Cancel if you choose not to create a composite image.",
348 "When you choose Grab, move the pointer to the desired window",
349 "and press any button.",
350 "",
351 "If the Composite image does not have any matte information,",
352 "you are informed and the file browser is displayed again.",
353 "Enter the name of a mask image. The image is typically",
354 "grayscale and the same size as the composite image. If the",
355 "image is not grayscale, it is converted to grayscale and the",
356 "resulting intensities are used as matte information.",
357 "",
358 "A small window appears showing the location of the cursor in",
359 "the image window. You are now in composite mode. To exit",
360 "immediately, press Dismiss. In composite mode, the Command",
361 "widget has these options:",
362 "",
363 " Operators",
364 " Over",
365 " In",
366 " Out",
367 " Atop",
368 " Xor",
369 " Plus",
370 " Minus",
371 " Add",
372 " Subtract",
373 " Difference",
374 " Multiply",
375 " Bumpmap",
376 " Copy",
377 " CopyRed",
378 " CopyGreen",
379 " CopyBlue",
380 " CopyOpacity",
381 " Clear",
382 " Dissolve",
383 " Displace",
384 " Help",
385 " Dismiss",
386 "",
387 "Choose a composite operation from the Operators sub-menu of",
388 "the Command widget. How each operator behaves is described",
389 "below. Image window is the image currently displayed on",
390 "your X server and image is the image obtained with the File",
391 "Browser widget.",
392 "",
393 "Over The result is the union of the two image shapes,",
394 " with image obscuring image window in the region of",
395 " overlap.",
396 "",
397 "In The result is simply image cut by the shape of",
398 " image window. None of the image data of image",
399 " window is in the result.",
400 "",
401 "Out The resulting image is image with the shape of",
402 " image window cut out.",
403 "",
404 "Atop The result is the same shape as image image window,",
405 " with image obscuring image window where the image",
406 " shapes overlap. Note this differs from over",
407 " because the portion of image outside image window's",
408 " shape does not appear in the result.",
409 "",
410 "Xor The result is the image data from both image and",
411 " image window that is outside the overlap region.",
412 " The overlap region is blank.",
413 "",
414 "Plus The result is just the sum of the image data.",
415 " Output values are cropped to QuantumRange (no overflow).",
416 "",
417 "Minus The result of image - image window, with underflow",
418 " cropped to zero.",
419 "",
420 "Add The result of image + image window, with overflow",
421 " wrapping around (mod 256).",
422 "",
423 "Subtract The result of image - image window, with underflow",
424 " wrapping around (mod 256). The add and subtract",
425 " operators can be used to perform reversible",
426 " transformations.",
427 "",
428 "Difference",
429 " The result of abs(image - image window). This",
430 " useful for comparing two very similar images.",
431 "",
432 "Multiply",
433 " The result of image * image window. This",
434 " useful for the creation of drop-shadows.",
435 "",
436 "Bumpmap The result of surface normals from image * image",
437 " window.",
438 "",
439 "Copy The resulting image is image window replaced with",
440 " image. Here the matte information is ignored.",
441 "",
442 "CopyRed The red layer of the image window is replace with",
443 " the red layer of the image. The other layers are",
444 " untouched.",
445 "",
446 "CopyGreen",
447 " The green layer of the image window is replace with",
448 " the green layer of the image. The other layers are",
449 " untouched.",
450 "",
451 "CopyBlue The blue layer of the image window is replace with",
452 " the blue layer of the image. The other layers are",
453 " untouched.",
454 "",
455 "CopyOpacity",
456 " The matte layer of the image window is replace with",
457 " the matte layer of the image. The other layers are",
458 " untouched.",
459 "",
460 "The image compositor requires a matte, or alpha channel in",
461 "the image for some operations. This extra channel usually",
462 "defines a mask which represents a sort of a cookie-cutter",
463 "for the image. This the case when matte is opaque (full",
464 "coverage) for pixels inside the shape, zero outside, and",
465 "between 0 and QuantumRange on the boundary. If image does not",
466 "have a matte channel, it is initialized with 0 for any pixel",
467 "matching in color to pixel location (0,0), otherwise QuantumRange.",
468 "",
469 "If you choose Dissolve, the composite operator becomes Over. The",
470 "image matte channel percent transparency is initialized to factor.",
471 "The image window is initialized to (100-factor). Where factor is the",
472 "value you specify in the Dialog widget.",
473 "",
474 "Displace shifts the image pixels as defined by a displacement",
475 "map. With this option, image is used as a displacement map.",
476 "Black, within the displacement map, is a maximum positive",
477 "displacement. White is a maximum negative displacement and",
478 "middle gray is neutral. The displacement is scaled to determine",
479 "the pixel shift. By default, the displacement applies in both the",
480 "horizontal and vertical directions. However, if you specify a mask,",
481 "image is the horizontal X displacement and mask the vertical Y",
482 "displacement.",
483 "",
484 "Note that matte information for image window is not retained",
485 "for colormapped X server visuals (e.g. StaticColor,",
486 "StaticColor, GrayScale, PseudoColor). Correct compositing",
487 "behavior may require a TrueColor or DirectColor visual or a",
488 "Standard Colormap.",
489 "",
490 "Choosing a composite operator is optional. The default",
491 "operator is replace. However, you must choose a location to",
492 "composite your image and press button 1. Press and hold the",
493 "button before releasing and an outline of the image will",
494 "appear to help you identify your location.",
495 "",
496 "The actual colors of the composite image is saved. However,",
497 "the color that appears in image window may be different.",
498 "For example, on a monochrome screen image window will appear",
499 "black or white even though your composited image may have",
500 "many colors. If the image is saved to a file it is written",
501 "with the correct colors. To assure the correct colors are",
502 "saved in the final image, any PseudoClass image is promoted",
503 "to DirectClass (see miff(5)). To force a PseudoClass image",
504 "to remain PseudoClass, use -colors.",
505 (char *) NULL,
506 },
507 *ImageCutHelp[] =
508 {
509 "In cut mode, the Command widget has these options:",
510 "",
511 " Help",
512 " Dismiss",
513 "",
514 "To define a cut region, press button 1 and drag. The",
515 "cut region is defined by a highlighted rectangle that",
516 "expands or contracts as it follows the pointer. Once you",
517 "are satisfied with the cut region, release the button.",
518 "You are now in rectify mode. In rectify mode, the Command",
519 "widget has these options:",
520 "",
521 " Cut",
522 " Help",
523 " Dismiss",
524 "",
525 "You can make adjustments by moving the pointer to one of the",
526 "cut rectangle corners, pressing a button, and dragging.",
527 "Finally, press Cut to commit your copy region. To",
528 "exit without cutting the image, press Dismiss.",
529 (char *) NULL,
530 },
531 *ImageCopyHelp[] =
532 {
533 "In copy mode, the Command widget has these options:",
534 "",
535 " Help",
536 " Dismiss",
537 "",
538 "To define a copy region, press button 1 and drag. The",
539 "copy region is defined by a highlighted rectangle that",
540 "expands or contracts as it follows the pointer. Once you",
541 "are satisfied with the copy region, release the button.",
542 "You are now in rectify mode. In rectify mode, the Command",
543 "widget has these options:",
544 "",
545 " Copy",
546 " Help",
547 " Dismiss",
548 "",
549 "You can make adjustments by moving the pointer to one of the",
550 "copy rectangle corners, pressing a button, and dragging.",
551 "Finally, press Copy to commit your copy region. To",
552 "exit without copying the image, press Dismiss.",
553 (char *) NULL,
554 },
555 *ImageCropHelp[] =
556 {
557 "In crop mode, the Command widget has these options:",
558 "",
559 " Help",
560 " Dismiss",
561 "",
562 "To define a cropping region, press button 1 and drag. The",
563 "cropping region is defined by a highlighted rectangle that",
564 "expands or contracts as it follows the pointer. Once you",
565 "are satisfied with the cropping region, release the button.",
566 "You are now in rectify mode. In rectify mode, the Command",
567 "widget has these options:",
568 "",
569 " Crop",
570 " Help",
571 " Dismiss",
572 "",
573 "You can make adjustments by moving the pointer to one of the",
574 "cropping rectangle corners, pressing a button, and dragging.",
575 "Finally, press Crop to commit your cropping region. To",
576 "exit without cropping the image, press Dismiss.",
577 (char *) NULL,
578 },
579 *ImageDrawHelp[] =
580 {
581 "The cursor changes to a crosshair to indicate you are in",
582 "draw mode. To exit immediately, press Dismiss. In draw mode,",
583 "the Command widget has these options:",
584 "",
585 " Element",
586 " point",
587 " line",
588 " rectangle",
589 " fill rectangle",
590 " circle",
591 " fill circle",
592 " ellipse",
593 " fill ellipse",
594 " polygon",
595 " fill polygon",
596 " Color",
597 " black",
598 " blue",
599 " cyan",
600 " green",
601 " gray",
602 " red",
603 " magenta",
604 " yellow",
605 " white",
606 " transparent",
607 " Browser...",
608 " Stipple",
609 " Brick",
610 " Diagonal",
611 " Scales",
612 " Vertical",
613 " Wavy",
614 " Translucent",
615 " Opaque",
616 " Open...",
617 " Width",
618 " 1",
619 " 2",
620 " 4",
621 " 8",
622 " 16",
623 " Dialog...",
624 " Undo",
625 " Help",
626 " Dismiss",
627 "",
628 "Choose a drawing primitive from the Element sub-menu.",
629 "",
630 "Choose a color from the Color sub-menu. Additional",
631 "colors can be specified with the color browser.",
632 "",
633 "If you choose the color browser and press Grab, you can",
634 "select the color by moving the pointer to the desired",
635 "color on the screen and press any button. The transparent",
636 "color updates the image matte channel and is useful for",
637 "image compositing.",
638 "",
639 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
640 "Additional stipples can be specified with the file browser.",
641 "Stipples obtained from the file browser must be on disk in the",
642 "X11 bitmap format.",
643 "",
644 "Choose a width, if appropriate, from the Width sub-menu. To",
645 "choose a specific width select the Dialog widget.",
646 "",
647 "Choose a point in the Image window and press button 1 and",
648 "hold. Next, move the pointer to another location in the",
649 "image. As you move, a line connects the initial location and",
650 "the pointer. When you release the button, the image is",
651 "updated with the primitive you just drew. For polygons, the",
652 "image is updated when you press and release the button without",
653 "moving the pointer.",
654 "",
655 "To cancel image drawing, move the pointer back to the",
656 "starting point of the line and release the button.",
657 (char *) NULL,
658 },
659 *DisplayHelp[] =
660 {
661 "BUTTONS",
662 " The effects of each button press is described below. Three",
663 " buttons are required. If you have a two button mouse,",
664 " button 1 and 3 are returned. Press ALT and button 3 to",
665 " simulate button 2.",
666 "",
667 " 1 Press this button to map or unmap the Command widget.",
668 "",
669 " 2 Press and drag to define a region of the image to",
670 " magnify.",
671 "",
672 " 3 Press and drag to choose from a select set of commands.",
673 " This button behaves differently if the image being",
674 " displayed is a visual image directory. Here, choose a",
675 " particular tile of the directory and press this button and",
676 " drag to select a command from a pop-up menu. Choose from",
677 " these menu items:",
678 "",
679 " Open",
680 " Next",
681 " Former",
682 " Delete",
683 " Update",
684 "",
685 " If you choose Open, the image represented by the tile is",
686 " displayed. To return to the visual image directory, choose",
687 " Next from the Command widget. Next and Former moves to the",
688 " next or former image respectively. Choose Delete to delete",
689 " a particular image tile. Finally, choose Update to",
690 " synchronize all the image tiles with their respective",
691 " images.",
692 "",
693 "COMMAND WIDGET",
694 " The Command widget lists a number of sub-menus and commands.",
695 " They are",
696 "",
697 " File",
698 " Open...",
699 " Next",
700 " Former",
701 " Select...",
702 " Save...",
703 " Print...",
704 " Delete...",
705 " New...",
706 " Visual Directory...",
707 " Quit",
708 " Edit",
709 " Undo",
710 " Redo",
711 " Cut",
712 " Copy",
713 " Paste",
714 " View",
715 " Half Size",
716 " Original Size",
717 " Double Size",
718 " Resize...",
719 " Apply",
720 " Refresh",
721 " Restore",
722 " Transform",
723 " Crop",
724 " Chop",
725 " Flop",
726 " Flip",
727 " Rotate Right",
728 " Rotate Left",
729 " Rotate...",
730 " Shear...",
731 " Roll...",
732 " Trim Edges",
733 " Enhance",
734 " Brightness...",
735 " Saturation...",
736 " Hue...",
737 " Gamma...",
738 " Sharpen...",
739 " Dull",
740 " Contrast Stretch...",
741 " Sigmoidal Contrast...",
742 " Normalize",
743 " Equalize",
744 " Negate",
745 " Grayscale",
746 " Map...",
747 " Quantize...",
748 " Effects",
749 " Despeckle",
750 " Emboss",
751 " Reduce Noise",
752 " Add Noise",
753 " Sharpen...",
754 " Blur...",
755 " Threshold...",
756 " Edge Detect...",
757 " Spread...",
758 " Shade...",
759 " Painting...",
760 " Segment...",
761 " F/X",
762 " Solarize...",
763 " Sepia Tone...",
764 " Swirl...",
765 " Implode...",
766 " Vignette...",
767 " Wave...",
768 " Oil Painting...",
769 " Charcoal Drawing...",
770 " Image Edit",
771 " Annotate...",
772 " Draw...",
773 " Color...",
774 " Matte...",
775 " Composite...",
776 " Add Border...",
777 " Add Frame...",
778 " Comment...",
779 " Launch...",
780 " Region of Interest...",
781 " Miscellany",
782 " Image Info",
783 " Zoom Image",
784 " Show Preview...",
785 " Show Histogram",
786 " Show Matte",
787 " Background...",
788 " Slide Show",
789 " Preferences...",
790 " Help",
791 " Overview",
792 " Browse Documentation",
793 " About Display",
794 "",
795 " Menu items with a indented triangle have a sub-menu. They",
796 " are represented above as the indented items. To access a",
797 " sub-menu item, move the pointer to the appropriate menu and",
798 " press a button and drag. When you find the desired sub-menu",
799 " item, release the button and the command is executed. Move",
800 " the pointer away from the sub-menu if you decide not to",
801 " execute a particular command.",
802 "",
803 "KEYBOARD ACCELERATORS",
804 " Accelerators are one or two key presses that effect a",
805 " particular command. The keyboard accelerators that",
806 " display(1) understands is:",
807 "",
808 " Ctl+O Press to open an image from a file.",
809 "",
810 " space Press to display the next image.",
811 "",
812 " If the image is a multi-paged document such as a Postscript",
813 " document, you can skip ahead several pages by preceding",
814 " this command with a number. For example to display the",
815 " third page beyond the current page, press 3<space>.",
816 "",
817 " backspace Press to display the former image.",
818 "",
819 " If the image is a multi-paged document such as a Postscript",
820 " document, you can skip behind several pages by preceding",
821 " this command with a number. For example to display the",
822 " third page preceding the current page, press 3<backspace>.",
823 "",
824 " Ctl+S Press to write the image to a file.",
825 "",
826 " Ctl+P Press to print the image to a Postscript printer.",
827 "",
828 " Ctl+D Press to delete an image file.",
829 "",
830 " Ctl+N Press to create a blank canvas.",
831 "",
832 " Ctl+Q Press to discard all images and exit program.",
833 "",
834 " Ctl+Z Press to undo last image transformation.",
835 "",
836 " Ctl+R Press to redo last image transformation.",
837 "",
838 " Ctl+X Press to cut a region of the image.",
839 "",
840 " Ctl+C Press to copy a region of the image.",
841 "",
842 " Ctl+V Press to paste a region to the image.",
843 "",
844 " < Press to half the image size.",
845 "",
846 " - Press to return to the original image size.",
847 "",
848 " > Press to double the image size.",
849 "",
850 " % Press to resize the image to a width and height you",
851 " specify.",
852 "",
853 "Cmd-A Press to make any image transformations permanent."
854 "",
855 " By default, any image size transformations are applied",
856 " to the original image to create the image displayed on",
857 " the X server. However, the transformations are not",
858 " permanent (i.e. the original image does not change",
859 " size only the X image does). For example, if you",
860 " press > the X image will appear to double in size,",
861 " but the original image will in fact remain the same size.",
862 " To force the original image to double in size, press >",
863 " followed by Cmd-A.",
864 "",
865 " @ Press to refresh the image window.",
866 "",
867 " C Press to cut out a rectangular region of the image.",
868 "",
869 " [ Press to chop the image.",
870 "",
871 " H Press to flop image in the horizontal direction.",
872 "",
873 " V Press to flip image in the vertical direction.",
874 "",
875 " / Press to rotate the image 90 degrees clockwise.",
876 "",
877 " \\ Press to rotate the image 90 degrees counter-clockwise.",
878 "",
879 " * Press to rotate the image the number of degrees you",
880 " specify.",
881 "",
882 " S Press to shear the image the number of degrees you",
883 " specify.",
884 "",
885 " R Press to roll the image.",
886 "",
887 " T Press to trim the image edges.",
888 "",
889 " Shft-H Press to vary the image hue.",
890 "",
891 " Shft-S Press to vary the color saturation.",
892 "",
893 " Shft-L Press to vary the color brightness.",
894 "",
895 " Shft-G Press to gamma correct the image.",
896 "",
897 " Shft-C Press to sharpen the image contrast.",
898 "",
899 " Shft-Z Press to dull the image contrast.",
900 "",
901 " = Press to perform histogram equalization on the image.",
902 "",
903 " Shft-N Press to perform histogram normalization on the image.",
904 "",
905 " Shft-~ Press to negate the colors of the image.",
906 "",
907 " . Press to convert the image colors to gray.",
908 "",
909 " Shft-# Press to set the maximum number of unique colors in the",
910 " image.",
911 "",
912 " F2 Press to reduce the speckles in an image.",
913 "",
914 " F3 Press to eliminate peak noise from an image.",
915 "",
916 " F4 Press to add noise to an image.",
917 "",
918 " F5 Press to sharpen an image.",
919 "",
920 " F6 Press to delete an image file.",
921 "",
922 " F7 Press to threshold the image.",
923 "",
924 " F8 Press to detect edges within an image.",
925 "",
926 " F9 Press to emboss an image.",
927 "",
928 " F10 Press to displace pixels by a random amount.",
929 "",
930 " F11 Press to negate all pixels above the threshold level.",
931 "",
932 " F12 Press to shade the image using a distant light source.",
933 "",
934 " F13 Press to lighten or darken image edges to create a 3-D effect.",
935 "",
936 " F14 Press to segment the image by color.",
937 "",
938 " Meta-S Press to swirl image pixels about the center.",
939 "",
940 " Meta-I Press to implode image pixels about the center.",
941 "",
cristycee97112010-05-28 00:44:52 +0000942 " Meta-W Press to alter an image along a sine wave.",
cristy3ed852e2009-09-05 21:47:34 +0000943 "",
944 " Meta-P Press to simulate an oil painting.",
945 "",
946 " Meta-C Press to simulate a charcoal drawing.",
947 "",
948 " Alt-A Press to annotate the image with text.",
949 "",
950 " Alt-D Press to draw on an image.",
951 "",
952 " Alt-P Press to edit an image pixel color.",
953 "",
954 " Alt-M Press to edit the image matte information.",
955 "",
956 " Alt-V Press to composite the image with another.",
957 "",
958 " Alt-B Press to add a border to the image.",
959 "",
960 " Alt-F Press to add an ornamental border to the image.",
961 "",
962 " Alt-Shft-!",
963 " Press to add an image comment.",
964 "",
965 " Ctl-A Press to apply image processing techniques to a region",
966 " of interest.",
967 "",
968 " Shft-? Press to display information about the image.",
969 "",
970 " Shft-+ Press to map the zoom image window.",
971 "",
972 " Shft-P Press to preview an image enhancement, effect, or f/x.",
973 "",
974 " F1 Press to display helpful information about display(1).",
975 "",
976 " Find Press to browse documentation about ImageMagick.",
977 "",
978 " 1-9 Press to change the level of magnification.",
979 "",
980 " Use the arrow keys to move the image one pixel up, down,",
981 " left, or right within the magnify window. Be sure to first",
982 " map the magnify window by pressing button 2.",
983 "",
984 " Press ALT and one of the arrow keys to trim off one pixel",
985 " from any side of the image.",
986 (char *) NULL,
987 },
988 *ImageMatteEditHelp[] =
989 {
990 "Matte information within an image is useful for some",
991 "operations such as image compositing (See IMAGE",
992 "COMPOSITING). This extra channel usually defines a mask",
993 "which represents a sort of a cookie-cutter for the image.",
994 "This the case when matte is opaque (full coverage) for",
995 "pixels inside the shape, zero outside, and between 0 and",
996 "QuantumRange on the boundary.",
997 "",
998 "A small window appears showing the location of the cursor in",
999 "the image window. You are now in matte edit mode. To exit",
1000 "immediately, press Dismiss. In matte edit mode, the Command",
1001 "widget has these options:",
1002 "",
1003 " Method",
1004 " point",
1005 " replace",
1006 " floodfill",
1007 " filltoborder",
1008 " reset",
1009 " Border Color",
1010 " black",
1011 " blue",
1012 " cyan",
1013 " green",
1014 " gray",
1015 " red",
1016 " magenta",
1017 " yellow",
1018 " white",
1019 " Browser...",
1020 " Fuzz",
1021 " 0%",
1022 " 2%",
1023 " 5%",
1024 " 10%",
1025 " 15%",
1026 " Dialog...",
1027 " Matte",
1028 " Opaque",
1029 " Transparent",
1030 " Dialog...",
1031 " Undo",
1032 " Help",
1033 " Dismiss",
1034 "",
1035 "Choose a matte editing method from the Method sub-menu of",
1036 "the Command widget. The point method changes the matte value",
1037 "of any pixel selected with the pointer until the button is",
1038 "is released. The replace method changes the matte value of",
1039 "any pixel that matches the color of the pixel you select with",
1040 "a button press. Floodfill changes the matte value of any pixel",
1041 "that matches the color of the pixel you select with a button",
1042 "press and is a neighbor. Whereas filltoborder changes the matte",
1043 "value any neighbor pixel that is not the border color. Finally",
1044 "reset changes the entire image to the designated matte value.",
1045 "",
1046 "Choose Matte Value and pick Opaque or Transarent. For other values",
1047 "select the Dialog entry. Here a dialog appears requesting a matte",
1048 "value. The value you select is assigned as the opacity value of the",
1049 "selected pixel or pixels.",
1050 "",
1051 "Now, press any button to select a pixel within the image",
1052 "window to change its matte value.",
1053 "",
1054 "If the Magnify widget is mapped, it can be helpful in positioning",
1055 "your pointer within the image (refer to button 2).",
1056 "",
1057 "Matte information is only valid in a DirectClass image.",
1058 "Therefore, any PseudoClass image is promoted to DirectClass",
1059 "(see miff(5)). Note that matte information for PseudoClass",
1060 "is not retained for colormapped X server visuals (e.g.",
1061 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1062 "immediately save your image to a file (refer to Write).",
1063 "Correct matte editing behavior may require a TrueColor or",
1064 "DirectColor visual or a Standard Colormap.",
1065 (char *) NULL,
1066 },
1067 *ImagePanHelp[] =
1068 {
1069 "When an image exceeds the width or height of the X server",
1070 "screen, display maps a small panning icon. The rectangle",
1071 "within the panning icon shows the area that is currently",
1072 "displayed in the image window. To pan about the image,",
1073 "press any button and drag the pointer within the panning",
1074 "icon. The pan rectangle moves with the pointer and the",
1075 "image window is updated to reflect the location of the",
1076 "rectangle within the panning icon. When you have selected",
1077 "the area of the image you wish to view, release the button.",
1078 "",
1079 "Use the arrow keys to pan the image one pixel up, down,",
1080 "left, or right within the image window.",
1081 "",
1082 "The panning icon is withdrawn if the image becomes smaller",
1083 "than the dimensions of the X server screen.",
1084 (char *) NULL,
1085 },
1086 *ImagePasteHelp[] =
1087 {
1088 "A small window appears showing the location of the cursor in",
1089 "the image window. You are now in paste mode. To exit",
1090 "immediately, press Dismiss. In paste mode, the Command",
1091 "widget has these options:",
1092 "",
1093 " Operators",
1094 " over",
1095 " in",
1096 " out",
1097 " atop",
1098 " xor",
1099 " plus",
1100 " minus",
1101 " add",
1102 " subtract",
1103 " difference",
1104 " replace",
1105 " Help",
1106 " Dismiss",
1107 "",
1108 "Choose a composite operation from the Operators sub-menu of",
1109 "the Command widget. How each operator behaves is described",
1110 "below. Image window is the image currently displayed on",
1111 "your X server and image is the image obtained with the File",
1112 "Browser widget.",
1113 "",
1114 "Over The result is the union of the two image shapes,",
1115 " with image obscuring image window in the region of",
1116 " overlap.",
1117 "",
1118 "In The result is simply image cut by the shape of",
1119 " image window. None of the image data of image",
1120 " window is in the result.",
1121 "",
1122 "Out The resulting image is image with the shape of",
1123 " image window cut out.",
1124 "",
1125 "Atop The result is the same shape as image image window,",
1126 " with image obscuring image window where the image",
1127 " shapes overlap. Note this differs from over",
1128 " because the portion of image outside image window's",
1129 " shape does not appear in the result.",
1130 "",
1131 "Xor The result is the image data from both image and",
1132 " image window that is outside the overlap region.",
1133 " The overlap region is blank.",
1134 "",
1135 "Plus The result is just the sum of the image data.",
1136 " Output values are cropped to QuantumRange (no overflow).",
1137 " This operation is independent of the matte",
1138 " channels.",
1139 "",
1140 "Minus The result of image - image window, with underflow",
1141 " cropped to zero.",
1142 "",
1143 "Add The result of image + image window, with overflow",
1144 " wrapping around (mod 256).",
1145 "",
1146 "Subtract The result of image - image window, with underflow",
1147 " wrapping around (mod 256). The add and subtract",
1148 " operators can be used to perform reversible",
1149 " transformations.",
1150 "",
1151 "Difference",
1152 " The result of abs(image - image window). This",
1153 " useful for comparing two very similar images.",
1154 "",
1155 "Copy The resulting image is image window replaced with",
1156 " image. Here the matte information is ignored.",
1157 "",
1158 "CopyRed The red layer of the image window is replace with",
1159 " the red layer of the image. The other layers are",
1160 " untouched.",
1161 "",
1162 "CopyGreen",
1163 " The green layer of the image window is replace with",
1164 " the green layer of the image. The other layers are",
1165 " untouched.",
1166 "",
1167 "CopyBlue The blue layer of the image window is replace with",
1168 " the blue layer of the image. The other layers are",
1169 " untouched.",
1170 "",
1171 "CopyOpacity",
1172 " The matte layer of the image window is replace with",
1173 " the matte layer of the image. The other layers are",
1174 " untouched.",
1175 "",
1176 "The image compositor requires a matte, or alpha channel in",
1177 "the image for some operations. This extra channel usually",
1178 "defines a mask which represents a sort of a cookie-cutter",
1179 "for the image. This the case when matte is opaque (full",
1180 "coverage) for pixels inside the shape, zero outside, and",
1181 "between 0 and QuantumRange on the boundary. If image does not",
1182 "have a matte channel, it is initialized with 0 for any pixel",
1183 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1184 "",
1185 "Note that matte information for image window is not retained",
1186 "for colormapped X server visuals (e.g. StaticColor,",
1187 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1188 "behavior may require a TrueColor or DirectColor visual or a",
1189 "Standard Colormap.",
1190 "",
1191 "Choosing a composite operator is optional. The default",
1192 "operator is replace. However, you must choose a location to",
1193 "paste your image and press button 1. Press and hold the",
1194 "button before releasing and an outline of the image will",
1195 "appear to help you identify your location.",
1196 "",
1197 "The actual colors of the pasted image is saved. However,",
1198 "the color that appears in image window may be different.",
1199 "For example, on a monochrome screen image window will appear",
1200 "black or white even though your pasted image may have",
1201 "many colors. If the image is saved to a file it is written",
1202 "with the correct colors. To assure the correct colors are",
1203 "saved in the final image, any PseudoClass image is promoted",
1204 "to DirectClass (see miff(5)). To force a PseudoClass image",
1205 "to remain PseudoClass, use -colors.",
1206 (char *) NULL,
1207 },
1208 *ImageROIHelp[] =
1209 {
1210 "In region of interest mode, the Command widget has these",
1211 "options:",
1212 "",
1213 " Help",
1214 " Dismiss",
1215 "",
1216 "To define a region of interest, press button 1 and drag.",
1217 "The region of interest is defined by a highlighted rectangle",
1218 "that expands or contracts as it follows the pointer. Once",
1219 "you are satisfied with the region of interest, release the",
1220 "button. You are now in apply mode. In apply mode the",
1221 "Command widget has these options:",
1222 "",
1223 " File",
1224 " Save...",
1225 " Print...",
1226 " Edit",
1227 " Undo",
1228 " Redo",
1229 " Transform",
1230 " Flop",
1231 " Flip",
1232 " Rotate Right",
1233 " Rotate Left",
1234 " Enhance",
1235 " Hue...",
1236 " Saturation...",
1237 " Brightness...",
1238 " Gamma...",
1239 " Spiff",
1240 " Dull",
1241 " Contrast Stretch",
1242 " Sigmoidal Contrast...",
1243 " Normalize",
1244 " Equalize",
1245 " Negate",
1246 " Grayscale",
1247 " Map...",
1248 " Quantize...",
1249 " Effects",
1250 " Despeckle",
1251 " Emboss",
1252 " Reduce Noise",
1253 " Sharpen...",
1254 " Blur...",
1255 " Threshold...",
1256 " Edge Detect...",
1257 " Spread...",
1258 " Shade...",
1259 " Raise...",
1260 " Segment...",
1261 " F/X",
1262 " Solarize...",
1263 " Sepia Tone...",
1264 " Swirl...",
1265 " Implode...",
1266 " Vignette...",
1267 " Wave...",
1268 " Oil Painting...",
1269 " Charcoal Drawing...",
1270 " Miscellany",
1271 " Image Info",
1272 " Zoom Image",
1273 " Show Preview...",
1274 " Show Histogram",
1275 " Show Matte",
1276 " Help",
1277 " Dismiss",
1278 "",
1279 "You can make adjustments to the region of interest by moving",
1280 "the pointer to one of the rectangle corners, pressing a",
1281 "button, and dragging. Finally, choose an image processing",
1282 "technique from the Command widget. You can choose more than",
1283 "one image processing technique to apply to an area.",
1284 "Alternatively, you can move the region of interest before",
1285 "applying another image processing technique. To exit, press",
1286 "Dismiss.",
1287 (char *) NULL,
1288 },
1289 *ImageRotateHelp[] =
1290 {
1291 "In rotate mode, the Command widget has these options:",
1292 "",
1293 " Pixel Color",
1294 " black",
1295 " blue",
1296 " cyan",
1297 " green",
1298 " gray",
1299 " red",
1300 " magenta",
1301 " yellow",
1302 " white",
1303 " Browser...",
1304 " Direction",
1305 " horizontal",
1306 " vertical",
1307 " Help",
1308 " Dismiss",
1309 "",
1310 "Choose a background color from the Pixel Color sub-menu.",
1311 "Additional background colors can be specified with the color",
1312 "browser. You can change the menu colors by setting the X",
1313 "resources pen1 through pen9.",
1314 "",
1315 "If you choose the color browser and press Grab, you can",
1316 "select the background color by moving the pointer to the",
1317 "desired color on the screen and press any button.",
1318 "",
1319 "Choose a point in the image window and press this button and",
1320 "hold. Next, move the pointer to another location in the",
1321 "image. As you move a line connects the initial location and",
1322 "the pointer. When you release the button, the degree of",
1323 "image rotation is determined by the slope of the line you",
1324 "just drew. The slope is relative to the direction you",
1325 "choose from the Direction sub-menu of the Command widget.",
1326 "",
1327 "To cancel the image rotation, move the pointer back to the",
1328 "starting point of the line and release the button.",
1329 (char *) NULL,
1330 };
1331
1332/*
1333 Enumeration declarations.
1334*/
1335typedef enum
1336{
1337 CopyMode,
1338 CropMode,
1339 CutMode
1340} ClipboardMode;
1341
1342typedef enum
1343{
1344 OpenCommand,
1345 NextCommand,
1346 FormerCommand,
1347 SelectCommand,
1348 SaveCommand,
1349 PrintCommand,
1350 DeleteCommand,
1351 NewCommand,
1352 VisualDirectoryCommand,
1353 QuitCommand,
1354 UndoCommand,
1355 RedoCommand,
1356 CutCommand,
1357 CopyCommand,
1358 PasteCommand,
1359 HalfSizeCommand,
1360 OriginalSizeCommand,
1361 DoubleSizeCommand,
1362 ResizeCommand,
1363 ApplyCommand,
1364 RefreshCommand,
1365 RestoreCommand,
1366 CropCommand,
1367 ChopCommand,
1368 FlopCommand,
1369 FlipCommand,
1370 RotateRightCommand,
1371 RotateLeftCommand,
1372 RotateCommand,
1373 ShearCommand,
1374 RollCommand,
1375 TrimCommand,
1376 HueCommand,
1377 SaturationCommand,
1378 BrightnessCommand,
1379 GammaCommand,
1380 SpiffCommand,
1381 DullCommand,
1382 ContrastStretchCommand,
1383 SigmoidalContrastCommand,
1384 NormalizeCommand,
1385 EqualizeCommand,
1386 NegateCommand,
1387 GrayscaleCommand,
1388 MapCommand,
1389 QuantizeCommand,
1390 DespeckleCommand,
1391 EmbossCommand,
1392 ReduceNoiseCommand,
1393 AddNoiseCommand,
1394 SharpenCommand,
1395 BlurCommand,
1396 ThresholdCommand,
1397 EdgeDetectCommand,
1398 SpreadCommand,
1399 ShadeCommand,
1400 RaiseCommand,
1401 SegmentCommand,
1402 SolarizeCommand,
1403 SepiaToneCommand,
1404 SwirlCommand,
1405 ImplodeCommand,
1406 VignetteCommand,
1407 WaveCommand,
1408 OilPaintCommand,
1409 CharcoalDrawCommand,
1410 AnnotateCommand,
1411 DrawCommand,
1412 ColorCommand,
1413 MatteCommand,
1414 CompositeCommand,
1415 AddBorderCommand,
1416 AddFrameCommand,
1417 CommentCommand,
1418 LaunchCommand,
1419 RegionofInterestCommand,
1420 ROIHelpCommand,
1421 ROIDismissCommand,
1422 InfoCommand,
1423 ZoomCommand,
1424 ShowPreviewCommand,
1425 ShowHistogramCommand,
1426 ShowMatteCommand,
1427 BackgroundCommand,
1428 SlideShowCommand,
1429 PreferencesCommand,
1430 HelpCommand,
1431 BrowseDocumentationCommand,
1432 VersionCommand,
1433 SaveToUndoBufferCommand,
1434 FreeBuffersCommand,
1435 NullCommand
1436} CommandType;
1437
1438typedef enum
1439{
1440 AnnotateNameCommand,
1441 AnnotateFontColorCommand,
1442 AnnotateBackgroundColorCommand,
1443 AnnotateRotateCommand,
1444 AnnotateHelpCommand,
1445 AnnotateDismissCommand,
1446 TextHelpCommand,
1447 TextApplyCommand,
1448 ChopDirectionCommand,
1449 ChopHelpCommand,
1450 ChopDismissCommand,
1451 HorizontalChopCommand,
1452 VerticalChopCommand,
1453 ColorEditMethodCommand,
1454 ColorEditColorCommand,
1455 ColorEditBorderCommand,
1456 ColorEditFuzzCommand,
1457 ColorEditUndoCommand,
1458 ColorEditHelpCommand,
1459 ColorEditDismissCommand,
1460 CompositeOperatorsCommand,
1461 CompositeDissolveCommand,
1462 CompositeDisplaceCommand,
1463 CompositeHelpCommand,
1464 CompositeDismissCommand,
1465 CropHelpCommand,
1466 CropDismissCommand,
1467 RectifyCopyCommand,
1468 RectifyHelpCommand,
1469 RectifyDismissCommand,
1470 DrawElementCommand,
1471 DrawColorCommand,
1472 DrawStippleCommand,
1473 DrawWidthCommand,
1474 DrawUndoCommand,
1475 DrawHelpCommand,
1476 DrawDismissCommand,
1477 MatteEditMethod,
1478 MatteEditBorderCommand,
1479 MatteEditFuzzCommand,
1480 MatteEditValueCommand,
1481 MatteEditUndoCommand,
1482 MatteEditHelpCommand,
1483 MatteEditDismissCommand,
1484 PasteOperatorsCommand,
1485 PasteHelpCommand,
1486 PasteDismissCommand,
1487 RotateColorCommand,
1488 RotateDirectionCommand,
1489 RotateCropCommand,
1490 RotateSharpenCommand,
1491 RotateHelpCommand,
1492 RotateDismissCommand,
1493 HorizontalRotateCommand,
1494 VerticalRotateCommand,
1495 TileLoadCommand,
1496 TileNextCommand,
1497 TileFormerCommand,
1498 TileDeleteCommand,
1499 TileUpdateCommand
1500} ModeType;
1501
1502/*
1503 Stipples.
1504*/
1505#define BricksWidth 20
1506#define BricksHeight 20
1507#define DiagonalWidth 16
1508#define DiagonalHeight 16
1509#define HighlightWidth 8
1510#define HighlightHeight 8
cristydd05beb2010-11-21 21:23:39 +00001511#define OpaqueWidth 8
1512#define OpaqueHeight 8
cristy3ed852e2009-09-05 21:47:34 +00001513#define ScalesWidth 16
1514#define ScalesHeight 16
1515#define ShadowWidth 8
1516#define ShadowHeight 8
1517#define VerticalWidth 16
1518#define VerticalHeight 16
1519#define WavyWidth 16
1520#define WavyHeight 16
1521
1522/*
1523 Constant declaration.
1524*/
1525static const int
1526 RoiDelta = 8;
1527
1528static const unsigned char
1529 BricksBitmap[] =
1530 {
1531 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1532 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1533 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1534 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1535 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1536 },
1537 DiagonalBitmap[] =
1538 {
1539 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1540 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1541 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1542 },
1543 ScalesBitmap[] =
1544 {
1545 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1546 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1547 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1548 },
1549 VerticalBitmap[] =
1550 {
1551 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1552 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1554 },
1555 WavyBitmap[] =
1556 {
1557 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1558 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1559 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1560 };
1561
1562/*
1563 Function prototypes.
1564*/
1565static CommandType
1566 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
cristy051718b2011-08-28 22:49:25 +00001567 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001568
1569static Image
1570 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
cristy051718b2011-08-28 22:49:25 +00001571 Image **,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001572 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
cristy051718b2011-08-28 22:49:25 +00001573 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1574 ExceptionInfo *),
1575 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1576 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001577
1578static MagickBooleanType
cristy051718b2011-08-28 22:49:25 +00001579 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1580 ExceptionInfo *),
1581 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1582 ExceptionInfo *),
1583 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1584 ExceptionInfo *),
1585 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1586 ExceptionInfo *),
1587 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1588 ExceptionInfo *),
1589 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1590 ExceptionInfo *),
1591 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1592 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1593 ExceptionInfo *),
1594 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1595 ExceptionInfo *),
1596 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1597 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1598 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1599 ExceptionInfo *),
1600 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1601 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1602 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001603
1604static void
1605 XDrawPanRectangle(Display *,XWindows *),
cristy051718b2011-08-28 22:49:25 +00001606 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1607 ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001608 XMagnifyImage(Display *,XWindows *,XEvent *),
cristy051718b2011-08-28 22:49:25 +00001609 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001610 XPanImage(Display *,XWindows *,XEvent *),
1611 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1612 const KeySym),
1613 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1614 XScreenEvent(Display *,XWindows *,XEvent *),
1615 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1616
1617/*
1618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619% %
1620% %
1621% %
1622% D i s p l a y I m a g e s %
1623% %
1624% %
1625% %
1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627%
1628% DisplayImages() displays an image sequence to any X window screen. It
1629% returns a value other than 0 if successful. Check the exception member
1630% of image to determine the reason for any failure.
1631%
1632% The format of the DisplayImages method is:
1633%
1634% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001635% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001636%
1637% A description of each parameter follows:
1638%
1639% o image_info: the image info.
1640%
1641% o image: the image.
1642%
cristy051718b2011-08-28 22:49:25 +00001643% o exception: return any errors or warnings in this structure.
1644%
cristy3ed852e2009-09-05 21:47:34 +00001645*/
1646MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001647 Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001648{
1649 char
1650 *argv[1];
1651
1652 Display
1653 *display;
1654
1655 Image
1656 *image;
1657
cristybb503372010-05-27 20:51:26 +00001658 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001659 i;
1660
cristybb503372010-05-27 20:51:26 +00001661 size_t
cristy3ed852e2009-09-05 21:47:34 +00001662 state;
1663
1664 XrmDatabase
1665 resource_database;
1666
1667 XResourceInfo
1668 resource_info;
1669
1670 assert(image_info != (const ImageInfo *) NULL);
1671 assert(image_info->signature == MagickSignature);
1672 assert(images != (Image *) NULL);
1673 assert(images->signature == MagickSignature);
1674 if (images->debug != MagickFalse)
1675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1676 display=XOpenDisplay(image_info->server_name);
1677 if (display == (Display *) NULL)
1678 {
cristy051718b2011-08-28 22:49:25 +00001679 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1680 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001681 return(MagickFalse);
1682 }
cristy051718b2011-08-28 22:49:25 +00001683 if (exception->severity != UndefinedException)
1684 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00001685 (void) XSetErrorHandler(XError);
1686 resource_database=XGetResourceDatabase(display,GetClientName());
1687 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1688 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1689 if (image_info->page != (char *) NULL)
1690 resource_info.image_geometry=AcquireString(image_info->page);
1691 resource_info.immutable=MagickTrue;
1692 argv[0]=AcquireString(GetClientName());
1693 state=DefaultState;
1694 for (i=0; (state & ExitState) == 0; i++)
1695 {
cristybb503372010-05-27 20:51:26 +00001696 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
cristy3ed852e2009-09-05 21:47:34 +00001697 break;
1698 image=GetImageFromList(images,i % GetImageListLength(images));
cristy051718b2011-08-28 22:49:25 +00001699 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00001700 }
cristy01cdc902011-08-31 01:05:44 +00001701 SetErrorHandler((ErrorHandler) NULL);
1702 SetWarningHandler((WarningHandler) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001703 argv[0]=DestroyString(argv[0]);
1704 (void) XCloseDisplay(display);
1705 XDestroyResourceInfo(&resource_info);
cristy051718b2011-08-28 22:49:25 +00001706 if (exception->severity != UndefinedException)
cristy3ed852e2009-09-05 21:47:34 +00001707 return(MagickFalse);
1708 return(MagickTrue);
1709}
1710
1711/*
1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713% %
1714% %
1715% %
1716% R e m o t e D i s p l a y C o m m a n d %
1717% %
1718% %
1719% %
1720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1721%
1722% RemoteDisplayCommand() encourages a remote display program to display the
1723% specified image filename.
1724%
1725% The format of the RemoteDisplayCommand method is:
1726%
1727% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1728% const char *window,const char *filename,ExceptionInfo *exception)
1729%
1730% A description of each parameter follows:
1731%
1732% o image_info: the image info.
1733%
1734% o window: Specifies the name or id of an X window.
1735%
1736% o filename: the name of the image filename to display.
1737%
1738% o exception: return any errors or warnings in this structure.
1739%
1740*/
1741MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1742 const char *window,const char *filename,ExceptionInfo *exception)
1743{
1744 Display
1745 *display;
1746
1747 MagickStatusType
1748 status;
1749
1750 assert(image_info != (const ImageInfo *) NULL);
1751 assert(image_info->signature == MagickSignature);
1752 assert(filename != (char *) NULL);
1753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1754 display=XOpenDisplay(image_info->server_name);
1755 if (display == (Display *) NULL)
1756 {
1757 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1758 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1759 return(MagickFalse);
1760 }
1761 (void) XSetErrorHandler(XError);
1762 status=XRemoteCommand(display,window,filename);
1763 (void) XCloseDisplay(display);
1764 return(status != 0 ? MagickTrue : MagickFalse);
1765}
1766
1767/*
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769% %
1770% %
1771% %
1772+ X A n n o t a t e E d i t I m a g e %
1773% %
1774% %
1775% %
1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777%
1778% XAnnotateEditImage() annotates the image with text.
1779%
1780% The format of the XAnnotateEditImage method is:
1781%
1782% MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001783% XResourceInfo *resource_info,XWindows *windows,Image *image,
1784% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% A description of each parameter follows:
1787%
1788% o display: Specifies a connection to an X server; returned from
1789% XOpenDisplay.
1790%
1791% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1792%
1793% o windows: Specifies a pointer to a XWindows structure.
1794%
1795% o image: the image; returned from ReadImage.
1796%
1797*/
1798
cristybb503372010-05-27 20:51:26 +00001799static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001800{
1801 if (x > y)
1802 return(x);
1803 return(y);
1804}
1805
cristybb503372010-05-27 20:51:26 +00001806static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001807{
1808 if (x < y)
1809 return(x);
1810 return(y);
1811}
1812
1813static MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001814 XResourceInfo *resource_info,XWindows *windows,Image *image,
1815 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001816{
1817 static const char
1818 *AnnotateMenu[] =
1819 {
1820 "Font Name",
1821 "Font Color",
1822 "Box Color",
1823 "Rotate Text",
1824 "Help",
1825 "Dismiss",
1826 (char *) NULL
1827 },
1828 *TextMenu[] =
1829 {
1830 "Help",
1831 "Apply",
1832 (char *) NULL
1833 };
1834
1835 static const ModeType
1836 AnnotateCommands[] =
1837 {
1838 AnnotateNameCommand,
1839 AnnotateFontColorCommand,
1840 AnnotateBackgroundColorCommand,
1841 AnnotateRotateCommand,
1842 AnnotateHelpCommand,
1843 AnnotateDismissCommand
1844 },
1845 TextCommands[] =
1846 {
1847 TextHelpCommand,
1848 TextApplyCommand
1849 };
1850
1851 static MagickBooleanType
1852 transparent_box = MagickTrue,
1853 transparent_pen = MagickFalse;
1854
1855 static MagickRealType
1856 degrees = 0.0;
1857
1858 static unsigned int
1859 box_id = MaxNumberPens-2,
1860 font_id = 0,
1861 pen_id = 0;
1862
1863 char
1864 command[MaxTextExtent],
1865 text[MaxTextExtent];
1866
1867 const char
1868 *ColorMenu[MaxNumberPens+1];
1869
1870 Cursor
1871 cursor;
1872
1873 GC
1874 annotate_context;
1875
1876 int
1877 id,
1878 pen_number,
1879 status,
1880 x,
1881 y;
1882
1883 KeySym
1884 key_symbol;
1885
1886 register char
1887 *p;
1888
cristybb503372010-05-27 20:51:26 +00001889 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001890 i;
1891
1892 unsigned int
1893 height,
1894 width;
1895
cristybb503372010-05-27 20:51:26 +00001896 size_t
cristy3ed852e2009-09-05 21:47:34 +00001897 state;
1898
1899 XAnnotateInfo
1900 *annotate_info,
1901 *previous_info;
1902
1903 XColor
1904 color;
1905
1906 XFontStruct
1907 *font_info;
1908
1909 XEvent
1910 event,
1911 text_event;
1912
1913 /*
1914 Map Command widget.
1915 */
1916 (void) CloneString(&windows->command.name,"Annotate");
1917 windows->command.data=4;
1918 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1919 (void) XMapRaised(display,windows->command.id);
1920 XClientMessage(display,windows->image.id,windows->im_protocols,
1921 windows->im_update_widget,CurrentTime);
1922 /*
1923 Track pointer until button 1 is pressed.
1924 */
1925 XQueryPosition(display,windows->image.id,&x,&y);
1926 (void) XSelectInput(display,windows->image.id,
1927 windows->image.attributes.event_mask | PointerMotionMask);
1928 cursor=XCreateFontCursor(display,XC_left_side);
1929 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1930 state=DefaultState;
1931 do
1932 {
1933 if (windows->info.mapped != MagickFalse)
1934 {
1935 /*
1936 Display pointer position.
1937 */
cristyb51dff52011-05-19 16:55:47 +00001938 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00001939 x+windows->image.x,y+windows->image.y);
1940 XInfoWidget(display,windows,text);
1941 }
1942 /*
1943 Wait for next event.
1944 */
1945 XScreenEvent(display,windows,&event);
1946 if (event.xany.window == windows->command.id)
1947 {
1948 /*
1949 Select a command from the Command widget.
1950 */
1951 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1952 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1953 if (id < 0)
1954 continue;
1955 switch (AnnotateCommands[id])
1956 {
1957 case AnnotateNameCommand:
1958 {
1959 const char
1960 *FontMenu[MaxNumberFonts];
1961
1962 int
1963 font_number;
1964
1965 /*
1966 Initialize menu selections.
1967 */
1968 for (i=0; i < MaxNumberFonts; i++)
1969 FontMenu[i]=resource_info->font_name[i];
1970 FontMenu[MaxNumberFonts-2]="Browser...";
1971 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1972 /*
1973 Select a font name from the pop-up menu.
1974 */
1975 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1976 (const char **) FontMenu,command);
1977 if (font_number < 0)
1978 break;
1979 if (font_number == (MaxNumberFonts-2))
1980 {
1981 static char
1982 font_name[MaxTextExtent] = "fixed";
1983
1984 /*
1985 Select a font name from a browser.
1986 */
1987 resource_info->font_name[font_number]=font_name;
1988 XFontBrowserWidget(display,windows,"Select",font_name);
1989 if (*font_name == '\0')
1990 break;
1991 }
1992 /*
1993 Initialize font info.
1994 */
1995 font_info=XLoadQueryFont(display,resource_info->font_name[
1996 font_number]);
1997 if (font_info == (XFontStruct *) NULL)
1998 {
1999 XNoticeWidget(display,windows,"Unable to load font:",
2000 resource_info->font_name[font_number]);
2001 break;
2002 }
2003 font_id=(unsigned int) font_number;
2004 (void) XFreeFont(display,font_info);
2005 break;
2006 }
2007 case AnnotateFontColorCommand:
2008 {
2009 /*
2010 Initialize menu selections.
2011 */
2012 for (i=0; i < (int) (MaxNumberPens-2); i++)
2013 ColorMenu[i]=resource_info->pen_colors[i];
2014 ColorMenu[MaxNumberPens-2]="transparent";
2015 ColorMenu[MaxNumberPens-1]="Browser...";
2016 ColorMenu[MaxNumberPens]=(const char *) NULL;
2017 /*
2018 Select a pen color from the pop-up menu.
2019 */
2020 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2021 (const char **) ColorMenu,command);
2022 if (pen_number < 0)
2023 break;
2024 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2025 MagickFalse;
2026 if (transparent_pen != MagickFalse)
2027 break;
2028 if (pen_number == (MaxNumberPens-1))
2029 {
2030 static char
2031 color_name[MaxTextExtent] = "gray";
2032
2033 /*
2034 Select a pen color from a dialog.
2035 */
2036 resource_info->pen_colors[pen_number]=color_name;
2037 XColorBrowserWidget(display,windows,"Select",color_name);
2038 if (*color_name == '\0')
2039 break;
2040 }
2041 /*
2042 Set pen color.
2043 */
2044 (void) XParseColor(display,windows->map_info->colormap,
2045 resource_info->pen_colors[pen_number],&color);
2046 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2047 (unsigned int) MaxColors,&color);
2048 windows->pixel_info->pen_colors[pen_number]=color;
2049 pen_id=(unsigned int) pen_number;
2050 break;
2051 }
2052 case AnnotateBackgroundColorCommand:
2053 {
2054 /*
2055 Initialize menu selections.
2056 */
2057 for (i=0; i < (int) (MaxNumberPens-2); i++)
2058 ColorMenu[i]=resource_info->pen_colors[i];
2059 ColorMenu[MaxNumberPens-2]="transparent";
2060 ColorMenu[MaxNumberPens-1]="Browser...";
2061 ColorMenu[MaxNumberPens]=(const char *) NULL;
2062 /*
2063 Select a pen color from the pop-up menu.
2064 */
2065 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2066 (const char **) ColorMenu,command);
2067 if (pen_number < 0)
2068 break;
2069 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2070 MagickFalse;
2071 if (transparent_box != MagickFalse)
2072 break;
2073 if (pen_number == (MaxNumberPens-1))
2074 {
2075 static char
2076 color_name[MaxTextExtent] = "gray";
2077
2078 /*
2079 Select a pen color from a dialog.
2080 */
2081 resource_info->pen_colors[pen_number]=color_name;
2082 XColorBrowserWidget(display,windows,"Select",color_name);
2083 if (*color_name == '\0')
2084 break;
2085 }
2086 /*
2087 Set pen color.
2088 */
2089 (void) XParseColor(display,windows->map_info->colormap,
2090 resource_info->pen_colors[pen_number],&color);
2091 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2092 (unsigned int) MaxColors,&color);
2093 windows->pixel_info->pen_colors[pen_number]=color;
2094 box_id=(unsigned int) pen_number;
2095 break;
2096 }
2097 case AnnotateRotateCommand:
2098 {
2099 int
2100 entry;
2101
2102 static char
2103 angle[MaxTextExtent] = "30.0";
2104
2105 static const char
2106 *RotateMenu[] =
2107 {
2108 "-90",
2109 "-45",
2110 "-30",
2111 "0",
2112 "30",
2113 "45",
2114 "90",
2115 "180",
2116 "Dialog...",
2117 (char *) NULL,
2118 };
2119
2120 /*
2121 Select a command from the pop-up menu.
2122 */
2123 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2124 command);
2125 if (entry < 0)
2126 break;
2127 if (entry != 8)
2128 {
cristyc1acd842011-05-19 23:05:47 +00002129 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002130 break;
2131 }
2132 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2133 angle);
2134 if (*angle == '\0')
2135 break;
cristyc1acd842011-05-19 23:05:47 +00002136 degrees=InterpretLocaleValue(angle,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002137 break;
2138 }
2139 case AnnotateHelpCommand:
2140 {
2141 XTextViewWidget(display,resource_info,windows,MagickFalse,
2142 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2143 break;
2144 }
2145 case AnnotateDismissCommand:
2146 {
2147 /*
2148 Prematurely exit.
2149 */
2150 state|=EscapeState;
2151 state|=ExitState;
2152 break;
2153 }
2154 default:
2155 break;
2156 }
2157 continue;
2158 }
2159 switch (event.type)
2160 {
2161 case ButtonPress:
2162 {
2163 if (event.xbutton.button != Button1)
2164 break;
2165 if (event.xbutton.window != windows->image.id)
2166 break;
2167 /*
2168 Change to text entering mode.
2169 */
2170 x=event.xbutton.x;
2171 y=event.xbutton.y;
2172 state|=ExitState;
2173 break;
2174 }
2175 case ButtonRelease:
2176 break;
2177 case Expose:
2178 break;
2179 case KeyPress:
2180 {
2181 if (event.xkey.window != windows->image.id)
2182 break;
2183 /*
2184 Respond to a user key press.
2185 */
2186 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2187 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2188 switch ((int) key_symbol)
2189 {
2190 case XK_Escape:
2191 case XK_F20:
2192 {
2193 /*
2194 Prematurely exit.
2195 */
2196 state|=EscapeState;
2197 state|=ExitState;
2198 break;
2199 }
2200 case XK_F1:
2201 case XK_Help:
2202 {
2203 XTextViewWidget(display,resource_info,windows,MagickFalse,
2204 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2205 break;
2206 }
2207 default:
2208 {
2209 (void) XBell(display,0);
2210 break;
2211 }
2212 }
2213 break;
2214 }
2215 case MotionNotify:
2216 {
2217 /*
2218 Map and unmap Info widget as cursor crosses its boundaries.
2219 */
2220 x=event.xmotion.x;
2221 y=event.xmotion.y;
2222 if (windows->info.mapped != MagickFalse)
2223 {
2224 if ((x < (int) (windows->info.x+windows->info.width)) &&
2225 (y < (int) (windows->info.y+windows->info.height)))
2226 (void) XWithdrawWindow(display,windows->info.id,
2227 windows->info.screen);
2228 }
2229 else
2230 if ((x > (int) (windows->info.x+windows->info.width)) ||
2231 (y > (int) (windows->info.y+windows->info.height)))
2232 (void) XMapWindow(display,windows->info.id);
2233 break;
2234 }
2235 default:
2236 break;
2237 }
2238 } while ((state & ExitState) == 0);
2239 (void) XSelectInput(display,windows->image.id,
2240 windows->image.attributes.event_mask);
2241 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2242 if ((state & EscapeState) != 0)
2243 return(MagickTrue);
2244 /*
2245 Set font info and check boundary conditions.
2246 */
2247 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2248 if (font_info == (XFontStruct *) NULL)
2249 {
2250 XNoticeWidget(display,windows,"Unable to load font:",
2251 resource_info->font_name[font_id]);
2252 font_info=windows->font_info;
2253 }
2254 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2255 x=(int) windows->image.width-font_info->max_bounds.width;
2256 if (y < (int) (font_info->ascent+font_info->descent))
2257 y=(int) font_info->ascent+font_info->descent;
2258 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2259 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2260 return(MagickFalse);
2261 /*
2262 Initialize annotate structure.
2263 */
cristy73bd4a52010-10-05 11:24:23 +00002264 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002265 if (annotate_info == (XAnnotateInfo *) NULL)
2266 return(MagickFalse);
2267 XGetAnnotateInfo(annotate_info);
2268 annotate_info->x=x;
2269 annotate_info->y=y;
2270 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2271 annotate_info->stencil=OpaqueStencil;
2272 else
2273 if (transparent_box == MagickFalse)
2274 annotate_info->stencil=BackgroundStencil;
2275 else
2276 annotate_info->stencil=ForegroundStencil;
2277 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2278 annotate_info->degrees=degrees;
2279 annotate_info->font_info=font_info;
2280 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002281 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
cristy3ed852e2009-09-05 21:47:34 +00002282 sizeof(*annotate_info->text));
2283 if (annotate_info->text == (char *) NULL)
2284 return(MagickFalse);
2285 /*
2286 Create cursor and set graphic context.
2287 */
2288 cursor=XCreateFontCursor(display,XC_pencil);
2289 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2290 annotate_context=windows->image.annotate_context;
2291 (void) XSetFont(display,annotate_context,font_info->fid);
2292 (void) XSetBackground(display,annotate_context,
2293 windows->pixel_info->pen_colors[box_id].pixel);
2294 (void) XSetForeground(display,annotate_context,
2295 windows->pixel_info->pen_colors[pen_id].pixel);
2296 /*
2297 Begin annotating the image with text.
2298 */
2299 (void) CloneString(&windows->command.name,"Text");
2300 windows->command.data=0;
2301 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2302 state=DefaultState;
2303 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2304 text_event.xexpose.width=(int) font_info->max_bounds.width;
2305 text_event.xexpose.height=font_info->max_bounds.ascent+
2306 font_info->max_bounds.descent;
2307 p=annotate_info->text;
2308 do
2309 {
2310 /*
2311 Display text cursor.
2312 */
2313 *p='\0';
2314 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2315 /*
2316 Wait for next event.
2317 */
2318 XScreenEvent(display,windows,&event);
2319 if (event.xany.window == windows->command.id)
2320 {
2321 /*
2322 Select a command from the Command widget.
2323 */
2324 (void) XSetBackground(display,annotate_context,
2325 windows->pixel_info->background_color.pixel);
2326 (void) XSetForeground(display,annotate_context,
2327 windows->pixel_info->foreground_color.pixel);
2328 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2329 (void) XSetBackground(display,annotate_context,
2330 windows->pixel_info->pen_colors[box_id].pixel);
2331 (void) XSetForeground(display,annotate_context,
2332 windows->pixel_info->pen_colors[pen_id].pixel);
2333 if (id < 0)
2334 continue;
2335 switch (TextCommands[id])
2336 {
2337 case TextHelpCommand:
2338 {
2339 XTextViewWidget(display,resource_info,windows,MagickFalse,
2340 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2341 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2342 break;
2343 }
2344 case TextApplyCommand:
2345 {
2346 /*
2347 Finished annotating.
2348 */
2349 annotate_info->width=(unsigned int) XTextWidth(font_info,
2350 annotate_info->text,(int) strlen(annotate_info->text));
2351 XRefreshWindow(display,&windows->image,&text_event);
2352 state|=ExitState;
2353 break;
2354 }
2355 default:
2356 break;
2357 }
2358 continue;
2359 }
2360 /*
2361 Erase text cursor.
2362 */
2363 text_event.xexpose.x=x;
2364 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2365 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2366 (unsigned int) text_event.xexpose.width,(unsigned int)
2367 text_event.xexpose.height,MagickFalse);
2368 XRefreshWindow(display,&windows->image,&text_event);
2369 switch (event.type)
2370 {
2371 case ButtonPress:
2372 {
2373 if (event.xbutton.window != windows->image.id)
2374 break;
2375 if (event.xbutton.button == Button2)
2376 {
2377 /*
2378 Request primary selection.
2379 */
2380 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2381 windows->image.id,CurrentTime);
2382 break;
2383 }
2384 break;
2385 }
2386 case Expose:
2387 {
2388 if (event.xexpose.count == 0)
2389 {
2390 XAnnotateInfo
2391 *text_info;
2392
2393 /*
2394 Refresh Image window.
2395 */
2396 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2397 text_info=annotate_info;
2398 while (text_info != (XAnnotateInfo *) NULL)
2399 {
2400 if (annotate_info->stencil == ForegroundStencil)
2401 (void) XDrawString(display,windows->image.id,annotate_context,
2402 text_info->x,text_info->y,text_info->text,
2403 (int) strlen(text_info->text));
2404 else
2405 (void) XDrawImageString(display,windows->image.id,
2406 annotate_context,text_info->x,text_info->y,text_info->text,
2407 (int) strlen(text_info->text));
2408 text_info=text_info->previous;
2409 }
2410 (void) XDrawString(display,windows->image.id,annotate_context,
2411 x,y,"_",1);
2412 }
2413 break;
2414 }
2415 case KeyPress:
2416 {
2417 int
2418 length;
2419
2420 if (event.xkey.window != windows->image.id)
2421 break;
2422 /*
2423 Respond to a user key press.
2424 */
2425 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2426 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2427 *(command+length)='\0';
2428 if (((event.xkey.state & ControlMask) != 0) ||
2429 ((event.xkey.state & Mod1Mask) != 0))
2430 state|=ModifierState;
2431 if ((state & ModifierState) != 0)
2432 switch ((int) key_symbol)
2433 {
2434 case XK_u:
2435 case XK_U:
2436 {
2437 key_symbol=DeleteCommand;
2438 break;
2439 }
2440 default:
2441 break;
2442 }
2443 switch ((int) key_symbol)
2444 {
2445 case XK_BackSpace:
2446 {
2447 /*
2448 Erase one character.
2449 */
2450 if (p == annotate_info->text)
2451 {
2452 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2453 break;
2454 else
2455 {
2456 /*
2457 Go to end of the previous line of text.
2458 */
2459 annotate_info=annotate_info->previous;
2460 p=annotate_info->text;
2461 x=annotate_info->x+annotate_info->width;
2462 y=annotate_info->y;
2463 if (annotate_info->width != 0)
2464 p+=strlen(annotate_info->text);
2465 break;
2466 }
2467 }
2468 p--;
2469 x-=XTextWidth(font_info,p,1);
2470 text_event.xexpose.x=x;
2471 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2472 XRefreshWindow(display,&windows->image,&text_event);
2473 break;
2474 }
2475 case XK_bracketleft:
2476 {
2477 key_symbol=XK_Escape;
2478 break;
2479 }
2480 case DeleteCommand:
2481 {
2482 /*
2483 Erase the entire line of text.
2484 */
2485 while (p != annotate_info->text)
2486 {
2487 p--;
2488 x-=XTextWidth(font_info,p,1);
2489 text_event.xexpose.x=x;
2490 XRefreshWindow(display,&windows->image,&text_event);
2491 }
2492 break;
2493 }
2494 case XK_Escape:
2495 case XK_F20:
2496 {
2497 /*
2498 Finished annotating.
2499 */
2500 annotate_info->width=(unsigned int) XTextWidth(font_info,
2501 annotate_info->text,(int) strlen(annotate_info->text));
2502 XRefreshWindow(display,&windows->image,&text_event);
2503 state|=ExitState;
2504 break;
2505 }
2506 default:
2507 {
2508 /*
2509 Draw a single character on the Image window.
2510 */
2511 if ((state & ModifierState) != 0)
2512 break;
2513 if (*command == '\0')
2514 break;
2515 *p=(*command);
2516 if (annotate_info->stencil == ForegroundStencil)
2517 (void) XDrawString(display,windows->image.id,annotate_context,
2518 x,y,p,1);
2519 else
2520 (void) XDrawImageString(display,windows->image.id,
2521 annotate_context,x,y,p,1);
2522 x+=XTextWidth(font_info,p,1);
2523 p++;
2524 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2525 break;
2526 }
2527 case XK_Return:
2528 case XK_KP_Enter:
2529 {
2530 /*
2531 Advance to the next line of text.
2532 */
2533 *p='\0';
2534 annotate_info->width=(unsigned int) XTextWidth(font_info,
2535 annotate_info->text,(int) strlen(annotate_info->text));
2536 if (annotate_info->next != (XAnnotateInfo *) NULL)
2537 {
2538 /*
2539 Line of text already exists.
2540 */
2541 annotate_info=annotate_info->next;
2542 x=annotate_info->x;
2543 y=annotate_info->y;
2544 p=annotate_info->text;
2545 break;
2546 }
2547 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2548 sizeof(*annotate_info->next));
2549 if (annotate_info->next == (XAnnotateInfo *) NULL)
2550 return(MagickFalse);
2551 *annotate_info->next=(*annotate_info);
2552 annotate_info->next->previous=annotate_info;
2553 annotate_info=annotate_info->next;
2554 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002555 windows->image.width/MagickMax((ssize_t)
2556 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002557 if (annotate_info->text == (char *) NULL)
2558 return(MagickFalse);
2559 annotate_info->y+=annotate_info->height;
2560 if (annotate_info->y > (int) windows->image.height)
2561 annotate_info->y=(int) annotate_info->height;
2562 annotate_info->next=(XAnnotateInfo *) NULL;
2563 x=annotate_info->x;
2564 y=annotate_info->y;
2565 p=annotate_info->text;
2566 break;
2567 }
2568 }
2569 break;
2570 }
2571 case KeyRelease:
2572 {
2573 /*
2574 Respond to a user key release.
2575 */
2576 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2577 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2578 state&=(~ModifierState);
2579 break;
2580 }
2581 case SelectionNotify:
2582 {
2583 Atom
2584 type;
2585
2586 int
2587 format;
2588
2589 unsigned char
2590 *data;
2591
cristyf2faecf2010-05-28 19:19:36 +00002592 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002593 after,
2594 length;
2595
2596 /*
2597 Obtain response from primary selection.
2598 */
2599 if (event.xselection.property == (Atom) None)
2600 break;
2601 status=XGetWindowProperty(display,event.xselection.requestor,
cristyecd0ab52010-05-30 14:59:20 +00002602 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
cristy3ed852e2009-09-05 21:47:34 +00002603 &type,&format,&length,&after,&data);
2604 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2605 (length == 0))
2606 break;
2607 /*
2608 Annotate Image window with primary selection.
2609 */
cristybb503372010-05-27 20:51:26 +00002610 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002611 {
2612 if ((char) data[i] != '\n')
2613 {
2614 /*
2615 Draw a single character on the Image window.
2616 */
2617 *p=(char) data[i];
2618 (void) XDrawString(display,windows->image.id,annotate_context,
2619 x,y,p,1);
2620 x+=XTextWidth(font_info,p,1);
2621 p++;
2622 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2623 continue;
2624 }
2625 /*
2626 Advance to the next line of text.
2627 */
2628 *p='\0';
2629 annotate_info->width=(unsigned int) XTextWidth(font_info,
2630 annotate_info->text,(int) strlen(annotate_info->text));
2631 if (annotate_info->next != (XAnnotateInfo *) NULL)
2632 {
2633 /*
2634 Line of text already exists.
2635 */
2636 annotate_info=annotate_info->next;
2637 x=annotate_info->x;
2638 y=annotate_info->y;
2639 p=annotate_info->text;
2640 continue;
2641 }
2642 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2643 sizeof(*annotate_info->next));
2644 if (annotate_info->next == (XAnnotateInfo *) NULL)
2645 return(MagickFalse);
2646 *annotate_info->next=(*annotate_info);
2647 annotate_info->next->previous=annotate_info;
2648 annotate_info=annotate_info->next;
2649 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002650 windows->image.width/MagickMax((ssize_t)
2651 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002652 if (annotate_info->text == (char *) NULL)
2653 return(MagickFalse);
2654 annotate_info->y+=annotate_info->height;
2655 if (annotate_info->y > (int) windows->image.height)
2656 annotate_info->y=(int) annotate_info->height;
2657 annotate_info->next=(XAnnotateInfo *) NULL;
2658 x=annotate_info->x;
2659 y=annotate_info->y;
2660 p=annotate_info->text;
2661 }
2662 (void) XFree((void *) data);
2663 break;
2664 }
2665 default:
2666 break;
2667 }
2668 } while ((state & ExitState) == 0);
2669 (void) XFreeCursor(display,cursor);
2670 /*
2671 Annotation is relative to image configuration.
2672 */
2673 width=(unsigned int) image->columns;
2674 height=(unsigned int) image->rows;
2675 x=0;
2676 y=0;
2677 if (windows->image.crop_geometry != (char *) NULL)
2678 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2679 /*
2680 Initialize annotated image.
2681 */
2682 XSetCursorState(display,windows,MagickTrue);
2683 XCheckRefreshWindows(display,windows);
2684 while (annotate_info != (XAnnotateInfo *) NULL)
2685 {
2686 if (annotate_info->width == 0)
2687 {
2688 /*
2689 No text on this line-- go to the next line of text.
2690 */
2691 previous_info=annotate_info->previous;
2692 annotate_info->text=(char *)
2693 RelinquishMagickMemory(annotate_info->text);
2694 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2695 annotate_info=previous_info;
2696 continue;
2697 }
2698 /*
2699 Determine pixel index for box and pen color.
2700 */
2701 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2702 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002703 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002704 if (windows->pixel_info->pixels[i] ==
2705 windows->pixel_info->pen_colors[box_id].pixel)
2706 {
2707 windows->pixel_info->box_index=(unsigned short) i;
2708 break;
2709 }
2710 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2711 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002712 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002713 if (windows->pixel_info->pixels[i] ==
2714 windows->pixel_info->pen_colors[pen_id].pixel)
2715 {
2716 windows->pixel_info->pen_index=(unsigned short) i;
2717 break;
2718 }
2719 /*
2720 Define the annotate geometry string.
2721 */
2722 annotate_info->x=(int)
2723 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2724 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2725 windows->image.y)/windows->image.ximage->height;
cristyb51dff52011-05-19 16:55:47 +00002726 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00002727 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2728 height*annotate_info->height/windows->image.ximage->height,
2729 annotate_info->x+x,annotate_info->y+y);
2730 /*
2731 Annotate image with text.
2732 */
2733 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2734 if (status == 0)
2735 return(MagickFalse);
2736 /*
2737 Free up memory.
2738 */
2739 previous_info=annotate_info->previous;
2740 annotate_info->text=DestroyString(annotate_info->text);
2741 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2742 annotate_info=previous_info;
2743 }
2744 (void) XSetForeground(display,annotate_context,
2745 windows->pixel_info->foreground_color.pixel);
2746 (void) XSetBackground(display,annotate_context,
2747 windows->pixel_info->background_color.pixel);
2748 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2749 XSetCursorState(display,windows,MagickFalse);
2750 (void) XFreeFont(display,font_info);
2751 /*
2752 Update image configuration.
2753 */
2754 XConfigureImageColormap(display,resource_info,windows,image);
cristy051718b2011-08-28 22:49:25 +00002755 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002756 return(MagickTrue);
2757}
2758
2759/*
2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761% %
2762% %
2763% %
2764+ X B a c k g r o u n d I m a g e %
2765% %
2766% %
2767% %
2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769%
2770% XBackgroundImage() displays the image in the background of a window.
2771%
2772% The format of the XBackgroundImage method is:
2773%
2774% MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002775% XResourceInfo *resource_info,XWindows *windows,Image **image,
2776% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002777%
2778% A description of each parameter follows:
2779%
2780% o display: Specifies a connection to an X server; returned from
2781% XOpenDisplay.
2782%
2783% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2784%
2785% o windows: Specifies a pointer to a XWindows structure.
2786%
2787% o image: the image.
2788%
cristy051718b2011-08-28 22:49:25 +00002789% o exception: return any errors or warnings in this structure.
2790%
cristy3ed852e2009-09-05 21:47:34 +00002791*/
2792static MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002793 XResourceInfo *resource_info,XWindows *windows,Image **image,
2794 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002795{
2796#define BackgroundImageTag "Background/Image"
2797
2798 int
2799 status;
2800
2801 static char
2802 window_id[MaxTextExtent] = "root";
2803
2804 XResourceInfo
2805 background_resources;
2806
2807 /*
2808 Put image in background.
2809 */
2810 status=XDialogWidget(display,windows,"Background",
2811 "Enter window id (id 0x00 selects window with pointer):",window_id);
2812 if (*window_id == '\0')
2813 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002814 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2815 exception);
cristy3ed852e2009-09-05 21:47:34 +00002816 XInfoWidget(display,windows,BackgroundImageTag);
2817 XSetCursorState(display,windows,MagickTrue);
2818 XCheckRefreshWindows(display,windows);
2819 background_resources=(*resource_info);
2820 background_resources.window_id=window_id;
2821 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
cristy051718b2011-08-28 22:49:25 +00002822 status=XDisplayBackgroundImage(display,&background_resources,*image,
2823 exception);
cristy3ed852e2009-09-05 21:47:34 +00002824 if (status != MagickFalse)
2825 XClientMessage(display,windows->image.id,windows->im_protocols,
2826 windows->im_retain_colors,CurrentTime);
2827 XSetCursorState(display,windows,MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002828 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2829 exception);
cristy3ed852e2009-09-05 21:47:34 +00002830 return(MagickTrue);
2831}
2832
2833/*
2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835% %
2836% %
2837% %
2838+ X C h o p I m a g e %
2839% %
2840% %
2841% %
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843%
2844% XChopImage() chops the X image.
2845%
2846% The format of the XChopImage method is:
2847%
2848% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00002849% XWindows *windows,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002850%
2851% A description of each parameter follows:
2852%
2853% o display: Specifies a connection to an X server; returned from
2854% XOpenDisplay.
2855%
2856% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2857%
2858% o windows: Specifies a pointer to a XWindows structure.
2859%
2860% o image: the image.
2861%
cristy051718b2011-08-28 22:49:25 +00002862% o exception: return any errors or warnings in this structure.
2863%
cristy3ed852e2009-09-05 21:47:34 +00002864*/
2865static MagickBooleanType XChopImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002866 XResourceInfo *resource_info,XWindows *windows,Image **image,
2867 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002868{
2869 static const char
2870 *ChopMenu[] =
2871 {
2872 "Direction",
2873 "Help",
2874 "Dismiss",
2875 (char *) NULL
2876 };
2877
2878 static ModeType
2879 direction = HorizontalChopCommand;
2880
2881 static const ModeType
2882 ChopCommands[] =
2883 {
2884 ChopDirectionCommand,
2885 ChopHelpCommand,
2886 ChopDismissCommand
2887 },
2888 DirectionCommands[] =
2889 {
2890 HorizontalChopCommand,
2891 VerticalChopCommand
2892 };
2893
2894 char
2895 text[MaxTextExtent];
2896
2897 Image
2898 *chop_image;
2899
2900 int
2901 id,
2902 x,
2903 y;
2904
2905 MagickRealType
2906 scale_factor;
2907
2908 RectangleInfo
2909 chop_info;
2910
2911 unsigned int
2912 distance,
2913 height,
2914 width;
2915
cristybb503372010-05-27 20:51:26 +00002916 size_t
cristy3ed852e2009-09-05 21:47:34 +00002917 state;
2918
2919 XEvent
2920 event;
2921
2922 XSegment
2923 segment_info;
2924
2925 /*
2926 Map Command widget.
2927 */
2928 (void) CloneString(&windows->command.name,"Chop");
2929 windows->command.data=1;
2930 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2931 (void) XMapRaised(display,windows->command.id);
2932 XClientMessage(display,windows->image.id,windows->im_protocols,
2933 windows->im_update_widget,CurrentTime);
2934 /*
2935 Track pointer until button 1 is pressed.
2936 */
2937 XQueryPosition(display,windows->image.id,&x,&y);
2938 (void) XSelectInput(display,windows->image.id,
2939 windows->image.attributes.event_mask | PointerMotionMask);
2940 state=DefaultState;
2941 do
2942 {
2943 if (windows->info.mapped != MagickFalse)
2944 {
2945 /*
2946 Display pointer position.
2947 */
cristyb51dff52011-05-19 16:55:47 +00002948 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00002949 x+windows->image.x,y+windows->image.y);
2950 XInfoWidget(display,windows,text);
2951 }
2952 /*
2953 Wait for next event.
2954 */
2955 XScreenEvent(display,windows,&event);
2956 if (event.xany.window == windows->command.id)
2957 {
2958 /*
2959 Select a command from the Command widget.
2960 */
2961 id=XCommandWidget(display,windows,ChopMenu,&event);
2962 if (id < 0)
2963 continue;
2964 switch (ChopCommands[id])
2965 {
2966 case ChopDirectionCommand:
2967 {
2968 char
2969 command[MaxTextExtent];
2970
2971 static const char
2972 *Directions[] =
2973 {
2974 "horizontal",
2975 "vertical",
2976 (char *) NULL,
2977 };
2978
2979 /*
2980 Select a command from the pop-up menu.
2981 */
2982 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2983 if (id >= 0)
2984 direction=DirectionCommands[id];
2985 break;
2986 }
2987 case ChopHelpCommand:
2988 {
2989 XTextViewWidget(display,resource_info,windows,MagickFalse,
2990 "Help Viewer - Image Chop",ImageChopHelp);
2991 break;
2992 }
2993 case ChopDismissCommand:
2994 {
2995 /*
2996 Prematurely exit.
2997 */
2998 state|=EscapeState;
2999 state|=ExitState;
3000 break;
3001 }
3002 default:
3003 break;
3004 }
3005 continue;
3006 }
3007 switch (event.type)
3008 {
3009 case ButtonPress:
3010 {
3011 if (event.xbutton.button != Button1)
3012 break;
3013 if (event.xbutton.window != windows->image.id)
3014 break;
3015 /*
3016 User has committed to start point of chopping line.
3017 */
3018 segment_info.x1=(short int) event.xbutton.x;
3019 segment_info.x2=(short int) event.xbutton.x;
3020 segment_info.y1=(short int) event.xbutton.y;
3021 segment_info.y2=(short int) event.xbutton.y;
3022 state|=ExitState;
3023 break;
3024 }
3025 case ButtonRelease:
3026 break;
3027 case Expose:
3028 break;
3029 case KeyPress:
3030 {
3031 char
3032 command[MaxTextExtent];
3033
3034 KeySym
3035 key_symbol;
3036
3037 if (event.xkey.window != windows->image.id)
3038 break;
3039 /*
3040 Respond to a user key press.
3041 */
3042 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3043 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3044 switch ((int) key_symbol)
3045 {
3046 case XK_Escape:
3047 case XK_F20:
3048 {
3049 /*
3050 Prematurely exit.
3051 */
3052 state|=EscapeState;
3053 state|=ExitState;
3054 break;
3055 }
3056 case XK_F1:
3057 case XK_Help:
3058 {
3059 (void) XSetFunction(display,windows->image.highlight_context,
3060 GXcopy);
3061 XTextViewWidget(display,resource_info,windows,MagickFalse,
3062 "Help Viewer - Image Chop",ImageChopHelp);
3063 (void) XSetFunction(display,windows->image.highlight_context,
3064 GXinvert);
3065 break;
3066 }
3067 default:
3068 {
3069 (void) XBell(display,0);
3070 break;
3071 }
3072 }
3073 break;
3074 }
3075 case MotionNotify:
3076 {
3077 /*
3078 Map and unmap Info widget as text cursor crosses its boundaries.
3079 */
3080 x=event.xmotion.x;
3081 y=event.xmotion.y;
3082 if (windows->info.mapped != MagickFalse)
3083 {
3084 if ((x < (int) (windows->info.x+windows->info.width)) &&
3085 (y < (int) (windows->info.y+windows->info.height)))
3086 (void) XWithdrawWindow(display,windows->info.id,
3087 windows->info.screen);
3088 }
3089 else
3090 if ((x > (int) (windows->info.x+windows->info.width)) ||
3091 (y > (int) (windows->info.y+windows->info.height)))
3092 (void) XMapWindow(display,windows->info.id);
3093 }
3094 }
3095 } while ((state & ExitState) == 0);
3096 (void) XSelectInput(display,windows->image.id,
3097 windows->image.attributes.event_mask);
3098 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3099 if ((state & EscapeState) != 0)
3100 return(MagickTrue);
3101 /*
3102 Draw line as pointer moves until the mouse button is released.
3103 */
3104 chop_info.width=0;
3105 chop_info.height=0;
3106 chop_info.x=0;
3107 chop_info.y=0;
3108 distance=0;
3109 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3110 state=DefaultState;
3111 do
3112 {
3113 if (distance > 9)
3114 {
3115 /*
3116 Display info and draw chopping line.
3117 */
3118 if (windows->info.mapped == MagickFalse)
3119 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00003120 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00003121 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00003122 chop_info.height,(double) chop_info.x,(double) chop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003123 XInfoWidget(display,windows,text);
3124 XHighlightLine(display,windows->image.id,
3125 windows->image.highlight_context,&segment_info);
3126 }
3127 else
3128 if (windows->info.mapped != MagickFalse)
3129 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3130 /*
3131 Wait for next event.
3132 */
3133 XScreenEvent(display,windows,&event);
3134 if (distance > 9)
3135 XHighlightLine(display,windows->image.id,
3136 windows->image.highlight_context,&segment_info);
3137 switch (event.type)
3138 {
3139 case ButtonPress:
3140 {
3141 segment_info.x2=(short int) event.xmotion.x;
3142 segment_info.y2=(short int) event.xmotion.y;
3143 break;
3144 }
3145 case ButtonRelease:
3146 {
3147 /*
3148 User has committed to chopping line.
3149 */
3150 segment_info.x2=(short int) event.xbutton.x;
3151 segment_info.y2=(short int) event.xbutton.y;
3152 state|=ExitState;
3153 break;
3154 }
3155 case Expose:
3156 break;
3157 case MotionNotify:
3158 {
3159 segment_info.x2=(short int) event.xmotion.x;
3160 segment_info.y2=(short int) event.xmotion.y;
3161 }
3162 default:
3163 break;
3164 }
3165 /*
3166 Check boundary conditions.
3167 */
3168 if (segment_info.x2 < 0)
3169 segment_info.x2=0;
3170 else
3171 if (segment_info.x2 > windows->image.ximage->width)
3172 segment_info.x2=windows->image.ximage->width;
3173 if (segment_info.y2 < 0)
3174 segment_info.y2=0;
3175 else
3176 if (segment_info.y2 > windows->image.ximage->height)
3177 segment_info.y2=windows->image.ximage->height;
3178 distance=(unsigned int)
3179 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3180 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3181 /*
3182 Compute chopping geometry.
3183 */
3184 if (direction == HorizontalChopCommand)
3185 {
cristybb503372010-05-27 20:51:26 +00003186 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
cristy49e2d862010-11-12 02:50:30 +00003187 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
cristy3ed852e2009-09-05 21:47:34 +00003188 chop_info.height=0;
3189 chop_info.y=0;
3190 if (segment_info.x1 > (int) segment_info.x2)
3191 {
cristybb503372010-05-27 20:51:26 +00003192 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
cristy49e2d862010-11-12 02:50:30 +00003193 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
cristy3ed852e2009-09-05 21:47:34 +00003194 }
3195 }
3196 else
3197 {
3198 chop_info.width=0;
cristybb503372010-05-27 20:51:26 +00003199 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
cristy3ed852e2009-09-05 21:47:34 +00003200 chop_info.x=0;
cristy49e2d862010-11-12 02:50:30 +00003201 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
cristy3ed852e2009-09-05 21:47:34 +00003202 if (segment_info.y1 > segment_info.y2)
3203 {
cristy49e2d862010-11-12 02:50:30 +00003204 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3205 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
cristy3ed852e2009-09-05 21:47:34 +00003206 }
3207 }
3208 } while ((state & ExitState) == 0);
3209 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3210 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3211 if (distance <= 9)
3212 return(MagickTrue);
3213 /*
3214 Image chopping is relative to image configuration.
3215 */
cristy051718b2011-08-28 22:49:25 +00003216 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3217 exception);
cristy3ed852e2009-09-05 21:47:34 +00003218 XSetCursorState(display,windows,MagickTrue);
3219 XCheckRefreshWindows(display,windows);
3220 windows->image.window_changes.width=windows->image.ximage->width-
3221 (unsigned int) chop_info.width;
3222 windows->image.window_changes.height=windows->image.ximage->height-
3223 (unsigned int) chop_info.height;
3224 width=(unsigned int) (*image)->columns;
3225 height=(unsigned int) (*image)->rows;
3226 x=0;
3227 y=0;
3228 if (windows->image.crop_geometry != (char *) NULL)
3229 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3230 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3231 chop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00003232 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003233 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3234 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3235 chop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00003236 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003237 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3238 /*
3239 Chop image.
3240 */
cristy051718b2011-08-28 22:49:25 +00003241 chop_image=ChopImage(*image,&chop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003242 XSetCursorState(display,windows,MagickFalse);
3243 if (chop_image == (Image *) NULL)
3244 return(MagickFalse);
3245 *image=DestroyImage(*image);
3246 *image=chop_image;
3247 /*
3248 Update image configuration.
3249 */
3250 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00003251 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003252 return(MagickTrue);
3253}
3254
3255/*
3256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3257% %
3258% %
3259% %
3260+ X C o l o r E d i t I m a g e %
3261% %
3262% %
3263% %
3264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3265%
3266% XColorEditImage() allows the user to interactively change the color of one
3267% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3268%
3269% The format of the XColorEditImage method is:
3270%
3271% MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003272% XResourceInfo *resource_info,XWindows *windows,Image **image,
3273% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003274%
3275% A description of each parameter follows:
3276%
3277% o display: Specifies a connection to an X server; returned from
3278% XOpenDisplay.
3279%
3280% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3281%
3282% o windows: Specifies a pointer to a XWindows structure.
3283%
3284% o image: the image; returned from ReadImage.
3285%
cristy051718b2011-08-28 22:49:25 +00003286% o exception: return any errors or warnings in this structure.
3287%
cristy3ed852e2009-09-05 21:47:34 +00003288*/
cristy3ed852e2009-09-05 21:47:34 +00003289static MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003290 XResourceInfo *resource_info,XWindows *windows,Image **image,
3291 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003292{
3293 static const char
3294 *ColorEditMenu[] =
3295 {
3296 "Method",
3297 "Pixel Color",
3298 "Border Color",
3299 "Fuzz",
3300 "Undo",
3301 "Help",
3302 "Dismiss",
3303 (char *) NULL
3304 };
3305
3306 static const ModeType
3307 ColorEditCommands[] =
3308 {
3309 ColorEditMethodCommand,
3310 ColorEditColorCommand,
3311 ColorEditBorderCommand,
3312 ColorEditFuzzCommand,
3313 ColorEditUndoCommand,
3314 ColorEditHelpCommand,
3315 ColorEditDismissCommand
3316 };
3317
3318 static PaintMethod
3319 method = PointMethod;
3320
3321 static unsigned int
3322 pen_id = 0;
3323
3324 static XColor
3325 border_color = { 0, 0, 0, 0, 0, 0 };
3326
3327 char
3328 command[MaxTextExtent],
3329 text[MaxTextExtent];
3330
3331 Cursor
3332 cursor;
3333
cristy3ed852e2009-09-05 21:47:34 +00003334 int
3335 entry,
3336 id,
3337 x,
3338 x_offset,
3339 y,
3340 y_offset;
3341
cristy4c08aed2011-07-01 19:47:50 +00003342 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00003343 *q;
3344
cristybb503372010-05-27 20:51:26 +00003345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003346 i;
3347
3348 unsigned int
3349 height,
3350 width;
3351
cristybb503372010-05-27 20:51:26 +00003352 size_t
cristy3ed852e2009-09-05 21:47:34 +00003353 state;
3354
3355 XColor
3356 color;
3357
3358 XEvent
3359 event;
3360
3361 /*
3362 Map Command widget.
3363 */
3364 (void) CloneString(&windows->command.name,"Color Edit");
3365 windows->command.data=4;
3366 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3367 (void) XMapRaised(display,windows->command.id);
3368 XClientMessage(display,windows->image.id,windows->im_protocols,
3369 windows->im_update_widget,CurrentTime);
3370 /*
3371 Make cursor.
3372 */
3373 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3374 resource_info->background_color,resource_info->foreground_color);
3375 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3376 /*
3377 Track pointer until button 1 is pressed.
3378 */
3379 XQueryPosition(display,windows->image.id,&x,&y);
3380 (void) XSelectInput(display,windows->image.id,
3381 windows->image.attributes.event_mask | PointerMotionMask);
3382 state=DefaultState;
3383 do
3384 {
3385 if (windows->info.mapped != MagickFalse)
3386 {
3387 /*
3388 Display pointer position.
3389 */
cristyb51dff52011-05-19 16:55:47 +00003390 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00003391 x+windows->image.x,y+windows->image.y);
3392 XInfoWidget(display,windows,text);
3393 }
3394 /*
3395 Wait for next event.
3396 */
3397 XScreenEvent(display,windows,&event);
3398 if (event.xany.window == windows->command.id)
3399 {
3400 /*
3401 Select a command from the Command widget.
3402 */
3403 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3404 if (id < 0)
3405 {
3406 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3407 continue;
3408 }
3409 switch (ColorEditCommands[id])
3410 {
3411 case ColorEditMethodCommand:
3412 {
3413 char
3414 **methods;
3415
3416 /*
3417 Select a method from the pop-up menu.
3418 */
cristy042ee782011-04-22 18:48:30 +00003419 methods=(char **) GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00003420 if (methods == (char **) NULL)
3421 break;
3422 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3423 (const char **) methods,command);
3424 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00003425 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00003426 MagickFalse,methods[entry]);
3427 methods=DestroyStringList(methods);
3428 break;
3429 }
3430 case ColorEditColorCommand:
3431 {
3432 const char
3433 *ColorMenu[MaxNumberPens];
3434
3435 int
3436 pen_number;
3437
3438 /*
3439 Initialize menu selections.
3440 */
3441 for (i=0; i < (int) (MaxNumberPens-2); i++)
3442 ColorMenu[i]=resource_info->pen_colors[i];
3443 ColorMenu[MaxNumberPens-2]="Browser...";
3444 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3445 /*
3446 Select a pen color from the pop-up menu.
3447 */
3448 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3449 (const char **) ColorMenu,command);
3450 if (pen_number < 0)
3451 break;
3452 if (pen_number == (MaxNumberPens-2))
3453 {
3454 static char
3455 color_name[MaxTextExtent] = "gray";
3456
3457 /*
3458 Select a pen color from a dialog.
3459 */
3460 resource_info->pen_colors[pen_number]=color_name;
3461 XColorBrowserWidget(display,windows,"Select",color_name);
3462 if (*color_name == '\0')
3463 break;
3464 }
3465 /*
3466 Set pen color.
3467 */
3468 (void) XParseColor(display,windows->map_info->colormap,
3469 resource_info->pen_colors[pen_number],&color);
3470 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3471 (unsigned int) MaxColors,&color);
3472 windows->pixel_info->pen_colors[pen_number]=color;
3473 pen_id=(unsigned int) pen_number;
3474 break;
3475 }
3476 case ColorEditBorderCommand:
3477 {
3478 const char
3479 *ColorMenu[MaxNumberPens];
3480
3481 int
3482 pen_number;
3483
3484 /*
3485 Initialize menu selections.
3486 */
3487 for (i=0; i < (int) (MaxNumberPens-2); i++)
3488 ColorMenu[i]=resource_info->pen_colors[i];
3489 ColorMenu[MaxNumberPens-2]="Browser...";
3490 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3491 /*
3492 Select a pen color from the pop-up menu.
3493 */
3494 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3495 (const char **) ColorMenu,command);
3496 if (pen_number < 0)
3497 break;
3498 if (pen_number == (MaxNumberPens-2))
3499 {
3500 static char
3501 color_name[MaxTextExtent] = "gray";
3502
3503 /*
3504 Select a pen color from a dialog.
3505 */
3506 resource_info->pen_colors[pen_number]=color_name;
3507 XColorBrowserWidget(display,windows,"Select",color_name);
3508 if (*color_name == '\0')
3509 break;
3510 }
3511 /*
3512 Set border color.
3513 */
3514 (void) XParseColor(display,windows->map_info->colormap,
3515 resource_info->pen_colors[pen_number],&border_color);
3516 break;
3517 }
3518 case ColorEditFuzzCommand:
3519 {
3520 static char
3521 fuzz[MaxTextExtent];
3522
3523 static const char
3524 *FuzzMenu[] =
3525 {
3526 "0%",
3527 "2%",
3528 "5%",
3529 "10%",
3530 "15%",
3531 "Dialog...",
3532 (char *) NULL,
3533 };
3534
3535 /*
3536 Select a command from the pop-up menu.
3537 */
3538 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3539 command);
3540 if (entry < 0)
3541 break;
3542 if (entry != 5)
3543 {
cristy40a08ad2010-02-09 02:27:44 +00003544 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
3545 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003546 break;
3547 }
3548 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3549 (void) XDialogWidget(display,windows,"Ok",
3550 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3551 if (*fuzz == '\0')
3552 break;
3553 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00003554 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003555 break;
3556 }
3557 case ColorEditUndoCommand:
3558 {
3559 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00003560 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003561 break;
3562 }
3563 case ColorEditHelpCommand:
3564 default:
3565 {
3566 XTextViewWidget(display,resource_info,windows,MagickFalse,
3567 "Help Viewer - Image Annotation",ImageColorEditHelp);
3568 break;
3569 }
3570 case ColorEditDismissCommand:
3571 {
3572 /*
3573 Prematurely exit.
3574 */
3575 state|=EscapeState;
3576 state|=ExitState;
3577 break;
3578 }
3579 }
3580 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3581 continue;
3582 }
3583 switch (event.type)
3584 {
3585 case ButtonPress:
3586 {
3587 if (event.xbutton.button != Button1)
3588 break;
3589 if ((event.xbutton.window != windows->image.id) &&
3590 (event.xbutton.window != windows->magnify.id))
3591 break;
3592 /*
3593 exit loop.
3594 */
3595 x=event.xbutton.x;
3596 y=event.xbutton.y;
3597 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00003598 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003599 state|=UpdateConfigurationState;
3600 break;
3601 }
3602 case ButtonRelease:
3603 {
3604 if (event.xbutton.button != Button1)
3605 break;
3606 if ((event.xbutton.window != windows->image.id) &&
3607 (event.xbutton.window != windows->magnify.id))
3608 break;
3609 /*
3610 Update colormap information.
3611 */
3612 x=event.xbutton.x;
3613 y=event.xbutton.y;
3614 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00003615 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003616 XInfoWidget(display,windows,text);
3617 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3618 state&=(~UpdateConfigurationState);
3619 break;
3620 }
3621 case Expose:
3622 break;
3623 case KeyPress:
3624 {
3625 KeySym
3626 key_symbol;
3627
3628 if (event.xkey.window == windows->magnify.id)
3629 {
3630 Window
3631 window;
3632
3633 window=windows->magnify.id;
3634 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3635 }
3636 if (event.xkey.window != windows->image.id)
3637 break;
3638 /*
3639 Respond to a user key press.
3640 */
3641 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3642 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3643 switch ((int) key_symbol)
3644 {
3645 case XK_Escape:
3646 case XK_F20:
3647 {
3648 /*
3649 Prematurely exit.
3650 */
3651 state|=ExitState;
3652 break;
3653 }
3654 case XK_F1:
3655 case XK_Help:
3656 {
3657 XTextViewWidget(display,resource_info,windows,MagickFalse,
3658 "Help Viewer - Image Annotation",ImageColorEditHelp);
3659 break;
3660 }
3661 default:
3662 {
3663 (void) XBell(display,0);
3664 break;
3665 }
3666 }
3667 break;
3668 }
3669 case MotionNotify:
3670 {
3671 /*
3672 Map and unmap Info widget as cursor crosses its boundaries.
3673 */
3674 x=event.xmotion.x;
3675 y=event.xmotion.y;
3676 if (windows->info.mapped != MagickFalse)
3677 {
3678 if ((x < (int) (windows->info.x+windows->info.width)) &&
3679 (y < (int) (windows->info.y+windows->info.height)))
3680 (void) XWithdrawWindow(display,windows->info.id,
3681 windows->info.screen);
3682 }
3683 else
3684 if ((x > (int) (windows->info.x+windows->info.width)) ||
3685 (y > (int) (windows->info.y+windows->info.height)))
3686 (void) XMapWindow(display,windows->info.id);
3687 break;
3688 }
3689 default:
3690 break;
3691 }
3692 if (event.xany.window == windows->magnify.id)
3693 {
3694 x=windows->magnify.x-windows->image.x;
3695 y=windows->magnify.y-windows->image.y;
3696 }
3697 x_offset=x;
3698 y_offset=y;
3699 if ((state & UpdateConfigurationState) != 0)
3700 {
cristy49e2d862010-11-12 02:50:30 +00003701 CacheView
3702 *image_view;
3703
cristy3ed852e2009-09-05 21:47:34 +00003704 int
3705 x,
3706 y;
3707
3708 /*
3709 Pixel edit is relative to image configuration.
3710 */
3711 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3712 MagickTrue);
3713 color=windows->pixel_info->pen_colors[pen_id];
3714 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3715 width=(unsigned int) (*image)->columns;
3716 height=(unsigned int) (*image)->rows;
3717 x=0;
3718 y=0;
3719 if (windows->image.crop_geometry != (char *) NULL)
3720 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3721 &width,&height);
3722 x_offset=(int)
3723 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3724 y_offset=(int)
3725 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3726 if ((x_offset < 0) || (y_offset < 0))
3727 continue;
cristy49e2d862010-11-12 02:50:30 +00003728 if ((x_offset >= (int) (*image)->columns) ||
3729 (y_offset >= (int) (*image)->rows))
cristy3ed852e2009-09-05 21:47:34 +00003730 continue;
cristy49e2d862010-11-12 02:50:30 +00003731 image_view=AcquireCacheView(*image);
cristy3ed852e2009-09-05 21:47:34 +00003732 switch (method)
3733 {
3734 case PointMethod:
3735 default:
3736 {
3737 /*
3738 Update color information using point algorithm.
3739 */
cristy574cc262011-08-05 01:23:58 +00003740 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003741 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003742 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
cristy574cc262011-08-05 01:23:58 +00003743 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003744 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003745 break;
cristy4c08aed2011-07-01 19:47:50 +00003746 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3747 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3748 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristy051718b2011-08-28 22:49:25 +00003749 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +00003750 break;
3751 }
3752 case ReplaceMethod:
3753 {
cristy101ab702011-10-13 13:06:32 +00003754 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +00003755 pixel,
cristy3ed852e2009-09-05 21:47:34 +00003756 target;
3757
cristy2ed42f62011-10-02 19:49:57 +00003758 Quantum
3759 virtual_pixel[MaxPixelChannels];
3760
cristy3ed852e2009-09-05 21:47:34 +00003761 /*
3762 Update color information using replace algorithm.
3763 */
cristy49e2d862010-11-12 02:50:30 +00003764 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
cristy2ed42f62011-10-02 19:49:57 +00003765 (ssize_t) y_offset,virtual_pixel,exception);
3766 target.red=virtual_pixel[RedPixelChannel];
3767 target.green=virtual_pixel[GreenPixelChannel];
3768 target.blue=virtual_pixel[BluePixelChannel];
3769 target.alpha=virtual_pixel[AlphaPixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003770 if ((*image)->storage_class == DirectClass)
3771 {
cristy49e2d862010-11-12 02:50:30 +00003772 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003773 {
cristy49e2d862010-11-12 02:50:30 +00003774 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3775 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003776 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003777 break;
3778 for (x=0; x < (int) (*image)->columns; x++)
3779 {
cristy101ab702011-10-13 13:06:32 +00003780 GetPixelInfoPixel(*image,q,&pixel);
3781 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy3ed852e2009-09-05 21:47:34 +00003782 {
cristy4c08aed2011-07-01 19:47:50 +00003783 SetPixelRed(*image,ScaleShortToQuantum(
3784 color.red),q);
3785 SetPixelGreen(*image,ScaleShortToQuantum(
3786 color.green),q);
3787 SetPixelBlue(*image,ScaleShortToQuantum(
3788 color.blue),q);
cristy3ed852e2009-09-05 21:47:34 +00003789 }
cristyed231572011-07-14 02:18:59 +00003790 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003791 }
cristy49e2d862010-11-12 02:50:30 +00003792 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003793 break;
3794 }
3795 }
3796 else
3797 {
cristy49e2d862010-11-12 02:50:30 +00003798 for (i=0; i < (ssize_t) (*image)->colors; i++)
cristy101ab702011-10-13 13:06:32 +00003799 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
cristy3ed852e2009-09-05 21:47:34 +00003800 {
cristy4c08aed2011-07-01 19:47:50 +00003801 (*image)->colormap[i].red=ScaleShortToQuantum(
3802 color.red);
cristy3ed852e2009-09-05 21:47:34 +00003803 (*image)->colormap[i].green=ScaleShortToQuantum(
3804 color.green);
3805 (*image)->colormap[i].blue=ScaleShortToQuantum(
3806 color.blue);
3807 }
3808 (void) SyncImage(*image);
3809 }
3810 break;
3811 }
3812 case FloodfillMethod:
3813 case FillToBorderMethod:
3814 {
3815 DrawInfo
3816 *draw_info;
3817
cristy4c08aed2011-07-01 19:47:50 +00003818 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003819 target;
3820
3821 /*
3822 Update color information using floodfill algorithm.
3823 */
cristy49e2d862010-11-12 02:50:30 +00003824 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3825 (ssize_t) y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003826 if (method == FillToBorderMethod)
3827 {
3828 target.red=(MagickRealType)
3829 ScaleShortToQuantum(border_color.red);
3830 target.green=(MagickRealType)
3831 ScaleShortToQuantum(border_color.green);
3832 target.blue=(MagickRealType)
3833 ScaleShortToQuantum(border_color.blue);
3834 }
3835 draw_info=CloneDrawInfo(resource_info->image_info,
3836 (DrawInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00003837 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3838 AllCompliance,&draw_info->fill,exception);
cristyd42d9952011-07-08 14:21:50 +00003839 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
3840 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
cristy189e84c2011-08-27 18:08:53 +00003841 MagickFalse : MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00003842 draw_info=DestroyDrawInfo(draw_info);
3843 break;
3844 }
3845 case ResetMethod:
3846 {
3847 /*
3848 Update color information using reset algorithm.
3849 */
cristy574cc262011-08-05 01:23:58 +00003850 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003851 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003852 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003853 {
cristy49e2d862010-11-12 02:50:30 +00003854 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3855 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003856 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003857 break;
3858 for (x=0; x < (int) (*image)->columns; x++)
3859 {
cristy4c08aed2011-07-01 19:47:50 +00003860 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3861 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3862 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristyed231572011-07-14 02:18:59 +00003863 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003864 }
cristy49e2d862010-11-12 02:50:30 +00003865 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003866 break;
3867 }
3868 break;
3869 }
3870 }
cristy49e2d862010-11-12 02:50:30 +00003871 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00003872 state&=(~UpdateConfigurationState);
3873 }
3874 } while ((state & ExitState) == 0);
3875 (void) XSelectInput(display,windows->image.id,
3876 windows->image.attributes.event_mask);
3877 XSetCursorState(display,windows,MagickFalse);
3878 (void) XFreeCursor(display,cursor);
3879 return(MagickTrue);
3880}
3881
3882/*
3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3884% %
3885% %
3886% %
3887+ X C o m p o s i t e I m a g e %
3888% %
3889% %
3890% %
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892%
3893% XCompositeImage() requests an image name from the user, reads the image and
3894% composites it with the X window image at a location the user chooses with
3895% the pointer.
3896%
3897% The format of the XCompositeImage method is:
3898%
3899% MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003900% XResourceInfo *resource_info,XWindows *windows,Image *image,
3901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003902%
3903% A description of each parameter follows:
3904%
3905% o display: Specifies a connection to an X server; returned from
3906% XOpenDisplay.
3907%
3908% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3909%
3910% o windows: Specifies a pointer to a XWindows structure.
3911%
3912% o image: the image; returned from ReadImage.
3913%
cristy051718b2011-08-28 22:49:25 +00003914% o exception: return any errors or warnings in this structure.
3915%
cristy3ed852e2009-09-05 21:47:34 +00003916*/
3917static MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003918 XResourceInfo *resource_info,XWindows *windows,Image *image,
3919 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003920{
3921 static char
3922 displacement_geometry[MaxTextExtent] = "30x30",
3923 filename[MaxTextExtent] = "\0";
3924
3925 static const char
3926 *CompositeMenu[] =
3927 {
3928 "Operators",
3929 "Dissolve",
3930 "Displace",
3931 "Help",
3932 "Dismiss",
3933 (char *) NULL
3934 };
3935
3936 static CompositeOperator
3937 compose = CopyCompositeOp;
3938
3939 static const ModeType
3940 CompositeCommands[] =
3941 {
3942 CompositeOperatorsCommand,
3943 CompositeDissolveCommand,
3944 CompositeDisplaceCommand,
3945 CompositeHelpCommand,
3946 CompositeDismissCommand
3947 };
3948
3949 char
3950 text[MaxTextExtent];
3951
3952 Cursor
3953 cursor;
3954
3955 Image
3956 *composite_image;
3957
3958 int
3959 entry,
3960 id,
3961 x,
3962 y;
3963
3964 MagickRealType
3965 blend,
3966 scale_factor;
3967
3968 RectangleInfo
3969 highlight_info,
3970 composite_info;
3971
3972 unsigned int
3973 height,
3974 width;
3975
cristybb503372010-05-27 20:51:26 +00003976 size_t
cristy3ed852e2009-09-05 21:47:34 +00003977 state;
3978
3979 XEvent
3980 event;
3981
3982 /*
3983 Request image file name from user.
3984 */
3985 XFileBrowserWidget(display,windows,"Composite",filename);
3986 if (*filename == '\0')
3987 return(MagickTrue);
3988 /*
3989 Read image.
3990 */
3991 XSetCursorState(display,windows,MagickTrue);
3992 XCheckRefreshWindows(display,windows);
3993 (void) CopyMagickString(resource_info->image_info->filename,filename,
3994 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00003995 composite_image=ReadImage(resource_info->image_info,exception);
3996 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00003997 XSetCursorState(display,windows,MagickFalse);
3998 if (composite_image == (Image *) NULL)
3999 return(MagickFalse);
4000 /*
4001 Map Command widget.
4002 */
4003 (void) CloneString(&windows->command.name,"Composite");
4004 windows->command.data=1;
4005 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
4006 (void) XMapRaised(display,windows->command.id);
4007 XClientMessage(display,windows->image.id,windows->im_protocols,
4008 windows->im_update_widget,CurrentTime);
4009 /*
4010 Track pointer until button 1 is pressed.
4011 */
4012 XQueryPosition(display,windows->image.id,&x,&y);
4013 (void) XSelectInput(display,windows->image.id,
4014 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004015 composite_info.x=(ssize_t) windows->image.x+x;
4016 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004017 composite_info.width=0;
4018 composite_info.height=0;
4019 cursor=XCreateFontCursor(display,XC_ul_angle);
4020 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4021 blend=0.0;
4022 state=DefaultState;
4023 do
4024 {
4025 if (windows->info.mapped != MagickFalse)
4026 {
4027 /*
4028 Display pointer position.
4029 */
cristyb51dff52011-05-19 16:55:47 +00004030 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004031 (long) composite_info.x,(long) composite_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004032 XInfoWidget(display,windows,text);
4033 }
4034 highlight_info=composite_info;
4035 highlight_info.x=composite_info.x-windows->image.x;
4036 highlight_info.y=composite_info.y-windows->image.y;
4037 XHighlightRectangle(display,windows->image.id,
4038 windows->image.highlight_context,&highlight_info);
4039 /*
4040 Wait for next event.
4041 */
4042 XScreenEvent(display,windows,&event);
4043 XHighlightRectangle(display,windows->image.id,
4044 windows->image.highlight_context,&highlight_info);
4045 if (event.xany.window == windows->command.id)
4046 {
4047 /*
4048 Select a command from the Command widget.
4049 */
4050 id=XCommandWidget(display,windows,CompositeMenu,&event);
4051 if (id < 0)
4052 continue;
4053 switch (CompositeCommands[id])
4054 {
4055 case CompositeOperatorsCommand:
4056 {
4057 char
4058 command[MaxTextExtent],
4059 **operators;
4060
4061 /*
4062 Select a command from the pop-up menu.
4063 */
cristy042ee782011-04-22 18:48:30 +00004064 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +00004065 if (operators == (char **) NULL)
4066 break;
4067 entry=XMenuWidget(display,windows,CompositeMenu[id],
4068 (const char **) operators,command);
4069 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00004070 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +00004071 MagickComposeOptions,MagickFalse,operators[entry]);
4072 operators=DestroyStringList(operators);
4073 break;
4074 }
4075 case CompositeDissolveCommand:
4076 {
4077 static char
4078 factor[MaxTextExtent] = "20.0";
4079
4080 /*
4081 Dissolve the two images a given percent.
4082 */
4083 (void) XSetFunction(display,windows->image.highlight_context,
4084 GXcopy);
4085 (void) XDialogWidget(display,windows,"Dissolve",
4086 "Enter the blend factor (0.0 - 99.9%):",factor);
4087 (void) XSetFunction(display,windows->image.highlight_context,
4088 GXinvert);
4089 if (*factor == '\0')
4090 break;
cristyc1acd842011-05-19 23:05:47 +00004091 blend=InterpretLocaleValue(factor,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004092 compose=DissolveCompositeOp;
4093 break;
4094 }
4095 case CompositeDisplaceCommand:
4096 {
4097 /*
4098 Get horizontal and vertical scale displacement geometry.
4099 */
4100 (void) XSetFunction(display,windows->image.highlight_context,
4101 GXcopy);
4102 (void) XDialogWidget(display,windows,"Displace",
4103 "Enter the horizontal and vertical scale:",displacement_geometry);
4104 (void) XSetFunction(display,windows->image.highlight_context,
4105 GXinvert);
4106 if (*displacement_geometry == '\0')
4107 break;
4108 compose=DisplaceCompositeOp;
4109 break;
4110 }
4111 case CompositeHelpCommand:
4112 {
4113 (void) XSetFunction(display,windows->image.highlight_context,
4114 GXcopy);
4115 XTextViewWidget(display,resource_info,windows,MagickFalse,
4116 "Help Viewer - Image Composite",ImageCompositeHelp);
4117 (void) XSetFunction(display,windows->image.highlight_context,
4118 GXinvert);
4119 break;
4120 }
4121 case CompositeDismissCommand:
4122 {
4123 /*
4124 Prematurely exit.
4125 */
4126 state|=EscapeState;
4127 state|=ExitState;
4128 break;
4129 }
4130 default:
4131 break;
4132 }
4133 continue;
4134 }
4135 switch (event.type)
4136 {
4137 case ButtonPress:
4138 {
4139 if (image->debug != MagickFalse)
4140 (void) LogMagickEvent(X11Event,GetMagickModule(),
4141 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4142 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4143 if (event.xbutton.button != Button1)
4144 break;
4145 if (event.xbutton.window != windows->image.id)
4146 break;
4147 /*
4148 Change cursor.
4149 */
4150 composite_info.width=composite_image->columns;
4151 composite_info.height=composite_image->rows;
4152 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004153 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4154 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004155 break;
4156 }
4157 case ButtonRelease:
4158 {
4159 if (image->debug != MagickFalse)
4160 (void) LogMagickEvent(X11Event,GetMagickModule(),
4161 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4162 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4163 if (event.xbutton.button != Button1)
4164 break;
4165 if (event.xbutton.window != windows->image.id)
4166 break;
4167 if ((composite_info.width != 0) && (composite_info.height != 0))
4168 {
4169 /*
4170 User has selected the location of the composite image.
4171 */
cristy49e2d862010-11-12 02:50:30 +00004172 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4173 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004174 state|=ExitState;
4175 }
4176 break;
4177 }
4178 case Expose:
4179 break;
4180 case KeyPress:
4181 {
4182 char
4183 command[MaxTextExtent];
4184
4185 KeySym
4186 key_symbol;
4187
4188 int
4189 length;
4190
4191 if (event.xkey.window != windows->image.id)
4192 break;
4193 /*
4194 Respond to a user key press.
4195 */
4196 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4197 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4198 *(command+length)='\0';
4199 if (image->debug != MagickFalse)
4200 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00004201 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +00004202 switch ((int) key_symbol)
4203 {
4204 case XK_Escape:
4205 case XK_F20:
4206 {
4207 /*
4208 Prematurely exit.
4209 */
4210 composite_image=DestroyImage(composite_image);
4211 state|=EscapeState;
4212 state|=ExitState;
4213 break;
4214 }
4215 case XK_F1:
4216 case XK_Help:
4217 {
4218 (void) XSetFunction(display,windows->image.highlight_context,
4219 GXcopy);
4220 XTextViewWidget(display,resource_info,windows,MagickFalse,
4221 "Help Viewer - Image Composite",ImageCompositeHelp);
4222 (void) XSetFunction(display,windows->image.highlight_context,
4223 GXinvert);
4224 break;
4225 }
4226 default:
4227 {
4228 (void) XBell(display,0);
4229 break;
4230 }
4231 }
4232 break;
4233 }
4234 case MotionNotify:
4235 {
4236 /*
4237 Map and unmap Info widget as text cursor crosses its boundaries.
4238 */
4239 x=event.xmotion.x;
4240 y=event.xmotion.y;
4241 if (windows->info.mapped != MagickFalse)
4242 {
4243 if ((x < (int) (windows->info.x+windows->info.width)) &&
4244 (y < (int) (windows->info.y+windows->info.height)))
4245 (void) XWithdrawWindow(display,windows->info.id,
4246 windows->info.screen);
4247 }
4248 else
4249 if ((x > (int) (windows->info.x+windows->info.width)) ||
4250 (y > (int) (windows->info.y+windows->info.height)))
4251 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004252 composite_info.x=(ssize_t) windows->image.x+x;
4253 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004254 break;
4255 }
4256 default:
4257 {
4258 if (image->debug != MagickFalse)
4259 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4260 event.type);
4261 break;
4262 }
4263 }
4264 } while ((state & ExitState) == 0);
4265 (void) XSelectInput(display,windows->image.id,
4266 windows->image.attributes.event_mask);
4267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4268 XSetCursorState(display,windows,MagickFalse);
4269 (void) XFreeCursor(display,cursor);
4270 if ((state & EscapeState) != 0)
4271 return(MagickTrue);
4272 /*
4273 Image compositing is relative to image configuration.
4274 */
4275 XSetCursorState(display,windows,MagickTrue);
4276 XCheckRefreshWindows(display,windows);
4277 width=(unsigned int) image->columns;
4278 height=(unsigned int) image->rows;
4279 x=0;
4280 y=0;
4281 if (windows->image.crop_geometry != (char *) NULL)
4282 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4283 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4284 composite_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00004285 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004286 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4287 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4288 composite_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00004289 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004290 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4291 if ((composite_info.width != composite_image->columns) ||
4292 (composite_info.height != composite_image->rows))
4293 {
4294 Image
4295 *resize_image;
4296
4297 /*
4298 Scale composite image.
4299 */
cristy15b98cd2010-09-12 19:42:50 +00004300 resize_image=ResizeImage(composite_image,composite_info.width,
4301 composite_info.height,composite_image->filter,composite_image->blur,
cristy051718b2011-08-28 22:49:25 +00004302 exception);
cristy3ed852e2009-09-05 21:47:34 +00004303 composite_image=DestroyImage(composite_image);
4304 if (resize_image == (Image *) NULL)
4305 {
4306 XSetCursorState(display,windows,MagickFalse);
4307 return(MagickFalse);
4308 }
4309 composite_image=resize_image;
4310 }
4311 if (compose == DisplaceCompositeOp)
4312 (void) SetImageArtifact(composite_image,"compose:args",
4313 displacement_geometry);
4314 if (blend != 0.0)
4315 {
cristy49e2d862010-11-12 02:50:30 +00004316 CacheView
4317 *image_view;
4318
cristy3ed852e2009-09-05 21:47:34 +00004319 int
4320 y;
4321
4322 Quantum
4323 opacity;
4324
4325 register int
4326 x;
4327
cristy4c08aed2011-07-01 19:47:50 +00004328 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004329 *q;
4330
4331 /*
4332 Create mattes for blending.
4333 */
cristy63240882011-08-05 19:05:27 +00004334 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00004335 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
cristybb503372010-05-27 20:51:26 +00004336 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
cristy574cc262011-08-05 01:23:58 +00004337 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004338 return(MagickFalse);
4339 image->matte=MagickTrue;
cristy49e2d862010-11-12 02:50:30 +00004340 image_view=AcquireCacheView(image);
4341 for (y=0; y < (int) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004342 {
cristy49e2d862010-11-12 02:50:30 +00004343 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4344 exception);
cristy4c08aed2011-07-01 19:47:50 +00004345 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004346 break;
4347 for (x=0; x < (int) image->columns; x++)
4348 {
cristy4c08aed2011-07-01 19:47:50 +00004349 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00004350 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004351 }
cristy49e2d862010-11-12 02:50:30 +00004352 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004353 break;
4354 }
cristy49e2d862010-11-12 02:50:30 +00004355 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00004356 }
4357 /*
4358 Composite image with X Image window.
4359 */
4360 (void) CompositeImage(image,compose,composite_image,composite_info.x,
cristye941a752011-10-15 01:52:48 +00004361 composite_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +00004362 composite_image=DestroyImage(composite_image);
4363 XSetCursorState(display,windows,MagickFalse);
4364 /*
4365 Update image configuration.
4366 */
4367 XConfigureImageColormap(display,resource_info,windows,image);
cristy051718b2011-08-28 22:49:25 +00004368 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00004369 return(MagickTrue);
4370}
4371
4372/*
4373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4374% %
4375% %
4376% %
4377+ X C o n f i g u r e I m a g e %
4378% %
4379% %
4380% %
4381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4382%
4383% XConfigureImage() creates a new X image. It also notifies the window
4384% manager of the new image size and configures the transient widows.
4385%
4386% The format of the XConfigureImage method is:
4387%
4388% MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004389% XResourceInfo *resource_info,XWindows *windows,Image *image,
4390% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004391%
4392% A description of each parameter follows:
4393%
4394% o display: Specifies a connection to an X server; returned from
4395% XOpenDisplay.
4396%
4397% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4398%
4399% o windows: Specifies a pointer to a XWindows structure.
4400%
4401% o image: the image.
4402%
cristy051718b2011-08-28 22:49:25 +00004403% o exception: return any errors or warnings in this structure.
4404%
4405% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00004406%
4407*/
4408static MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004409 XResourceInfo *resource_info,XWindows *windows,Image *image,
4410 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004411{
4412 char
4413 geometry[MaxTextExtent];
4414
cristy3ed852e2009-09-05 21:47:34 +00004415 MagickStatusType
4416 status;
4417
cristybb503372010-05-27 20:51:26 +00004418 size_t
cristy3ed852e2009-09-05 21:47:34 +00004419 mask,
4420 height,
4421 width;
4422
cristy9d314ff2011-03-09 01:30:28 +00004423 ssize_t
4424 x,
4425 y;
4426
cristy3ed852e2009-09-05 21:47:34 +00004427 XSizeHints
4428 *size_hints;
4429
4430 XWindowChanges
4431 window_changes;
4432
4433 /*
4434 Dismiss if window dimensions are zero.
4435 */
4436 width=(unsigned int) windows->image.window_changes.width;
4437 height=(unsigned int) windows->image.window_changes.height;
4438 if (image->debug != MagickFalse)
4439 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00004440 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4441 windows->image.ximage->height,(double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00004442 if ((width*height) == 0)
4443 return(MagickTrue);
4444 x=0;
4445 y=0;
4446 /*
4447 Resize image to fit Image window dimensions.
4448 */
4449 XSetCursorState(display,windows,MagickTrue);
4450 (void) XFlush(display);
4451 if (((int) width != windows->image.ximage->width) ||
4452 ((int) height != windows->image.ximage->height))
4453 image->taint=MagickTrue;
4454 windows->magnify.x=(int)
4455 width*windows->magnify.x/windows->image.ximage->width;
4456 windows->magnify.y=(int)
4457 height*windows->magnify.y/windows->image.ximage->height;
4458 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4459 windows->image.y=(int)
4460 (height*windows->image.y/windows->image.ximage->height);
4461 status=XMakeImage(display,resource_info,&windows->image,image,
cristy051718b2011-08-28 22:49:25 +00004462 (unsigned int) width,(unsigned int) height,exception);
cristy3ed852e2009-09-05 21:47:34 +00004463 if (status == MagickFalse)
4464 XNoticeWidget(display,windows,"Unable to configure X image:",
4465 windows->image.name);
4466 /*
4467 Notify window manager of the new configuration.
4468 */
4469 if (resource_info->image_geometry != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00004470 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
cristy3ed852e2009-09-05 21:47:34 +00004471 resource_info->image_geometry);
4472 else
cristyb51dff52011-05-19 16:55:47 +00004473 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +00004474 XDisplayWidth(display,windows->image.screen),
4475 XDisplayHeight(display,windows->image.screen));
4476 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4477 window_changes.width=(int) width;
4478 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4479 window_changes.width=XDisplayWidth(display,windows->image.screen);
4480 window_changes.height=(int) height;
4481 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4482 window_changes.height=XDisplayHeight(display,windows->image.screen);
cristybb503372010-05-27 20:51:26 +00004483 mask=(size_t) (CWWidth | CWHeight);
cristy3ed852e2009-09-05 21:47:34 +00004484 if (resource_info->backdrop)
4485 {
4486 mask|=CWX | CWY;
4487 window_changes.x=(int)
4488 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4489 window_changes.y=(int)
4490 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4491 }
4492 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4493 (unsigned int) mask,&window_changes);
4494 (void) XClearWindow(display,windows->image.id);
4495 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4496 /*
4497 Update Magnify window configuration.
4498 */
4499 if (windows->magnify.mapped != MagickFalse)
4500 XMakeMagnifyImage(display,windows);
4501 windows->pan.crop_geometry=windows->image.crop_geometry;
4502 XBestIconSize(display,&windows->pan,image);
4503 while (((windows->pan.width << 1) < MaxIconSize) &&
4504 ((windows->pan.height << 1) < MaxIconSize))
4505 {
4506 windows->pan.width<<=1;
4507 windows->pan.height<<=1;
4508 }
4509 if (windows->pan.geometry != (char *) NULL)
4510 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4511 &windows->pan.width,&windows->pan.height);
4512 window_changes.width=(int) windows->pan.width;
4513 window_changes.height=(int) windows->pan.height;
4514 size_hints=XAllocSizeHints();
4515 if (size_hints != (XSizeHints *) NULL)
4516 {
4517 /*
4518 Set new size hints.
4519 */
4520 size_hints->flags=PSize | PMinSize | PMaxSize;
4521 size_hints->width=window_changes.width;
4522 size_hints->height=window_changes.height;
4523 size_hints->min_width=size_hints->width;
4524 size_hints->min_height=size_hints->height;
4525 size_hints->max_width=size_hints->width;
4526 size_hints->max_height=size_hints->height;
4527 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4528 (void) XFree((void *) size_hints);
4529 }
4530 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4531 (unsigned int) (CWWidth | CWHeight),&window_changes);
4532 /*
4533 Update icon window configuration.
4534 */
4535 windows->icon.crop_geometry=windows->image.crop_geometry;
4536 XBestIconSize(display,&windows->icon,image);
4537 window_changes.width=(int) windows->icon.width;
4538 window_changes.height=(int) windows->icon.height;
4539 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4540 (unsigned int) (CWWidth | CWHeight),&window_changes);
4541 XSetCursorState(display,windows,MagickFalse);
4542 return(status != 0 ? MagickTrue : MagickFalse);
4543}
4544
4545/*
4546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4547% %
4548% %
4549% %
4550+ X C r o p I m a g e %
4551% %
4552% %
4553% %
4554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555%
4556% XCropImage() allows the user to select a region of the image and crop, copy,
4557% or cut it. For copy or cut, the image can subsequently be composited onto
4558% the image with XPasteImage.
4559%
4560% The format of the XCropImage method is:
4561%
4562% MagickBooleanType XCropImage(Display *display,
4563% XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004564% const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004565%
4566% A description of each parameter follows:
4567%
4568% o display: Specifies a connection to an X server; returned from
4569% XOpenDisplay.
4570%
4571% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4572%
4573% o windows: Specifies a pointer to a XWindows structure.
4574%
4575% o image: the image; returned from ReadImage.
4576%
4577% o mode: This unsigned value specified whether the image should be
4578% cropped, copied, or cut.
4579%
cristy051718b2011-08-28 22:49:25 +00004580% o exception: return any errors or warnings in this structure.
4581%
cristy3ed852e2009-09-05 21:47:34 +00004582*/
4583static MagickBooleanType XCropImage(Display *display,
4584 XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004585 const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004586{
4587 static const char
4588 *CropModeMenu[] =
4589 {
4590 "Help",
4591 "Dismiss",
4592 (char *) NULL
4593 },
4594 *RectifyModeMenu[] =
4595 {
4596 "Crop",
4597 "Help",
4598 "Dismiss",
4599 (char *) NULL
4600 };
4601
4602 static const ModeType
4603 CropCommands[] =
4604 {
4605 CropHelpCommand,
4606 CropDismissCommand
4607 },
4608 RectifyCommands[] =
4609 {
4610 RectifyCopyCommand,
4611 RectifyHelpCommand,
4612 RectifyDismissCommand
4613 };
4614
cristy49e2d862010-11-12 02:50:30 +00004615 CacheView
4616 *image_view;
4617
cristy3ed852e2009-09-05 21:47:34 +00004618 char
4619 command[MaxTextExtent],
4620 text[MaxTextExtent];
4621
4622 Cursor
4623 cursor;
4624
cristy3ed852e2009-09-05 21:47:34 +00004625 int
4626 id,
4627 x,
4628 y;
4629
4630 KeySym
4631 key_symbol;
4632
4633 Image
4634 *crop_image;
4635
4636 MagickRealType
4637 scale_factor;
4638
4639 RectangleInfo
4640 crop_info,
4641 highlight_info;
4642
cristy4c08aed2011-07-01 19:47:50 +00004643 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004644 *q;
4645
4646 unsigned int
4647 height,
4648 width;
4649
cristybb503372010-05-27 20:51:26 +00004650 size_t
cristy3ed852e2009-09-05 21:47:34 +00004651 state;
4652
4653 XEvent
4654 event;
4655
4656 /*
4657 Map Command widget.
4658 */
4659 switch (mode)
4660 {
4661 case CopyMode:
4662 {
4663 (void) CloneString(&windows->command.name,"Copy");
4664 break;
4665 }
4666 case CropMode:
4667 {
4668 (void) CloneString(&windows->command.name,"Crop");
4669 break;
4670 }
4671 case CutMode:
4672 {
4673 (void) CloneString(&windows->command.name,"Cut");
4674 break;
4675 }
4676 }
4677 RectifyModeMenu[0]=windows->command.name;
4678 windows->command.data=0;
4679 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4680 (void) XMapRaised(display,windows->command.id);
4681 XClientMessage(display,windows->image.id,windows->im_protocols,
4682 windows->im_update_widget,CurrentTime);
4683 /*
4684 Track pointer until button 1 is pressed.
4685 */
4686 XQueryPosition(display,windows->image.id,&x,&y);
4687 (void) XSelectInput(display,windows->image.id,
4688 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004689 crop_info.x=(ssize_t) windows->image.x+x;
4690 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004691 crop_info.width=0;
4692 crop_info.height=0;
4693 cursor=XCreateFontCursor(display,XC_fleur);
4694 state=DefaultState;
4695 do
4696 {
4697 if (windows->info.mapped != MagickFalse)
4698 {
4699 /*
4700 Display pointer position.
4701 */
cristyb51dff52011-05-19 16:55:47 +00004702 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004703 (long) crop_info.x,(long) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004704 XInfoWidget(display,windows,text);
4705 }
4706 /*
4707 Wait for next event.
4708 */
4709 XScreenEvent(display,windows,&event);
4710 if (event.xany.window == windows->command.id)
4711 {
4712 /*
4713 Select a command from the Command widget.
4714 */
4715 id=XCommandWidget(display,windows,CropModeMenu,&event);
4716 if (id < 0)
4717 continue;
4718 switch (CropCommands[id])
4719 {
4720 case CropHelpCommand:
4721 {
4722 switch (mode)
4723 {
4724 case CopyMode:
4725 {
4726 XTextViewWidget(display,resource_info,windows,MagickFalse,
4727 "Help Viewer - Image Copy",ImageCopyHelp);
4728 break;
4729 }
4730 case CropMode:
4731 {
4732 XTextViewWidget(display,resource_info,windows,MagickFalse,
4733 "Help Viewer - Image Crop",ImageCropHelp);
4734 break;
4735 }
4736 case CutMode:
4737 {
4738 XTextViewWidget(display,resource_info,windows,MagickFalse,
4739 "Help Viewer - Image Cut",ImageCutHelp);
4740 break;
4741 }
4742 }
4743 break;
4744 }
4745 case CropDismissCommand:
4746 {
4747 /*
4748 Prematurely exit.
4749 */
4750 state|=EscapeState;
4751 state|=ExitState;
4752 break;
4753 }
4754 default:
4755 break;
4756 }
4757 continue;
4758 }
4759 switch (event.type)
4760 {
4761 case ButtonPress:
4762 {
4763 if (event.xbutton.button != Button1)
4764 break;
4765 if (event.xbutton.window != windows->image.id)
4766 break;
4767 /*
4768 Note first corner of cropping rectangle-- exit loop.
4769 */
4770 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004771 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4772 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004773 state|=ExitState;
4774 break;
4775 }
4776 case ButtonRelease:
4777 break;
4778 case Expose:
4779 break;
4780 case KeyPress:
4781 {
4782 if (event.xkey.window != windows->image.id)
4783 break;
4784 /*
4785 Respond to a user key press.
4786 */
4787 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4788 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4789 switch ((int) key_symbol)
4790 {
4791 case XK_Escape:
4792 case XK_F20:
4793 {
4794 /*
4795 Prematurely exit.
4796 */
4797 state|=EscapeState;
4798 state|=ExitState;
4799 break;
4800 }
4801 case XK_F1:
4802 case XK_Help:
4803 {
4804 switch (mode)
4805 {
4806 case CopyMode:
4807 {
4808 XTextViewWidget(display,resource_info,windows,MagickFalse,
4809 "Help Viewer - Image Copy",ImageCopyHelp);
4810 break;
4811 }
4812 case CropMode:
4813 {
4814 XTextViewWidget(display,resource_info,windows,MagickFalse,
4815 "Help Viewer - Image Crop",ImageCropHelp);
4816 break;
4817 }
4818 case CutMode:
4819 {
4820 XTextViewWidget(display,resource_info,windows,MagickFalse,
4821 "Help Viewer - Image Cut",ImageCutHelp);
4822 break;
4823 }
4824 }
4825 break;
4826 }
4827 default:
4828 {
4829 (void) XBell(display,0);
4830 break;
4831 }
4832 }
4833 break;
4834 }
4835 case MotionNotify:
4836 {
4837 if (event.xmotion.window != windows->image.id)
4838 break;
4839 /*
4840 Map and unmap Info widget as text cursor crosses its boundaries.
4841 */
4842 x=event.xmotion.x;
4843 y=event.xmotion.y;
4844 if (windows->info.mapped != MagickFalse)
4845 {
4846 if ((x < (int) (windows->info.x+windows->info.width)) &&
4847 (y < (int) (windows->info.y+windows->info.height)))
4848 (void) XWithdrawWindow(display,windows->info.id,
4849 windows->info.screen);
4850 }
4851 else
4852 if ((x > (int) (windows->info.x+windows->info.width)) ||
4853 (y > (int) (windows->info.y+windows->info.height)))
4854 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004855 crop_info.x=(ssize_t) windows->image.x+x;
4856 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004857 break;
4858 }
4859 default:
4860 break;
4861 }
4862 } while ((state & ExitState) == 0);
4863 (void) XSelectInput(display,windows->image.id,
4864 windows->image.attributes.event_mask);
4865 if ((state & EscapeState) != 0)
4866 {
4867 /*
4868 User want to exit without cropping.
4869 */
4870 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4871 (void) XFreeCursor(display,cursor);
4872 return(MagickTrue);
4873 }
4874 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4875 do
4876 {
4877 /*
4878 Size rectangle as pointer moves until the mouse button is released.
4879 */
4880 x=(int) crop_info.x;
4881 y=(int) crop_info.y;
4882 crop_info.width=0;
4883 crop_info.height=0;
4884 state=DefaultState;
4885 do
4886 {
4887 highlight_info=crop_info;
4888 highlight_info.x=crop_info.x-windows->image.x;
4889 highlight_info.y=crop_info.y-windows->image.y;
4890 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4891 {
4892 /*
4893 Display info and draw cropping rectangle.
4894 */
4895 if (windows->info.mapped == MagickFalse)
4896 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00004897 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004898 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004899 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004900 XInfoWidget(display,windows,text);
4901 XHighlightRectangle(display,windows->image.id,
4902 windows->image.highlight_context,&highlight_info);
4903 }
4904 else
4905 if (windows->info.mapped != MagickFalse)
4906 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4907 /*
4908 Wait for next event.
4909 */
4910 XScreenEvent(display,windows,&event);
4911 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4912 XHighlightRectangle(display,windows->image.id,
4913 windows->image.highlight_context,&highlight_info);
4914 switch (event.type)
4915 {
4916 case ButtonPress:
4917 {
cristy49e2d862010-11-12 02:50:30 +00004918 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4919 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004920 break;
4921 }
4922 case ButtonRelease:
4923 {
4924 /*
4925 User has committed to cropping rectangle.
4926 */
cristy49e2d862010-11-12 02:50:30 +00004927 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4928 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004929 XSetCursorState(display,windows,MagickFalse);
4930 state|=ExitState;
4931 windows->command.data=0;
4932 (void) XCommandWidget(display,windows,RectifyModeMenu,
4933 (XEvent *) NULL);
4934 break;
4935 }
4936 case Expose:
4937 break;
4938 case MotionNotify:
4939 {
cristy49e2d862010-11-12 02:50:30 +00004940 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4941 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00004942 }
4943 default:
4944 break;
4945 }
4946 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4947 ((state & ExitState) != 0))
4948 {
4949 /*
4950 Check boundary conditions.
4951 */
4952 if (crop_info.x < 0)
4953 crop_info.x=0;
4954 else
cristy49e2d862010-11-12 02:50:30 +00004955 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4956 crop_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004957 if ((int) crop_info.x < x)
4958 crop_info.width=(unsigned int) (x-crop_info.x);
4959 else
4960 {
4961 crop_info.width=(unsigned int) (crop_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00004962 crop_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00004963 }
4964 if (crop_info.y < 0)
4965 crop_info.y=0;
4966 else
cristy49e2d862010-11-12 02:50:30 +00004967 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4968 crop_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004969 if ((int) crop_info.y < y)
4970 crop_info.height=(unsigned int) (y-crop_info.y);
4971 else
4972 {
4973 crop_info.height=(unsigned int) (crop_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00004974 crop_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00004975 }
4976 }
4977 } while ((state & ExitState) == 0);
4978 /*
4979 Wait for user to grab a corner of the rectangle or press return.
4980 */
4981 state=DefaultState;
4982 (void) XMapWindow(display,windows->info.id);
4983 do
4984 {
4985 if (windows->info.mapped != MagickFalse)
4986 {
4987 /*
4988 Display pointer position.
4989 */
cristyb51dff52011-05-19 16:55:47 +00004990 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004991 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004992 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004993 XInfoWidget(display,windows,text);
4994 }
4995 highlight_info=crop_info;
4996 highlight_info.x=crop_info.x-windows->image.x;
4997 highlight_info.y=crop_info.y-windows->image.y;
4998 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4999 {
5000 state|=EscapeState;
5001 state|=ExitState;
5002 break;
5003 }
5004 XHighlightRectangle(display,windows->image.id,
5005 windows->image.highlight_context,&highlight_info);
5006 XScreenEvent(display,windows,&event);
5007 if (event.xany.window == windows->command.id)
5008 {
5009 /*
5010 Select a command from the Command widget.
5011 */
5012 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5013 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
5014 (void) XSetFunction(display,windows->image.highlight_context,
5015 GXinvert);
5016 XHighlightRectangle(display,windows->image.id,
5017 windows->image.highlight_context,&highlight_info);
5018 if (id >= 0)
5019 switch (RectifyCommands[id])
5020 {
5021 case RectifyCopyCommand:
5022 {
5023 state|=ExitState;
5024 break;
5025 }
5026 case RectifyHelpCommand:
5027 {
5028 (void) XSetFunction(display,windows->image.highlight_context,
5029 GXcopy);
5030 switch (mode)
5031 {
5032 case CopyMode:
5033 {
5034 XTextViewWidget(display,resource_info,windows,MagickFalse,
5035 "Help Viewer - Image Copy",ImageCopyHelp);
5036 break;
5037 }
5038 case CropMode:
5039 {
5040 XTextViewWidget(display,resource_info,windows,MagickFalse,
5041 "Help Viewer - Image Crop",ImageCropHelp);
5042 break;
5043 }
5044 case CutMode:
5045 {
5046 XTextViewWidget(display,resource_info,windows,MagickFalse,
5047 "Help Viewer - Image Cut",ImageCutHelp);
5048 break;
5049 }
5050 }
5051 (void) XSetFunction(display,windows->image.highlight_context,
5052 GXinvert);
5053 break;
5054 }
5055 case RectifyDismissCommand:
5056 {
5057 /*
5058 Prematurely exit.
5059 */
5060 state|=EscapeState;
5061 state|=ExitState;
5062 break;
5063 }
5064 default:
5065 break;
5066 }
5067 continue;
5068 }
5069 XHighlightRectangle(display,windows->image.id,
5070 windows->image.highlight_context,&highlight_info);
5071 switch (event.type)
5072 {
5073 case ButtonPress:
5074 {
5075 if (event.xbutton.button != Button1)
5076 break;
5077 if (event.xbutton.window != windows->image.id)
5078 break;
5079 x=windows->image.x+event.xbutton.x;
5080 y=windows->image.y+event.xbutton.y;
5081 if ((x < (int) (crop_info.x+RoiDelta)) &&
5082 (x > (int) (crop_info.x-RoiDelta)) &&
5083 (y < (int) (crop_info.y+RoiDelta)) &&
5084 (y > (int) (crop_info.y-RoiDelta)))
5085 {
cristybb503372010-05-27 20:51:26 +00005086 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5087 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005088 state|=UpdateConfigurationState;
5089 break;
5090 }
5091 if ((x < (int) (crop_info.x+RoiDelta)) &&
5092 (x > (int) (crop_info.x-RoiDelta)) &&
5093 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5094 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5095 {
cristybb503372010-05-27 20:51:26 +00005096 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
cristy3ed852e2009-09-05 21:47:34 +00005097 state|=UpdateConfigurationState;
5098 break;
5099 }
5100 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5101 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5102 (y < (int) (crop_info.y+RoiDelta)) &&
5103 (y > (int) (crop_info.y-RoiDelta)))
5104 {
cristybb503372010-05-27 20:51:26 +00005105 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005106 state|=UpdateConfigurationState;
5107 break;
5108 }
5109 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5110 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5111 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5112 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5113 {
5114 state|=UpdateConfigurationState;
5115 break;
5116 }
5117 }
5118 case ButtonRelease:
5119 {
5120 if (event.xbutton.window == windows->pan.id)
5121 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5122 (highlight_info.y != crop_info.y-windows->image.y))
5123 XHighlightRectangle(display,windows->image.id,
5124 windows->image.highlight_context,&highlight_info);
5125 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5126 event.xbutton.time);
5127 break;
5128 }
5129 case Expose:
5130 {
5131 if (event.xexpose.window == windows->image.id)
5132 if (event.xexpose.count == 0)
5133 {
5134 event.xexpose.x=(int) highlight_info.x;
5135 event.xexpose.y=(int) highlight_info.y;
5136 event.xexpose.width=(int) highlight_info.width;
5137 event.xexpose.height=(int) highlight_info.height;
5138 XRefreshWindow(display,&windows->image,&event);
5139 }
5140 if (event.xexpose.window == windows->info.id)
5141 if (event.xexpose.count == 0)
5142 XInfoWidget(display,windows,text);
5143 break;
5144 }
5145 case KeyPress:
5146 {
5147 if (event.xkey.window != windows->image.id)
5148 break;
5149 /*
5150 Respond to a user key press.
5151 */
5152 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5153 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5154 switch ((int) key_symbol)
5155 {
5156 case XK_Escape:
5157 case XK_F20:
5158 state|=EscapeState;
5159 case XK_Return:
5160 {
5161 state|=ExitState;
5162 break;
5163 }
5164 case XK_Home:
5165 case XK_KP_Home:
5166 {
cristy49e2d862010-11-12 02:50:30 +00005167 crop_info.x=(ssize_t) (windows->image.width/2L-
5168 crop_info.width/2L);
5169 crop_info.y=(ssize_t) (windows->image.height/2L-
5170 crop_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +00005171 break;
5172 }
5173 case XK_Left:
5174 case XK_KP_Left:
5175 {
5176 crop_info.x--;
5177 break;
5178 }
5179 case XK_Up:
5180 case XK_KP_Up:
5181 case XK_Next:
5182 {
5183 crop_info.y--;
5184 break;
5185 }
5186 case XK_Right:
5187 case XK_KP_Right:
5188 {
5189 crop_info.x++;
5190 break;
5191 }
5192 case XK_Prior:
5193 case XK_Down:
5194 case XK_KP_Down:
5195 {
5196 crop_info.y++;
5197 break;
5198 }
5199 case XK_F1:
5200 case XK_Help:
5201 {
5202 (void) XSetFunction(display,windows->image.highlight_context,
5203 GXcopy);
5204 switch (mode)
5205 {
5206 case CopyMode:
5207 {
5208 XTextViewWidget(display,resource_info,windows,MagickFalse,
5209 "Help Viewer - Image Copy",ImageCopyHelp);
5210 break;
5211 }
5212 case CropMode:
5213 {
5214 XTextViewWidget(display,resource_info,windows,MagickFalse,
5215 "Help Viewer - Image Cropg",ImageCropHelp);
5216 break;
5217 }
5218 case CutMode:
5219 {
5220 XTextViewWidget(display,resource_info,windows,MagickFalse,
5221 "Help Viewer - Image Cutg",ImageCutHelp);
5222 break;
5223 }
5224 }
5225 (void) XSetFunction(display,windows->image.highlight_context,
5226 GXinvert);
5227 break;
5228 }
5229 default:
5230 {
5231 (void) XBell(display,0);
5232 break;
5233 }
5234 }
5235 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5236 event.xkey.time);
5237 break;
5238 }
5239 case KeyRelease:
5240 break;
5241 case MotionNotify:
5242 {
5243 if (event.xmotion.window != windows->image.id)
5244 break;
5245 /*
5246 Map and unmap Info widget as text cursor crosses its boundaries.
5247 */
5248 x=event.xmotion.x;
5249 y=event.xmotion.y;
5250 if (windows->info.mapped != MagickFalse)
5251 {
5252 if ((x < (int) (windows->info.x+windows->info.width)) &&
5253 (y < (int) (windows->info.y+windows->info.height)))
5254 (void) XWithdrawWindow(display,windows->info.id,
5255 windows->info.screen);
5256 }
5257 else
5258 if ((x > (int) (windows->info.x+windows->info.width)) ||
5259 (y > (int) (windows->info.y+windows->info.height)))
5260 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00005261 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5262 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00005263 break;
5264 }
5265 case SelectionRequest:
5266 {
5267 XSelectionEvent
5268 notify;
5269
5270 XSelectionRequestEvent
5271 *request;
5272
5273 /*
5274 Set primary selection.
5275 */
cristyb51dff52011-05-19 16:55:47 +00005276 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005277 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00005278 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005279 request=(&(event.xselectionrequest));
5280 (void) XChangeProperty(request->display,request->requestor,
5281 request->property,request->target,8,PropModeReplace,
5282 (unsigned char *) text,(int) strlen(text));
5283 notify.type=SelectionNotify;
5284 notify.display=request->display;
5285 notify.requestor=request->requestor;
5286 notify.selection=request->selection;
5287 notify.target=request->target;
5288 notify.time=request->time;
5289 if (request->property == None)
5290 notify.property=request->target;
5291 else
5292 notify.property=request->property;
5293 (void) XSendEvent(request->display,request->requestor,False,0,
5294 (XEvent *) &notify);
5295 }
5296 default:
5297 break;
5298 }
5299 if ((state & UpdateConfigurationState) != 0)
5300 {
5301 (void) XPutBackEvent(display,&event);
5302 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5303 break;
5304 }
5305 } while ((state & ExitState) == 0);
5306 } while ((state & ExitState) == 0);
5307 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5308 XSetCursorState(display,windows,MagickFalse);
5309 if ((state & EscapeState) != 0)
5310 return(MagickTrue);
5311 if (mode == CropMode)
5312 if (((int) crop_info.width != windows->image.ximage->width) ||
5313 ((int) crop_info.height != windows->image.ximage->height))
5314 {
5315 /*
5316 Reconfigure Image window as defined by cropping rectangle.
5317 */
5318 XSetCropGeometry(display,windows,&crop_info,image);
5319 windows->image.window_changes.width=(int) crop_info.width;
5320 windows->image.window_changes.height=(int) crop_info.height;
cristy051718b2011-08-28 22:49:25 +00005321 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005322 return(MagickTrue);
5323 }
5324 /*
5325 Copy image before applying image transforms.
5326 */
5327 XSetCursorState(display,windows,MagickTrue);
5328 XCheckRefreshWindows(display,windows);
5329 width=(unsigned int) image->columns;
5330 height=(unsigned int) image->rows;
5331 x=0;
5332 y=0;
5333 if (windows->image.crop_geometry != (char *) NULL)
5334 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5335 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5336 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00005337 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005338 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5339 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5340 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00005341 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005342 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +00005343 crop_image=CropImage(image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00005344 XSetCursorState(display,windows,MagickFalse);
5345 if (crop_image == (Image *) NULL)
5346 return(MagickFalse);
5347 if (resource_info->copy_image != (Image *) NULL)
5348 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5349 resource_info->copy_image=crop_image;
5350 if (mode == CopyMode)
5351 {
cristy051718b2011-08-28 22:49:25 +00005352 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005353 return(MagickTrue);
5354 }
5355 /*
5356 Cut image.
5357 */
cristy574cc262011-08-05 01:23:58 +00005358 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005359 return(MagickFalse);
5360 image->matte=MagickTrue;
cristy49e2d862010-11-12 02:50:30 +00005361 image_view=AcquireCacheView(image);
5362 for (y=0; y < (int) crop_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00005363 {
cristy49e2d862010-11-12 02:50:30 +00005364 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5365 crop_info.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00005366 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005367 break;
5368 for (x=0; x < (int) crop_info.width; x++)
5369 {
cristy4c08aed2011-07-01 19:47:50 +00005370 SetPixelAlpha(image,TransparentAlpha,q);
cristyed231572011-07-14 02:18:59 +00005371 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00005372 }
cristy49e2d862010-11-12 02:50:30 +00005373 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005374 break;
5375 }
cristy49e2d862010-11-12 02:50:30 +00005376 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00005377 /*
5378 Update image configuration.
5379 */
5380 XConfigureImageColormap(display,resource_info,windows,image);
cristy051718b2011-08-28 22:49:25 +00005381 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005382 return(MagickTrue);
5383}
5384
5385/*
5386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5387% %
5388% %
5389% %
5390+ X D r a w I m a g e %
5391% %
5392% %
5393% %
5394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5395%
5396% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5397% the image.
5398%
5399% The format of the XDrawEditImage method is:
5400%
5401% MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005402% XResourceInfo *resource_info,XWindows *windows,Image **image,
5403% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005404%
5405% A description of each parameter follows:
5406%
5407% o display: Specifies a connection to an X server; returned from
5408% XOpenDisplay.
5409%
5410% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5411%
5412% o windows: Specifies a pointer to a XWindows structure.
5413%
5414% o image: the image.
5415%
cristy051718b2011-08-28 22:49:25 +00005416% o exception: return any errors or warnings in this structure.
5417%
cristy3ed852e2009-09-05 21:47:34 +00005418*/
5419static MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005420 XResourceInfo *resource_info,XWindows *windows,Image **image,
5421 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005422{
5423 static const char
5424 *DrawMenu[] =
5425 {
5426 "Element",
5427 "Color",
5428 "Stipple",
5429 "Width",
5430 "Undo",
5431 "Help",
5432 "Dismiss",
5433 (char *) NULL
5434 };
5435
5436 static ElementType
5437 element = PointElement;
5438
5439 static const ModeType
5440 DrawCommands[] =
5441 {
5442 DrawElementCommand,
5443 DrawColorCommand,
5444 DrawStippleCommand,
5445 DrawWidthCommand,
5446 DrawUndoCommand,
5447 DrawHelpCommand,
5448 DrawDismissCommand
5449 };
5450
5451 static Pixmap
5452 stipple = (Pixmap) NULL;
5453
5454 static unsigned int
5455 pen_id = 0,
5456 line_width = 1;
5457
5458 char
5459 command[MaxTextExtent],
5460 text[MaxTextExtent];
5461
5462 Cursor
5463 cursor;
5464
5465 int
5466 entry,
5467 id,
5468 number_coordinates,
5469 x,
5470 y;
5471
5472 MagickRealType
5473 degrees;
5474
5475 MagickStatusType
5476 status;
5477
5478 RectangleInfo
5479 rectangle_info;
5480
5481 register int
5482 i;
5483
5484 unsigned int
5485 distance,
5486 height,
5487 max_coordinates,
5488 width;
5489
cristybb503372010-05-27 20:51:26 +00005490 size_t
cristy3ed852e2009-09-05 21:47:34 +00005491 state;
5492
5493 Window
5494 root_window;
5495
5496 XDrawInfo
5497 draw_info;
5498
5499 XEvent
5500 event;
5501
5502 XPoint
5503 *coordinate_info;
5504
5505 XSegment
5506 line_info;
5507
5508 /*
5509 Allocate polygon info.
5510 */
5511 max_coordinates=2048;
5512 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5513 sizeof(*coordinate_info));
5514 if (coordinate_info == (XPoint *) NULL)
5515 {
cristy051718b2011-08-28 22:49:25 +00005516 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00005517 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5518 return(MagickFalse);
5519 }
5520 /*
5521 Map Command widget.
5522 */
5523 (void) CloneString(&windows->command.name,"Draw");
5524 windows->command.data=4;
5525 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5526 (void) XMapRaised(display,windows->command.id);
5527 XClientMessage(display,windows->image.id,windows->im_protocols,
5528 windows->im_update_widget,CurrentTime);
5529 /*
5530 Wait for first button press.
5531 */
5532 root_window=XRootWindow(display,XDefaultScreen(display));
5533 draw_info.stencil=OpaqueStencil;
5534 status=MagickTrue;
5535 cursor=XCreateFontCursor(display,XC_tcross);
5536 for ( ; ; )
5537 {
5538 XQueryPosition(display,windows->image.id,&x,&y);
5539 (void) XSelectInput(display,windows->image.id,
5540 windows->image.attributes.event_mask | PointerMotionMask);
5541 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5542 state=DefaultState;
5543 do
5544 {
5545 if (windows->info.mapped != MagickFalse)
5546 {
5547 /*
5548 Display pointer position.
5549 */
cristyb51dff52011-05-19 16:55:47 +00005550 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00005551 x+windows->image.x,y+windows->image.y);
5552 XInfoWidget(display,windows,text);
5553 }
5554 /*
5555 Wait for next event.
5556 */
5557 XScreenEvent(display,windows,&event);
5558 if (event.xany.window == windows->command.id)
5559 {
5560 /*
5561 Select a command from the Command widget.
5562 */
5563 id=XCommandWidget(display,windows,DrawMenu,&event);
5564 if (id < 0)
5565 continue;
5566 switch (DrawCommands[id])
5567 {
5568 case DrawElementCommand:
5569 {
5570 static const char
5571 *Elements[] =
5572 {
5573 "point",
5574 "line",
5575 "rectangle",
5576 "fill rectangle",
5577 "circle",
5578 "fill circle",
5579 "ellipse",
5580 "fill ellipse",
5581 "polygon",
5582 "fill polygon",
5583 (char *) NULL,
5584 };
5585
5586 /*
5587 Select a command from the pop-up menu.
5588 */
5589 element=(ElementType) (XMenuWidget(display,windows,
5590 DrawMenu[id],Elements,command)+1);
5591 break;
5592 }
5593 case DrawColorCommand:
5594 {
5595 const char
5596 *ColorMenu[MaxNumberPens+1];
5597
5598 int
5599 pen_number;
5600
5601 MagickBooleanType
5602 transparent;
5603
5604 XColor
5605 color;
5606
5607 /*
5608 Initialize menu selections.
5609 */
5610 for (i=0; i < (int) (MaxNumberPens-2); i++)
5611 ColorMenu[i]=resource_info->pen_colors[i];
5612 ColorMenu[MaxNumberPens-2]="transparent";
5613 ColorMenu[MaxNumberPens-1]="Browser...";
5614 ColorMenu[MaxNumberPens]=(char *) NULL;
5615 /*
5616 Select a pen color from the pop-up menu.
5617 */
5618 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5619 (const char **) ColorMenu,command);
5620 if (pen_number < 0)
5621 break;
5622 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5623 MagickFalse;
5624 if (transparent != MagickFalse)
5625 {
5626 draw_info.stencil=TransparentStencil;
5627 break;
5628 }
5629 if (pen_number == (MaxNumberPens-1))
5630 {
5631 static char
5632 color_name[MaxTextExtent] = "gray";
5633
5634 /*
5635 Select a pen color from a dialog.
5636 */
5637 resource_info->pen_colors[pen_number]=color_name;
5638 XColorBrowserWidget(display,windows,"Select",color_name);
5639 if (*color_name == '\0')
5640 break;
5641 }
5642 /*
5643 Set pen color.
5644 */
5645 (void) XParseColor(display,windows->map_info->colormap,
5646 resource_info->pen_colors[pen_number],&color);
5647 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5648 (unsigned int) MaxColors,&color);
5649 windows->pixel_info->pen_colors[pen_number]=color;
5650 pen_id=(unsigned int) pen_number;
5651 draw_info.stencil=OpaqueStencil;
5652 break;
5653 }
5654 case DrawStippleCommand:
5655 {
5656 Image
5657 *stipple_image;
5658
5659 ImageInfo
5660 *image_info;
5661
5662 int
5663 status;
5664
5665 static char
5666 filename[MaxTextExtent] = "\0";
5667
5668 static const char
5669 *StipplesMenu[] =
5670 {
5671 "Brick",
5672 "Diagonal",
5673 "Scales",
5674 "Vertical",
5675 "Wavy",
5676 "Translucent",
5677 "Opaque",
5678 (char *) NULL,
5679 (char *) NULL,
5680 };
5681
5682 /*
5683 Select a command from the pop-up menu.
5684 */
5685 StipplesMenu[7]="Open...";
5686 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5687 command);
5688 if (entry < 0)
5689 break;
5690 if (stipple != (Pixmap) NULL)
5691 (void) XFreePixmap(display,stipple);
5692 stipple=(Pixmap) NULL;
cristy3ed852e2009-09-05 21:47:34 +00005693 if (entry != 7)
5694 {
5695 switch (entry)
5696 {
5697 case 0:
5698 {
5699 stipple=XCreateBitmapFromData(display,root_window,
5700 (char *) BricksBitmap,BricksWidth,BricksHeight);
5701 break;
5702 }
5703 case 1:
5704 {
5705 stipple=XCreateBitmapFromData(display,root_window,
5706 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5707 break;
5708 }
5709 case 2:
5710 {
5711 stipple=XCreateBitmapFromData(display,root_window,
5712 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5713 break;
5714 }
5715 case 3:
5716 {
5717 stipple=XCreateBitmapFromData(display,root_window,
5718 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5719 break;
5720 }
5721 case 4:
5722 {
5723 stipple=XCreateBitmapFromData(display,root_window,
5724 (char *) WavyBitmap,WavyWidth,WavyHeight);
5725 break;
5726 }
5727 case 5:
cristy3ed852e2009-09-05 21:47:34 +00005728 {
5729 stipple=XCreateBitmapFromData(display,root_window,
5730 (char *) HighlightBitmap,HighlightWidth,
5731 HighlightHeight);
5732 break;
5733 }
cristydd05beb2010-11-21 21:23:39 +00005734 case 6:
5735 default:
5736 {
5737 stipple=XCreateBitmapFromData(display,root_window,
5738 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5739 break;
5740 }
cristy3ed852e2009-09-05 21:47:34 +00005741 }
5742 break;
5743 }
5744 XFileBrowserWidget(display,windows,"Stipple",filename);
5745 if (*filename == '\0')
5746 break;
5747 /*
5748 Read image.
5749 */
5750 XSetCursorState(display,windows,MagickTrue);
5751 XCheckRefreshWindows(display,windows);
5752 image_info=AcquireImageInfo();
5753 (void) CopyMagickString(image_info->filename,filename,
5754 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00005755 stipple_image=ReadImage(image_info,exception);
5756 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00005757 XSetCursorState(display,windows,MagickFalse);
5758 if (stipple_image == (Image *) NULL)
5759 break;
5760 (void) AcquireUniqueFileResource(filename);
cristyb51dff52011-05-19 16:55:47 +00005761 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00005762 "xbm:%s",filename);
cristy051718b2011-08-28 22:49:25 +00005763 (void) WriteImage(image_info,stipple_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005764 stipple_image=DestroyImage(stipple_image);
5765 image_info=DestroyImageInfo(image_info);
5766 status=XReadBitmapFile(display,root_window,filename,&width,
5767 &height,&stipple,&x,&y);
5768 (void) RelinquishUniqueFileResource(filename);
5769 if ((status != BitmapSuccess) != 0)
5770 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5771 filename);
5772 break;
5773 }
5774 case DrawWidthCommand:
5775 {
5776 static char
5777 width[MaxTextExtent] = "0";
5778
5779 static const char
5780 *WidthsMenu[] =
5781 {
5782 "1",
5783 "2",
5784 "4",
5785 "8",
5786 "16",
5787 "Dialog...",
5788 (char *) NULL,
5789 };
5790
5791 /*
5792 Select a command from the pop-up menu.
5793 */
5794 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5795 command);
5796 if (entry < 0)
5797 break;
5798 if (entry != 5)
5799 {
cristydd05beb2010-11-21 21:23:39 +00005800 line_width=(unsigned int) StringToUnsignedLong(
5801 WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005802 break;
5803 }
5804 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5805 width);
5806 if (*width == '\0')
5807 break;
cristye27293e2009-12-18 02:53:20 +00005808 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005809 break;
5810 }
5811 case DrawUndoCommand:
5812 {
5813 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00005814 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005815 break;
5816 }
5817 case DrawHelpCommand:
5818 {
5819 XTextViewWidget(display,resource_info,windows,MagickFalse,
5820 "Help Viewer - Image Rotation",ImageDrawHelp);
5821 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5822 break;
5823 }
5824 case DrawDismissCommand:
5825 {
5826 /*
5827 Prematurely exit.
5828 */
5829 state|=EscapeState;
5830 state|=ExitState;
5831 break;
5832 }
5833 default:
5834 break;
5835 }
5836 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5837 continue;
5838 }
5839 switch (event.type)
5840 {
5841 case ButtonPress:
5842 {
5843 if (event.xbutton.button != Button1)
5844 break;
5845 if (event.xbutton.window != windows->image.id)
5846 break;
5847 /*
5848 exit loop.
5849 */
5850 x=event.xbutton.x;
5851 y=event.xbutton.y;
5852 state|=ExitState;
5853 break;
5854 }
5855 case ButtonRelease:
5856 break;
5857 case Expose:
5858 break;
5859 case KeyPress:
5860 {
5861 KeySym
5862 key_symbol;
5863
5864 if (event.xkey.window != windows->image.id)
5865 break;
5866 /*
5867 Respond to a user key press.
5868 */
5869 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5870 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5871 switch ((int) key_symbol)
5872 {
5873 case XK_Escape:
5874 case XK_F20:
5875 {
5876 /*
5877 Prematurely exit.
5878 */
5879 state|=EscapeState;
5880 state|=ExitState;
5881 break;
5882 }
5883 case XK_F1:
5884 case XK_Help:
5885 {
5886 XTextViewWidget(display,resource_info,windows,MagickFalse,
5887 "Help Viewer - Image Rotation",ImageDrawHelp);
5888 break;
5889 }
5890 default:
5891 {
5892 (void) XBell(display,0);
5893 break;
5894 }
5895 }
5896 break;
5897 }
5898 case MotionNotify:
5899 {
5900 /*
5901 Map and unmap Info widget as text cursor crosses its boundaries.
5902 */
5903 x=event.xmotion.x;
5904 y=event.xmotion.y;
5905 if (windows->info.mapped != MagickFalse)
5906 {
5907 if ((x < (int) (windows->info.x+windows->info.width)) &&
5908 (y < (int) (windows->info.y+windows->info.height)))
5909 (void) XWithdrawWindow(display,windows->info.id,
5910 windows->info.screen);
5911 }
5912 else
5913 if ((x > (int) (windows->info.x+windows->info.width)) ||
5914 (y > (int) (windows->info.y+windows->info.height)))
5915 (void) XMapWindow(display,windows->info.id);
5916 break;
5917 }
5918 }
5919 } while ((state & ExitState) == 0);
5920 (void) XSelectInput(display,windows->image.id,
5921 windows->image.attributes.event_mask);
5922 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5923 if ((state & EscapeState) != 0)
5924 break;
5925 /*
5926 Draw element as pointer moves until the button is released.
5927 */
5928 distance=0;
5929 degrees=0.0;
5930 line_info.x1=x;
5931 line_info.y1=y;
5932 line_info.x2=x;
5933 line_info.y2=y;
cristy49e2d862010-11-12 02:50:30 +00005934 rectangle_info.x=(ssize_t) x;
5935 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00005936 rectangle_info.width=0;
5937 rectangle_info.height=0;
5938 number_coordinates=1;
5939 coordinate_info->x=x;
5940 coordinate_info->y=y;
5941 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5942 state=DefaultState;
5943 do
5944 {
5945 switch (element)
5946 {
5947 case PointElement:
5948 default:
5949 {
5950 if (number_coordinates > 1)
5951 {
5952 (void) XDrawLines(display,windows->image.id,
5953 windows->image.highlight_context,coordinate_info,
5954 number_coordinates,CoordModeOrigin);
cristyb51dff52011-05-19 16:55:47 +00005955 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00005956 coordinate_info[number_coordinates-1].x,
5957 coordinate_info[number_coordinates-1].y);
5958 XInfoWidget(display,windows,text);
5959 }
5960 break;
5961 }
5962 case LineElement:
5963 {
5964 if (distance > 9)
5965 {
5966 /*
5967 Display angle of the line.
5968 */
5969 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5970 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00005971 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005972 (double) degrees);
5973 XInfoWidget(display,windows,text);
5974 XHighlightLine(display,windows->image.id,
5975 windows->image.highlight_context,&line_info);
5976 }
5977 else
5978 if (windows->info.mapped != MagickFalse)
5979 (void) XWithdrawWindow(display,windows->info.id,
5980 windows->info.screen);
5981 break;
5982 }
5983 case RectangleElement:
5984 case FillRectangleElement:
5985 {
5986 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5987 {
5988 /*
5989 Display info and draw drawing rectangle.
5990 */
cristyb51dff52011-05-19 16:55:47 +00005991 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005992 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005993 (double) rectangle_info.height,(double) rectangle_info.x,
5994 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005995 XInfoWidget(display,windows,text);
5996 XHighlightRectangle(display,windows->image.id,
5997 windows->image.highlight_context,&rectangle_info);
5998 }
5999 else
6000 if (windows->info.mapped != MagickFalse)
6001 (void) XWithdrawWindow(display,windows->info.id,
6002 windows->info.screen);
6003 break;
6004 }
6005 case CircleElement:
6006 case FillCircleElement:
6007 case EllipseElement:
6008 case FillEllipseElement:
6009 {
6010 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6011 {
6012 /*
6013 Display info and draw drawing rectangle.
6014 */
cristyb51dff52011-05-19 16:55:47 +00006015 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00006016 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00006017 (double) rectangle_info.height,(double) rectangle_info.x,
6018 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006019 XInfoWidget(display,windows,text);
6020 XHighlightEllipse(display,windows->image.id,
6021 windows->image.highlight_context,&rectangle_info);
6022 }
6023 else
6024 if (windows->info.mapped != MagickFalse)
6025 (void) XWithdrawWindow(display,windows->info.id,
6026 windows->info.screen);
6027 break;
6028 }
6029 case PolygonElement:
6030 case FillPolygonElement:
6031 {
6032 if (number_coordinates > 1)
6033 (void) XDrawLines(display,windows->image.id,
6034 windows->image.highlight_context,coordinate_info,
6035 number_coordinates,CoordModeOrigin);
6036 if (distance > 9)
6037 {
6038 /*
6039 Display angle of the line.
6040 */
6041 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6042 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00006043 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00006044 (double) degrees);
6045 XInfoWidget(display,windows,text);
6046 XHighlightLine(display,windows->image.id,
6047 windows->image.highlight_context,&line_info);
6048 }
6049 else
6050 if (windows->info.mapped != MagickFalse)
6051 (void) XWithdrawWindow(display,windows->info.id,
6052 windows->info.screen);
6053 break;
6054 }
6055 }
6056 /*
6057 Wait for next event.
6058 */
6059 XScreenEvent(display,windows,&event);
6060 switch (element)
6061 {
6062 case PointElement:
6063 default:
6064 {
6065 if (number_coordinates > 1)
6066 (void) XDrawLines(display,windows->image.id,
6067 windows->image.highlight_context,coordinate_info,
6068 number_coordinates,CoordModeOrigin);
6069 break;
6070 }
6071 case LineElement:
6072 {
6073 if (distance > 9)
6074 XHighlightLine(display,windows->image.id,
6075 windows->image.highlight_context,&line_info);
6076 break;
6077 }
6078 case RectangleElement:
6079 case FillRectangleElement:
6080 {
6081 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6082 XHighlightRectangle(display,windows->image.id,
6083 windows->image.highlight_context,&rectangle_info);
6084 break;
6085 }
6086 case CircleElement:
6087 case FillCircleElement:
6088 case EllipseElement:
6089 case FillEllipseElement:
6090 {
6091 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6092 XHighlightEllipse(display,windows->image.id,
6093 windows->image.highlight_context,&rectangle_info);
6094 break;
6095 }
6096 case PolygonElement:
6097 case FillPolygonElement:
6098 {
6099 if (number_coordinates > 1)
6100 (void) XDrawLines(display,windows->image.id,
6101 windows->image.highlight_context,coordinate_info,
6102 number_coordinates,CoordModeOrigin);
6103 if (distance > 9)
6104 XHighlightLine(display,windows->image.id,
6105 windows->image.highlight_context,&line_info);
6106 break;
6107 }
6108 }
6109 switch (event.type)
6110 {
6111 case ButtonPress:
6112 break;
6113 case ButtonRelease:
6114 {
6115 /*
6116 User has committed to element.
6117 */
6118 line_info.x2=event.xbutton.x;
6119 line_info.y2=event.xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00006120 rectangle_info.x=(ssize_t) event.xbutton.x;
6121 rectangle_info.y=(ssize_t) event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00006122 coordinate_info[number_coordinates].x=event.xbutton.x;
6123 coordinate_info[number_coordinates].y=event.xbutton.y;
6124 if (((element != PolygonElement) &&
6125 (element != FillPolygonElement)) || (distance <= 9))
6126 {
6127 state|=ExitState;
6128 break;
6129 }
6130 number_coordinates++;
6131 if (number_coordinates < (int) max_coordinates)
6132 {
6133 line_info.x1=event.xbutton.x;
6134 line_info.y1=event.xbutton.y;
6135 break;
6136 }
6137 max_coordinates<<=1;
6138 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6139 max_coordinates,sizeof(*coordinate_info));
6140 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006141 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00006142 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6143 break;
6144 }
6145 case Expose:
6146 break;
6147 case MotionNotify:
6148 {
6149 if (event.xmotion.window != windows->image.id)
6150 break;
6151 if (element != PointElement)
6152 {
6153 line_info.x2=event.xmotion.x;
6154 line_info.y2=event.xmotion.y;
cristy49e2d862010-11-12 02:50:30 +00006155 rectangle_info.x=(ssize_t) event.xmotion.x;
6156 rectangle_info.y=(ssize_t) event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00006157 break;
6158 }
6159 coordinate_info[number_coordinates].x=event.xbutton.x;
6160 coordinate_info[number_coordinates].y=event.xbutton.y;
6161 number_coordinates++;
6162 if (number_coordinates < (int) max_coordinates)
6163 break;
6164 max_coordinates<<=1;
6165 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6166 max_coordinates,sizeof(*coordinate_info));
6167 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006168 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00006169 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6170 break;
6171 }
6172 default:
6173 break;
6174 }
6175 /*
6176 Check boundary conditions.
6177 */
6178 if (line_info.x2 < 0)
6179 line_info.x2=0;
6180 else
6181 if (line_info.x2 > (int) windows->image.width)
6182 line_info.x2=(short) windows->image.width;
6183 if (line_info.y2 < 0)
6184 line_info.y2=0;
6185 else
6186 if (line_info.y2 > (int) windows->image.height)
6187 line_info.y2=(short) windows->image.height;
6188 distance=(unsigned int)
6189 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6190 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6191 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6192 ((state & ExitState) != 0))
6193 {
6194 if (rectangle_info.x < 0)
6195 rectangle_info.x=0;
6196 else
cristy49e2d862010-11-12 02:50:30 +00006197 if (rectangle_info.x > (ssize_t) windows->image.width)
cristybb503372010-05-27 20:51:26 +00006198 rectangle_info.x=(ssize_t) windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +00006199 if ((int) rectangle_info.x < x)
6200 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6201 else
6202 {
6203 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00006204 rectangle_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00006205 }
6206 if (rectangle_info.y < 0)
6207 rectangle_info.y=0;
6208 else
cristy49e2d862010-11-12 02:50:30 +00006209 if (rectangle_info.y > (ssize_t) windows->image.height)
cristybb503372010-05-27 20:51:26 +00006210 rectangle_info.y=(ssize_t) windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +00006211 if ((int) rectangle_info.y < y)
6212 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6213 else
6214 {
6215 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00006216 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00006217 }
6218 }
6219 } while ((state & ExitState) == 0);
6220 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6221 if ((element == PointElement) || (element == PolygonElement) ||
6222 (element == FillPolygonElement))
6223 {
6224 /*
6225 Determine polygon bounding box.
6226 */
cristy49e2d862010-11-12 02:50:30 +00006227 rectangle_info.x=(ssize_t) coordinate_info->x;
6228 rectangle_info.y=(ssize_t) coordinate_info->y;
cristy3ed852e2009-09-05 21:47:34 +00006229 x=coordinate_info->x;
6230 y=coordinate_info->y;
6231 for (i=1; i < number_coordinates; i++)
6232 {
6233 if (coordinate_info[i].x > x)
6234 x=coordinate_info[i].x;
6235 if (coordinate_info[i].y > y)
6236 y=coordinate_info[i].y;
cristy49e2d862010-11-12 02:50:30 +00006237 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6238 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6239 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6240 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
cristy3ed852e2009-09-05 21:47:34 +00006241 }
cristybb503372010-05-27 20:51:26 +00006242 rectangle_info.width=(size_t) (x-rectangle_info.x);
6243 rectangle_info.height=(size_t) (y-rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006244 for (i=0; i < number_coordinates; i++)
6245 {
6246 coordinate_info[i].x-=rectangle_info.x;
6247 coordinate_info[i].y-=rectangle_info.y;
6248 }
6249 }
6250 else
6251 if (distance <= 9)
6252 continue;
6253 else
6254 if ((element == RectangleElement) ||
6255 (element == CircleElement) || (element == EllipseElement))
6256 {
6257 rectangle_info.width--;
6258 rectangle_info.height--;
6259 }
6260 /*
6261 Drawing is relative to image configuration.
6262 */
6263 draw_info.x=(int) rectangle_info.x;
6264 draw_info.y=(int) rectangle_info.y;
6265 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
cristy051718b2011-08-28 22:49:25 +00006266 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006267 width=(unsigned int) (*image)->columns;
6268 height=(unsigned int) (*image)->rows;
6269 x=0;
6270 y=0;
6271 if (windows->image.crop_geometry != (char *) NULL)
6272 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6273 draw_info.x+=windows->image.x-(line_width/2);
6274 if (draw_info.x < 0)
6275 draw_info.x=0;
6276 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6277 draw_info.y+=windows->image.y-(line_width/2);
6278 if (draw_info.y < 0)
6279 draw_info.y=0;
6280 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6281 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6282 if (draw_info.width > (unsigned int) (*image)->columns)
6283 draw_info.width=(unsigned int) (*image)->columns;
6284 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6285 if (draw_info.height > (unsigned int) (*image)->rows)
6286 draw_info.height=(unsigned int) (*image)->rows;
cristyb51dff52011-05-19 16:55:47 +00006287 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00006288 width*draw_info.width/windows->image.ximage->width,
6289 height*draw_info.height/windows->image.ximage->height,
6290 draw_info.x+x,draw_info.y+y);
6291 /*
6292 Initialize drawing attributes.
6293 */
6294 draw_info.degrees=0.0;
6295 draw_info.element=element;
6296 draw_info.stipple=stipple;
6297 draw_info.line_width=line_width;
6298 draw_info.line_info=line_info;
6299 if (line_info.x1 > (int) (line_width/2))
6300 draw_info.line_info.x1=(short) line_width/2;
6301 if (line_info.y1 > (int) (line_width/2))
6302 draw_info.line_info.y1=(short) line_width/2;
6303 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6304 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6305 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6306 {
6307 draw_info.line_info.x2=(-draw_info.line_info.x2);
6308 draw_info.line_info.y2=(-draw_info.line_info.y2);
6309 }
6310 if (draw_info.line_info.x2 < 0)
6311 {
6312 draw_info.line_info.x2=(-draw_info.line_info.x2);
6313 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6314 }
6315 if (draw_info.line_info.y2 < 0)
6316 {
6317 draw_info.line_info.y2=(-draw_info.line_info.y2);
6318 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6319 }
6320 draw_info.rectangle_info=rectangle_info;
cristy49e2d862010-11-12 02:50:30 +00006321 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006322 draw_info.rectangle_info.x=(ssize_t) line_width/2;
cristy49e2d862010-11-12 02:50:30 +00006323 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006324 draw_info.rectangle_info.y=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006325 draw_info.number_coordinates=(unsigned int) number_coordinates;
6326 draw_info.coordinate_info=coordinate_info;
6327 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6328 /*
6329 Draw element on image.
6330 */
6331 XSetCursorState(display,windows,MagickTrue);
6332 XCheckRefreshWindows(display,windows);
6333 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6334 XSetCursorState(display,windows,MagickFalse);
6335 /*
6336 Update image colormap and return to image drawing.
6337 */
6338 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00006339 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006340 }
6341 XSetCursorState(display,windows,MagickFalse);
6342 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6343 return(status != 0 ? MagickTrue : MagickFalse);
6344}
6345
6346/*
6347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6348% %
6349% %
6350% %
6351+ X D r a w P a n R e c t a n g l e %
6352% %
6353% %
6354% %
6355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6356%
6357% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6358% displays a zoom image and the rectangle shows which portion of the image is
6359% displayed in the Image window.
6360%
6361% The format of the XDrawPanRectangle method is:
6362%
6363% XDrawPanRectangle(Display *display,XWindows *windows)
6364%
6365% A description of each parameter follows:
6366%
6367% o display: Specifies a connection to an X server; returned from
6368% XOpenDisplay.
6369%
6370% o windows: Specifies a pointer to a XWindows structure.
6371%
6372*/
6373static void XDrawPanRectangle(Display *display,XWindows *windows)
6374{
6375 MagickRealType
6376 scale_factor;
6377
6378 RectangleInfo
6379 highlight_info;
6380
6381 /*
6382 Determine dimensions of the panning rectangle.
6383 */
6384 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
cristy49e2d862010-11-12 02:50:30 +00006385 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006386 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6387 scale_factor=(MagickRealType)
6388 windows->pan.height/windows->image.ximage->height;
cristy49e2d862010-11-12 02:50:30 +00006389 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006390 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6391 /*
6392 Display the panning rectangle.
6393 */
6394 (void) XClearWindow(display,windows->pan.id);
6395 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6396 &highlight_info);
6397}
6398
6399/*
6400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6401% %
6402% %
6403% %
6404+ X I m a g e C a c h e %
6405% %
6406% %
6407% %
6408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6409%
6410% XImageCache() handles the creation, manipulation, and destruction of the
6411% image cache (undo and redo buffers).
6412%
6413% The format of the XImageCache method is:
6414%
6415% void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006416% XWindows *windows,const CommandType command,Image **image,
6417% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006418%
6419% A description of each parameter follows:
6420%
6421% o display: Specifies a connection to an X server; returned from
6422% XOpenDisplay.
6423%
6424% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6425%
6426% o windows: Specifies a pointer to a XWindows structure.
6427%
6428% o command: Specifies a command to perform.
6429%
cristya9a86bb2011-01-13 01:11:00 +00006430% o image: the image; XImageCache may transform the image and return a new
6431% image pointer.
cristy3ed852e2009-09-05 21:47:34 +00006432%
cristy051718b2011-08-28 22:49:25 +00006433% o exception: return any errors or warnings in this structure.
6434%
cristy3ed852e2009-09-05 21:47:34 +00006435*/
6436static void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006437 XWindows *windows,const CommandType command,Image **image,
6438 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006439{
6440 Image
6441 *cache_image;
6442
6443 static Image
6444 *redo_image = (Image *) NULL,
6445 *undo_image = (Image *) NULL;
6446
6447 switch (command)
6448 {
6449 case FreeBuffersCommand:
6450 {
6451 /*
6452 Free memory from the undo and redo cache.
6453 */
6454 while (undo_image != (Image *) NULL)
6455 {
6456 cache_image=undo_image;
6457 undo_image=GetPreviousImageInList(undo_image);
6458 cache_image->list=DestroyImage(cache_image->list);
6459 cache_image=DestroyImage(cache_image);
6460 }
6461 undo_image=NewImageList();
6462 if (redo_image != (Image *) NULL)
6463 redo_image=DestroyImage(redo_image);
6464 redo_image=NewImageList();
6465 return;
6466 }
6467 case UndoCommand:
6468 {
cristya9a86bb2011-01-13 01:11:00 +00006469 char
6470 image_geometry[MaxTextExtent];
6471
cristy3ed852e2009-09-05 21:47:34 +00006472 /*
6473 Undo the last image transformation.
6474 */
6475 if (undo_image == (Image *) NULL)
6476 {
6477 (void) XBell(display,0);
6478 return;
6479 }
6480 cache_image=undo_image;
6481 undo_image=GetPreviousImageInList(undo_image);
6482 windows->image.window_changes.width=(int) cache_image->columns;
6483 windows->image.window_changes.height=(int) cache_image->rows;
cristyb51dff52011-05-19 16:55:47 +00006484 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristya9a86bb2011-01-13 01:11:00 +00006485 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00006486 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6487 exception);
cristy3ed852e2009-09-05 21:47:34 +00006488 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00006489 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6490 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00006491 windows->image.crop_geometry=cache_image->geometry;
6492 if (redo_image != (Image *) NULL)
6493 redo_image=DestroyImage(redo_image);
6494 redo_image=(*image);
6495 *image=cache_image->list;
6496 cache_image=DestroyImage(cache_image);
6497 if (windows->image.orphan != MagickFalse)
6498 return;
6499 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00006500 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006501 return;
6502 }
6503 case CutCommand:
6504 case PasteCommand:
6505 case ApplyCommand:
6506 case HalfSizeCommand:
6507 case OriginalSizeCommand:
6508 case DoubleSizeCommand:
6509 case ResizeCommand:
6510 case TrimCommand:
6511 case CropCommand:
6512 case ChopCommand:
6513 case FlipCommand:
6514 case FlopCommand:
6515 case RotateRightCommand:
6516 case RotateLeftCommand:
6517 case RotateCommand:
6518 case ShearCommand:
6519 case RollCommand:
6520 case NegateCommand:
6521 case ContrastStretchCommand:
6522 case SigmoidalContrastCommand:
6523 case NormalizeCommand:
6524 case EqualizeCommand:
6525 case HueCommand:
6526 case SaturationCommand:
6527 case BrightnessCommand:
6528 case GammaCommand:
6529 case SpiffCommand:
6530 case DullCommand:
6531 case GrayscaleCommand:
6532 case MapCommand:
6533 case QuantizeCommand:
6534 case DespeckleCommand:
6535 case EmbossCommand:
6536 case ReduceNoiseCommand:
6537 case AddNoiseCommand:
6538 case SharpenCommand:
6539 case BlurCommand:
6540 case ThresholdCommand:
6541 case EdgeDetectCommand:
6542 case SpreadCommand:
6543 case ShadeCommand:
6544 case RaiseCommand:
6545 case SegmentCommand:
6546 case SolarizeCommand:
6547 case SepiaToneCommand:
6548 case SwirlCommand:
6549 case ImplodeCommand:
6550 case VignetteCommand:
6551 case WaveCommand:
6552 case OilPaintCommand:
6553 case CharcoalDrawCommand:
6554 case AnnotateCommand:
6555 case AddBorderCommand:
6556 case AddFrameCommand:
6557 case CompositeCommand:
6558 case CommentCommand:
6559 case LaunchCommand:
6560 case RegionofInterestCommand:
6561 case SaveToUndoBufferCommand:
6562 case RedoCommand:
6563 {
6564 Image
6565 *previous_image;
6566
cristybb503372010-05-27 20:51:26 +00006567 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00006568 bytes;
6569
cristy101ab702011-10-13 13:06:32 +00006570 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
cristy3ed852e2009-09-05 21:47:34 +00006571 if (undo_image != (Image *) NULL)
6572 {
6573 /*
cristya9a86bb2011-01-13 01:11:00 +00006574 Ensure the undo cache has enough memory available.
cristy3ed852e2009-09-05 21:47:34 +00006575 */
6576 previous_image=undo_image;
6577 while (previous_image != (Image *) NULL)
6578 {
6579 bytes+=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006580 sizeof(PixelInfo);
cristybb503372010-05-27 20:51:26 +00006581 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006582 {
6583 previous_image=GetPreviousImageInList(previous_image);
6584 continue;
6585 }
6586 bytes-=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006587 sizeof(PixelInfo);
cristy3ed852e2009-09-05 21:47:34 +00006588 if (previous_image == undo_image)
6589 undo_image=NewImageList();
6590 else
6591 previous_image->next->previous=NewImageList();
6592 break;
6593 }
6594 while (previous_image != (Image *) NULL)
6595 {
6596 /*
6597 Delete any excess memory from undo cache.
6598 */
6599 cache_image=previous_image;
6600 previous_image=GetPreviousImageInList(previous_image);
6601 cache_image->list=DestroyImage(cache_image->list);
6602 cache_image=DestroyImage(cache_image);
6603 }
6604 }
cristybb503372010-05-27 20:51:26 +00006605 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006606 break;
6607 /*
6608 Save image before transformations are applied.
6609 */
cristy9950d572011-10-01 18:22:35 +00006610 cache_image=AcquireImage((ImageInfo *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +00006611 if (cache_image == (Image *) NULL)
6612 break;
6613 XSetCursorState(display,windows,MagickTrue);
6614 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00006615 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00006616 XSetCursorState(display,windows,MagickFalse);
6617 if (cache_image->list == (Image *) NULL)
6618 {
6619 cache_image=DestroyImage(cache_image);
6620 break;
6621 }
cristybb503372010-05-27 20:51:26 +00006622 cache_image->columns=(size_t) windows->image.ximage->width;
6623 cache_image->rows=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006624 cache_image->geometry=windows->image.crop_geometry;
6625 if (windows->image.crop_geometry != (char *) NULL)
6626 {
6627 cache_image->geometry=AcquireString((char *) NULL);
6628 (void) CopyMagickString(cache_image->geometry,
6629 windows->image.crop_geometry,MaxTextExtent);
6630 }
6631 if (undo_image == (Image *) NULL)
6632 {
6633 undo_image=cache_image;
6634 break;
6635 }
6636 undo_image->next=cache_image;
6637 undo_image->next->previous=undo_image;
6638 undo_image=undo_image->next;
6639 break;
6640 }
6641 default:
6642 break;
6643 }
6644 if (command == RedoCommand)
6645 {
6646 /*
6647 Redo the last image transformation.
6648 */
6649 if (redo_image == (Image *) NULL)
6650 {
6651 (void) XBell(display,0);
6652 return;
6653 }
6654 windows->image.window_changes.width=(int) redo_image->columns;
6655 windows->image.window_changes.height=(int) redo_image->rows;
6656 if (windows->image.crop_geometry != (char *) NULL)
6657 windows->image.crop_geometry=(char *)
6658 RelinquishMagickMemory(windows->image.crop_geometry);
6659 windows->image.crop_geometry=redo_image->geometry;
6660 *image=DestroyImage(*image);
6661 *image=redo_image;
6662 redo_image=NewImageList();
6663 if (windows->image.orphan != MagickFalse)
6664 return;
6665 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00006666 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006667 return;
6668 }
6669 if (command != InfoCommand)
6670 return;
6671 /*
6672 Display image info.
6673 */
6674 XSetCursorState(display,windows,MagickTrue);
6675 XCheckRefreshWindows(display,windows);
6676 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6677 XSetCursorState(display,windows,MagickFalse);
6678}
6679
6680/*
6681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6682% %
6683% %
6684% %
6685+ X I m a g e W i n d o w C o m m a n d %
6686% %
6687% %
6688% %
6689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6690%
6691% XImageWindowCommand() makes a transform to the image or Image window as
6692% specified by a user menu button or keyboard command.
6693%
cristy051718b2011-08-28 22:49:25 +00006694% The format of the XImageWindowCommand method is:
cristy3ed852e2009-09-05 21:47:34 +00006695%
6696% CommandType XImageWindowCommand(Display *display,
6697% XResourceInfo *resource_info,XWindows *windows,
cristy051718b2011-08-28 22:49:25 +00006698% const MagickStatusType state,KeySym key_symbol,Image **image,
6699% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006700%
6701% A description of each parameter follows:
6702%
6703% o nexus: Method XImageWindowCommand returns an image when the
6704% user chooses 'Open Image' from the command menu. Otherwise a null
6705% image is returned.
6706%
6707% o display: Specifies a connection to an X server; returned from
6708% XOpenDisplay.
6709%
6710% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6711%
6712% o windows: Specifies a pointer to a XWindows structure.
6713%
6714% o state: key mask.
6715%
6716% o key_symbol: Specifies a command to perform.
6717%
cristy051718b2011-08-28 22:49:25 +00006718% o image: the image; XImageWIndowCommand may transform the image and
6719% return a new image pointer.
6720%
6721% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00006722%
6723*/
6724static CommandType XImageWindowCommand(Display *display,
6725 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
cristy051718b2011-08-28 22:49:25 +00006726 KeySym key_symbol,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006727{
6728 static char
6729 delta[MaxTextExtent] = "";
6730
6731 static const char
6732 Digits[] = "01234567890";
6733
6734 static KeySym
6735 last_symbol = XK_0;
6736
6737 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6738 {
6739 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6740 {
6741 *delta='\0';
6742 resource_info->quantum=1;
6743 }
6744 last_symbol=key_symbol;
6745 delta[strlen(delta)+1]='\0';
6746 delta[strlen(delta)]=Digits[key_symbol-XK_0];
cristyf2f27272009-12-17 14:48:46 +00006747 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006748 return(NullCommand);
6749 }
6750 last_symbol=key_symbol;
6751 if (resource_info->immutable)
6752 {
6753 /*
6754 Virtual image window has a restricted command set.
6755 */
6756 switch (key_symbol)
6757 {
6758 case XK_question:
6759 return(InfoCommand);
6760 case XK_p:
6761 case XK_Print:
6762 return(PrintCommand);
6763 case XK_space:
6764 return(NextCommand);
6765 case XK_q:
6766 case XK_Escape:
6767 return(QuitCommand);
6768 default:
6769 break;
6770 }
6771 return(NullCommand);
6772 }
6773 switch ((int) key_symbol)
6774 {
6775 case XK_o:
6776 {
6777 if ((state & ControlMask) == 0)
6778 break;
6779 return(OpenCommand);
6780 }
6781 case XK_space:
6782 return(NextCommand);
6783 case XK_BackSpace:
6784 return(FormerCommand);
6785 case XK_s:
6786 {
6787 if ((state & Mod1Mask) != 0)
6788 return(SwirlCommand);
6789 if ((state & ControlMask) == 0)
6790 return(ShearCommand);
6791 return(SaveCommand);
6792 }
6793 case XK_p:
6794 case XK_Print:
6795 {
6796 if ((state & Mod1Mask) != 0)
6797 return(OilPaintCommand);
6798 if ((state & Mod4Mask) != 0)
6799 return(ColorCommand);
6800 if ((state & ControlMask) == 0)
6801 return(NullCommand);
6802 return(PrintCommand);
6803 }
6804 case XK_d:
6805 {
6806 if ((state & Mod4Mask) != 0)
6807 return(DrawCommand);
6808 if ((state & ControlMask) == 0)
6809 return(NullCommand);
6810 return(DeleteCommand);
6811 }
6812 case XK_Select:
6813 {
6814 if ((state & ControlMask) == 0)
6815 return(NullCommand);
6816 return(SelectCommand);
6817 }
6818 case XK_n:
6819 {
6820 if ((state & ControlMask) == 0)
6821 return(NullCommand);
6822 return(NewCommand);
6823 }
6824 case XK_q:
6825 case XK_Escape:
6826 return(QuitCommand);
6827 case XK_z:
6828 case XK_Undo:
6829 {
6830 if ((state & ControlMask) == 0)
6831 return(NullCommand);
6832 return(UndoCommand);
6833 }
6834 case XK_r:
6835 case XK_Redo:
6836 {
6837 if ((state & ControlMask) == 0)
6838 return(RollCommand);
6839 return(RedoCommand);
6840 }
6841 case XK_x:
6842 {
6843 if ((state & ControlMask) == 0)
6844 return(NullCommand);
6845 return(CutCommand);
6846 }
6847 case XK_c:
6848 {
6849 if ((state & Mod1Mask) != 0)
6850 return(CharcoalDrawCommand);
6851 if ((state & ControlMask) == 0)
6852 return(CropCommand);
6853 return(CopyCommand);
6854 }
6855 case XK_v:
6856 case XK_Insert:
6857 {
6858 if ((state & Mod4Mask) != 0)
6859 return(CompositeCommand);
6860 if ((state & ControlMask) == 0)
6861 return(FlipCommand);
6862 return(PasteCommand);
6863 }
6864 case XK_less:
6865 return(HalfSizeCommand);
6866 case XK_minus:
6867 return(OriginalSizeCommand);
6868 case XK_greater:
6869 return(DoubleSizeCommand);
6870 case XK_percent:
6871 return(ResizeCommand);
6872 case XK_at:
6873 return(RefreshCommand);
6874 case XK_bracketleft:
6875 return(ChopCommand);
6876 case XK_h:
6877 return(FlopCommand);
6878 case XK_slash:
6879 return(RotateRightCommand);
6880 case XK_backslash:
6881 return(RotateLeftCommand);
6882 case XK_asterisk:
6883 return(RotateCommand);
6884 case XK_t:
6885 return(TrimCommand);
6886 case XK_H:
6887 return(HueCommand);
6888 case XK_S:
6889 return(SaturationCommand);
6890 case XK_L:
6891 return(BrightnessCommand);
6892 case XK_G:
6893 return(GammaCommand);
6894 case XK_C:
6895 return(SpiffCommand);
6896 case XK_Z:
6897 return(DullCommand);
6898 case XK_N:
6899 return(NormalizeCommand);
6900 case XK_equal:
6901 return(EqualizeCommand);
6902 case XK_asciitilde:
6903 return(NegateCommand);
6904 case XK_period:
6905 return(GrayscaleCommand);
6906 case XK_numbersign:
6907 return(QuantizeCommand);
6908 case XK_F2:
6909 return(DespeckleCommand);
6910 case XK_F3:
6911 return(EmbossCommand);
6912 case XK_F4:
6913 return(ReduceNoiseCommand);
6914 case XK_F5:
6915 return(AddNoiseCommand);
6916 case XK_F6:
6917 return(SharpenCommand);
6918 case XK_F7:
6919 return(BlurCommand);
6920 case XK_F8:
6921 return(ThresholdCommand);
6922 case XK_F9:
6923 return(EdgeDetectCommand);
6924 case XK_F10:
6925 return(SpreadCommand);
6926 case XK_F11:
6927 return(ShadeCommand);
6928 case XK_F12:
6929 return(RaiseCommand);
6930 case XK_F13:
6931 return(SegmentCommand);
6932 case XK_i:
6933 {
6934 if ((state & Mod1Mask) == 0)
6935 return(NullCommand);
6936 return(ImplodeCommand);
6937 }
6938 case XK_w:
6939 {
6940 if ((state & Mod1Mask) == 0)
6941 return(NullCommand);
6942 return(WaveCommand);
6943 }
6944 case XK_m:
6945 {
6946 if ((state & Mod4Mask) == 0)
6947 return(NullCommand);
6948 return(MatteCommand);
6949 }
6950 case XK_b:
6951 {
6952 if ((state & Mod4Mask) == 0)
6953 return(NullCommand);
6954 return(AddBorderCommand);
6955 }
6956 case XK_f:
6957 {
6958 if ((state & Mod4Mask) == 0)
6959 return(NullCommand);
6960 return(AddFrameCommand);
6961 }
6962 case XK_exclam:
6963 {
6964 if ((state & Mod4Mask) == 0)
6965 return(NullCommand);
6966 return(CommentCommand);
6967 }
6968 case XK_a:
6969 {
6970 if ((state & Mod1Mask) != 0)
6971 return(ApplyCommand);
6972 if ((state & Mod4Mask) != 0)
6973 return(AnnotateCommand);
6974 if ((state & ControlMask) == 0)
6975 return(NullCommand);
6976 return(RegionofInterestCommand);
6977 }
6978 case XK_question:
6979 return(InfoCommand);
6980 case XK_plus:
6981 return(ZoomCommand);
6982 case XK_P:
6983 {
6984 if ((state & ShiftMask) == 0)
6985 return(NullCommand);
6986 return(ShowPreviewCommand);
6987 }
6988 case XK_Execute:
6989 return(LaunchCommand);
6990 case XK_F1:
6991 return(HelpCommand);
6992 case XK_Find:
6993 return(BrowseDocumentationCommand);
6994 case XK_Menu:
6995 {
6996 (void) XMapRaised(display,windows->command.id);
6997 return(NullCommand);
6998 }
6999 case XK_Next:
7000 case XK_Prior:
7001 case XK_Home:
7002 case XK_KP_Home:
7003 {
7004 XTranslateImage(display,windows,*image,key_symbol);
7005 return(NullCommand);
7006 }
7007 case XK_Up:
7008 case XK_KP_Up:
7009 case XK_Down:
7010 case XK_KP_Down:
7011 case XK_Left:
7012 case XK_KP_Left:
7013 case XK_Right:
7014 case XK_KP_Right:
7015 {
7016 if ((state & Mod1Mask) != 0)
7017 {
7018 RectangleInfo
7019 crop_info;
7020
7021 /*
7022 Trim one pixel from edge of image.
7023 */
7024 crop_info.x=0;
7025 crop_info.y=0;
cristybb503372010-05-27 20:51:26 +00007026 crop_info.width=(size_t) windows->image.ximage->width;
7027 crop_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007028 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
7029 {
7030 if (resource_info->quantum >= (int) crop_info.height)
7031 resource_info->quantum=(int) crop_info.height-1;
7032 crop_info.height-=resource_info->quantum;
7033 }
7034 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
7035 {
7036 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
7037 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
7038 crop_info.y+=resource_info->quantum;
7039 crop_info.height-=resource_info->quantum;
7040 }
7041 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7042 {
7043 if (resource_info->quantum >= (int) crop_info.width)
7044 resource_info->quantum=(int) crop_info.width-1;
7045 crop_info.width-=resource_info->quantum;
7046 }
7047 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7048 {
7049 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7050 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7051 crop_info.x+=resource_info->quantum;
7052 crop_info.width-=resource_info->quantum;
7053 }
7054 if ((int) (windows->image.x+windows->image.width) >
7055 (int) crop_info.width)
7056 windows->image.x=(int) (crop_info.width-windows->image.width);
7057 if ((int) (windows->image.y+windows->image.height) >
7058 (int) crop_info.height)
7059 windows->image.y=(int) (crop_info.height-windows->image.height);
7060 XSetCropGeometry(display,windows,&crop_info,*image);
7061 windows->image.window_changes.width=(int) crop_info.width;
7062 windows->image.window_changes.height=(int) crop_info.height;
7063 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
cristy051718b2011-08-28 22:49:25 +00007064 (void) XConfigureImage(display,resource_info,windows,*image,
7065 exception);
cristy3ed852e2009-09-05 21:47:34 +00007066 return(NullCommand);
7067 }
7068 XTranslateImage(display,windows,*image,key_symbol);
7069 return(NullCommand);
7070 }
7071 default:
7072 return(NullCommand);
7073 }
7074 return(NullCommand);
7075}
7076
7077/*
7078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7079% %
7080% %
7081% %
7082+ X M a g i c k C o m m a n d %
7083% %
7084% %
7085% %
7086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7087%
7088% XMagickCommand() makes a transform to the image or Image window as
7089% specified by a user menu button or keyboard command.
7090%
7091% The format of the XMagickCommand method is:
7092%
7093% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007094% XWindows *windows,const CommandType command,Image **image,
7095% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007096%
7097% A description of each parameter follows:
7098%
cristy3ed852e2009-09-05 21:47:34 +00007099% o display: Specifies a connection to an X server; returned from
7100% XOpenDisplay.
7101%
7102% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7103%
7104% o windows: Specifies a pointer to a XWindows structure.
7105%
7106% o command: Specifies a command to perform.
7107%
cristy051718b2011-08-28 22:49:25 +00007108% o image: the image; XMagickCommand may transform the image and return a
7109% new image pointer.
7110%
7111% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00007112%
7113*/
7114static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007115 XWindows *windows,const CommandType command,Image **image,
7116 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007117{
7118 char
7119 filename[MaxTextExtent],
7120 geometry[MaxTextExtent],
7121 modulate_factors[MaxTextExtent];
7122
7123 GeometryInfo
7124 geometry_info;
7125
7126 Image
7127 *nexus;
7128
7129 ImageInfo
7130 *image_info;
7131
7132 int
7133 x,
7134 y;
7135
7136 MagickStatusType
7137 flags,
7138 status;
7139
7140 QuantizeInfo
7141 quantize_info;
7142
7143 RectangleInfo
7144 page_geometry;
7145
7146 register int
7147 i;
7148
7149 static char
7150 color[MaxTextExtent] = "gray";
7151
7152 unsigned int
7153 height,
7154 width;
7155
7156 /*
7157 Process user command.
7158 */
7159 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007160 XImageCache(display,resource_info,windows,command,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007161 nexus=NewImageList();
7162 windows->image.window_changes.width=windows->image.ximage->width;
7163 windows->image.window_changes.height=windows->image.ximage->height;
7164 image_info=CloneImageInfo(resource_info->image_info);
7165 SetGeometryInfo(&geometry_info);
7166 GetQuantizeInfo(&quantize_info);
7167 switch (command)
7168 {
7169 case OpenCommand:
7170 {
7171 /*
7172 Load image.
7173 */
7174 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7175 break;
7176 }
7177 case NextCommand:
7178 {
7179 /*
7180 Display next image.
7181 */
7182 for (i=0; i < resource_info->quantum; i++)
7183 XClientMessage(display,windows->image.id,windows->im_protocols,
7184 windows->im_next_image,CurrentTime);
7185 break;
7186 }
7187 case FormerCommand:
7188 {
7189 /*
7190 Display former image.
7191 */
7192 for (i=0; i < resource_info->quantum; i++)
7193 XClientMessage(display,windows->image.id,windows->im_protocols,
7194 windows->im_former_image,CurrentTime);
7195 break;
7196 }
7197 case SelectCommand:
7198 {
7199 int
7200 status;
7201
7202 /*
7203 Select image.
7204 */
7205 status=chdir(resource_info->home_directory);
7206 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00007207 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7208 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +00007209 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7210 break;
7211 }
7212 case SaveCommand:
7213 {
7214 /*
7215 Save image.
7216 */
cristy051718b2011-08-28 22:49:25 +00007217 status=XSaveImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007218 if (status == MagickFalse)
7219 {
cristyc663dbd2011-09-16 19:43:14 +00007220 char
7221 message[MaxTextExtent];
7222
7223 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7224 exception->reason != (char *) NULL ? exception->reason : "",
7225 exception->description != (char *) NULL ? exception->description :
7226 "");
7227 XNoticeWidget(display,windows,"Unable to save file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007228 break;
7229 }
7230 break;
7231 }
7232 case PrintCommand:
7233 {
7234 /*
7235 Print image.
7236 */
cristy051718b2011-08-28 22:49:25 +00007237 status=XPrintImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007238 if (status == MagickFalse)
7239 {
cristyc663dbd2011-09-16 19:43:14 +00007240 char
7241 message[MaxTextExtent];
7242
7243 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7244 exception->reason != (char *) NULL ? exception->reason : "",
7245 exception->description != (char *) NULL ? exception->description :
7246 "");
7247 XNoticeWidget(display,windows,"Unable to print file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007248 break;
7249 }
7250 break;
7251 }
7252 case DeleteCommand:
7253 {
7254 static char
7255 filename[MaxTextExtent] = "\0";
7256
7257 /*
7258 Delete image file.
7259 */
7260 XFileBrowserWidget(display,windows,"Delete",filename);
7261 if (*filename == '\0')
7262 break;
cristy18c6c272011-09-23 14:40:37 +00007263 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00007264 if (status != MagickFalse)
7265 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7266 break;
7267 }
7268 case NewCommand:
7269 {
7270 int
7271 status;
7272
7273 static char
7274 color[MaxTextExtent] = "gray",
7275 geometry[MaxTextExtent] = "640x480";
7276
7277 static const char
7278 *format = "gradient";
7279
7280 /*
7281 Query user for canvas geometry.
7282 */
7283 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7284 geometry);
7285 if (*geometry == '\0')
7286 break;
7287 if (status == 0)
7288 format="xc";
7289 XColorBrowserWidget(display,windows,"Select",color);
7290 if (*color == '\0')
7291 break;
7292 /*
7293 Create canvas.
7294 */
cristyb51dff52011-05-19 16:55:47 +00007295 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007296 "%s:%s",format,color);
7297 (void) CloneString(&image_info->size,geometry);
cristy051718b2011-08-28 22:49:25 +00007298 nexus=ReadImage(image_info,exception);
7299 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007300 XClientMessage(display,windows->image.id,windows->im_protocols,
7301 windows->im_next_image,CurrentTime);
7302 break;
7303 }
7304 case VisualDirectoryCommand:
7305 {
7306 /*
7307 Visual Image directory.
7308 */
cristy051718b2011-08-28 22:49:25 +00007309 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00007310 break;
7311 }
7312 case QuitCommand:
7313 {
7314 /*
7315 exit program.
7316 */
7317 if (resource_info->confirm_exit == MagickFalse)
7318 XClientMessage(display,windows->image.id,windows->im_protocols,
7319 windows->im_exit,CurrentTime);
7320 else
7321 {
7322 int
7323 status;
7324
7325 /*
7326 Confirm program exit.
7327 */
7328 status=XConfirmWidget(display,windows,"Do you really want to exit",
7329 resource_info->client_name);
7330 if (status > 0)
7331 XClientMessage(display,windows->image.id,windows->im_protocols,
7332 windows->im_exit,CurrentTime);
7333 }
7334 break;
7335 }
7336 case CutCommand:
7337 {
7338 /*
7339 Cut image.
7340 */
cristy051718b2011-08-28 22:49:25 +00007341 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00007342 break;
7343 }
7344 case CopyCommand:
7345 {
7346 /*
7347 Copy image.
7348 */
cristy051718b2011-08-28 22:49:25 +00007349 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7350 exception);
cristy3ed852e2009-09-05 21:47:34 +00007351 break;
7352 }
7353 case PasteCommand:
7354 {
7355 /*
7356 Paste image.
7357 */
cristy051718b2011-08-28 22:49:25 +00007358 status=XPasteImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007359 if (status == MagickFalse)
7360 {
7361 XNoticeWidget(display,windows,"Unable to paste X image",
7362 (*image)->filename);
7363 break;
7364 }
7365 break;
7366 }
7367 case HalfSizeCommand:
7368 {
7369 /*
7370 Half image size.
7371 */
7372 windows->image.window_changes.width=windows->image.ximage->width/2;
7373 windows->image.window_changes.height=windows->image.ximage->height/2;
cristy051718b2011-08-28 22:49:25 +00007374 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007375 break;
7376 }
7377 case OriginalSizeCommand:
7378 {
7379 /*
7380 Original image size.
7381 */
7382 windows->image.window_changes.width=(int) (*image)->columns;
7383 windows->image.window_changes.height=(int) (*image)->rows;
cristy051718b2011-08-28 22:49:25 +00007384 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007385 break;
7386 }
7387 case DoubleSizeCommand:
7388 {
7389 /*
7390 Double the image size.
7391 */
7392 windows->image.window_changes.width=windows->image.ximage->width << 1;
7393 windows->image.window_changes.height=windows->image.ximage->height << 1;
cristy051718b2011-08-28 22:49:25 +00007394 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007395 break;
7396 }
7397 case ResizeCommand:
7398 {
7399 int
7400 status;
7401
cristybb503372010-05-27 20:51:26 +00007402 size_t
cristy3ed852e2009-09-05 21:47:34 +00007403 height,
7404 width;
7405
cristy9d314ff2011-03-09 01:30:28 +00007406 ssize_t
7407 x,
7408 y;
7409
cristy3ed852e2009-09-05 21:47:34 +00007410 /*
7411 Resize image.
7412 */
cristybb503372010-05-27 20:51:26 +00007413 width=(size_t) windows->image.ximage->width;
7414 height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007415 x=0;
7416 y=0;
cristyb51dff52011-05-19 16:55:47 +00007417 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
cristye8c25f92010-06-03 00:53:06 +00007418 (double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00007419 status=XDialogWidget(display,windows,"Resize",
7420 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7421 if (*geometry == '\0')
7422 break;
7423 if (status == 0)
7424 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7425 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7426 windows->image.window_changes.width=(int) width;
7427 windows->image.window_changes.height=(int) height;
cristy051718b2011-08-28 22:49:25 +00007428 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007429 break;
7430 }
7431 case ApplyCommand:
7432 {
7433 char
7434 image_geometry[MaxTextExtent];
7435
7436 if ((windows->image.crop_geometry == (char *) NULL) &&
7437 ((int) (*image)->columns == windows->image.ximage->width) &&
7438 ((int) (*image)->rows == windows->image.ximage->height))
7439 break;
7440 /*
7441 Apply size transforms to image.
7442 */
7443 XSetCursorState(display,windows,MagickTrue);
7444 XCheckRefreshWindows(display,windows);
7445 /*
7446 Crop and/or scale displayed image.
7447 */
cristyb51dff52011-05-19 16:55:47 +00007448 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +00007449 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00007450 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7451 exception);
cristy3ed852e2009-09-05 21:47:34 +00007452 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00007453 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7454 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00007455 windows->image.x=0;
7456 windows->image.y=0;
7457 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007458 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007459 break;
7460 }
7461 case RefreshCommand:
7462 {
cristy051718b2011-08-28 22:49:25 +00007463 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007464 break;
7465 }
7466 case RestoreCommand:
7467 {
7468 /*
7469 Restore Image window to its original size.
7470 */
7471 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7472 (windows->image.height == (unsigned int) (*image)->rows) &&
7473 (windows->image.crop_geometry == (char *) NULL))
7474 {
7475 (void) XBell(display,0);
7476 break;
7477 }
7478 windows->image.window_changes.width=(int) (*image)->columns;
7479 windows->image.window_changes.height=(int) (*image)->rows;
7480 if (windows->image.crop_geometry != (char *) NULL)
7481 {
7482 windows->image.crop_geometry=(char *)
7483 RelinquishMagickMemory(windows->image.crop_geometry);
7484 windows->image.crop_geometry=(char *) NULL;
7485 windows->image.x=0;
7486 windows->image.y=0;
7487 }
7488 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007489 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007490 break;
7491 }
7492 case CropCommand:
7493 {
7494 /*
7495 Crop image.
7496 */
cristy051718b2011-08-28 22:49:25 +00007497 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7498 exception);
cristy3ed852e2009-09-05 21:47:34 +00007499 break;
7500 }
7501 case ChopCommand:
7502 {
7503 /*
7504 Chop image.
7505 */
cristy051718b2011-08-28 22:49:25 +00007506 status=XChopImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007507 if (status == MagickFalse)
7508 {
7509 XNoticeWidget(display,windows,"Unable to cut X image",
7510 (*image)->filename);
7511 break;
7512 }
7513 break;
7514 }
7515 case FlopCommand:
7516 {
7517 Image
7518 *flop_image;
7519
7520 /*
7521 Flop image scanlines.
7522 */
7523 XSetCursorState(display,windows,MagickTrue);
7524 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007525 flop_image=FlopImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007526 if (flop_image != (Image *) NULL)
7527 {
7528 *image=DestroyImage(*image);
7529 *image=flop_image;
7530 }
cristy051718b2011-08-28 22:49:25 +00007531 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007532 XSetCursorState(display,windows,MagickFalse);
7533 if (windows->image.crop_geometry != (char *) NULL)
7534 {
7535 /*
7536 Flop crop geometry.
7537 */
7538 width=(unsigned int) (*image)->columns;
7539 height=(unsigned int) (*image)->rows;
7540 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7541 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007542 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007543 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7544 }
7545 if (windows->image.orphan != MagickFalse)
7546 break;
cristy051718b2011-08-28 22:49:25 +00007547 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007548 break;
7549 }
7550 case FlipCommand:
7551 {
7552 Image
7553 *flip_image;
7554
7555 /*
7556 Flip image scanlines.
7557 */
7558 XSetCursorState(display,windows,MagickTrue);
7559 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007560 flip_image=FlipImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007561 if (flip_image != (Image *) NULL)
7562 {
7563 *image=DestroyImage(*image);
7564 *image=flip_image;
7565 }
cristy051718b2011-08-28 22:49:25 +00007566 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007567 XSetCursorState(display,windows,MagickFalse);
7568 if (windows->image.crop_geometry != (char *) NULL)
7569 {
7570 /*
7571 Flip crop geometry.
7572 */
7573 width=(unsigned int) (*image)->columns;
7574 height=(unsigned int) (*image)->rows;
7575 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7576 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007577 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007578 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7579 }
7580 if (windows->image.orphan != MagickFalse)
7581 break;
cristy051718b2011-08-28 22:49:25 +00007582 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007583 break;
7584 }
7585 case RotateRightCommand:
7586 {
7587 /*
7588 Rotate image 90 degrees clockwise.
7589 */
cristy051718b2011-08-28 22:49:25 +00007590 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007591 if (status == MagickFalse)
7592 {
7593 XNoticeWidget(display,windows,"Unable to rotate X image",
7594 (*image)->filename);
7595 break;
7596 }
7597 break;
7598 }
7599 case RotateLeftCommand:
7600 {
7601 /*
7602 Rotate image 90 degrees counter-clockwise.
7603 */
cristy051718b2011-08-28 22:49:25 +00007604 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007605 if (status == MagickFalse)
7606 {
7607 XNoticeWidget(display,windows,"Unable to rotate X image",
7608 (*image)->filename);
7609 break;
7610 }
7611 break;
7612 }
7613 case RotateCommand:
7614 {
7615 /*
7616 Rotate image.
7617 */
cristy051718b2011-08-28 22:49:25 +00007618 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007619 if (status == MagickFalse)
7620 {
7621 XNoticeWidget(display,windows,"Unable to rotate X image",
7622 (*image)->filename);
7623 break;
7624 }
7625 break;
7626 }
7627 case ShearCommand:
7628 {
7629 Image
7630 *shear_image;
7631
7632 static char
7633 geometry[MaxTextExtent] = "45.0x45.0";
7634
7635 /*
7636 Query user for shear color and geometry.
7637 */
7638 XColorBrowserWidget(display,windows,"Select",color);
7639 if (*color == '\0')
7640 break;
7641 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7642 geometry);
7643 if (*geometry == '\0')
7644 break;
7645 /*
7646 Shear image.
7647 */
cristy051718b2011-08-28 22:49:25 +00007648 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7649 exception);
cristy3ed852e2009-09-05 21:47:34 +00007650 XSetCursorState(display,windows,MagickTrue);
7651 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00007652 (void) QueryColorCompliance(color,AllCompliance,
7653 &(*image)->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00007654 flags=ParseGeometry(geometry,&geometry_info);
7655 if ((flags & SigmaValue) == 0)
7656 geometry_info.sigma=geometry_info.rho;
7657 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00007658 exception);
cristy3ed852e2009-09-05 21:47:34 +00007659 if (shear_image != (Image *) NULL)
7660 {
7661 *image=DestroyImage(*image);
7662 *image=shear_image;
7663 }
cristy051718b2011-08-28 22:49:25 +00007664 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007665 XSetCursorState(display,windows,MagickFalse);
7666 if (windows->image.orphan != MagickFalse)
7667 break;
7668 windows->image.window_changes.width=(int) (*image)->columns;
7669 windows->image.window_changes.height=(int) (*image)->rows;
7670 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007671 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007672 break;
7673 }
7674 case RollCommand:
7675 {
7676 Image
7677 *roll_image;
7678
7679 static char
7680 geometry[MaxTextExtent] = "+2+2";
7681
7682 /*
7683 Query user for the roll geometry.
7684 */
7685 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7686 geometry);
7687 if (*geometry == '\0')
7688 break;
7689 /*
7690 Roll image.
7691 */
cristy051718b2011-08-28 22:49:25 +00007692 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7693 exception);
cristy3ed852e2009-09-05 21:47:34 +00007694 XSetCursorState(display,windows,MagickTrue);
7695 XCheckRefreshWindows(display,windows);
7696 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00007697 exception);
cristy3ed852e2009-09-05 21:47:34 +00007698 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
cristy051718b2011-08-28 22:49:25 +00007699 exception);
cristy3ed852e2009-09-05 21:47:34 +00007700 if (roll_image != (Image *) NULL)
7701 {
7702 *image=DestroyImage(*image);
7703 *image=roll_image;
7704 }
cristy051718b2011-08-28 22:49:25 +00007705 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007706 XSetCursorState(display,windows,MagickFalse);
7707 if (windows->image.orphan != MagickFalse)
7708 break;
7709 windows->image.window_changes.width=(int) (*image)->columns;
7710 windows->image.window_changes.height=(int) (*image)->rows;
7711 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007712 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007713 break;
7714 }
7715 case TrimCommand:
7716 {
7717 static char
7718 fuzz[MaxTextExtent];
7719
7720 /*
7721 Query user for the fuzz factor.
7722 */
cristyb51dff52011-05-19 16:55:47 +00007723 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007724 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007725 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7726 if (*fuzz == '\0')
7727 break;
cristyf2f27272009-12-17 14:48:46 +00007728 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007729 /*
7730 Trim image.
7731 */
cristy051718b2011-08-28 22:49:25 +00007732 status=XTrimImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007733 if (status == MagickFalse)
7734 {
7735 XNoticeWidget(display,windows,"Unable to trim X image",
7736 (*image)->filename);
7737 break;
7738 }
7739 break;
7740 }
7741 case HueCommand:
7742 {
7743 static char
7744 hue_percent[MaxTextExtent] = "110";
7745
7746 /*
7747 Query user for percent hue change.
7748 */
7749 (void) XDialogWidget(display,windows,"Apply",
7750 "Enter percent change in image hue (0-200):",hue_percent);
7751 if (*hue_percent == '\0')
7752 break;
7753 /*
7754 Vary the image hue.
7755 */
7756 XSetCursorState(display,windows,MagickTrue);
7757 XCheckRefreshWindows(display,windows);
7758 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7759 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7760 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007761 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007762 XSetCursorState(display,windows,MagickFalse);
7763 if (windows->image.orphan != MagickFalse)
7764 break;
7765 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007766 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007767 break;
7768 }
7769 case SaturationCommand:
7770 {
7771 static char
7772 saturation_percent[MaxTextExtent] = "110";
7773
7774 /*
7775 Query user for percent saturation change.
7776 */
7777 (void) XDialogWidget(display,windows,"Apply",
7778 "Enter percent change in color saturation (0-200):",saturation_percent);
7779 if (*saturation_percent == '\0')
7780 break;
7781 /*
7782 Vary color saturation.
7783 */
7784 XSetCursorState(display,windows,MagickTrue);
7785 XCheckRefreshWindows(display,windows);
7786 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7787 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7788 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007789 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007790 XSetCursorState(display,windows,MagickFalse);
7791 if (windows->image.orphan != MagickFalse)
7792 break;
7793 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007794 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007795 break;
7796 }
7797 case BrightnessCommand:
7798 {
7799 static char
7800 brightness_percent[MaxTextExtent] = "110";
7801
7802 /*
7803 Query user for percent brightness change.
7804 */
7805 (void) XDialogWidget(display,windows,"Apply",
7806 "Enter percent change in color brightness (0-200):",brightness_percent);
7807 if (*brightness_percent == '\0')
7808 break;
7809 /*
7810 Vary the color brightness.
7811 */
7812 XSetCursorState(display,windows,MagickTrue);
7813 XCheckRefreshWindows(display,windows);
7814 (void) CopyMagickString(modulate_factors,brightness_percent,
7815 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007816 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007817 XSetCursorState(display,windows,MagickFalse);
7818 if (windows->image.orphan != MagickFalse)
7819 break;
7820 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007821 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007822 break;
7823 }
7824 case GammaCommand:
7825 {
7826 static char
7827 factor[MaxTextExtent] = "1.6";
7828
7829 /*
7830 Query user for gamma value.
7831 */
7832 (void) XDialogWidget(display,windows,"Gamma",
cristy50fbc382011-07-07 02:19:17 +00007833 "Enter gamma value (e.g. 1.2):",factor);
cristy3ed852e2009-09-05 21:47:34 +00007834 if (*factor == '\0')
7835 break;
7836 /*
7837 Gamma correct image.
7838 */
7839 XSetCursorState(display,windows,MagickTrue);
7840 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007841 (void) GammaImage(*image,atof(factor),exception);
cristy3ed852e2009-09-05 21:47:34 +00007842 XSetCursorState(display,windows,MagickFalse);
7843 if (windows->image.orphan != MagickFalse)
7844 break;
7845 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007846 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007847 break;
7848 }
7849 case SpiffCommand:
7850 {
7851 /*
7852 Sharpen the image contrast.
7853 */
7854 XSetCursorState(display,windows,MagickTrue);
7855 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007856 (void) ContrastImage(*image,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00007857 XSetCursorState(display,windows,MagickFalse);
7858 if (windows->image.orphan != MagickFalse)
7859 break;
7860 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007861 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007862 break;
7863 }
7864 case DullCommand:
7865 {
7866 /*
7867 Dull the image contrast.
7868 */
7869 XSetCursorState(display,windows,MagickTrue);
7870 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007871 (void) ContrastImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007872 XSetCursorState(display,windows,MagickFalse);
7873 if (windows->image.orphan != MagickFalse)
7874 break;
7875 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007876 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007877 break;
7878 }
7879 case ContrastStretchCommand:
7880 {
7881 double
7882 black_point,
7883 white_point;
7884
7885 static char
7886 levels[MaxTextExtent] = "1%";
7887
7888 /*
7889 Query user for gamma value.
7890 */
7891 (void) XDialogWidget(display,windows,"Contrast Stretch",
7892 "Enter black and white points:",levels);
7893 if (*levels == '\0')
7894 break;
7895 /*
7896 Contrast stretch image.
7897 */
7898 XSetCursorState(display,windows,MagickTrue);
7899 XCheckRefreshWindows(display,windows);
7900 flags=ParseGeometry(levels,&geometry_info);
7901 black_point=geometry_info.rho;
7902 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7903 if ((flags & PercentValue) != 0)
7904 {
7905 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7906 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7907 }
7908 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
cristye23ec9d2011-08-16 18:15:40 +00007909 (void) ContrastStretchImage(*image,black_point,white_point,
cristy051718b2011-08-28 22:49:25 +00007910 exception);
cristy3ed852e2009-09-05 21:47:34 +00007911 XSetCursorState(display,windows,MagickFalse);
7912 if (windows->image.orphan != MagickFalse)
7913 break;
7914 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007915 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007916 break;
7917 }
7918 case SigmoidalContrastCommand:
7919 {
cristy9ee60942011-07-06 14:54:38 +00007920 GeometryInfo
7921 geometry_info;
7922
7923 MagickStatusType
7924 flags;
7925
cristy3ed852e2009-09-05 21:47:34 +00007926 static char
7927 levels[MaxTextExtent] = "3x50%";
7928
7929 /*
7930 Query user for gamma value.
7931 */
7932 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7933 "Enter contrast and midpoint:",levels);
7934 if (*levels == '\0')
7935 break;
7936 /*
7937 Contrast stretch image.
7938 */
7939 XSetCursorState(display,windows,MagickTrue);
7940 XCheckRefreshWindows(display,windows);
cristy9ee60942011-07-06 14:54:38 +00007941 flags=ParseGeometry(levels,&geometry_info);
7942 if ((flags & SigmaValue) == 0)
7943 geometry_info.sigma=1.0*QuantumRange/2.0;
7944 if ((flags & PercentValue) != 0)
7945 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7946 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
cristy051718b2011-08-28 22:49:25 +00007947 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00007948 XSetCursorState(display,windows,MagickFalse);
7949 if (windows->image.orphan != MagickFalse)
7950 break;
7951 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007952 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007953 break;
7954 }
7955 case NormalizeCommand:
7956 {
7957 /*
7958 Perform histogram normalization on the image.
7959 */
7960 XSetCursorState(display,windows,MagickTrue);
7961 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007962 (void) NormalizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007963 XSetCursorState(display,windows,MagickFalse);
7964 if (windows->image.orphan != MagickFalse)
7965 break;
7966 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007967 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007968 break;
7969 }
7970 case EqualizeCommand:
7971 {
7972 /*
7973 Perform histogram equalization on the image.
7974 */
7975 XSetCursorState(display,windows,MagickTrue);
7976 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007977 (void) EqualizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007978 XSetCursorState(display,windows,MagickFalse);
7979 if (windows->image.orphan != MagickFalse)
7980 break;
7981 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007982 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007983 break;
7984 }
7985 case NegateCommand:
7986 {
7987 /*
7988 Negate colors in image.
7989 */
7990 XSetCursorState(display,windows,MagickTrue);
7991 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007992 (void) NegateImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007993 XSetCursorState(display,windows,MagickFalse);
7994 if (windows->image.orphan != MagickFalse)
7995 break;
7996 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00007997 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007998 break;
7999 }
8000 case GrayscaleCommand:
8001 {
8002 /*
8003 Convert image to grayscale.
8004 */
8005 XSetCursorState(display,windows,MagickTrue);
8006 XCheckRefreshWindows(display,windows);
8007 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
cristy018f07f2011-09-04 21:15:19 +00008008 GrayscaleType : GrayscaleMatteType,exception);
cristy3ed852e2009-09-05 21:47:34 +00008009 XSetCursorState(display,windows,MagickFalse);
8010 if (windows->image.orphan != MagickFalse)
8011 break;
8012 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008013 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008014 break;
8015 }
8016 case MapCommand:
8017 {
8018 Image
8019 *affinity_image;
8020
8021 static char
8022 filename[MaxTextExtent] = "\0";
8023
8024 /*
8025 Request image file name from user.
8026 */
8027 XFileBrowserWidget(display,windows,"Map",filename);
8028 if (*filename == '\0')
8029 break;
8030 /*
8031 Map image.
8032 */
8033 XSetCursorState(display,windows,MagickTrue);
8034 XCheckRefreshWindows(display,windows);
8035 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00008036 affinity_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00008037 if (affinity_image != (Image *) NULL)
8038 {
cristy018f07f2011-09-04 21:15:19 +00008039 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008040 affinity_image=DestroyImage(affinity_image);
8041 }
cristy051718b2011-08-28 22:49:25 +00008042 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008043 XSetCursorState(display,windows,MagickFalse);
8044 if (windows->image.orphan != MagickFalse)
8045 break;
8046 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008047 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008048 break;
8049 }
8050 case QuantizeCommand:
8051 {
8052 int
8053 status;
8054
8055 static char
8056 colors[MaxTextExtent] = "256";
8057
8058 /*
8059 Query user for maximum number of colors.
8060 */
8061 status=XDialogWidget(display,windows,"Quantize",
8062 "Maximum number of colors:",colors);
8063 if (*colors == '\0')
8064 break;
8065 /*
8066 Color reduce the image.
8067 */
8068 XSetCursorState(display,windows,MagickTrue);
8069 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00008070 quantize_info.number_colors=StringToUnsignedLong(colors);
cristy3ed852e2009-09-05 21:47:34 +00008071 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
cristy018f07f2011-09-04 21:15:19 +00008072 (void) QuantizeImage(&quantize_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008073 XSetCursorState(display,windows,MagickFalse);
8074 if (windows->image.orphan != MagickFalse)
8075 break;
8076 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008077 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008078 break;
8079 }
8080 case DespeckleCommand:
8081 {
8082 Image
8083 *despeckle_image;
8084
8085 /*
8086 Despeckle image.
8087 */
8088 XSetCursorState(display,windows,MagickTrue);
8089 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00008090 despeckle_image=DespeckleImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008091 if (despeckle_image != (Image *) NULL)
8092 {
8093 *image=DestroyImage(*image);
8094 *image=despeckle_image;
8095 }
cristy051718b2011-08-28 22:49:25 +00008096 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008097 XSetCursorState(display,windows,MagickFalse);
8098 if (windows->image.orphan != MagickFalse)
8099 break;
8100 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008101 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008102 break;
8103 }
8104 case EmbossCommand:
8105 {
8106 Image
8107 *emboss_image;
8108
8109 static char
8110 radius[MaxTextExtent] = "0.0x1.0";
8111
8112 /*
8113 Query user for emboss radius.
8114 */
8115 (void) XDialogWidget(display,windows,"Emboss",
8116 "Enter the emboss radius and standard deviation:",radius);
8117 if (*radius == '\0')
8118 break;
8119 /*
8120 Reduce noise in the image.
8121 */
8122 XSetCursorState(display,windows,MagickTrue);
8123 XCheckRefreshWindows(display,windows);
8124 flags=ParseGeometry(radius,&geometry_info);
8125 if ((flags & SigmaValue) == 0)
8126 geometry_info.sigma=1.0;
8127 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008128 exception);
cristy3ed852e2009-09-05 21:47:34 +00008129 if (emboss_image != (Image *) NULL)
8130 {
8131 *image=DestroyImage(*image);
8132 *image=emboss_image;
8133 }
cristy051718b2011-08-28 22:49:25 +00008134 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008135 XSetCursorState(display,windows,MagickFalse);
8136 if (windows->image.orphan != MagickFalse)
8137 break;
8138 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008139 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008140 break;
8141 }
8142 case ReduceNoiseCommand:
8143 {
8144 Image
8145 *noise_image;
8146
8147 static char
8148 radius[MaxTextExtent] = "0";
8149
8150 /*
8151 Query user for noise radius.
8152 */
8153 (void) XDialogWidget(display,windows,"Reduce Noise",
8154 "Enter the noise radius:",radius);
8155 if (*radius == '\0')
8156 break;
8157 /*
8158 Reduce noise in the image.
8159 */
8160 XSetCursorState(display,windows,MagickTrue);
8161 XCheckRefreshWindows(display,windows);
8162 flags=ParseGeometry(radius,&geometry_info);
cristy95c38342011-03-18 22:39:51 +00008163 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
cristy051718b2011-08-28 22:49:25 +00008164 geometry_info.rho,(size_t) geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008165 if (noise_image != (Image *) NULL)
8166 {
8167 *image=DestroyImage(*image);
8168 *image=noise_image;
8169 }
cristy051718b2011-08-28 22:49:25 +00008170 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008171 XSetCursorState(display,windows,MagickFalse);
8172 if (windows->image.orphan != MagickFalse)
8173 break;
8174 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008175 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008176 break;
8177 }
8178 case AddNoiseCommand:
8179 {
8180 char
8181 **noises;
8182
8183 Image
8184 *noise_image;
8185
8186 static char
8187 noise_type[MaxTextExtent] = "Gaussian";
8188
8189 /*
8190 Add noise to the image.
8191 */
cristy042ee782011-04-22 18:48:30 +00008192 noises=GetCommandOptions(MagickNoiseOptions);
cristy3ed852e2009-09-05 21:47:34 +00008193 if (noises == (char **) NULL)
8194 break;
8195 XListBrowserWidget(display,windows,&windows->widget,
8196 (const char **) noises,"Add Noise",
8197 "Select a type of noise to add to your image:",noise_type);
8198 noises=DestroyStringList(noises);
8199 if (*noise_type == '\0')
8200 break;
8201 XSetCursorState(display,windows,MagickTrue);
8202 XCheckRefreshWindows(display,windows);
cristy042ee782011-04-22 18:48:30 +00008203 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
cristy9ed1f812011-10-08 02:00:08 +00008204 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00008205 if (noise_image != (Image *) NULL)
8206 {
8207 *image=DestroyImage(*image);
8208 *image=noise_image;
8209 }
cristy051718b2011-08-28 22:49:25 +00008210 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008211 XSetCursorState(display,windows,MagickFalse);
8212 if (windows->image.orphan != MagickFalse)
8213 break;
8214 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008215 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008216 break;
8217 }
8218 case SharpenCommand:
8219 {
8220 Image
8221 *sharp_image;
8222
8223 static char
8224 radius[MaxTextExtent] = "0.0x1.0";
8225
8226 /*
8227 Query user for sharpen radius.
8228 */
8229 (void) XDialogWidget(display,windows,"Sharpen",
8230 "Enter the sharpen radius and standard deviation:",radius);
8231 if (*radius == '\0')
8232 break;
8233 /*
8234 Sharpen image scanlines.
8235 */
8236 XSetCursorState(display,windows,MagickTrue);
8237 XCheckRefreshWindows(display,windows);
8238 flags=ParseGeometry(radius,&geometry_info);
8239 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
cristy05c0c9a2011-09-05 23:16:13 +00008240 geometry_info.xi,exception);
cristy3ed852e2009-09-05 21:47:34 +00008241 if (sharp_image != (Image *) NULL)
8242 {
8243 *image=DestroyImage(*image);
8244 *image=sharp_image;
8245 }
cristy051718b2011-08-28 22:49:25 +00008246 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008247 XSetCursorState(display,windows,MagickFalse);
8248 if (windows->image.orphan != MagickFalse)
8249 break;
8250 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008251 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008252 break;
8253 }
8254 case BlurCommand:
8255 {
8256 Image
8257 *blur_image;
8258
8259 static char
8260 radius[MaxTextExtent] = "0.0x1.0";
8261
8262 /*
8263 Query user for blur radius.
8264 */
8265 (void) XDialogWidget(display,windows,"Blur",
8266 "Enter the blur radius and standard deviation:",radius);
8267 if (*radius == '\0')
8268 break;
8269 /*
8270 Blur an image.
8271 */
8272 XSetCursorState(display,windows,MagickTrue);
8273 XCheckRefreshWindows(display,windows);
8274 flags=ParseGeometry(radius,&geometry_info);
8275 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
cristy05c0c9a2011-09-05 23:16:13 +00008276 geometry_info.xi,exception);
cristy3ed852e2009-09-05 21:47:34 +00008277 if (blur_image != (Image *) NULL)
8278 {
8279 *image=DestroyImage(*image);
8280 *image=blur_image;
8281 }
cristy051718b2011-08-28 22:49:25 +00008282 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008283 XSetCursorState(display,windows,MagickFalse);
8284 if (windows->image.orphan != MagickFalse)
8285 break;
8286 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008287 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008288 break;
8289 }
8290 case ThresholdCommand:
8291 {
8292 double
8293 threshold;
8294
8295 static char
8296 factor[MaxTextExtent] = "128";
8297
8298 /*
8299 Query user for threshold value.
8300 */
8301 (void) XDialogWidget(display,windows,"Threshold",
8302 "Enter threshold value:",factor);
8303 if (*factor == '\0')
8304 break;
8305 /*
8306 Gamma correct image.
8307 */
8308 XSetCursorState(display,windows,MagickTrue);
8309 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008310 threshold=SiPrefixToDouble(factor,QuantumRange);
cristye941a752011-10-15 01:52:48 +00008311 (void) BilevelImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008312 XSetCursorState(display,windows,MagickFalse);
8313 if (windows->image.orphan != MagickFalse)
8314 break;
8315 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008316 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008317 break;
8318 }
8319 case EdgeDetectCommand:
8320 {
8321 Image
8322 *edge_image;
8323
8324 static char
8325 radius[MaxTextExtent] = "0";
8326
8327 /*
8328 Query user for edge factor.
8329 */
8330 (void) XDialogWidget(display,windows,"Detect Edges",
8331 "Enter the edge detect radius:",radius);
8332 if (*radius == '\0')
8333 break;
8334 /*
8335 Detect edge in image.
8336 */
8337 XSetCursorState(display,windows,MagickTrue);
8338 XCheckRefreshWindows(display,windows);
8339 flags=ParseGeometry(radius,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008340 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8341 exception);
cristy3ed852e2009-09-05 21:47:34 +00008342 if (edge_image != (Image *) NULL)
8343 {
8344 *image=DestroyImage(*image);
8345 *image=edge_image;
8346 }
cristy051718b2011-08-28 22:49:25 +00008347 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008348 XSetCursorState(display,windows,MagickFalse);
8349 if (windows->image.orphan != MagickFalse)
8350 break;
8351 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008352 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008353 break;
8354 }
8355 case SpreadCommand:
8356 {
8357 Image
8358 *spread_image;
8359
8360 static char
8361 amount[MaxTextExtent] = "2";
8362
8363 /*
8364 Query user for spread amount.
8365 */
8366 (void) XDialogWidget(display,windows,"Spread",
8367 "Enter the displacement amount:",amount);
8368 if (*amount == '\0')
8369 break;
8370 /*
8371 Displace image pixels by a random amount.
8372 */
8373 XSetCursorState(display,windows,MagickTrue);
8374 XCheckRefreshWindows(display,windows);
8375 flags=ParseGeometry(amount,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008376 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8377 exception);
cristy3ed852e2009-09-05 21:47:34 +00008378 if (spread_image != (Image *) NULL)
8379 {
8380 *image=DestroyImage(*image);
8381 *image=spread_image;
8382 }
cristy051718b2011-08-28 22:49:25 +00008383 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008384 XSetCursorState(display,windows,MagickFalse);
8385 if (windows->image.orphan != MagickFalse)
8386 break;
8387 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008388 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008389 break;
8390 }
8391 case ShadeCommand:
8392 {
8393 Image
8394 *shade_image;
8395
8396 int
8397 status;
8398
8399 static char
8400 geometry[MaxTextExtent] = "30x30";
8401
8402 /*
8403 Query user for the shade geometry.
8404 */
8405 status=XDialogWidget(display,windows,"Shade",
8406 "Enter the azimuth and elevation of the light source:",geometry);
8407 if (*geometry == '\0')
8408 break;
8409 /*
8410 Shade image pixels.
8411 */
8412 XSetCursorState(display,windows,MagickTrue);
8413 XCheckRefreshWindows(display,windows);
8414 flags=ParseGeometry(geometry,&geometry_info);
8415 if ((flags & SigmaValue) == 0)
8416 geometry_info.sigma=1.0;
8417 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
cristy051718b2011-08-28 22:49:25 +00008418 geometry_info.rho,geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008419 if (shade_image != (Image *) NULL)
8420 {
8421 *image=DestroyImage(*image);
8422 *image=shade_image;
8423 }
cristy051718b2011-08-28 22:49:25 +00008424 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008425 XSetCursorState(display,windows,MagickFalse);
8426 if (windows->image.orphan != MagickFalse)
8427 break;
8428 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008429 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008430 break;
8431 }
8432 case RaiseCommand:
8433 {
8434 static char
8435 bevel_width[MaxTextExtent] = "10";
8436
8437 /*
8438 Query user for bevel width.
8439 */
8440 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8441 if (*bevel_width == '\0')
8442 break;
8443 /*
8444 Raise an image.
8445 */
cristy051718b2011-08-28 22:49:25 +00008446 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8447 exception);
cristy3ed852e2009-09-05 21:47:34 +00008448 XSetCursorState(display,windows,MagickTrue);
8449 XCheckRefreshWindows(display,windows);
8450 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008451 exception);
8452 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00008453 XSetCursorState(display,windows,MagickFalse);
8454 if (windows->image.orphan != MagickFalse)
8455 break;
8456 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008457 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008458 break;
8459 }
8460 case SegmentCommand:
8461 {
8462 static char
8463 threshold[MaxTextExtent] = "1.0x1.5";
8464
8465 /*
8466 Query user for smoothing threshold.
8467 */
8468 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8469 threshold);
8470 if (*threshold == '\0')
8471 break;
8472 /*
8473 Segment an image.
8474 */
8475 XSetCursorState(display,windows,MagickTrue);
8476 XCheckRefreshWindows(display,windows);
8477 flags=ParseGeometry(threshold,&geometry_info);
8478 if ((flags & SigmaValue) == 0)
8479 geometry_info.sigma=1.0;
8480 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
cristy018f07f2011-09-04 21:15:19 +00008481 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008482 XSetCursorState(display,windows,MagickFalse);
8483 if (windows->image.orphan != MagickFalse)
8484 break;
8485 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008486 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008487 break;
8488 }
8489 case SepiaToneCommand:
8490 {
8491 double
8492 threshold;
8493
8494 Image
8495 *sepia_image;
8496
8497 static char
8498 factor[MaxTextExtent] = "80%";
8499
8500 /*
8501 Query user for sepia-tone factor.
8502 */
8503 (void) XDialogWidget(display,windows,"Sepia Tone",
8504 "Enter the sepia tone factor (0 - 99.9%):",factor);
8505 if (*factor == '\0')
8506 break;
8507 /*
8508 Sepia tone image pixels.
8509 */
8510 XSetCursorState(display,windows,MagickTrue);
8511 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008512 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy051718b2011-08-28 22:49:25 +00008513 sepia_image=SepiaToneImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008514 if (sepia_image != (Image *) NULL)
8515 {
8516 *image=DestroyImage(*image);
8517 *image=sepia_image;
8518 }
cristy051718b2011-08-28 22:49:25 +00008519 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008520 XSetCursorState(display,windows,MagickFalse);
8521 if (windows->image.orphan != MagickFalse)
8522 break;
8523 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008524 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008525 break;
8526 }
8527 case SolarizeCommand:
8528 {
8529 double
8530 threshold;
8531
8532 static char
8533 factor[MaxTextExtent] = "60%";
8534
8535 /*
8536 Query user for solarize factor.
8537 */
8538 (void) XDialogWidget(display,windows,"Solarize",
8539 "Enter the solarize factor (0 - 99.9%):",factor);
8540 if (*factor == '\0')
8541 break;
8542 /*
8543 Solarize image pixels.
8544 */
8545 XSetCursorState(display,windows,MagickTrue);
8546 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008547 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy5cbc0162011-08-29 00:36:28 +00008548 (void) SolarizeImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008549 XSetCursorState(display,windows,MagickFalse);
8550 if (windows->image.orphan != MagickFalse)
8551 break;
8552 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008553 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008554 break;
8555 }
8556 case SwirlCommand:
8557 {
8558 Image
8559 *swirl_image;
8560
8561 static char
8562 degrees[MaxTextExtent] = "60";
8563
8564 /*
8565 Query user for swirl angle.
8566 */
8567 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8568 degrees);
8569 if (*degrees == '\0')
8570 break;
8571 /*
8572 Swirl image pixels about the center.
8573 */
8574 XSetCursorState(display,windows,MagickTrue);
8575 XCheckRefreshWindows(display,windows);
8576 flags=ParseGeometry(degrees,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008577 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8578 exception);
cristy3ed852e2009-09-05 21:47:34 +00008579 if (swirl_image != (Image *) NULL)
8580 {
8581 *image=DestroyImage(*image);
8582 *image=swirl_image;
8583 }
cristy051718b2011-08-28 22:49:25 +00008584 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008585 XSetCursorState(display,windows,MagickFalse);
8586 if (windows->image.orphan != MagickFalse)
8587 break;
8588 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008589 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008590 break;
8591 }
8592 case ImplodeCommand:
8593 {
8594 Image
8595 *implode_image;
8596
8597 static char
8598 factor[MaxTextExtent] = "0.3";
8599
8600 /*
8601 Query user for implode factor.
8602 */
8603 (void) XDialogWidget(display,windows,"Implode",
8604 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8605 if (*factor == '\0')
8606 break;
8607 /*
8608 Implode image pixels about the center.
8609 */
8610 XSetCursorState(display,windows,MagickTrue);
8611 XCheckRefreshWindows(display,windows);
8612 flags=ParseGeometry(factor,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008613 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8614 exception);
cristy3ed852e2009-09-05 21:47:34 +00008615 if (implode_image != (Image *) NULL)
8616 {
8617 *image=DestroyImage(*image);
8618 *image=implode_image;
8619 }
cristy051718b2011-08-28 22:49:25 +00008620 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008621 XSetCursorState(display,windows,MagickFalse);
8622 if (windows->image.orphan != MagickFalse)
8623 break;
8624 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008625 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008626 break;
8627 }
8628 case VignetteCommand:
8629 {
8630 Image
8631 *vignette_image;
8632
8633 static char
8634 geometry[MaxTextExtent] = "0x20";
8635
8636 /*
8637 Query user for the vignette geometry.
8638 */
8639 (void) XDialogWidget(display,windows,"Vignette",
8640 "Enter the radius, sigma, and x and y offsets:",geometry);
8641 if (*geometry == '\0')
8642 break;
8643 /*
8644 Soften the edges of the image in vignette style
8645 */
8646 XSetCursorState(display,windows,MagickTrue);
8647 XCheckRefreshWindows(display,windows);
8648 flags=ParseGeometry(geometry,&geometry_info);
8649 if ((flags & SigmaValue) == 0)
8650 geometry_info.sigma=1.0;
8651 if ((flags & XiValue) == 0)
8652 geometry_info.xi=0.1*(*image)->columns;
8653 if ((flags & PsiValue) == 0)
8654 geometry_info.psi=0.1*(*image)->rows;
8655 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
cristyb70a4862010-06-18 01:18:44 +00008656 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
cristy051718b2011-08-28 22:49:25 +00008657 0.5),exception);
cristy3ed852e2009-09-05 21:47:34 +00008658 if (vignette_image != (Image *) NULL)
8659 {
8660 *image=DestroyImage(*image);
8661 *image=vignette_image;
8662 }
cristy051718b2011-08-28 22:49:25 +00008663 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008664 XSetCursorState(display,windows,MagickFalse);
8665 if (windows->image.orphan != MagickFalse)
8666 break;
8667 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008668 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008669 break;
8670 }
8671 case WaveCommand:
8672 {
8673 Image
8674 *wave_image;
8675
8676 static char
8677 geometry[MaxTextExtent] = "25x150";
8678
8679 /*
8680 Query user for the wave geometry.
8681 */
8682 (void) XDialogWidget(display,windows,"Wave",
8683 "Enter the amplitude and length of the wave:",geometry);
8684 if (*geometry == '\0')
8685 break;
8686 /*
cristycee97112010-05-28 00:44:52 +00008687 Alter an image along a sine wave.
cristy3ed852e2009-09-05 21:47:34 +00008688 */
8689 XSetCursorState(display,windows,MagickTrue);
8690 XCheckRefreshWindows(display,windows);
8691 flags=ParseGeometry(geometry,&geometry_info);
8692 if ((flags & SigmaValue) == 0)
8693 geometry_info.sigma=1.0;
8694 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
cristy5c4e2582011-09-11 19:21:03 +00008695 (*image)->interpolate,exception);
cristy3ed852e2009-09-05 21:47:34 +00008696 if (wave_image != (Image *) NULL)
8697 {
8698 *image=DestroyImage(*image);
8699 *image=wave_image;
8700 }
cristy051718b2011-08-28 22:49:25 +00008701 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008702 XSetCursorState(display,windows,MagickFalse);
8703 if (windows->image.orphan != MagickFalse)
8704 break;
8705 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008706 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008707 break;
8708 }
8709 case OilPaintCommand:
8710 {
8711 Image
8712 *paint_image;
8713
8714 static char
8715 radius[MaxTextExtent] = "0";
8716
8717 /*
8718 Query user for circular neighborhood radius.
8719 */
8720 (void) XDialogWidget(display,windows,"Oil Paint",
8721 "Enter the mask radius:",radius);
8722 if (*radius == '\0')
8723 break;
8724 /*
8725 OilPaint image scanlines.
8726 */
8727 XSetCursorState(display,windows,MagickTrue);
8728 XCheckRefreshWindows(display,windows);
8729 flags=ParseGeometry(radius,&geometry_info);
cristy14973ba2011-08-27 23:48:07 +00008730 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008731 exception);
cristy3ed852e2009-09-05 21:47:34 +00008732 if (paint_image != (Image *) NULL)
8733 {
8734 *image=DestroyImage(*image);
8735 *image=paint_image;
8736 }
cristy051718b2011-08-28 22:49:25 +00008737 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008738 XSetCursorState(display,windows,MagickFalse);
8739 if (windows->image.orphan != MagickFalse)
8740 break;
8741 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008742 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008743 break;
8744 }
8745 case CharcoalDrawCommand:
8746 {
8747 Image
8748 *charcoal_image;
8749
8750 static char
8751 radius[MaxTextExtent] = "0x1";
8752
8753 /*
8754 Query user for charcoal radius.
8755 */
8756 (void) XDialogWidget(display,windows,"Charcoal Draw",
8757 "Enter the charcoal radius and sigma:",radius);
8758 if (*radius == '\0')
8759 break;
8760 /*
8761 Charcoal the image.
8762 */
cristy051718b2011-08-28 22:49:25 +00008763 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8764 exception);
cristy3ed852e2009-09-05 21:47:34 +00008765 XSetCursorState(display,windows,MagickTrue);
8766 XCheckRefreshWindows(display,windows);
8767 flags=ParseGeometry(radius,&geometry_info);
8768 if ((flags & SigmaValue) == 0)
8769 geometry_info.sigma=geometry_info.rho;
8770 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
cristy05c0c9a2011-09-05 23:16:13 +00008771 geometry_info.xi,exception);
cristy3ed852e2009-09-05 21:47:34 +00008772 if (charcoal_image != (Image *) NULL)
8773 {
8774 *image=DestroyImage(*image);
8775 *image=charcoal_image;
8776 }
cristy051718b2011-08-28 22:49:25 +00008777 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008778 XSetCursorState(display,windows,MagickFalse);
8779 if (windows->image.orphan != MagickFalse)
8780 break;
8781 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008782 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008783 break;
8784 }
8785 case AnnotateCommand:
8786 {
8787 /*
8788 Annotate the image with text.
8789 */
cristy051718b2011-08-28 22:49:25 +00008790 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008791 if (status == MagickFalse)
8792 {
8793 XNoticeWidget(display,windows,"Unable to annotate X image",
8794 (*image)->filename);
8795 break;
8796 }
8797 break;
8798 }
8799 case DrawCommand:
8800 {
8801 /*
8802 Draw image.
8803 */
cristy051718b2011-08-28 22:49:25 +00008804 status=XDrawEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008805 if (status == MagickFalse)
8806 {
8807 XNoticeWidget(display,windows,"Unable to draw on the X image",
8808 (*image)->filename);
8809 break;
8810 }
8811 break;
8812 }
8813 case ColorCommand:
8814 {
8815 /*
8816 Color edit.
8817 */
cristy051718b2011-08-28 22:49:25 +00008818 status=XColorEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008819 if (status == MagickFalse)
8820 {
8821 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8822 (*image)->filename);
8823 break;
8824 }
8825 break;
8826 }
8827 case MatteCommand:
8828 {
8829 /*
8830 Matte edit.
8831 */
cristy051718b2011-08-28 22:49:25 +00008832 status=XMatteEditImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008833 if (status == MagickFalse)
8834 {
8835 XNoticeWidget(display,windows,"Unable to matte edit X image",
8836 (*image)->filename);
8837 break;
8838 }
8839 break;
8840 }
8841 case CompositeCommand:
8842 {
8843 /*
8844 Composite image.
8845 */
cristy051718b2011-08-28 22:49:25 +00008846 status=XCompositeImage(display,resource_info,windows,*image,
8847 exception);
cristy3ed852e2009-09-05 21:47:34 +00008848 if (status == MagickFalse)
8849 {
8850 XNoticeWidget(display,windows,"Unable to composite X image",
8851 (*image)->filename);
8852 break;
8853 }
8854 break;
8855 }
8856 case AddBorderCommand:
8857 {
8858 Image
8859 *border_image;
8860
8861 static char
8862 geometry[MaxTextExtent] = "6x6";
8863
8864 /*
8865 Query user for border color and geometry.
8866 */
8867 XColorBrowserWidget(display,windows,"Select",color);
8868 if (*color == '\0')
8869 break;
8870 (void) XDialogWidget(display,windows,"Add Border",
8871 "Enter border geometry:",geometry);
8872 if (*geometry == '\0')
8873 break;
8874 /*
8875 Add a border to the image.
8876 */
cristy051718b2011-08-28 22:49:25 +00008877 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8878 exception);
cristy3ed852e2009-09-05 21:47:34 +00008879 XSetCursorState(display,windows,MagickTrue);
8880 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008881 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
cristy051718b2011-08-28 22:49:25 +00008882 exception);
cristy3ed852e2009-09-05 21:47:34 +00008883 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008884 exception);
cristy633f0c62011-09-15 13:27:36 +00008885 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8886 exception);
cristy3ed852e2009-09-05 21:47:34 +00008887 if (border_image != (Image *) NULL)
8888 {
8889 *image=DestroyImage(*image);
8890 *image=border_image;
8891 }
cristy051718b2011-08-28 22:49:25 +00008892 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008893 XSetCursorState(display,windows,MagickFalse);
8894 if (windows->image.orphan != MagickFalse)
8895 break;
8896 windows->image.window_changes.width=(int) (*image)->columns;
8897 windows->image.window_changes.height=(int) (*image)->rows;
8898 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008899 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008900 break;
8901 }
8902 case AddFrameCommand:
8903 {
8904 FrameInfo
8905 frame_info;
8906
8907 Image
8908 *frame_image;
8909
8910 static char
8911 geometry[MaxTextExtent] = "6x6";
8912
8913 /*
8914 Query user for frame color and geometry.
8915 */
8916 XColorBrowserWidget(display,windows,"Select",color);
8917 if (*color == '\0')
8918 break;
8919 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8920 geometry);
8921 if (*geometry == '\0')
8922 break;
8923 /*
8924 Surround image with an ornamental border.
8925 */
cristy051718b2011-08-28 22:49:25 +00008926 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8927 exception);
cristy3ed852e2009-09-05 21:47:34 +00008928 XSetCursorState(display,windows,MagickTrue);
8929 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008930 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
cristy051718b2011-08-28 22:49:25 +00008931 exception);
cristy3ed852e2009-09-05 21:47:34 +00008932 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008933 exception);
cristy3ed852e2009-09-05 21:47:34 +00008934 frame_info.width=page_geometry.width;
8935 frame_info.height=page_geometry.height;
8936 frame_info.outer_bevel=page_geometry.x;
8937 frame_info.inner_bevel=page_geometry.y;
cristybb503372010-05-27 20:51:26 +00008938 frame_info.x=(ssize_t) frame_info.width;
8939 frame_info.y=(ssize_t) frame_info.height;
cristy3ed852e2009-09-05 21:47:34 +00008940 frame_info.width=(*image)->columns+2*frame_info.width;
8941 frame_info.height=(*image)->rows+2*frame_info.height;
cristy633f0c62011-09-15 13:27:36 +00008942 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
cristy3ed852e2009-09-05 21:47:34 +00008943 if (frame_image != (Image *) NULL)
8944 {
8945 *image=DestroyImage(*image);
8946 *image=frame_image;
8947 }
cristy051718b2011-08-28 22:49:25 +00008948 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008949 XSetCursorState(display,windows,MagickFalse);
8950 if (windows->image.orphan != MagickFalse)
8951 break;
8952 windows->image.window_changes.width=(int) (*image)->columns;
8953 windows->image.window_changes.height=(int) (*image)->rows;
8954 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00008955 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008956 break;
8957 }
8958 case CommentCommand:
8959 {
8960 const char
8961 *value;
8962
8963 FILE
8964 *file;
8965
8966 int
8967 unique_file;
8968
8969 /*
8970 Edit image comment.
8971 */
8972 unique_file=AcquireUniqueFileResource(image_info->filename);
8973 if (unique_file == -1)
8974 XNoticeWidget(display,windows,"Unable to edit image comment",
8975 image_info->filename);
cristyd15e6592011-10-15 00:13:06 +00008976 value=GetImageProperty(*image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +00008977 if (value == (char *) NULL)
8978 unique_file=close(unique_file)-1;
8979 else
8980 {
8981 register const char
8982 *p;
8983
8984 file=fdopen(unique_file,"w");
8985 if (file == (FILE *) NULL)
8986 {
8987 XNoticeWidget(display,windows,"Unable to edit image comment",
8988 image_info->filename);
8989 break;
8990 }
8991 for (p=value; *p != '\0'; p++)
8992 (void) fputc((int) *p,file);
8993 (void) fputc('\n',file);
8994 (void) fclose(file);
8995 }
8996 XSetCursorState(display,windows,MagickTrue);
8997 XCheckRefreshWindows(display,windows);
8998 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00008999 exception);
cristy3ed852e2009-09-05 21:47:34 +00009000 if (status == MagickFalse)
9001 XNoticeWidget(display,windows,"Unable to edit image comment",
9002 (char *) NULL);
9003 else
9004 {
9005 char
9006 *comment;
9007
cristy051718b2011-08-28 22:49:25 +00009008 comment=FileToString(image_info->filename,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00009009 if (comment != (char *) NULL)
9010 {
cristyd15e6592011-10-15 00:13:06 +00009011 (void) SetImageProperty(*image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +00009012 (*image)->taint=MagickTrue;
9013 }
9014 }
9015 (void) RelinquishUniqueFileResource(image_info->filename);
9016 XSetCursorState(display,windows,MagickFalse);
9017 break;
9018 }
9019 case LaunchCommand:
9020 {
9021 /*
9022 Launch program.
9023 */
9024 XSetCursorState(display,windows,MagickTrue);
9025 XCheckRefreshWindows(display,windows);
9026 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009027 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
cristy3ed852e2009-09-05 21:47:34 +00009028 filename);
cristy051718b2011-08-28 22:49:25 +00009029 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009030 if (status == MagickFalse)
9031 XNoticeWidget(display,windows,"Unable to launch image editor",
9032 (char *) NULL);
9033 else
9034 {
cristy051718b2011-08-28 22:49:25 +00009035 nexus=ReadImage(resource_info->image_info,exception);
9036 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00009037 XClientMessage(display,windows->image.id,windows->im_protocols,
9038 windows->im_next_image,CurrentTime);
9039 }
9040 (void) RelinquishUniqueFileResource(filename);
9041 XSetCursorState(display,windows,MagickFalse);
9042 break;
9043 }
9044 case RegionofInterestCommand:
9045 {
9046 /*
9047 Apply an image processing technique to a region of interest.
9048 */
cristy051718b2011-08-28 22:49:25 +00009049 (void) XROIImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009050 break;
9051 }
9052 case InfoCommand:
9053 break;
9054 case ZoomCommand:
9055 {
9056 /*
9057 Zoom image.
9058 */
9059 if (windows->magnify.mapped != MagickFalse)
9060 (void) XRaiseWindow(display,windows->magnify.id);
9061 else
9062 {
9063 /*
9064 Make magnify image.
9065 */
9066 XSetCursorState(display,windows,MagickTrue);
9067 (void) XMapRaised(display,windows->magnify.id);
9068 XSetCursorState(display,windows,MagickFalse);
9069 }
9070 break;
9071 }
9072 case ShowPreviewCommand:
9073 {
9074 char
9075 **previews;
9076
9077 Image
9078 *preview_image;
9079
9080 static char
9081 preview_type[MaxTextExtent] = "Gamma";
9082
9083 /*
9084 Select preview type from menu.
9085 */
cristy042ee782011-04-22 18:48:30 +00009086 previews=GetCommandOptions(MagickPreviewOptions);
cristy3ed852e2009-09-05 21:47:34 +00009087 if (previews == (char **) NULL)
9088 break;
9089 XListBrowserWidget(display,windows,&windows->widget,
9090 (const char **) previews,"Preview",
9091 "Select an enhancement, effect, or F/X:",preview_type);
9092 previews=DestroyStringList(previews);
9093 if (*preview_type == '\0')
9094 break;
9095 /*
9096 Show image preview.
9097 */
9098 XSetCursorState(display,windows,MagickTrue);
9099 XCheckRefreshWindows(display,windows);
9100 image_info->preview_type=(PreviewType)
cristy042ee782011-04-22 18:48:30 +00009101 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
cristybb503372010-05-27 20:51:26 +00009102 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009103 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009104 (void) SetImageProperty(*image,"label","Preview",exception);
cristy3ed852e2009-09-05 21:47:34 +00009105 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009106 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
cristy3ed852e2009-09-05 21:47:34 +00009107 filename);
cristy051718b2011-08-28 22:49:25 +00009108 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009109 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009110 preview_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009111 (void) RelinquishUniqueFileResource(filename);
9112 if (preview_image == (Image *) NULL)
9113 break;
cristyb51dff52011-05-19 16:55:47 +00009114 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009115 filename);
cristy051718b2011-08-28 22:49:25 +00009116 status=WriteImage(image_info,preview_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009117 preview_image=DestroyImage(preview_image);
9118 if (status == MagickFalse)
9119 XNoticeWidget(display,windows,"Unable to show image preview",
9120 (*image)->filename);
9121 XDelay(display,1500);
9122 XSetCursorState(display,windows,MagickFalse);
9123 break;
9124 }
9125 case ShowHistogramCommand:
9126 {
9127 Image
9128 *histogram_image;
9129
9130 /*
9131 Show image histogram.
9132 */
9133 XSetCursorState(display,windows,MagickTrue);
9134 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009135 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009136 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009137 (void) SetImageProperty(*image,"label","Histogram",exception);
cristy3ed852e2009-09-05 21:47:34 +00009138 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009139 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
cristy3ed852e2009-09-05 21:47:34 +00009140 filename);
cristy051718b2011-08-28 22:49:25 +00009141 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009142 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009143 histogram_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009144 (void) RelinquishUniqueFileResource(filename);
9145 if (histogram_image == (Image *) NULL)
9146 break;
cristyb51dff52011-05-19 16:55:47 +00009147 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009148 "show:%s",filename);
cristy051718b2011-08-28 22:49:25 +00009149 status=WriteImage(image_info,histogram_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009150 histogram_image=DestroyImage(histogram_image);
9151 if (status == MagickFalse)
9152 XNoticeWidget(display,windows,"Unable to show histogram",
9153 (*image)->filename);
9154 XDelay(display,1500);
9155 XSetCursorState(display,windows,MagickFalse);
9156 break;
9157 }
9158 case ShowMatteCommand:
9159 {
9160 Image
9161 *matte_image;
9162
9163 if ((*image)->matte == MagickFalse)
9164 {
9165 XNoticeWidget(display,windows,
9166 "Image does not have any matte information",(*image)->filename);
9167 break;
9168 }
9169 /*
9170 Show image matte.
9171 */
9172 XSetCursorState(display,windows,MagickTrue);
9173 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009174 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009175 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009176 (void) SetImageProperty(*image,"label","Matte",exception);
cristy3ed852e2009-09-05 21:47:34 +00009177 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009178 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
cristy3ed852e2009-09-05 21:47:34 +00009179 filename);
cristy051718b2011-08-28 22:49:25 +00009180 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009181 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009182 matte_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009183 (void) RelinquishUniqueFileResource(filename);
9184 if (matte_image == (Image *) NULL)
9185 break;
cristyb51dff52011-05-19 16:55:47 +00009186 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009187 filename);
cristy051718b2011-08-28 22:49:25 +00009188 status=WriteImage(image_info,matte_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009189 matte_image=DestroyImage(matte_image);
9190 if (status == MagickFalse)
9191 XNoticeWidget(display,windows,"Unable to show matte",
9192 (*image)->filename);
9193 XDelay(display,1500);
9194 XSetCursorState(display,windows,MagickFalse);
9195 break;
9196 }
9197 case BackgroundCommand:
9198 {
9199 /*
9200 Background image.
9201 */
cristy051718b2011-08-28 22:49:25 +00009202 status=XBackgroundImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009203 if (status == MagickFalse)
9204 break;
cristy051718b2011-08-28 22:49:25 +00009205 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009206 if (nexus != (Image *) NULL)
9207 XClientMessage(display,windows->image.id,windows->im_protocols,
9208 windows->im_next_image,CurrentTime);
9209 break;
9210 }
9211 case SlideShowCommand:
9212 {
9213 static char
9214 delay[MaxTextExtent] = "5";
9215
9216 /*
9217 Display next image after pausing.
9218 */
9219 (void) XDialogWidget(display,windows,"Slide Show",
9220 "Pause how many 1/100ths of a second between images:",delay);
9221 if (*delay == '\0')
9222 break;
cristye27293e2009-12-18 02:53:20 +00009223 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009224 XClientMessage(display,windows->image.id,windows->im_protocols,
9225 windows->im_next_image,CurrentTime);
9226 break;
9227 }
9228 case PreferencesCommand:
9229 {
9230 /*
9231 Set user preferences.
9232 */
9233 status=XPreferencesWidget(display,resource_info,windows);
9234 if (status == MagickFalse)
9235 break;
cristy051718b2011-08-28 22:49:25 +00009236 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009237 if (nexus != (Image *) NULL)
9238 XClientMessage(display,windows->image.id,windows->im_protocols,
9239 windows->im_next_image,CurrentTime);
9240 break;
9241 }
9242 case HelpCommand:
9243 {
9244 /*
9245 User requested help.
9246 */
9247 XTextViewWidget(display,resource_info,windows,MagickFalse,
9248 "Help Viewer - Display",DisplayHelp);
9249 break;
9250 }
9251 case BrowseDocumentationCommand:
9252 {
9253 Atom
9254 mozilla_atom;
9255
9256 Window
9257 mozilla_window,
9258 root_window;
9259
9260 /*
9261 Browse the ImageMagick documentation.
9262 */
9263 root_window=XRootWindow(display,XDefaultScreen(display));
9264 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9265 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9266 if (mozilla_window != (Window) NULL)
9267 {
9268 char
9269 command[MaxTextExtent],
9270 *url;
9271
9272 /*
9273 Display documentation using Netscape remote control.
9274 */
9275 url=GetMagickHomeURL();
cristyb51dff52011-05-19 16:55:47 +00009276 (void) FormatLocaleString(command,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009277 "openurl(%s,new-tab)",url);
9278 url=DestroyString(url);
9279 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9280 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9281 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9282 XSetCursorState(display,windows,MagickFalse);
9283 break;
9284 }
9285 XSetCursorState(display,windows,MagickTrue);
9286 XCheckRefreshWindows(display,windows);
9287 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00009288 exception);
cristy3ed852e2009-09-05 21:47:34 +00009289 if (status == MagickFalse)
9290 XNoticeWidget(display,windows,"Unable to browse documentation",
9291 (char *) NULL);
9292 XDelay(display,1500);
9293 XSetCursorState(display,windows,MagickFalse);
9294 break;
9295 }
9296 case VersionCommand:
9297 {
cristybb503372010-05-27 20:51:26 +00009298 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +00009299 GetMagickCopyright());
9300 break;
9301 }
9302 case SaveToUndoBufferCommand:
9303 break;
9304 default:
9305 {
9306 (void) XBell(display,0);
9307 break;
9308 }
9309 }
9310 image_info=DestroyImageInfo(image_info);
9311 return(nexus);
9312}
9313
9314/*
9315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9316% %
9317% %
9318% %
9319+ X M a g n i f y I m a g e %
9320% %
9321% %
9322% %
9323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9324%
9325% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9326% The magnified portion is displayed in a separate window.
9327%
9328% The format of the XMagnifyImage method is:
9329%
9330% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9331%
9332% A description of each parameter follows:
9333%
9334% o display: Specifies a connection to an X server; returned from
9335% XOpenDisplay.
9336%
9337% o windows: Specifies a pointer to a XWindows structure.
9338%
9339% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9340% the entire image is refreshed.
9341%
9342*/
9343static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9344{
9345 char
9346 text[MaxTextExtent];
9347
9348 register int
9349 x,
9350 y;
9351
cristybb503372010-05-27 20:51:26 +00009352 size_t
cristy3ed852e2009-09-05 21:47:34 +00009353 state;
9354
9355 /*
9356 Update magnified image until the mouse button is released.
9357 */
9358 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9359 state=DefaultState;
9360 x=event->xbutton.x;
9361 y=event->xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00009362 windows->magnify.x=(int) windows->image.x+x;
9363 windows->magnify.y=(int) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00009364 do
9365 {
9366 /*
9367 Map and unmap Info widget as text cursor crosses its boundaries.
9368 */
9369 if (windows->info.mapped != MagickFalse)
9370 {
9371 if ((x < (int) (windows->info.x+windows->info.width)) &&
9372 (y < (int) (windows->info.y+windows->info.height)))
9373 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9374 }
9375 else
9376 if ((x > (int) (windows->info.x+windows->info.width)) ||
9377 (y > (int) (windows->info.y+windows->info.height)))
9378 (void) XMapWindow(display,windows->info.id);
9379 if (windows->info.mapped != MagickFalse)
9380 {
9381 /*
9382 Display pointer position.
9383 */
cristyb51dff52011-05-19 16:55:47 +00009384 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009385 windows->magnify.x,windows->magnify.y);
9386 XInfoWidget(display,windows,text);
9387 }
9388 /*
9389 Wait for next event.
9390 */
9391 XScreenEvent(display,windows,event);
9392 switch (event->type)
9393 {
9394 case ButtonPress:
9395 break;
9396 case ButtonRelease:
9397 {
9398 /*
9399 User has finished magnifying image.
9400 */
9401 x=event->xbutton.x;
9402 y=event->xbutton.y;
9403 state|=ExitState;
9404 break;
9405 }
9406 case Expose:
9407 break;
9408 case MotionNotify:
9409 {
9410 x=event->xmotion.x;
9411 y=event->xmotion.y;
9412 break;
9413 }
9414 default:
9415 break;
9416 }
9417 /*
9418 Check boundary conditions.
9419 */
9420 if (x < 0)
9421 x=0;
9422 else
9423 if (x >= (int) windows->image.width)
9424 x=(int) windows->image.width-1;
9425 if (y < 0)
9426 y=0;
9427 else
9428 if (y >= (int) windows->image.height)
9429 y=(int) windows->image.height-1;
9430 } while ((state & ExitState) == 0);
9431 /*
9432 Display magnified image.
9433 */
9434 XSetCursorState(display,windows,MagickFalse);
9435}
9436
9437/*
9438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9439% %
9440% %
9441% %
9442+ X M a g n i f y W i n d o w C o m m a n d %
9443% %
9444% %
9445% %
9446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9447%
9448% XMagnifyWindowCommand() moves the image within an Magnify window by one
9449% pixel as specified by the key symbol.
9450%
9451% The format of the XMagnifyWindowCommand method is:
9452%
9453% void XMagnifyWindowCommand(Display *display,XWindows *windows,
9454% const MagickStatusType state,const KeySym key_symbol)
9455%
9456% A description of each parameter follows:
9457%
9458% o display: Specifies a connection to an X server; returned from
9459% XOpenDisplay.
9460%
9461% o windows: Specifies a pointer to a XWindows structure.
9462%
9463% o state: key mask.
9464%
9465% o key_symbol: Specifies a KeySym which indicates which side of the image
9466% to trim.
9467%
9468*/
9469static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9470 const MagickStatusType state,const KeySym key_symbol)
9471{
9472 unsigned int
9473 quantum;
9474
9475 /*
9476 User specified a magnify factor or position.
9477 */
9478 quantum=1;
9479 if ((state & Mod1Mask) != 0)
9480 quantum=10;
9481 switch ((int) key_symbol)
9482 {
9483 case QuitCommand:
9484 {
9485 (void) XWithdrawWindow(display,windows->magnify.id,
9486 windows->magnify.screen);
9487 break;
9488 }
9489 case XK_Home:
9490 case XK_KP_Home:
9491 {
9492 windows->magnify.x=(int) windows->image.width/2;
9493 windows->magnify.y=(int) windows->image.height/2;
9494 break;
9495 }
9496 case XK_Left:
9497 case XK_KP_Left:
9498 {
9499 if (windows->magnify.x > 0)
9500 windows->magnify.x-=quantum;
9501 break;
9502 }
9503 case XK_Up:
9504 case XK_KP_Up:
9505 {
9506 if (windows->magnify.y > 0)
9507 windows->magnify.y-=quantum;
9508 break;
9509 }
9510 case XK_Right:
9511 case XK_KP_Right:
9512 {
9513 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9514 windows->magnify.x+=quantum;
9515 break;
9516 }
9517 case XK_Down:
9518 case XK_KP_Down:
9519 {
9520 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9521 windows->magnify.y+=quantum;
9522 break;
9523 }
9524 case XK_0:
9525 case XK_1:
9526 case XK_2:
9527 case XK_3:
9528 case XK_4:
9529 case XK_5:
9530 case XK_6:
9531 case XK_7:
9532 case XK_8:
9533 case XK_9:
9534 {
9535 windows->magnify.data=(key_symbol-XK_0);
9536 break;
9537 }
9538 case XK_KP_0:
9539 case XK_KP_1:
9540 case XK_KP_2:
9541 case XK_KP_3:
9542 case XK_KP_4:
9543 case XK_KP_5:
9544 case XK_KP_6:
9545 case XK_KP_7:
9546 case XK_KP_8:
9547 case XK_KP_9:
9548 {
9549 windows->magnify.data=(key_symbol-XK_KP_0);
9550 break;
9551 }
9552 default:
9553 break;
9554 }
9555 XMakeMagnifyImage(display,windows);
9556}
9557
9558/*
9559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9560% %
9561% %
9562% %
9563+ X M a k e P a n I m a g e %
9564% %
9565% %
9566% %
9567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9568%
9569% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9570% icon window.
9571%
9572% The format of the XMakePanImage method is:
9573%
9574% void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009575% XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009576%
9577% A description of each parameter follows:
9578%
9579% o display: Specifies a connection to an X server; returned from
9580% XOpenDisplay.
9581%
9582% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9583%
9584% o windows: Specifies a pointer to a XWindows structure.
9585%
9586% o image: the image.
9587%
cristy051718b2011-08-28 22:49:25 +00009588% o exception: return any errors or warnings in this structure.
9589%
cristy3ed852e2009-09-05 21:47:34 +00009590*/
9591static void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009592 XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009593{
9594 MagickStatusType
9595 status;
9596
9597 /*
9598 Create and display image for panning icon.
9599 */
9600 XSetCursorState(display,windows,MagickTrue);
9601 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +00009602 windows->pan.x=(int) windows->image.x;
9603 windows->pan.y=(int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +00009604 status=XMakeImage(display,resource_info,&windows->pan,image,
cristy051718b2011-08-28 22:49:25 +00009605 windows->pan.width,windows->pan.height,exception);
cristy3ed852e2009-09-05 21:47:34 +00009606 if (status == MagickFalse)
cristy051718b2011-08-28 22:49:25 +00009607 ThrowXWindowFatalException(ResourceLimitError,
9608 "MemoryAllocationFailed",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00009609 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9610 windows->pan.pixmap);
9611 (void) XClearWindow(display,windows->pan.id);
9612 XDrawPanRectangle(display,windows);
9613 XSetCursorState(display,windows,MagickFalse);
9614}
9615
9616/*
9617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9618% %
9619% %
9620% %
9621+ X M a t t a E d i t I m a g e %
9622% %
9623% %
9624% %
9625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9626%
9627% XMatteEditImage() allows the user to interactively change the Matte channel
9628% of an image. If the image is PseudoClass it is promoted to DirectClass
9629% before the matte information is stored.
9630%
9631% The format of the XMatteEditImage method is:
9632%
9633% MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009634% XResourceInfo *resource_info,XWindows *windows,Image **image,
9635% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009636%
9637% A description of each parameter follows:
9638%
9639% o display: Specifies a connection to an X server; returned from
9640% XOpenDisplay.
9641%
9642% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9643%
9644% o windows: Specifies a pointer to a XWindows structure.
9645%
9646% o image: the image; returned from ReadImage.
9647%
cristy051718b2011-08-28 22:49:25 +00009648% o exception: return any errors or warnings in this structure.
9649%
cristy3ed852e2009-09-05 21:47:34 +00009650*/
9651static MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009652 XResourceInfo *resource_info,XWindows *windows,Image **image,
9653 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009654{
9655 static char
9656 matte[MaxTextExtent] = "0";
9657
9658 static const char
9659 *MatteEditMenu[] =
9660 {
9661 "Method",
9662 "Border Color",
9663 "Fuzz",
9664 "Matte Value",
9665 "Undo",
9666 "Help",
9667 "Dismiss",
9668 (char *) NULL
9669 };
9670
9671 static const ModeType
9672 MatteEditCommands[] =
9673 {
9674 MatteEditMethod,
9675 MatteEditBorderCommand,
9676 MatteEditFuzzCommand,
9677 MatteEditValueCommand,
9678 MatteEditUndoCommand,
9679 MatteEditHelpCommand,
9680 MatteEditDismissCommand
9681 };
9682
9683 static PaintMethod
9684 method = PointMethod;
9685
9686 static XColor
9687 border_color = { 0, 0, 0, 0, 0, 0 };
9688
9689 char
9690 command[MaxTextExtent],
9691 text[MaxTextExtent];
9692
9693 Cursor
9694 cursor;
9695
9696 int
9697 entry,
9698 id,
9699 x,
9700 x_offset,
9701 y,
9702 y_offset;
9703
9704 register int
9705 i;
9706
cristy4c08aed2011-07-01 19:47:50 +00009707 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00009708 *q;
9709
9710 unsigned int
9711 height,
9712 width;
9713
cristybb503372010-05-27 20:51:26 +00009714 size_t
cristy3ed852e2009-09-05 21:47:34 +00009715 state;
9716
9717 XEvent
9718 event;
9719
9720 /*
9721 Map Command widget.
9722 */
9723 (void) CloneString(&windows->command.name,"Matte Edit");
9724 windows->command.data=4;
9725 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9726 (void) XMapRaised(display,windows->command.id);
9727 XClientMessage(display,windows->image.id,windows->im_protocols,
9728 windows->im_update_widget,CurrentTime);
9729 /*
9730 Make cursor.
9731 */
9732 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9733 resource_info->background_color,resource_info->foreground_color);
9734 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9735 /*
9736 Track pointer until button 1 is pressed.
9737 */
9738 XQueryPosition(display,windows->image.id,&x,&y);
9739 (void) XSelectInput(display,windows->image.id,
9740 windows->image.attributes.event_mask | PointerMotionMask);
9741 state=DefaultState;
9742 do
9743 {
9744 if (windows->info.mapped != MagickFalse)
9745 {
9746 /*
9747 Display pointer position.
9748 */
cristyb51dff52011-05-19 16:55:47 +00009749 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009750 x+windows->image.x,y+windows->image.y);
9751 XInfoWidget(display,windows,text);
9752 }
9753 /*
9754 Wait for next event.
9755 */
9756 XScreenEvent(display,windows,&event);
9757 if (event.xany.window == windows->command.id)
9758 {
9759 /*
9760 Select a command from the Command widget.
9761 */
9762 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9763 if (id < 0)
9764 {
9765 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9766 continue;
9767 }
9768 switch (MatteEditCommands[id])
9769 {
9770 case MatteEditMethod:
9771 {
9772 char
9773 **methods;
9774
9775 /*
9776 Select a method from the pop-up menu.
9777 */
cristy042ee782011-04-22 18:48:30 +00009778 methods=GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00009779 if (methods == (char **) NULL)
9780 break;
9781 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9782 (const char **) methods,command);
9783 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00009784 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00009785 MagickFalse,methods[entry]);
9786 methods=DestroyStringList(methods);
9787 break;
9788 }
9789 case MatteEditBorderCommand:
9790 {
9791 const char
9792 *ColorMenu[MaxNumberPens];
9793
9794 int
9795 pen_number;
9796
9797 /*
9798 Initialize menu selections.
9799 */
9800 for (i=0; i < (int) (MaxNumberPens-2); i++)
9801 ColorMenu[i]=resource_info->pen_colors[i];
9802 ColorMenu[MaxNumberPens-2]="Browser...";
9803 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9804 /*
9805 Select a pen color from the pop-up menu.
9806 */
9807 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9808 (const char **) ColorMenu,command);
9809 if (pen_number < 0)
9810 break;
9811 if (pen_number == (MaxNumberPens-2))
9812 {
9813 static char
9814 color_name[MaxTextExtent] = "gray";
9815
9816 /*
9817 Select a pen color from a dialog.
9818 */
9819 resource_info->pen_colors[pen_number]=color_name;
9820 XColorBrowserWidget(display,windows,"Select",color_name);
9821 if (*color_name == '\0')
9822 break;
9823 }
9824 /*
9825 Set border color.
9826 */
9827 (void) XParseColor(display,windows->map_info->colormap,
9828 resource_info->pen_colors[pen_number],&border_color);
9829 break;
9830 }
9831 case MatteEditFuzzCommand:
9832 {
9833 static char
9834 fuzz[MaxTextExtent];
9835
9836 static const char
9837 *FuzzMenu[] =
9838 {
9839 "0%",
9840 "2%",
9841 "5%",
9842 "10%",
9843 "15%",
9844 "Dialog...",
9845 (char *) NULL,
9846 };
9847
9848 /*
9849 Select a command from the pop-up menu.
9850 */
9851 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9852 command);
9853 if (entry < 0)
9854 break;
9855 if (entry != 5)
9856 {
cristy4c08aed2011-07-01 19:47:50 +00009857 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
9858 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009859 break;
9860 }
9861 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9862 (void) XDialogWidget(display,windows,"Ok",
9863 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9864 if (*fuzz == '\0')
9865 break;
9866 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00009867 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009868 break;
9869 }
9870 case MatteEditValueCommand:
9871 {
9872 static char
9873 message[MaxTextExtent];
9874
9875 static const char
9876 *MatteMenu[] =
9877 {
9878 "Opaque",
9879 "Transparent",
9880 "Dialog...",
9881 (char *) NULL,
9882 };
9883
9884 /*
9885 Select a command from the pop-up menu.
9886 */
9887 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9888 command);
9889 if (entry < 0)
9890 break;
9891 if (entry != 2)
9892 {
cristyb51dff52011-05-19 16:55:47 +00009893 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009894 OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009895 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
cristyb51dff52011-05-19 16:55:47 +00009896 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009897 (Quantum) TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009898 break;
9899 }
cristyb51dff52011-05-19 16:55:47 +00009900 (void) FormatLocaleString(message,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009901 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9902 QuantumRange);
9903 (void) XDialogWidget(display,windows,"Matte",message,matte);
9904 if (*matte == '\0')
9905 break;
9906 break;
9907 }
9908 case MatteEditUndoCommand:
9909 {
9910 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00009911 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009912 break;
9913 }
9914 case MatteEditHelpCommand:
9915 {
9916 XTextViewWidget(display,resource_info,windows,MagickFalse,
9917 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9918 break;
9919 }
9920 case MatteEditDismissCommand:
9921 {
9922 /*
9923 Prematurely exit.
9924 */
9925 state|=EscapeState;
9926 state|=ExitState;
9927 break;
9928 }
9929 default:
9930 break;
9931 }
9932 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9933 continue;
9934 }
9935 switch (event.type)
9936 {
9937 case ButtonPress:
9938 {
9939 if (event.xbutton.button != Button1)
9940 break;
9941 if ((event.xbutton.window != windows->image.id) &&
9942 (event.xbutton.window != windows->magnify.id))
9943 break;
9944 /*
9945 Update matte data.
9946 */
9947 x=event.xbutton.x;
9948 y=event.xbutton.y;
9949 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00009950 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009951 state|=UpdateConfigurationState;
9952 break;
9953 }
9954 case ButtonRelease:
9955 {
9956 if (event.xbutton.button != Button1)
9957 break;
9958 if ((event.xbutton.window != windows->image.id) &&
9959 (event.xbutton.window != windows->magnify.id))
9960 break;
9961 /*
9962 Update colormap information.
9963 */
9964 x=event.xbutton.x;
9965 y=event.xbutton.y;
9966 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +00009967 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009968 XInfoWidget(display,windows,text);
9969 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9970 state&=(~UpdateConfigurationState);
9971 break;
9972 }
9973 case Expose:
9974 break;
9975 case KeyPress:
9976 {
9977 char
9978 command[MaxTextExtent];
9979
9980 KeySym
9981 key_symbol;
9982
9983 if (event.xkey.window == windows->magnify.id)
9984 {
9985 Window
9986 window;
9987
9988 window=windows->magnify.id;
9989 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9990 }
9991 if (event.xkey.window != windows->image.id)
9992 break;
9993 /*
9994 Respond to a user key press.
9995 */
9996 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9997 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9998 switch ((int) key_symbol)
9999 {
10000 case XK_Escape:
10001 case XK_F20:
10002 {
10003 /*
10004 Prematurely exit.
10005 */
10006 state|=ExitState;
10007 break;
10008 }
10009 case XK_F1:
10010 case XK_Help:
10011 {
10012 XTextViewWidget(display,resource_info,windows,MagickFalse,
10013 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10014 break;
10015 }
10016 default:
10017 {
10018 (void) XBell(display,0);
10019 break;
10020 }
10021 }
10022 break;
10023 }
10024 case MotionNotify:
10025 {
10026 /*
10027 Map and unmap Info widget as cursor crosses its boundaries.
10028 */
10029 x=event.xmotion.x;
10030 y=event.xmotion.y;
10031 if (windows->info.mapped != MagickFalse)
10032 {
10033 if ((x < (int) (windows->info.x+windows->info.width)) &&
10034 (y < (int) (windows->info.y+windows->info.height)))
10035 (void) XWithdrawWindow(display,windows->info.id,
10036 windows->info.screen);
10037 }
10038 else
10039 if ((x > (int) (windows->info.x+windows->info.width)) ||
10040 (y > (int) (windows->info.y+windows->info.height)))
10041 (void) XMapWindow(display,windows->info.id);
10042 break;
10043 }
10044 default:
10045 break;
10046 }
10047 if (event.xany.window == windows->magnify.id)
10048 {
10049 x=windows->magnify.x-windows->image.x;
10050 y=windows->magnify.y-windows->image.y;
10051 }
10052 x_offset=x;
10053 y_offset=y;
10054 if ((state & UpdateConfigurationState) != 0)
10055 {
cristy49e2d862010-11-12 02:50:30 +000010056 CacheView
10057 *image_view;
10058
cristy3ed852e2009-09-05 21:47:34 +000010059 int
10060 x,
10061 y;
10062
10063 /*
10064 Matte edit is relative to image configuration.
10065 */
10066 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10067 MagickTrue);
10068 XPutPixel(windows->image.ximage,x_offset,y_offset,
10069 windows->pixel_info->background_color.pixel);
10070 width=(unsigned int) (*image)->columns;
10071 height=(unsigned int) (*image)->rows;
10072 x=0;
10073 y=0;
10074 if (windows->image.crop_geometry != (char *) NULL)
cristy4c08aed2011-07-01 19:47:50 +000010075 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10076 &height);
10077 x_offset=(int) (width*(windows->image.x+x_offset)/
10078 windows->image.ximage->width+x);
10079 y_offset=(int) (height*(windows->image.y+y_offset)/
10080 windows->image.ximage->height+y);
cristy3ed852e2009-09-05 21:47:34 +000010081 if ((x_offset < 0) || (y_offset < 0))
10082 continue;
10083 if ((x_offset >= (int) (*image)->columns) ||
10084 (y_offset >= (int) (*image)->rows))
10085 continue;
cristy574cc262011-08-05 01:23:58 +000010086 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010087 return(MagickFalse);
10088 (*image)->matte=MagickTrue;
cristy49e2d862010-11-12 02:50:30 +000010089 image_view=AcquireCacheView(*image);
cristy3ed852e2009-09-05 21:47:34 +000010090 switch (method)
10091 {
10092 case PointMethod:
10093 default:
10094 {
10095 /*
10096 Update matte information using point algorithm.
10097 */
cristy49e2d862010-11-12 02:50:30 +000010098 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10099 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010100 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010101 break;
cristy4c08aed2011-07-01 19:47:50 +000010102 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristy49e2d862010-11-12 02:50:30 +000010103 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +000010104 break;
10105 }
10106 case ReplaceMethod:
10107 {
cristy101ab702011-10-13 13:06:32 +000010108 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +000010109 pixel,
cristy3ed852e2009-09-05 21:47:34 +000010110 target;
10111
cristy2ed42f62011-10-02 19:49:57 +000010112 Quantum
10113 virtual_pixel[MaxPixelChannels];
10114
cristy3ed852e2009-09-05 21:47:34 +000010115 /*
10116 Update matte information using replace algorithm.
10117 */
cristy49e2d862010-11-12 02:50:30 +000010118 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
cristy2ed42f62011-10-02 19:49:57 +000010119 (ssize_t) y_offset,virtual_pixel,exception);
10120 target.red=virtual_pixel[RedPixelChannel];
10121 target.green=virtual_pixel[GreenPixelChannel];
10122 target.blue=virtual_pixel[BluePixelChannel];
10123 target.alpha=virtual_pixel[AlphaPixelChannel];
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 */
cristy49e2d862010-11-12 02:50:30 +000010157 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10158 (ssize_t) y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +000010159 if (method == FillToBorderMethod)
10160 {
cristy4c08aed2011-07-01 19:47:50 +000010161 target.red=(MagickRealType) ScaleShortToQuantum(
10162 border_color.red);
10163 target.green=(MagickRealType) ScaleShortToQuantum(
10164 border_color.green);
10165 target.blue=(MagickRealType) ScaleShortToQuantum(
10166 border_color.blue);
cristy3ed852e2009-09-05 21:47:34 +000010167 }
10168 draw_info=CloneDrawInfo(resource_info->image_info,
10169 (DrawInfo *) NULL);
cristy4c08aed2011-07-01 19:47:50 +000010170 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte,
cristy0df696d2011-05-18 19:55:22 +000010171 (char **) NULL));
cristybd5a96c2011-08-21 00:04:26 +000010172 channel_mask=SetPixelChannelMask(*image,AlphaChannel);
cristyd42d9952011-07-08 14:21:50 +000010173 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10174 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
cristy189e84c2011-08-27 18:08:53 +000010175 MagickFalse : MagickTrue,exception);
cristybd5a96c2011-08-21 00:04:26 +000010176 (void) SetPixelChannelMap(*image,channel_mask);
cristy3ed852e2009-09-05 21:47:34 +000010177 draw_info=DestroyDrawInfo(draw_info);
10178 break;
10179 }
10180 case ResetMethod:
10181 {
10182 /*
10183 Update matte information using reset algorithm.
10184 */
cristy574cc262011-08-05 01:23:58 +000010185 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010186 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +000010187 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010188 {
cristy49e2d862010-11-12 02:50:30 +000010189 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10190 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010191 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010192 break;
10193 for (x=0; x < (int) (*image)->columns; x++)
10194 {
cristy4c08aed2011-07-01 19:47:50 +000010195 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010196 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010197 }
cristy49e2d862010-11-12 02:50:30 +000010198 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000010199 break;
10200 }
cristy4c08aed2011-07-01 19:47:50 +000010201 if (StringToLong(matte) == (long) OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +000010202 (*image)->matte=MagickFalse;
10203 break;
10204 }
10205 }
cristy49e2d862010-11-12 02:50:30 +000010206 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000010207 state&=(~UpdateConfigurationState);
10208 }
10209 } while ((state & ExitState) == 0);
10210 (void) XSelectInput(display,windows->image.id,
10211 windows->image.attributes.event_mask);
10212 XSetCursorState(display,windows,MagickFalse);
10213 (void) XFreeCursor(display,cursor);
10214 return(MagickTrue);
10215}
10216
10217/*
10218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10219% %
10220% %
10221% %
10222+ X O p e n I m a g e %
10223% %
10224% %
10225% %
10226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10227%
10228% XOpenImage() loads an image from a file.
10229%
10230% The format of the XOpenImage method is:
10231%
10232% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10233% XWindows *windows,const unsigned int command)
10234%
10235% A description of each parameter follows:
10236%
10237% o display: Specifies a connection to an X server; returned from
10238% XOpenDisplay.
10239%
10240% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10241%
10242% o windows: Specifies a pointer to a XWindows structure.
10243%
10244% o command: A value other than zero indicates that the file is selected
10245% from the command line argument list.
10246%
10247*/
10248static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10249 XWindows *windows,const MagickBooleanType command)
10250{
10251 const MagickInfo
10252 *magick_info;
10253
10254 ExceptionInfo
10255 *exception;
10256
10257 Image
10258 *nexus;
10259
10260 ImageInfo
10261 *image_info;
10262
10263 static char
10264 filename[MaxTextExtent] = "\0";
10265
10266 /*
10267 Request file name from user.
10268 */
10269 if (command == MagickFalse)
10270 XFileBrowserWidget(display,windows,"Open",filename);
10271 else
10272 {
10273 char
10274 **filelist,
10275 **files;
10276
10277 int
10278 count,
10279 status;
10280
10281 register int
10282 i,
10283 j;
10284
10285 /*
10286 Select next image from the command line.
10287 */
10288 status=XGetCommand(display,windows->image.id,&files,&count);
10289 if (status == 0)
10290 {
10291 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10292 return((Image *) NULL);
10293 }
10294 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10295 if (filelist == (char **) NULL)
10296 {
10297 ThrowXWindowFatalException(ResourceLimitError,
10298 "MemoryAllocationFailed","...");
10299 (void) XFreeStringList(files);
10300 return((Image *) NULL);
10301 }
10302 j=0;
10303 for (i=1; i < count; i++)
10304 if (*files[i] != '-')
10305 filelist[j++]=files[i];
10306 filelist[j]=(char *) NULL;
10307 XListBrowserWidget(display,windows,&windows->widget,
10308 (const char **) filelist,"Load","Select Image to Load:",filename);
10309 filelist=(char **) RelinquishMagickMemory(filelist);
10310 (void) XFreeStringList(files);
10311 }
10312 if (*filename == '\0')
10313 return((Image *) NULL);
10314 image_info=CloneImageInfo(resource_info->image_info);
10315 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10316 (void *) NULL);
10317 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10318 exception=AcquireExceptionInfo();
cristyd965a422010-03-03 17:47:35 +000010319 (void) SetImageInfo(image_info,0,exception);
cristy3ed852e2009-09-05 21:47:34 +000010320 if (LocaleCompare(image_info->magick,"X") == 0)
10321 {
10322 char
10323 seconds[MaxTextExtent];
10324
10325 /*
10326 User may want to delay the X server screen grab.
10327 */
10328 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10329 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10330 seconds);
10331 if (*seconds == '\0')
10332 return((Image *) NULL);
cristybb503372010-05-27 20:51:26 +000010333 XDelay(display,(size_t) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010334 }
10335 magick_info=GetMagickInfo(image_info->magick,exception);
10336 if ((magick_info != (const MagickInfo *) NULL) &&
10337 (magick_info->raw != MagickFalse))
10338 {
10339 char
10340 geometry[MaxTextExtent];
10341
10342 /*
10343 Request image size from the user.
10344 */
10345 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10346 if (image_info->size != (char *) NULL)
10347 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10348 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10349 geometry);
10350 (void) CloneString(&image_info->size,geometry);
10351 }
10352 /*
10353 Load the image.
10354 */
10355 XSetCursorState(display,windows,MagickTrue);
10356 XCheckRefreshWindows(display,windows);
10357 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10358 nexus=ReadImage(image_info,exception);
10359 CatchException(exception);
10360 XSetCursorState(display,windows,MagickFalse);
10361 if (nexus != (Image *) NULL)
10362 XClientMessage(display,windows->image.id,windows->im_protocols,
10363 windows->im_next_image,CurrentTime);
10364 else
10365 {
10366 char
10367 *text,
10368 **textlist;
10369
10370 /*
10371 Unknown image format.
10372 */
10373 text=FileToString(filename,~0,exception);
10374 if (text == (char *) NULL)
10375 return((Image *) NULL);
10376 textlist=StringToList(text);
10377 if (textlist != (char **) NULL)
10378 {
10379 char
10380 title[MaxTextExtent];
10381
10382 register int
10383 i;
10384
cristyb51dff52011-05-19 16:55:47 +000010385 (void) FormatLocaleString(title,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000010386 "Unknown format: %s",filename);
10387 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10388 (const char **) textlist);
10389 for (i=0; textlist[i] != (char *) NULL; i++)
10390 textlist[i]=DestroyString(textlist[i]);
10391 textlist=(char **) RelinquishMagickMemory(textlist);
10392 }
10393 text=DestroyString(text);
10394 }
10395 exception=DestroyExceptionInfo(exception);
10396 image_info=DestroyImageInfo(image_info);
10397 return(nexus);
10398}
10399
10400/*
10401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10402% %
10403% %
10404% %
10405+ X P a n I m a g e %
10406% %
10407% %
10408% %
10409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10410%
10411% XPanImage() pans the image until the mouse button is released.
10412%
10413% The format of the XPanImage method is:
10414%
10415% void XPanImage(Display *display,XWindows *windows,XEvent *event)
10416%
10417% A description of each parameter follows:
10418%
10419% o display: Specifies a connection to an X server; returned from
10420% XOpenDisplay.
10421%
10422% o windows: Specifies a pointer to a XWindows structure.
10423%
10424% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10425% the entire image is refreshed.
10426%
10427*/
10428static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10429{
10430 char
10431 text[MaxTextExtent];
10432
10433 Cursor
10434 cursor;
10435
10436 MagickRealType
10437 x_factor,
10438 y_factor;
10439
10440 RectangleInfo
10441 pan_info;
10442
cristybb503372010-05-27 20:51:26 +000010443 size_t
cristy3ed852e2009-09-05 21:47:34 +000010444 state;
10445
10446 /*
10447 Define cursor.
10448 */
10449 if ((windows->image.ximage->width > (int) windows->image.width) &&
10450 (windows->image.ximage->height > (int) windows->image.height))
10451 cursor=XCreateFontCursor(display,XC_fleur);
10452 else
10453 if (windows->image.ximage->width > (int) windows->image.width)
10454 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10455 else
10456 if (windows->image.ximage->height > (int) windows->image.height)
10457 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10458 else
10459 cursor=XCreateFontCursor(display,XC_arrow);
10460 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10461 /*
10462 Pan image as pointer moves until the mouse button is released.
10463 */
10464 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10465 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10466 pan_info.width=windows->pan.width*windows->image.width/
10467 windows->image.ximage->width;
10468 pan_info.height=windows->pan.height*windows->image.height/
10469 windows->image.ximage->height;
10470 pan_info.x=0;
10471 pan_info.y=0;
10472 state=UpdateConfigurationState;
10473 do
10474 {
10475 switch (event->type)
10476 {
10477 case ButtonPress:
10478 {
10479 /*
10480 User choose an initial pan location.
10481 */
cristy49e2d862010-11-12 02:50:30 +000010482 pan_info.x=(ssize_t) event->xbutton.x;
10483 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010484 state|=UpdateConfigurationState;
10485 break;
10486 }
10487 case ButtonRelease:
10488 {
10489 /*
10490 User has finished panning the image.
10491 */
cristy49e2d862010-11-12 02:50:30 +000010492 pan_info.x=(ssize_t) event->xbutton.x;
10493 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010494 state|=UpdateConfigurationState | ExitState;
10495 break;
10496 }
10497 case MotionNotify:
10498 {
cristy49e2d862010-11-12 02:50:30 +000010499 pan_info.x=(ssize_t) event->xmotion.x;
10500 pan_info.y=(ssize_t) event->xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000010501 state|=UpdateConfigurationState;
10502 }
10503 default:
10504 break;
10505 }
10506 if ((state & UpdateConfigurationState) != 0)
10507 {
10508 /*
10509 Check boundary conditions.
10510 */
cristy49e2d862010-11-12 02:50:30 +000010511 if (pan_info.x < (ssize_t) (pan_info.width/2))
cristy3ed852e2009-09-05 21:47:34 +000010512 pan_info.x=0;
10513 else
cristy49e2d862010-11-12 02:50:30 +000010514 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
cristy3ed852e2009-09-05 21:47:34 +000010515 if (pan_info.x < 0)
10516 pan_info.x=0;
10517 else
10518 if ((int) (pan_info.x+windows->image.width) >
10519 windows->image.ximage->width)
cristybb503372010-05-27 20:51:26 +000010520 pan_info.x=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010521 (windows->image.ximage->width-windows->image.width);
cristybb503372010-05-27 20:51:26 +000010522 if (pan_info.y < (ssize_t) (pan_info.height/2))
cristy3ed852e2009-09-05 21:47:34 +000010523 pan_info.y=0;
10524 else
cristybb503372010-05-27 20:51:26 +000010525 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
cristy3ed852e2009-09-05 21:47:34 +000010526 if (pan_info.y < 0)
10527 pan_info.y=0;
10528 else
10529 if ((int) (pan_info.y+windows->image.height) >
10530 windows->image.ximage->height)
cristybb503372010-05-27 20:51:26 +000010531 pan_info.y=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010532 (windows->image.ximage->height-windows->image.height);
10533 if ((windows->image.x != (int) pan_info.x) ||
10534 (windows->image.y != (int) pan_info.y))
10535 {
10536 /*
10537 Display image pan offset.
10538 */
10539 windows->image.x=(int) pan_info.x;
10540 windows->image.y=(int) pan_info.y;
cristyb51dff52011-05-19 16:55:47 +000010541 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000010542 windows->image.width,windows->image.height,windows->image.x,
10543 windows->image.y);
10544 XInfoWidget(display,windows,text);
10545 /*
10546 Refresh Image window.
10547 */
10548 XDrawPanRectangle(display,windows);
10549 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10550 }
10551 state&=(~UpdateConfigurationState);
10552 }
10553 /*
10554 Wait for next event.
10555 */
10556 if ((state & ExitState) == 0)
10557 XScreenEvent(display,windows,event);
10558 } while ((state & ExitState) == 0);
10559 /*
10560 Restore cursor.
10561 */
10562 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10563 (void) XFreeCursor(display,cursor);
10564 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10565}
10566
10567/*
10568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10569% %
10570% %
10571% %
10572+ X P a s t e I m a g e %
10573% %
10574% %
10575% %
10576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10577%
10578% XPasteImage() pastes an image previously saved with XCropImage in the X
10579% window image at a location the user chooses with the pointer.
10580%
10581% The format of the XPasteImage method is:
10582%
10583% MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010584% XResourceInfo *resource_info,XWindows *windows,Image *image,
10585% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010586%
10587% A description of each parameter follows:
10588%
10589% o display: Specifies a connection to an X server; returned from
10590% XOpenDisplay.
10591%
10592% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10593%
10594% o windows: Specifies a pointer to a XWindows structure.
10595%
10596% o image: the image; returned from ReadImage.
10597%
cristy051718b2011-08-28 22:49:25 +000010598% o exception: return any errors or warnings in this structure.
10599%
cristy3ed852e2009-09-05 21:47:34 +000010600*/
10601static MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010602 XResourceInfo *resource_info,XWindows *windows,Image *image,
10603 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010604{
10605 static const char
10606 *PasteMenu[] =
10607 {
10608 "Operator",
10609 "Help",
10610 "Dismiss",
10611 (char *) NULL
10612 };
10613
10614 static const ModeType
10615 PasteCommands[] =
10616 {
10617 PasteOperatorsCommand,
10618 PasteHelpCommand,
10619 PasteDismissCommand
10620 };
10621
10622 static CompositeOperator
10623 compose = CopyCompositeOp;
10624
10625 char
10626 text[MaxTextExtent];
10627
10628 Cursor
10629 cursor;
10630
10631 Image
10632 *paste_image;
10633
10634 int
10635 entry,
10636 id,
10637 x,
10638 y;
10639
10640 MagickRealType
10641 scale_factor;
10642
10643 RectangleInfo
10644 highlight_info,
10645 paste_info;
10646
10647 unsigned int
10648 height,
10649 width;
10650
cristybb503372010-05-27 20:51:26 +000010651 size_t
cristy3ed852e2009-09-05 21:47:34 +000010652 state;
10653
10654 XEvent
10655 event;
10656
10657 /*
10658 Copy image.
10659 */
10660 if (resource_info->copy_image == (Image *) NULL)
10661 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +000010662 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000010663 /*
10664 Map Command widget.
10665 */
10666 (void) CloneString(&windows->command.name,"Paste");
10667 windows->command.data=1;
10668 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10669 (void) XMapRaised(display,windows->command.id);
10670 XClientMessage(display,windows->image.id,windows->im_protocols,
10671 windows->im_update_widget,CurrentTime);
10672 /*
10673 Track pointer until button 1 is pressed.
10674 */
10675 XSetCursorState(display,windows,MagickFalse);
10676 XQueryPosition(display,windows->image.id,&x,&y);
10677 (void) XSelectInput(display,windows->image.id,
10678 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000010679 paste_info.x=(ssize_t) windows->image.x+x;
10680 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010681 paste_info.width=0;
10682 paste_info.height=0;
10683 cursor=XCreateFontCursor(display,XC_ul_angle);
10684 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10685 state=DefaultState;
10686 do
10687 {
10688 if (windows->info.mapped != MagickFalse)
10689 {
10690 /*
10691 Display pointer position.
10692 */
cristyb51dff52011-05-19 16:55:47 +000010693 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000010694 (long) paste_info.x,(long) paste_info.y);
cristy3ed852e2009-09-05 21:47:34 +000010695 XInfoWidget(display,windows,text);
10696 }
10697 highlight_info=paste_info;
10698 highlight_info.x=paste_info.x-windows->image.x;
10699 highlight_info.y=paste_info.y-windows->image.y;
10700 XHighlightRectangle(display,windows->image.id,
10701 windows->image.highlight_context,&highlight_info);
10702 /*
10703 Wait for next event.
10704 */
10705 XScreenEvent(display,windows,&event);
10706 XHighlightRectangle(display,windows->image.id,
10707 windows->image.highlight_context,&highlight_info);
10708 if (event.xany.window == windows->command.id)
10709 {
10710 /*
10711 Select a command from the Command widget.
10712 */
10713 id=XCommandWidget(display,windows,PasteMenu,&event);
10714 if (id < 0)
10715 continue;
10716 switch (PasteCommands[id])
10717 {
10718 case PasteOperatorsCommand:
10719 {
10720 char
10721 command[MaxTextExtent],
10722 **operators;
10723
10724 /*
10725 Select a command from the pop-up menu.
10726 */
cristy042ee782011-04-22 18:48:30 +000010727 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +000010728 if (operators == (char **) NULL)
10729 break;
10730 entry=XMenuWidget(display,windows,PasteMenu[id],
10731 (const char **) operators,command);
10732 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +000010733 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +000010734 MagickComposeOptions,MagickFalse,operators[entry]);
10735 operators=DestroyStringList(operators);
10736 break;
10737 }
10738 case PasteHelpCommand:
10739 {
10740 XTextViewWidget(display,resource_info,windows,MagickFalse,
10741 "Help Viewer - Image Composite",ImagePasteHelp);
10742 break;
10743 }
10744 case PasteDismissCommand:
10745 {
10746 /*
10747 Prematurely exit.
10748 */
10749 state|=EscapeState;
10750 state|=ExitState;
10751 break;
10752 }
10753 default:
10754 break;
10755 }
10756 continue;
10757 }
10758 switch (event.type)
10759 {
10760 case ButtonPress:
10761 {
10762 if (image->debug != MagickFalse)
10763 (void) LogMagickEvent(X11Event,GetMagickModule(),
10764 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10765 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10766 if (event.xbutton.button != Button1)
10767 break;
10768 if (event.xbutton.window != windows->image.id)
10769 break;
10770 /*
10771 Paste rectangle is relative to image configuration.
10772 */
10773 width=(unsigned int) image->columns;
10774 height=(unsigned int) image->rows;
10775 x=0;
10776 y=0;
10777 if (windows->image.crop_geometry != (char *) NULL)
10778 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10779 &width,&height);
10780 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10781 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10782 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10783 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10784 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000010785 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10786 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010787 break;
10788 }
10789 case ButtonRelease:
10790 {
10791 if (image->debug != MagickFalse)
10792 (void) LogMagickEvent(X11Event,GetMagickModule(),
10793 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10794 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10795 if (event.xbutton.button != Button1)
10796 break;
10797 if (event.xbutton.window != windows->image.id)
10798 break;
10799 if ((paste_info.width != 0) && (paste_info.height != 0))
10800 {
10801 /*
10802 User has selected the location of the paste image.
10803 */
cristy49e2d862010-11-12 02:50:30 +000010804 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10805 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010806 state|=ExitState;
10807 }
10808 break;
10809 }
10810 case Expose:
10811 break;
10812 case KeyPress:
10813 {
10814 char
10815 command[MaxTextExtent];
10816
10817 KeySym
10818 key_symbol;
10819
10820 int
10821 length;
10822
10823 if (event.xkey.window != windows->image.id)
10824 break;
10825 /*
10826 Respond to a user key press.
10827 */
10828 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10829 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10830 *(command+length)='\0';
10831 if (image->debug != MagickFalse)
10832 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000010833 "Key press: 0x%lx (%s)",(long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +000010834 switch ((int) key_symbol)
10835 {
10836 case XK_Escape:
10837 case XK_F20:
10838 {
10839 /*
10840 Prematurely exit.
10841 */
10842 paste_image=DestroyImage(paste_image);
10843 state|=EscapeState;
10844 state|=ExitState;
10845 break;
10846 }
10847 case XK_F1:
10848 case XK_Help:
10849 {
10850 (void) XSetFunction(display,windows->image.highlight_context,
10851 GXcopy);
10852 XTextViewWidget(display,resource_info,windows,MagickFalse,
10853 "Help Viewer - Image Composite",ImagePasteHelp);
10854 (void) XSetFunction(display,windows->image.highlight_context,
10855 GXinvert);
10856 break;
10857 }
10858 default:
10859 {
10860 (void) XBell(display,0);
10861 break;
10862 }
10863 }
10864 break;
10865 }
10866 case MotionNotify:
10867 {
10868 /*
10869 Map and unmap Info widget as text cursor crosses its boundaries.
10870 */
10871 x=event.xmotion.x;
10872 y=event.xmotion.y;
10873 if (windows->info.mapped != MagickFalse)
10874 {
10875 if ((x < (int) (windows->info.x+windows->info.width)) &&
10876 (y < (int) (windows->info.y+windows->info.height)))
10877 (void) XWithdrawWindow(display,windows->info.id,
10878 windows->info.screen);
10879 }
10880 else
10881 if ((x > (int) (windows->info.x+windows->info.width)) ||
10882 (y > (int) (windows->info.y+windows->info.height)))
10883 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000010884 paste_info.x=(ssize_t) windows->image.x+x;
10885 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010886 break;
10887 }
10888 default:
10889 {
10890 if (image->debug != MagickFalse)
10891 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10892 event.type);
10893 break;
10894 }
10895 }
10896 } while ((state & ExitState) == 0);
10897 (void) XSelectInput(display,windows->image.id,
10898 windows->image.attributes.event_mask);
10899 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10900 XSetCursorState(display,windows,MagickFalse);
10901 (void) XFreeCursor(display,cursor);
10902 if ((state & EscapeState) != 0)
10903 return(MagickTrue);
10904 /*
10905 Image pasting is relative to image configuration.
10906 */
10907 XSetCursorState(display,windows,MagickTrue);
10908 XCheckRefreshWindows(display,windows);
10909 width=(unsigned int) image->columns;
10910 height=(unsigned int) image->rows;
10911 x=0;
10912 y=0;
10913 if (windows->image.crop_geometry != (char *) NULL)
10914 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10915 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10916 paste_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000010917 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010918 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10919 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10920 paste_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000010921 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010922 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10923 /*
10924 Paste image with X Image window.
10925 */
cristye941a752011-10-15 01:52:48 +000010926 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y,
10927 exception);
cristy3ed852e2009-09-05 21:47:34 +000010928 paste_image=DestroyImage(paste_image);
10929 XSetCursorState(display,windows,MagickFalse);
10930 /*
10931 Update image colormap.
10932 */
10933 XConfigureImageColormap(display,resource_info,windows,image);
cristy051718b2011-08-28 22:49:25 +000010934 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010935 return(MagickTrue);
10936}
10937
10938/*
10939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10940% %
10941% %
10942% %
10943+ X P r i n t I m a g e %
10944% %
10945% %
10946% %
10947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10948%
10949% XPrintImage() prints an image to a Postscript printer.
10950%
10951% The format of the XPrintImage method is:
10952%
10953% MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010954% XResourceInfo *resource_info,XWindows *windows,Image *image,
10955% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010956%
10957% A description of each parameter follows:
10958%
10959% o display: Specifies a connection to an X server; returned from
10960% XOpenDisplay.
10961%
10962% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10963%
10964% o windows: Specifies a pointer to a XWindows structure.
10965%
10966% o image: the image.
10967%
cristy051718b2011-08-28 22:49:25 +000010968% o exception: return any errors or warnings in this structure.
10969%
cristy3ed852e2009-09-05 21:47:34 +000010970*/
10971static MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010972 XResourceInfo *resource_info,XWindows *windows,Image *image,
10973 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010974{
10975 char
10976 filename[MaxTextExtent],
10977 geometry[MaxTextExtent];
10978
10979 Image
10980 *print_image;
10981
10982 ImageInfo
10983 *image_info;
10984
10985 MagickStatusType
10986 status;
10987
10988 /*
10989 Request Postscript page geometry from user.
10990 */
10991 image_info=CloneImageInfo(resource_info->image_info);
cristyb51dff52011-05-19 16:55:47 +000010992 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
cristy3ed852e2009-09-05 21:47:34 +000010993 if (image_info->page != (char *) NULL)
10994 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10995 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10996 "Select Postscript Page Geometry:",geometry);
10997 if (*geometry == '\0')
10998 return(MagickTrue);
10999 image_info->page=GetPageGeometry(geometry);
11000 /*
11001 Apply image transforms.
11002 */
11003 XSetCursorState(display,windows,MagickTrue);
11004 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000011005 print_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000011006 if (print_image == (Image *) NULL)
11007 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000011008 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000011009 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000011010 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11011 exception);
cristy3ed852e2009-09-05 21:47:34 +000011012 /*
11013 Print image.
11014 */
11015 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +000011016 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
cristy3ed852e2009-09-05 21:47:34 +000011017 filename);
cristy051718b2011-08-28 22:49:25 +000011018 status=WriteImage(image_info,print_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011019 (void) RelinquishUniqueFileResource(filename);
11020 print_image=DestroyImage(print_image);
11021 image_info=DestroyImageInfo(image_info);
11022 XSetCursorState(display,windows,MagickFalse);
11023 return(status != 0 ? MagickTrue : MagickFalse);
11024}
11025
11026/*
11027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11028% %
11029% %
11030% %
11031+ X R O I I m a g e %
11032% %
11033% %
11034% %
11035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11036%
11037% XROIImage() applies an image processing technique to a region of interest.
11038%
11039% The format of the XROIImage method is:
11040%
11041% MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011042% XResourceInfo *resource_info,XWindows *windows,Image **image,
11043% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011044%
11045% A description of each parameter follows:
11046%
11047% o display: Specifies a connection to an X server; returned from
11048% XOpenDisplay.
11049%
11050% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11051%
11052% o windows: Specifies a pointer to a XWindows structure.
11053%
11054% o image: the image; returned from ReadImage.
11055%
cristy051718b2011-08-28 22:49:25 +000011056% o exception: return any errors or warnings in this structure.
11057%
cristy3ed852e2009-09-05 21:47:34 +000011058*/
11059static MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011060 XResourceInfo *resource_info,XWindows *windows,Image **image,
11061 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011062{
11063#define ApplyMenus 7
11064
11065 static const char
11066 *ROIMenu[] =
11067 {
11068 "Help",
11069 "Dismiss",
11070 (char *) NULL
11071 },
11072 *ApplyMenu[] =
11073 {
11074 "File",
11075 "Edit",
11076 "Transform",
11077 "Enhance",
11078 "Effects",
11079 "F/X",
11080 "Miscellany",
11081 "Help",
11082 "Dismiss",
11083 (char *) NULL
11084 },
11085 *FileMenu[] =
11086 {
11087 "Save...",
11088 "Print...",
11089 (char *) NULL
11090 },
11091 *EditMenu[] =
11092 {
11093 "Undo",
11094 "Redo",
11095 (char *) NULL
11096 },
11097 *TransformMenu[] =
11098 {
11099 "Flop",
11100 "Flip",
11101 "Rotate Right",
11102 "Rotate Left",
11103 (char *) NULL
11104 },
11105 *EnhanceMenu[] =
11106 {
11107 "Hue...",
11108 "Saturation...",
11109 "Brightness...",
11110 "Gamma...",
11111 "Spiff",
11112 "Dull",
11113 "Contrast Stretch...",
11114 "Sigmoidal Contrast...",
11115 "Normalize",
11116 "Equalize",
11117 "Negate",
11118 "Grayscale",
11119 "Map...",
11120 "Quantize...",
11121 (char *) NULL
11122 },
11123 *EffectsMenu[] =
11124 {
11125 "Despeckle",
11126 "Emboss",
11127 "Reduce Noise",
11128 "Add Noise",
11129 "Sharpen...",
11130 "Blur...",
11131 "Threshold...",
11132 "Edge Detect...",
11133 "Spread...",
11134 "Shade...",
11135 "Raise...",
11136 "Segment...",
11137 (char *) NULL
11138 },
11139 *FXMenu[] =
11140 {
11141 "Solarize...",
11142 "Sepia Tone...",
11143 "Swirl...",
11144 "Implode...",
11145 "Vignette...",
11146 "Wave...",
11147 "Oil Paint...",
11148 "Charcoal Draw...",
11149 (char *) NULL
11150 },
11151 *MiscellanyMenu[] =
11152 {
11153 "Image Info",
11154 "Zoom Image",
11155 "Show Preview...",
11156 "Show Histogram",
11157 "Show Matte",
11158 (char *) NULL
11159 };
11160
11161 static const char
11162 **Menus[ApplyMenus] =
11163 {
11164 FileMenu,
11165 EditMenu,
11166 TransformMenu,
11167 EnhanceMenu,
11168 EffectsMenu,
11169 FXMenu,
11170 MiscellanyMenu
11171 };
11172
11173 static const CommandType
11174 ApplyCommands[] =
11175 {
11176 NullCommand,
11177 NullCommand,
11178 NullCommand,
11179 NullCommand,
11180 NullCommand,
11181 NullCommand,
11182 NullCommand,
11183 HelpCommand,
11184 QuitCommand
11185 },
11186 FileCommands[] =
11187 {
11188 SaveCommand,
11189 PrintCommand
11190 },
11191 EditCommands[] =
11192 {
11193 UndoCommand,
11194 RedoCommand
11195 },
11196 TransformCommands[] =
11197 {
11198 FlopCommand,
11199 FlipCommand,
11200 RotateRightCommand,
11201 RotateLeftCommand
11202 },
11203 EnhanceCommands[] =
11204 {
11205 HueCommand,
11206 SaturationCommand,
11207 BrightnessCommand,
11208 GammaCommand,
11209 SpiffCommand,
11210 DullCommand,
11211 ContrastStretchCommand,
11212 SigmoidalContrastCommand,
11213 NormalizeCommand,
11214 EqualizeCommand,
11215 NegateCommand,
11216 GrayscaleCommand,
11217 MapCommand,
11218 QuantizeCommand
11219 },
11220 EffectsCommands[] =
11221 {
11222 DespeckleCommand,
11223 EmbossCommand,
11224 ReduceNoiseCommand,
11225 AddNoiseCommand,
11226 SharpenCommand,
11227 BlurCommand,
11228 EdgeDetectCommand,
11229 SpreadCommand,
11230 ShadeCommand,
11231 RaiseCommand,
11232 SegmentCommand
11233 },
11234 FXCommands[] =
11235 {
11236 SolarizeCommand,
11237 SepiaToneCommand,
11238 SwirlCommand,
11239 ImplodeCommand,
11240 VignetteCommand,
11241 WaveCommand,
11242 OilPaintCommand,
11243 CharcoalDrawCommand
11244 },
11245 MiscellanyCommands[] =
11246 {
11247 InfoCommand,
11248 ZoomCommand,
11249 ShowPreviewCommand,
11250 ShowHistogramCommand,
11251 ShowMatteCommand
11252 },
11253 ROICommands[] =
11254 {
11255 ROIHelpCommand,
11256 ROIDismissCommand
11257 };
11258
11259 static const CommandType
11260 *Commands[ApplyMenus] =
11261 {
11262 FileCommands,
11263 EditCommands,
11264 TransformCommands,
11265 EnhanceCommands,
11266 EffectsCommands,
11267 FXCommands,
11268 MiscellanyCommands
11269 };
11270
11271 char
11272 command[MaxTextExtent],
11273 text[MaxTextExtent];
11274
11275 CommandType
11276 command_type;
11277
11278 Cursor
11279 cursor;
11280
11281 Image
11282 *roi_image;
11283
11284 int
11285 entry,
11286 id,
11287 x,
11288 y;
11289
11290 MagickRealType
11291 scale_factor;
11292
11293 MagickProgressMonitor
11294 progress_monitor;
11295
11296 RectangleInfo
11297 crop_info,
11298 highlight_info,
11299 roi_info;
11300
11301 unsigned int
11302 height,
11303 width;
11304
cristybb503372010-05-27 20:51:26 +000011305 size_t
cristy3ed852e2009-09-05 21:47:34 +000011306 state;
11307
11308 XEvent
11309 event;
11310
11311 /*
11312 Map Command widget.
11313 */
11314 (void) CloneString(&windows->command.name,"ROI");
11315 windows->command.data=0;
11316 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11317 (void) XMapRaised(display,windows->command.id);
11318 XClientMessage(display,windows->image.id,windows->im_protocols,
11319 windows->im_update_widget,CurrentTime);
11320 /*
11321 Track pointer until button 1 is pressed.
11322 */
11323 XQueryPosition(display,windows->image.id,&x,&y);
11324 (void) XSelectInput(display,windows->image.id,
11325 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000011326 roi_info.x=(ssize_t) windows->image.x+x;
11327 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011328 roi_info.width=0;
11329 roi_info.height=0;
11330 cursor=XCreateFontCursor(display,XC_fleur);
11331 state=DefaultState;
11332 do
11333 {
11334 if (windows->info.mapped != MagickFalse)
11335 {
11336 /*
11337 Display pointer position.
11338 */
cristyb51dff52011-05-19 16:55:47 +000011339 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000011340 (long) roi_info.x,(long) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011341 XInfoWidget(display,windows,text);
11342 }
11343 /*
11344 Wait for next event.
11345 */
11346 XScreenEvent(display,windows,&event);
11347 if (event.xany.window == windows->command.id)
11348 {
11349 /*
11350 Select a command from the Command widget.
11351 */
11352 id=XCommandWidget(display,windows,ROIMenu,&event);
11353 if (id < 0)
11354 continue;
11355 switch (ROICommands[id])
11356 {
11357 case ROIHelpCommand:
11358 {
11359 XTextViewWidget(display,resource_info,windows,MagickFalse,
11360 "Help Viewer - Region of Interest",ImageROIHelp);
11361 break;
11362 }
11363 case ROIDismissCommand:
11364 {
11365 /*
11366 Prematurely exit.
11367 */
11368 state|=EscapeState;
11369 state|=ExitState;
11370 break;
11371 }
11372 default:
11373 break;
11374 }
11375 continue;
11376 }
11377 switch (event.type)
11378 {
11379 case ButtonPress:
11380 {
11381 if (event.xbutton.button != Button1)
11382 break;
11383 if (event.xbutton.window != windows->image.id)
11384 break;
11385 /*
11386 Note first corner of region of interest rectangle-- exit loop.
11387 */
11388 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000011389 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11390 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011391 state|=ExitState;
11392 break;
11393 }
11394 case ButtonRelease:
11395 break;
11396 case Expose:
11397 break;
11398 case KeyPress:
11399 {
11400 KeySym
11401 key_symbol;
11402
11403 if (event.xkey.window != windows->image.id)
11404 break;
11405 /*
11406 Respond to a user key press.
11407 */
11408 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11409 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11410 switch ((int) key_symbol)
11411 {
11412 case XK_Escape:
11413 case XK_F20:
11414 {
11415 /*
11416 Prematurely exit.
11417 */
11418 state|=EscapeState;
11419 state|=ExitState;
11420 break;
11421 }
11422 case XK_F1:
11423 case XK_Help:
11424 {
11425 XTextViewWidget(display,resource_info,windows,MagickFalse,
11426 "Help Viewer - Region of Interest",ImageROIHelp);
11427 break;
11428 }
11429 default:
11430 {
11431 (void) XBell(display,0);
11432 break;
11433 }
11434 }
11435 break;
11436 }
11437 case MotionNotify:
11438 {
11439 /*
11440 Map and unmap Info widget as text cursor crosses its boundaries.
11441 */
11442 x=event.xmotion.x;
11443 y=event.xmotion.y;
11444 if (windows->info.mapped != MagickFalse)
11445 {
11446 if ((x < (int) (windows->info.x+windows->info.width)) &&
11447 (y < (int) (windows->info.y+windows->info.height)))
11448 (void) XWithdrawWindow(display,windows->info.id,
11449 windows->info.screen);
11450 }
11451 else
11452 if ((x > (int) (windows->info.x+windows->info.width)) ||
11453 (y > (int) (windows->info.y+windows->info.height)))
11454 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011455 roi_info.x=(ssize_t) windows->image.x+x;
11456 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011457 break;
11458 }
11459 default:
11460 break;
11461 }
11462 } while ((state & ExitState) == 0);
11463 (void) XSelectInput(display,windows->image.id,
11464 windows->image.attributes.event_mask);
11465 if ((state & EscapeState) != 0)
11466 {
11467 /*
11468 User want to exit without region of interest.
11469 */
11470 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11471 (void) XFreeCursor(display,cursor);
11472 return(MagickTrue);
11473 }
11474 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11475 do
11476 {
11477 /*
11478 Size rectangle as pointer moves until the mouse button is released.
11479 */
11480 x=(int) roi_info.x;
11481 y=(int) roi_info.y;
11482 roi_info.width=0;
11483 roi_info.height=0;
11484 state=DefaultState;
11485 do
11486 {
11487 highlight_info=roi_info;
11488 highlight_info.x=roi_info.x-windows->image.x;
11489 highlight_info.y=roi_info.y-windows->image.y;
11490 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11491 {
11492 /*
11493 Display info and draw region of interest rectangle.
11494 */
11495 if (windows->info.mapped == MagickFalse)
11496 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000011497 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011498 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011499 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011500 XInfoWidget(display,windows,text);
11501 XHighlightRectangle(display,windows->image.id,
11502 windows->image.highlight_context,&highlight_info);
11503 }
11504 else
11505 if (windows->info.mapped != MagickFalse)
11506 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11507 /*
11508 Wait for next event.
11509 */
11510 XScreenEvent(display,windows,&event);
11511 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11512 XHighlightRectangle(display,windows->image.id,
11513 windows->image.highlight_context,&highlight_info);
11514 switch (event.type)
11515 {
11516 case ButtonPress:
11517 {
cristy49e2d862010-11-12 02:50:30 +000011518 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11519 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011520 break;
11521 }
11522 case ButtonRelease:
11523 {
11524 /*
11525 User has committed to region of interest rectangle.
11526 */
cristy49e2d862010-11-12 02:50:30 +000011527 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11528 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011529 XSetCursorState(display,windows,MagickFalse);
11530 state|=ExitState;
11531 if (LocaleCompare(windows->command.name,"Apply") == 0)
11532 break;
11533 (void) CloneString(&windows->command.name,"Apply");
11534 windows->command.data=ApplyMenus;
11535 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11536 break;
11537 }
11538 case Expose:
11539 break;
11540 case MotionNotify:
11541 {
cristy49e2d862010-11-12 02:50:30 +000011542 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11543 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011544 }
11545 default:
11546 break;
11547 }
11548 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11549 ((state & ExitState) != 0))
11550 {
11551 /*
11552 Check boundary conditions.
11553 */
11554 if (roi_info.x < 0)
11555 roi_info.x=0;
11556 else
cristy49e2d862010-11-12 02:50:30 +000011557 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11558 roi_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011559 if ((int) roi_info.x < x)
11560 roi_info.width=(unsigned int) (x-roi_info.x);
11561 else
11562 {
11563 roi_info.width=(unsigned int) (roi_info.x-x);
cristy49e2d862010-11-12 02:50:30 +000011564 roi_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +000011565 }
11566 if (roi_info.y < 0)
11567 roi_info.y=0;
11568 else
cristy49e2d862010-11-12 02:50:30 +000011569 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11570 roi_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000011571 if ((int) roi_info.y < y)
11572 roi_info.height=(unsigned int) (y-roi_info.y);
11573 else
11574 {
11575 roi_info.height=(unsigned int) (roi_info.y-y);
cristy49e2d862010-11-12 02:50:30 +000011576 roi_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000011577 }
11578 }
11579 } while ((state & ExitState) == 0);
11580 /*
11581 Wait for user to grab a corner of the rectangle or press return.
11582 */
11583 state=DefaultState;
11584 command_type=NullCommand;
11585 (void) XMapWindow(display,windows->info.id);
11586 do
11587 {
11588 if (windows->info.mapped != MagickFalse)
11589 {
11590 /*
11591 Display pointer position.
11592 */
cristyb51dff52011-05-19 16:55:47 +000011593 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011594 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011595 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011596 XInfoWidget(display,windows,text);
11597 }
11598 highlight_info=roi_info;
11599 highlight_info.x=roi_info.x-windows->image.x;
11600 highlight_info.y=roi_info.y-windows->image.y;
11601 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11602 {
11603 state|=EscapeState;
11604 state|=ExitState;
11605 break;
11606 }
11607 if ((state & UpdateRegionState) != 0)
11608 {
11609 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11610 switch (command_type)
11611 {
11612 case UndoCommand:
11613 case RedoCommand:
11614 {
11615 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011616 image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011617 break;
11618 }
11619 default:
11620 {
11621 /*
11622 Region of interest is relative to image configuration.
11623 */
11624 progress_monitor=SetImageProgressMonitor(*image,
11625 (MagickProgressMonitor) NULL,(*image)->client_data);
11626 crop_info=roi_info;
11627 width=(unsigned int) (*image)->columns;
11628 height=(unsigned int) (*image)->rows;
11629 x=0;
11630 y=0;
11631 if (windows->image.crop_geometry != (char *) NULL)
11632 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11633 &width,&height);
11634 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11635 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000011636 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011637 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11638 scale_factor=(MagickRealType)
11639 height/windows->image.ximage->height;
11640 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000011641 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011642 crop_info.height=(unsigned int)
11643 (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +000011644 roi_image=CropImage(*image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000011645 (void) SetImageProgressMonitor(*image,progress_monitor,
11646 (*image)->client_data);
11647 if (roi_image == (Image *) NULL)
11648 continue;
11649 /*
11650 Apply image processing technique to the region of interest.
11651 */
11652 windows->image.orphan=MagickTrue;
11653 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011654 &roi_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011655 progress_monitor=SetImageProgressMonitor(*image,
11656 (MagickProgressMonitor) NULL,(*image)->client_data);
11657 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011658 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011659 windows->image.orphan=MagickFalse;
11660 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
cristye941a752011-10-15 01:52:48 +000011661 crop_info.x,crop_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000011662 roi_image=DestroyImage(roi_image);
11663 (void) SetImageProgressMonitor(*image,progress_monitor,
11664 (*image)->client_data);
11665 break;
11666 }
11667 }
11668 if (command_type != InfoCommand)
11669 {
11670 XConfigureImageColormap(display,resource_info,windows,*image);
cristy051718b2011-08-28 22:49:25 +000011671 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011672 }
11673 XCheckRefreshWindows(display,windows);
11674 XInfoWidget(display,windows,text);
11675 (void) XSetFunction(display,windows->image.highlight_context,
11676 GXinvert);
11677 state&=(~UpdateRegionState);
11678 }
11679 XHighlightRectangle(display,windows->image.id,
11680 windows->image.highlight_context,&highlight_info);
11681 XScreenEvent(display,windows,&event);
11682 if (event.xany.window == windows->command.id)
11683 {
11684 /*
11685 Select a command from the Command widget.
11686 */
11687 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11688 command_type=NullCommand;
11689 id=XCommandWidget(display,windows,ApplyMenu,&event);
11690 if (id >= 0)
11691 {
11692 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11693 command_type=ApplyCommands[id];
11694 if (id < ApplyMenus)
11695 {
11696 /*
11697 Select a command from a pop-up menu.
11698 */
11699 entry=XMenuWidget(display,windows,ApplyMenu[id],
11700 (const char **) Menus[id],command);
11701 if (entry >= 0)
11702 {
11703 (void) CopyMagickString(command,Menus[id][entry],
11704 MaxTextExtent);
11705 command_type=Commands[id][entry];
11706 }
11707 }
11708 }
11709 (void) XSetFunction(display,windows->image.highlight_context,
11710 GXinvert);
11711 XHighlightRectangle(display,windows->image.id,
11712 windows->image.highlight_context,&highlight_info);
11713 if (command_type == HelpCommand)
11714 {
11715 (void) XSetFunction(display,windows->image.highlight_context,
11716 GXcopy);
11717 XTextViewWidget(display,resource_info,windows,MagickFalse,
11718 "Help Viewer - Region of Interest",ImageROIHelp);
11719 (void) XSetFunction(display,windows->image.highlight_context,
11720 GXinvert);
11721 continue;
11722 }
11723 if (command_type == QuitCommand)
11724 {
11725 /*
11726 exit.
11727 */
11728 state|=EscapeState;
11729 state|=ExitState;
11730 continue;
11731 }
11732 if (command_type != NullCommand)
11733 state|=UpdateRegionState;
11734 continue;
11735 }
11736 XHighlightRectangle(display,windows->image.id,
11737 windows->image.highlight_context,&highlight_info);
11738 switch (event.type)
11739 {
11740 case ButtonPress:
11741 {
11742 x=windows->image.x;
11743 y=windows->image.y;
11744 if (event.xbutton.button != Button1)
11745 break;
11746 if (event.xbutton.window != windows->image.id)
11747 break;
11748 x=windows->image.x+event.xbutton.x;
11749 y=windows->image.y+event.xbutton.y;
11750 if ((x < (int) (roi_info.x+RoiDelta)) &&
11751 (x > (int) (roi_info.x-RoiDelta)) &&
11752 (y < (int) (roi_info.y+RoiDelta)) &&
11753 (y > (int) (roi_info.y-RoiDelta)))
11754 {
cristybb503372010-05-27 20:51:26 +000011755 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11756 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011757 state|=UpdateConfigurationState;
11758 break;
11759 }
11760 if ((x < (int) (roi_info.x+RoiDelta)) &&
11761 (x > (int) (roi_info.x-RoiDelta)) &&
11762 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11763 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11764 {
cristybb503372010-05-27 20:51:26 +000011765 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
cristy3ed852e2009-09-05 21:47:34 +000011766 state|=UpdateConfigurationState;
11767 break;
11768 }
11769 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11770 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11771 (y < (int) (roi_info.y+RoiDelta)) &&
11772 (y > (int) (roi_info.y-RoiDelta)))
11773 {
cristybb503372010-05-27 20:51:26 +000011774 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011775 state|=UpdateConfigurationState;
11776 break;
11777 }
11778 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11779 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11780 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11781 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11782 {
11783 state|=UpdateConfigurationState;
11784 break;
11785 }
11786 }
11787 case ButtonRelease:
11788 {
11789 if (event.xbutton.window == windows->pan.id)
11790 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11791 (highlight_info.y != crop_info.y-windows->image.y))
11792 XHighlightRectangle(display,windows->image.id,
11793 windows->image.highlight_context,&highlight_info);
11794 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11795 event.xbutton.time);
11796 break;
11797 }
11798 case Expose:
11799 {
11800 if (event.xexpose.window == windows->image.id)
11801 if (event.xexpose.count == 0)
11802 {
11803 event.xexpose.x=(int) highlight_info.x;
11804 event.xexpose.y=(int) highlight_info.y;
11805 event.xexpose.width=(int) highlight_info.width;
11806 event.xexpose.height=(int) highlight_info.height;
11807 XRefreshWindow(display,&windows->image,&event);
11808 }
11809 if (event.xexpose.window == windows->info.id)
11810 if (event.xexpose.count == 0)
11811 XInfoWidget(display,windows,text);
11812 break;
11813 }
11814 case KeyPress:
11815 {
11816 KeySym
11817 key_symbol;
11818
11819 if (event.xkey.window != windows->image.id)
11820 break;
11821 /*
11822 Respond to a user key press.
11823 */
11824 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11825 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11826 switch ((int) key_symbol)
11827 {
11828 case XK_Shift_L:
11829 case XK_Shift_R:
11830 break;
11831 case XK_Escape:
11832 case XK_F20:
11833 state|=EscapeState;
11834 case XK_Return:
11835 {
11836 state|=ExitState;
11837 break;
11838 }
11839 case XK_Home:
11840 case XK_KP_Home:
11841 {
cristybb503372010-05-27 20:51:26 +000011842 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
cristy49e2d862010-11-12 02:50:30 +000011843 roi_info.y=(ssize_t) (windows->image.height/2L-
11844 roi_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +000011845 break;
11846 }
11847 case XK_Left:
11848 case XK_KP_Left:
11849 {
11850 roi_info.x--;
11851 break;
11852 }
11853 case XK_Up:
11854 case XK_KP_Up:
11855 case XK_Next:
11856 {
11857 roi_info.y--;
11858 break;
11859 }
11860 case XK_Right:
11861 case XK_KP_Right:
11862 {
11863 roi_info.x++;
11864 break;
11865 }
11866 case XK_Prior:
11867 case XK_Down:
11868 case XK_KP_Down:
11869 {
11870 roi_info.y++;
11871 break;
11872 }
11873 case XK_F1:
11874 case XK_Help:
11875 {
11876 (void) XSetFunction(display,windows->image.highlight_context,
11877 GXcopy);
11878 XTextViewWidget(display,resource_info,windows,MagickFalse,
11879 "Help Viewer - Region of Interest",ImageROIHelp);
11880 (void) XSetFunction(display,windows->image.highlight_context,
11881 GXinvert);
11882 break;
11883 }
11884 default:
11885 {
11886 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011887 event.xkey.state,key_symbol,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011888 if (command_type != NullCommand)
11889 state|=UpdateRegionState;
11890 break;
11891 }
11892 }
11893 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11894 event.xkey.time);
11895 break;
11896 }
11897 case KeyRelease:
11898 break;
11899 case MotionNotify:
11900 {
11901 if (event.xbutton.window != windows->image.id)
11902 break;
11903 /*
11904 Map and unmap Info widget as text cursor crosses its boundaries.
11905 */
11906 x=event.xmotion.x;
11907 y=event.xmotion.y;
11908 if (windows->info.mapped != MagickFalse)
11909 {
11910 if ((x < (int) (windows->info.x+windows->info.width)) &&
11911 (y < (int) (windows->info.y+windows->info.height)))
11912 (void) XWithdrawWindow(display,windows->info.id,
11913 windows->info.screen);
11914 }
11915 else
11916 if ((x > (int) (windows->info.x+windows->info.width)) ||
11917 (y > (int) (windows->info.y+windows->info.height)))
11918 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011919 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11920 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011921 break;
11922 }
11923 case SelectionRequest:
11924 {
11925 XSelectionEvent
11926 notify;
11927
11928 XSelectionRequestEvent
11929 *request;
11930
11931 /*
11932 Set primary selection.
11933 */
cristyb51dff52011-05-19 16:55:47 +000011934 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011935 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011936 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011937 request=(&(event.xselectionrequest));
11938 (void) XChangeProperty(request->display,request->requestor,
11939 request->property,request->target,8,PropModeReplace,
11940 (unsigned char *) text,(int) strlen(text));
11941 notify.type=SelectionNotify;
11942 notify.display=request->display;
11943 notify.requestor=request->requestor;
11944 notify.selection=request->selection;
11945 notify.target=request->target;
11946 notify.time=request->time;
11947 if (request->property == None)
11948 notify.property=request->target;
11949 else
11950 notify.property=request->property;
11951 (void) XSendEvent(request->display,request->requestor,False,0,
11952 (XEvent *) &notify);
11953 }
11954 default:
11955 break;
11956 }
11957 if ((state & UpdateConfigurationState) != 0)
11958 {
11959 (void) XPutBackEvent(display,&event);
11960 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11961 break;
11962 }
11963 } while ((state & ExitState) == 0);
11964 } while ((state & ExitState) == 0);
11965 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11966 XSetCursorState(display,windows,MagickFalse);
11967 if ((state & EscapeState) != 0)
11968 return(MagickTrue);
11969 return(MagickTrue);
11970}
11971
11972/*
11973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11974% %
11975% %
11976% %
11977+ X R o t a t e I m a g e %
11978% %
11979% %
11980% %
11981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11982%
11983% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11984% rotation angle is computed from the slope of a line drawn by the user.
11985%
11986% The format of the XRotateImage method is:
11987%
11988% MagickBooleanType XRotateImage(Display *display,
11989% XResourceInfo *resource_info,XWindows *windows,double degrees,
cristy051718b2011-08-28 22:49:25 +000011990% Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011991%
11992% A description of each parameter follows:
11993%
11994% o display: Specifies a connection to an X server; returned from
11995% XOpenDisplay.
11996%
11997% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11998%
11999% o windows: Specifies a pointer to a XWindows structure.
12000%
12001% o degrees: Specifies the number of degrees to rotate the image.
12002%
12003% o image: the image.
12004%
cristy051718b2011-08-28 22:49:25 +000012005% o exception: return any errors or warnings in this structure.
12006%
cristy3ed852e2009-09-05 21:47:34 +000012007*/
12008static MagickBooleanType XRotateImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012009 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12010 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012011{
12012 static const char
12013 *RotateMenu[] =
12014 {
12015 "Pixel Color",
12016 "Direction",
12017 "Help",
12018 "Dismiss",
12019 (char *) NULL
12020 };
12021
12022 static ModeType
12023 direction = HorizontalRotateCommand;
12024
12025 static const ModeType
12026 DirectionCommands[] =
12027 {
12028 HorizontalRotateCommand,
12029 VerticalRotateCommand
12030 },
12031 RotateCommands[] =
12032 {
12033 RotateColorCommand,
12034 RotateDirectionCommand,
12035 RotateHelpCommand,
12036 RotateDismissCommand
12037 };
12038
12039 static unsigned int
12040 pen_id = 0;
12041
12042 char
12043 command[MaxTextExtent],
12044 text[MaxTextExtent];
12045
12046 Image
12047 *rotate_image;
12048
12049 int
12050 id,
12051 x,
12052 y;
12053
12054 MagickRealType
12055 normalized_degrees;
12056
12057 register int
12058 i;
12059
12060 unsigned int
12061 height,
12062 rotations,
12063 width;
12064
12065 if (degrees == 0.0)
12066 {
12067 unsigned int
12068 distance;
12069
cristybb503372010-05-27 20:51:26 +000012070 size_t
cristy3ed852e2009-09-05 21:47:34 +000012071 state;
12072
12073 XEvent
12074 event;
12075
12076 XSegment
12077 rotate_info;
12078
12079 /*
12080 Map Command widget.
12081 */
12082 (void) CloneString(&windows->command.name,"Rotate");
12083 windows->command.data=2;
12084 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12085 (void) XMapRaised(display,windows->command.id);
12086 XClientMessage(display,windows->image.id,windows->im_protocols,
12087 windows->im_update_widget,CurrentTime);
12088 /*
12089 Wait for first button press.
12090 */
12091 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12092 XQueryPosition(display,windows->image.id,&x,&y);
12093 rotate_info.x1=x;
12094 rotate_info.y1=y;
12095 rotate_info.x2=x;
12096 rotate_info.y2=y;
12097 state=DefaultState;
12098 do
12099 {
12100 XHighlightLine(display,windows->image.id,
12101 windows->image.highlight_context,&rotate_info);
12102 /*
12103 Wait for next event.
12104 */
12105 XScreenEvent(display,windows,&event);
12106 XHighlightLine(display,windows->image.id,
12107 windows->image.highlight_context,&rotate_info);
12108 if (event.xany.window == windows->command.id)
12109 {
12110 /*
12111 Select a command from the Command widget.
12112 */
12113 id=XCommandWidget(display,windows,RotateMenu,&event);
12114 if (id < 0)
12115 continue;
12116 (void) XSetFunction(display,windows->image.highlight_context,
12117 GXcopy);
12118 switch (RotateCommands[id])
12119 {
12120 case RotateColorCommand:
12121 {
12122 const char
12123 *ColorMenu[MaxNumberPens];
12124
12125 int
12126 pen_number;
12127
12128 XColor
12129 color;
12130
12131 /*
12132 Initialize menu selections.
12133 */
12134 for (i=0; i < (int) (MaxNumberPens-2); i++)
12135 ColorMenu[i]=resource_info->pen_colors[i];
12136 ColorMenu[MaxNumberPens-2]="Browser...";
12137 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12138 /*
12139 Select a pen color from the pop-up menu.
12140 */
12141 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12142 (const char **) ColorMenu,command);
12143 if (pen_number < 0)
12144 break;
12145 if (pen_number == (MaxNumberPens-2))
12146 {
12147 static char
12148 color_name[MaxTextExtent] = "gray";
12149
12150 /*
12151 Select a pen color from a dialog.
12152 */
12153 resource_info->pen_colors[pen_number]=color_name;
12154 XColorBrowserWidget(display,windows,"Select",color_name);
12155 if (*color_name == '\0')
12156 break;
12157 }
12158 /*
12159 Set pen color.
12160 */
12161 (void) XParseColor(display,windows->map_info->colormap,
12162 resource_info->pen_colors[pen_number],&color);
12163 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12164 (unsigned int) MaxColors,&color);
12165 windows->pixel_info->pen_colors[pen_number]=color;
12166 pen_id=(unsigned int) pen_number;
12167 break;
12168 }
12169 case RotateDirectionCommand:
12170 {
12171 static const char
12172 *Directions[] =
12173 {
12174 "horizontal",
12175 "vertical",
12176 (char *) NULL,
12177 };
12178
12179 /*
12180 Select a command from the pop-up menu.
12181 */
12182 id=XMenuWidget(display,windows,RotateMenu[id],
12183 Directions,command);
12184 if (id >= 0)
12185 direction=DirectionCommands[id];
12186 break;
12187 }
12188 case RotateHelpCommand:
12189 {
12190 XTextViewWidget(display,resource_info,windows,MagickFalse,
12191 "Help Viewer - Image Rotation",ImageRotateHelp);
12192 break;
12193 }
12194 case RotateDismissCommand:
12195 {
12196 /*
12197 Prematurely exit.
12198 */
12199 state|=EscapeState;
12200 state|=ExitState;
12201 break;
12202 }
12203 default:
12204 break;
12205 }
12206 (void) XSetFunction(display,windows->image.highlight_context,
12207 GXinvert);
12208 continue;
12209 }
12210 switch (event.type)
12211 {
12212 case ButtonPress:
12213 {
12214 if (event.xbutton.button != Button1)
12215 break;
12216 if (event.xbutton.window != windows->image.id)
12217 break;
12218 /*
12219 exit loop.
12220 */
12221 (void) XSetFunction(display,windows->image.highlight_context,
12222 GXcopy);
12223 rotate_info.x1=event.xbutton.x;
12224 rotate_info.y1=event.xbutton.y;
12225 state|=ExitState;
12226 break;
12227 }
12228 case ButtonRelease:
12229 break;
12230 case Expose:
12231 break;
12232 case KeyPress:
12233 {
12234 char
12235 command[MaxTextExtent];
12236
12237 KeySym
12238 key_symbol;
12239
12240 if (event.xkey.window != windows->image.id)
12241 break;
12242 /*
12243 Respond to a user key press.
12244 */
12245 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12246 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12247 switch ((int) key_symbol)
12248 {
12249 case XK_Escape:
12250 case XK_F20:
12251 {
12252 /*
12253 Prematurely exit.
12254 */
12255 state|=EscapeState;
12256 state|=ExitState;
12257 break;
12258 }
12259 case XK_F1:
12260 case XK_Help:
12261 {
12262 (void) XSetFunction(display,windows->image.highlight_context,
12263 GXcopy);
12264 XTextViewWidget(display,resource_info,windows,MagickFalse,
12265 "Help Viewer - Image Rotation",ImageRotateHelp);
12266 (void) XSetFunction(display,windows->image.highlight_context,
12267 GXinvert);
12268 break;
12269 }
12270 default:
12271 {
12272 (void) XBell(display,0);
12273 break;
12274 }
12275 }
12276 break;
12277 }
12278 case MotionNotify:
12279 {
12280 rotate_info.x1=event.xmotion.x;
12281 rotate_info.y1=event.xmotion.y;
12282 }
12283 }
12284 rotate_info.x2=rotate_info.x1;
12285 rotate_info.y2=rotate_info.y1;
12286 if (direction == HorizontalRotateCommand)
12287 rotate_info.x2+=32;
12288 else
12289 rotate_info.y2-=32;
12290 } while ((state & ExitState) == 0);
12291 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12292 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12293 if ((state & EscapeState) != 0)
12294 return(MagickTrue);
12295 /*
12296 Draw line as pointer moves until the mouse button is released.
12297 */
12298 distance=0;
12299 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12300 state=DefaultState;
12301 do
12302 {
12303 if (distance > 9)
12304 {
12305 /*
12306 Display info and draw rotation line.
12307 */
12308 if (windows->info.mapped == MagickFalse)
12309 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000012310 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012311 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12312 XInfoWidget(display,windows,text);
12313 XHighlightLine(display,windows->image.id,
12314 windows->image.highlight_context,&rotate_info);
12315 }
12316 else
12317 if (windows->info.mapped != MagickFalse)
12318 (void) XWithdrawWindow(display,windows->info.id,
12319 windows->info.screen);
12320 /*
12321 Wait for next event.
12322 */
12323 XScreenEvent(display,windows,&event);
12324 if (distance > 9)
12325 XHighlightLine(display,windows->image.id,
12326 windows->image.highlight_context,&rotate_info);
12327 switch (event.type)
12328 {
12329 case ButtonPress:
12330 break;
12331 case ButtonRelease:
12332 {
12333 /*
12334 User has committed to rotation line.
12335 */
12336 rotate_info.x2=event.xbutton.x;
12337 rotate_info.y2=event.xbutton.y;
12338 state|=ExitState;
12339 break;
12340 }
12341 case Expose:
12342 break;
12343 case MotionNotify:
12344 {
12345 rotate_info.x2=event.xmotion.x;
12346 rotate_info.y2=event.xmotion.y;
12347 }
12348 default:
12349 break;
12350 }
12351 /*
12352 Check boundary conditions.
12353 */
12354 if (rotate_info.x2 < 0)
12355 rotate_info.x2=0;
12356 else
12357 if (rotate_info.x2 > (int) windows->image.width)
12358 rotate_info.x2=(short) windows->image.width;
12359 if (rotate_info.y2 < 0)
12360 rotate_info.y2=0;
12361 else
12362 if (rotate_info.y2 > (int) windows->image.height)
12363 rotate_info.y2=(short) windows->image.height;
12364 /*
12365 Compute rotation angle from the slope of the line.
12366 */
12367 degrees=0.0;
12368 distance=(unsigned int)
12369 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12370 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12371 if (distance > 9)
12372 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12373 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12374 } while ((state & ExitState) == 0);
12375 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12376 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12377 if (distance <= 9)
12378 return(MagickTrue);
12379 }
12380 if (direction == VerticalRotateCommand)
12381 degrees-=90.0;
12382 if (degrees == 0.0)
12383 return(MagickTrue);
12384 /*
12385 Rotate image.
12386 */
12387 normalized_degrees=degrees;
12388 while (normalized_degrees < -45.0)
12389 normalized_degrees+=360.0;
12390 for (rotations=0; normalized_degrees > 45.0; rotations++)
12391 normalized_degrees-=90.0;
12392 if (normalized_degrees != 0.0)
cristy051718b2011-08-28 22:49:25 +000012393 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12394 exception);
cristy3ed852e2009-09-05 21:47:34 +000012395 XSetCursorState(display,windows,MagickTrue);
12396 XCheckRefreshWindows(display,windows);
12397 (*image)->background_color.red=ScaleShortToQuantum(
12398 windows->pixel_info->pen_colors[pen_id].red);
12399 (*image)->background_color.green=ScaleShortToQuantum(
12400 windows->pixel_info->pen_colors[pen_id].green);
12401 (*image)->background_color.blue=ScaleShortToQuantum(
12402 windows->pixel_info->pen_colors[pen_id].blue);
cristy051718b2011-08-28 22:49:25 +000012403 rotate_image=RotateImage(*image,degrees,exception);
cristy3ed852e2009-09-05 21:47:34 +000012404 XSetCursorState(display,windows,MagickFalse);
12405 if (rotate_image == (Image *) NULL)
12406 return(MagickFalse);
12407 *image=DestroyImage(*image);
12408 *image=rotate_image;
12409 if (windows->image.crop_geometry != (char *) NULL)
12410 {
12411 /*
12412 Rotate crop geometry.
12413 */
12414 width=(unsigned int) (*image)->columns;
12415 height=(unsigned int) (*image)->rows;
12416 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12417 switch (rotations % 4)
12418 {
12419 default:
12420 case 0:
12421 break;
12422 case 1:
12423 {
12424 /*
12425 Rotate 90 degrees.
12426 */
cristyb51dff52011-05-19 16:55:47 +000012427 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012428 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12429 (int) height-y,x);
12430 break;
12431 }
12432 case 2:
12433 {
12434 /*
12435 Rotate 180 degrees.
12436 */
cristyb51dff52011-05-19 16:55:47 +000012437 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012438 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12439 break;
12440 }
12441 case 3:
12442 {
12443 /*
12444 Rotate 270 degrees.
12445 */
cristyb51dff52011-05-19 16:55:47 +000012446 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012447 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12448 break;
12449 }
12450 }
12451 }
12452 if (windows->image.orphan != MagickFalse)
12453 return(MagickTrue);
12454 if (normalized_degrees != 0.0)
12455 {
12456 /*
12457 Update image colormap.
12458 */
12459 windows->image.window_changes.width=(int) (*image)->columns;
12460 windows->image.window_changes.height=(int) (*image)->rows;
12461 if (windows->image.crop_geometry != (char *) NULL)
12462 {
12463 /*
12464 Obtain dimensions of image from crop geometry.
12465 */
12466 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12467 &width,&height);
12468 windows->image.window_changes.width=(int) width;
12469 windows->image.window_changes.height=(int) height;
12470 }
12471 XConfigureImageColormap(display,resource_info,windows,*image);
12472 }
12473 else
12474 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12475 {
12476 windows->image.window_changes.width=windows->image.ximage->height;
12477 windows->image.window_changes.height=windows->image.ximage->width;
12478 }
12479 /*
12480 Update image configuration.
12481 */
cristy051718b2011-08-28 22:49:25 +000012482 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012483 return(MagickTrue);
12484}
12485
12486/*
12487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12488% %
12489% %
12490% %
12491+ X S a v e I m a g e %
12492% %
12493% %
12494% %
12495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12496%
12497% XSaveImage() saves an image to a file.
12498%
12499% The format of the XSaveImage method is:
12500%
12501% MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012502% XResourceInfo *resource_info,XWindows *windows,Image *image,
12503% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012504%
12505% A description of each parameter follows:
12506%
12507% o display: Specifies a connection to an X server; returned from
12508% XOpenDisplay.
12509%
12510% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12511%
12512% o windows: Specifies a pointer to a XWindows structure.
12513%
12514% o image: the image.
12515%
cristy051718b2011-08-28 22:49:25 +000012516% o exception: return any errors or warnings in this structure.
12517%
cristy3ed852e2009-09-05 21:47:34 +000012518*/
12519static MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012520 XResourceInfo *resource_info,XWindows *windows,Image *image,
12521 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012522{
12523 char
12524 filename[MaxTextExtent],
12525 geometry[MaxTextExtent];
12526
12527 Image
12528 *save_image;
12529
12530 ImageInfo
12531 *image_info;
12532
12533 MagickStatusType
12534 status;
12535
12536 /*
12537 Request file name from user.
12538 */
12539 if (resource_info->write_filename != (char *) NULL)
12540 (void) CopyMagickString(filename,resource_info->write_filename,
12541 MaxTextExtent);
12542 else
12543 {
12544 char
12545 path[MaxTextExtent];
12546
12547 int
12548 status;
12549
12550 GetPathComponent(image->filename,HeadPath,path);
12551 GetPathComponent(image->filename,TailPath,filename);
cristy0da1d642011-08-29 16:53:16 +000012552 if (*path != '\0')
12553 {
12554 status=chdir(path);
12555 if (status == -1)
12556 (void) ThrowMagickException(exception,GetMagickModule(),
12557 FileOpenError,"UnableToOpenFile","%s",path);
12558 }
cristy3ed852e2009-09-05 21:47:34 +000012559 }
12560 XFileBrowserWidget(display,windows,"Save",filename);
12561 if (*filename == '\0')
12562 return(MagickTrue);
12563 if (IsPathAccessible(filename) != MagickFalse)
12564 {
12565 int
12566 status;
12567
12568 /*
12569 File exists-- seek user's permission before overwriting.
12570 */
12571 status=XConfirmWidget(display,windows,"Overwrite",filename);
12572 if (status <= 0)
12573 return(MagickTrue);
12574 }
12575 image_info=CloneImageInfo(resource_info->image_info);
12576 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012577 (void) SetImageInfo(image_info,1,exception);
cristy3ed852e2009-09-05 21:47:34 +000012578 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12579 (LocaleCompare(image_info->magick,"JPG") == 0))
12580 {
12581 char
12582 quality[MaxTextExtent];
12583
12584 int
12585 status;
12586
12587 /*
12588 Request JPEG quality from user.
12589 */
cristyb51dff52011-05-19 16:55:47 +000012590 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
cristyf2faecf2010-05-28 19:19:36 +000012591 image->quality);
cristy3ed852e2009-09-05 21:47:34 +000012592 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12593 quality);
12594 if (*quality == '\0')
12595 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012596 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012597 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12598 }
12599 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12600 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12601 (LocaleCompare(image_info->magick,"PS") == 0) ||
12602 (LocaleCompare(image_info->magick,"PS2") == 0))
12603 {
12604 char
12605 geometry[MaxTextExtent];
12606
12607 /*
12608 Request page geometry from user.
12609 */
cristyb93d9e72009-09-12 20:02:21 +000012610 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012611 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristyb93d9e72009-09-12 20:02:21 +000012612 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012613 if (image_info->page != (char *) NULL)
12614 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12615 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12616 "Select page geometry:",geometry);
12617 if (*geometry != '\0')
12618 image_info->page=GetPageGeometry(geometry);
12619 }
12620 /*
12621 Apply image transforms.
12622 */
12623 XSetCursorState(display,windows,MagickTrue);
12624 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000012625 save_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000012626 if (save_image == (Image *) NULL)
12627 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000012628 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000012629 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000012630 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12631 exception);
cristy3ed852e2009-09-05 21:47:34 +000012632 /*
12633 Write image.
12634 */
12635 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012636 status=WriteImage(image_info,save_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012637 if (status != MagickFalse)
12638 image->taint=MagickFalse;
12639 save_image=DestroyImage(save_image);
12640 image_info=DestroyImageInfo(image_info);
12641 XSetCursorState(display,windows,MagickFalse);
12642 return(status != 0 ? MagickTrue : MagickFalse);
12643}
12644
12645/*
12646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12647% %
12648% %
12649% %
12650+ X S c r e e n E v e n t %
12651% %
12652% %
12653% %
12654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12655%
12656% XScreenEvent() handles global events associated with the Pan and Magnify
12657% windows.
12658%
12659% The format of the XScreenEvent function is:
12660%
12661% void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12662%
12663% A description of each parameter follows:
12664%
12665% o display: Specifies a pointer to the Display structure; returned from
12666% XOpenDisplay.
12667%
12668% o windows: Specifies a pointer to a XWindows structure.
12669%
12670% o event: Specifies a pointer to a X11 XEvent structure.
12671%
12672%
12673*/
12674
12675#if defined(__cplusplus) || defined(c_plusplus)
12676extern "C" {
12677#endif
12678
12679static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12680{
12681 register XWindows
12682 *windows;
12683
12684 windows=(XWindows *) data;
12685 if ((event->type == ClientMessage) &&
12686 (event->xclient.window == windows->image.id))
12687 return(MagickFalse);
12688 return(MagickTrue);
12689}
12690
12691#if defined(__cplusplus) || defined(c_plusplus)
12692}
12693#endif
12694
12695static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12696{
12697 register int
12698 x,
12699 y;
12700
12701 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12702 if (event->xany.window == windows->command.id)
12703 return;
12704 switch (event->type)
12705 {
12706 case ButtonPress:
12707 case ButtonRelease:
12708 {
12709 if ((event->xbutton.button == Button3) &&
12710 (event->xbutton.state & Mod1Mask))
12711 {
12712 /*
12713 Convert Alt-Button3 to Button2.
12714 */
12715 event->xbutton.button=Button2;
12716 event->xbutton.state&=(~Mod1Mask);
12717 }
12718 if (event->xbutton.window == windows->backdrop.id)
12719 {
12720 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12721 event->xbutton.time);
12722 break;
12723 }
12724 if (event->xbutton.window == windows->pan.id)
12725 {
12726 XPanImage(display,windows,event);
12727 break;
12728 }
12729 if (event->xbutton.window == windows->image.id)
12730 if (event->xbutton.button == Button2)
12731 {
12732 /*
12733 Update magnified image.
12734 */
12735 x=event->xbutton.x;
12736 y=event->xbutton.y;
12737 if (x < 0)
12738 x=0;
12739 else
12740 if (x >= (int) windows->image.width)
12741 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012742 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012743 if (y < 0)
12744 y=0;
12745 else
12746 if (y >= (int) windows->image.height)
12747 y=(int) (windows->image.height-1);
12748 windows->magnify.y=windows->image.y+y;
12749 if (windows->magnify.mapped == MagickFalse)
12750 (void) XMapRaised(display,windows->magnify.id);
12751 XMakeMagnifyImage(display,windows);
12752 if (event->type == ButtonRelease)
12753 (void) XWithdrawWindow(display,windows->info.id,
12754 windows->info.screen);
12755 break;
12756 }
12757 break;
12758 }
12759 case ClientMessage:
12760 {
12761 /*
12762 If client window delete message, exit.
12763 */
12764 if (event->xclient.message_type != windows->wm_protocols)
12765 break;
cristyecd0ab52010-05-30 14:59:20 +000012766 if (*event->xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000012767 break;
12768 if (event->xclient.window == windows->magnify.id)
12769 {
12770 (void) XWithdrawWindow(display,windows->magnify.id,
12771 windows->magnify.screen);
12772 break;
12773 }
12774 break;
12775 }
12776 case ConfigureNotify:
12777 {
12778 if (event->xconfigure.window == windows->magnify.id)
12779 {
12780 unsigned int
12781 magnify;
12782
12783 /*
12784 Magnify window has a new configuration.
12785 */
12786 windows->magnify.width=(unsigned int) event->xconfigure.width;
12787 windows->magnify.height=(unsigned int) event->xconfigure.height;
12788 if (windows->magnify.mapped == MagickFalse)
12789 break;
12790 magnify=1;
12791 while ((int) magnify <= event->xconfigure.width)
12792 magnify<<=1;
12793 while ((int) magnify <= event->xconfigure.height)
12794 magnify<<=1;
12795 magnify>>=1;
12796 if (((int) magnify != event->xconfigure.width) ||
12797 ((int) magnify != event->xconfigure.height))
12798 {
12799 XWindowChanges
12800 window_changes;
12801
12802 window_changes.width=(int) magnify;
12803 window_changes.height=(int) magnify;
12804 (void) XReconfigureWMWindow(display,windows->magnify.id,
12805 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12806 &window_changes);
12807 break;
12808 }
12809 XMakeMagnifyImage(display,windows);
12810 break;
12811 }
12812 break;
12813 }
12814 case Expose:
12815 {
12816 if (event->xexpose.window == windows->image.id)
12817 {
12818 XRefreshWindow(display,&windows->image,event);
12819 break;
12820 }
12821 if (event->xexpose.window == windows->pan.id)
12822 if (event->xexpose.count == 0)
12823 {
12824 XDrawPanRectangle(display,windows);
12825 break;
12826 }
12827 if (event->xexpose.window == windows->magnify.id)
12828 if (event->xexpose.count == 0)
12829 {
12830 XMakeMagnifyImage(display,windows);
12831 break;
12832 }
12833 break;
12834 }
12835 case KeyPress:
12836 {
12837 char
12838 command[MaxTextExtent];
12839
12840 KeySym
12841 key_symbol;
12842
12843 if (event->xkey.window != windows->magnify.id)
12844 break;
12845 /*
12846 Respond to a user key press.
12847 */
12848 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12849 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12850 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12851 break;
12852 }
12853 case MapNotify:
12854 {
12855 if (event->xmap.window == windows->magnify.id)
12856 {
12857 windows->magnify.mapped=MagickTrue;
12858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12859 break;
12860 }
12861 if (event->xmap.window == windows->info.id)
12862 {
12863 windows->info.mapped=MagickTrue;
12864 break;
12865 }
12866 break;
12867 }
12868 case MotionNotify:
12869 {
12870 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12871 if (event->xmotion.window == windows->image.id)
12872 if (windows->magnify.mapped != MagickFalse)
12873 {
12874 /*
12875 Update magnified image.
12876 */
12877 x=event->xmotion.x;
12878 y=event->xmotion.y;
12879 if (x < 0)
12880 x=0;
12881 else
12882 if (x >= (int) windows->image.width)
12883 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012884 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012885 if (y < 0)
12886 y=0;
12887 else
12888 if (y >= (int) windows->image.height)
12889 y=(int) (windows->image.height-1);
12890 windows->magnify.y=windows->image.y+y;
12891 XMakeMagnifyImage(display,windows);
12892 }
12893 break;
12894 }
12895 case UnmapNotify:
12896 {
12897 if (event->xunmap.window == windows->magnify.id)
12898 {
12899 windows->magnify.mapped=MagickFalse;
12900 break;
12901 }
12902 if (event->xunmap.window == windows->info.id)
12903 {
12904 windows->info.mapped=MagickFalse;
12905 break;
12906 }
12907 break;
12908 }
12909 default:
12910 break;
12911 }
12912}
12913
12914/*
12915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12916% %
12917% %
12918% %
12919+ X S e t C r o p G e o m e t r y %
12920% %
12921% %
12922% %
12923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12924%
12925% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12926% and translates it to a cropping geometry relative to the image.
12927%
12928% The format of the XSetCropGeometry method is:
12929%
12930% void XSetCropGeometry(Display *display,XWindows *windows,
12931% RectangleInfo *crop_info,Image *image)
12932%
12933% A description of each parameter follows:
12934%
12935% o display: Specifies a connection to an X server; returned from
12936% XOpenDisplay.
12937%
12938% o windows: Specifies a pointer to a XWindows structure.
12939%
12940% o crop_info: A pointer to a RectangleInfo that defines a region of the
12941% Image window to crop.
12942%
12943% o image: the image.
12944%
12945*/
12946static void XSetCropGeometry(Display *display,XWindows *windows,
12947 RectangleInfo *crop_info,Image *image)
12948{
12949 char
12950 text[MaxTextExtent];
12951
12952 int
12953 x,
12954 y;
12955
12956 MagickRealType
12957 scale_factor;
12958
12959 unsigned int
12960 height,
12961 width;
12962
12963 if (windows->info.mapped != MagickFalse)
12964 {
12965 /*
12966 Display info on cropping rectangle.
12967 */
cristyb51dff52011-05-19 16:55:47 +000012968 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
cristye8c25f92010-06-03 00:53:06 +000012969 (double) crop_info->width,(double) crop_info->height,(double)
12970 crop_info->x,(double) crop_info->y);
cristy3ed852e2009-09-05 21:47:34 +000012971 XInfoWidget(display,windows,text);
12972 }
12973 /*
12974 Cropping geometry is relative to any previous crop geometry.
12975 */
12976 x=0;
12977 y=0;
12978 width=(unsigned int) image->columns;
12979 height=(unsigned int) image->rows;
12980 if (windows->image.crop_geometry != (char *) NULL)
12981 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12982 else
12983 windows->image.crop_geometry=AcquireString((char *) NULL);
12984 /*
12985 Define the crop geometry string from the cropping rectangle.
12986 */
12987 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12988 if (crop_info->x > 0)
12989 x+=(int) (scale_factor*crop_info->x+0.5);
12990 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12991 if (width == 0)
12992 width=1;
12993 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12994 if (crop_info->y > 0)
12995 y+=(int) (scale_factor*crop_info->y+0.5);
12996 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12997 if (height == 0)
12998 height=1;
cristyb51dff52011-05-19 16:55:47 +000012999 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013000 "%ux%u%+d%+d",width,height,x,y);
13001}
13002
13003/*
13004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13005% %
13006% %
13007% %
13008+ X T i l e I m a g e %
13009% %
13010% %
13011% %
13012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13013%
13014% XTileImage() loads or deletes a selected tile from a visual image directory.
13015% The load or delete command is chosen from a menu.
13016%
13017% The format of the XTileImage method is:
13018%
13019% Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013020% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013021%
13022% A description of each parameter follows:
13023%
13024% o tile_image: XTileImage reads or deletes the tile image
13025% and returns it. A null image is returned if an error occurs.
13026%
13027% o display: Specifies a connection to an X server; returned from
13028% XOpenDisplay.
13029%
13030% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13031%
13032% o windows: Specifies a pointer to a XWindows structure.
13033%
13034% o image: the image; returned from ReadImage.
13035%
13036% o event: Specifies a pointer to a XEvent structure. If it is NULL,
13037% the entire image is refreshed.
13038%
cristy051718b2011-08-28 22:49:25 +000013039% o exception: return any errors or warnings in this structure.
13040%
cristy3ed852e2009-09-05 21:47:34 +000013041*/
13042static Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013043 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013044{
13045 static const char
13046 *VerbMenu[] =
13047 {
13048 "Load",
13049 "Next",
13050 "Former",
13051 "Delete",
13052 "Update",
13053 (char *) NULL,
13054 };
13055
13056 static const ModeType
13057 TileCommands[] =
13058 {
13059 TileLoadCommand,
13060 TileNextCommand,
13061 TileFormerCommand,
13062 TileDeleteCommand,
13063 TileUpdateCommand
13064 };
13065
13066 char
13067 command[MaxTextExtent],
13068 filename[MaxTextExtent];
13069
13070 Image
13071 *tile_image;
13072
13073 int
13074 id,
13075 status,
13076 tile,
13077 x,
13078 y;
13079
13080 MagickRealType
13081 scale_factor;
13082
13083 register char
13084 *p,
13085 *q;
13086
13087 register int
13088 i;
13089
13090 unsigned int
13091 height,
13092 width;
13093
13094 /*
13095 Tile image is relative to montage image configuration.
13096 */
13097 x=0;
13098 y=0;
13099 width=(unsigned int) image->columns;
13100 height=(unsigned int) image->rows;
13101 if (windows->image.crop_geometry != (char *) NULL)
13102 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13103 scale_factor=(MagickRealType) width/windows->image.ximage->width;
13104 event->xbutton.x+=windows->image.x;
13105 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13106 scale_factor=(MagickRealType) height/windows->image.ximage->height;
13107 event->xbutton.y+=windows->image.y;
13108 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13109 /*
13110 Determine size and location of each tile in the visual image directory.
13111 */
13112 width=(unsigned int) image->columns;
13113 height=(unsigned int) image->rows;
13114 x=0;
13115 y=0;
13116 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13117 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13118 (event->xbutton.x-x)/width;
13119 if (tile < 0)
13120 {
13121 /*
13122 Button press is outside any tile.
13123 */
13124 (void) XBell(display,0);
13125 return((Image *) NULL);
13126 }
13127 /*
13128 Determine file name from the tile directory.
13129 */
13130 p=image->directory;
13131 for (i=tile; (i != 0) && (*p != '\0'); )
13132 {
13133 if (*p == '\n')
13134 i--;
13135 p++;
13136 }
13137 if (*p == '\0')
13138 {
13139 /*
13140 Button press is outside any tile.
13141 */
13142 (void) XBell(display,0);
13143 return((Image *) NULL);
13144 }
13145 /*
13146 Select a command from the pop-up menu.
13147 */
13148 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13149 if (id < 0)
13150 return((Image *) NULL);
13151 q=p;
13152 while ((*q != '\n') && (*q != '\0'))
13153 q++;
13154 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13155 /*
13156 Perform command for the selected tile.
13157 */
13158 XSetCursorState(display,windows,MagickTrue);
13159 XCheckRefreshWindows(display,windows);
13160 tile_image=NewImageList();
13161 switch (TileCommands[id])
13162 {
13163 case TileLoadCommand:
13164 {
13165 /*
13166 Load tile image.
13167 */
13168 XCheckRefreshWindows(display,windows);
13169 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13170 MaxTextExtent);
13171 (void) CopyMagickString(resource_info->image_info->filename,filename,
13172 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000013173 tile_image=ReadImage(resource_info->image_info,exception);
13174 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000013175 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13176 break;
13177 }
13178 case TileNextCommand:
13179 {
13180 /*
13181 Display next image.
13182 */
13183 XClientMessage(display,windows->image.id,windows->im_protocols,
13184 windows->im_next_image,CurrentTime);
13185 break;
13186 }
13187 case TileFormerCommand:
13188 {
13189 /*
13190 Display former image.
13191 */
13192 XClientMessage(display,windows->image.id,windows->im_protocols,
13193 windows->im_former_image,CurrentTime);
13194 break;
13195 }
13196 case TileDeleteCommand:
13197 {
13198 /*
13199 Delete tile image.
13200 */
13201 if (IsPathAccessible(filename) == MagickFalse)
13202 {
13203 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13204 break;
13205 }
13206 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13207 if (status <= 0)
13208 break;
cristy18c6c272011-09-23 14:40:37 +000013209 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +000013210 if (status != MagickFalse)
13211 {
13212 XNoticeWidget(display,windows,"Unable to delete image file:",
13213 filename);
13214 break;
13215 }
13216 }
13217 case TileUpdateCommand:
13218 {
cristy3ed852e2009-09-05 21:47:34 +000013219 int
13220 x_offset,
13221 y_offset;
13222
cristy101ab702011-10-13 13:06:32 +000013223 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000013224 pixel;
13225
cristy2ed42f62011-10-02 19:49:57 +000013226 Quantum
13227 virtual_pixel[MaxPixelChannels];
13228
cristy3ed852e2009-09-05 21:47:34 +000013229 register int
13230 j;
13231
cristy4c08aed2011-07-01 19:47:50 +000013232 register Quantum
cristy3ed852e2009-09-05 21:47:34 +000013233 *s;
13234
13235 /*
13236 Ensure all the images exist.
13237 */
13238 tile=0;
cristy101ab702011-10-13 13:06:32 +000013239 GetPixelInfo(image,&pixel);
cristy3ed852e2009-09-05 21:47:34 +000013240 for (p=image->directory; *p != '\0'; p++)
13241 {
cristyf7c25522010-11-15 01:25:14 +000013242 CacheView
13243 *image_view;
13244
cristy3ed852e2009-09-05 21:47:34 +000013245 q=p;
13246 while ((*q != '\n') && (*q != '\0'))
13247 q++;
13248 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13249 p=q;
13250 if (IsPathAccessible(filename) != MagickFalse)
13251 {
13252 tile++;
13253 continue;
13254 }
13255 /*
13256 Overwrite tile with background color.
13257 */
13258 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13259 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
cristy49e2d862010-11-12 02:50:30 +000013260 image_view=AcquireCacheView(image);
cristy2ed42f62011-10-02 19:49:57 +000013261 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel,
13262 exception);
13263 pixel.red=virtual_pixel[RedPixelChannel];
13264 pixel.green=virtual_pixel[GreenPixelChannel];
13265 pixel.blue=virtual_pixel[BluePixelChannel];
13266 pixel.alpha=virtual_pixel[AlphaPixelChannel];
cristy3ed852e2009-09-05 21:47:34 +000013267 for (i=0; i < (int) height; i++)
13268 {
cristy49e2d862010-11-12 02:50:30 +000013269 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13270 y_offset+i,width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000013271 if (s == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000013272 break;
13273 for (j=0; j < (int) width; j++)
cristy4c08aed2011-07-01 19:47:50 +000013274 {
cristy101ab702011-10-13 13:06:32 +000013275 SetPixelPixelInfo(image,&pixel,s);
cristyed231572011-07-14 02:18:59 +000013276 s+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +000013277 }
cristy49e2d862010-11-12 02:50:30 +000013278 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +000013279 break;
13280 }
cristyca1628f2010-11-15 01:17:49 +000013281 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000013282 tile++;
13283 }
13284 windows->image.window_changes.width=(int) image->columns;
13285 windows->image.window_changes.height=(int) image->rows;
13286 XConfigureImageColormap(display,resource_info,windows,image);
cristy051718b2011-08-28 22:49:25 +000013287 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013288 break;
13289 }
13290 default:
13291 break;
13292 }
13293 XSetCursorState(display,windows,MagickFalse);
13294 return(tile_image);
13295}
13296
13297/*
13298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13299% %
13300% %
13301% %
13302+ X T r a n s l a t e I m a g e %
13303% %
13304% %
13305% %
13306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13307%
13308% XTranslateImage() translates the image within an Image window by one pixel
13309% as specified by the key symbol. If the image has a `montage string the
13310% translation is respect to the width and height contained within the string.
13311%
13312% The format of the XTranslateImage method is:
13313%
13314% void XTranslateImage(Display *display,XWindows *windows,
13315% Image *image,const KeySym key_symbol)
13316%
13317% A description of each parameter follows:
13318%
13319% o display: Specifies a connection to an X server; returned from
13320% XOpenDisplay.
13321%
13322% o windows: Specifies a pointer to a XWindows structure.
13323%
13324% o image: the image.
13325%
13326% o key_symbol: Specifies a KeySym which indicates which side of the image
13327% to trim.
13328%
13329*/
13330static void XTranslateImage(Display *display,XWindows *windows,
13331 Image *image,const KeySym key_symbol)
13332{
13333 char
13334 text[MaxTextExtent];
13335
13336 int
13337 x,
13338 y;
13339
13340 unsigned int
13341 x_offset,
13342 y_offset;
13343
13344 /*
13345 User specified a pan position offset.
13346 */
13347 x_offset=windows->image.width;
13348 y_offset=windows->image.height;
13349 if (image->montage != (char *) NULL)
13350 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13351 switch ((int) key_symbol)
13352 {
13353 case XK_Home:
13354 case XK_KP_Home:
13355 {
13356 windows->image.x=(int) windows->image.width/2;
13357 windows->image.y=(int) windows->image.height/2;
13358 break;
13359 }
13360 case XK_Left:
13361 case XK_KP_Left:
13362 {
13363 windows->image.x-=x_offset;
13364 break;
13365 }
13366 case XK_Next:
13367 case XK_Up:
13368 case XK_KP_Up:
13369 {
13370 windows->image.y-=y_offset;
13371 break;
13372 }
13373 case XK_Right:
13374 case XK_KP_Right:
13375 {
13376 windows->image.x+=x_offset;
13377 break;
13378 }
13379 case XK_Prior:
13380 case XK_Down:
13381 case XK_KP_Down:
13382 {
13383 windows->image.y+=y_offset;
13384 break;
13385 }
13386 default:
13387 return;
13388 }
13389 /*
13390 Check boundary conditions.
13391 */
13392 if (windows->image.x < 0)
13393 windows->image.x=0;
13394 else
13395 if ((int) (windows->image.x+windows->image.width) >
13396 windows->image.ximage->width)
cristy49e2d862010-11-12 02:50:30 +000013397 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +000013398 if (windows->image.y < 0)
13399 windows->image.y=0;
13400 else
13401 if ((int) (windows->image.y+windows->image.height) >
13402 windows->image.ximage->height)
cristy49e2d862010-11-12 02:50:30 +000013403 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +000013404 /*
13405 Refresh Image window.
13406 */
cristyb51dff52011-05-19 16:55:47 +000013407 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000013408 windows->image.width,windows->image.height,windows->image.x,
13409 windows->image.y);
13410 XInfoWidget(display,windows,text);
13411 XCheckRefreshWindows(display,windows);
13412 XDrawPanRectangle(display,windows);
13413 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13414 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13415}
13416
13417/*
13418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13419% %
13420% %
13421% %
13422+ X T r i m I m a g e %
13423% %
13424% %
13425% %
13426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13427%
13428% XTrimImage() trims the edges from the Image window.
13429%
13430% The format of the XTrimImage method is:
13431%
13432% MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013433% XResourceInfo *resource_info,XWindows *windows,Image *image,
13434% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013435%
13436% A description of each parameter follows:
13437%
13438% o display: Specifies a connection to an X server; returned from
13439% XOpenDisplay.
13440%
13441% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13442%
13443% o windows: Specifies a pointer to a XWindows structure.
13444%
13445% o image: the image.
13446%
cristy051718b2011-08-28 22:49:25 +000013447% o exception: return any errors or warnings in this structure.
13448%
cristy3ed852e2009-09-05 21:47:34 +000013449*/
13450static MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013451 XResourceInfo *resource_info,XWindows *windows,Image *image,
13452 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013453{
13454 RectangleInfo
13455 trim_info;
13456
13457 register int
13458 x,
13459 y;
13460
cristybb503372010-05-27 20:51:26 +000013461 size_t
cristy3ed852e2009-09-05 21:47:34 +000013462 background,
13463 pixel;
13464
13465 /*
13466 Trim edges from image.
13467 */
13468 XSetCursorState(display,windows,MagickTrue);
13469 XCheckRefreshWindows(display,windows);
13470 /*
13471 Crop the left edge.
13472 */
13473 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013474 trim_info.width=(size_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013475 for (x=0; x < windows->image.ximage->width; x++)
13476 {
13477 for (y=0; y < windows->image.ximage->height; y++)
13478 {
13479 pixel=XGetPixel(windows->image.ximage,x,y);
13480 if (pixel != background)
13481 break;
13482 }
13483 if (y < windows->image.ximage->height)
13484 break;
13485 }
cristy49e2d862010-11-12 02:50:30 +000013486 trim_info.x=(ssize_t) x;
13487 if (trim_info.x == (ssize_t) windows->image.ximage->width)
cristy3ed852e2009-09-05 21:47:34 +000013488 {
13489 XSetCursorState(display,windows,MagickFalse);
13490 return(MagickFalse);
13491 }
13492 /*
13493 Crop the right edge.
13494 */
13495 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13496 for (x=windows->image.ximage->width-1; x != 0; x--)
13497 {
13498 for (y=0; y < windows->image.ximage->height; y++)
13499 {
13500 pixel=XGetPixel(windows->image.ximage,x,y);
13501 if (pixel != background)
13502 break;
13503 }
13504 if (y < windows->image.ximage->height)
13505 break;
13506 }
cristybb503372010-05-27 20:51:26 +000013507 trim_info.width=(size_t) (x-trim_info.x+1);
cristy3ed852e2009-09-05 21:47:34 +000013508 /*
13509 Crop the top edge.
13510 */
13511 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013512 trim_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013513 for (y=0; y < windows->image.ximage->height; y++)
13514 {
13515 for (x=0; x < windows->image.ximage->width; x++)
13516 {
13517 pixel=XGetPixel(windows->image.ximage,x,y);
13518 if (pixel != background)
13519 break;
13520 }
13521 if (x < windows->image.ximage->width)
13522 break;
13523 }
cristy49e2d862010-11-12 02:50:30 +000013524 trim_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000013525 /*
13526 Crop the bottom edge.
13527 */
13528 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13529 for (y=windows->image.ximage->height-1; y != 0; y--)
13530 {
13531 for (x=0; x < windows->image.ximage->width; x++)
13532 {
13533 pixel=XGetPixel(windows->image.ximage,x,y);
13534 if (pixel != background)
13535 break;
13536 }
13537 if (x < windows->image.ximage->width)
13538 break;
13539 }
cristybb503372010-05-27 20:51:26 +000013540 trim_info.height=(size_t) y-trim_info.y+1;
cristy3ed852e2009-09-05 21:47:34 +000013541 if (((unsigned int) trim_info.width != windows->image.width) ||
13542 ((unsigned int) trim_info.height != windows->image.height))
13543 {
13544 /*
13545 Reconfigure Image window as defined by the trimming rectangle.
13546 */
13547 XSetCropGeometry(display,windows,&trim_info,image);
13548 windows->image.window_changes.width=(int) trim_info.width;
13549 windows->image.window_changes.height=(int) trim_info.height;
cristy051718b2011-08-28 22:49:25 +000013550 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013551 }
13552 XSetCursorState(display,windows,MagickFalse);
13553 return(MagickTrue);
13554}
13555
13556/*
13557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13558% %
13559% %
13560% %
13561+ X V i s u a l D i r e c t o r y I m a g e %
13562% %
13563% %
13564% %
13565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13566%
13567% XVisualDirectoryImage() creates a Visual Image Directory.
13568%
13569% The format of the XVisualDirectoryImage method is:
13570%
13571% Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013572% XResourceInfo *resource_info,XWindows *windows,
13573% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013574%
13575% A description of each parameter follows:
13576%
cristy3ed852e2009-09-05 21:47:34 +000013577% o display: Specifies a connection to an X server; returned from
13578% XOpenDisplay.
13579%
13580% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13581%
13582% o windows: Specifies a pointer to a XWindows structure.
13583%
cristy051718b2011-08-28 22:49:25 +000013584% o exception: return any errors or warnings in this structure.
13585%
cristy3ed852e2009-09-05 21:47:34 +000013586*/
13587static Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013588 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013589{
13590#define TileImageTag "Scale/Image"
13591#define XClientName "montage"
13592
13593 char
13594 **filelist;
13595
cristy3ed852e2009-09-05 21:47:34 +000013596 Image
13597 *images,
13598 *montage_image,
13599 *next_image,
13600 *thumbnail_image;
13601
13602 ImageInfo
13603 *read_info;
13604
13605 int
13606 number_files;
13607
13608 MagickBooleanType
13609 backdrop;
13610
13611 MagickStatusType
13612 status;
13613
13614 MontageInfo
13615 *montage_info;
13616
13617 RectangleInfo
13618 geometry;
13619
13620 register int
13621 i;
13622
13623 static char
13624 filename[MaxTextExtent] = "\0",
13625 filenames[MaxTextExtent] = "*";
13626
13627 XResourceInfo
13628 background_resources;
13629
13630 /*
13631 Request file name from user.
13632 */
13633 XFileBrowserWidget(display,windows,"Directory",filenames);
13634 if (*filenames == '\0')
13635 return((Image *) NULL);
13636 /*
13637 Expand the filenames.
13638 */
cristy73bd4a52010-10-05 11:24:23 +000013639 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013640 if (filelist == (char **) NULL)
13641 {
13642 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13643 filenames);
13644 return((Image *) NULL);
13645 }
13646 number_files=1;
13647 filelist[0]=filenames;
13648 status=ExpandFilenames(&number_files,&filelist);
13649 if ((status == MagickFalse) || (number_files == 0))
13650 {
13651 if (number_files == 0)
13652 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13653 else
13654 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13655 filenames);
13656 return((Image *) NULL);
13657 }
13658 /*
13659 Set image background resources.
13660 */
13661 background_resources=(*resource_info);
13662 background_resources.window_id=AcquireString("");
cristyb51dff52011-05-19 16:55:47 +000013663 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013664 "0x%lx",windows->image.id);
13665 background_resources.backdrop=MagickTrue;
13666 /*
13667 Read each image and convert them to a tile.
13668 */
13669 backdrop=(windows->visual_info->klass == TrueColor) ||
13670 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13671 read_info=CloneImageInfo(resource_info->image_info);
cristy9ce61202010-11-24 00:38:37 +000013672 (void) SetImageOption(read_info,"jpeg:size","120x120");
13673 (void) CloneString(&read_info->size,DefaultTileGeometry);
cristy3ed852e2009-09-05 21:47:34 +000013674 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13675 (void *) NULL);
13676 images=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +000013677 XSetCursorState(display,windows,MagickTrue);
13678 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +000013679 for (i=0; i < (int) number_files; i++)
cristy3ed852e2009-09-05 21:47:34 +000013680 {
13681 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13682 filelist[i]=DestroyString(filelist[i]);
13683 *read_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +000013684 next_image=ReadImage(read_info,exception);
13685 CatchException(exception);
13686 if (next_image != (Image *) NULL)
13687 {
13688 (void) DeleteImageProperty(next_image,"label");
cristy77619442010-11-24 00:27:23 +000013689 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
cristyd15e6592011-10-15 00:13:06 +000013690 read_info,next_image,DefaultTileLabel,exception),exception);
cristy3ed852e2009-09-05 21:47:34 +000013691 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13692 exception);
13693 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13694 geometry.height,exception);
13695 if (thumbnail_image != (Image *) NULL)
13696 {
13697 next_image=DestroyImage(next_image);
13698 next_image=thumbnail_image;
13699 }
13700 if (backdrop)
13701 {
13702 (void) XDisplayBackgroundImage(display,&background_resources,
cristy051718b2011-08-28 22:49:25 +000013703 next_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013704 XSetCursorState(display,windows,MagickTrue);
13705 }
13706 AppendImageToList(&images,next_image);
13707 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13708 {
13709 MagickBooleanType
13710 proceed;
13711
13712 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13713 (MagickSizeType) number_files);
13714 if (proceed == MagickFalse)
13715 break;
13716 }
13717 }
13718 }
cristy3ed852e2009-09-05 21:47:34 +000013719 filelist=(char **) RelinquishMagickMemory(filelist);
cristy3ed852e2009-09-05 21:47:34 +000013720 if (images == (Image *) NULL)
13721 {
cristy8d52fca2010-11-24 00:45:05 +000013722 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013723 XSetCursorState(display,windows,MagickFalse);
13724 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13725 return((Image *) NULL);
13726 }
13727 /*
13728 Create the Visual Image Directory.
13729 */
cristy8d52fca2010-11-24 00:45:05 +000013730 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13731 montage_info->pointsize=10;
cristy3ed852e2009-09-05 21:47:34 +000013732 if (resource_info->font != (char *) NULL)
13733 (void) CloneString(&montage_info->font,resource_info->font);
13734 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
cristy8d52fca2010-11-24 00:45:05 +000013735 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
cristy051718b2011-08-28 22:49:25 +000013736 images),exception);
cristy3ed852e2009-09-05 21:47:34 +000013737 images=DestroyImageList(images);
cristy8d52fca2010-11-24 00:45:05 +000013738 montage_info=DestroyMontageInfo(montage_info);
13739 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013740 XSetCursorState(display,windows,MagickFalse);
13741 if (montage_image == (Image *) NULL)
13742 return(montage_image);
13743 XClientMessage(display,windows->image.id,windows->im_protocols,
13744 windows->im_next_image,CurrentTime);
13745 return(montage_image);
13746}
13747
13748/*
13749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13750% %
13751% %
13752% %
13753% X D i s p l a y B a c k g r o u n d I m a g e %
13754% %
13755% %
13756% %
13757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13758%
13759% XDisplayBackgroundImage() displays an image in the background of a window.
13760%
13761% The format of the XDisplayBackgroundImage method is:
13762%
13763% MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013764% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013765%
13766% A description of each parameter follows:
13767%
13768% o display: Specifies a connection to an X server; returned from
13769% XOpenDisplay.
13770%
13771% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13772%
13773% o image: the image.
13774%
cristy051718b2011-08-28 22:49:25 +000013775% o exception: return any errors or warnings in this structure.
13776%
cristy3ed852e2009-09-05 21:47:34 +000013777*/
13778MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013779 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013780{
13781 char
13782 geometry[MaxTextExtent],
13783 visual_type[MaxTextExtent];
13784
13785 int
13786 height,
13787 status,
13788 width;
13789
13790 RectangleInfo
13791 geometry_info;
13792
13793 static XPixelInfo
13794 pixel;
13795
13796 static XStandardColormap
13797 *map_info;
13798
13799 static XVisualInfo
13800 *visual_info = (XVisualInfo *) NULL;
13801
13802 static XWindowInfo
13803 window_info;
13804
cristybb503372010-05-27 20:51:26 +000013805 size_t
cristy3ed852e2009-09-05 21:47:34 +000013806 delay;
13807
13808 Window
13809 root_window;
13810
13811 XGCValues
13812 context_values;
13813
13814 XResourceInfo
13815 resources;
13816
13817 XWindowAttributes
13818 window_attributes;
13819
13820 /*
13821 Determine target window.
13822 */
13823 assert(image != (Image *) NULL);
13824 assert(image->signature == MagickSignature);
13825 if (image->debug != MagickFalse)
13826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13827 resources=(*resource_info);
13828 window_info.id=(Window) NULL;
13829 root_window=XRootWindow(display,XDefaultScreen(display));
13830 if (LocaleCompare(resources.window_id,"root") == 0)
13831 window_info.id=root_window;
13832 else
13833 {
13834 if (isdigit((unsigned char) *resources.window_id) != 0)
13835 window_info.id=XWindowByID(display,root_window,
13836 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13837 if (window_info.id == (Window) NULL)
13838 window_info.id=XWindowByName(display,root_window,resources.window_id);
13839 }
13840 if (window_info.id == (Window) NULL)
13841 {
13842 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13843 resources.window_id);
13844 return(MagickFalse);
13845 }
13846 /*
13847 Determine window visual id.
13848 */
13849 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13850 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13851 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13852 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13853 if (status != 0)
cristyb51dff52011-05-19 16:55:47 +000013854 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
cristy3ed852e2009-09-05 21:47:34 +000013855 XVisualIDFromVisual(window_attributes.visual));
13856 if (visual_info == (XVisualInfo *) NULL)
13857 {
13858 /*
13859 Allocate standard colormap.
13860 */
13861 map_info=XAllocStandardColormap();
13862 if (map_info == (XStandardColormap *) NULL)
13863 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13864 image->filename);
13865 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +000013866 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000013867 /*
13868 Initialize visual info.
13869 */
13870 resources.map_type=(char *) NULL;
13871 resources.visual_type=visual_type;
13872 visual_info=XBestVisualInfo(display,map_info,&resources);
13873 if (visual_info == (XVisualInfo *) NULL)
13874 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13875 resources.visual_type);
13876 /*
13877 Initialize window info.
13878 */
13879 window_info.ximage=(XImage *) NULL;
13880 window_info.matte_image=(XImage *) NULL;
13881 window_info.pixmap=(Pixmap) NULL;
13882 window_info.matte_pixmap=(Pixmap) NULL;
13883 }
13884 /*
13885 Free previous root colors.
13886 */
13887 if (window_info.id == root_window)
13888 (void) XDestroyWindowColors(display,root_window);
13889 /*
13890 Initialize Standard Colormap.
13891 */
13892 resources.colormap=SharedColormap;
13893 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13894 /*
13895 Graphic context superclass.
13896 */
13897 context_values.background=pixel.background_color.pixel;
13898 context_values.foreground=pixel.foreground_color.pixel;
13899 pixel.annotate_context=XCreateGC(display,window_info.id,
cristybb503372010-05-27 20:51:26 +000013900 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000013901 if (pixel.annotate_context == (GC) NULL)
13902 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13903 image->filename);
13904 /*
13905 Initialize Image window attributes.
13906 */
13907 window_info.name=AcquireString("\0");
13908 window_info.icon_name=AcquireString("\0");
13909 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13910 &resources,&window_info);
13911 /*
13912 Create the X image.
13913 */
13914 window_info.width=(unsigned int) image->columns;
13915 window_info.height=(unsigned int) image->rows;
13916 if ((image->columns != window_info.width) ||
13917 (image->rows != window_info.height))
13918 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13919 image->filename);
cristyb51dff52011-05-19 16:55:47 +000013920 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
cristy3ed852e2009-09-05 21:47:34 +000013921 window_attributes.width,window_attributes.height);
13922 geometry_info.width=window_info.width;
13923 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +000013924 geometry_info.x=(ssize_t) window_info.x;
13925 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +000013926 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13927 &geometry_info.width,&geometry_info.height);
13928 window_info.width=(unsigned int) geometry_info.width;
13929 window_info.height=(unsigned int) geometry_info.height;
13930 window_info.x=(int) geometry_info.x;
13931 window_info.y=(int) geometry_info.y;
13932 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
cristy051718b2011-08-28 22:49:25 +000013933 window_info.height,exception);
cristy3ed852e2009-09-05 21:47:34 +000013934 if (status == MagickFalse)
13935 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13936 image->filename);
13937 window_info.x=0;
13938 window_info.y=0;
13939 if (image->debug != MagickFalse)
13940 {
13941 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000013942 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13943 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +000013944 if (image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000013945 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13946 image->colors);
cristy3ed852e2009-09-05 21:47:34 +000013947 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13948 }
13949 /*
13950 Adjust image dimensions as specified by backdrop or geometry options.
13951 */
13952 width=(int) window_info.width;
13953 height=(int) window_info.height;
13954 if (resources.backdrop != MagickFalse)
13955 {
13956 /*
13957 Center image on window.
13958 */
13959 window_info.x=(window_attributes.width/2)-
13960 (window_info.ximage->width/2);
13961 window_info.y=(window_attributes.height/2)-
13962 (window_info.ximage->height/2);
13963 width=window_attributes.width;
13964 height=window_attributes.height;
13965 }
13966 if ((resources.image_geometry != (char *) NULL) &&
13967 (*resources.image_geometry != '\0'))
13968 {
13969 char
13970 default_geometry[MaxTextExtent];
13971
13972 int
13973 flags,
13974 gravity;
13975
13976 XSizeHints
13977 *size_hints;
13978
13979 /*
13980 User specified geometry.
13981 */
13982 size_hints=XAllocSizeHints();
13983 if (size_hints == (XSizeHints *) NULL)
13984 ThrowXWindowFatalException(ResourceLimitFatalError,
13985 "MemoryAllocationFailed",image->filename);
13986 size_hints->flags=0L;
cristyb51dff52011-05-19 16:55:47 +000013987 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
cristy3ed852e2009-09-05 21:47:34 +000013988 width,height);
13989 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13990 default_geometry,window_info.border_width,size_hints,&window_info.x,
13991 &window_info.y,&width,&height,&gravity);
13992 if (flags & (XValue | YValue))
13993 {
13994 width=window_attributes.width;
13995 height=window_attributes.height;
13996 }
13997 (void) XFree((void *) size_hints);
13998 }
13999 /*
14000 Create the X pixmap.
14001 */
14002 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14003 (unsigned int) height,window_info.depth);
14004 if (window_info.pixmap == (Pixmap) NULL)
14005 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14006 image->filename);
14007 /*
14008 Display pixmap on the window.
14009 */
14010 if (((unsigned int) width > window_info.width) ||
14011 ((unsigned int) height > window_info.height))
14012 (void) XFillRectangle(display,window_info.pixmap,
14013 window_info.annotate_context,0,0,(unsigned int) width,
14014 (unsigned int) height);
14015 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14016 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14017 window_info.width,(unsigned int) window_info.height);
14018 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14019 (void) XClearWindow(display,window_info.id);
14020 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14021 XDelay(display,delay == 0UL ? 10UL : delay);
14022 (void) XSync(display,MagickFalse);
14023 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14024}
14025
14026/*
14027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14028% %
14029% %
14030% %
14031+ X D i s p l a y I m a g e %
14032% %
14033% %
14034% %
14035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14036%
14037% XDisplayImage() displays an image via X11. A new image is created and
14038% returned if the user interactively transforms the displayed image.
14039%
14040% The format of the XDisplayImage method is:
14041%
14042% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014043% char **argv,int argc,Image **image,size_t *state,
14044% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014045%
14046% A description of each parameter follows:
14047%
14048% o nexus: Method XDisplayImage returns an image when the
14049% user chooses 'Open Image' from the command menu or picks a tile
14050% from the image directory. Otherwise a null image is returned.
14051%
14052% o display: Specifies a connection to an X server; returned from
14053% XOpenDisplay.
14054%
14055% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14056%
14057% o argv: Specifies the application's argument list.
14058%
14059% o argc: Specifies the number of arguments.
14060%
14061% o image: Specifies an address to an address of an Image structure;
14062%
cristy051718b2011-08-28 22:49:25 +000014063% o exception: return any errors or warnings in this structure.
14064%
cristy3ed852e2009-09-05 21:47:34 +000014065*/
14066MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014067 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014068{
14069#define MagnifySize 256 /* must be a power of 2 */
14070#define MagickMenus 10
14071#define MagickTitle "Commands"
14072
14073 static const char
14074 *CommandMenu[] =
14075 {
14076 "File",
14077 "Edit",
14078 "View",
14079 "Transform",
14080 "Enhance",
14081 "Effects",
14082 "F/X",
14083 "Image Edit",
14084 "Miscellany",
14085 "Help",
14086 (char *) NULL
14087 },
14088 *FileMenu[] =
14089 {
14090 "Open...",
14091 "Next",
14092 "Former",
14093 "Select...",
14094 "Save...",
14095 "Print...",
14096 "Delete...",
14097 "New...",
14098 "Visual Directory...",
14099 "Quit",
14100 (char *) NULL
14101 },
14102 *EditMenu[] =
14103 {
14104 "Undo",
14105 "Redo",
14106 "Cut",
14107 "Copy",
14108 "Paste",
14109 (char *) NULL
14110 },
14111 *ViewMenu[] =
14112 {
14113 "Half Size",
14114 "Original Size",
14115 "Double Size",
14116 "Resize...",
14117 "Apply",
14118 "Refresh",
14119 "Restore",
14120 (char *) NULL
14121 },
14122 *TransformMenu[] =
14123 {
14124 "Crop",
14125 "Chop",
14126 "Flop",
14127 "Flip",
14128 "Rotate Right",
14129 "Rotate Left",
14130 "Rotate...",
14131 "Shear...",
14132 "Roll...",
14133 "Trim Edges",
14134 (char *) NULL
14135 },
14136 *EnhanceMenu[] =
14137 {
14138 "Hue...",
14139 "Saturation...",
14140 "Brightness...",
14141 "Gamma...",
14142 "Spiff",
14143 "Dull",
14144 "Contrast Stretch...",
14145 "Sigmoidal Contrast...",
14146 "Normalize",
14147 "Equalize",
14148 "Negate",
14149 "Grayscale",
14150 "Map...",
14151 "Quantize...",
14152 (char *) NULL
14153 },
14154 *EffectsMenu[] =
14155 {
14156 "Despeckle",
14157 "Emboss",
14158 "Reduce Noise",
14159 "Add Noise...",
14160 "Sharpen...",
14161 "Blur...",
14162 "Threshold...",
14163 "Edge Detect...",
14164 "Spread...",
14165 "Shade...",
14166 "Raise...",
14167 "Segment...",
14168 (char *) NULL
14169 },
14170 *FXMenu[] =
14171 {
14172 "Solarize...",
14173 "Sepia Tone...",
14174 "Swirl...",
14175 "Implode...",
14176 "Vignette...",
14177 "Wave...",
14178 "Oil Paint...",
14179 "Charcoal Draw...",
14180 (char *) NULL
14181 },
14182 *ImageEditMenu[] =
14183 {
14184 "Annotate...",
14185 "Draw...",
14186 "Color...",
14187 "Matte...",
14188 "Composite...",
14189 "Add Border...",
14190 "Add Frame...",
14191 "Comment...",
14192 "Launch...",
14193 "Region of Interest...",
14194 (char *) NULL
14195 },
14196 *MiscellanyMenu[] =
14197 {
14198 "Image Info",
14199 "Zoom Image",
14200 "Show Preview...",
14201 "Show Histogram",
14202 "Show Matte",
14203 "Background...",
14204 "Slide Show...",
14205 "Preferences...",
14206 (char *) NULL
14207 },
14208 *HelpMenu[] =
14209 {
14210 "Overview",
14211 "Browse Documentation",
14212 "About Display",
14213 (char *) NULL
14214 },
14215 *ShortCutsMenu[] =
14216 {
14217 "Next",
14218 "Former",
14219 "Open...",
14220 "Save...",
14221 "Print...",
14222 "Undo",
14223 "Restore",
14224 "Image Info",
14225 "Quit",
14226 (char *) NULL
14227 },
14228 *VirtualMenu[] =
14229 {
14230 "Image Info",
14231 "Print",
14232 "Next",
14233 "Quit",
14234 (char *) NULL
14235 };
14236
14237 static const char
14238 **Menus[MagickMenus] =
14239 {
14240 FileMenu,
14241 EditMenu,
14242 ViewMenu,
14243 TransformMenu,
14244 EnhanceMenu,
14245 EffectsMenu,
14246 FXMenu,
14247 ImageEditMenu,
14248 MiscellanyMenu,
14249 HelpMenu
14250 };
14251
14252 static CommandType
14253 CommandMenus[] =
14254 {
14255 NullCommand,
14256 NullCommand,
14257 NullCommand,
14258 NullCommand,
14259 NullCommand,
14260 NullCommand,
14261 NullCommand,
14262 NullCommand,
14263 NullCommand,
14264 NullCommand,
14265 },
14266 FileCommands[] =
14267 {
14268 OpenCommand,
14269 NextCommand,
14270 FormerCommand,
14271 SelectCommand,
14272 SaveCommand,
14273 PrintCommand,
14274 DeleteCommand,
14275 NewCommand,
14276 VisualDirectoryCommand,
14277 QuitCommand
14278 },
14279 EditCommands[] =
14280 {
14281 UndoCommand,
14282 RedoCommand,
14283 CutCommand,
14284 CopyCommand,
14285 PasteCommand
14286 },
14287 ViewCommands[] =
14288 {
14289 HalfSizeCommand,
14290 OriginalSizeCommand,
14291 DoubleSizeCommand,
14292 ResizeCommand,
14293 ApplyCommand,
14294 RefreshCommand,
14295 RestoreCommand
14296 },
14297 TransformCommands[] =
14298 {
14299 CropCommand,
14300 ChopCommand,
14301 FlopCommand,
14302 FlipCommand,
14303 RotateRightCommand,
14304 RotateLeftCommand,
14305 RotateCommand,
14306 ShearCommand,
14307 RollCommand,
14308 TrimCommand
14309 },
14310 EnhanceCommands[] =
14311 {
14312 HueCommand,
14313 SaturationCommand,
14314 BrightnessCommand,
14315 GammaCommand,
14316 SpiffCommand,
14317 DullCommand,
14318 ContrastStretchCommand,
14319 SigmoidalContrastCommand,
14320 NormalizeCommand,
14321 EqualizeCommand,
14322 NegateCommand,
14323 GrayscaleCommand,
14324 MapCommand,
14325 QuantizeCommand
14326 },
14327 EffectsCommands[] =
14328 {
14329 DespeckleCommand,
14330 EmbossCommand,
14331 ReduceNoiseCommand,
14332 AddNoiseCommand,
14333 SharpenCommand,
14334 BlurCommand,
14335 ThresholdCommand,
14336 EdgeDetectCommand,
14337 SpreadCommand,
14338 ShadeCommand,
14339 RaiseCommand,
14340 SegmentCommand
14341 },
14342 FXCommands[] =
14343 {
14344 SolarizeCommand,
14345 SepiaToneCommand,
14346 SwirlCommand,
14347 ImplodeCommand,
14348 VignetteCommand,
14349 WaveCommand,
14350 OilPaintCommand,
14351 CharcoalDrawCommand
14352 },
14353 ImageEditCommands[] =
14354 {
14355 AnnotateCommand,
14356 DrawCommand,
14357 ColorCommand,
14358 MatteCommand,
14359 CompositeCommand,
14360 AddBorderCommand,
14361 AddFrameCommand,
14362 CommentCommand,
14363 LaunchCommand,
14364 RegionofInterestCommand
14365 },
14366 MiscellanyCommands[] =
14367 {
14368 InfoCommand,
14369 ZoomCommand,
14370 ShowPreviewCommand,
14371 ShowHistogramCommand,
14372 ShowMatteCommand,
14373 BackgroundCommand,
14374 SlideShowCommand,
14375 PreferencesCommand
14376 },
14377 HelpCommands[] =
14378 {
14379 HelpCommand,
14380 BrowseDocumentationCommand,
14381 VersionCommand
14382 },
14383 ShortCutsCommands[] =
14384 {
14385 NextCommand,
14386 FormerCommand,
14387 OpenCommand,
14388 SaveCommand,
14389 PrintCommand,
14390 UndoCommand,
14391 RestoreCommand,
14392 InfoCommand,
14393 QuitCommand
14394 },
14395 VirtualCommands[] =
14396 {
14397 InfoCommand,
14398 PrintCommand,
14399 NextCommand,
14400 QuitCommand
14401 };
14402
14403 static CommandType
14404 *Commands[MagickMenus] =
14405 {
14406 FileCommands,
14407 EditCommands,
14408 ViewCommands,
14409 TransformCommands,
14410 EnhanceCommands,
14411 EffectsCommands,
14412 FXCommands,
14413 ImageEditCommands,
14414 MiscellanyCommands,
14415 HelpCommands
14416 };
14417
14418 char
14419 command[MaxTextExtent],
cristy00976d82011-02-20 20:31:28 +000014420 *directory,
cristy3ed852e2009-09-05 21:47:34 +000014421 geometry[MaxTextExtent],
14422 resource_name[MaxTextExtent];
14423
14424 CommandType
14425 command_type;
14426
14427 Image
14428 *display_image,
14429 *nexus;
14430
14431 int
14432 entry,
14433 id;
14434
14435 KeySym
14436 key_symbol;
14437
14438 MagickStatusType
14439 context_mask,
14440 status;
14441
14442 RectangleInfo
14443 geometry_info;
14444
14445 register int
14446 i;
14447
14448 static char
14449 working_directory[MaxTextExtent];
14450
14451 static XPoint
14452 vid_info;
14453
14454 static XWindowInfo
14455 *magick_windows[MaxXWindows];
14456
14457 static unsigned int
14458 number_windows;
14459
14460 struct stat
14461 attributes;
14462
14463 time_t
14464 timer,
14465 timestamp,
14466 update_time;
14467
14468 unsigned int
14469 height,
14470 width;
14471
cristybb503372010-05-27 20:51:26 +000014472 size_t
cristy3ed852e2009-09-05 21:47:34 +000014473 delay;
14474
14475 WarningHandler
14476 warning_handler;
14477
14478 Window
14479 root_window;
14480
14481 XClassHint
14482 *class_hints;
14483
14484 XEvent
14485 event;
14486
14487 XFontStruct
14488 *font_info;
14489
14490 XGCValues
14491 context_values;
14492
14493 XPixelInfo
14494 *icon_pixel,
14495 *pixel;
14496
14497 XResourceInfo
14498 *icon_resources;
14499
14500 XStandardColormap
14501 *icon_map,
14502 *map_info;
14503
14504 XVisualInfo
14505 *icon_visual,
14506 *visual_info;
14507
14508 XWindowChanges
14509 window_changes;
14510
14511 XWindows
14512 *windows;
14513
14514 XWMHints
14515 *manager_hints;
14516
14517 assert(image != (Image **) NULL);
14518 assert((*image)->signature == MagickSignature);
14519 if ((*image)->debug != MagickFalse)
14520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14521 display_image=(*image);
14522 warning_handler=(WarningHandler) NULL;
14523 windows=XSetWindows((XWindows *) ~0);
14524 if (windows != (XWindows *) NULL)
14525 {
14526 int
14527 status;
14528
14529 status=chdir(working_directory);
14530 if (status == -1)
cristy051718b2011-08-28 22:49:25 +000014531 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14532 "UnableToOpenFile","%s",working_directory);
cristy3ed852e2009-09-05 21:47:34 +000014533 warning_handler=resource_info->display_warnings ?
14534 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14535 warning_handler=resource_info->display_warnings ?
14536 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14537 }
14538 else
14539 {
14540 /*
14541 Allocate windows structure.
14542 */
14543 resource_info->colors=display_image->colors;
14544 windows=XSetWindows(XInitializeWindows(display,resource_info));
14545 if (windows == (XWindows *) NULL)
14546 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14547 (*image)->filename);
14548 /*
14549 Initialize window id's.
14550 */
14551 number_windows=0;
14552 magick_windows[number_windows++]=(&windows->icon);
14553 magick_windows[number_windows++]=(&windows->backdrop);
14554 magick_windows[number_windows++]=(&windows->image);
14555 magick_windows[number_windows++]=(&windows->info);
14556 magick_windows[number_windows++]=(&windows->command);
14557 magick_windows[number_windows++]=(&windows->widget);
14558 magick_windows[number_windows++]=(&windows->popup);
14559 magick_windows[number_windows++]=(&windows->magnify);
14560 magick_windows[number_windows++]=(&windows->pan);
14561 for (i=0; i < (int) number_windows; i++)
14562 magick_windows[i]->id=(Window) NULL;
14563 vid_info.x=0;
14564 vid_info.y=0;
14565 }
14566 /*
14567 Initialize font info.
14568 */
14569 if (windows->font_info != (XFontStruct *) NULL)
14570 (void) XFreeFont(display,windows->font_info);
14571 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14572 if (windows->font_info == (XFontStruct *) NULL)
14573 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14574 resource_info->font);
14575 /*
14576 Initialize Standard Colormap.
14577 */
14578 map_info=windows->map_info;
14579 icon_map=windows->icon_map;
14580 visual_info=windows->visual_info;
14581 icon_visual=windows->icon_visual;
14582 pixel=windows->pixel_info;
14583 icon_pixel=windows->icon_pixel;
14584 font_info=windows->font_info;
14585 icon_resources=windows->icon_resources;
14586 class_hints=windows->class_hints;
14587 manager_hints=windows->manager_hints;
14588 root_window=XRootWindow(display,visual_info->screen);
14589 nexus=NewImageList();
14590 if (display_image->debug != MagickFalse)
14591 {
14592 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000014593 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14594 (double) display_image->scene,(double) display_image->columns,
14595 (double) display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +000014596 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000014597 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14598 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +000014599 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14600 display_image->magick);
14601 }
14602 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14603 map_info,pixel);
14604 display_image->taint=MagickFalse;
14605 /*
14606 Initialize graphic context.
14607 */
14608 windows->context.id=(Window) NULL;
14609 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14610 resource_info,&windows->context);
14611 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14612 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14613 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14614 manager_hints->flags=InputHint | StateHint;
14615 manager_hints->input=MagickFalse;
14616 manager_hints->initial_state=WithdrawnState;
14617 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14618 &windows->context);
14619 if (display_image->debug != MagickFalse)
14620 (void) LogMagickEvent(X11Event,GetMagickModule(),
14621 "Window id: 0x%lx (context)",windows->context.id);
14622 context_values.background=pixel->background_color.pixel;
14623 context_values.font=font_info->fid;
14624 context_values.foreground=pixel->foreground_color.pixel;
14625 context_values.graphics_exposures=MagickFalse;
14626 context_mask=(MagickStatusType)
14627 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14628 if (pixel->annotate_context != (GC) NULL)
14629 (void) XFreeGC(display,pixel->annotate_context);
14630 pixel->annotate_context=XCreateGC(display,windows->context.id,
14631 context_mask,&context_values);
14632 if (pixel->annotate_context == (GC) NULL)
14633 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14634 display_image->filename);
14635 context_values.background=pixel->depth_color.pixel;
14636 if (pixel->widget_context != (GC) NULL)
14637 (void) XFreeGC(display,pixel->widget_context);
14638 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14639 &context_values);
14640 if (pixel->widget_context == (GC) NULL)
14641 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14642 display_image->filename);
14643 context_values.background=pixel->foreground_color.pixel;
14644 context_values.foreground=pixel->background_color.pixel;
14645 context_values.plane_mask=context_values.background ^
14646 context_values.foreground;
14647 if (pixel->highlight_context != (GC) NULL)
14648 (void) XFreeGC(display,pixel->highlight_context);
14649 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +000014650 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014651 if (pixel->highlight_context == (GC) NULL)
14652 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14653 display_image->filename);
14654 (void) XDestroyWindow(display,windows->context.id);
14655 /*
14656 Initialize icon window.
14657 */
14658 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14659 icon_resources,&windows->icon);
14660 windows->icon.geometry=resource_info->icon_geometry;
14661 XBestIconSize(display,&windows->icon,display_image);
14662 windows->icon.attributes.colormap=XDefaultColormap(display,
14663 icon_visual->screen);
14664 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14665 manager_hints->flags=InputHint | StateHint;
14666 manager_hints->input=MagickFalse;
14667 manager_hints->initial_state=IconicState;
14668 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14669 &windows->icon);
14670 if (display_image->debug != MagickFalse)
14671 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14672 windows->icon.id);
14673 /*
14674 Initialize graphic context for icon window.
14675 */
14676 if (icon_pixel->annotate_context != (GC) NULL)
14677 (void) XFreeGC(display,icon_pixel->annotate_context);
14678 context_values.background=icon_pixel->background_color.pixel;
14679 context_values.foreground=icon_pixel->foreground_color.pixel;
14680 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +000014681 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014682 if (icon_pixel->annotate_context == (GC) NULL)
14683 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14684 display_image->filename);
14685 windows->icon.annotate_context=icon_pixel->annotate_context;
14686 /*
14687 Initialize Image window.
14688 */
14689 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14690 &windows->image);
14691 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14692 if (resource_info->use_shared_memory == MagickFalse)
14693 windows->image.shared_memory=MagickFalse;
14694 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14695 {
14696 char
14697 *title;
14698
14699 title=InterpretImageProperties(resource_info->image_info,display_image,
cristy018f07f2011-09-04 21:15:19 +000014700 resource_info->title,exception);
cristy3ed852e2009-09-05 21:47:34 +000014701 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14702 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14703 title=DestroyString(title);
14704 }
14705 else
14706 {
14707 char
14708 filename[MaxTextExtent];
14709
14710 /*
14711 Window name is the base of the filename.
14712 */
14713 GetPathComponent(display_image->magick_filename,TailPath,filename);
cristy9a48b172011-09-20 17:41:05 +000014714 if (display_image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +000014715 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy40a08ad2010-02-09 02:27:44 +000014716 "%s: %s",MagickPackageName,filename);
cristy3ed852e2009-09-05 21:47:34 +000014717 else
cristyb51dff52011-05-19 16:55:47 +000014718 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy04d55062011-03-15 18:58:50 +000014719 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14720 (double) display_image->scene,(double) GetImageListLength(
14721 display_image));
cristy3ed852e2009-09-05 21:47:34 +000014722 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14723 }
14724 if (resource_info->immutable)
14725 windows->image.immutable=MagickTrue;
14726 windows->image.use_pixmap=resource_info->use_pixmap;
14727 windows->image.geometry=resource_info->image_geometry;
cristyb51dff52011-05-19 16:55:47 +000014728 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +000014729 XDisplayWidth(display,visual_info->screen),
14730 XDisplayHeight(display,visual_info->screen));
14731 geometry_info.width=display_image->columns;
14732 geometry_info.height=display_image->rows;
14733 geometry_info.x=0;
14734 geometry_info.y=0;
14735 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14736 &geometry_info.width,&geometry_info.height);
14737 windows->image.width=(unsigned int) geometry_info.width;
14738 windows->image.height=(unsigned int) geometry_info.height;
14739 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14740 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14741 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14742 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14743 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14744 resource_info,&windows->backdrop);
14745 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14746 {
14747 /*
14748 Initialize backdrop window.
14749 */
14750 windows->backdrop.x=0;
14751 windows->backdrop.y=0;
cristy40a08ad2010-02-09 02:27:44 +000014752 (void) CloneString(&windows->backdrop.name,"Backdrop");
cristybb503372010-05-27 20:51:26 +000014753 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +000014754 windows->backdrop.width=(unsigned int)
14755 XDisplayWidth(display,visual_info->screen);
14756 windows->backdrop.height=(unsigned int)
14757 XDisplayHeight(display,visual_info->screen);
14758 windows->backdrop.border_width=0;
14759 windows->backdrop.immutable=MagickTrue;
14760 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14761 ButtonReleaseMask;
14762 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14763 StructureNotifyMask;
14764 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14765 manager_hints->icon_window=windows->icon.id;
14766 manager_hints->input=MagickTrue;
14767 manager_hints->initial_state=resource_info->iconic ? IconicState :
14768 NormalState;
14769 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14770 &windows->backdrop);
14771 if (display_image->debug != MagickFalse)
14772 (void) LogMagickEvent(X11Event,GetMagickModule(),
14773 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14774 (void) XMapWindow(display,windows->backdrop.id);
14775 (void) XClearWindow(display,windows->backdrop.id);
14776 if (windows->image.id != (Window) NULL)
14777 {
14778 (void) XDestroyWindow(display,windows->image.id);
14779 windows->image.id=(Window) NULL;
14780 }
14781 /*
14782 Position image in the center the backdrop.
14783 */
14784 windows->image.flags|=USPosition;
14785 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14786 (windows->image.width/2);
14787 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14788 (windows->image.height/2);
14789 }
14790 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14791 manager_hints->icon_window=windows->icon.id;
14792 manager_hints->input=MagickTrue;
14793 manager_hints->initial_state=resource_info->iconic ? IconicState :
14794 NormalState;
14795 if (windows->group_leader.id != (Window) NULL)
14796 {
14797 /*
14798 Follow the leader.
14799 */
14800 manager_hints->flags|=WindowGroupHint;
14801 manager_hints->window_group=windows->group_leader.id;
14802 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14803 if (display_image->debug != MagickFalse)
14804 (void) LogMagickEvent(X11Event,GetMagickModule(),
14805 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14806 }
14807 XMakeWindow(display,
14808 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14809 argv,argc,class_hints,manager_hints,&windows->image);
14810 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14811 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14812 if (windows->group_leader.id != (Window) NULL)
14813 (void) XSetTransientForHint(display,windows->image.id,
14814 windows->group_leader.id);
14815 if (display_image->debug != MagickFalse)
14816 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14817 windows->image.id);
14818 /*
14819 Initialize Info widget.
14820 */
14821 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14822 &windows->info);
14823 (void) CloneString(&windows->info.name,"Info");
14824 (void) CloneString(&windows->info.icon_name,"Info");
14825 windows->info.border_width=1;
14826 windows->info.x=2;
14827 windows->info.y=2;
14828 windows->info.flags|=PPosition;
14829 windows->info.attributes.win_gravity=UnmapGravity;
14830 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14831 StructureNotifyMask;
14832 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14833 manager_hints->input=MagickFalse;
14834 manager_hints->initial_state=NormalState;
14835 manager_hints->window_group=windows->image.id;
14836 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14837 &windows->info);
14838 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14839 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14840 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14841 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14842 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14843 if (windows->image.mapped != MagickFalse)
14844 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14845 if (display_image->debug != MagickFalse)
14846 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14847 windows->info.id);
14848 /*
14849 Initialize Command widget.
14850 */
14851 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14852 resource_info,&windows->command);
14853 windows->command.data=MagickMenus;
14854 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014855 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
cristy3ed852e2009-09-05 21:47:34 +000014856 resource_info->client_name);
14857 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14858 resource_name,"geometry",(char *) NULL);
14859 (void) CloneString(&windows->command.name,MagickTitle);
14860 windows->command.border_width=0;
14861 windows->command.flags|=PPosition;
14862 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14863 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14864 OwnerGrabButtonMask | StructureNotifyMask;
14865 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14866 manager_hints->input=MagickTrue;
14867 manager_hints->initial_state=NormalState;
14868 manager_hints->window_group=windows->image.id;
14869 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14870 &windows->command);
14871 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14872 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14873 HighlightHeight);
14874 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14875 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14876 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14877 if (windows->command.mapped != MagickFalse)
14878 (void) XMapRaised(display,windows->command.id);
14879 if (display_image->debug != MagickFalse)
14880 (void) LogMagickEvent(X11Event,GetMagickModule(),
14881 "Window id: 0x%lx (command)",windows->command.id);
14882 /*
14883 Initialize Widget window.
14884 */
14885 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14886 resource_info,&windows->widget);
cristyb51dff52011-05-19 16:55:47 +000014887 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
cristy3ed852e2009-09-05 21:47:34 +000014888 resource_info->client_name);
14889 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14890 resource_name,"geometry",(char *) NULL);
14891 windows->widget.border_width=0;
14892 windows->widget.flags|=PPosition;
14893 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14894 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14895 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14896 StructureNotifyMask;
14897 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14898 manager_hints->input=MagickTrue;
14899 manager_hints->initial_state=NormalState;
14900 manager_hints->window_group=windows->image.id;
14901 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14902 &windows->widget);
14903 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14904 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14905 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14906 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14907 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14908 if (display_image->debug != MagickFalse)
14909 (void) LogMagickEvent(X11Event,GetMagickModule(),
14910 "Window id: 0x%lx (widget)",windows->widget.id);
14911 /*
14912 Initialize popup window.
14913 */
14914 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14915 resource_info,&windows->popup);
14916 windows->popup.border_width=0;
14917 windows->popup.flags|=PPosition;
14918 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14919 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14920 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14921 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14922 manager_hints->input=MagickTrue;
14923 manager_hints->initial_state=NormalState;
14924 manager_hints->window_group=windows->image.id;
14925 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14926 &windows->popup);
14927 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14928 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14929 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14930 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14931 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14932 if (display_image->debug != MagickFalse)
14933 (void) LogMagickEvent(X11Event,GetMagickModule(),
14934 "Window id: 0x%lx (pop up)",windows->popup.id);
14935 /*
14936 Initialize Magnify window and cursor.
14937 */
14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14939 resource_info,&windows->magnify);
14940 if (resource_info->use_shared_memory == MagickFalse)
14941 windows->magnify.shared_memory=MagickFalse;
cristyb51dff52011-05-19 16:55:47 +000014942 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
cristy3ed852e2009-09-05 21:47:34 +000014943 resource_info->client_name);
14944 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14945 resource_name,"geometry",(char *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014946 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
cristy3ed852e2009-09-05 21:47:34 +000014947 resource_info->magnify);
14948 if (windows->magnify.cursor != (Cursor) NULL)
14949 (void) XFreeCursor(display,windows->magnify.cursor);
14950 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14951 map_info->colormap,resource_info->background_color,
14952 resource_info->foreground_color);
14953 if (windows->magnify.cursor == (Cursor) NULL)
14954 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14955 display_image->filename);
14956 windows->magnify.width=MagnifySize;
14957 windows->magnify.height=MagnifySize;
14958 windows->magnify.flags|=PPosition;
14959 windows->magnify.min_width=MagnifySize;
14960 windows->magnify.min_height=MagnifySize;
14961 windows->magnify.width_inc=MagnifySize;
14962 windows->magnify.height_inc=MagnifySize;
14963 windows->magnify.data=resource_info->magnify;
14964 windows->magnify.attributes.cursor=windows->magnify.cursor;
14965 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14966 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14967 StructureNotifyMask;
14968 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14969 manager_hints->input=MagickTrue;
14970 manager_hints->initial_state=NormalState;
14971 manager_hints->window_group=windows->image.id;
14972 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14973 &windows->magnify);
14974 if (display_image->debug != MagickFalse)
14975 (void) LogMagickEvent(X11Event,GetMagickModule(),
14976 "Window id: 0x%lx (magnify)",windows->magnify.id);
14977 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14978 /*
14979 Initialize panning window.
14980 */
14981 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14982 resource_info,&windows->pan);
14983 (void) CloneString(&windows->pan.name,"Pan Icon");
14984 windows->pan.width=windows->icon.width;
14985 windows->pan.height=windows->icon.height;
cristyb51dff52011-05-19 16:55:47 +000014986 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
cristy3ed852e2009-09-05 21:47:34 +000014987 resource_info->client_name);
14988 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14989 resource_name,"geometry",(char *) NULL);
14990 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14991 &windows->pan.width,&windows->pan.height);
14992 windows->pan.flags|=PPosition;
14993 windows->pan.immutable=MagickTrue;
14994 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14995 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14996 StructureNotifyMask;
14997 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14998 manager_hints->input=MagickFalse;
14999 manager_hints->initial_state=NormalState;
15000 manager_hints->window_group=windows->image.id;
15001 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15002 &windows->pan);
15003 if (display_image->debug != MagickFalse)
15004 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15005 windows->pan.id);
15006 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15007 if (windows->info.mapped != MagickFalse)
15008 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15009 if ((windows->image.mapped == MagickFalse) ||
15010 (windows->backdrop.id != (Window) NULL))
15011 (void) XMapWindow(display,windows->image.id);
15012 /*
15013 Set our progress monitor and warning handlers.
15014 */
15015 if (warning_handler == (WarningHandler) NULL)
15016 {
15017 warning_handler=resource_info->display_warnings ?
15018 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15019 warning_handler=resource_info->display_warnings ?
15020 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15021 }
15022 /*
15023 Initialize Image and Magnify X images.
15024 */
15025 windows->image.x=0;
15026 windows->image.y=0;
15027 windows->magnify.shape=MagickFalse;
15028 width=(unsigned int) display_image->columns;
15029 height=(unsigned int) display_image->rows;
15030 if ((display_image->columns != width) || (display_image->rows != height))
15031 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15032 display_image->filename);
15033 status=XMakeImage(display,resource_info,&windows->image,display_image,
cristy051718b2011-08-28 22:49:25 +000015034 width,height,exception);
cristy3ed852e2009-09-05 21:47:34 +000015035 if (status == MagickFalse)
15036 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15037 display_image->filename);
15038 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
cristy051718b2011-08-28 22:49:25 +000015039 windows->magnify.width,windows->magnify.height,exception);
cristy3ed852e2009-09-05 21:47:34 +000015040 if (status == MagickFalse)
15041 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15042 display_image->filename);
15043 if (windows->magnify.mapped != MagickFalse)
15044 (void) XMapRaised(display,windows->magnify.id);
15045 if (windows->pan.mapped != MagickFalse)
15046 (void) XMapRaised(display,windows->pan.id);
15047 windows->image.window_changes.width=(int) display_image->columns;
15048 windows->image.window_changes.height=(int) display_image->rows;
cristy051718b2011-08-28 22:49:25 +000015049 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015050 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15051 (void) XSync(display,MagickFalse);
15052 /*
15053 Respond to events.
15054 */
15055 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15056 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15057 update_time=0;
15058 if (resource_info->update != MagickFalse)
15059 {
15060 MagickBooleanType
15061 status;
15062
15063 /*
15064 Determine when file data was last modified.
15065 */
15066 status=GetPathAttributes(display_image->filename,&attributes);
15067 if (status != MagickFalse)
15068 update_time=attributes.st_mtime;
15069 }
15070 *state&=(~FormerImageState);
15071 *state&=(~MontageImageState);
15072 *state&=(~NextImageState);
15073 do
15074 {
15075 /*
15076 Handle a window event.
15077 */
15078 if (windows->image.mapped != MagickFalse)
15079 if ((display_image->delay != 0) || (resource_info->update != 0))
15080 {
15081 if (timer < time((time_t *) NULL))
15082 {
15083 if (resource_info->update == MagickFalse)
15084 *state|=NextImageState | ExitState;
15085 else
15086 {
15087 MagickBooleanType
15088 status;
15089
15090 /*
15091 Determine if image file was modified.
15092 */
15093 status=GetPathAttributes(display_image->filename,&attributes);
15094 if (status != MagickFalse)
15095 if (update_time != attributes.st_mtime)
15096 {
15097 /*
15098 Redisplay image.
15099 */
cristyb51dff52011-05-19 16:55:47 +000015100 (void) FormatLocaleString(
cristy3ed852e2009-09-05 21:47:34 +000015101 resource_info->image_info->filename,MaxTextExtent,
15102 "%s:%s",display_image->magick,
15103 display_image->filename);
15104 nexus=ReadImage(resource_info->image_info,
15105 &display_image->exception);
15106 if (nexus != (Image *) NULL)
15107 {
15108 nexus=DestroyImage(nexus);
15109 *state|=NextImageState | ExitState;
15110 }
15111 }
15112 delay=display_image->delay/MagickMax(
15113 display_image->ticks_per_second,1L);
15114 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15115 }
15116 }
15117 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15118 {
15119 /*
15120 Do not block if delay > 0.
15121 */
15122 XDelay(display,SuspendTime << 2);
15123 continue;
15124 }
15125 }
15126 timestamp=time((time_t *) NULL);
15127 (void) XNextEvent(display,&event);
15128 if (windows->image.stasis == MagickFalse)
15129 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15130 MagickTrue : MagickFalse;
15131 if (windows->magnify.stasis == MagickFalse)
15132 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15133 MagickTrue : MagickFalse;
15134 if (event.xany.window == windows->command.id)
15135 {
15136 /*
15137 Select a command from the Command widget.
15138 */
15139 id=XCommandWidget(display,windows,CommandMenu,&event);
15140 if (id < 0)
15141 continue;
15142 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15143 command_type=CommandMenus[id];
15144 if (id < MagickMenus)
15145 {
15146 /*
15147 Select a command from a pop-up menu.
15148 */
15149 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15150 command);
15151 if (entry < 0)
15152 continue;
15153 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15154 command_type=Commands[id][entry];
15155 }
15156 if (command_type != NullCommand)
15157 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015158 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015159 continue;
15160 }
15161 switch (event.type)
15162 {
15163 case ButtonPress:
15164 {
15165 if (display_image->debug != MagickFalse)
15166 (void) LogMagickEvent(X11Event,GetMagickModule(),
15167 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15168 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15169 if ((event.xbutton.button == Button3) &&
15170 (event.xbutton.state & Mod1Mask))
15171 {
15172 /*
15173 Convert Alt-Button3 to Button2.
15174 */
15175 event.xbutton.button=Button2;
15176 event.xbutton.state&=(~Mod1Mask);
15177 }
15178 if (event.xbutton.window == windows->backdrop.id)
15179 {
15180 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15181 event.xbutton.time);
15182 break;
15183 }
15184 if (event.xbutton.window == windows->image.id)
15185 {
15186 switch (event.xbutton.button)
15187 {
15188 case Button1:
15189 {
15190 if (resource_info->immutable)
15191 {
15192 /*
15193 Select a command from the Virtual menu.
15194 */
15195 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15196 command);
15197 if (entry >= 0)
15198 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015199 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015200 break;
15201 }
15202 /*
15203 Map/unmap Command widget.
15204 */
15205 if (windows->command.mapped != MagickFalse)
15206 (void) XWithdrawWindow(display,windows->command.id,
15207 windows->command.screen);
15208 else
15209 {
15210 (void) XCommandWidget(display,windows,CommandMenu,
15211 (XEvent *) NULL);
15212 (void) XMapRaised(display,windows->command.id);
15213 }
15214 break;
15215 }
15216 case Button2:
15217 {
15218 /*
15219 User pressed the image magnify button.
15220 */
15221 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
cristy051718b2011-08-28 22:49:25 +000015222 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015223 XMagnifyImage(display,windows,&event);
15224 break;
15225 }
15226 case Button3:
15227 {
15228 if (resource_info->immutable)
15229 {
15230 /*
15231 Select a command from the Virtual menu.
15232 */
15233 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15234 command);
15235 if (entry >= 0)
15236 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015237 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015238 break;
15239 }
15240 if (display_image->montage != (char *) NULL)
15241 {
15242 /*
15243 Open or delete a tile from a visual image directory.
15244 */
15245 nexus=XTileImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015246 display_image,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015247 if (nexus != (Image *) NULL)
15248 *state|=MontageImageState | NextImageState | ExitState;
cristy49e2d862010-11-12 02:50:30 +000015249 vid_info.x=(short int) windows->image.x;
15250 vid_info.y=(short int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +000015251 break;
15252 }
15253 /*
15254 Select a command from the Short Cuts menu.
15255 */
15256 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15257 command);
15258 if (entry >= 0)
15259 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015260 ShortCutsCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015261 break;
15262 }
15263 case Button4:
15264 {
15265 /*
15266 Wheel up.
15267 */
15268 XTranslateImage(display,windows,*image,XK_Up);
15269 break;
15270 }
15271 case Button5:
15272 {
15273 /*
15274 Wheel down.
15275 */
15276 XTranslateImage(display,windows,*image,XK_Down);
15277 break;
15278 }
15279 default:
15280 break;
15281 }
15282 break;
15283 }
15284 if (event.xbutton.window == windows->magnify.id)
15285 {
15286 int
15287 factor;
15288
15289 static const char
15290 *MagnifyMenu[] =
15291 {
15292 "2",
15293 "4",
15294 "5",
15295 "6",
15296 "7",
15297 "8",
15298 "9",
15299 "3",
15300 (char *) NULL,
15301 };
15302
15303 static KeySym
15304 MagnifyCommands[] =
15305 {
15306 XK_2,
15307 XK_4,
15308 XK_5,
15309 XK_6,
15310 XK_7,
15311 XK_8,
15312 XK_9,
15313 XK_3
15314 };
15315
15316 /*
15317 Select a magnify factor from the pop-up menu.
15318 */
15319 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15320 if (factor >= 0)
15321 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15322 break;
15323 }
15324 if (event.xbutton.window == windows->pan.id)
15325 {
15326 switch (event.xbutton.button)
15327 {
15328 case Button4:
15329 {
15330 /*
15331 Wheel up.
15332 */
15333 XTranslateImage(display,windows,*image,XK_Up);
15334 break;
15335 }
15336 case Button5:
15337 {
15338 /*
15339 Wheel down.
15340 */
15341 XTranslateImage(display,windows,*image,XK_Down);
15342 break;
15343 }
15344 default:
15345 {
15346 XPanImage(display,windows,&event);
15347 break;
15348 }
15349 }
15350 break;
15351 }
15352 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15353 1L);
15354 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15355 break;
15356 }
15357 case ButtonRelease:
15358 {
15359 if (display_image->debug != MagickFalse)
15360 (void) LogMagickEvent(X11Event,GetMagickModule(),
15361 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15362 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15363 break;
15364 }
15365 case ClientMessage:
15366 {
15367 if (display_image->debug != MagickFalse)
15368 (void) LogMagickEvent(X11Event,GetMagickModule(),
15369 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
cristyf2faecf2010-05-28 19:19:36 +000015370 event.xclient.message_type,event.xclient.format,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015371 event.xclient.data.l[0]);
15372 if (event.xclient.message_type == windows->im_protocols)
15373 {
cristyecd0ab52010-05-30 14:59:20 +000015374 if (*event.xclient.data.l == (long) windows->im_update_widget)
cristy3ed852e2009-09-05 21:47:34 +000015375 {
15376 (void) CloneString(&windows->command.name,MagickTitle);
15377 windows->command.data=MagickMenus;
15378 (void) XCommandWidget(display,windows,CommandMenu,
15379 (XEvent *) NULL);
15380 break;
15381 }
cristyecd0ab52010-05-30 14:59:20 +000015382 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +000015383 {
15384 /*
15385 Update graphic context and window colormap.
15386 */
15387 for (i=0; i < (int) number_windows; i++)
15388 {
15389 if (magick_windows[i]->id == windows->icon.id)
15390 continue;
15391 context_values.background=pixel->background_color.pixel;
15392 context_values.foreground=pixel->foreground_color.pixel;
15393 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15394 context_mask,&context_values);
15395 (void) XChangeGC(display,magick_windows[i]->widget_context,
15396 context_mask,&context_values);
15397 context_values.background=pixel->foreground_color.pixel;
15398 context_values.foreground=pixel->background_color.pixel;
15399 context_values.plane_mask=context_values.background ^
15400 context_values.foreground;
15401 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +000015402 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +000015403 &context_values);
15404 magick_windows[i]->attributes.background_pixel=
15405 pixel->background_color.pixel;
15406 magick_windows[i]->attributes.border_pixel=
15407 pixel->border_color.pixel;
15408 magick_windows[i]->attributes.colormap=map_info->colormap;
15409 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
cristy49e2d862010-11-12 02:50:30 +000015410 (unsigned long) magick_windows[i]->mask,
15411 &magick_windows[i]->attributes);
cristy3ed852e2009-09-05 21:47:34 +000015412 }
15413 if (windows->pan.mapped != MagickFalse)
15414 {
15415 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15416 windows->pan.pixmap);
15417 (void) XClearWindow(display,windows->pan.id);
15418 XDrawPanRectangle(display,windows);
15419 }
15420 if (windows->backdrop.id != (Window) NULL)
15421 (void) XInstallColormap(display,map_info->colormap);
15422 break;
15423 }
cristyecd0ab52010-05-30 14:59:20 +000015424 if (*event.xclient.data.l == (long) windows->im_former_image)
cristy3ed852e2009-09-05 21:47:34 +000015425 {
15426 *state|=FormerImageState | ExitState;
15427 break;
15428 }
cristyecd0ab52010-05-30 14:59:20 +000015429 if (*event.xclient.data.l == (long) windows->im_next_image)
cristy3ed852e2009-09-05 21:47:34 +000015430 {
15431 *state|=NextImageState | ExitState;
15432 break;
15433 }
cristyecd0ab52010-05-30 14:59:20 +000015434 if (*event.xclient.data.l == (long) windows->im_retain_colors)
cristy3ed852e2009-09-05 21:47:34 +000015435 {
15436 *state|=RetainColorsState;
15437 break;
15438 }
cristyecd0ab52010-05-30 14:59:20 +000015439 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +000015440 {
15441 *state|=ExitState;
15442 break;
15443 }
15444 break;
15445 }
15446 if (event.xclient.message_type == windows->dnd_protocols)
15447 {
15448 Atom
15449 selection,
15450 type;
15451
15452 int
15453 format,
15454 status;
15455
15456 unsigned char
15457 *data;
15458
cristyf2faecf2010-05-28 19:19:36 +000015459 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015460 after,
15461 length;
15462
15463 /*
15464 Display image named by the Drag-and-Drop selection.
15465 */
15466 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15467 break;
15468 selection=XInternAtom(display,"DndSelection",MagickFalse);
cristyecd0ab52010-05-30 14:59:20 +000015469 status=XGetWindowProperty(display,root_window,selection,0L,(long)
cristy3ed852e2009-09-05 21:47:34 +000015470 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15471 &length,&after,&data);
15472 if ((status != Success) || (length == 0))
15473 break;
15474 if (*event.xclient.data.l == 2)
15475 {
15476 /*
15477 Offix DND.
15478 */
15479 (void) CopyMagickString(resource_info->image_info->filename,
15480 (char *) data,MaxTextExtent);
15481 }
15482 else
15483 {
15484 /*
15485 XDND.
15486 */
15487 if (strncmp((char *) data, "file:", 5) != 0)
15488 {
15489 (void) XFree((void *) data);
15490 break;
15491 }
15492 (void) CopyMagickString(resource_info->image_info->filename,
15493 ((char *) data)+5,MaxTextExtent);
15494 }
15495 nexus=ReadImage(resource_info->image_info,
15496 &display_image->exception);
15497 CatchException(&display_image->exception);
15498 if (nexus != (Image *) NULL)
15499 *state|=NextImageState | ExitState;
15500 (void) XFree((void *) data);
15501 break;
15502 }
15503 /*
15504 If client window delete message, exit.
15505 */
15506 if (event.xclient.message_type != windows->wm_protocols)
15507 break;
cristyecd0ab52010-05-30 14:59:20 +000015508 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000015509 break;
15510 (void) XWithdrawWindow(display,event.xclient.window,
15511 visual_info->screen);
15512 if (event.xclient.window == windows->image.id)
15513 {
15514 *state|=ExitState;
15515 break;
15516 }
15517 if (event.xclient.window == windows->pan.id)
15518 {
15519 /*
15520 Restore original image size when pan window is deleted.
15521 */
15522 windows->image.window_changes.width=windows->image.ximage->width;
15523 windows->image.window_changes.height=windows->image.ximage->height;
15524 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015525 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015526 }
15527 break;
15528 }
15529 case ConfigureNotify:
15530 {
15531 if (display_image->debug != MagickFalse)
15532 (void) LogMagickEvent(X11Event,GetMagickModule(),
15533 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15534 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15535 event.xconfigure.y,event.xconfigure.send_event);
15536 if (event.xconfigure.window == windows->image.id)
15537 {
15538 /*
15539 Image window has a new configuration.
15540 */
15541 if (event.xconfigure.send_event != 0)
15542 {
15543 XWindowChanges
15544 window_changes;
15545
15546 /*
15547 Position the transient windows relative of the Image window.
15548 */
15549 if (windows->command.geometry == (char *) NULL)
15550 if (windows->command.mapped == MagickFalse)
15551 {
15552 windows->command.x=event.xconfigure.x-
15553 windows->command.width-25;
15554 windows->command.y=event.xconfigure.y;
15555 XConstrainWindowPosition(display,&windows->command);
15556 window_changes.x=windows->command.x;
15557 window_changes.y=windows->command.y;
15558 (void) XReconfigureWMWindow(display,windows->command.id,
15559 windows->command.screen,(unsigned int) (CWX | CWY),
15560 &window_changes);
15561 }
15562 if (windows->widget.geometry == (char *) NULL)
15563 if (windows->widget.mapped == MagickFalse)
15564 {
15565 windows->widget.x=event.xconfigure.x+
15566 event.xconfigure.width/10;
15567 windows->widget.y=event.xconfigure.y+
15568 event.xconfigure.height/10;
15569 XConstrainWindowPosition(display,&windows->widget);
15570 window_changes.x=windows->widget.x;
15571 window_changes.y=windows->widget.y;
15572 (void) XReconfigureWMWindow(display,windows->widget.id,
15573 windows->widget.screen,(unsigned int) (CWX | CWY),
15574 &window_changes);
15575 }
15576 if (windows->magnify.geometry == (char *) NULL)
15577 if (windows->magnify.mapped == MagickFalse)
15578 {
15579 windows->magnify.x=event.xconfigure.x+
15580 event.xconfigure.width+25;
15581 windows->magnify.y=event.xconfigure.y;
15582 XConstrainWindowPosition(display,&windows->magnify);
15583 window_changes.x=windows->magnify.x;
15584 window_changes.y=windows->magnify.y;
15585 (void) XReconfigureWMWindow(display,windows->magnify.id,
15586 windows->magnify.screen,(unsigned int) (CWX | CWY),
15587 &window_changes);
15588 }
15589 if (windows->pan.geometry == (char *) NULL)
15590 if (windows->pan.mapped == MagickFalse)
15591 {
15592 windows->pan.x=event.xconfigure.x+
15593 event.xconfigure.width+25;
15594 windows->pan.y=event.xconfigure.y+
15595 windows->magnify.height+50;
15596 XConstrainWindowPosition(display,&windows->pan);
15597 window_changes.x=windows->pan.x;
15598 window_changes.y=windows->pan.y;
15599 (void) XReconfigureWMWindow(display,windows->pan.id,
15600 windows->pan.screen,(unsigned int) (CWX | CWY),
15601 &window_changes);
15602 }
15603 }
cristyecd0ab52010-05-30 14:59:20 +000015604 if ((event.xconfigure.width == (int) windows->image.width) &&
15605 (event.xconfigure.height == (int) windows->image.height))
cristy3ed852e2009-09-05 21:47:34 +000015606 break;
15607 windows->image.width=(unsigned int) event.xconfigure.width;
15608 windows->image.height=(unsigned int) event.xconfigure.height;
15609 windows->image.x=0;
15610 windows->image.y=0;
15611 if (display_image->montage != (char *) NULL)
15612 {
15613 windows->image.x=vid_info.x;
15614 windows->image.y=vid_info.y;
15615 }
cristy34b9f452010-01-06 20:04:29 +000015616 if ((windows->image.mapped != MagickFalse) &&
15617 (windows->image.stasis != MagickFalse))
15618 {
15619 /*
15620 Update image window configuration.
15621 */
15622 windows->image.window_changes.width=event.xconfigure.width;
15623 windows->image.window_changes.height=event.xconfigure.height;
15624 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015625 display_image,exception);
cristy34b9f452010-01-06 20:04:29 +000015626 }
cristy3ed852e2009-09-05 21:47:34 +000015627 /*
15628 Update pan window configuration.
15629 */
15630 if ((event.xconfigure.width < windows->image.ximage->width) ||
15631 (event.xconfigure.height < windows->image.ximage->height))
15632 {
15633 (void) XMapRaised(display,windows->pan.id);
15634 XDrawPanRectangle(display,windows);
15635 }
15636 else
15637 if (windows->pan.mapped != MagickFalse)
15638 (void) XWithdrawWindow(display,windows->pan.id,
15639 windows->pan.screen);
15640 break;
15641 }
15642 if (event.xconfigure.window == windows->magnify.id)
15643 {
15644 unsigned int
15645 magnify;
15646
15647 /*
15648 Magnify window has a new configuration.
15649 */
15650 windows->magnify.width=(unsigned int) event.xconfigure.width;
15651 windows->magnify.height=(unsigned int) event.xconfigure.height;
15652 if (windows->magnify.mapped == MagickFalse)
15653 break;
15654 magnify=1;
15655 while ((int) magnify <= event.xconfigure.width)
15656 magnify<<=1;
15657 while ((int) magnify <= event.xconfigure.height)
15658 magnify<<=1;
15659 magnify>>=1;
15660 if (((int) magnify != event.xconfigure.width) ||
15661 ((int) magnify != event.xconfigure.height))
15662 {
15663 window_changes.width=(int) magnify;
15664 window_changes.height=(int) magnify;
15665 (void) XReconfigureWMWindow(display,windows->magnify.id,
15666 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15667 &window_changes);
15668 break;
15669 }
15670 if ((windows->magnify.mapped != MagickFalse) &&
15671 (windows->magnify.stasis != MagickFalse))
15672 {
15673 status=XMakeImage(display,resource_info,&windows->magnify,
cristy051718b2011-08-28 22:49:25 +000015674 display_image,windows->magnify.width,windows->magnify.height,
15675 exception);
cristy3ed852e2009-09-05 21:47:34 +000015676 XMakeMagnifyImage(display,windows);
15677 }
15678 break;
15679 }
15680 if ((windows->magnify.mapped != MagickFalse) &&
15681 (event.xconfigure.window == windows->pan.id))
15682 {
15683 /*
15684 Pan icon window has a new configuration.
15685 */
15686 if (event.xconfigure.send_event != 0)
15687 {
15688 windows->pan.x=event.xconfigure.x;
15689 windows->pan.y=event.xconfigure.y;
15690 }
15691 windows->pan.width=(unsigned int) event.xconfigure.width;
15692 windows->pan.height=(unsigned int) event.xconfigure.height;
15693 break;
15694 }
15695 if (event.xconfigure.window == windows->icon.id)
15696 {
15697 /*
15698 Icon window has a new configuration.
15699 */
15700 windows->icon.width=(unsigned int) event.xconfigure.width;
15701 windows->icon.height=(unsigned int) event.xconfigure.height;
15702 break;
15703 }
15704 break;
15705 }
15706 case DestroyNotify:
15707 {
15708 /*
15709 Group leader has exited.
15710 */
15711 if (display_image->debug != MagickFalse)
15712 (void) LogMagickEvent(X11Event,GetMagickModule(),
15713 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15714 if (event.xdestroywindow.window == windows->group_leader.id)
15715 {
15716 *state|=ExitState;
15717 break;
15718 }
15719 break;
15720 }
15721 case EnterNotify:
15722 {
15723 /*
15724 Selectively install colormap.
15725 */
15726 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15727 if (event.xcrossing.mode != NotifyUngrab)
15728 XInstallColormap(display,map_info->colormap);
15729 break;
15730 }
15731 case Expose:
15732 {
15733 if (display_image->debug != MagickFalse)
15734 (void) LogMagickEvent(X11Event,GetMagickModule(),
15735 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15736 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15737 event.xexpose.y);
15738 /*
15739 Refresh windows that are now exposed.
15740 */
cristy6bee4042010-01-30 15:27:14 +000015741 if ((event.xexpose.window == windows->image.id) &&
15742 (windows->image.mapped != MagickFalse))
15743 {
15744 XRefreshWindow(display,&windows->image,&event);
15745 delay=display_image->delay/MagickMax(
15746 display_image->ticks_per_second,1L);
15747 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15748 break;
15749 }
15750 if ((event.xexpose.window == windows->magnify.id) &&
15751 (windows->magnify.mapped != MagickFalse))
15752 {
15753 XMakeMagnifyImage(display,windows);
15754 break;
15755 }
cristy3ed852e2009-09-05 21:47:34 +000015756 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015757 {
15758 XDrawPanRectangle(display,windows);
15759 break;
15760 }
cristy3ed852e2009-09-05 21:47:34 +000015761 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015762 {
15763 XRefreshWindow(display,&windows->icon,&event);
15764 break;
15765 }
cristy3ed852e2009-09-05 21:47:34 +000015766 break;
15767 }
15768 case KeyPress:
15769 {
15770 int
15771 length;
15772
15773 /*
15774 Respond to a user key press.
15775 */
15776 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15777 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15778 *(command+length)='\0';
15779 if (display_image->debug != MagickFalse)
15780 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015781 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015782 key_symbol,command);
15783 if (event.xkey.window == windows->image.id)
15784 {
15785 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015786 event.xkey.state,key_symbol,&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015787 if (command_type != NullCommand)
15788 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015789 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015790 }
15791 if (event.xkey.window == windows->magnify.id)
15792 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15793 if (event.xkey.window == windows->pan.id)
15794 {
15795 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15796 (void) XWithdrawWindow(display,windows->pan.id,
15797 windows->pan.screen);
15798 else
15799 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15800 XTextViewWidget(display,resource_info,windows,MagickFalse,
15801 "Help Viewer - Image Pan",ImagePanHelp);
15802 else
15803 XTranslateImage(display,windows,*image,key_symbol);
15804 }
15805 delay=display_image->delay/MagickMax(
15806 display_image->ticks_per_second,1L);
15807 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15808 break;
15809 }
15810 case KeyRelease:
15811 {
15812 /*
15813 Respond to a user key release.
15814 */
15815 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15816 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15817 if (display_image->debug != MagickFalse)
15818 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015819 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +000015820 break;
15821 }
15822 case LeaveNotify:
15823 {
15824 /*
15825 Selectively uninstall colormap.
15826 */
15827 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15828 if (event.xcrossing.mode != NotifyUngrab)
15829 XUninstallColormap(display,map_info->colormap);
15830 break;
15831 }
15832 case MapNotify:
15833 {
15834 if (display_image->debug != MagickFalse)
15835 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15836 event.xmap.window);
15837 if (event.xmap.window == windows->backdrop.id)
15838 {
15839 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15840 CurrentTime);
15841 windows->backdrop.mapped=MagickTrue;
15842 break;
15843 }
15844 if (event.xmap.window == windows->image.id)
15845 {
15846 if (windows->backdrop.id != (Window) NULL)
15847 (void) XInstallColormap(display,map_info->colormap);
15848 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15849 {
15850 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15851 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15852 }
15853 if (((int) windows->image.width < windows->image.ximage->width) ||
15854 ((int) windows->image.height < windows->image.ximage->height))
15855 (void) XMapRaised(display,windows->pan.id);
15856 windows->image.mapped=MagickTrue;
15857 break;
15858 }
15859 if (event.xmap.window == windows->magnify.id)
15860 {
15861 XMakeMagnifyImage(display,windows);
15862 windows->magnify.mapped=MagickTrue;
15863 (void) XWithdrawWindow(display,windows->info.id,
15864 windows->info.screen);
15865 break;
15866 }
15867 if (event.xmap.window == windows->pan.id)
15868 {
cristy051718b2011-08-28 22:49:25 +000015869 XMakePanImage(display,resource_info,windows,display_image,
15870 exception);
cristy3ed852e2009-09-05 21:47:34 +000015871 windows->pan.mapped=MagickTrue;
15872 break;
15873 }
15874 if (event.xmap.window == windows->info.id)
15875 {
15876 windows->info.mapped=MagickTrue;
15877 break;
15878 }
15879 if (event.xmap.window == windows->icon.id)
15880 {
15881 MagickBooleanType
15882 taint;
15883
15884 /*
15885 Create an icon image.
15886 */
15887 taint=display_image->taint;
15888 XMakeStandardColormap(display,icon_visual,icon_resources,
15889 display_image,icon_map,icon_pixel);
15890 (void) XMakeImage(display,icon_resources,&windows->icon,
cristy051718b2011-08-28 22:49:25 +000015891 display_image,windows->icon.width,windows->icon.height,
15892 exception);
cristy3ed852e2009-09-05 21:47:34 +000015893 display_image->taint=taint;
15894 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15895 windows->icon.pixmap);
15896 (void) XClearWindow(display,windows->icon.id);
15897 (void) XWithdrawWindow(display,windows->info.id,
15898 windows->info.screen);
15899 windows->icon.mapped=MagickTrue;
15900 break;
15901 }
15902 if (event.xmap.window == windows->command.id)
15903 {
15904 windows->command.mapped=MagickTrue;
15905 break;
15906 }
15907 if (event.xmap.window == windows->popup.id)
15908 {
15909 windows->popup.mapped=MagickTrue;
15910 break;
15911 }
15912 if (event.xmap.window == windows->widget.id)
15913 {
15914 windows->widget.mapped=MagickTrue;
15915 break;
15916 }
15917 break;
15918 }
15919 case MappingNotify:
15920 {
15921 (void) XRefreshKeyboardMapping(&event.xmapping);
15922 break;
15923 }
15924 case NoExpose:
15925 break;
15926 case PropertyNotify:
15927 {
15928 Atom
15929 type;
15930
15931 int
15932 format,
15933 status;
15934
15935 unsigned char
15936 *data;
15937
cristyf2faecf2010-05-28 19:19:36 +000015938 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015939 after,
15940 length;
15941
15942 if (display_image->debug != MagickFalse)
15943 (void) LogMagickEvent(X11Event,GetMagickModule(),
15944 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15945 event.xproperty.atom,event.xproperty.state);
15946 if (event.xproperty.atom != windows->im_remote_command)
15947 break;
15948 /*
15949 Display image named by the remote command protocol.
15950 */
15951 status=XGetWindowProperty(display,event.xproperty.window,
cristyecd0ab52010-05-30 14:59:20 +000015952 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +000015953 AnyPropertyType,&type,&format,&length,&after,&data);
15954 if ((status != Success) || (length == 0))
15955 break;
15956 if (LocaleCompare((char *) data,"-quit") == 0)
15957 {
15958 XClientMessage(display,windows->image.id,windows->im_protocols,
15959 windows->im_exit,CurrentTime);
15960 (void) XFree((void *) data);
15961 break;
15962 }
15963 (void) CopyMagickString(resource_info->image_info->filename,
15964 (char *) data,MaxTextExtent);
15965 (void) XFree((void *) data);
15966 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15967 CatchException(&display_image->exception);
15968 if (nexus != (Image *) NULL)
15969 *state|=NextImageState | ExitState;
15970 break;
15971 }
15972 case ReparentNotify:
15973 {
15974 if (display_image->debug != MagickFalse)
15975 (void) LogMagickEvent(X11Event,GetMagickModule(),
15976 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15977 event.xreparent.window);
15978 break;
15979 }
15980 case UnmapNotify:
15981 {
15982 if (display_image->debug != MagickFalse)
15983 (void) LogMagickEvent(X11Event,GetMagickModule(),
15984 "Unmap Notify: 0x%lx",event.xunmap.window);
15985 if (event.xunmap.window == windows->backdrop.id)
15986 {
15987 windows->backdrop.mapped=MagickFalse;
15988 break;
15989 }
15990 if (event.xunmap.window == windows->image.id)
15991 {
15992 windows->image.mapped=MagickFalse;
15993 break;
15994 }
15995 if (event.xunmap.window == windows->magnify.id)
15996 {
15997 windows->magnify.mapped=MagickFalse;
15998 break;
15999 }
16000 if (event.xunmap.window == windows->pan.id)
16001 {
16002 windows->pan.mapped=MagickFalse;
16003 break;
16004 }
16005 if (event.xunmap.window == windows->info.id)
16006 {
16007 windows->info.mapped=MagickFalse;
16008 break;
16009 }
16010 if (event.xunmap.window == windows->icon.id)
16011 {
16012 if (map_info->colormap == icon_map->colormap)
16013 XConfigureImageColormap(display,resource_info,windows,
16014 display_image);
16015 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16016 icon_pixel);
16017 windows->icon.mapped=MagickFalse;
16018 break;
16019 }
16020 if (event.xunmap.window == windows->command.id)
16021 {
16022 windows->command.mapped=MagickFalse;
16023 break;
16024 }
16025 if (event.xunmap.window == windows->popup.id)
16026 {
16027 if (windows->backdrop.id != (Window) NULL)
16028 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16029 CurrentTime);
16030 windows->popup.mapped=MagickFalse;
16031 break;
16032 }
16033 if (event.xunmap.window == windows->widget.id)
16034 {
16035 if (windows->backdrop.id != (Window) NULL)
16036 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16037 CurrentTime);
16038 windows->widget.mapped=MagickFalse;
16039 break;
16040 }
16041 break;
16042 }
16043 default:
16044 {
16045 if (display_image->debug != MagickFalse)
16046 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16047 event.type);
16048 break;
16049 }
16050 }
16051 } while (!(*state & ExitState));
16052 if ((*state & ExitState) == 0)
16053 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
cristy051718b2011-08-28 22:49:25 +000016054 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016055 else
16056 if (resource_info->confirm_edit != MagickFalse)
16057 {
16058 /*
16059 Query user if image has changed.
16060 */
16061 if ((resource_info->immutable == MagickFalse) &&
16062 (display_image->taint != MagickFalse))
16063 {
16064 int
16065 status;
16066
16067 status=XConfirmWidget(display,windows,"Your image changed.",
16068 "Do you want to save it");
16069 if (status == 0)
16070 *state&=(~ExitState);
16071 else
16072 if (status > 0)
16073 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
cristy051718b2011-08-28 22:49:25 +000016074 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016075 }
16076 }
16077 if ((windows->visual_info->klass == GrayScale) ||
16078 (windows->visual_info->klass == PseudoColor) ||
16079 (windows->visual_info->klass == DirectColor))
16080 {
16081 /*
16082 Withdraw pan and Magnify window.
16083 */
16084 if (windows->info.mapped != MagickFalse)
16085 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16086 if (windows->magnify.mapped != MagickFalse)
16087 (void) XWithdrawWindow(display,windows->magnify.id,
16088 windows->magnify.screen);
16089 if (windows->command.mapped != MagickFalse)
16090 (void) XWithdrawWindow(display,windows->command.id,
16091 windows->command.screen);
16092 }
16093 if (windows->pan.mapped != MagickFalse)
16094 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16095 if (resource_info->backdrop == MagickFalse)
16096 if (windows->backdrop.mapped)
16097 {
16098 (void) XWithdrawWindow(display,windows->backdrop.id,
16099 windows->backdrop.screen);
16100 (void) XDestroyWindow(display,windows->backdrop.id);
16101 windows->backdrop.id=(Window) NULL;
16102 (void) XWithdrawWindow(display,windows->image.id,
16103 windows->image.screen);
16104 (void) XDestroyWindow(display,windows->image.id);
16105 windows->image.id=(Window) NULL;
16106 }
16107 XSetCursorState(display,windows,MagickTrue);
16108 XCheckRefreshWindows(display,windows);
16109 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16110 *state&=(~ExitState);
16111 if (*state & ExitState)
16112 {
16113 /*
16114 Free Standard Colormap.
16115 */
16116 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16117 if (resource_info->map_type == (char *) NULL)
16118 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16119 /*
16120 Free X resources.
16121 */
16122 if (resource_info->copy_image != (Image *) NULL)
16123 {
16124 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16125 resource_info->copy_image=NewImageList();
16126 }
16127 DestroyXResources();
16128 }
16129 (void) XSync(display,MagickFalse);
16130 /*
16131 Restore our progress monitor and warning handlers.
16132 */
16133 (void) SetErrorHandler(warning_handler);
16134 (void) SetWarningHandler(warning_handler);
16135 /*
16136 Change to home directory.
16137 */
cristy00976d82011-02-20 20:31:28 +000016138 directory=getcwd(working_directory,MaxTextExtent);
16139 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +000016140 {
16141 int
16142 status;
16143
16144 status=chdir(resource_info->home_directory);
16145 if (status == -1)
16146 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
16147 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
16148 }
16149 *image=display_image;
16150 return(nexus);
16151}
16152#else
16153
16154/*
16155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16156% %
16157% %
16158% %
16159+ D i s p l a y I m a g e s %
16160% %
16161% %
16162% %
16163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16164%
16165% DisplayImages() displays an image sequence to any X window screen. It
16166% returns a value other than 0 if successful. Check the exception member
16167% of image to determine the reason for any failure.
16168%
16169% The format of the DisplayImages method is:
16170%
16171% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016172% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016173%
16174% A description of each parameter follows:
16175%
16176% o image_info: the image info.
16177%
16178% o image: the image.
16179%
cristy051718b2011-08-28 22:49:25 +000016180% o exception: return any errors or warnings in this structure.
16181%
cristy3ed852e2009-09-05 21:47:34 +000016182*/
16183MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016184 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016185{
16186 assert(image_info != (const ImageInfo *) NULL);
16187 assert(image_info->signature == MagickSignature);
16188 assert(image != (Image *) NULL);
16189 assert(image->signature == MagickSignature);
16190 if (image->debug != MagickFalse)
16191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy051718b2011-08-28 22:49:25 +000016192 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16193 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename);
cristy3ed852e2009-09-05 21:47:34 +000016194 return(MagickFalse);
16195}
16196
16197/*
16198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16199% %
16200% %
16201% %
16202+ R e m o t e D i s p l a y C o m m a n d %
16203% %
16204% %
16205% %
16206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16207%
16208% RemoteDisplayCommand() encourages a remote display program to display the
16209% specified image filename.
16210%
16211% The format of the RemoteDisplayCommand method is:
16212%
16213% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16214% const char *window,const char *filename,ExceptionInfo *exception)
16215%
16216% A description of each parameter follows:
16217%
16218% o image_info: the image info.
16219%
16220% o window: Specifies the name or id of an X window.
16221%
16222% o filename: the name of the image filename to display.
16223%
16224% o exception: return any errors or warnings in this structure.
16225%
16226*/
16227MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16228 const char *window,const char *filename,ExceptionInfo *exception)
16229{
16230 assert(image_info != (const ImageInfo *) NULL);
16231 assert(image_info->signature == MagickSignature);
16232 assert(filename != (char *) NULL);
16233 (void) window;
16234 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16235 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16236 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16237 return(MagickFalse);
16238}
16239#endif