blob: 4498c2899db19bb628aa5e03cb2a0ce2dfdb255f [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% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 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*/
42#include "magick/studio.h"
43#include "magick/artifact.h"
44#include "magick/blob.h"
45#include "magick/cache.h"
46#include "magick/client.h"
47#include "magick/color.h"
48#include "magick/colorspace.h"
49#include "magick/composite.h"
50#include "magick/constitute.h"
51#include "magick/decorate.h"
52#include "magick/delegate.h"
53#include "magick/display.h"
54#include "magick/display-private.h"
55#include "magick/draw.h"
56#include "magick/effect.h"
57#include "magick/enhance.h"
58#include "magick/exception.h"
59#include "magick/exception-private.h"
60#include "magick/fx.h"
61#include "magick/geometry.h"
62#include "magick/image.h"
63#include "magick/image-private.h"
64#include "magick/list.h"
65#include "magick/log.h"
66#include "magick/magick.h"
67#include "magick/memory_.h"
68#include "magick/monitor.h"
69#include "magick/monitor-private.h"
70#include "magick/montage.h"
71#include "magick/option.h"
72#include "magick/paint.h"
73#include "magick/pixel.h"
74#include "magick/pixel-private.h"
75#include "magick/PreRvIcccm.h"
76#include "magick/property.h"
77#include "magick/quantum.h"
78#include "magick/resize.h"
79#include "magick/resource_.h"
80#include "magick/shear.h"
81#include "magick/segment.h"
82#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000083#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000084#include "magick/transform.h"
85#include "magick/threshold.h"
86#include "magick/utility.h"
87#include "magick/version.h"
88#include "magick/widget.h"
89#include "magick/xwindow-private.h"
90
91#if defined(MAGICKCORE_X11_DELEGATE)
92/*
93 Define declarations.
94*/
95#define MaxColors MagickMin(windows->visual_info->colormap_size,256L)
96
97/*
98 Constant declarations.
99*/
100static const unsigned char
101 HighlightBitmap[8] =
102 {
103 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
104 },
105 ShadowBitmap[8] =
106 {
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
108 };
109
110static const char
111 *PageSizes[] =
112 {
113 "Letter",
114 "Tabloid",
115 "Ledger",
116 "Legal",
117 "Statement",
118 "Executive",
119 "A3",
120 "A4",
121 "A5",
122 "B4",
123 "B5",
124 "Folio",
125 "Quarto",
126 "10x14",
127 (char *) NULL
128 };
129
130/*
131 Help widget declarations.
132*/
133static const char
134 *ImageAnnotateHelp[] =
135 {
136 "In annotate mode, the Command widget has these options:",
137 "",
138 " Font Name",
139 " fixed",
140 " variable",
141 " 5x8",
142 " 6x10",
143 " 7x13bold",
144 " 8x13bold",
145 " 9x15bold",
146 " 10x20",
147 " 12x24",
148 " Browser...",
149 " Font Color",
150 " black",
151 " blue",
152 " cyan",
153 " green",
154 " gray",
155 " red",
156 " magenta",
157 " yellow",
158 " white",
159 " transparent",
160 " Browser...",
161 " Font Color",
162 " black",
163 " blue",
164 " cyan",
165 " green",
166 " gray",
167 " red",
168 " magenta",
169 " yellow",
170 " white",
171 " transparent",
172 " Browser...",
173 " Rotate Text",
174 " -90",
175 " -45",
176 " -30",
177 " 0",
178 " 30",
179 " 45",
180 " 90",
181 " 180",
182 " Dialog...",
183 " Help",
184 " Dismiss",
185 "",
186 "Choose a font name from the Font Name sub-menu. Additional",
187 "font names can be specified with the font browser. You can",
188 "change the menu names by setting the X resources font1",
189 "through font9.",
190 "",
191 "Choose a font color from the Font Color sub-menu.",
192 "Additional font colors can be specified with the color",
193 "browser. You can change the menu colors by setting the X",
194 "resources pen1 through pen9.",
195 "",
196 "If you select the color browser and press Grab, you can",
197 "choose the font color by moving the pointer to the desired",
198 "color on the screen and press any button.",
199 "",
200 "If you choose to rotate the text, choose Rotate Text from the",
201 "menu and select an angle. Typically you will only want to",
202 "rotate one line of text at a time. Depending on the angle you",
203 "choose, subsequent lines may end up overwriting each other.",
204 "",
205 "Choosing a font and its color is optional. The default font",
206 "is fixed and the default color is black. However, you must",
207 "choose a location to begin entering text and press button 1.",
208 "An underscore character will appear at the location of the",
209 "pointer. The cursor changes to a pencil to indicate you are",
210 "in text mode. To exit immediately, press Dismiss.",
211 "",
212 "In text mode, any key presses will display the character at",
213 "the location of the underscore and advance the underscore",
214 "cursor. Enter your text and once completed press Apply to",
215 "finish your image annotation. To correct errors press BACK",
216 "SPACE. To delete an entire line of text, press DELETE. Any",
217 "text that exceeds the boundaries of the image window is",
218 "automagically continued onto the next line.",
219 "",
220 "The actual color you request for the font is saved in the",
221 "image. However, the color that appears in your image window",
222 "may be different. For example, on a monochrome screen the",
223 "text will appear black or white even if you choose the color",
224 "red as the font color. However, the image saved to a file",
225 "with -write is written with red lettering. To assure the",
226 "correct color text in the final image, any PseudoClass image",
227 "is promoted to DirectClass (see miff(5)). To force a",
228 "PseudoClass image to remain PseudoClass, use -colors.",
229 (char *) NULL,
230 },
231 *ImageChopHelp[] =
232 {
233 "In chop mode, the Command widget has these options:",
234 "",
235 " Direction",
236 " horizontal",
237 " vertical",
238 " Help",
239 " Dismiss",
240 "",
241 "If the you choose the horizontal direction (this the",
242 "default), the area of the image between the two horizontal",
243 "endpoints of the chop line is removed. Otherwise, the area",
244 "of the image between the two vertical endpoints of the chop",
245 "line is removed.",
246 "",
247 "Select a location within the image window to begin your chop,",
248 "press and hold any button. Next, move the pointer to",
249 "another location in the image. As you move a line will",
250 "connect the initial location and the pointer. When you",
251 "release the button, the area within the image to chop is",
252 "determined by which direction you choose from the Command",
253 "widget.",
254 "",
255 "To cancel the image chopping, move the pointer back to the",
256 "starting point of the line and release the button.",
257 (char *) NULL,
258 },
259 *ImageColorEditHelp[] =
260 {
261 "In color edit mode, the Command widget has these options:",
262 "",
263 " Method",
264 " point",
265 " replace",
266 " floodfill",
267 " filltoborder",
268 " reset",
269 " Pixel Color",
270 " black",
271 " blue",
272 " cyan",
273 " green",
274 " gray",
275 " red",
276 " magenta",
277 " yellow",
278 " white",
279 " Browser...",
280 " Border Color",
281 " black",
282 " blue",
283 " cyan",
284 " green",
285 " gray",
286 " red",
287 " magenta",
288 " yellow",
289 " white",
290 " Browser...",
291 " Fuzz",
292 " 0%",
293 " 2%",
294 " 5%",
295 " 10%",
296 " 15%",
297 " Dialog...",
298 " Undo",
299 " Help",
300 " Dismiss",
301 "",
302 "Choose a color editing method from the Method sub-menu",
303 "of the Command widget. The point method recolors any pixel",
304 "selected with the pointer until the button is released. The",
305 "replace method recolors any pixel that matches the color of",
306 "the pixel you select with a button press. Floodfill recolors",
307 "any pixel that matches the color of the pixel you select with",
308 "a button press and is a neighbor. Whereas filltoborder recolors",
309 "any neighbor pixel that is not the border color. Finally reset",
310 "changes the entire image to the designated color.",
311 "",
312 "Next, choose a pixel color from the Pixel Color sub-menu.",
313 "Additional pixel colors can be specified with the color",
314 "browser. You can change the menu colors by setting the X",
315 "resources pen1 through pen9.",
316 "",
317 "Now press button 1 to select a pixel within the image window",
318 "to change its color. Additional pixels may be recolored as",
319 "prescribed by the method you choose.",
320 "",
321 "If the Magnify widget is mapped, it can be helpful in positioning",
322 "your pointer within the image (refer to button 2).",
323 "",
324 "The actual color you request for the pixels is saved in the",
325 "image. However, the color that appears in your image window",
326 "may be different. For example, on a monochrome screen the",
327 "pixel will appear black or white even if you choose the",
328 "color red as the pixel color. However, the image saved to a",
329 "file with -write is written with red pixels. To assure the",
330 "correct color text in the final image, any PseudoClass image",
331 "is promoted to DirectClass (see miff(5)). To force a",
332 "PseudoClass image to remain PseudoClass, use -colors.",
333 (char *) NULL,
334 },
335 *ImageCompositeHelp[] =
336 {
337 "First a widget window is displayed requesting you to enter an",
338 "image name. Press Composite, Grab or type a file name.",
339 "Press Cancel if you choose not to create a composite image.",
340 "When you choose Grab, move the pointer to the desired window",
341 "and press any button.",
342 "",
343 "If the Composite image does not have any matte information,",
344 "you are informed and the file browser is displayed again.",
345 "Enter the name of a mask image. The image is typically",
346 "grayscale and the same size as the composite image. If the",
347 "image is not grayscale, it is converted to grayscale and the",
348 "resulting intensities are used as matte information.",
349 "",
350 "A small window appears showing the location of the cursor in",
351 "the image window. You are now in composite mode. To exit",
352 "immediately, press Dismiss. In composite mode, the Command",
353 "widget has these options:",
354 "",
355 " Operators",
356 " Over",
357 " In",
358 " Out",
359 " Atop",
360 " Xor",
361 " Plus",
362 " Minus",
363 " Add",
364 " Subtract",
365 " Difference",
366 " Multiply",
367 " Bumpmap",
368 " Copy",
369 " CopyRed",
370 " CopyGreen",
371 " CopyBlue",
372 " CopyOpacity",
373 " Clear",
374 " Dissolve",
375 " Displace",
376 " Help",
377 " Dismiss",
378 "",
379 "Choose a composite operation from the Operators sub-menu of",
380 "the Command widget. How each operator behaves is described",
381 "below. Image window is the image currently displayed on",
382 "your X server and image is the image obtained with the File",
383 "Browser widget.",
384 "",
385 "Over The result is the union of the two image shapes,",
386 " with image obscuring image window in the region of",
387 " overlap.",
388 "",
389 "In The result is simply image cut by the shape of",
390 " image window. None of the image data of image",
391 " window is in the result.",
392 "",
393 "Out The resulting image is image with the shape of",
394 " image window cut out.",
395 "",
396 "Atop The result is the same shape as image image window,",
397 " with image obscuring image window where the image",
398 " shapes overlap. Note this differs from over",
399 " because the portion of image outside image window's",
400 " shape does not appear in the result.",
401 "",
402 "Xor The result is the image data from both image and",
403 " image window that is outside the overlap region.",
404 " The overlap region is blank.",
405 "",
406 "Plus The result is just the sum of the image data.",
407 " Output values are cropped to QuantumRange (no overflow).",
408 "",
409 "Minus The result of image - image window, with underflow",
410 " cropped to zero.",
411 "",
412 "Add The result of image + image window, with overflow",
413 " wrapping around (mod 256).",
414 "",
415 "Subtract The result of image - image window, with underflow",
416 " wrapping around (mod 256). The add and subtract",
417 " operators can be used to perform reversible",
418 " transformations.",
419 "",
420 "Difference",
421 " The result of abs(image - image window). This",
422 " useful for comparing two very similar images.",
423 "",
424 "Multiply",
425 " The result of image * image window. This",
426 " useful for the creation of drop-shadows.",
427 "",
428 "Bumpmap The result of surface normals from image * image",
429 " window.",
430 "",
431 "Copy The resulting image is image window replaced with",
432 " image. Here the matte information is ignored.",
433 "",
434 "CopyRed The red layer of the image window is replace with",
435 " the red layer of the image. The other layers are",
436 " untouched.",
437 "",
438 "CopyGreen",
439 " The green layer of the image window is replace with",
440 " the green layer of the image. The other layers are",
441 " untouched.",
442 "",
443 "CopyBlue The blue layer of the image window is replace with",
444 " the blue layer of the image. The other layers are",
445 " untouched.",
446 "",
447 "CopyOpacity",
448 " The matte layer of the image window is replace with",
449 " the matte layer of the image. The other layers are",
450 " untouched.",
451 "",
452 "The image compositor requires a matte, or alpha channel in",
453 "the image for some operations. This extra channel usually",
454 "defines a mask which represents a sort of a cookie-cutter",
455 "for the image. This the case when matte is opaque (full",
456 "coverage) for pixels inside the shape, zero outside, and",
457 "between 0 and QuantumRange on the boundary. If image does not",
458 "have a matte channel, it is initialized with 0 for any pixel",
459 "matching in color to pixel location (0,0), otherwise QuantumRange.",
460 "",
461 "If you choose Dissolve, the composite operator becomes Over. The",
462 "image matte channel percent transparency is initialized to factor.",
463 "The image window is initialized to (100-factor). Where factor is the",
464 "value you specify in the Dialog widget.",
465 "",
466 "Displace shifts the image pixels as defined by a displacement",
467 "map. With this option, image is used as a displacement map.",
468 "Black, within the displacement map, is a maximum positive",
469 "displacement. White is a maximum negative displacement and",
470 "middle gray is neutral. The displacement is scaled to determine",
471 "the pixel shift. By default, the displacement applies in both the",
472 "horizontal and vertical directions. However, if you specify a mask,",
473 "image is the horizontal X displacement and mask the vertical Y",
474 "displacement.",
475 "",
476 "Note that matte information for image window is not retained",
477 "for colormapped X server visuals (e.g. StaticColor,",
478 "StaticColor, GrayScale, PseudoColor). Correct compositing",
479 "behavior may require a TrueColor or DirectColor visual or a",
480 "Standard Colormap.",
481 "",
482 "Choosing a composite operator is optional. The default",
483 "operator is replace. However, you must choose a location to",
484 "composite your image and press button 1. Press and hold the",
485 "button before releasing and an outline of the image will",
486 "appear to help you identify your location.",
487 "",
488 "The actual colors of the composite image is saved. However,",
489 "the color that appears in image window may be different.",
490 "For example, on a monochrome screen image window will appear",
491 "black or white even though your composited image may have",
492 "many colors. If the image is saved to a file it is written",
493 "with the correct colors. To assure the correct colors are",
494 "saved in the final image, any PseudoClass image is promoted",
495 "to DirectClass (see miff(5)). To force a PseudoClass image",
496 "to remain PseudoClass, use -colors.",
497 (char *) NULL,
498 },
499 *ImageCutHelp[] =
500 {
501 "In cut mode, the Command widget has these options:",
502 "",
503 " Help",
504 " Dismiss",
505 "",
506 "To define a cut region, press button 1 and drag. The",
507 "cut region is defined by a highlighted rectangle that",
508 "expands or contracts as it follows the pointer. Once you",
509 "are satisfied with the cut region, release the button.",
510 "You are now in rectify mode. In rectify mode, the Command",
511 "widget has these options:",
512 "",
513 " Cut",
514 " Help",
515 " Dismiss",
516 "",
517 "You can make adjustments by moving the pointer to one of the",
518 "cut rectangle corners, pressing a button, and dragging.",
519 "Finally, press Cut to commit your copy region. To",
520 "exit without cutting the image, press Dismiss.",
521 (char *) NULL,
522 },
523 *ImageCopyHelp[] =
524 {
525 "In copy mode, the Command widget has these options:",
526 "",
527 " Help",
528 " Dismiss",
529 "",
530 "To define a copy region, press button 1 and drag. The",
531 "copy region is defined by a highlighted rectangle that",
532 "expands or contracts as it follows the pointer. Once you",
533 "are satisfied with the copy region, release the button.",
534 "You are now in rectify mode. In rectify mode, the Command",
535 "widget has these options:",
536 "",
537 " Copy",
538 " Help",
539 " Dismiss",
540 "",
541 "You can make adjustments by moving the pointer to one of the",
542 "copy rectangle corners, pressing a button, and dragging.",
543 "Finally, press Copy to commit your copy region. To",
544 "exit without copying the image, press Dismiss.",
545 (char *) NULL,
546 },
547 *ImageCropHelp[] =
548 {
549 "In crop mode, the Command widget has these options:",
550 "",
551 " Help",
552 " Dismiss",
553 "",
554 "To define a cropping region, press button 1 and drag. The",
555 "cropping region is defined by a highlighted rectangle that",
556 "expands or contracts as it follows the pointer. Once you",
557 "are satisfied with the cropping region, release the button.",
558 "You are now in rectify mode. In rectify mode, the Command",
559 "widget has these options:",
560 "",
561 " Crop",
562 " Help",
563 " Dismiss",
564 "",
565 "You can make adjustments by moving the pointer to one of the",
566 "cropping rectangle corners, pressing a button, and dragging.",
567 "Finally, press Crop to commit your cropping region. To",
568 "exit without cropping the image, press Dismiss.",
569 (char *) NULL,
570 },
571 *ImageDrawHelp[] =
572 {
573 "The cursor changes to a crosshair to indicate you are in",
574 "draw mode. To exit immediately, press Dismiss. In draw mode,",
575 "the Command widget has these options:",
576 "",
577 " Element",
578 " point",
579 " line",
580 " rectangle",
581 " fill rectangle",
582 " circle",
583 " fill circle",
584 " ellipse",
585 " fill ellipse",
586 " polygon",
587 " fill polygon",
588 " Color",
589 " black",
590 " blue",
591 " cyan",
592 " green",
593 " gray",
594 " red",
595 " magenta",
596 " yellow",
597 " white",
598 " transparent",
599 " Browser...",
600 " Stipple",
601 " Brick",
602 " Diagonal",
603 " Scales",
604 " Vertical",
605 " Wavy",
606 " Translucent",
607 " Opaque",
608 " Open...",
609 " Width",
610 " 1",
611 " 2",
612 " 4",
613 " 8",
614 " 16",
615 " Dialog...",
616 " Undo",
617 " Help",
618 " Dismiss",
619 "",
620 "Choose a drawing primitive from the Element sub-menu.",
621 "",
622 "Choose a color from the Color sub-menu. Additional",
623 "colors can be specified with the color browser.",
624 "",
625 "If you choose the color browser and press Grab, you can",
626 "select the color by moving the pointer to the desired",
627 "color on the screen and press any button. The transparent",
628 "color updates the image matte channel and is useful for",
629 "image compositing.",
630 "",
631 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
632 "Additional stipples can be specified with the file browser.",
633 "Stipples obtained from the file browser must be on disk in the",
634 "X11 bitmap format.",
635 "",
636 "Choose a width, if appropriate, from the Width sub-menu. To",
637 "choose a specific width select the Dialog widget.",
638 "",
639 "Choose a point in the Image window and press button 1 and",
640 "hold. Next, move the pointer to another location in the",
641 "image. As you move, a line connects the initial location and",
642 "the pointer. When you release the button, the image is",
643 "updated with the primitive you just drew. For polygons, the",
644 "image is updated when you press and release the button without",
645 "moving the pointer.",
646 "",
647 "To cancel image drawing, move the pointer back to the",
648 "starting point of the line and release the button.",
649 (char *) NULL,
650 },
651 *DisplayHelp[] =
652 {
653 "BUTTONS",
654 " The effects of each button press is described below. Three",
655 " buttons are required. If you have a two button mouse,",
656 " button 1 and 3 are returned. Press ALT and button 3 to",
657 " simulate button 2.",
658 "",
659 " 1 Press this button to map or unmap the Command widget.",
660 "",
661 " 2 Press and drag to define a region of the image to",
662 " magnify.",
663 "",
664 " 3 Press and drag to choose from a select set of commands.",
665 " This button behaves differently if the image being",
666 " displayed is a visual image directory. Here, choose a",
667 " particular tile of the directory and press this button and",
668 " drag to select a command from a pop-up menu. Choose from",
669 " these menu items:",
670 "",
671 " Open",
672 " Next",
673 " Former",
674 " Delete",
675 " Update",
676 "",
677 " If you choose Open, the image represented by the tile is",
678 " displayed. To return to the visual image directory, choose",
679 " Next from the Command widget. Next and Former moves to the",
680 " next or former image respectively. Choose Delete to delete",
681 " a particular image tile. Finally, choose Update to",
682 " synchronize all the image tiles with their respective",
683 " images.",
684 "",
685 "COMMAND WIDGET",
686 " The Command widget lists a number of sub-menus and commands.",
687 " They are",
688 "",
689 " File",
690 " Open...",
691 " Next",
692 " Former",
693 " Select...",
694 " Save...",
695 " Print...",
696 " Delete...",
697 " New...",
698 " Visual Directory...",
699 " Quit",
700 " Edit",
701 " Undo",
702 " Redo",
703 " Cut",
704 " Copy",
705 " Paste",
706 " View",
707 " Half Size",
708 " Original Size",
709 " Double Size",
710 " Resize...",
711 " Apply",
712 " Refresh",
713 " Restore",
714 " Transform",
715 " Crop",
716 " Chop",
717 " Flop",
718 " Flip",
719 " Rotate Right",
720 " Rotate Left",
721 " Rotate...",
722 " Shear...",
723 " Roll...",
724 " Trim Edges",
725 " Enhance",
726 " Brightness...",
727 " Saturation...",
728 " Hue...",
729 " Gamma...",
730 " Sharpen...",
731 " Dull",
732 " Contrast Stretch...",
733 " Sigmoidal Contrast...",
734 " Normalize",
735 " Equalize",
736 " Negate",
737 " Grayscale",
738 " Map...",
739 " Quantize...",
740 " Effects",
741 " Despeckle",
742 " Emboss",
743 " Reduce Noise",
744 " Add Noise",
745 " Sharpen...",
746 " Blur...",
747 " Threshold...",
748 " Edge Detect...",
749 " Spread...",
750 " Shade...",
751 " Painting...",
752 " Segment...",
753 " F/X",
754 " Solarize...",
755 " Sepia Tone...",
756 " Swirl...",
757 " Implode...",
758 " Vignette...",
759 " Wave...",
760 " Oil Painting...",
761 " Charcoal Drawing...",
762 " Image Edit",
763 " Annotate...",
764 " Draw...",
765 " Color...",
766 " Matte...",
767 " Composite...",
768 " Add Border...",
769 " Add Frame...",
770 " Comment...",
771 " Launch...",
772 " Region of Interest...",
773 " Miscellany",
774 " Image Info",
775 " Zoom Image",
776 " Show Preview...",
777 " Show Histogram",
778 " Show Matte",
779 " Background...",
780 " Slide Show",
781 " Preferences...",
782 " Help",
783 " Overview",
784 " Browse Documentation",
785 " About Display",
786 "",
787 " Menu items with a indented triangle have a sub-menu. They",
788 " are represented above as the indented items. To access a",
789 " sub-menu item, move the pointer to the appropriate menu and",
790 " press a button and drag. When you find the desired sub-menu",
791 " item, release the button and the command is executed. Move",
792 " the pointer away from the sub-menu if you decide not to",
793 " execute a particular command.",
794 "",
795 "KEYBOARD ACCELERATORS",
796 " Accelerators are one or two key presses that effect a",
797 " particular command. The keyboard accelerators that",
798 " display(1) understands is:",
799 "",
800 " Ctl+O Press to open an image from a file.",
801 "",
802 " space Press to display the next image.",
803 "",
804 " If the image is a multi-paged document such as a Postscript",
805 " document, you can skip ahead several pages by preceding",
806 " this command with a number. For example to display the",
807 " third page beyond the current page, press 3<space>.",
808 "",
809 " backspace Press to display the former image.",
810 "",
811 " If the image is a multi-paged document such as a Postscript",
812 " document, you can skip behind several pages by preceding",
813 " this command with a number. For example to display the",
814 " third page preceding the current page, press 3<backspace>.",
815 "",
816 " Ctl+S Press to write the image to a file.",
817 "",
818 " Ctl+P Press to print the image to a Postscript printer.",
819 "",
820 " Ctl+D Press to delete an image file.",
821 "",
822 " Ctl+N Press to create a blank canvas.",
823 "",
824 " Ctl+Q Press to discard all images and exit program.",
825 "",
826 " Ctl+Z Press to undo last image transformation.",
827 "",
828 " Ctl+R Press to redo last image transformation.",
829 "",
830 " Ctl+X Press to cut a region of the image.",
831 "",
832 " Ctl+C Press to copy a region of the image.",
833 "",
834 " Ctl+V Press to paste a region to the image.",
835 "",
836 " < Press to half the image size.",
837 "",
838 " - Press to return to the original image size.",
839 "",
840 " > Press to double the image size.",
841 "",
842 " % Press to resize the image to a width and height you",
843 " specify.",
844 "",
845 "Cmd-A Press to make any image transformations permanent."
846 "",
847 " By default, any image size transformations are applied",
848 " to the original image to create the image displayed on",
849 " the X server. However, the transformations are not",
850 " permanent (i.e. the original image does not change",
851 " size only the X image does). For example, if you",
852 " press > the X image will appear to double in size,",
853 " but the original image will in fact remain the same size.",
854 " To force the original image to double in size, press >",
855 " followed by Cmd-A.",
856 "",
857 " @ Press to refresh the image window.",
858 "",
859 " C Press to cut out a rectangular region of the image.",
860 "",
861 " [ Press to chop the image.",
862 "",
863 " H Press to flop image in the horizontal direction.",
864 "",
865 " V Press to flip image in the vertical direction.",
866 "",
867 " / Press to rotate the image 90 degrees clockwise.",
868 "",
869 " \\ Press to rotate the image 90 degrees counter-clockwise.",
870 "",
871 " * Press to rotate the image the number of degrees you",
872 " specify.",
873 "",
874 " S Press to shear the image the number of degrees you",
875 " specify.",
876 "",
877 " R Press to roll the image.",
878 "",
879 " T Press to trim the image edges.",
880 "",
881 " Shft-H Press to vary the image hue.",
882 "",
883 " Shft-S Press to vary the color saturation.",
884 "",
885 " Shft-L Press to vary the color brightness.",
886 "",
887 " Shft-G Press to gamma correct the image.",
888 "",
889 " Shft-C Press to sharpen the image contrast.",
890 "",
891 " Shft-Z Press to dull the image contrast.",
892 "",
893 " = Press to perform histogram equalization on the image.",
894 "",
895 " Shft-N Press to perform histogram normalization on the image.",
896 "",
897 " Shft-~ Press to negate the colors of the image.",
898 "",
899 " . Press to convert the image colors to gray.",
900 "",
901 " Shft-# Press to set the maximum number of unique colors in the",
902 " image.",
903 "",
904 " F2 Press to reduce the speckles in an image.",
905 "",
906 " F3 Press to eliminate peak noise from an image.",
907 "",
908 " F4 Press to add noise to an image.",
909 "",
910 " F5 Press to sharpen an image.",
911 "",
912 " F6 Press to delete an image file.",
913 "",
914 " F7 Press to threshold the image.",
915 "",
916 " F8 Press to detect edges within an image.",
917 "",
918 " F9 Press to emboss an image.",
919 "",
920 " F10 Press to displace pixels by a random amount.",
921 "",
922 " F11 Press to negate all pixels above the threshold level.",
923 "",
924 " F12 Press to shade the image using a distant light source.",
925 "",
926 " F13 Press to lighten or darken image edges to create a 3-D effect.",
927 "",
928 " F14 Press to segment the image by color.",
929 "",
930 " Meta-S Press to swirl image pixels about the center.",
931 "",
932 " Meta-I Press to implode image pixels about the center.",
933 "",
cristycee97112010-05-28 00:44:52 +0000934 " Meta-W Press to alter an image along a sine wave.",
cristy3ed852e2009-09-05 21:47:34 +0000935 "",
936 " Meta-P Press to simulate an oil painting.",
937 "",
938 " Meta-C Press to simulate a charcoal drawing.",
939 "",
940 " Alt-A Press to annotate the image with text.",
941 "",
942 " Alt-D Press to draw on an image.",
943 "",
944 " Alt-P Press to edit an image pixel color.",
945 "",
946 " Alt-M Press to edit the image matte information.",
947 "",
948 " Alt-V Press to composite the image with another.",
949 "",
950 " Alt-B Press to add a border to the image.",
951 "",
952 " Alt-F Press to add an ornamental border to the image.",
953 "",
954 " Alt-Shft-!",
955 " Press to add an image comment.",
956 "",
957 " Ctl-A Press to apply image processing techniques to a region",
958 " of interest.",
959 "",
960 " Shft-? Press to display information about the image.",
961 "",
962 " Shft-+ Press to map the zoom image window.",
963 "",
964 " Shft-P Press to preview an image enhancement, effect, or f/x.",
965 "",
966 " F1 Press to display helpful information about display(1).",
967 "",
968 " Find Press to browse documentation about ImageMagick.",
969 "",
970 " 1-9 Press to change the level of magnification.",
971 "",
972 " Use the arrow keys to move the image one pixel up, down,",
973 " left, or right within the magnify window. Be sure to first",
974 " map the magnify window by pressing button 2.",
975 "",
976 " Press ALT and one of the arrow keys to trim off one pixel",
977 " from any side of the image.",
978 (char *) NULL,
979 },
980 *ImageMatteEditHelp[] =
981 {
982 "Matte information within an image is useful for some",
983 "operations such as image compositing (See IMAGE",
984 "COMPOSITING). This extra channel usually defines a mask",
985 "which represents a sort of a cookie-cutter for the image.",
986 "This the case when matte is opaque (full coverage) for",
987 "pixels inside the shape, zero outside, and between 0 and",
988 "QuantumRange on the boundary.",
989 "",
990 "A small window appears showing the location of the cursor in",
991 "the image window. You are now in matte edit mode. To exit",
992 "immediately, press Dismiss. In matte edit mode, the Command",
993 "widget has these options:",
994 "",
995 " Method",
996 " point",
997 " replace",
998 " floodfill",
999 " filltoborder",
1000 " reset",
1001 " Border Color",
1002 " black",
1003 " blue",
1004 " cyan",
1005 " green",
1006 " gray",
1007 " red",
1008 " magenta",
1009 " yellow",
1010 " white",
1011 " Browser...",
1012 " Fuzz",
1013 " 0%",
1014 " 2%",
1015 " 5%",
1016 " 10%",
1017 " 15%",
1018 " Dialog...",
1019 " Matte",
1020 " Opaque",
1021 " Transparent",
1022 " Dialog...",
1023 " Undo",
1024 " Help",
1025 " Dismiss",
1026 "",
1027 "Choose a matte editing method from the Method sub-menu of",
1028 "the Command widget. The point method changes the matte value",
1029 "of any pixel selected with the pointer until the button is",
1030 "is released. The replace method changes the matte value of",
1031 "any pixel that matches the color of the pixel you select with",
1032 "a button press. Floodfill changes the matte value of any pixel",
1033 "that matches the color of the pixel you select with a button",
1034 "press and is a neighbor. Whereas filltoborder changes the matte",
1035 "value any neighbor pixel that is not the border color. Finally",
1036 "reset changes the entire image to the designated matte value.",
1037 "",
1038 "Choose Matte Value and pick Opaque or Transarent. For other values",
1039 "select the Dialog entry. Here a dialog appears requesting a matte",
1040 "value. The value you select is assigned as the opacity value of the",
1041 "selected pixel or pixels.",
1042 "",
1043 "Now, press any button to select a pixel within the image",
1044 "window to change its matte value.",
1045 "",
1046 "If the Magnify widget is mapped, it can be helpful in positioning",
1047 "your pointer within the image (refer to button 2).",
1048 "",
1049 "Matte information is only valid in a DirectClass image.",
1050 "Therefore, any PseudoClass image is promoted to DirectClass",
1051 "(see miff(5)). Note that matte information for PseudoClass",
1052 "is not retained for colormapped X server visuals (e.g.",
1053 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1054 "immediately save your image to a file (refer to Write).",
1055 "Correct matte editing behavior may require a TrueColor or",
1056 "DirectColor visual or a Standard Colormap.",
1057 (char *) NULL,
1058 },
1059 *ImagePanHelp[] =
1060 {
1061 "When an image exceeds the width or height of the X server",
1062 "screen, display maps a small panning icon. The rectangle",
1063 "within the panning icon shows the area that is currently",
1064 "displayed in the image window. To pan about the image,",
1065 "press any button and drag the pointer within the panning",
1066 "icon. The pan rectangle moves with the pointer and the",
1067 "image window is updated to reflect the location of the",
1068 "rectangle within the panning icon. When you have selected",
1069 "the area of the image you wish to view, release the button.",
1070 "",
1071 "Use the arrow keys to pan the image one pixel up, down,",
1072 "left, or right within the image window.",
1073 "",
1074 "The panning icon is withdrawn if the image becomes smaller",
1075 "than the dimensions of the X server screen.",
1076 (char *) NULL,
1077 },
1078 *ImagePasteHelp[] =
1079 {
1080 "A small window appears showing the location of the cursor in",
1081 "the image window. You are now in paste mode. To exit",
1082 "immediately, press Dismiss. In paste mode, the Command",
1083 "widget has these options:",
1084 "",
1085 " Operators",
1086 " over",
1087 " in",
1088 " out",
1089 " atop",
1090 " xor",
1091 " plus",
1092 " minus",
1093 " add",
1094 " subtract",
1095 " difference",
1096 " replace",
1097 " Help",
1098 " Dismiss",
1099 "",
1100 "Choose a composite operation from the Operators sub-menu of",
1101 "the Command widget. How each operator behaves is described",
1102 "below. Image window is the image currently displayed on",
1103 "your X server and image is the image obtained with the File",
1104 "Browser widget.",
1105 "",
1106 "Over The result is the union of the two image shapes,",
1107 " with image obscuring image window in the region of",
1108 " overlap.",
1109 "",
1110 "In The result is simply image cut by the shape of",
1111 " image window. None of the image data of image",
1112 " window is in the result.",
1113 "",
1114 "Out The resulting image is image with the shape of",
1115 " image window cut out.",
1116 "",
1117 "Atop The result is the same shape as image image window,",
1118 " with image obscuring image window where the image",
1119 " shapes overlap. Note this differs from over",
1120 " because the portion of image outside image window's",
1121 " shape does not appear in the result.",
1122 "",
1123 "Xor The result is the image data from both image and",
1124 " image window that is outside the overlap region.",
1125 " The overlap region is blank.",
1126 "",
1127 "Plus The result is just the sum of the image data.",
1128 " Output values are cropped to QuantumRange (no overflow).",
1129 " This operation is independent of the matte",
1130 " channels.",
1131 "",
1132 "Minus The result of image - image window, with underflow",
1133 " cropped to zero.",
1134 "",
1135 "Add The result of image + image window, with overflow",
1136 " wrapping around (mod 256).",
1137 "",
1138 "Subtract The result of image - image window, with underflow",
1139 " wrapping around (mod 256). The add and subtract",
1140 " operators can be used to perform reversible",
1141 " transformations.",
1142 "",
1143 "Difference",
1144 " The result of abs(image - image window). This",
1145 " useful for comparing two very similar images.",
1146 "",
1147 "Copy The resulting image is image window replaced with",
1148 " image. Here the matte information is ignored.",
1149 "",
1150 "CopyRed The red layer of the image window is replace with",
1151 " the red layer of the image. The other layers are",
1152 " untouched.",
1153 "",
1154 "CopyGreen",
1155 " The green layer of the image window is replace with",
1156 " the green layer of the image. The other layers are",
1157 " untouched.",
1158 "",
1159 "CopyBlue The blue layer of the image window is replace with",
1160 " the blue layer of the image. The other layers are",
1161 " untouched.",
1162 "",
1163 "CopyOpacity",
1164 " The matte layer of the image window is replace with",
1165 " the matte layer of the image. The other layers are",
1166 " untouched.",
1167 "",
1168 "The image compositor requires a matte, or alpha channel in",
1169 "the image for some operations. This extra channel usually",
1170 "defines a mask which represents a sort of a cookie-cutter",
1171 "for the image. This the case when matte is opaque (full",
1172 "coverage) for pixels inside the shape, zero outside, and",
1173 "between 0 and QuantumRange on the boundary. If image does not",
1174 "have a matte channel, it is initialized with 0 for any pixel",
1175 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1176 "",
1177 "Note that matte information for image window is not retained",
1178 "for colormapped X server visuals (e.g. StaticColor,",
1179 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1180 "behavior may require a TrueColor or DirectColor visual or a",
1181 "Standard Colormap.",
1182 "",
1183 "Choosing a composite operator is optional. The default",
1184 "operator is replace. However, you must choose a location to",
1185 "paste your image and press button 1. Press and hold the",
1186 "button before releasing and an outline of the image will",
1187 "appear to help you identify your location.",
1188 "",
1189 "The actual colors of the pasted image is saved. However,",
1190 "the color that appears in image window may be different.",
1191 "For example, on a monochrome screen image window will appear",
1192 "black or white even though your pasted image may have",
1193 "many colors. If the image is saved to a file it is written",
1194 "with the correct colors. To assure the correct colors are",
1195 "saved in the final image, any PseudoClass image is promoted",
1196 "to DirectClass (see miff(5)). To force a PseudoClass image",
1197 "to remain PseudoClass, use -colors.",
1198 (char *) NULL,
1199 },
1200 *ImageROIHelp[] =
1201 {
1202 "In region of interest mode, the Command widget has these",
1203 "options:",
1204 "",
1205 " Help",
1206 " Dismiss",
1207 "",
1208 "To define a region of interest, press button 1 and drag.",
1209 "The region of interest is defined by a highlighted rectangle",
1210 "that expands or contracts as it follows the pointer. Once",
1211 "you are satisfied with the region of interest, release the",
1212 "button. You are now in apply mode. In apply mode the",
1213 "Command widget has these options:",
1214 "",
1215 " File",
1216 " Save...",
1217 " Print...",
1218 " Edit",
1219 " Undo",
1220 " Redo",
1221 " Transform",
1222 " Flop",
1223 " Flip",
1224 " Rotate Right",
1225 " Rotate Left",
1226 " Enhance",
1227 " Hue...",
1228 " Saturation...",
1229 " Brightness...",
1230 " Gamma...",
1231 " Spiff",
1232 " Dull",
1233 " Contrast Stretch",
1234 " Sigmoidal Contrast...",
1235 " Normalize",
1236 " Equalize",
1237 " Negate",
1238 " Grayscale",
1239 " Map...",
1240 " Quantize...",
1241 " Effects",
1242 " Despeckle",
1243 " Emboss",
1244 " Reduce Noise",
1245 " Sharpen...",
1246 " Blur...",
1247 " Threshold...",
1248 " Edge Detect...",
1249 " Spread...",
1250 " Shade...",
1251 " Raise...",
1252 " Segment...",
1253 " F/X",
1254 " Solarize...",
1255 " Sepia Tone...",
1256 " Swirl...",
1257 " Implode...",
1258 " Vignette...",
1259 " Wave...",
1260 " Oil Painting...",
1261 " Charcoal Drawing...",
1262 " Miscellany",
1263 " Image Info",
1264 " Zoom Image",
1265 " Show Preview...",
1266 " Show Histogram",
1267 " Show Matte",
1268 " Help",
1269 " Dismiss",
1270 "",
1271 "You can make adjustments to the region of interest by moving",
1272 "the pointer to one of the rectangle corners, pressing a",
1273 "button, and dragging. Finally, choose an image processing",
1274 "technique from the Command widget. You can choose more than",
1275 "one image processing technique to apply to an area.",
1276 "Alternatively, you can move the region of interest before",
1277 "applying another image processing technique. To exit, press",
1278 "Dismiss.",
1279 (char *) NULL,
1280 },
1281 *ImageRotateHelp[] =
1282 {
1283 "In rotate mode, the Command widget has these options:",
1284 "",
1285 " Pixel Color",
1286 " black",
1287 " blue",
1288 " cyan",
1289 " green",
1290 " gray",
1291 " red",
1292 " magenta",
1293 " yellow",
1294 " white",
1295 " Browser...",
1296 " Direction",
1297 " horizontal",
1298 " vertical",
1299 " Help",
1300 " Dismiss",
1301 "",
1302 "Choose a background color from the Pixel Color sub-menu.",
1303 "Additional background colors can be specified with the color",
1304 "browser. You can change the menu colors by setting the X",
1305 "resources pen1 through pen9.",
1306 "",
1307 "If you choose the color browser and press Grab, you can",
1308 "select the background color by moving the pointer to the",
1309 "desired color on the screen and press any button.",
1310 "",
1311 "Choose a point in the image window and press this button and",
1312 "hold. Next, move the pointer to another location in the",
1313 "image. As you move a line connects the initial location and",
1314 "the pointer. When you release the button, the degree of",
1315 "image rotation is determined by the slope of the line you",
1316 "just drew. The slope is relative to the direction you",
1317 "choose from the Direction sub-menu of the Command widget.",
1318 "",
1319 "To cancel the image rotation, move the pointer back to the",
1320 "starting point of the line and release the button.",
1321 (char *) NULL,
1322 };
1323
1324/*
1325 Enumeration declarations.
1326*/
1327typedef enum
1328{
1329 CopyMode,
1330 CropMode,
1331 CutMode
1332} ClipboardMode;
1333
1334typedef enum
1335{
1336 OpenCommand,
1337 NextCommand,
1338 FormerCommand,
1339 SelectCommand,
1340 SaveCommand,
1341 PrintCommand,
1342 DeleteCommand,
1343 NewCommand,
1344 VisualDirectoryCommand,
1345 QuitCommand,
1346 UndoCommand,
1347 RedoCommand,
1348 CutCommand,
1349 CopyCommand,
1350 PasteCommand,
1351 HalfSizeCommand,
1352 OriginalSizeCommand,
1353 DoubleSizeCommand,
1354 ResizeCommand,
1355 ApplyCommand,
1356 RefreshCommand,
1357 RestoreCommand,
1358 CropCommand,
1359 ChopCommand,
1360 FlopCommand,
1361 FlipCommand,
1362 RotateRightCommand,
1363 RotateLeftCommand,
1364 RotateCommand,
1365 ShearCommand,
1366 RollCommand,
1367 TrimCommand,
1368 HueCommand,
1369 SaturationCommand,
1370 BrightnessCommand,
1371 GammaCommand,
1372 SpiffCommand,
1373 DullCommand,
1374 ContrastStretchCommand,
1375 SigmoidalContrastCommand,
1376 NormalizeCommand,
1377 EqualizeCommand,
1378 NegateCommand,
1379 GrayscaleCommand,
1380 MapCommand,
1381 QuantizeCommand,
1382 DespeckleCommand,
1383 EmbossCommand,
1384 ReduceNoiseCommand,
1385 AddNoiseCommand,
1386 SharpenCommand,
1387 BlurCommand,
1388 ThresholdCommand,
1389 EdgeDetectCommand,
1390 SpreadCommand,
1391 ShadeCommand,
1392 RaiseCommand,
1393 SegmentCommand,
1394 SolarizeCommand,
1395 SepiaToneCommand,
1396 SwirlCommand,
1397 ImplodeCommand,
1398 VignetteCommand,
1399 WaveCommand,
1400 OilPaintCommand,
1401 CharcoalDrawCommand,
1402 AnnotateCommand,
1403 DrawCommand,
1404 ColorCommand,
1405 MatteCommand,
1406 CompositeCommand,
1407 AddBorderCommand,
1408 AddFrameCommand,
1409 CommentCommand,
1410 LaunchCommand,
1411 RegionofInterestCommand,
1412 ROIHelpCommand,
1413 ROIDismissCommand,
1414 InfoCommand,
1415 ZoomCommand,
1416 ShowPreviewCommand,
1417 ShowHistogramCommand,
1418 ShowMatteCommand,
1419 BackgroundCommand,
1420 SlideShowCommand,
1421 PreferencesCommand,
1422 HelpCommand,
1423 BrowseDocumentationCommand,
1424 VersionCommand,
1425 SaveToUndoBufferCommand,
1426 FreeBuffersCommand,
1427 NullCommand
1428} CommandType;
1429
1430typedef enum
1431{
1432 AnnotateNameCommand,
1433 AnnotateFontColorCommand,
1434 AnnotateBackgroundColorCommand,
1435 AnnotateRotateCommand,
1436 AnnotateHelpCommand,
1437 AnnotateDismissCommand,
1438 TextHelpCommand,
1439 TextApplyCommand,
1440 ChopDirectionCommand,
1441 ChopHelpCommand,
1442 ChopDismissCommand,
1443 HorizontalChopCommand,
1444 VerticalChopCommand,
1445 ColorEditMethodCommand,
1446 ColorEditColorCommand,
1447 ColorEditBorderCommand,
1448 ColorEditFuzzCommand,
1449 ColorEditUndoCommand,
1450 ColorEditHelpCommand,
1451 ColorEditDismissCommand,
1452 CompositeOperatorsCommand,
1453 CompositeDissolveCommand,
1454 CompositeDisplaceCommand,
1455 CompositeHelpCommand,
1456 CompositeDismissCommand,
1457 CropHelpCommand,
1458 CropDismissCommand,
1459 RectifyCopyCommand,
1460 RectifyHelpCommand,
1461 RectifyDismissCommand,
1462 DrawElementCommand,
1463 DrawColorCommand,
1464 DrawStippleCommand,
1465 DrawWidthCommand,
1466 DrawUndoCommand,
1467 DrawHelpCommand,
1468 DrawDismissCommand,
1469 MatteEditMethod,
1470 MatteEditBorderCommand,
1471 MatteEditFuzzCommand,
1472 MatteEditValueCommand,
1473 MatteEditUndoCommand,
1474 MatteEditHelpCommand,
1475 MatteEditDismissCommand,
1476 PasteOperatorsCommand,
1477 PasteHelpCommand,
1478 PasteDismissCommand,
1479 RotateColorCommand,
1480 RotateDirectionCommand,
1481 RotateCropCommand,
1482 RotateSharpenCommand,
1483 RotateHelpCommand,
1484 RotateDismissCommand,
1485 HorizontalRotateCommand,
1486 VerticalRotateCommand,
1487 TileLoadCommand,
1488 TileNextCommand,
1489 TileFormerCommand,
1490 TileDeleteCommand,
1491 TileUpdateCommand
1492} ModeType;
1493
1494/*
1495 Stipples.
1496*/
1497#define BricksWidth 20
1498#define BricksHeight 20
1499#define DiagonalWidth 16
1500#define DiagonalHeight 16
1501#define HighlightWidth 8
1502#define HighlightHeight 8
1503#define ScalesWidth 16
1504#define ScalesHeight 16
1505#define ShadowWidth 8
1506#define ShadowHeight 8
1507#define VerticalWidth 16
1508#define VerticalHeight 16
1509#define WavyWidth 16
1510#define WavyHeight 16
1511
1512/*
1513 Constant declaration.
1514*/
1515static const int
1516 RoiDelta = 8;
1517
1518static const unsigned char
1519 BricksBitmap[] =
1520 {
1521 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1522 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1523 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1524 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1525 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1526 },
1527 DiagonalBitmap[] =
1528 {
1529 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1530 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1531 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1532 },
1533 ScalesBitmap[] =
1534 {
1535 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1536 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1537 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1538 },
1539 VerticalBitmap[] =
1540 {
1541 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1542 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1543 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1544 },
1545 WavyBitmap[] =
1546 {
1547 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1548 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1549 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1550 };
1551
1552/*
1553 Function prototypes.
1554*/
1555static CommandType
1556 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1557 const MagickStatusType,KeySym,Image **);
1558
1559static Image
1560 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1561 Image **),
1562 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1563 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1564 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1565
1566static MagickBooleanType
1567 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1568 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1569 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1570 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1571 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1572 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1573 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1574 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1575 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1576 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1577 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1578 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1579 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1580 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1581 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1582
1583static void
1584 XDrawPanRectangle(Display *,XWindows *),
1585 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
1586 XMagnifyImage(Display *,XWindows *,XEvent *),
1587 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1588 XPanImage(Display *,XWindows *,XEvent *),
1589 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1590 const KeySym),
1591 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1592 XScreenEvent(Display *,XWindows *,XEvent *),
1593 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1594
1595/*
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597% %
1598% %
1599% %
1600% D i s p l a y I m a g e s %
1601% %
1602% %
1603% %
1604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605%
1606% DisplayImages() displays an image sequence to any X window screen. It
1607% returns a value other than 0 if successful. Check the exception member
1608% of image to determine the reason for any failure.
1609%
1610% The format of the DisplayImages method is:
1611%
1612% MagickBooleanType DisplayImages(const ImageInfo *image_info,
1613% Image *images)
1614%
1615% A description of each parameter follows:
1616%
1617% o image_info: the image info.
1618%
1619% o image: the image.
1620%
1621*/
1622MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1623 Image *images)
1624{
1625 char
1626 *argv[1];
1627
1628 Display
1629 *display;
1630
1631 Image
1632 *image;
1633
cristybb503372010-05-27 20:51:26 +00001634 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001635 i;
1636
cristybb503372010-05-27 20:51:26 +00001637 size_t
cristy3ed852e2009-09-05 21:47:34 +00001638 state;
1639
1640 XrmDatabase
1641 resource_database;
1642
1643 XResourceInfo
1644 resource_info;
1645
1646 assert(image_info != (const ImageInfo *) NULL);
1647 assert(image_info->signature == MagickSignature);
1648 assert(images != (Image *) NULL);
1649 assert(images->signature == MagickSignature);
1650 if (images->debug != MagickFalse)
1651 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1652 display=XOpenDisplay(image_info->server_name);
1653 if (display == (Display *) NULL)
1654 {
1655 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1656 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1657 image_info->server_name));
1658 return(MagickFalse);
1659 }
1660 if (images->exception.severity != UndefinedException)
1661 CatchException(&images->exception);
1662 (void) XSetErrorHandler(XError);
1663 resource_database=XGetResourceDatabase(display,GetClientName());
1664 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1665 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1666 if (image_info->page != (char *) NULL)
1667 resource_info.image_geometry=AcquireString(image_info->page);
1668 resource_info.immutable=MagickTrue;
1669 argv[0]=AcquireString(GetClientName());
1670 state=DefaultState;
1671 for (i=0; (state & ExitState) == 0; i++)
1672 {
cristybb503372010-05-27 20:51:26 +00001673 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
cristy3ed852e2009-09-05 21:47:34 +00001674 break;
1675 image=GetImageFromList(images,i % GetImageListLength(images));
1676 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1677 }
1678 argv[0]=DestroyString(argv[0]);
1679 (void) XCloseDisplay(display);
1680 XDestroyResourceInfo(&resource_info);
1681 if (images->exception.severity != UndefinedException)
1682 return(MagickFalse);
1683 return(MagickTrue);
1684}
1685
1686/*
1687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688% %
1689% %
1690% %
1691% R e m o t e D i s p l a y C o m m a n d %
1692% %
1693% %
1694% %
1695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696%
1697% RemoteDisplayCommand() encourages a remote display program to display the
1698% specified image filename.
1699%
1700% The format of the RemoteDisplayCommand method is:
1701%
1702% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1703% const char *window,const char *filename,ExceptionInfo *exception)
1704%
1705% A description of each parameter follows:
1706%
1707% o image_info: the image info.
1708%
1709% o window: Specifies the name or id of an X window.
1710%
1711% o filename: the name of the image filename to display.
1712%
1713% o exception: return any errors or warnings in this structure.
1714%
1715*/
1716MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1717 const char *window,const char *filename,ExceptionInfo *exception)
1718{
1719 Display
1720 *display;
1721
1722 MagickStatusType
1723 status;
1724
1725 assert(image_info != (const ImageInfo *) NULL);
1726 assert(image_info->signature == MagickSignature);
1727 assert(filename != (char *) NULL);
1728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1729 display=XOpenDisplay(image_info->server_name);
1730 if (display == (Display *) NULL)
1731 {
1732 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1733 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1734 return(MagickFalse);
1735 }
1736 (void) XSetErrorHandler(XError);
1737 status=XRemoteCommand(display,window,filename);
1738 (void) XCloseDisplay(display);
1739 return(status != 0 ? MagickTrue : MagickFalse);
1740}
1741
1742/*
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744% %
1745% %
1746% %
1747+ X A n n o t a t e E d i t I m a g e %
1748% %
1749% %
1750% %
1751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752%
1753% XAnnotateEditImage() annotates the image with text.
1754%
1755% The format of the XAnnotateEditImage method is:
1756%
1757% MagickBooleanType XAnnotateEditImage(Display *display,
1758% XResourceInfo *resource_info,XWindows *windows,Image *image)
1759%
1760% A description of each parameter follows:
1761%
1762% o display: Specifies a connection to an X server; returned from
1763% XOpenDisplay.
1764%
1765% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1766%
1767% o windows: Specifies a pointer to a XWindows structure.
1768%
1769% o image: the image; returned from ReadImage.
1770%
1771*/
1772
cristybb503372010-05-27 20:51:26 +00001773static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001774{
1775 if (x > y)
1776 return(x);
1777 return(y);
1778}
1779
cristybb503372010-05-27 20:51:26 +00001780static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001781{
1782 if (x < y)
1783 return(x);
1784 return(y);
1785}
1786
1787static MagickBooleanType XAnnotateEditImage(Display *display,
1788 XResourceInfo *resource_info,XWindows *windows,Image *image)
1789{
1790 static const char
1791 *AnnotateMenu[] =
1792 {
1793 "Font Name",
1794 "Font Color",
1795 "Box Color",
1796 "Rotate Text",
1797 "Help",
1798 "Dismiss",
1799 (char *) NULL
1800 },
1801 *TextMenu[] =
1802 {
1803 "Help",
1804 "Apply",
1805 (char *) NULL
1806 };
1807
1808 static const ModeType
1809 AnnotateCommands[] =
1810 {
1811 AnnotateNameCommand,
1812 AnnotateFontColorCommand,
1813 AnnotateBackgroundColorCommand,
1814 AnnotateRotateCommand,
1815 AnnotateHelpCommand,
1816 AnnotateDismissCommand
1817 },
1818 TextCommands[] =
1819 {
1820 TextHelpCommand,
1821 TextApplyCommand
1822 };
1823
1824 static MagickBooleanType
1825 transparent_box = MagickTrue,
1826 transparent_pen = MagickFalse;
1827
1828 static MagickRealType
1829 degrees = 0.0;
1830
1831 static unsigned int
1832 box_id = MaxNumberPens-2,
1833 font_id = 0,
1834 pen_id = 0;
1835
1836 char
1837 command[MaxTextExtent],
1838 text[MaxTextExtent];
1839
1840 const char
1841 *ColorMenu[MaxNumberPens+1];
1842
1843 Cursor
1844 cursor;
1845
1846 GC
1847 annotate_context;
1848
1849 int
1850 id,
1851 pen_number,
1852 status,
1853 x,
1854 y;
1855
1856 KeySym
1857 key_symbol;
1858
1859 register char
1860 *p;
1861
cristybb503372010-05-27 20:51:26 +00001862 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001863 i;
1864
1865 unsigned int
1866 height,
1867 width;
1868
cristybb503372010-05-27 20:51:26 +00001869 size_t
cristy3ed852e2009-09-05 21:47:34 +00001870 state;
1871
1872 XAnnotateInfo
1873 *annotate_info,
1874 *previous_info;
1875
1876 XColor
1877 color;
1878
1879 XFontStruct
1880 *font_info;
1881
1882 XEvent
1883 event,
1884 text_event;
1885
1886 /*
1887 Map Command widget.
1888 */
1889 (void) CloneString(&windows->command.name,"Annotate");
1890 windows->command.data=4;
1891 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1892 (void) XMapRaised(display,windows->command.id);
1893 XClientMessage(display,windows->image.id,windows->im_protocols,
1894 windows->im_update_widget,CurrentTime);
1895 /*
1896 Track pointer until button 1 is pressed.
1897 */
1898 XQueryPosition(display,windows->image.id,&x,&y);
1899 (void) XSelectInput(display,windows->image.id,
1900 windows->image.attributes.event_mask | PointerMotionMask);
1901 cursor=XCreateFontCursor(display,XC_left_side);
1902 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1903 state=DefaultState;
1904 do
1905 {
1906 if (windows->info.mapped != MagickFalse)
1907 {
1908 /*
1909 Display pointer position.
1910 */
1911 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
1912 x+windows->image.x,y+windows->image.y);
1913 XInfoWidget(display,windows,text);
1914 }
1915 /*
1916 Wait for next event.
1917 */
1918 XScreenEvent(display,windows,&event);
1919 if (event.xany.window == windows->command.id)
1920 {
1921 /*
1922 Select a command from the Command widget.
1923 */
1924 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1925 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1926 if (id < 0)
1927 continue;
1928 switch (AnnotateCommands[id])
1929 {
1930 case AnnotateNameCommand:
1931 {
1932 const char
1933 *FontMenu[MaxNumberFonts];
1934
1935 int
1936 font_number;
1937
1938 /*
1939 Initialize menu selections.
1940 */
1941 for (i=0; i < MaxNumberFonts; i++)
1942 FontMenu[i]=resource_info->font_name[i];
1943 FontMenu[MaxNumberFonts-2]="Browser...";
1944 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1945 /*
1946 Select a font name from the pop-up menu.
1947 */
1948 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1949 (const char **) FontMenu,command);
1950 if (font_number < 0)
1951 break;
1952 if (font_number == (MaxNumberFonts-2))
1953 {
1954 static char
1955 font_name[MaxTextExtent] = "fixed";
1956
1957 /*
1958 Select a font name from a browser.
1959 */
1960 resource_info->font_name[font_number]=font_name;
1961 XFontBrowserWidget(display,windows,"Select",font_name);
1962 if (*font_name == '\0')
1963 break;
1964 }
1965 /*
1966 Initialize font info.
1967 */
1968 font_info=XLoadQueryFont(display,resource_info->font_name[
1969 font_number]);
1970 if (font_info == (XFontStruct *) NULL)
1971 {
1972 XNoticeWidget(display,windows,"Unable to load font:",
1973 resource_info->font_name[font_number]);
1974 break;
1975 }
1976 font_id=(unsigned int) font_number;
1977 (void) XFreeFont(display,font_info);
1978 break;
1979 }
1980 case AnnotateFontColorCommand:
1981 {
1982 /*
1983 Initialize menu selections.
1984 */
1985 for (i=0; i < (int) (MaxNumberPens-2); i++)
1986 ColorMenu[i]=resource_info->pen_colors[i];
1987 ColorMenu[MaxNumberPens-2]="transparent";
1988 ColorMenu[MaxNumberPens-1]="Browser...";
1989 ColorMenu[MaxNumberPens]=(const char *) NULL;
1990 /*
1991 Select a pen color from the pop-up menu.
1992 */
1993 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
1994 (const char **) ColorMenu,command);
1995 if (pen_number < 0)
1996 break;
1997 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
1998 MagickFalse;
1999 if (transparent_pen != MagickFalse)
2000 break;
2001 if (pen_number == (MaxNumberPens-1))
2002 {
2003 static char
2004 color_name[MaxTextExtent] = "gray";
2005
2006 /*
2007 Select a pen color from a dialog.
2008 */
2009 resource_info->pen_colors[pen_number]=color_name;
2010 XColorBrowserWidget(display,windows,"Select",color_name);
2011 if (*color_name == '\0')
2012 break;
2013 }
2014 /*
2015 Set pen color.
2016 */
2017 (void) XParseColor(display,windows->map_info->colormap,
2018 resource_info->pen_colors[pen_number],&color);
2019 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2020 (unsigned int) MaxColors,&color);
2021 windows->pixel_info->pen_colors[pen_number]=color;
2022 pen_id=(unsigned int) pen_number;
2023 break;
2024 }
2025 case AnnotateBackgroundColorCommand:
2026 {
2027 /*
2028 Initialize menu selections.
2029 */
2030 for (i=0; i < (int) (MaxNumberPens-2); i++)
2031 ColorMenu[i]=resource_info->pen_colors[i];
2032 ColorMenu[MaxNumberPens-2]="transparent";
2033 ColorMenu[MaxNumberPens-1]="Browser...";
2034 ColorMenu[MaxNumberPens]=(const char *) NULL;
2035 /*
2036 Select a pen color from the pop-up menu.
2037 */
2038 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2039 (const char **) ColorMenu,command);
2040 if (pen_number < 0)
2041 break;
2042 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2043 MagickFalse;
2044 if (transparent_box != MagickFalse)
2045 break;
2046 if (pen_number == (MaxNumberPens-1))
2047 {
2048 static char
2049 color_name[MaxTextExtent] = "gray";
2050
2051 /*
2052 Select a pen color from a dialog.
2053 */
2054 resource_info->pen_colors[pen_number]=color_name;
2055 XColorBrowserWidget(display,windows,"Select",color_name);
2056 if (*color_name == '\0')
2057 break;
2058 }
2059 /*
2060 Set pen color.
2061 */
2062 (void) XParseColor(display,windows->map_info->colormap,
2063 resource_info->pen_colors[pen_number],&color);
2064 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2065 (unsigned int) MaxColors,&color);
2066 windows->pixel_info->pen_colors[pen_number]=color;
2067 box_id=(unsigned int) pen_number;
2068 break;
2069 }
2070 case AnnotateRotateCommand:
2071 {
2072 int
2073 entry;
2074
2075 static char
2076 angle[MaxTextExtent] = "30.0";
2077
2078 static const char
2079 *RotateMenu[] =
2080 {
2081 "-90",
2082 "-45",
2083 "-30",
2084 "0",
2085 "30",
2086 "45",
2087 "90",
2088 "180",
2089 "Dialog...",
2090 (char *) NULL,
2091 };
2092
2093 /*
2094 Select a command from the pop-up menu.
2095 */
2096 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2097 command);
2098 if (entry < 0)
2099 break;
2100 if (entry != 8)
2101 {
cristyf2f27272009-12-17 14:48:46 +00002102 degrees=StringToDouble(RotateMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00002103 break;
2104 }
2105 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2106 angle);
2107 if (*angle == '\0')
2108 break;
cristyf2f27272009-12-17 14:48:46 +00002109 degrees=StringToDouble(angle);
cristy3ed852e2009-09-05 21:47:34 +00002110 break;
2111 }
2112 case AnnotateHelpCommand:
2113 {
2114 XTextViewWidget(display,resource_info,windows,MagickFalse,
2115 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2116 break;
2117 }
2118 case AnnotateDismissCommand:
2119 {
2120 /*
2121 Prematurely exit.
2122 */
2123 state|=EscapeState;
2124 state|=ExitState;
2125 break;
2126 }
2127 default:
2128 break;
2129 }
2130 continue;
2131 }
2132 switch (event.type)
2133 {
2134 case ButtonPress:
2135 {
2136 if (event.xbutton.button != Button1)
2137 break;
2138 if (event.xbutton.window != windows->image.id)
2139 break;
2140 /*
2141 Change to text entering mode.
2142 */
2143 x=event.xbutton.x;
2144 y=event.xbutton.y;
2145 state|=ExitState;
2146 break;
2147 }
2148 case ButtonRelease:
2149 break;
2150 case Expose:
2151 break;
2152 case KeyPress:
2153 {
2154 if (event.xkey.window != windows->image.id)
2155 break;
2156 /*
2157 Respond to a user key press.
2158 */
2159 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2160 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2161 switch ((int) key_symbol)
2162 {
2163 case XK_Escape:
2164 case XK_F20:
2165 {
2166 /*
2167 Prematurely exit.
2168 */
2169 state|=EscapeState;
2170 state|=ExitState;
2171 break;
2172 }
2173 case XK_F1:
2174 case XK_Help:
2175 {
2176 XTextViewWidget(display,resource_info,windows,MagickFalse,
2177 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2178 break;
2179 }
2180 default:
2181 {
2182 (void) XBell(display,0);
2183 break;
2184 }
2185 }
2186 break;
2187 }
2188 case MotionNotify:
2189 {
2190 /*
2191 Map and unmap Info widget as cursor crosses its boundaries.
2192 */
2193 x=event.xmotion.x;
2194 y=event.xmotion.y;
2195 if (windows->info.mapped != MagickFalse)
2196 {
2197 if ((x < (int) (windows->info.x+windows->info.width)) &&
2198 (y < (int) (windows->info.y+windows->info.height)))
2199 (void) XWithdrawWindow(display,windows->info.id,
2200 windows->info.screen);
2201 }
2202 else
2203 if ((x > (int) (windows->info.x+windows->info.width)) ||
2204 (y > (int) (windows->info.y+windows->info.height)))
2205 (void) XMapWindow(display,windows->info.id);
2206 break;
2207 }
2208 default:
2209 break;
2210 }
2211 } while ((state & ExitState) == 0);
2212 (void) XSelectInput(display,windows->image.id,
2213 windows->image.attributes.event_mask);
2214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2215 if ((state & EscapeState) != 0)
2216 return(MagickTrue);
2217 /*
2218 Set font info and check boundary conditions.
2219 */
2220 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2221 if (font_info == (XFontStruct *) NULL)
2222 {
2223 XNoticeWidget(display,windows,"Unable to load font:",
2224 resource_info->font_name[font_id]);
2225 font_info=windows->font_info;
2226 }
2227 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2228 x=(int) windows->image.width-font_info->max_bounds.width;
2229 if (y < (int) (font_info->ascent+font_info->descent))
2230 y=(int) font_info->ascent+font_info->descent;
2231 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2232 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2233 return(MagickFalse);
2234 /*
2235 Initialize annotate structure.
2236 */
cristy90823212009-12-12 20:48:33 +00002237 annotate_info=(XAnnotateInfo *) AcquireAlignedMemory(1,sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002238 if (annotate_info == (XAnnotateInfo *) NULL)
2239 return(MagickFalse);
2240 XGetAnnotateInfo(annotate_info);
2241 annotate_info->x=x;
2242 annotate_info->y=y;
2243 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2244 annotate_info->stencil=OpaqueStencil;
2245 else
2246 if (transparent_box == MagickFalse)
2247 annotate_info->stencil=BackgroundStencil;
2248 else
2249 annotate_info->stencil=ForegroundStencil;
2250 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2251 annotate_info->degrees=degrees;
2252 annotate_info->font_info=font_info;
2253 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2254 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2255 sizeof(*annotate_info->text));
2256 if (annotate_info->text == (char *) NULL)
2257 return(MagickFalse);
2258 /*
2259 Create cursor and set graphic context.
2260 */
2261 cursor=XCreateFontCursor(display,XC_pencil);
2262 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2263 annotate_context=windows->image.annotate_context;
2264 (void) XSetFont(display,annotate_context,font_info->fid);
2265 (void) XSetBackground(display,annotate_context,
2266 windows->pixel_info->pen_colors[box_id].pixel);
2267 (void) XSetForeground(display,annotate_context,
2268 windows->pixel_info->pen_colors[pen_id].pixel);
2269 /*
2270 Begin annotating the image with text.
2271 */
2272 (void) CloneString(&windows->command.name,"Text");
2273 windows->command.data=0;
2274 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2275 state=DefaultState;
2276 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2277 text_event.xexpose.width=(int) font_info->max_bounds.width;
2278 text_event.xexpose.height=font_info->max_bounds.ascent+
2279 font_info->max_bounds.descent;
2280 p=annotate_info->text;
2281 do
2282 {
2283 /*
2284 Display text cursor.
2285 */
2286 *p='\0';
2287 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2288 /*
2289 Wait for next event.
2290 */
2291 XScreenEvent(display,windows,&event);
2292 if (event.xany.window == windows->command.id)
2293 {
2294 /*
2295 Select a command from the Command widget.
2296 */
2297 (void) XSetBackground(display,annotate_context,
2298 windows->pixel_info->background_color.pixel);
2299 (void) XSetForeground(display,annotate_context,
2300 windows->pixel_info->foreground_color.pixel);
2301 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2302 (void) XSetBackground(display,annotate_context,
2303 windows->pixel_info->pen_colors[box_id].pixel);
2304 (void) XSetForeground(display,annotate_context,
2305 windows->pixel_info->pen_colors[pen_id].pixel);
2306 if (id < 0)
2307 continue;
2308 switch (TextCommands[id])
2309 {
2310 case TextHelpCommand:
2311 {
2312 XTextViewWidget(display,resource_info,windows,MagickFalse,
2313 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2314 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2315 break;
2316 }
2317 case TextApplyCommand:
2318 {
2319 /*
2320 Finished annotating.
2321 */
2322 annotate_info->width=(unsigned int) XTextWidth(font_info,
2323 annotate_info->text,(int) strlen(annotate_info->text));
2324 XRefreshWindow(display,&windows->image,&text_event);
2325 state|=ExitState;
2326 break;
2327 }
2328 default:
2329 break;
2330 }
2331 continue;
2332 }
2333 /*
2334 Erase text cursor.
2335 */
2336 text_event.xexpose.x=x;
2337 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2338 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2339 (unsigned int) text_event.xexpose.width,(unsigned int)
2340 text_event.xexpose.height,MagickFalse);
2341 XRefreshWindow(display,&windows->image,&text_event);
2342 switch (event.type)
2343 {
2344 case ButtonPress:
2345 {
2346 if (event.xbutton.window != windows->image.id)
2347 break;
2348 if (event.xbutton.button == Button2)
2349 {
2350 /*
2351 Request primary selection.
2352 */
2353 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2354 windows->image.id,CurrentTime);
2355 break;
2356 }
2357 break;
2358 }
2359 case Expose:
2360 {
2361 if (event.xexpose.count == 0)
2362 {
2363 XAnnotateInfo
2364 *text_info;
2365
2366 /*
2367 Refresh Image window.
2368 */
2369 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2370 text_info=annotate_info;
2371 while (text_info != (XAnnotateInfo *) NULL)
2372 {
2373 if (annotate_info->stencil == ForegroundStencil)
2374 (void) XDrawString(display,windows->image.id,annotate_context,
2375 text_info->x,text_info->y,text_info->text,
2376 (int) strlen(text_info->text));
2377 else
2378 (void) XDrawImageString(display,windows->image.id,
2379 annotate_context,text_info->x,text_info->y,text_info->text,
2380 (int) strlen(text_info->text));
2381 text_info=text_info->previous;
2382 }
2383 (void) XDrawString(display,windows->image.id,annotate_context,
2384 x,y,"_",1);
2385 }
2386 break;
2387 }
2388 case KeyPress:
2389 {
2390 int
2391 length;
2392
2393 if (event.xkey.window != windows->image.id)
2394 break;
2395 /*
2396 Respond to a user key press.
2397 */
2398 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2399 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2400 *(command+length)='\0';
2401 if (((event.xkey.state & ControlMask) != 0) ||
2402 ((event.xkey.state & Mod1Mask) != 0))
2403 state|=ModifierState;
2404 if ((state & ModifierState) != 0)
2405 switch ((int) key_symbol)
2406 {
2407 case XK_u:
2408 case XK_U:
2409 {
2410 key_symbol=DeleteCommand;
2411 break;
2412 }
2413 default:
2414 break;
2415 }
2416 switch ((int) key_symbol)
2417 {
2418 case XK_BackSpace:
2419 {
2420 /*
2421 Erase one character.
2422 */
2423 if (p == annotate_info->text)
2424 {
2425 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2426 break;
2427 else
2428 {
2429 /*
2430 Go to end of the previous line of text.
2431 */
2432 annotate_info=annotate_info->previous;
2433 p=annotate_info->text;
2434 x=annotate_info->x+annotate_info->width;
2435 y=annotate_info->y;
2436 if (annotate_info->width != 0)
2437 p+=strlen(annotate_info->text);
2438 break;
2439 }
2440 }
2441 p--;
2442 x-=XTextWidth(font_info,p,1);
2443 text_event.xexpose.x=x;
2444 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2445 XRefreshWindow(display,&windows->image,&text_event);
2446 break;
2447 }
2448 case XK_bracketleft:
2449 {
2450 key_symbol=XK_Escape;
2451 break;
2452 }
2453 case DeleteCommand:
2454 {
2455 /*
2456 Erase the entire line of text.
2457 */
2458 while (p != annotate_info->text)
2459 {
2460 p--;
2461 x-=XTextWidth(font_info,p,1);
2462 text_event.xexpose.x=x;
2463 XRefreshWindow(display,&windows->image,&text_event);
2464 }
2465 break;
2466 }
2467 case XK_Escape:
2468 case XK_F20:
2469 {
2470 /*
2471 Finished annotating.
2472 */
2473 annotate_info->width=(unsigned int) XTextWidth(font_info,
2474 annotate_info->text,(int) strlen(annotate_info->text));
2475 XRefreshWindow(display,&windows->image,&text_event);
2476 state|=ExitState;
2477 break;
2478 }
2479 default:
2480 {
2481 /*
2482 Draw a single character on the Image window.
2483 */
2484 if ((state & ModifierState) != 0)
2485 break;
2486 if (*command == '\0')
2487 break;
2488 *p=(*command);
2489 if (annotate_info->stencil == ForegroundStencil)
2490 (void) XDrawString(display,windows->image.id,annotate_context,
2491 x,y,p,1);
2492 else
2493 (void) XDrawImageString(display,windows->image.id,
2494 annotate_context,x,y,p,1);
2495 x+=XTextWidth(font_info,p,1);
2496 p++;
2497 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2498 break;
2499 }
2500 case XK_Return:
2501 case XK_KP_Enter:
2502 {
2503 /*
2504 Advance to the next line of text.
2505 */
2506 *p='\0';
2507 annotate_info->width=(unsigned int) XTextWidth(font_info,
2508 annotate_info->text,(int) strlen(annotate_info->text));
2509 if (annotate_info->next != (XAnnotateInfo *) NULL)
2510 {
2511 /*
2512 Line of text already exists.
2513 */
2514 annotate_info=annotate_info->next;
2515 x=annotate_info->x;
2516 y=annotate_info->y;
2517 p=annotate_info->text;
2518 break;
2519 }
2520 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2521 sizeof(*annotate_info->next));
2522 if (annotate_info->next == (XAnnotateInfo *) NULL)
2523 return(MagickFalse);
2524 *annotate_info->next=(*annotate_info);
2525 annotate_info->next->previous=annotate_info;
2526 annotate_info=annotate_info->next;
2527 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2528 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2529 sizeof(*annotate_info->text));
2530 if (annotate_info->text == (char *) NULL)
2531 return(MagickFalse);
2532 annotate_info->y+=annotate_info->height;
2533 if (annotate_info->y > (int) windows->image.height)
2534 annotate_info->y=(int) annotate_info->height;
2535 annotate_info->next=(XAnnotateInfo *) NULL;
2536 x=annotate_info->x;
2537 y=annotate_info->y;
2538 p=annotate_info->text;
2539 break;
2540 }
2541 }
2542 break;
2543 }
2544 case KeyRelease:
2545 {
2546 /*
2547 Respond to a user key release.
2548 */
2549 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2550 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2551 state&=(~ModifierState);
2552 break;
2553 }
2554 case SelectionNotify:
2555 {
2556 Atom
2557 type;
2558
2559 int
2560 format;
2561
2562 unsigned char
2563 *data;
2564
cristyf2faecf2010-05-28 19:19:36 +00002565 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002566 after,
2567 length;
2568
2569 /*
2570 Obtain response from primary selection.
2571 */
2572 if (event.xselection.property == (Atom) None)
2573 break;
2574 status=XGetWindowProperty(display,event.xselection.requestor,
cristyecd0ab52010-05-30 14:59:20 +00002575 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
cristy3ed852e2009-09-05 21:47:34 +00002576 &type,&format,&length,&after,&data);
2577 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2578 (length == 0))
2579 break;
2580 /*
2581 Annotate Image window with primary selection.
2582 */
cristybb503372010-05-27 20:51:26 +00002583 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002584 {
2585 if ((char) data[i] != '\n')
2586 {
2587 /*
2588 Draw a single character on the Image window.
2589 */
2590 *p=(char) data[i];
2591 (void) XDrawString(display,windows->image.id,annotate_context,
2592 x,y,p,1);
2593 x+=XTextWidth(font_info,p,1);
2594 p++;
2595 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2596 continue;
2597 }
2598 /*
2599 Advance to the next line of text.
2600 */
2601 *p='\0';
2602 annotate_info->width=(unsigned int) XTextWidth(font_info,
2603 annotate_info->text,(int) strlen(annotate_info->text));
2604 if (annotate_info->next != (XAnnotateInfo *) NULL)
2605 {
2606 /*
2607 Line of text already exists.
2608 */
2609 annotate_info=annotate_info->next;
2610 x=annotate_info->x;
2611 y=annotate_info->y;
2612 p=annotate_info->text;
2613 continue;
2614 }
2615 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2616 sizeof(*annotate_info->next));
2617 if (annotate_info->next == (XAnnotateInfo *) NULL)
2618 return(MagickFalse);
2619 *annotate_info->next=(*annotate_info);
2620 annotate_info->next->previous=annotate_info;
2621 annotate_info=annotate_info->next;
2622 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2623 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2624 sizeof(*annotate_info->text));
2625 if (annotate_info->text == (char *) NULL)
2626 return(MagickFalse);
2627 annotate_info->y+=annotate_info->height;
2628 if (annotate_info->y > (int) windows->image.height)
2629 annotate_info->y=(int) annotate_info->height;
2630 annotate_info->next=(XAnnotateInfo *) NULL;
2631 x=annotate_info->x;
2632 y=annotate_info->y;
2633 p=annotate_info->text;
2634 }
2635 (void) XFree((void *) data);
2636 break;
2637 }
2638 default:
2639 break;
2640 }
2641 } while ((state & ExitState) == 0);
2642 (void) XFreeCursor(display,cursor);
2643 /*
2644 Annotation is relative to image configuration.
2645 */
2646 width=(unsigned int) image->columns;
2647 height=(unsigned int) image->rows;
2648 x=0;
2649 y=0;
2650 if (windows->image.crop_geometry != (char *) NULL)
2651 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2652 /*
2653 Initialize annotated image.
2654 */
2655 XSetCursorState(display,windows,MagickTrue);
2656 XCheckRefreshWindows(display,windows);
2657 while (annotate_info != (XAnnotateInfo *) NULL)
2658 {
2659 if (annotate_info->width == 0)
2660 {
2661 /*
2662 No text on this line-- go to the next line of text.
2663 */
2664 previous_info=annotate_info->previous;
2665 annotate_info->text=(char *)
2666 RelinquishMagickMemory(annotate_info->text);
2667 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2668 annotate_info=previous_info;
2669 continue;
2670 }
2671 /*
2672 Determine pixel index for box and pen color.
2673 */
2674 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2675 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002676 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002677 if (windows->pixel_info->pixels[i] ==
2678 windows->pixel_info->pen_colors[box_id].pixel)
2679 {
2680 windows->pixel_info->box_index=(unsigned short) i;
2681 break;
2682 }
2683 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2684 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002685 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002686 if (windows->pixel_info->pixels[i] ==
2687 windows->pixel_info->pen_colors[pen_id].pixel)
2688 {
2689 windows->pixel_info->pen_index=(unsigned short) i;
2690 break;
2691 }
2692 /*
2693 Define the annotate geometry string.
2694 */
2695 annotate_info->x=(int)
2696 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2697 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2698 windows->image.y)/windows->image.ximage->height;
2699 (void) FormatMagickString(annotate_info->geometry,MaxTextExtent,
2700 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2701 height*annotate_info->height/windows->image.ximage->height,
2702 annotate_info->x+x,annotate_info->y+y);
2703 /*
2704 Annotate image with text.
2705 */
2706 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2707 if (status == 0)
2708 return(MagickFalse);
2709 /*
2710 Free up memory.
2711 */
2712 previous_info=annotate_info->previous;
2713 annotate_info->text=DestroyString(annotate_info->text);
2714 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2715 annotate_info=previous_info;
2716 }
2717 (void) XSetForeground(display,annotate_context,
2718 windows->pixel_info->foreground_color.pixel);
2719 (void) XSetBackground(display,annotate_context,
2720 windows->pixel_info->background_color.pixel);
2721 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2722 XSetCursorState(display,windows,MagickFalse);
2723 (void) XFreeFont(display,font_info);
2724 /*
2725 Update image configuration.
2726 */
2727 XConfigureImageColormap(display,resource_info,windows,image);
2728 (void) XConfigureImage(display,resource_info,windows,image);
2729 return(MagickTrue);
2730}
2731
2732/*
2733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2734% %
2735% %
2736% %
2737+ X B a c k g r o u n d I m a g e %
2738% %
2739% %
2740% %
2741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2742%
2743% XBackgroundImage() displays the image in the background of a window.
2744%
2745% The format of the XBackgroundImage method is:
2746%
2747% MagickBooleanType XBackgroundImage(Display *display,
2748% XResourceInfo *resource_info,XWindows *windows,Image **image)
2749%
2750% A description of each parameter follows:
2751%
2752% o display: Specifies a connection to an X server; returned from
2753% XOpenDisplay.
2754%
2755% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2756%
2757% o windows: Specifies a pointer to a XWindows structure.
2758%
2759% o image: the image.
2760%
2761*/
2762static MagickBooleanType XBackgroundImage(Display *display,
2763 XResourceInfo *resource_info,XWindows *windows,Image **image)
2764{
2765#define BackgroundImageTag "Background/Image"
2766
2767 int
2768 status;
2769
2770 static char
2771 window_id[MaxTextExtent] = "root";
2772
2773 XResourceInfo
2774 background_resources;
2775
2776 /*
2777 Put image in background.
2778 */
2779 status=XDialogWidget(display,windows,"Background",
2780 "Enter window id (id 0x00 selects window with pointer):",window_id);
2781 if (*window_id == '\0')
2782 return(MagickFalse);
2783 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2784 XInfoWidget(display,windows,BackgroundImageTag);
2785 XSetCursorState(display,windows,MagickTrue);
2786 XCheckRefreshWindows(display,windows);
2787 background_resources=(*resource_info);
2788 background_resources.window_id=window_id;
2789 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2790 status=XDisplayBackgroundImage(display,&background_resources,*image);
2791 if (status != MagickFalse)
2792 XClientMessage(display,windows->image.id,windows->im_protocols,
2793 windows->im_retain_colors,CurrentTime);
2794 XSetCursorState(display,windows,MagickFalse);
2795 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2796 return(MagickTrue);
2797}
2798
2799/*
2800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801% %
2802% %
2803% %
2804+ X C h o p I m a g e %
2805% %
2806% %
2807% %
2808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809%
2810% XChopImage() chops the X image.
2811%
2812% The format of the XChopImage method is:
2813%
2814% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2815% XWindows *windows,Image **image)
2816%
2817% A description of each parameter follows:
2818%
2819% o display: Specifies a connection to an X server; returned from
2820% XOpenDisplay.
2821%
2822% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2823%
2824% o windows: Specifies a pointer to a XWindows structure.
2825%
2826% o image: the image.
2827%
2828*/
2829static MagickBooleanType XChopImage(Display *display,
2830 XResourceInfo *resource_info,XWindows *windows,Image **image)
2831{
2832 static const char
2833 *ChopMenu[] =
2834 {
2835 "Direction",
2836 "Help",
2837 "Dismiss",
2838 (char *) NULL
2839 };
2840
2841 static ModeType
2842 direction = HorizontalChopCommand;
2843
2844 static const ModeType
2845 ChopCommands[] =
2846 {
2847 ChopDirectionCommand,
2848 ChopHelpCommand,
2849 ChopDismissCommand
2850 },
2851 DirectionCommands[] =
2852 {
2853 HorizontalChopCommand,
2854 VerticalChopCommand
2855 };
2856
2857 char
2858 text[MaxTextExtent];
2859
2860 Image
2861 *chop_image;
2862
2863 int
2864 id,
2865 x,
2866 y;
2867
2868 MagickRealType
2869 scale_factor;
2870
2871 RectangleInfo
2872 chop_info;
2873
2874 unsigned int
2875 distance,
2876 height,
2877 width;
2878
cristybb503372010-05-27 20:51:26 +00002879 size_t
cristy3ed852e2009-09-05 21:47:34 +00002880 state;
2881
2882 XEvent
2883 event;
2884
2885 XSegment
2886 segment_info;
2887
2888 /*
2889 Map Command widget.
2890 */
2891 (void) CloneString(&windows->command.name,"Chop");
2892 windows->command.data=1;
2893 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2894 (void) XMapRaised(display,windows->command.id);
2895 XClientMessage(display,windows->image.id,windows->im_protocols,
2896 windows->im_update_widget,CurrentTime);
2897 /*
2898 Track pointer until button 1 is pressed.
2899 */
2900 XQueryPosition(display,windows->image.id,&x,&y);
2901 (void) XSelectInput(display,windows->image.id,
2902 windows->image.attributes.event_mask | PointerMotionMask);
2903 state=DefaultState;
2904 do
2905 {
2906 if (windows->info.mapped != MagickFalse)
2907 {
2908 /*
2909 Display pointer position.
2910 */
2911 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
2912 x+windows->image.x,y+windows->image.y);
2913 XInfoWidget(display,windows,text);
2914 }
2915 /*
2916 Wait for next event.
2917 */
2918 XScreenEvent(display,windows,&event);
2919 if (event.xany.window == windows->command.id)
2920 {
2921 /*
2922 Select a command from the Command widget.
2923 */
2924 id=XCommandWidget(display,windows,ChopMenu,&event);
2925 if (id < 0)
2926 continue;
2927 switch (ChopCommands[id])
2928 {
2929 case ChopDirectionCommand:
2930 {
2931 char
2932 command[MaxTextExtent];
2933
2934 static const char
2935 *Directions[] =
2936 {
2937 "horizontal",
2938 "vertical",
2939 (char *) NULL,
2940 };
2941
2942 /*
2943 Select a command from the pop-up menu.
2944 */
2945 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2946 if (id >= 0)
2947 direction=DirectionCommands[id];
2948 break;
2949 }
2950 case ChopHelpCommand:
2951 {
2952 XTextViewWidget(display,resource_info,windows,MagickFalse,
2953 "Help Viewer - Image Chop",ImageChopHelp);
2954 break;
2955 }
2956 case ChopDismissCommand:
2957 {
2958 /*
2959 Prematurely exit.
2960 */
2961 state|=EscapeState;
2962 state|=ExitState;
2963 break;
2964 }
2965 default:
2966 break;
2967 }
2968 continue;
2969 }
2970 switch (event.type)
2971 {
2972 case ButtonPress:
2973 {
2974 if (event.xbutton.button != Button1)
2975 break;
2976 if (event.xbutton.window != windows->image.id)
2977 break;
2978 /*
2979 User has committed to start point of chopping line.
2980 */
2981 segment_info.x1=(short int) event.xbutton.x;
2982 segment_info.x2=(short int) event.xbutton.x;
2983 segment_info.y1=(short int) event.xbutton.y;
2984 segment_info.y2=(short int) event.xbutton.y;
2985 state|=ExitState;
2986 break;
2987 }
2988 case ButtonRelease:
2989 break;
2990 case Expose:
2991 break;
2992 case KeyPress:
2993 {
2994 char
2995 command[MaxTextExtent];
2996
2997 KeySym
2998 key_symbol;
2999
3000 if (event.xkey.window != windows->image.id)
3001 break;
3002 /*
3003 Respond to a user key press.
3004 */
3005 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3006 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3007 switch ((int) key_symbol)
3008 {
3009 case XK_Escape:
3010 case XK_F20:
3011 {
3012 /*
3013 Prematurely exit.
3014 */
3015 state|=EscapeState;
3016 state|=ExitState;
3017 break;
3018 }
3019 case XK_F1:
3020 case XK_Help:
3021 {
3022 (void) XSetFunction(display,windows->image.highlight_context,
3023 GXcopy);
3024 XTextViewWidget(display,resource_info,windows,MagickFalse,
3025 "Help Viewer - Image Chop",ImageChopHelp);
3026 (void) XSetFunction(display,windows->image.highlight_context,
3027 GXinvert);
3028 break;
3029 }
3030 default:
3031 {
3032 (void) XBell(display,0);
3033 break;
3034 }
3035 }
3036 break;
3037 }
3038 case MotionNotify:
3039 {
3040 /*
3041 Map and unmap Info widget as text cursor crosses its boundaries.
3042 */
3043 x=event.xmotion.x;
3044 y=event.xmotion.y;
3045 if (windows->info.mapped != MagickFalse)
3046 {
3047 if ((x < (int) (windows->info.x+windows->info.width)) &&
3048 (y < (int) (windows->info.y+windows->info.height)))
3049 (void) XWithdrawWindow(display,windows->info.id,
3050 windows->info.screen);
3051 }
3052 else
3053 if ((x > (int) (windows->info.x+windows->info.width)) ||
3054 (y > (int) (windows->info.y+windows->info.height)))
3055 (void) XMapWindow(display,windows->info.id);
3056 }
3057 }
3058 } while ((state & ExitState) == 0);
3059 (void) XSelectInput(display,windows->image.id,
3060 windows->image.attributes.event_mask);
3061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3062 if ((state & EscapeState) != 0)
3063 return(MagickTrue);
3064 /*
3065 Draw line as pointer moves until the mouse button is released.
3066 */
3067 chop_info.width=0;
3068 chop_info.height=0;
3069 chop_info.x=0;
3070 chop_info.y=0;
3071 distance=0;
3072 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3073 state=DefaultState;
3074 do
3075 {
3076 if (distance > 9)
3077 {
3078 /*
3079 Display info and draw chopping line.
3080 */
3081 if (windows->info.mapped == MagickFalse)
3082 (void) XMapWindow(display,windows->info.id);
cristye8c25f92010-06-03 00:53:06 +00003083 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00003084 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00003085 chop_info.height,(double) chop_info.x,(double) chop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003086 XInfoWidget(display,windows,text);
3087 XHighlightLine(display,windows->image.id,
3088 windows->image.highlight_context,&segment_info);
3089 }
3090 else
3091 if (windows->info.mapped != MagickFalse)
3092 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3093 /*
3094 Wait for next event.
3095 */
3096 XScreenEvent(display,windows,&event);
3097 if (distance > 9)
3098 XHighlightLine(display,windows->image.id,
3099 windows->image.highlight_context,&segment_info);
3100 switch (event.type)
3101 {
3102 case ButtonPress:
3103 {
3104 segment_info.x2=(short int) event.xmotion.x;
3105 segment_info.y2=(short int) event.xmotion.y;
3106 break;
3107 }
3108 case ButtonRelease:
3109 {
3110 /*
3111 User has committed to chopping line.
3112 */
3113 segment_info.x2=(short int) event.xbutton.x;
3114 segment_info.y2=(short int) event.xbutton.y;
3115 state|=ExitState;
3116 break;
3117 }
3118 case Expose:
3119 break;
3120 case MotionNotify:
3121 {
3122 segment_info.x2=(short int) event.xmotion.x;
3123 segment_info.y2=(short int) event.xmotion.y;
3124 }
3125 default:
3126 break;
3127 }
3128 /*
3129 Check boundary conditions.
3130 */
3131 if (segment_info.x2 < 0)
3132 segment_info.x2=0;
3133 else
3134 if (segment_info.x2 > windows->image.ximage->width)
3135 segment_info.x2=windows->image.ximage->width;
3136 if (segment_info.y2 < 0)
3137 segment_info.y2=0;
3138 else
3139 if (segment_info.y2 > windows->image.ximage->height)
3140 segment_info.y2=windows->image.ximage->height;
3141 distance=(unsigned int)
3142 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3143 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3144 /*
3145 Compute chopping geometry.
3146 */
3147 if (direction == HorizontalChopCommand)
3148 {
cristybb503372010-05-27 20:51:26 +00003149 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
cristy3ed852e2009-09-05 21:47:34 +00003150 chop_info.x=windows->image.x+segment_info.x1;
3151 chop_info.height=0;
3152 chop_info.y=0;
3153 if (segment_info.x1 > (int) segment_info.x2)
3154 {
cristybb503372010-05-27 20:51:26 +00003155 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
cristy3ed852e2009-09-05 21:47:34 +00003156 chop_info.x=windows->image.x+segment_info.x2;
3157 }
3158 }
3159 else
3160 {
3161 chop_info.width=0;
cristybb503372010-05-27 20:51:26 +00003162 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
cristy3ed852e2009-09-05 21:47:34 +00003163 chop_info.x=0;
3164 chop_info.y=windows->image.y+segment_info.y1;
3165 if (segment_info.y1 > segment_info.y2)
3166 {
cristybb503372010-05-27 20:51:26 +00003167 chop_info.height=(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003168 (segment_info.y1-segment_info.y2+1);
3169 chop_info.y=windows->image.y+segment_info.y2;
3170 }
3171 }
3172 } while ((state & ExitState) == 0);
3173 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3174 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3175 if (distance <= 9)
3176 return(MagickTrue);
3177 /*
3178 Image chopping is relative to image configuration.
3179 */
3180 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3181 XSetCursorState(display,windows,MagickTrue);
3182 XCheckRefreshWindows(display,windows);
3183 windows->image.window_changes.width=windows->image.ximage->width-
3184 (unsigned int) chop_info.width;
3185 windows->image.window_changes.height=windows->image.ximage->height-
3186 (unsigned int) chop_info.height;
3187 width=(unsigned int) (*image)->columns;
3188 height=(unsigned int) (*image)->rows;
3189 x=0;
3190 y=0;
3191 if (windows->image.crop_geometry != (char *) NULL)
3192 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3193 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3194 chop_info.x+=x;
3195 chop_info.x=(int) (scale_factor*chop_info.x+0.5);
3196 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3197 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3198 chop_info.y+=y;
3199 chop_info.y=(int) (scale_factor*chop_info.y+0.5);
3200 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3201 /*
3202 Chop image.
3203 */
3204 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3205 XSetCursorState(display,windows,MagickFalse);
3206 if (chop_image == (Image *) NULL)
3207 return(MagickFalse);
3208 *image=DestroyImage(*image);
3209 *image=chop_image;
3210 /*
3211 Update image configuration.
3212 */
3213 XConfigureImageColormap(display,resource_info,windows,*image);
3214 (void) XConfigureImage(display,resource_info,windows,*image);
3215 return(MagickTrue);
3216}
3217
3218/*
3219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3220% %
3221% %
3222% %
3223+ X C o l o r E d i t I m a g e %
3224% %
3225% %
3226% %
3227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3228%
3229% XColorEditImage() allows the user to interactively change the color of one
3230% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3231%
3232% The format of the XColorEditImage method is:
3233%
3234% MagickBooleanType XColorEditImage(Display *display,
3235% XResourceInfo *resource_info,XWindows *windows,Image **image)
3236%
3237% A description of each parameter follows:
3238%
3239% o display: Specifies a connection to an X server; returned from
3240% XOpenDisplay.
3241%
3242% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3243%
3244% o windows: Specifies a pointer to a XWindows structure.
3245%
3246% o image: the image; returned from ReadImage.
3247%
3248*/
3249
3250
3251static MagickBooleanType XColorEditImage(Display *display,
3252 XResourceInfo *resource_info,XWindows *windows,Image **image)
3253{
3254 static const char
3255 *ColorEditMenu[] =
3256 {
3257 "Method",
3258 "Pixel Color",
3259 "Border Color",
3260 "Fuzz",
3261 "Undo",
3262 "Help",
3263 "Dismiss",
3264 (char *) NULL
3265 };
3266
3267 static const ModeType
3268 ColorEditCommands[] =
3269 {
3270 ColorEditMethodCommand,
3271 ColorEditColorCommand,
3272 ColorEditBorderCommand,
3273 ColorEditFuzzCommand,
3274 ColorEditUndoCommand,
3275 ColorEditHelpCommand,
3276 ColorEditDismissCommand
3277 };
3278
3279 static PaintMethod
3280 method = PointMethod;
3281
3282 static unsigned int
3283 pen_id = 0;
3284
3285 static XColor
3286 border_color = { 0, 0, 0, 0, 0, 0 };
3287
3288 char
3289 command[MaxTextExtent],
3290 text[MaxTextExtent];
3291
3292 Cursor
3293 cursor;
3294
3295 ExceptionInfo
3296 *exception;
3297
3298 int
3299 entry,
3300 id,
3301 x,
3302 x_offset,
3303 y,
3304 y_offset;
3305
3306 register PixelPacket
3307 *q;
3308
cristybb503372010-05-27 20:51:26 +00003309 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003310 i;
3311
3312 unsigned int
3313 height,
3314 width;
3315
cristybb503372010-05-27 20:51:26 +00003316 size_t
cristy3ed852e2009-09-05 21:47:34 +00003317 state;
3318
3319 XColor
3320 color;
3321
3322 XEvent
3323 event;
3324
3325 /*
3326 Map Command widget.
3327 */
3328 (void) CloneString(&windows->command.name,"Color Edit");
3329 windows->command.data=4;
3330 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3331 (void) XMapRaised(display,windows->command.id);
3332 XClientMessage(display,windows->image.id,windows->im_protocols,
3333 windows->im_update_widget,CurrentTime);
3334 /*
3335 Make cursor.
3336 */
3337 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3338 resource_info->background_color,resource_info->foreground_color);
3339 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3340 /*
3341 Track pointer until button 1 is pressed.
3342 */
3343 XQueryPosition(display,windows->image.id,&x,&y);
3344 (void) XSelectInput(display,windows->image.id,
3345 windows->image.attributes.event_mask | PointerMotionMask);
3346 state=DefaultState;
3347 do
3348 {
3349 if (windows->info.mapped != MagickFalse)
3350 {
3351 /*
3352 Display pointer position.
3353 */
3354 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
3355 x+windows->image.x,y+windows->image.y);
3356 XInfoWidget(display,windows,text);
3357 }
3358 /*
3359 Wait for next event.
3360 */
3361 XScreenEvent(display,windows,&event);
3362 if (event.xany.window == windows->command.id)
3363 {
3364 /*
3365 Select a command from the Command widget.
3366 */
3367 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3368 if (id < 0)
3369 {
3370 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3371 continue;
3372 }
3373 switch (ColorEditCommands[id])
3374 {
3375 case ColorEditMethodCommand:
3376 {
3377 char
3378 **methods;
3379
3380 /*
3381 Select a method from the pop-up menu.
3382 */
3383 methods=(char **) GetMagickOptions(MagickMethodOptions);
3384 if (methods == (char **) NULL)
3385 break;
3386 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3387 (const char **) methods,command);
3388 if (entry >= 0)
3389 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
3390 MagickFalse,methods[entry]);
3391 methods=DestroyStringList(methods);
3392 break;
3393 }
3394 case ColorEditColorCommand:
3395 {
3396 const char
3397 *ColorMenu[MaxNumberPens];
3398
3399 int
3400 pen_number;
3401
3402 /*
3403 Initialize menu selections.
3404 */
3405 for (i=0; i < (int) (MaxNumberPens-2); i++)
3406 ColorMenu[i]=resource_info->pen_colors[i];
3407 ColorMenu[MaxNumberPens-2]="Browser...";
3408 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3409 /*
3410 Select a pen color from the pop-up menu.
3411 */
3412 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3413 (const char **) ColorMenu,command);
3414 if (pen_number < 0)
3415 break;
3416 if (pen_number == (MaxNumberPens-2))
3417 {
3418 static char
3419 color_name[MaxTextExtent] = "gray";
3420
3421 /*
3422 Select a pen color from a dialog.
3423 */
3424 resource_info->pen_colors[pen_number]=color_name;
3425 XColorBrowserWidget(display,windows,"Select",color_name);
3426 if (*color_name == '\0')
3427 break;
3428 }
3429 /*
3430 Set pen color.
3431 */
3432 (void) XParseColor(display,windows->map_info->colormap,
3433 resource_info->pen_colors[pen_number],&color);
3434 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3435 (unsigned int) MaxColors,&color);
3436 windows->pixel_info->pen_colors[pen_number]=color;
3437 pen_id=(unsigned int) pen_number;
3438 break;
3439 }
3440 case ColorEditBorderCommand:
3441 {
3442 const char
3443 *ColorMenu[MaxNumberPens];
3444
3445 int
3446 pen_number;
3447
3448 /*
3449 Initialize menu selections.
3450 */
3451 for (i=0; i < (int) (MaxNumberPens-2); i++)
3452 ColorMenu[i]=resource_info->pen_colors[i];
3453 ColorMenu[MaxNumberPens-2]="Browser...";
3454 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3455 /*
3456 Select a pen color from the pop-up menu.
3457 */
3458 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3459 (const char **) ColorMenu,command);
3460 if (pen_number < 0)
3461 break;
3462 if (pen_number == (MaxNumberPens-2))
3463 {
3464 static char
3465 color_name[MaxTextExtent] = "gray";
3466
3467 /*
3468 Select a pen color from a dialog.
3469 */
3470 resource_info->pen_colors[pen_number]=color_name;
3471 XColorBrowserWidget(display,windows,"Select",color_name);
3472 if (*color_name == '\0')
3473 break;
3474 }
3475 /*
3476 Set border color.
3477 */
3478 (void) XParseColor(display,windows->map_info->colormap,
3479 resource_info->pen_colors[pen_number],&border_color);
3480 break;
3481 }
3482 case ColorEditFuzzCommand:
3483 {
3484 static char
3485 fuzz[MaxTextExtent];
3486
3487 static const char
3488 *FuzzMenu[] =
3489 {
3490 "0%",
3491 "2%",
3492 "5%",
3493 "10%",
3494 "15%",
3495 "Dialog...",
3496 (char *) NULL,
3497 };
3498
3499 /*
3500 Select a command from the pop-up menu.
3501 */
3502 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3503 command);
3504 if (entry < 0)
3505 break;
3506 if (entry != 5)
3507 {
cristy40a08ad2010-02-09 02:27:44 +00003508 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
3509 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003510 break;
3511 }
3512 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3513 (void) XDialogWidget(display,windows,"Ok",
3514 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3515 if (*fuzz == '\0')
3516 break;
3517 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00003518 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003519 break;
3520 }
3521 case ColorEditUndoCommand:
3522 {
3523 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3524 image);
3525 break;
3526 }
3527 case ColorEditHelpCommand:
3528 default:
3529 {
3530 XTextViewWidget(display,resource_info,windows,MagickFalse,
3531 "Help Viewer - Image Annotation",ImageColorEditHelp);
3532 break;
3533 }
3534 case ColorEditDismissCommand:
3535 {
3536 /*
3537 Prematurely exit.
3538 */
3539 state|=EscapeState;
3540 state|=ExitState;
3541 break;
3542 }
3543 }
3544 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3545 continue;
3546 }
3547 switch (event.type)
3548 {
3549 case ButtonPress:
3550 {
3551 if (event.xbutton.button != Button1)
3552 break;
3553 if ((event.xbutton.window != windows->image.id) &&
3554 (event.xbutton.window != windows->magnify.id))
3555 break;
3556 /*
3557 exit loop.
3558 */
3559 x=event.xbutton.x;
3560 y=event.xbutton.y;
3561 (void) XMagickCommand(display,resource_info,windows,
3562 SaveToUndoBufferCommand,image);
3563 state|=UpdateConfigurationState;
3564 break;
3565 }
3566 case ButtonRelease:
3567 {
3568 if (event.xbutton.button != Button1)
3569 break;
3570 if ((event.xbutton.window != windows->image.id) &&
3571 (event.xbutton.window != windows->magnify.id))
3572 break;
3573 /*
3574 Update colormap information.
3575 */
3576 x=event.xbutton.x;
3577 y=event.xbutton.y;
3578 XConfigureImageColormap(display,resource_info,windows,*image);
3579 (void) XConfigureImage(display,resource_info,windows,*image);
3580 XInfoWidget(display,windows,text);
3581 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3582 state&=(~UpdateConfigurationState);
3583 break;
3584 }
3585 case Expose:
3586 break;
3587 case KeyPress:
3588 {
3589 KeySym
3590 key_symbol;
3591
3592 if (event.xkey.window == windows->magnify.id)
3593 {
3594 Window
3595 window;
3596
3597 window=windows->magnify.id;
3598 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3599 }
3600 if (event.xkey.window != windows->image.id)
3601 break;
3602 /*
3603 Respond to a user key press.
3604 */
3605 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3606 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3607 switch ((int) key_symbol)
3608 {
3609 case XK_Escape:
3610 case XK_F20:
3611 {
3612 /*
3613 Prematurely exit.
3614 */
3615 state|=ExitState;
3616 break;
3617 }
3618 case XK_F1:
3619 case XK_Help:
3620 {
3621 XTextViewWidget(display,resource_info,windows,MagickFalse,
3622 "Help Viewer - Image Annotation",ImageColorEditHelp);
3623 break;
3624 }
3625 default:
3626 {
3627 (void) XBell(display,0);
3628 break;
3629 }
3630 }
3631 break;
3632 }
3633 case MotionNotify:
3634 {
3635 /*
3636 Map and unmap Info widget as cursor crosses its boundaries.
3637 */
3638 x=event.xmotion.x;
3639 y=event.xmotion.y;
3640 if (windows->info.mapped != MagickFalse)
3641 {
3642 if ((x < (int) (windows->info.x+windows->info.width)) &&
3643 (y < (int) (windows->info.y+windows->info.height)))
3644 (void) XWithdrawWindow(display,windows->info.id,
3645 windows->info.screen);
3646 }
3647 else
3648 if ((x > (int) (windows->info.x+windows->info.width)) ||
3649 (y > (int) (windows->info.y+windows->info.height)))
3650 (void) XMapWindow(display,windows->info.id);
3651 break;
3652 }
3653 default:
3654 break;
3655 }
3656 if (event.xany.window == windows->magnify.id)
3657 {
3658 x=windows->magnify.x-windows->image.x;
3659 y=windows->magnify.y-windows->image.y;
3660 }
3661 x_offset=x;
3662 y_offset=y;
3663 if ((state & UpdateConfigurationState) != 0)
3664 {
3665 int
3666 x,
3667 y;
3668
3669 /*
3670 Pixel edit is relative to image configuration.
3671 */
3672 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3673 MagickTrue);
3674 color=windows->pixel_info->pen_colors[pen_id];
3675 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3676 width=(unsigned int) (*image)->columns;
3677 height=(unsigned int) (*image)->rows;
3678 x=0;
3679 y=0;
3680 if (windows->image.crop_geometry != (char *) NULL)
3681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3682 &width,&height);
3683 x_offset=(int)
3684 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3685 y_offset=(int)
3686 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3687 if ((x_offset < 0) || (y_offset < 0))
3688 continue;
cristybb503372010-05-27 20:51:26 +00003689 if ((x_offset >= (ssize_t) (*image)->columns) ||
3690 (y_offset >= (ssize_t) (*image)->rows))
cristy3ed852e2009-09-05 21:47:34 +00003691 continue;
3692 exception=(&(*image)->exception);
3693 switch (method)
3694 {
3695 case PointMethod:
3696 default:
3697 {
3698 /*
3699 Update color information using point algorithm.
3700 */
3701 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3702 return(MagickFalse);
3703 q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
3704 if (q == (PixelPacket *) NULL)
3705 break;
3706 q->red=ScaleShortToQuantum(color.red);
3707 q->green=ScaleShortToQuantum(color.green);
3708 q->blue=ScaleShortToQuantum(color.blue);
3709 (void) SyncAuthenticPixels(*image,&(*image)->exception);
3710 break;
3711 }
3712 case ReplaceMethod:
3713 {
3714 PixelPacket
3715 target;
3716
3717 /*
3718 Update color information using replace algorithm.
3719 */
3720 (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
3721 &(*image)->exception);
3722 if ((*image)->storage_class == DirectClass)
3723 {
cristybb503372010-05-27 20:51:26 +00003724 for (y=0; y < (ssize_t) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003725 {
cristyf154a4e2009-12-19 02:44:50 +00003726 q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,
3727 exception);
cristy3ed852e2009-09-05 21:47:34 +00003728 if (q == (PixelPacket *) NULL)
3729 break;
3730 for (x=0; x < (int) (*image)->columns; x++)
3731 {
3732 if (IsColorSimilar(*image,q,&target))
3733 {
3734 q->red=ScaleShortToQuantum(color.red);
3735 q->green=ScaleShortToQuantum(color.green);
3736 q->blue=ScaleShortToQuantum(color.blue);
3737 }
3738 q++;
3739 }
3740 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
3741 break;
3742 }
3743 }
3744 else
3745 {
3746 for (i=0; i < (int) (*image)->colors; i++)
3747 if (IsColorSimilar(*image,(*image)->colormap+i,&target))
3748 {
3749 (*image)->colormap[i].red=ScaleShortToQuantum(color.red);
3750 (*image)->colormap[i].green=ScaleShortToQuantum(
3751 color.green);
3752 (*image)->colormap[i].blue=ScaleShortToQuantum(
3753 color.blue);
3754 }
3755 (void) SyncImage(*image);
3756 }
3757 break;
3758 }
3759 case FloodfillMethod:
3760 case FillToBorderMethod:
3761 {
3762 DrawInfo
3763 *draw_info;
3764
3765 MagickPixelPacket
3766 target;
3767
3768 /*
3769 Update color information using floodfill algorithm.
3770 */
3771 (void) GetOneVirtualMagickPixel(*image,x_offset,y_offset,&target,
3772 exception);
3773 if (method == FillToBorderMethod)
3774 {
3775 target.red=(MagickRealType)
3776 ScaleShortToQuantum(border_color.red);
3777 target.green=(MagickRealType)
3778 ScaleShortToQuantum(border_color.green);
3779 target.blue=(MagickRealType)
3780 ScaleShortToQuantum(border_color.blue);
3781 }
3782 draw_info=CloneDrawInfo(resource_info->image_info,
3783 (DrawInfo *) NULL);
3784 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3785 &draw_info->fill,exception);
3786 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
3787 x_offset,y_offset,method == FloodfillMethod ? MagickFalse :
3788 MagickTrue);
3789 draw_info=DestroyDrawInfo(draw_info);
3790 break;
3791 }
3792 case ResetMethod:
3793 {
3794 /*
3795 Update color information using reset algorithm.
3796 */
3797 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3798 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +00003799 for (y=0; y < (ssize_t) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003800 {
3801 q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
3802 if (q == (PixelPacket *) NULL)
3803 break;
3804 for (x=0; x < (int) (*image)->columns; x++)
3805 {
3806 q->red=ScaleShortToQuantum(color.red);
3807 q->green=ScaleShortToQuantum(color.green);
3808 q->blue=ScaleShortToQuantum(color.blue);
3809 q++;
3810 }
3811 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
3812 break;
3813 }
3814 break;
3815 }
3816 }
3817 state&=(~UpdateConfigurationState);
3818 }
3819 } while ((state & ExitState) == 0);
3820 (void) XSelectInput(display,windows->image.id,
3821 windows->image.attributes.event_mask);
3822 XSetCursorState(display,windows,MagickFalse);
3823 (void) XFreeCursor(display,cursor);
3824 return(MagickTrue);
3825}
3826
3827/*
3828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3829% %
3830% %
3831% %
3832+ X C o m p o s i t e I m a g e %
3833% %
3834% %
3835% %
3836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837%
3838% XCompositeImage() requests an image name from the user, reads the image and
3839% composites it with the X window image at a location the user chooses with
3840% the pointer.
3841%
3842% The format of the XCompositeImage method is:
3843%
3844% MagickBooleanType XCompositeImage(Display *display,
3845% XResourceInfo *resource_info,XWindows *windows,Image *image)
3846%
3847% A description of each parameter follows:
3848%
3849% o display: Specifies a connection to an X server; returned from
3850% XOpenDisplay.
3851%
3852% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3853%
3854% o windows: Specifies a pointer to a XWindows structure.
3855%
3856% o image: the image; returned from ReadImage.
3857%
3858*/
3859static MagickBooleanType XCompositeImage(Display *display,
3860 XResourceInfo *resource_info,XWindows *windows,Image *image)
3861{
3862 static char
3863 displacement_geometry[MaxTextExtent] = "30x30",
3864 filename[MaxTextExtent] = "\0";
3865
3866 static const char
3867 *CompositeMenu[] =
3868 {
3869 "Operators",
3870 "Dissolve",
3871 "Displace",
3872 "Help",
3873 "Dismiss",
3874 (char *) NULL
3875 };
3876
3877 static CompositeOperator
3878 compose = CopyCompositeOp;
3879
3880 static const ModeType
3881 CompositeCommands[] =
3882 {
3883 CompositeOperatorsCommand,
3884 CompositeDissolveCommand,
3885 CompositeDisplaceCommand,
3886 CompositeHelpCommand,
3887 CompositeDismissCommand
3888 };
3889
3890 char
3891 text[MaxTextExtent];
3892
3893 Cursor
3894 cursor;
3895
3896 Image
3897 *composite_image;
3898
3899 int
3900 entry,
3901 id,
3902 x,
3903 y;
3904
3905 MagickRealType
3906 blend,
3907 scale_factor;
3908
3909 RectangleInfo
3910 highlight_info,
3911 composite_info;
3912
3913 unsigned int
3914 height,
3915 width;
3916
cristybb503372010-05-27 20:51:26 +00003917 size_t
cristy3ed852e2009-09-05 21:47:34 +00003918 state;
3919
3920 XEvent
3921 event;
3922
3923 /*
3924 Request image file name from user.
3925 */
3926 XFileBrowserWidget(display,windows,"Composite",filename);
3927 if (*filename == '\0')
3928 return(MagickTrue);
3929 /*
3930 Read image.
3931 */
3932 XSetCursorState(display,windows,MagickTrue);
3933 XCheckRefreshWindows(display,windows);
3934 (void) CopyMagickString(resource_info->image_info->filename,filename,
3935 MaxTextExtent);
3936 composite_image=ReadImage(resource_info->image_info,&image->exception);
3937 CatchException(&image->exception);
3938 XSetCursorState(display,windows,MagickFalse);
3939 if (composite_image == (Image *) NULL)
3940 return(MagickFalse);
3941 /*
3942 Map Command widget.
3943 */
3944 (void) CloneString(&windows->command.name,"Composite");
3945 windows->command.data=1;
3946 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3947 (void) XMapRaised(display,windows->command.id);
3948 XClientMessage(display,windows->image.id,windows->im_protocols,
3949 windows->im_update_widget,CurrentTime);
3950 /*
3951 Track pointer until button 1 is pressed.
3952 */
3953 XQueryPosition(display,windows->image.id,&x,&y);
3954 (void) XSelectInput(display,windows->image.id,
3955 windows->image.attributes.event_mask | PointerMotionMask);
3956 composite_info.x=windows->image.x+x;
3957 composite_info.y=windows->image.y+y;
3958 composite_info.width=0;
3959 composite_info.height=0;
3960 cursor=XCreateFontCursor(display,XC_ul_angle);
3961 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3962 blend=0.0;
3963 state=DefaultState;
3964 do
3965 {
3966 if (windows->info.mapped != MagickFalse)
3967 {
3968 /*
3969 Display pointer position.
3970 */
3971 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00003972 (long) composite_info.x,(long) composite_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003973 XInfoWidget(display,windows,text);
3974 }
3975 highlight_info=composite_info;
3976 highlight_info.x=composite_info.x-windows->image.x;
3977 highlight_info.y=composite_info.y-windows->image.y;
3978 XHighlightRectangle(display,windows->image.id,
3979 windows->image.highlight_context,&highlight_info);
3980 /*
3981 Wait for next event.
3982 */
3983 XScreenEvent(display,windows,&event);
3984 XHighlightRectangle(display,windows->image.id,
3985 windows->image.highlight_context,&highlight_info);
3986 if (event.xany.window == windows->command.id)
3987 {
3988 /*
3989 Select a command from the Command widget.
3990 */
3991 id=XCommandWidget(display,windows,CompositeMenu,&event);
3992 if (id < 0)
3993 continue;
3994 switch (CompositeCommands[id])
3995 {
3996 case CompositeOperatorsCommand:
3997 {
3998 char
3999 command[MaxTextExtent],
4000 **operators;
4001
4002 /*
4003 Select a command from the pop-up menu.
4004 */
4005 operators=GetMagickOptions(MagickComposeOptions);
4006 if (operators == (char **) NULL)
4007 break;
4008 entry=XMenuWidget(display,windows,CompositeMenu[id],
4009 (const char **) operators,command);
4010 if (entry >= 0)
4011 compose=(CompositeOperator) ParseMagickOption(
4012 MagickComposeOptions,MagickFalse,operators[entry]);
4013 operators=DestroyStringList(operators);
4014 break;
4015 }
4016 case CompositeDissolveCommand:
4017 {
4018 static char
4019 factor[MaxTextExtent] = "20.0";
4020
4021 /*
4022 Dissolve the two images a given percent.
4023 */
4024 (void) XSetFunction(display,windows->image.highlight_context,
4025 GXcopy);
4026 (void) XDialogWidget(display,windows,"Dissolve",
4027 "Enter the blend factor (0.0 - 99.9%):",factor);
4028 (void) XSetFunction(display,windows->image.highlight_context,
4029 GXinvert);
4030 if (*factor == '\0')
4031 break;
cristyf2f27272009-12-17 14:48:46 +00004032 blend=StringToDouble(factor);
cristy3ed852e2009-09-05 21:47:34 +00004033 compose=DissolveCompositeOp;
4034 break;
4035 }
4036 case CompositeDisplaceCommand:
4037 {
4038 /*
4039 Get horizontal and vertical scale displacement geometry.
4040 */
4041 (void) XSetFunction(display,windows->image.highlight_context,
4042 GXcopy);
4043 (void) XDialogWidget(display,windows,"Displace",
4044 "Enter the horizontal and vertical scale:",displacement_geometry);
4045 (void) XSetFunction(display,windows->image.highlight_context,
4046 GXinvert);
4047 if (*displacement_geometry == '\0')
4048 break;
4049 compose=DisplaceCompositeOp;
4050 break;
4051 }
4052 case CompositeHelpCommand:
4053 {
4054 (void) XSetFunction(display,windows->image.highlight_context,
4055 GXcopy);
4056 XTextViewWidget(display,resource_info,windows,MagickFalse,
4057 "Help Viewer - Image Composite",ImageCompositeHelp);
4058 (void) XSetFunction(display,windows->image.highlight_context,
4059 GXinvert);
4060 break;
4061 }
4062 case CompositeDismissCommand:
4063 {
4064 /*
4065 Prematurely exit.
4066 */
4067 state|=EscapeState;
4068 state|=ExitState;
4069 break;
4070 }
4071 default:
4072 break;
4073 }
4074 continue;
4075 }
4076 switch (event.type)
4077 {
4078 case ButtonPress:
4079 {
4080 if (image->debug != MagickFalse)
4081 (void) LogMagickEvent(X11Event,GetMagickModule(),
4082 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4083 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4084 if (event.xbutton.button != Button1)
4085 break;
4086 if (event.xbutton.window != windows->image.id)
4087 break;
4088 /*
4089 Change cursor.
4090 */
4091 composite_info.width=composite_image->columns;
4092 composite_info.height=composite_image->rows;
4093 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4094 composite_info.x=windows->image.x+event.xbutton.x;
4095 composite_info.y=windows->image.y+event.xbutton.y;
4096 break;
4097 }
4098 case ButtonRelease:
4099 {
4100 if (image->debug != MagickFalse)
4101 (void) LogMagickEvent(X11Event,GetMagickModule(),
4102 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4103 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4104 if (event.xbutton.button != Button1)
4105 break;
4106 if (event.xbutton.window != windows->image.id)
4107 break;
4108 if ((composite_info.width != 0) && (composite_info.height != 0))
4109 {
4110 /*
4111 User has selected the location of the composite image.
4112 */
4113 composite_info.x=windows->image.x+event.xbutton.x;
4114 composite_info.y=windows->image.y+event.xbutton.y;
4115 state|=ExitState;
4116 }
4117 break;
4118 }
4119 case Expose:
4120 break;
4121 case KeyPress:
4122 {
4123 char
4124 command[MaxTextExtent];
4125
4126 KeySym
4127 key_symbol;
4128
4129 int
4130 length;
4131
4132 if (event.xkey.window != windows->image.id)
4133 break;
4134 /*
4135 Respond to a user key press.
4136 */
4137 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4138 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4139 *(command+length)='\0';
4140 if (image->debug != MagickFalse)
4141 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00004142 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +00004143 switch ((int) key_symbol)
4144 {
4145 case XK_Escape:
4146 case XK_F20:
4147 {
4148 /*
4149 Prematurely exit.
4150 */
4151 composite_image=DestroyImage(composite_image);
4152 state|=EscapeState;
4153 state|=ExitState;
4154 break;
4155 }
4156 case XK_F1:
4157 case XK_Help:
4158 {
4159 (void) XSetFunction(display,windows->image.highlight_context,
4160 GXcopy);
4161 XTextViewWidget(display,resource_info,windows,MagickFalse,
4162 "Help Viewer - Image Composite",ImageCompositeHelp);
4163 (void) XSetFunction(display,windows->image.highlight_context,
4164 GXinvert);
4165 break;
4166 }
4167 default:
4168 {
4169 (void) XBell(display,0);
4170 break;
4171 }
4172 }
4173 break;
4174 }
4175 case MotionNotify:
4176 {
4177 /*
4178 Map and unmap Info widget as text cursor crosses its boundaries.
4179 */
4180 x=event.xmotion.x;
4181 y=event.xmotion.y;
4182 if (windows->info.mapped != MagickFalse)
4183 {
4184 if ((x < (int) (windows->info.x+windows->info.width)) &&
4185 (y < (int) (windows->info.y+windows->info.height)))
4186 (void) XWithdrawWindow(display,windows->info.id,
4187 windows->info.screen);
4188 }
4189 else
4190 if ((x > (int) (windows->info.x+windows->info.width)) ||
4191 (y > (int) (windows->info.y+windows->info.height)))
4192 (void) XMapWindow(display,windows->info.id);
4193 composite_info.x=windows->image.x+x;
4194 composite_info.y=windows->image.y+y;
4195 break;
4196 }
4197 default:
4198 {
4199 if (image->debug != MagickFalse)
4200 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4201 event.type);
4202 break;
4203 }
4204 }
4205 } while ((state & ExitState) == 0);
4206 (void) XSelectInput(display,windows->image.id,
4207 windows->image.attributes.event_mask);
4208 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4209 XSetCursorState(display,windows,MagickFalse);
4210 (void) XFreeCursor(display,cursor);
4211 if ((state & EscapeState) != 0)
4212 return(MagickTrue);
4213 /*
4214 Image compositing is relative to image configuration.
4215 */
4216 XSetCursorState(display,windows,MagickTrue);
4217 XCheckRefreshWindows(display,windows);
4218 width=(unsigned int) image->columns;
4219 height=(unsigned int) image->rows;
4220 x=0;
4221 y=0;
4222 if (windows->image.crop_geometry != (char *) NULL)
4223 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4224 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4225 composite_info.x+=x;
4226 composite_info.x=(int) (scale_factor*composite_info.x+0.5);
4227 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4228 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4229 composite_info.y+=y;
4230 composite_info.y=(int) (scale_factor*composite_info.y+0.5);
4231 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4232 if ((composite_info.width != composite_image->columns) ||
4233 (composite_info.height != composite_image->rows))
4234 {
4235 Image
4236 *resize_image;
4237
4238 /*
4239 Scale composite image.
4240 */
cristy15b98cd2010-09-12 19:42:50 +00004241 resize_image=ResizeImage(composite_image,composite_info.width,
4242 composite_info.height,composite_image->filter,composite_image->blur,
4243 &image->exception);
cristy3ed852e2009-09-05 21:47:34 +00004244 composite_image=DestroyImage(composite_image);
4245 if (resize_image == (Image *) NULL)
4246 {
4247 XSetCursorState(display,windows,MagickFalse);
4248 return(MagickFalse);
4249 }
4250 composite_image=resize_image;
4251 }
4252 if (compose == DisplaceCompositeOp)
4253 (void) SetImageArtifact(composite_image,"compose:args",
4254 displacement_geometry);
4255 if (blend != 0.0)
4256 {
4257 ExceptionInfo
4258 *exception;
4259
4260 int
4261 y;
4262
4263 Quantum
4264 opacity;
4265
4266 register int
4267 x;
4268
4269 register PixelPacket
4270 *q;
4271
4272 /*
4273 Create mattes for blending.
4274 */
4275 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
4276 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
cristybb503372010-05-27 20:51:26 +00004277 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
cristy3ed852e2009-09-05 21:47:34 +00004278 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4279 return(MagickFalse);
4280 image->matte=MagickTrue;
4281 exception=(&image->exception);
cristybb503372010-05-27 20:51:26 +00004282 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004283 {
4284 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4285 if (q == (PixelPacket *) NULL)
4286 break;
4287 for (x=0; x < (int) image->columns; x++)
4288 {
4289 q->opacity=opacity;
4290 q++;
4291 }
4292 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4293 break;
4294 }
4295 }
4296 /*
4297 Composite image with X Image window.
4298 */
4299 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4300 composite_info.y);
4301 composite_image=DestroyImage(composite_image);
4302 XSetCursorState(display,windows,MagickFalse);
4303 /*
4304 Update image configuration.
4305 */
4306 XConfigureImageColormap(display,resource_info,windows,image);
4307 (void) XConfigureImage(display,resource_info,windows,image);
4308 return(MagickTrue);
4309}
4310
4311/*
4312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4313% %
4314% %
4315% %
4316+ X C o n f i g u r e I m a g e %
4317% %
4318% %
4319% %
4320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4321%
4322% XConfigureImage() creates a new X image. It also notifies the window
4323% manager of the new image size and configures the transient widows.
4324%
4325% The format of the XConfigureImage method is:
4326%
4327% MagickBooleanType XConfigureImage(Display *display,
4328% XResourceInfo *resource_info,XWindows *windows,Image *image)
4329%
4330% A description of each parameter follows:
4331%
4332% o display: Specifies a connection to an X server; returned from
4333% XOpenDisplay.
4334%
4335% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4336%
4337% o windows: Specifies a pointer to a XWindows structure.
4338%
4339% o image: the image.
4340%
4341%
4342*/
4343static MagickBooleanType XConfigureImage(Display *display,
4344 XResourceInfo *resource_info,XWindows *windows,Image *image)
4345{
4346 char
4347 geometry[MaxTextExtent];
4348
cristybb503372010-05-27 20:51:26 +00004349 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004350 x,
4351 y;
4352
4353 MagickStatusType
4354 status;
4355
cristybb503372010-05-27 20:51:26 +00004356 size_t
cristy3ed852e2009-09-05 21:47:34 +00004357 mask,
4358 height,
4359 width;
4360
4361 XSizeHints
4362 *size_hints;
4363
4364 XWindowChanges
4365 window_changes;
4366
4367 /*
4368 Dismiss if window dimensions are zero.
4369 */
4370 width=(unsigned int) windows->image.window_changes.width;
4371 height=(unsigned int) windows->image.window_changes.height;
4372 if (image->debug != MagickFalse)
4373 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00004374 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4375 windows->image.ximage->height,(double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00004376 if ((width*height) == 0)
4377 return(MagickTrue);
4378 x=0;
4379 y=0;
4380 /*
4381 Resize image to fit Image window dimensions.
4382 */
4383 XSetCursorState(display,windows,MagickTrue);
4384 (void) XFlush(display);
4385 if (((int) width != windows->image.ximage->width) ||
4386 ((int) height != windows->image.ximage->height))
4387 image->taint=MagickTrue;
4388 windows->magnify.x=(int)
4389 width*windows->magnify.x/windows->image.ximage->width;
4390 windows->magnify.y=(int)
4391 height*windows->magnify.y/windows->image.ximage->height;
4392 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4393 windows->image.y=(int)
4394 (height*windows->image.y/windows->image.ximage->height);
4395 status=XMakeImage(display,resource_info,&windows->image,image,
4396 (unsigned int) width,(unsigned int) height);
4397 if (status == MagickFalse)
4398 XNoticeWidget(display,windows,"Unable to configure X image:",
4399 windows->image.name);
4400 /*
4401 Notify window manager of the new configuration.
4402 */
4403 if (resource_info->image_geometry != (char *) NULL)
4404 (void) FormatMagickString(geometry,MaxTextExtent,"%s>!",
4405 resource_info->image_geometry);
4406 else
4407 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4408 XDisplayWidth(display,windows->image.screen),
4409 XDisplayHeight(display,windows->image.screen));
4410 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4411 window_changes.width=(int) width;
4412 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4413 window_changes.width=XDisplayWidth(display,windows->image.screen);
4414 window_changes.height=(int) height;
4415 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4416 window_changes.height=XDisplayHeight(display,windows->image.screen);
cristybb503372010-05-27 20:51:26 +00004417 mask=(size_t) (CWWidth | CWHeight);
cristy3ed852e2009-09-05 21:47:34 +00004418 if (resource_info->backdrop)
4419 {
4420 mask|=CWX | CWY;
4421 window_changes.x=(int)
4422 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4423 window_changes.y=(int)
4424 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4425 }
4426 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4427 (unsigned int) mask,&window_changes);
4428 (void) XClearWindow(display,windows->image.id);
4429 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4430 /*
4431 Update Magnify window configuration.
4432 */
4433 if (windows->magnify.mapped != MagickFalse)
4434 XMakeMagnifyImage(display,windows);
4435 windows->pan.crop_geometry=windows->image.crop_geometry;
4436 XBestIconSize(display,&windows->pan,image);
4437 while (((windows->pan.width << 1) < MaxIconSize) &&
4438 ((windows->pan.height << 1) < MaxIconSize))
4439 {
4440 windows->pan.width<<=1;
4441 windows->pan.height<<=1;
4442 }
4443 if (windows->pan.geometry != (char *) NULL)
4444 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4445 &windows->pan.width,&windows->pan.height);
4446 window_changes.width=(int) windows->pan.width;
4447 window_changes.height=(int) windows->pan.height;
4448 size_hints=XAllocSizeHints();
4449 if (size_hints != (XSizeHints *) NULL)
4450 {
4451 /*
4452 Set new size hints.
4453 */
4454 size_hints->flags=PSize | PMinSize | PMaxSize;
4455 size_hints->width=window_changes.width;
4456 size_hints->height=window_changes.height;
4457 size_hints->min_width=size_hints->width;
4458 size_hints->min_height=size_hints->height;
4459 size_hints->max_width=size_hints->width;
4460 size_hints->max_height=size_hints->height;
4461 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4462 (void) XFree((void *) size_hints);
4463 }
4464 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4465 (unsigned int) (CWWidth | CWHeight),&window_changes);
4466 /*
4467 Update icon window configuration.
4468 */
4469 windows->icon.crop_geometry=windows->image.crop_geometry;
4470 XBestIconSize(display,&windows->icon,image);
4471 window_changes.width=(int) windows->icon.width;
4472 window_changes.height=(int) windows->icon.height;
4473 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4474 (unsigned int) (CWWidth | CWHeight),&window_changes);
4475 XSetCursorState(display,windows,MagickFalse);
4476 return(status != 0 ? MagickTrue : MagickFalse);
4477}
4478
4479/*
4480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4481% %
4482% %
4483% %
4484+ X C r o p I m a g e %
4485% %
4486% %
4487% %
4488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4489%
4490% XCropImage() allows the user to select a region of the image and crop, copy,
4491% or cut it. For copy or cut, the image can subsequently be composited onto
4492% the image with XPasteImage.
4493%
4494% The format of the XCropImage method is:
4495%
4496% MagickBooleanType XCropImage(Display *display,
4497% XResourceInfo *resource_info,XWindows *windows,Image *image,
4498% const ClipboardMode mode)
4499%
4500% A description of each parameter follows:
4501%
4502% o display: Specifies a connection to an X server; returned from
4503% XOpenDisplay.
4504%
4505% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4506%
4507% o windows: Specifies a pointer to a XWindows structure.
4508%
4509% o image: the image; returned from ReadImage.
4510%
4511% o mode: This unsigned value specified whether the image should be
4512% cropped, copied, or cut.
4513%
4514*/
4515static MagickBooleanType XCropImage(Display *display,
4516 XResourceInfo *resource_info,XWindows *windows,Image *image,
4517 const ClipboardMode mode)
4518{
4519 static const char
4520 *CropModeMenu[] =
4521 {
4522 "Help",
4523 "Dismiss",
4524 (char *) NULL
4525 },
4526 *RectifyModeMenu[] =
4527 {
4528 "Crop",
4529 "Help",
4530 "Dismiss",
4531 (char *) NULL
4532 };
4533
4534 static const ModeType
4535 CropCommands[] =
4536 {
4537 CropHelpCommand,
4538 CropDismissCommand
4539 },
4540 RectifyCommands[] =
4541 {
4542 RectifyCopyCommand,
4543 RectifyHelpCommand,
4544 RectifyDismissCommand
4545 };
4546
4547 char
4548 command[MaxTextExtent],
4549 text[MaxTextExtent];
4550
4551 Cursor
4552 cursor;
4553
4554 ExceptionInfo
4555 *exception;
4556
4557 int
4558 id,
4559 x,
4560 y;
4561
4562 KeySym
4563 key_symbol;
4564
4565 Image
4566 *crop_image;
4567
4568 MagickRealType
4569 scale_factor;
4570
4571 RectangleInfo
4572 crop_info,
4573 highlight_info;
4574
4575 register PixelPacket
4576 *q;
4577
4578 unsigned int
4579 height,
4580 width;
4581
cristybb503372010-05-27 20:51:26 +00004582 size_t
cristy3ed852e2009-09-05 21:47:34 +00004583 state;
4584
4585 XEvent
4586 event;
4587
4588 /*
4589 Map Command widget.
4590 */
4591 switch (mode)
4592 {
4593 case CopyMode:
4594 {
4595 (void) CloneString(&windows->command.name,"Copy");
4596 break;
4597 }
4598 case CropMode:
4599 {
4600 (void) CloneString(&windows->command.name,"Crop");
4601 break;
4602 }
4603 case CutMode:
4604 {
4605 (void) CloneString(&windows->command.name,"Cut");
4606 break;
4607 }
4608 }
4609 RectifyModeMenu[0]=windows->command.name;
4610 windows->command.data=0;
4611 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4612 (void) XMapRaised(display,windows->command.id);
4613 XClientMessage(display,windows->image.id,windows->im_protocols,
4614 windows->im_update_widget,CurrentTime);
4615 /*
4616 Track pointer until button 1 is pressed.
4617 */
4618 XQueryPosition(display,windows->image.id,&x,&y);
4619 (void) XSelectInput(display,windows->image.id,
4620 windows->image.attributes.event_mask | PointerMotionMask);
4621 crop_info.x=windows->image.x+x;
4622 crop_info.y=windows->image.y+y;
4623 crop_info.width=0;
4624 crop_info.height=0;
4625 cursor=XCreateFontCursor(display,XC_fleur);
4626 state=DefaultState;
4627 do
4628 {
4629 if (windows->info.mapped != MagickFalse)
4630 {
4631 /*
4632 Display pointer position.
4633 */
4634 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004635 (long) crop_info.x,(long) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004636 XInfoWidget(display,windows,text);
4637 }
4638 /*
4639 Wait for next event.
4640 */
4641 XScreenEvent(display,windows,&event);
4642 if (event.xany.window == windows->command.id)
4643 {
4644 /*
4645 Select a command from the Command widget.
4646 */
4647 id=XCommandWidget(display,windows,CropModeMenu,&event);
4648 if (id < 0)
4649 continue;
4650 switch (CropCommands[id])
4651 {
4652 case CropHelpCommand:
4653 {
4654 switch (mode)
4655 {
4656 case CopyMode:
4657 {
4658 XTextViewWidget(display,resource_info,windows,MagickFalse,
4659 "Help Viewer - Image Copy",ImageCopyHelp);
4660 break;
4661 }
4662 case CropMode:
4663 {
4664 XTextViewWidget(display,resource_info,windows,MagickFalse,
4665 "Help Viewer - Image Crop",ImageCropHelp);
4666 break;
4667 }
4668 case CutMode:
4669 {
4670 XTextViewWidget(display,resource_info,windows,MagickFalse,
4671 "Help Viewer - Image Cut",ImageCutHelp);
4672 break;
4673 }
4674 }
4675 break;
4676 }
4677 case CropDismissCommand:
4678 {
4679 /*
4680 Prematurely exit.
4681 */
4682 state|=EscapeState;
4683 state|=ExitState;
4684 break;
4685 }
4686 default:
4687 break;
4688 }
4689 continue;
4690 }
4691 switch (event.type)
4692 {
4693 case ButtonPress:
4694 {
4695 if (event.xbutton.button != Button1)
4696 break;
4697 if (event.xbutton.window != windows->image.id)
4698 break;
4699 /*
4700 Note first corner of cropping rectangle-- exit loop.
4701 */
4702 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4703 crop_info.x=windows->image.x+event.xbutton.x;
4704 crop_info.y=windows->image.y+event.xbutton.y;
4705 state|=ExitState;
4706 break;
4707 }
4708 case ButtonRelease:
4709 break;
4710 case Expose:
4711 break;
4712 case KeyPress:
4713 {
4714 if (event.xkey.window != windows->image.id)
4715 break;
4716 /*
4717 Respond to a user key press.
4718 */
4719 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4720 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4721 switch ((int) key_symbol)
4722 {
4723 case XK_Escape:
4724 case XK_F20:
4725 {
4726 /*
4727 Prematurely exit.
4728 */
4729 state|=EscapeState;
4730 state|=ExitState;
4731 break;
4732 }
4733 case XK_F1:
4734 case XK_Help:
4735 {
4736 switch (mode)
4737 {
4738 case CopyMode:
4739 {
4740 XTextViewWidget(display,resource_info,windows,MagickFalse,
4741 "Help Viewer - Image Copy",ImageCopyHelp);
4742 break;
4743 }
4744 case CropMode:
4745 {
4746 XTextViewWidget(display,resource_info,windows,MagickFalse,
4747 "Help Viewer - Image Crop",ImageCropHelp);
4748 break;
4749 }
4750 case CutMode:
4751 {
4752 XTextViewWidget(display,resource_info,windows,MagickFalse,
4753 "Help Viewer - Image Cut",ImageCutHelp);
4754 break;
4755 }
4756 }
4757 break;
4758 }
4759 default:
4760 {
4761 (void) XBell(display,0);
4762 break;
4763 }
4764 }
4765 break;
4766 }
4767 case MotionNotify:
4768 {
4769 if (event.xmotion.window != windows->image.id)
4770 break;
4771 /*
4772 Map and unmap Info widget as text cursor crosses its boundaries.
4773 */
4774 x=event.xmotion.x;
4775 y=event.xmotion.y;
4776 if (windows->info.mapped != MagickFalse)
4777 {
4778 if ((x < (int) (windows->info.x+windows->info.width)) &&
4779 (y < (int) (windows->info.y+windows->info.height)))
4780 (void) XWithdrawWindow(display,windows->info.id,
4781 windows->info.screen);
4782 }
4783 else
4784 if ((x > (int) (windows->info.x+windows->info.width)) ||
4785 (y > (int) (windows->info.y+windows->info.height)))
4786 (void) XMapWindow(display,windows->info.id);
4787 crop_info.x=windows->image.x+x;
4788 crop_info.y=windows->image.y+y;
4789 break;
4790 }
4791 default:
4792 break;
4793 }
4794 } while ((state & ExitState) == 0);
4795 (void) XSelectInput(display,windows->image.id,
4796 windows->image.attributes.event_mask);
4797 if ((state & EscapeState) != 0)
4798 {
4799 /*
4800 User want to exit without cropping.
4801 */
4802 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4803 (void) XFreeCursor(display,cursor);
4804 return(MagickTrue);
4805 }
4806 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4807 do
4808 {
4809 /*
4810 Size rectangle as pointer moves until the mouse button is released.
4811 */
4812 x=(int) crop_info.x;
4813 y=(int) crop_info.y;
4814 crop_info.width=0;
4815 crop_info.height=0;
4816 state=DefaultState;
4817 do
4818 {
4819 highlight_info=crop_info;
4820 highlight_info.x=crop_info.x-windows->image.x;
4821 highlight_info.y=crop_info.y-windows->image.y;
4822 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4823 {
4824 /*
4825 Display info and draw cropping rectangle.
4826 */
4827 if (windows->info.mapped == MagickFalse)
4828 (void) XMapWindow(display,windows->info.id);
cristye8c25f92010-06-03 00:53:06 +00004829 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004830 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004831 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004832 XInfoWidget(display,windows,text);
4833 XHighlightRectangle(display,windows->image.id,
4834 windows->image.highlight_context,&highlight_info);
4835 }
4836 else
4837 if (windows->info.mapped != MagickFalse)
4838 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4839 /*
4840 Wait for next event.
4841 */
4842 XScreenEvent(display,windows,&event);
4843 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4844 XHighlightRectangle(display,windows->image.id,
4845 windows->image.highlight_context,&highlight_info);
4846 switch (event.type)
4847 {
4848 case ButtonPress:
4849 {
4850 crop_info.x=windows->image.x+event.xbutton.x;
4851 crop_info.y=windows->image.y+event.xbutton.y;
4852 break;
4853 }
4854 case ButtonRelease:
4855 {
4856 /*
4857 User has committed to cropping rectangle.
4858 */
4859 crop_info.x=windows->image.x+event.xbutton.x;
4860 crop_info.y=windows->image.y+event.xbutton.y;
4861 XSetCursorState(display,windows,MagickFalse);
4862 state|=ExitState;
4863 windows->command.data=0;
4864 (void) XCommandWidget(display,windows,RectifyModeMenu,
4865 (XEvent *) NULL);
4866 break;
4867 }
4868 case Expose:
4869 break;
4870 case MotionNotify:
4871 {
4872 crop_info.x=windows->image.x+event.xmotion.x;
4873 crop_info.y=windows->image.y+event.xmotion.y;
4874 }
4875 default:
4876 break;
4877 }
4878 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4879 ((state & ExitState) != 0))
4880 {
4881 /*
4882 Check boundary conditions.
4883 */
4884 if (crop_info.x < 0)
4885 crop_info.x=0;
4886 else
4887 if (crop_info.x > (int) windows->image.ximage->width)
4888 crop_info.x=windows->image.ximage->width;
4889 if ((int) crop_info.x < x)
4890 crop_info.width=(unsigned int) (x-crop_info.x);
4891 else
4892 {
4893 crop_info.width=(unsigned int) (crop_info.x-x);
4894 crop_info.x=x;
4895 }
4896 if (crop_info.y < 0)
4897 crop_info.y=0;
4898 else
4899 if (crop_info.y > (int) windows->image.ximage->height)
4900 crop_info.y=windows->image.ximage->height;
4901 if ((int) crop_info.y < y)
4902 crop_info.height=(unsigned int) (y-crop_info.y);
4903 else
4904 {
4905 crop_info.height=(unsigned int) (crop_info.y-y);
4906 crop_info.y=y;
4907 }
4908 }
4909 } while ((state & ExitState) == 0);
4910 /*
4911 Wait for user to grab a corner of the rectangle or press return.
4912 */
4913 state=DefaultState;
4914 (void) XMapWindow(display,windows->info.id);
4915 do
4916 {
4917 if (windows->info.mapped != MagickFalse)
4918 {
4919 /*
4920 Display pointer position.
4921 */
cristye8c25f92010-06-03 00:53:06 +00004922 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004923 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004924 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004925 XInfoWidget(display,windows,text);
4926 }
4927 highlight_info=crop_info;
4928 highlight_info.x=crop_info.x-windows->image.x;
4929 highlight_info.y=crop_info.y-windows->image.y;
4930 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4931 {
4932 state|=EscapeState;
4933 state|=ExitState;
4934 break;
4935 }
4936 XHighlightRectangle(display,windows->image.id,
4937 windows->image.highlight_context,&highlight_info);
4938 XScreenEvent(display,windows,&event);
4939 if (event.xany.window == windows->command.id)
4940 {
4941 /*
4942 Select a command from the Command widget.
4943 */
4944 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4945 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4946 (void) XSetFunction(display,windows->image.highlight_context,
4947 GXinvert);
4948 XHighlightRectangle(display,windows->image.id,
4949 windows->image.highlight_context,&highlight_info);
4950 if (id >= 0)
4951 switch (RectifyCommands[id])
4952 {
4953 case RectifyCopyCommand:
4954 {
4955 state|=ExitState;
4956 break;
4957 }
4958 case RectifyHelpCommand:
4959 {
4960 (void) XSetFunction(display,windows->image.highlight_context,
4961 GXcopy);
4962 switch (mode)
4963 {
4964 case CopyMode:
4965 {
4966 XTextViewWidget(display,resource_info,windows,MagickFalse,
4967 "Help Viewer - Image Copy",ImageCopyHelp);
4968 break;
4969 }
4970 case CropMode:
4971 {
4972 XTextViewWidget(display,resource_info,windows,MagickFalse,
4973 "Help Viewer - Image Crop",ImageCropHelp);
4974 break;
4975 }
4976 case CutMode:
4977 {
4978 XTextViewWidget(display,resource_info,windows,MagickFalse,
4979 "Help Viewer - Image Cut",ImageCutHelp);
4980 break;
4981 }
4982 }
4983 (void) XSetFunction(display,windows->image.highlight_context,
4984 GXinvert);
4985 break;
4986 }
4987 case RectifyDismissCommand:
4988 {
4989 /*
4990 Prematurely exit.
4991 */
4992 state|=EscapeState;
4993 state|=ExitState;
4994 break;
4995 }
4996 default:
4997 break;
4998 }
4999 continue;
5000 }
5001 XHighlightRectangle(display,windows->image.id,
5002 windows->image.highlight_context,&highlight_info);
5003 switch (event.type)
5004 {
5005 case ButtonPress:
5006 {
5007 if (event.xbutton.button != Button1)
5008 break;
5009 if (event.xbutton.window != windows->image.id)
5010 break;
5011 x=windows->image.x+event.xbutton.x;
5012 y=windows->image.y+event.xbutton.y;
5013 if ((x < (int) (crop_info.x+RoiDelta)) &&
5014 (x > (int) (crop_info.x-RoiDelta)) &&
5015 (y < (int) (crop_info.y+RoiDelta)) &&
5016 (y > (int) (crop_info.y-RoiDelta)))
5017 {
cristybb503372010-05-27 20:51:26 +00005018 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5019 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005020 state|=UpdateConfigurationState;
5021 break;
5022 }
5023 if ((x < (int) (crop_info.x+RoiDelta)) &&
5024 (x > (int) (crop_info.x-RoiDelta)) &&
5025 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5026 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5027 {
cristybb503372010-05-27 20:51:26 +00005028 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
cristy3ed852e2009-09-05 21:47:34 +00005029 state|=UpdateConfigurationState;
5030 break;
5031 }
5032 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5033 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5034 (y < (int) (crop_info.y+RoiDelta)) &&
5035 (y > (int) (crop_info.y-RoiDelta)))
5036 {
cristybb503372010-05-27 20:51:26 +00005037 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005038 state|=UpdateConfigurationState;
5039 break;
5040 }
5041 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5042 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5043 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5044 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5045 {
5046 state|=UpdateConfigurationState;
5047 break;
5048 }
5049 }
5050 case ButtonRelease:
5051 {
5052 if (event.xbutton.window == windows->pan.id)
5053 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5054 (highlight_info.y != crop_info.y-windows->image.y))
5055 XHighlightRectangle(display,windows->image.id,
5056 windows->image.highlight_context,&highlight_info);
5057 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5058 event.xbutton.time);
5059 break;
5060 }
5061 case Expose:
5062 {
5063 if (event.xexpose.window == windows->image.id)
5064 if (event.xexpose.count == 0)
5065 {
5066 event.xexpose.x=(int) highlight_info.x;
5067 event.xexpose.y=(int) highlight_info.y;
5068 event.xexpose.width=(int) highlight_info.width;
5069 event.xexpose.height=(int) highlight_info.height;
5070 XRefreshWindow(display,&windows->image,&event);
5071 }
5072 if (event.xexpose.window == windows->info.id)
5073 if (event.xexpose.count == 0)
5074 XInfoWidget(display,windows,text);
5075 break;
5076 }
5077 case KeyPress:
5078 {
5079 if (event.xkey.window != windows->image.id)
5080 break;
5081 /*
5082 Respond to a user key press.
5083 */
5084 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5085 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5086 switch ((int) key_symbol)
5087 {
5088 case XK_Escape:
5089 case XK_F20:
5090 state|=EscapeState;
5091 case XK_Return:
5092 {
5093 state|=ExitState;
5094 break;
5095 }
5096 case XK_Home:
5097 case XK_KP_Home:
5098 {
cristybb503372010-05-27 20:51:26 +00005099 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/2L);
5100 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +00005101 break;
5102 }
5103 case XK_Left:
5104 case XK_KP_Left:
5105 {
5106 crop_info.x--;
5107 break;
5108 }
5109 case XK_Up:
5110 case XK_KP_Up:
5111 case XK_Next:
5112 {
5113 crop_info.y--;
5114 break;
5115 }
5116 case XK_Right:
5117 case XK_KP_Right:
5118 {
5119 crop_info.x++;
5120 break;
5121 }
5122 case XK_Prior:
5123 case XK_Down:
5124 case XK_KP_Down:
5125 {
5126 crop_info.y++;
5127 break;
5128 }
5129 case XK_F1:
5130 case XK_Help:
5131 {
5132 (void) XSetFunction(display,windows->image.highlight_context,
5133 GXcopy);
5134 switch (mode)
5135 {
5136 case CopyMode:
5137 {
5138 XTextViewWidget(display,resource_info,windows,MagickFalse,
5139 "Help Viewer - Image Copy",ImageCopyHelp);
5140 break;
5141 }
5142 case CropMode:
5143 {
5144 XTextViewWidget(display,resource_info,windows,MagickFalse,
5145 "Help Viewer - Image Cropg",ImageCropHelp);
5146 break;
5147 }
5148 case CutMode:
5149 {
5150 XTextViewWidget(display,resource_info,windows,MagickFalse,
5151 "Help Viewer - Image Cutg",ImageCutHelp);
5152 break;
5153 }
5154 }
5155 (void) XSetFunction(display,windows->image.highlight_context,
5156 GXinvert);
5157 break;
5158 }
5159 default:
5160 {
5161 (void) XBell(display,0);
5162 break;
5163 }
5164 }
5165 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5166 event.xkey.time);
5167 break;
5168 }
5169 case KeyRelease:
5170 break;
5171 case MotionNotify:
5172 {
5173 if (event.xmotion.window != windows->image.id)
5174 break;
5175 /*
5176 Map and unmap Info widget as text cursor crosses its boundaries.
5177 */
5178 x=event.xmotion.x;
5179 y=event.xmotion.y;
5180 if (windows->info.mapped != MagickFalse)
5181 {
5182 if ((x < (int) (windows->info.x+windows->info.width)) &&
5183 (y < (int) (windows->info.y+windows->info.height)))
5184 (void) XWithdrawWindow(display,windows->info.id,
5185 windows->info.screen);
5186 }
5187 else
5188 if ((x > (int) (windows->info.x+windows->info.width)) ||
5189 (y > (int) (windows->info.y+windows->info.height)))
5190 (void) XMapWindow(display,windows->info.id);
5191 crop_info.x=windows->image.x+event.xmotion.x;
5192 crop_info.y=windows->image.y+event.xmotion.y;
5193 break;
5194 }
5195 case SelectionRequest:
5196 {
5197 XSelectionEvent
5198 notify;
5199
5200 XSelectionRequestEvent
5201 *request;
5202
5203 /*
5204 Set primary selection.
5205 */
cristye8c25f92010-06-03 00:53:06 +00005206 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005207 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00005208 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005209 request=(&(event.xselectionrequest));
5210 (void) XChangeProperty(request->display,request->requestor,
5211 request->property,request->target,8,PropModeReplace,
5212 (unsigned char *) text,(int) strlen(text));
5213 notify.type=SelectionNotify;
5214 notify.display=request->display;
5215 notify.requestor=request->requestor;
5216 notify.selection=request->selection;
5217 notify.target=request->target;
5218 notify.time=request->time;
5219 if (request->property == None)
5220 notify.property=request->target;
5221 else
5222 notify.property=request->property;
5223 (void) XSendEvent(request->display,request->requestor,False,0,
5224 (XEvent *) &notify);
5225 }
5226 default:
5227 break;
5228 }
5229 if ((state & UpdateConfigurationState) != 0)
5230 {
5231 (void) XPutBackEvent(display,&event);
5232 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5233 break;
5234 }
5235 } while ((state & ExitState) == 0);
5236 } while ((state & ExitState) == 0);
5237 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5238 XSetCursorState(display,windows,MagickFalse);
5239 if ((state & EscapeState) != 0)
5240 return(MagickTrue);
5241 if (mode == CropMode)
5242 if (((int) crop_info.width != windows->image.ximage->width) ||
5243 ((int) crop_info.height != windows->image.ximage->height))
5244 {
5245 /*
5246 Reconfigure Image window as defined by cropping rectangle.
5247 */
5248 XSetCropGeometry(display,windows,&crop_info,image);
5249 windows->image.window_changes.width=(int) crop_info.width;
5250 windows->image.window_changes.height=(int) crop_info.height;
5251 (void) XConfigureImage(display,resource_info,windows,image);
5252 return(MagickTrue);
5253 }
5254 /*
5255 Copy image before applying image transforms.
5256 */
5257 XSetCursorState(display,windows,MagickTrue);
5258 XCheckRefreshWindows(display,windows);
5259 width=(unsigned int) image->columns;
5260 height=(unsigned int) image->rows;
5261 x=0;
5262 y=0;
5263 if (windows->image.crop_geometry != (char *) NULL)
5264 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5265 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5266 crop_info.x+=x;
5267 crop_info.x=(int) (scale_factor*crop_info.x+0.5);
5268 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5269 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5270 crop_info.y+=y;
5271 crop_info.y=(int) (scale_factor*crop_info.y+0.5);
5272 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5273 crop_image=CropImage(image,&crop_info,&image->exception);
5274 XSetCursorState(display,windows,MagickFalse);
5275 if (crop_image == (Image *) NULL)
5276 return(MagickFalse);
5277 if (resource_info->copy_image != (Image *) NULL)
5278 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5279 resource_info->copy_image=crop_image;
5280 if (mode == CopyMode)
5281 {
5282 (void) XConfigureImage(display,resource_info,windows,image);
5283 return(MagickTrue);
5284 }
5285 /*
5286 Cut image.
5287 */
5288 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
5289 return(MagickFalse);
5290 image->matte=MagickTrue;
5291 exception=(&image->exception);
cristybb503372010-05-27 20:51:26 +00005292 for (y=0; y < (ssize_t) crop_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00005293 {
5294 q=GetAuthenticPixels(image,crop_info.x,y+crop_info.y,crop_info.width,1,
5295 exception);
5296 if (q == (PixelPacket *) NULL)
5297 break;
5298 for (x=0; x < (int) crop_info.width; x++)
5299 {
5300 q->opacity=(Quantum) TransparentOpacity;
5301 q++;
5302 }
5303 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5304 break;
5305 }
5306 /*
5307 Update image configuration.
5308 */
5309 XConfigureImageColormap(display,resource_info,windows,image);
5310 (void) XConfigureImage(display,resource_info,windows,image);
5311 return(MagickTrue);
5312}
5313
5314/*
5315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316% %
5317% %
5318% %
5319+ X D r a w I m a g e %
5320% %
5321% %
5322% %
5323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324%
5325% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5326% the image.
5327%
5328% The format of the XDrawEditImage method is:
5329%
5330% MagickBooleanType XDrawEditImage(Display *display,
5331% XResourceInfo *resource_info,XWindows *windows,Image **image)
5332%
5333% A description of each parameter follows:
5334%
5335% o display: Specifies a connection to an X server; returned from
5336% XOpenDisplay.
5337%
5338% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5339%
5340% o windows: Specifies a pointer to a XWindows structure.
5341%
5342% o image: the image.
5343%
5344*/
5345static MagickBooleanType XDrawEditImage(Display *display,
5346 XResourceInfo *resource_info,XWindows *windows,Image **image)
5347{
5348 static const char
5349 *DrawMenu[] =
5350 {
5351 "Element",
5352 "Color",
5353 "Stipple",
5354 "Width",
5355 "Undo",
5356 "Help",
5357 "Dismiss",
5358 (char *) NULL
5359 };
5360
5361 static ElementType
5362 element = PointElement;
5363
5364 static const ModeType
5365 DrawCommands[] =
5366 {
5367 DrawElementCommand,
5368 DrawColorCommand,
5369 DrawStippleCommand,
5370 DrawWidthCommand,
5371 DrawUndoCommand,
5372 DrawHelpCommand,
5373 DrawDismissCommand
5374 };
5375
5376 static Pixmap
5377 stipple = (Pixmap) NULL;
5378
5379 static unsigned int
5380 pen_id = 0,
5381 line_width = 1;
5382
5383 char
5384 command[MaxTextExtent],
5385 text[MaxTextExtent];
5386
5387 Cursor
5388 cursor;
5389
5390 int
5391 entry,
5392 id,
5393 number_coordinates,
5394 x,
5395 y;
5396
5397 MagickRealType
5398 degrees;
5399
5400 MagickStatusType
5401 status;
5402
5403 RectangleInfo
5404 rectangle_info;
5405
5406 register int
5407 i;
5408
5409 unsigned int
5410 distance,
5411 height,
5412 max_coordinates,
5413 width;
5414
cristybb503372010-05-27 20:51:26 +00005415 size_t
cristy3ed852e2009-09-05 21:47:34 +00005416 state;
5417
5418 Window
5419 root_window;
5420
5421 XDrawInfo
5422 draw_info;
5423
5424 XEvent
5425 event;
5426
5427 XPoint
5428 *coordinate_info;
5429
5430 XSegment
5431 line_info;
5432
5433 /*
5434 Allocate polygon info.
5435 */
5436 max_coordinates=2048;
5437 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5438 sizeof(*coordinate_info));
5439 if (coordinate_info == (XPoint *) NULL)
5440 {
5441 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5442 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5443 return(MagickFalse);
5444 }
5445 /*
5446 Map Command widget.
5447 */
5448 (void) CloneString(&windows->command.name,"Draw");
5449 windows->command.data=4;
5450 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5451 (void) XMapRaised(display,windows->command.id);
5452 XClientMessage(display,windows->image.id,windows->im_protocols,
5453 windows->im_update_widget,CurrentTime);
5454 /*
5455 Wait for first button press.
5456 */
5457 root_window=XRootWindow(display,XDefaultScreen(display));
5458 draw_info.stencil=OpaqueStencil;
5459 status=MagickTrue;
5460 cursor=XCreateFontCursor(display,XC_tcross);
5461 for ( ; ; )
5462 {
5463 XQueryPosition(display,windows->image.id,&x,&y);
5464 (void) XSelectInput(display,windows->image.id,
5465 windows->image.attributes.event_mask | PointerMotionMask);
5466 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5467 state=DefaultState;
5468 do
5469 {
5470 if (windows->info.mapped != MagickFalse)
5471 {
5472 /*
5473 Display pointer position.
5474 */
5475 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
5476 x+windows->image.x,y+windows->image.y);
5477 XInfoWidget(display,windows,text);
5478 }
5479 /*
5480 Wait for next event.
5481 */
5482 XScreenEvent(display,windows,&event);
5483 if (event.xany.window == windows->command.id)
5484 {
5485 /*
5486 Select a command from the Command widget.
5487 */
5488 id=XCommandWidget(display,windows,DrawMenu,&event);
5489 if (id < 0)
5490 continue;
5491 switch (DrawCommands[id])
5492 {
5493 case DrawElementCommand:
5494 {
5495 static const char
5496 *Elements[] =
5497 {
5498 "point",
5499 "line",
5500 "rectangle",
5501 "fill rectangle",
5502 "circle",
5503 "fill circle",
5504 "ellipse",
5505 "fill ellipse",
5506 "polygon",
5507 "fill polygon",
5508 (char *) NULL,
5509 };
5510
5511 /*
5512 Select a command from the pop-up menu.
5513 */
5514 element=(ElementType) (XMenuWidget(display,windows,
5515 DrawMenu[id],Elements,command)+1);
5516 break;
5517 }
5518 case DrawColorCommand:
5519 {
5520 const char
5521 *ColorMenu[MaxNumberPens+1];
5522
5523 int
5524 pen_number;
5525
5526 MagickBooleanType
5527 transparent;
5528
5529 XColor
5530 color;
5531
5532 /*
5533 Initialize menu selections.
5534 */
5535 for (i=0; i < (int) (MaxNumberPens-2); i++)
5536 ColorMenu[i]=resource_info->pen_colors[i];
5537 ColorMenu[MaxNumberPens-2]="transparent";
5538 ColorMenu[MaxNumberPens-1]="Browser...";
5539 ColorMenu[MaxNumberPens]=(char *) NULL;
5540 /*
5541 Select a pen color from the pop-up menu.
5542 */
5543 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5544 (const char **) ColorMenu,command);
5545 if (pen_number < 0)
5546 break;
5547 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5548 MagickFalse;
5549 if (transparent != MagickFalse)
5550 {
5551 draw_info.stencil=TransparentStencil;
5552 break;
5553 }
5554 if (pen_number == (MaxNumberPens-1))
5555 {
5556 static char
5557 color_name[MaxTextExtent] = "gray";
5558
5559 /*
5560 Select a pen color from a dialog.
5561 */
5562 resource_info->pen_colors[pen_number]=color_name;
5563 XColorBrowserWidget(display,windows,"Select",color_name);
5564 if (*color_name == '\0')
5565 break;
5566 }
5567 /*
5568 Set pen color.
5569 */
5570 (void) XParseColor(display,windows->map_info->colormap,
5571 resource_info->pen_colors[pen_number],&color);
5572 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5573 (unsigned int) MaxColors,&color);
5574 windows->pixel_info->pen_colors[pen_number]=color;
5575 pen_id=(unsigned int) pen_number;
5576 draw_info.stencil=OpaqueStencil;
5577 break;
5578 }
5579 case DrawStippleCommand:
5580 {
5581 Image
5582 *stipple_image;
5583
5584 ImageInfo
5585 *image_info;
5586
5587 int
5588 status;
5589
5590 static char
5591 filename[MaxTextExtent] = "\0";
5592
5593 static const char
5594 *StipplesMenu[] =
5595 {
5596 "Brick",
5597 "Diagonal",
5598 "Scales",
5599 "Vertical",
5600 "Wavy",
5601 "Translucent",
5602 "Opaque",
5603 (char *) NULL,
5604 (char *) NULL,
5605 };
5606
5607 /*
5608 Select a command from the pop-up menu.
5609 */
5610 StipplesMenu[7]="Open...";
5611 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5612 command);
5613 if (entry < 0)
5614 break;
5615 if (stipple != (Pixmap) NULL)
5616 (void) XFreePixmap(display,stipple);
5617 stipple=(Pixmap) NULL;
5618 if (entry == 6)
5619 break;
5620 if (entry != 7)
5621 {
5622 switch (entry)
5623 {
5624 case 0:
5625 {
5626 stipple=XCreateBitmapFromData(display,root_window,
5627 (char *) BricksBitmap,BricksWidth,BricksHeight);
5628 break;
5629 }
5630 case 1:
5631 {
5632 stipple=XCreateBitmapFromData(display,root_window,
5633 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5634 break;
5635 }
5636 case 2:
5637 {
5638 stipple=XCreateBitmapFromData(display,root_window,
5639 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5640 break;
5641 }
5642 case 3:
5643 {
5644 stipple=XCreateBitmapFromData(display,root_window,
5645 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5646 break;
5647 }
5648 case 4:
5649 {
5650 stipple=XCreateBitmapFromData(display,root_window,
5651 (char *) WavyBitmap,WavyWidth,WavyHeight);
5652 break;
5653 }
5654 case 5:
5655 default:
5656 {
5657 stipple=XCreateBitmapFromData(display,root_window,
5658 (char *) HighlightBitmap,HighlightWidth,
5659 HighlightHeight);
5660 break;
5661 }
5662 }
5663 break;
5664 }
5665 XFileBrowserWidget(display,windows,"Stipple",filename);
5666 if (*filename == '\0')
5667 break;
5668 /*
5669 Read image.
5670 */
5671 XSetCursorState(display,windows,MagickTrue);
5672 XCheckRefreshWindows(display,windows);
5673 image_info=AcquireImageInfo();
5674 (void) CopyMagickString(image_info->filename,filename,
5675 MaxTextExtent);
5676 stipple_image=ReadImage(image_info,&(*image)->exception);
5677 CatchException(&(*image)->exception);
5678 XSetCursorState(display,windows,MagickFalse);
5679 if (stipple_image == (Image *) NULL)
5680 break;
5681 (void) AcquireUniqueFileResource(filename);
5682 (void) FormatMagickString(stipple_image->filename,MaxTextExtent,
5683 "xbm:%s",filename);
5684 (void) WriteImage(image_info,stipple_image);
5685 stipple_image=DestroyImage(stipple_image);
5686 image_info=DestroyImageInfo(image_info);
5687 status=XReadBitmapFile(display,root_window,filename,&width,
5688 &height,&stipple,&x,&y);
5689 (void) RelinquishUniqueFileResource(filename);
5690 if ((status != BitmapSuccess) != 0)
5691 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5692 filename);
5693 break;
5694 }
5695 case DrawWidthCommand:
5696 {
5697 static char
5698 width[MaxTextExtent] = "0";
5699
5700 static const char
5701 *WidthsMenu[] =
5702 {
5703 "1",
5704 "2",
5705 "4",
5706 "8",
5707 "16",
5708 "Dialog...",
5709 (char *) NULL,
5710 };
5711
5712 /*
5713 Select a command from the pop-up menu.
5714 */
5715 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5716 command);
5717 if (entry < 0)
5718 break;
5719 if (entry != 5)
5720 {
cristye27293e2009-12-18 02:53:20 +00005721 line_width=(unsigned int) StringToUnsignedLong(WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005722 break;
5723 }
5724 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5725 width);
5726 if (*width == '\0')
5727 break;
cristye27293e2009-12-18 02:53:20 +00005728 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005729 break;
5730 }
5731 case DrawUndoCommand:
5732 {
5733 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5734 image);
5735 break;
5736 }
5737 case DrawHelpCommand:
5738 {
5739 XTextViewWidget(display,resource_info,windows,MagickFalse,
5740 "Help Viewer - Image Rotation",ImageDrawHelp);
5741 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5742 break;
5743 }
5744 case DrawDismissCommand:
5745 {
5746 /*
5747 Prematurely exit.
5748 */
5749 state|=EscapeState;
5750 state|=ExitState;
5751 break;
5752 }
5753 default:
5754 break;
5755 }
5756 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5757 continue;
5758 }
5759 switch (event.type)
5760 {
5761 case ButtonPress:
5762 {
5763 if (event.xbutton.button != Button1)
5764 break;
5765 if (event.xbutton.window != windows->image.id)
5766 break;
5767 /*
5768 exit loop.
5769 */
5770 x=event.xbutton.x;
5771 y=event.xbutton.y;
5772 state|=ExitState;
5773 break;
5774 }
5775 case ButtonRelease:
5776 break;
5777 case Expose:
5778 break;
5779 case KeyPress:
5780 {
5781 KeySym
5782 key_symbol;
5783
5784 if (event.xkey.window != windows->image.id)
5785 break;
5786 /*
5787 Respond to a user key press.
5788 */
5789 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5790 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5791 switch ((int) key_symbol)
5792 {
5793 case XK_Escape:
5794 case XK_F20:
5795 {
5796 /*
5797 Prematurely exit.
5798 */
5799 state|=EscapeState;
5800 state|=ExitState;
5801 break;
5802 }
5803 case XK_F1:
5804 case XK_Help:
5805 {
5806 XTextViewWidget(display,resource_info,windows,MagickFalse,
5807 "Help Viewer - Image Rotation",ImageDrawHelp);
5808 break;
5809 }
5810 default:
5811 {
5812 (void) XBell(display,0);
5813 break;
5814 }
5815 }
5816 break;
5817 }
5818 case MotionNotify:
5819 {
5820 /*
5821 Map and unmap Info widget as text cursor crosses its boundaries.
5822 */
5823 x=event.xmotion.x;
5824 y=event.xmotion.y;
5825 if (windows->info.mapped != MagickFalse)
5826 {
5827 if ((x < (int) (windows->info.x+windows->info.width)) &&
5828 (y < (int) (windows->info.y+windows->info.height)))
5829 (void) XWithdrawWindow(display,windows->info.id,
5830 windows->info.screen);
5831 }
5832 else
5833 if ((x > (int) (windows->info.x+windows->info.width)) ||
5834 (y > (int) (windows->info.y+windows->info.height)))
5835 (void) XMapWindow(display,windows->info.id);
5836 break;
5837 }
5838 }
5839 } while ((state & ExitState) == 0);
5840 (void) XSelectInput(display,windows->image.id,
5841 windows->image.attributes.event_mask);
5842 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5843 if ((state & EscapeState) != 0)
5844 break;
5845 /*
5846 Draw element as pointer moves until the button is released.
5847 */
5848 distance=0;
5849 degrees=0.0;
5850 line_info.x1=x;
5851 line_info.y1=y;
5852 line_info.x2=x;
5853 line_info.y2=y;
5854 rectangle_info.x=x;
5855 rectangle_info.y=y;
5856 rectangle_info.width=0;
5857 rectangle_info.height=0;
5858 number_coordinates=1;
5859 coordinate_info->x=x;
5860 coordinate_info->y=y;
5861 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5862 state=DefaultState;
5863 do
5864 {
5865 switch (element)
5866 {
5867 case PointElement:
5868 default:
5869 {
5870 if (number_coordinates > 1)
5871 {
5872 (void) XDrawLines(display,windows->image.id,
5873 windows->image.highlight_context,coordinate_info,
5874 number_coordinates,CoordModeOrigin);
5875 (void) FormatMagickString(text,MaxTextExtent," %+d%+d",
5876 coordinate_info[number_coordinates-1].x,
5877 coordinate_info[number_coordinates-1].y);
5878 XInfoWidget(display,windows,text);
5879 }
5880 break;
5881 }
5882 case LineElement:
5883 {
5884 if (distance > 9)
5885 {
5886 /*
5887 Display angle of the line.
5888 */
5889 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5890 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristye7f51092010-01-17 00:39:37 +00005891 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005892 (double) degrees);
5893 XInfoWidget(display,windows,text);
5894 XHighlightLine(display,windows->image.id,
5895 windows->image.highlight_context,&line_info);
5896 }
5897 else
5898 if (windows->info.mapped != MagickFalse)
5899 (void) XWithdrawWindow(display,windows->info.id,
5900 windows->info.screen);
5901 break;
5902 }
5903 case RectangleElement:
5904 case FillRectangleElement:
5905 {
5906 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5907 {
5908 /*
5909 Display info and draw drawing rectangle.
5910 */
cristye8c25f92010-06-03 00:53:06 +00005911 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005912 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005913 (double) rectangle_info.height,(double) rectangle_info.x,
5914 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005915 XInfoWidget(display,windows,text);
5916 XHighlightRectangle(display,windows->image.id,
5917 windows->image.highlight_context,&rectangle_info);
5918 }
5919 else
5920 if (windows->info.mapped != MagickFalse)
5921 (void) XWithdrawWindow(display,windows->info.id,
5922 windows->info.screen);
5923 break;
5924 }
5925 case CircleElement:
5926 case FillCircleElement:
5927 case EllipseElement:
5928 case FillEllipseElement:
5929 {
5930 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5931 {
5932 /*
5933 Display info and draw drawing rectangle.
5934 */
cristye8c25f92010-06-03 00:53:06 +00005935 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005936 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005937 (double) rectangle_info.height,(double) rectangle_info.x,
5938 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005939 XInfoWidget(display,windows,text);
5940 XHighlightEllipse(display,windows->image.id,
5941 windows->image.highlight_context,&rectangle_info);
5942 }
5943 else
5944 if (windows->info.mapped != MagickFalse)
5945 (void) XWithdrawWindow(display,windows->info.id,
5946 windows->info.screen);
5947 break;
5948 }
5949 case PolygonElement:
5950 case FillPolygonElement:
5951 {
5952 if (number_coordinates > 1)
5953 (void) XDrawLines(display,windows->image.id,
5954 windows->image.highlight_context,coordinate_info,
5955 number_coordinates,CoordModeOrigin);
5956 if (distance > 9)
5957 {
5958 /*
5959 Display angle of the line.
5960 */
5961 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5962 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristye7f51092010-01-17 00:39:37 +00005963 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005964 (double) degrees);
5965 XInfoWidget(display,windows,text);
5966 XHighlightLine(display,windows->image.id,
5967 windows->image.highlight_context,&line_info);
5968 }
5969 else
5970 if (windows->info.mapped != MagickFalse)
5971 (void) XWithdrawWindow(display,windows->info.id,
5972 windows->info.screen);
5973 break;
5974 }
5975 }
5976 /*
5977 Wait for next event.
5978 */
5979 XScreenEvent(display,windows,&event);
5980 switch (element)
5981 {
5982 case PointElement:
5983 default:
5984 {
5985 if (number_coordinates > 1)
5986 (void) XDrawLines(display,windows->image.id,
5987 windows->image.highlight_context,coordinate_info,
5988 number_coordinates,CoordModeOrigin);
5989 break;
5990 }
5991 case LineElement:
5992 {
5993 if (distance > 9)
5994 XHighlightLine(display,windows->image.id,
5995 windows->image.highlight_context,&line_info);
5996 break;
5997 }
5998 case RectangleElement:
5999 case FillRectangleElement:
6000 {
6001 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6002 XHighlightRectangle(display,windows->image.id,
6003 windows->image.highlight_context,&rectangle_info);
6004 break;
6005 }
6006 case CircleElement:
6007 case FillCircleElement:
6008 case EllipseElement:
6009 case FillEllipseElement:
6010 {
6011 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6012 XHighlightEllipse(display,windows->image.id,
6013 windows->image.highlight_context,&rectangle_info);
6014 break;
6015 }
6016 case PolygonElement:
6017 case FillPolygonElement:
6018 {
6019 if (number_coordinates > 1)
6020 (void) XDrawLines(display,windows->image.id,
6021 windows->image.highlight_context,coordinate_info,
6022 number_coordinates,CoordModeOrigin);
6023 if (distance > 9)
6024 XHighlightLine(display,windows->image.id,
6025 windows->image.highlight_context,&line_info);
6026 break;
6027 }
6028 }
6029 switch (event.type)
6030 {
6031 case ButtonPress:
6032 break;
6033 case ButtonRelease:
6034 {
6035 /*
6036 User has committed to element.
6037 */
6038 line_info.x2=event.xbutton.x;
6039 line_info.y2=event.xbutton.y;
6040 rectangle_info.x=event.xbutton.x;
6041 rectangle_info.y=event.xbutton.y;
6042 coordinate_info[number_coordinates].x=event.xbutton.x;
6043 coordinate_info[number_coordinates].y=event.xbutton.y;
6044 if (((element != PolygonElement) &&
6045 (element != FillPolygonElement)) || (distance <= 9))
6046 {
6047 state|=ExitState;
6048 break;
6049 }
6050 number_coordinates++;
6051 if (number_coordinates < (int) max_coordinates)
6052 {
6053 line_info.x1=event.xbutton.x;
6054 line_info.y1=event.xbutton.y;
6055 break;
6056 }
6057 max_coordinates<<=1;
6058 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6059 max_coordinates,sizeof(*coordinate_info));
6060 if (coordinate_info == (XPoint *) NULL)
6061 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6062 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6063 break;
6064 }
6065 case Expose:
6066 break;
6067 case MotionNotify:
6068 {
6069 if (event.xmotion.window != windows->image.id)
6070 break;
6071 if (element != PointElement)
6072 {
6073 line_info.x2=event.xmotion.x;
6074 line_info.y2=event.xmotion.y;
6075 rectangle_info.x=event.xmotion.x;
6076 rectangle_info.y=event.xmotion.y;
6077 break;
6078 }
6079 coordinate_info[number_coordinates].x=event.xbutton.x;
6080 coordinate_info[number_coordinates].y=event.xbutton.y;
6081 number_coordinates++;
6082 if (number_coordinates < (int) max_coordinates)
6083 break;
6084 max_coordinates<<=1;
6085 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6086 max_coordinates,sizeof(*coordinate_info));
6087 if (coordinate_info == (XPoint *) NULL)
6088 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6089 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6090 break;
6091 }
6092 default:
6093 break;
6094 }
6095 /*
6096 Check boundary conditions.
6097 */
6098 if (line_info.x2 < 0)
6099 line_info.x2=0;
6100 else
6101 if (line_info.x2 > (int) windows->image.width)
6102 line_info.x2=(short) windows->image.width;
6103 if (line_info.y2 < 0)
6104 line_info.y2=0;
6105 else
6106 if (line_info.y2 > (int) windows->image.height)
6107 line_info.y2=(short) windows->image.height;
6108 distance=(unsigned int)
6109 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6110 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6111 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6112 ((state & ExitState) != 0))
6113 {
6114 if (rectangle_info.x < 0)
6115 rectangle_info.x=0;
6116 else
6117 if (rectangle_info.x > (int) windows->image.width)
cristybb503372010-05-27 20:51:26 +00006118 rectangle_info.x=(ssize_t) windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +00006119 if ((int) rectangle_info.x < x)
6120 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6121 else
6122 {
6123 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6124 rectangle_info.x=x;
6125 }
6126 if (rectangle_info.y < 0)
6127 rectangle_info.y=0;
6128 else
6129 if (rectangle_info.y > (int) windows->image.height)
cristybb503372010-05-27 20:51:26 +00006130 rectangle_info.y=(ssize_t) windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +00006131 if ((int) rectangle_info.y < y)
6132 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6133 else
6134 {
6135 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6136 rectangle_info.y=y;
6137 }
6138 }
6139 } while ((state & ExitState) == 0);
6140 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6141 if ((element == PointElement) || (element == PolygonElement) ||
6142 (element == FillPolygonElement))
6143 {
6144 /*
6145 Determine polygon bounding box.
6146 */
6147 rectangle_info.x=coordinate_info->x;
6148 rectangle_info.y=coordinate_info->y;
6149 x=coordinate_info->x;
6150 y=coordinate_info->y;
6151 for (i=1; i < number_coordinates; i++)
6152 {
6153 if (coordinate_info[i].x > x)
6154 x=coordinate_info[i].x;
6155 if (coordinate_info[i].y > y)
6156 y=coordinate_info[i].y;
6157 if (coordinate_info[i].x < rectangle_info.x)
6158 rectangle_info.x=MagickMax(coordinate_info[i].x,0);
6159 if (coordinate_info[i].y < rectangle_info.y)
6160 rectangle_info.y=MagickMax(coordinate_info[i].y,0);
6161 }
cristybb503372010-05-27 20:51:26 +00006162 rectangle_info.width=(size_t) (x-rectangle_info.x);
6163 rectangle_info.height=(size_t) (y-rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006164 for (i=0; i < number_coordinates; i++)
6165 {
6166 coordinate_info[i].x-=rectangle_info.x;
6167 coordinate_info[i].y-=rectangle_info.y;
6168 }
6169 }
6170 else
6171 if (distance <= 9)
6172 continue;
6173 else
6174 if ((element == RectangleElement) ||
6175 (element == CircleElement) || (element == EllipseElement))
6176 {
6177 rectangle_info.width--;
6178 rectangle_info.height--;
6179 }
6180 /*
6181 Drawing is relative to image configuration.
6182 */
6183 draw_info.x=(int) rectangle_info.x;
6184 draw_info.y=(int) rectangle_info.y;
6185 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6186 image);
6187 width=(unsigned int) (*image)->columns;
6188 height=(unsigned int) (*image)->rows;
6189 x=0;
6190 y=0;
6191 if (windows->image.crop_geometry != (char *) NULL)
6192 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6193 draw_info.x+=windows->image.x-(line_width/2);
6194 if (draw_info.x < 0)
6195 draw_info.x=0;
6196 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6197 draw_info.y+=windows->image.y-(line_width/2);
6198 if (draw_info.y < 0)
6199 draw_info.y=0;
6200 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6201 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6202 if (draw_info.width > (unsigned int) (*image)->columns)
6203 draw_info.width=(unsigned int) (*image)->columns;
6204 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6205 if (draw_info.height > (unsigned int) (*image)->rows)
6206 draw_info.height=(unsigned int) (*image)->rows;
6207 (void) FormatMagickString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6208 width*draw_info.width/windows->image.ximage->width,
6209 height*draw_info.height/windows->image.ximage->height,
6210 draw_info.x+x,draw_info.y+y);
6211 /*
6212 Initialize drawing attributes.
6213 */
6214 draw_info.degrees=0.0;
6215 draw_info.element=element;
6216 draw_info.stipple=stipple;
6217 draw_info.line_width=line_width;
6218 draw_info.line_info=line_info;
6219 if (line_info.x1 > (int) (line_width/2))
6220 draw_info.line_info.x1=(short) line_width/2;
6221 if (line_info.y1 > (int) (line_width/2))
6222 draw_info.line_info.y1=(short) line_width/2;
6223 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6224 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6225 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6226 {
6227 draw_info.line_info.x2=(-draw_info.line_info.x2);
6228 draw_info.line_info.y2=(-draw_info.line_info.y2);
6229 }
6230 if (draw_info.line_info.x2 < 0)
6231 {
6232 draw_info.line_info.x2=(-draw_info.line_info.x2);
6233 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6234 }
6235 if (draw_info.line_info.y2 < 0)
6236 {
6237 draw_info.line_info.y2=(-draw_info.line_info.y2);
6238 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6239 }
6240 draw_info.rectangle_info=rectangle_info;
6241 if (draw_info.rectangle_info.x > (int) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006242 draw_info.rectangle_info.x=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006243 if (draw_info.rectangle_info.y > (int) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006244 draw_info.rectangle_info.y=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006245 draw_info.number_coordinates=(unsigned int) number_coordinates;
6246 draw_info.coordinate_info=coordinate_info;
6247 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6248 /*
6249 Draw element on image.
6250 */
6251 XSetCursorState(display,windows,MagickTrue);
6252 XCheckRefreshWindows(display,windows);
6253 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6254 XSetCursorState(display,windows,MagickFalse);
6255 /*
6256 Update image colormap and return to image drawing.
6257 */
6258 XConfigureImageColormap(display,resource_info,windows,*image);
6259 (void) XConfigureImage(display,resource_info,windows,*image);
6260 }
6261 XSetCursorState(display,windows,MagickFalse);
6262 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6263 return(status != 0 ? MagickTrue : MagickFalse);
6264}
6265
6266/*
6267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6268% %
6269% %
6270% %
6271+ X D r a w P a n R e c t a n g l e %
6272% %
6273% %
6274% %
6275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6276%
6277% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6278% displays a zoom image and the rectangle shows which portion of the image is
6279% displayed in the Image window.
6280%
6281% The format of the XDrawPanRectangle method is:
6282%
6283% XDrawPanRectangle(Display *display,XWindows *windows)
6284%
6285% A description of each parameter follows:
6286%
6287% o display: Specifies a connection to an X server; returned from
6288% XOpenDisplay.
6289%
6290% o windows: Specifies a pointer to a XWindows structure.
6291%
6292*/
6293static void XDrawPanRectangle(Display *display,XWindows *windows)
6294{
6295 MagickRealType
6296 scale_factor;
6297
6298 RectangleInfo
6299 highlight_info;
6300
6301 /*
6302 Determine dimensions of the panning rectangle.
6303 */
6304 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6305 highlight_info.x=(int) (scale_factor*windows->image.x+0.5);
6306 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6307 scale_factor=(MagickRealType)
6308 windows->pan.height/windows->image.ximage->height;
6309 highlight_info.y=(int) (scale_factor*windows->image.y+0.5);
6310 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6311 /*
6312 Display the panning rectangle.
6313 */
6314 (void) XClearWindow(display,windows->pan.id);
6315 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6316 &highlight_info);
6317}
6318
6319/*
6320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6321% %
6322% %
6323% %
6324+ X I m a g e C a c h e %
6325% %
6326% %
6327% %
6328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6329%
6330% XImageCache() handles the creation, manipulation, and destruction of the
6331% image cache (undo and redo buffers).
6332%
6333% The format of the XImageCache method is:
6334%
6335% void XImageCache(Display *display,XResourceInfo *resource_info,
6336% XWindows *windows,const CommandType command,Image **image)
6337%
6338% A description of each parameter follows:
6339%
6340% o display: Specifies a connection to an X server; returned from
6341% XOpenDisplay.
6342%
6343% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6344%
6345% o windows: Specifies a pointer to a XWindows structure.
6346%
6347% o command: Specifies a command to perform.
6348%
6349% o image: the image; XImageCache
6350% may transform the image and return a new image pointer.
6351%
6352*/
6353static void XImageCache(Display *display,XResourceInfo *resource_info,
6354 XWindows *windows,const CommandType command,Image **image)
6355{
6356 Image
6357 *cache_image;
6358
6359 static Image
6360 *redo_image = (Image *) NULL,
6361 *undo_image = (Image *) NULL;
6362
6363 switch (command)
6364 {
6365 case FreeBuffersCommand:
6366 {
6367 /*
6368 Free memory from the undo and redo cache.
6369 */
6370 while (undo_image != (Image *) NULL)
6371 {
6372 cache_image=undo_image;
6373 undo_image=GetPreviousImageInList(undo_image);
6374 cache_image->list=DestroyImage(cache_image->list);
6375 cache_image=DestroyImage(cache_image);
6376 }
6377 undo_image=NewImageList();
6378 if (redo_image != (Image *) NULL)
6379 redo_image=DestroyImage(redo_image);
6380 redo_image=NewImageList();
6381 return;
6382 }
6383 case UndoCommand:
6384 {
6385 /*
6386 Undo the last image transformation.
6387 */
6388 if (undo_image == (Image *) NULL)
6389 {
6390 (void) XBell(display,0);
6391 return;
6392 }
6393 cache_image=undo_image;
6394 undo_image=GetPreviousImageInList(undo_image);
6395 windows->image.window_changes.width=(int) cache_image->columns;
6396 windows->image.window_changes.height=(int) cache_image->rows;
6397 if (windows->image.crop_geometry != (char *) NULL)
6398 windows->image.crop_geometry=(char *)
6399 RelinquishMagickMemory(windows->image.crop_geometry);
6400 windows->image.crop_geometry=cache_image->geometry;
6401 if (redo_image != (Image *) NULL)
6402 redo_image=DestroyImage(redo_image);
6403 redo_image=(*image);
6404 *image=cache_image->list;
6405 cache_image=DestroyImage(cache_image);
6406 if (windows->image.orphan != MagickFalse)
6407 return;
6408 XConfigureImageColormap(display,resource_info,windows,*image);
6409 (void) XConfigureImage(display,resource_info,windows,*image);
6410 return;
6411 }
6412 case CutCommand:
6413 case PasteCommand:
6414 case ApplyCommand:
6415 case HalfSizeCommand:
6416 case OriginalSizeCommand:
6417 case DoubleSizeCommand:
6418 case ResizeCommand:
6419 case TrimCommand:
6420 case CropCommand:
6421 case ChopCommand:
6422 case FlipCommand:
6423 case FlopCommand:
6424 case RotateRightCommand:
6425 case RotateLeftCommand:
6426 case RotateCommand:
6427 case ShearCommand:
6428 case RollCommand:
6429 case NegateCommand:
6430 case ContrastStretchCommand:
6431 case SigmoidalContrastCommand:
6432 case NormalizeCommand:
6433 case EqualizeCommand:
6434 case HueCommand:
6435 case SaturationCommand:
6436 case BrightnessCommand:
6437 case GammaCommand:
6438 case SpiffCommand:
6439 case DullCommand:
6440 case GrayscaleCommand:
6441 case MapCommand:
6442 case QuantizeCommand:
6443 case DespeckleCommand:
6444 case EmbossCommand:
6445 case ReduceNoiseCommand:
6446 case AddNoiseCommand:
6447 case SharpenCommand:
6448 case BlurCommand:
6449 case ThresholdCommand:
6450 case EdgeDetectCommand:
6451 case SpreadCommand:
6452 case ShadeCommand:
6453 case RaiseCommand:
6454 case SegmentCommand:
6455 case SolarizeCommand:
6456 case SepiaToneCommand:
6457 case SwirlCommand:
6458 case ImplodeCommand:
6459 case VignetteCommand:
6460 case WaveCommand:
6461 case OilPaintCommand:
6462 case CharcoalDrawCommand:
6463 case AnnotateCommand:
6464 case AddBorderCommand:
6465 case AddFrameCommand:
6466 case CompositeCommand:
6467 case CommentCommand:
6468 case LaunchCommand:
6469 case RegionofInterestCommand:
6470 case SaveToUndoBufferCommand:
6471 case RedoCommand:
6472 {
6473 Image
6474 *previous_image;
6475
cristybb503372010-05-27 20:51:26 +00006476 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00006477 bytes;
6478
cristybb503372010-05-27 20:51:26 +00006479 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
cristy3ed852e2009-09-05 21:47:34 +00006480 if (undo_image != (Image *) NULL)
6481 {
6482 /*
6483 Ensure the undo stash.has enough memory available.
6484 */
6485 previous_image=undo_image;
6486 while (previous_image != (Image *) NULL)
6487 {
6488 bytes+=previous_image->list->columns*previous_image->list->rows*
6489 sizeof(PixelPacket);
cristybb503372010-05-27 20:51:26 +00006490 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006491 {
6492 previous_image=GetPreviousImageInList(previous_image);
6493 continue;
6494 }
6495 bytes-=previous_image->list->columns*previous_image->list->rows*
6496 sizeof(PixelPacket);
6497 if (previous_image == undo_image)
6498 undo_image=NewImageList();
6499 else
6500 previous_image->next->previous=NewImageList();
6501 break;
6502 }
6503 while (previous_image != (Image *) NULL)
6504 {
6505 /*
6506 Delete any excess memory from undo cache.
6507 */
6508 cache_image=previous_image;
6509 previous_image=GetPreviousImageInList(previous_image);
6510 cache_image->list=DestroyImage(cache_image->list);
6511 cache_image=DestroyImage(cache_image);
6512 }
6513 }
cristybb503372010-05-27 20:51:26 +00006514 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006515 break;
6516 /*
6517 Save image before transformations are applied.
6518 */
6519 cache_image=AcquireImage((ImageInfo *) NULL);
6520 if (cache_image == (Image *) NULL)
6521 break;
6522 XSetCursorState(display,windows,MagickTrue);
6523 XCheckRefreshWindows(display,windows);
6524 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6525 XSetCursorState(display,windows,MagickFalse);
6526 if (cache_image->list == (Image *) NULL)
6527 {
6528 cache_image=DestroyImage(cache_image);
6529 break;
6530 }
cristybb503372010-05-27 20:51:26 +00006531 cache_image->columns=(size_t) windows->image.ximage->width;
6532 cache_image->rows=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006533 cache_image->geometry=windows->image.crop_geometry;
6534 if (windows->image.crop_geometry != (char *) NULL)
6535 {
6536 cache_image->geometry=AcquireString((char *) NULL);
6537 (void) CopyMagickString(cache_image->geometry,
6538 windows->image.crop_geometry,MaxTextExtent);
6539 }
6540 if (undo_image == (Image *) NULL)
6541 {
6542 undo_image=cache_image;
6543 break;
6544 }
6545 undo_image->next=cache_image;
6546 undo_image->next->previous=undo_image;
6547 undo_image=undo_image->next;
6548 break;
6549 }
6550 default:
6551 break;
6552 }
6553 if (command == RedoCommand)
6554 {
6555 /*
6556 Redo the last image transformation.
6557 */
6558 if (redo_image == (Image *) NULL)
6559 {
6560 (void) XBell(display,0);
6561 return;
6562 }
6563 windows->image.window_changes.width=(int) redo_image->columns;
6564 windows->image.window_changes.height=(int) redo_image->rows;
6565 if (windows->image.crop_geometry != (char *) NULL)
6566 windows->image.crop_geometry=(char *)
6567 RelinquishMagickMemory(windows->image.crop_geometry);
6568 windows->image.crop_geometry=redo_image->geometry;
6569 *image=DestroyImage(*image);
6570 *image=redo_image;
6571 redo_image=NewImageList();
6572 if (windows->image.orphan != MagickFalse)
6573 return;
6574 XConfigureImageColormap(display,resource_info,windows,*image);
6575 (void) XConfigureImage(display,resource_info,windows,*image);
6576 return;
6577 }
6578 if (command != InfoCommand)
6579 return;
6580 /*
6581 Display image info.
6582 */
6583 XSetCursorState(display,windows,MagickTrue);
6584 XCheckRefreshWindows(display,windows);
6585 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6586 XSetCursorState(display,windows,MagickFalse);
6587}
6588
6589/*
6590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6591% %
6592% %
6593% %
6594+ X I m a g e W i n d o w C o m m a n d %
6595% %
6596% %
6597% %
6598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6599%
6600% XImageWindowCommand() makes a transform to the image or Image window as
6601% specified by a user menu button or keyboard command.
6602%
6603% The format of the XMagickCommand method is:
6604%
6605% CommandType XImageWindowCommand(Display *display,
6606% XResourceInfo *resource_info,XWindows *windows,
6607% const MagickStatusType state,KeySym key_symbol,Image **image)
6608%
6609% A description of each parameter follows:
6610%
6611% o nexus: Method XImageWindowCommand returns an image when the
6612% user chooses 'Open Image' from the command menu. Otherwise a null
6613% image is returned.
6614%
6615% o display: Specifies a connection to an X server; returned from
6616% XOpenDisplay.
6617%
6618% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6619%
6620% o windows: Specifies a pointer to a XWindows structure.
6621%
6622% o state: key mask.
6623%
6624% o key_symbol: Specifies a command to perform.
6625%
6626% o image: the image; XImageWIndowCommand
6627% may transform the image and return a new image pointer.
6628%
6629*/
6630static CommandType XImageWindowCommand(Display *display,
6631 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6632 KeySym key_symbol,Image **image)
6633{
6634 static char
6635 delta[MaxTextExtent] = "";
6636
6637 static const char
6638 Digits[] = "01234567890";
6639
6640 static KeySym
6641 last_symbol = XK_0;
6642
6643 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6644 {
6645 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6646 {
6647 *delta='\0';
6648 resource_info->quantum=1;
6649 }
6650 last_symbol=key_symbol;
6651 delta[strlen(delta)+1]='\0';
6652 delta[strlen(delta)]=Digits[key_symbol-XK_0];
cristyf2f27272009-12-17 14:48:46 +00006653 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006654 return(NullCommand);
6655 }
6656 last_symbol=key_symbol;
6657 if (resource_info->immutable)
6658 {
6659 /*
6660 Virtual image window has a restricted command set.
6661 */
6662 switch (key_symbol)
6663 {
6664 case XK_question:
6665 return(InfoCommand);
6666 case XK_p:
6667 case XK_Print:
6668 return(PrintCommand);
6669 case XK_space:
6670 return(NextCommand);
6671 case XK_q:
6672 case XK_Escape:
6673 return(QuitCommand);
6674 default:
6675 break;
6676 }
6677 return(NullCommand);
6678 }
6679 switch ((int) key_symbol)
6680 {
6681 case XK_o:
6682 {
6683 if ((state & ControlMask) == 0)
6684 break;
6685 return(OpenCommand);
6686 }
6687 case XK_space:
6688 return(NextCommand);
6689 case XK_BackSpace:
6690 return(FormerCommand);
6691 case XK_s:
6692 {
6693 if ((state & Mod1Mask) != 0)
6694 return(SwirlCommand);
6695 if ((state & ControlMask) == 0)
6696 return(ShearCommand);
6697 return(SaveCommand);
6698 }
6699 case XK_p:
6700 case XK_Print:
6701 {
6702 if ((state & Mod1Mask) != 0)
6703 return(OilPaintCommand);
6704 if ((state & Mod4Mask) != 0)
6705 return(ColorCommand);
6706 if ((state & ControlMask) == 0)
6707 return(NullCommand);
6708 return(PrintCommand);
6709 }
6710 case XK_d:
6711 {
6712 if ((state & Mod4Mask) != 0)
6713 return(DrawCommand);
6714 if ((state & ControlMask) == 0)
6715 return(NullCommand);
6716 return(DeleteCommand);
6717 }
6718 case XK_Select:
6719 {
6720 if ((state & ControlMask) == 0)
6721 return(NullCommand);
6722 return(SelectCommand);
6723 }
6724 case XK_n:
6725 {
6726 if ((state & ControlMask) == 0)
6727 return(NullCommand);
6728 return(NewCommand);
6729 }
6730 case XK_q:
6731 case XK_Escape:
6732 return(QuitCommand);
6733 case XK_z:
6734 case XK_Undo:
6735 {
6736 if ((state & ControlMask) == 0)
6737 return(NullCommand);
6738 return(UndoCommand);
6739 }
6740 case XK_r:
6741 case XK_Redo:
6742 {
6743 if ((state & ControlMask) == 0)
6744 return(RollCommand);
6745 return(RedoCommand);
6746 }
6747 case XK_x:
6748 {
6749 if ((state & ControlMask) == 0)
6750 return(NullCommand);
6751 return(CutCommand);
6752 }
6753 case XK_c:
6754 {
6755 if ((state & Mod1Mask) != 0)
6756 return(CharcoalDrawCommand);
6757 if ((state & ControlMask) == 0)
6758 return(CropCommand);
6759 return(CopyCommand);
6760 }
6761 case XK_v:
6762 case XK_Insert:
6763 {
6764 if ((state & Mod4Mask) != 0)
6765 return(CompositeCommand);
6766 if ((state & ControlMask) == 0)
6767 return(FlipCommand);
6768 return(PasteCommand);
6769 }
6770 case XK_less:
6771 return(HalfSizeCommand);
6772 case XK_minus:
6773 return(OriginalSizeCommand);
6774 case XK_greater:
6775 return(DoubleSizeCommand);
6776 case XK_percent:
6777 return(ResizeCommand);
6778 case XK_at:
6779 return(RefreshCommand);
6780 case XK_bracketleft:
6781 return(ChopCommand);
6782 case XK_h:
6783 return(FlopCommand);
6784 case XK_slash:
6785 return(RotateRightCommand);
6786 case XK_backslash:
6787 return(RotateLeftCommand);
6788 case XK_asterisk:
6789 return(RotateCommand);
6790 case XK_t:
6791 return(TrimCommand);
6792 case XK_H:
6793 return(HueCommand);
6794 case XK_S:
6795 return(SaturationCommand);
6796 case XK_L:
6797 return(BrightnessCommand);
6798 case XK_G:
6799 return(GammaCommand);
6800 case XK_C:
6801 return(SpiffCommand);
6802 case XK_Z:
6803 return(DullCommand);
6804 case XK_N:
6805 return(NormalizeCommand);
6806 case XK_equal:
6807 return(EqualizeCommand);
6808 case XK_asciitilde:
6809 return(NegateCommand);
6810 case XK_period:
6811 return(GrayscaleCommand);
6812 case XK_numbersign:
6813 return(QuantizeCommand);
6814 case XK_F2:
6815 return(DespeckleCommand);
6816 case XK_F3:
6817 return(EmbossCommand);
6818 case XK_F4:
6819 return(ReduceNoiseCommand);
6820 case XK_F5:
6821 return(AddNoiseCommand);
6822 case XK_F6:
6823 return(SharpenCommand);
6824 case XK_F7:
6825 return(BlurCommand);
6826 case XK_F8:
6827 return(ThresholdCommand);
6828 case XK_F9:
6829 return(EdgeDetectCommand);
6830 case XK_F10:
6831 return(SpreadCommand);
6832 case XK_F11:
6833 return(ShadeCommand);
6834 case XK_F12:
6835 return(RaiseCommand);
6836 case XK_F13:
6837 return(SegmentCommand);
6838 case XK_i:
6839 {
6840 if ((state & Mod1Mask) == 0)
6841 return(NullCommand);
6842 return(ImplodeCommand);
6843 }
6844 case XK_w:
6845 {
6846 if ((state & Mod1Mask) == 0)
6847 return(NullCommand);
6848 return(WaveCommand);
6849 }
6850 case XK_m:
6851 {
6852 if ((state & Mod4Mask) == 0)
6853 return(NullCommand);
6854 return(MatteCommand);
6855 }
6856 case XK_b:
6857 {
6858 if ((state & Mod4Mask) == 0)
6859 return(NullCommand);
6860 return(AddBorderCommand);
6861 }
6862 case XK_f:
6863 {
6864 if ((state & Mod4Mask) == 0)
6865 return(NullCommand);
6866 return(AddFrameCommand);
6867 }
6868 case XK_exclam:
6869 {
6870 if ((state & Mod4Mask) == 0)
6871 return(NullCommand);
6872 return(CommentCommand);
6873 }
6874 case XK_a:
6875 {
6876 if ((state & Mod1Mask) != 0)
6877 return(ApplyCommand);
6878 if ((state & Mod4Mask) != 0)
6879 return(AnnotateCommand);
6880 if ((state & ControlMask) == 0)
6881 return(NullCommand);
6882 return(RegionofInterestCommand);
6883 }
6884 case XK_question:
6885 return(InfoCommand);
6886 case XK_plus:
6887 return(ZoomCommand);
6888 case XK_P:
6889 {
6890 if ((state & ShiftMask) == 0)
6891 return(NullCommand);
6892 return(ShowPreviewCommand);
6893 }
6894 case XK_Execute:
6895 return(LaunchCommand);
6896 case XK_F1:
6897 return(HelpCommand);
6898 case XK_Find:
6899 return(BrowseDocumentationCommand);
6900 case XK_Menu:
6901 {
6902 (void) XMapRaised(display,windows->command.id);
6903 return(NullCommand);
6904 }
6905 case XK_Next:
6906 case XK_Prior:
6907 case XK_Home:
6908 case XK_KP_Home:
6909 {
6910 XTranslateImage(display,windows,*image,key_symbol);
6911 return(NullCommand);
6912 }
6913 case XK_Up:
6914 case XK_KP_Up:
6915 case XK_Down:
6916 case XK_KP_Down:
6917 case XK_Left:
6918 case XK_KP_Left:
6919 case XK_Right:
6920 case XK_KP_Right:
6921 {
6922 if ((state & Mod1Mask) != 0)
6923 {
6924 RectangleInfo
6925 crop_info;
6926
6927 /*
6928 Trim one pixel from edge of image.
6929 */
6930 crop_info.x=0;
6931 crop_info.y=0;
cristybb503372010-05-27 20:51:26 +00006932 crop_info.width=(size_t) windows->image.ximage->width;
6933 crop_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006934 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6935 {
6936 if (resource_info->quantum >= (int) crop_info.height)
6937 resource_info->quantum=(int) crop_info.height-1;
6938 crop_info.height-=resource_info->quantum;
6939 }
6940 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6941 {
6942 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6943 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6944 crop_info.y+=resource_info->quantum;
6945 crop_info.height-=resource_info->quantum;
6946 }
6947 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6948 {
6949 if (resource_info->quantum >= (int) crop_info.width)
6950 resource_info->quantum=(int) crop_info.width-1;
6951 crop_info.width-=resource_info->quantum;
6952 }
6953 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6954 {
6955 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6956 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6957 crop_info.x+=resource_info->quantum;
6958 crop_info.width-=resource_info->quantum;
6959 }
6960 if ((int) (windows->image.x+windows->image.width) >
6961 (int) crop_info.width)
6962 windows->image.x=(int) (crop_info.width-windows->image.width);
6963 if ((int) (windows->image.y+windows->image.height) >
6964 (int) crop_info.height)
6965 windows->image.y=(int) (crop_info.height-windows->image.height);
6966 XSetCropGeometry(display,windows,&crop_info,*image);
6967 windows->image.window_changes.width=(int) crop_info.width;
6968 windows->image.window_changes.height=(int) crop_info.height;
6969 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
6970 (void) XConfigureImage(display,resource_info,windows,*image);
6971 return(NullCommand);
6972 }
6973 XTranslateImage(display,windows,*image,key_symbol);
6974 return(NullCommand);
6975 }
6976 default:
6977 return(NullCommand);
6978 }
6979 return(NullCommand);
6980}
6981
6982/*
6983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6984% %
6985% %
6986% %
6987+ X M a g i c k C o m m a n d %
6988% %
6989% %
6990% %
6991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6992%
6993% XMagickCommand() makes a transform to the image or Image window as
6994% specified by a user menu button or keyboard command.
6995%
6996% The format of the XMagickCommand method is:
6997%
6998% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
6999% XWindows *windows,const CommandType command,Image **image)
7000%
7001% A description of each parameter follows:
7002%
7003% o nexus: Method XMagickCommand returns an image when the
7004% user chooses 'Load Image' from the command menu. Otherwise a null
7005% image is returned.
7006%
7007% o display: Specifies a connection to an X server; returned from
7008% XOpenDisplay.
7009%
7010% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7011%
7012% o windows: Specifies a pointer to a XWindows structure.
7013%
7014% o command: Specifies a command to perform.
7015%
7016% o image: the image; XMagickCommand
7017% may transform the image and return a new image pointer.
7018%
7019*/
7020static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7021 XWindows *windows,const CommandType command,Image **image)
7022{
7023 char
7024 filename[MaxTextExtent],
7025 geometry[MaxTextExtent],
7026 modulate_factors[MaxTextExtent];
7027
7028 GeometryInfo
7029 geometry_info;
7030
7031 Image
7032 *nexus;
7033
7034 ImageInfo
7035 *image_info;
7036
7037 int
7038 x,
7039 y;
7040
7041 MagickStatusType
7042 flags,
7043 status;
7044
7045 QuantizeInfo
7046 quantize_info;
7047
7048 RectangleInfo
7049 page_geometry;
7050
7051 register int
7052 i;
7053
7054 static char
7055 color[MaxTextExtent] = "gray";
7056
7057 unsigned int
7058 height,
7059 width;
7060
7061 /*
7062 Process user command.
7063 */
7064 XCheckRefreshWindows(display,windows);
7065 XImageCache(display,resource_info,windows,command,image);
7066 nexus=NewImageList();
7067 windows->image.window_changes.width=windows->image.ximage->width;
7068 windows->image.window_changes.height=windows->image.ximage->height;
7069 image_info=CloneImageInfo(resource_info->image_info);
7070 SetGeometryInfo(&geometry_info);
7071 GetQuantizeInfo(&quantize_info);
7072 switch (command)
7073 {
7074 case OpenCommand:
7075 {
7076 /*
7077 Load image.
7078 */
7079 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7080 break;
7081 }
7082 case NextCommand:
7083 {
7084 /*
7085 Display next image.
7086 */
7087 for (i=0; i < resource_info->quantum; i++)
7088 XClientMessage(display,windows->image.id,windows->im_protocols,
7089 windows->im_next_image,CurrentTime);
7090 break;
7091 }
7092 case FormerCommand:
7093 {
7094 /*
7095 Display former image.
7096 */
7097 for (i=0; i < resource_info->quantum; i++)
7098 XClientMessage(display,windows->image.id,windows->im_protocols,
7099 windows->im_former_image,CurrentTime);
7100 break;
7101 }
7102 case SelectCommand:
7103 {
7104 int
7105 status;
7106
7107 /*
7108 Select image.
7109 */
7110 status=chdir(resource_info->home_directory);
7111 if (status == -1)
7112 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7113 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7114 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7115 break;
7116 }
7117 case SaveCommand:
7118 {
7119 /*
7120 Save image.
7121 */
7122 status=XSaveImage(display,resource_info,windows,*image);
7123 if (status == MagickFalse)
7124 {
7125 XNoticeWidget(display,windows,"Unable to write X image:",
7126 (*image)->filename);
7127 break;
7128 }
7129 break;
7130 }
7131 case PrintCommand:
7132 {
7133 /*
7134 Print image.
7135 */
7136 status=XPrintImage(display,resource_info,windows,*image);
7137 if (status == MagickFalse)
7138 {
7139 XNoticeWidget(display,windows,"Unable to print X image:",
7140 (*image)->filename);
7141 break;
7142 }
7143 break;
7144 }
7145 case DeleteCommand:
7146 {
7147 static char
7148 filename[MaxTextExtent] = "\0";
7149
7150 /*
7151 Delete image file.
7152 */
7153 XFileBrowserWidget(display,windows,"Delete",filename);
7154 if (*filename == '\0')
7155 break;
7156 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7157 if (status != MagickFalse)
7158 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7159 break;
7160 }
7161 case NewCommand:
7162 {
7163 int
7164 status;
7165
7166 static char
7167 color[MaxTextExtent] = "gray",
7168 geometry[MaxTextExtent] = "640x480";
7169
7170 static const char
7171 *format = "gradient";
7172
7173 /*
7174 Query user for canvas geometry.
7175 */
7176 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7177 geometry);
7178 if (*geometry == '\0')
7179 break;
7180 if (status == 0)
7181 format="xc";
7182 XColorBrowserWidget(display,windows,"Select",color);
7183 if (*color == '\0')
7184 break;
7185 /*
7186 Create canvas.
7187 */
7188 (void) FormatMagickString(image_info->filename,MaxTextExtent,
7189 "%s:%s",format,color);
7190 (void) CloneString(&image_info->size,geometry);
7191 nexus=ReadImage(image_info,&(*image)->exception);
7192 CatchException(&(*image)->exception);
7193 XClientMessage(display,windows->image.id,windows->im_protocols,
7194 windows->im_next_image,CurrentTime);
7195 break;
7196 }
7197 case VisualDirectoryCommand:
7198 {
7199 /*
7200 Visual Image directory.
7201 */
7202 nexus=XVisualDirectoryImage(display,resource_info,windows);
7203 break;
7204 }
7205 case QuitCommand:
7206 {
7207 /*
7208 exit program.
7209 */
7210 if (resource_info->confirm_exit == MagickFalse)
7211 XClientMessage(display,windows->image.id,windows->im_protocols,
7212 windows->im_exit,CurrentTime);
7213 else
7214 {
7215 int
7216 status;
7217
7218 /*
7219 Confirm program exit.
7220 */
7221 status=XConfirmWidget(display,windows,"Do you really want to exit",
7222 resource_info->client_name);
7223 if (status > 0)
7224 XClientMessage(display,windows->image.id,windows->im_protocols,
7225 windows->im_exit,CurrentTime);
7226 }
7227 break;
7228 }
7229 case CutCommand:
7230 {
7231 /*
7232 Cut image.
7233 */
7234 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7235 break;
7236 }
7237 case CopyCommand:
7238 {
7239 /*
7240 Copy image.
7241 */
7242 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7243 break;
7244 }
7245 case PasteCommand:
7246 {
7247 /*
7248 Paste image.
7249 */
7250 status=XPasteImage(display,resource_info,windows,*image);
7251 if (status == MagickFalse)
7252 {
7253 XNoticeWidget(display,windows,"Unable to paste X image",
7254 (*image)->filename);
7255 break;
7256 }
7257 break;
7258 }
7259 case HalfSizeCommand:
7260 {
7261 /*
7262 Half image size.
7263 */
7264 windows->image.window_changes.width=windows->image.ximage->width/2;
7265 windows->image.window_changes.height=windows->image.ximage->height/2;
7266 (void) XConfigureImage(display,resource_info,windows,*image);
7267 break;
7268 }
7269 case OriginalSizeCommand:
7270 {
7271 /*
7272 Original image size.
7273 */
7274 windows->image.window_changes.width=(int) (*image)->columns;
7275 windows->image.window_changes.height=(int) (*image)->rows;
7276 (void) XConfigureImage(display,resource_info,windows,*image);
7277 break;
7278 }
7279 case DoubleSizeCommand:
7280 {
7281 /*
7282 Double the image size.
7283 */
7284 windows->image.window_changes.width=windows->image.ximage->width << 1;
7285 windows->image.window_changes.height=windows->image.ximage->height << 1;
7286 (void) XConfigureImage(display,resource_info,windows,*image);
7287 break;
7288 }
7289 case ResizeCommand:
7290 {
7291 int
7292 status;
7293
cristybb503372010-05-27 20:51:26 +00007294 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00007295 x,
7296 y;
7297
cristybb503372010-05-27 20:51:26 +00007298 size_t
cristy3ed852e2009-09-05 21:47:34 +00007299 height,
7300 width;
7301
7302 /*
7303 Resize image.
7304 */
cristybb503372010-05-27 20:51:26 +00007305 width=(size_t) windows->image.ximage->width;
7306 height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007307 x=0;
7308 y=0;
cristye8c25f92010-06-03 00:53:06 +00007309 (void) FormatMagickString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7310 (double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00007311 status=XDialogWidget(display,windows,"Resize",
7312 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7313 if (*geometry == '\0')
7314 break;
7315 if (status == 0)
7316 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7317 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7318 windows->image.window_changes.width=(int) width;
7319 windows->image.window_changes.height=(int) height;
7320 (void) XConfigureImage(display,resource_info,windows,*image);
7321 break;
7322 }
7323 case ApplyCommand:
7324 {
7325 char
7326 image_geometry[MaxTextExtent];
7327
7328 if ((windows->image.crop_geometry == (char *) NULL) &&
7329 ((int) (*image)->columns == windows->image.ximage->width) &&
7330 ((int) (*image)->rows == windows->image.ximage->height))
7331 break;
7332 /*
7333 Apply size transforms to image.
7334 */
7335 XSetCursorState(display,windows,MagickTrue);
7336 XCheckRefreshWindows(display,windows);
7337 /*
7338 Crop and/or scale displayed image.
7339 */
7340 (void) FormatMagickString(image_geometry,MaxTextExtent,"%dx%d!",
7341 windows->image.ximage->width,windows->image.ximage->height);
7342 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7343 if (windows->image.crop_geometry != (char *) NULL)
7344 windows->image.crop_geometry=(char *)
7345 RelinquishMagickMemory(windows->image.crop_geometry);
7346 windows->image.x=0;
7347 windows->image.y=0;
7348 XConfigureImageColormap(display,resource_info,windows,*image);
7349 (void) XConfigureImage(display,resource_info,windows,*image);
7350 break;
7351 }
7352 case RefreshCommand:
7353 {
7354 (void) XConfigureImage(display,resource_info,windows,*image);
7355 break;
7356 }
7357 case RestoreCommand:
7358 {
7359 /*
7360 Restore Image window to its original size.
7361 */
7362 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7363 (windows->image.height == (unsigned int) (*image)->rows) &&
7364 (windows->image.crop_geometry == (char *) NULL))
7365 {
7366 (void) XBell(display,0);
7367 break;
7368 }
7369 windows->image.window_changes.width=(int) (*image)->columns;
7370 windows->image.window_changes.height=(int) (*image)->rows;
7371 if (windows->image.crop_geometry != (char *) NULL)
7372 {
7373 windows->image.crop_geometry=(char *)
7374 RelinquishMagickMemory(windows->image.crop_geometry);
7375 windows->image.crop_geometry=(char *) NULL;
7376 windows->image.x=0;
7377 windows->image.y=0;
7378 }
7379 XConfigureImageColormap(display,resource_info,windows,*image);
7380 (void) XConfigureImage(display,resource_info,windows,*image);
7381 break;
7382 }
7383 case CropCommand:
7384 {
7385 /*
7386 Crop image.
7387 */
7388 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7389 break;
7390 }
7391 case ChopCommand:
7392 {
7393 /*
7394 Chop image.
7395 */
7396 status=XChopImage(display,resource_info,windows,image);
7397 if (status == MagickFalse)
7398 {
7399 XNoticeWidget(display,windows,"Unable to cut X image",
7400 (*image)->filename);
7401 break;
7402 }
7403 break;
7404 }
7405 case FlopCommand:
7406 {
7407 Image
7408 *flop_image;
7409
7410 /*
7411 Flop image scanlines.
7412 */
7413 XSetCursorState(display,windows,MagickTrue);
7414 XCheckRefreshWindows(display,windows);
7415 flop_image=FlopImage(*image,&(*image)->exception);
7416 if (flop_image != (Image *) NULL)
7417 {
7418 *image=DestroyImage(*image);
7419 *image=flop_image;
7420 }
7421 CatchException(&(*image)->exception);
7422 XSetCursorState(display,windows,MagickFalse);
7423 if (windows->image.crop_geometry != (char *) NULL)
7424 {
7425 /*
7426 Flop crop geometry.
7427 */
7428 width=(unsigned int) (*image)->columns;
7429 height=(unsigned int) (*image)->rows;
7430 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7431 &width,&height);
7432 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7433 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7434 }
7435 if (windows->image.orphan != MagickFalse)
7436 break;
7437 (void) XConfigureImage(display,resource_info,windows,*image);
7438 break;
7439 }
7440 case FlipCommand:
7441 {
7442 Image
7443 *flip_image;
7444
7445 /*
7446 Flip image scanlines.
7447 */
7448 XSetCursorState(display,windows,MagickTrue);
7449 XCheckRefreshWindows(display,windows);
7450 flip_image=FlipImage(*image,&(*image)->exception);
7451 if (flip_image != (Image *) NULL)
7452 {
7453 *image=DestroyImage(*image);
7454 *image=flip_image;
7455 }
7456 CatchException(&(*image)->exception);
7457 XSetCursorState(display,windows,MagickFalse);
7458 if (windows->image.crop_geometry != (char *) NULL)
7459 {
7460 /*
7461 Flip crop geometry.
7462 */
7463 width=(unsigned int) (*image)->columns;
7464 height=(unsigned int) (*image)->rows;
7465 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7466 &width,&height);
7467 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7468 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7469 }
7470 if (windows->image.orphan != MagickFalse)
7471 break;
7472 (void) XConfigureImage(display,resource_info,windows,*image);
7473 break;
7474 }
7475 case RotateRightCommand:
7476 {
7477 /*
7478 Rotate image 90 degrees clockwise.
7479 */
7480 status=XRotateImage(display,resource_info,windows,90.0,image);
7481 if (status == MagickFalse)
7482 {
7483 XNoticeWidget(display,windows,"Unable to rotate X image",
7484 (*image)->filename);
7485 break;
7486 }
7487 break;
7488 }
7489 case RotateLeftCommand:
7490 {
7491 /*
7492 Rotate image 90 degrees counter-clockwise.
7493 */
7494 status=XRotateImage(display,resource_info,windows,-90.0,image);
7495 if (status == MagickFalse)
7496 {
7497 XNoticeWidget(display,windows,"Unable to rotate X image",
7498 (*image)->filename);
7499 break;
7500 }
7501 break;
7502 }
7503 case RotateCommand:
7504 {
7505 /*
7506 Rotate image.
7507 */
7508 status=XRotateImage(display,resource_info,windows,0.0,image);
7509 if (status == MagickFalse)
7510 {
7511 XNoticeWidget(display,windows,"Unable to rotate X image",
7512 (*image)->filename);
7513 break;
7514 }
7515 break;
7516 }
7517 case ShearCommand:
7518 {
7519 Image
7520 *shear_image;
7521
7522 static char
7523 geometry[MaxTextExtent] = "45.0x45.0";
7524
7525 /*
7526 Query user for shear color and geometry.
7527 */
7528 XColorBrowserWidget(display,windows,"Select",color);
7529 if (*color == '\0')
7530 break;
7531 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7532 geometry);
7533 if (*geometry == '\0')
7534 break;
7535 /*
7536 Shear image.
7537 */
7538 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7539 XSetCursorState(display,windows,MagickTrue);
7540 XCheckRefreshWindows(display,windows);
7541 (void) QueryColorDatabase(color,&(*image)->background_color,
7542 &(*image)->exception);
7543 flags=ParseGeometry(geometry,&geometry_info);
7544 if ((flags & SigmaValue) == 0)
7545 geometry_info.sigma=geometry_info.rho;
7546 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7547 &(*image)->exception);
7548 if (shear_image != (Image *) NULL)
7549 {
7550 *image=DestroyImage(*image);
7551 *image=shear_image;
7552 }
7553 CatchException(&(*image)->exception);
7554 XSetCursorState(display,windows,MagickFalse);
7555 if (windows->image.orphan != MagickFalse)
7556 break;
7557 windows->image.window_changes.width=(int) (*image)->columns;
7558 windows->image.window_changes.height=(int) (*image)->rows;
7559 XConfigureImageColormap(display,resource_info,windows,*image);
7560 (void) XConfigureImage(display,resource_info,windows,*image);
7561 break;
7562 }
7563 case RollCommand:
7564 {
7565 Image
7566 *roll_image;
7567
7568 static char
7569 geometry[MaxTextExtent] = "+2+2";
7570
7571 /*
7572 Query user for the roll geometry.
7573 */
7574 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7575 geometry);
7576 if (*geometry == '\0')
7577 break;
7578 /*
7579 Roll image.
7580 */
7581 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7582 XSetCursorState(display,windows,MagickTrue);
7583 XCheckRefreshWindows(display,windows);
7584 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7585 &(*image)->exception);
7586 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7587 &(*image)->exception);
7588 if (roll_image != (Image *) NULL)
7589 {
7590 *image=DestroyImage(*image);
7591 *image=roll_image;
7592 }
7593 CatchException(&(*image)->exception);
7594 XSetCursorState(display,windows,MagickFalse);
7595 if (windows->image.orphan != MagickFalse)
7596 break;
7597 windows->image.window_changes.width=(int) (*image)->columns;
7598 windows->image.window_changes.height=(int) (*image)->rows;
7599 XConfigureImageColormap(display,resource_info,windows,*image);
7600 (void) XConfigureImage(display,resource_info,windows,*image);
7601 break;
7602 }
7603 case TrimCommand:
7604 {
7605 static char
7606 fuzz[MaxTextExtent];
7607
7608 /*
7609 Query user for the fuzz factor.
7610 */
cristye7f51092010-01-17 00:39:37 +00007611 (void) FormatMagickString(fuzz,MaxTextExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007612 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007613 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7614 if (*fuzz == '\0')
7615 break;
cristyf2f27272009-12-17 14:48:46 +00007616 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007617 /*
7618 Trim image.
7619 */
7620 status=XTrimImage(display,resource_info,windows,*image);
7621 if (status == MagickFalse)
7622 {
7623 XNoticeWidget(display,windows,"Unable to trim X image",
7624 (*image)->filename);
7625 break;
7626 }
7627 break;
7628 }
7629 case HueCommand:
7630 {
7631 static char
7632 hue_percent[MaxTextExtent] = "110";
7633
7634 /*
7635 Query user for percent hue change.
7636 */
7637 (void) XDialogWidget(display,windows,"Apply",
7638 "Enter percent change in image hue (0-200):",hue_percent);
7639 if (*hue_percent == '\0')
7640 break;
7641 /*
7642 Vary the image hue.
7643 */
7644 XSetCursorState(display,windows,MagickTrue);
7645 XCheckRefreshWindows(display,windows);
7646 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7647 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7648 MaxTextExtent);
7649 (void) ModulateImage(*image,modulate_factors);
7650 XSetCursorState(display,windows,MagickFalse);
7651 if (windows->image.orphan != MagickFalse)
7652 break;
7653 XConfigureImageColormap(display,resource_info,windows,*image);
7654 (void) XConfigureImage(display,resource_info,windows,*image);
7655 break;
7656 }
7657 case SaturationCommand:
7658 {
7659 static char
7660 saturation_percent[MaxTextExtent] = "110";
7661
7662 /*
7663 Query user for percent saturation change.
7664 */
7665 (void) XDialogWidget(display,windows,"Apply",
7666 "Enter percent change in color saturation (0-200):",saturation_percent);
7667 if (*saturation_percent == '\0')
7668 break;
7669 /*
7670 Vary color saturation.
7671 */
7672 XSetCursorState(display,windows,MagickTrue);
7673 XCheckRefreshWindows(display,windows);
7674 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7675 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7676 MaxTextExtent);
7677 (void) ModulateImage(*image,modulate_factors);
7678 XSetCursorState(display,windows,MagickFalse);
7679 if (windows->image.orphan != MagickFalse)
7680 break;
7681 XConfigureImageColormap(display,resource_info,windows,*image);
7682 (void) XConfigureImage(display,resource_info,windows,*image);
7683 break;
7684 }
7685 case BrightnessCommand:
7686 {
7687 static char
7688 brightness_percent[MaxTextExtent] = "110";
7689
7690 /*
7691 Query user for percent brightness change.
7692 */
7693 (void) XDialogWidget(display,windows,"Apply",
7694 "Enter percent change in color brightness (0-200):",brightness_percent);
7695 if (*brightness_percent == '\0')
7696 break;
7697 /*
7698 Vary the color brightness.
7699 */
7700 XSetCursorState(display,windows,MagickTrue);
7701 XCheckRefreshWindows(display,windows);
7702 (void) CopyMagickString(modulate_factors,brightness_percent,
7703 MaxTextExtent);
7704 (void) ModulateImage(*image,modulate_factors);
7705 XSetCursorState(display,windows,MagickFalse);
7706 if (windows->image.orphan != MagickFalse)
7707 break;
7708 XConfigureImageColormap(display,resource_info,windows,*image);
7709 (void) XConfigureImage(display,resource_info,windows,*image);
7710 break;
7711 }
7712 case GammaCommand:
7713 {
7714 static char
7715 factor[MaxTextExtent] = "1.6";
7716
7717 /*
7718 Query user for gamma value.
7719 */
7720 (void) XDialogWidget(display,windows,"Gamma",
7721 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7722 if (*factor == '\0')
7723 break;
7724 /*
7725 Gamma correct image.
7726 */
7727 XSetCursorState(display,windows,MagickTrue);
7728 XCheckRefreshWindows(display,windows);
7729 (void) GammaImage(*image,factor);
7730 XSetCursorState(display,windows,MagickFalse);
7731 if (windows->image.orphan != MagickFalse)
7732 break;
7733 XConfigureImageColormap(display,resource_info,windows,*image);
7734 (void) XConfigureImage(display,resource_info,windows,*image);
7735 break;
7736 }
7737 case SpiffCommand:
7738 {
7739 /*
7740 Sharpen the image contrast.
7741 */
7742 XSetCursorState(display,windows,MagickTrue);
7743 XCheckRefreshWindows(display,windows);
7744 (void) ContrastImage(*image,MagickTrue);
7745 XSetCursorState(display,windows,MagickFalse);
7746 if (windows->image.orphan != MagickFalse)
7747 break;
7748 XConfigureImageColormap(display,resource_info,windows,*image);
7749 (void) XConfigureImage(display,resource_info,windows,*image);
7750 break;
7751 }
7752 case DullCommand:
7753 {
7754 /*
7755 Dull the image contrast.
7756 */
7757 XSetCursorState(display,windows,MagickTrue);
7758 XCheckRefreshWindows(display,windows);
7759 (void) ContrastImage(*image,MagickFalse);
7760 XSetCursorState(display,windows,MagickFalse);
7761 if (windows->image.orphan != MagickFalse)
7762 break;
7763 XConfigureImageColormap(display,resource_info,windows,*image);
7764 (void) XConfigureImage(display,resource_info,windows,*image);
7765 break;
7766 }
7767 case ContrastStretchCommand:
7768 {
7769 double
7770 black_point,
7771 white_point;
7772
7773 static char
7774 levels[MaxTextExtent] = "1%";
7775
7776 /*
7777 Query user for gamma value.
7778 */
7779 (void) XDialogWidget(display,windows,"Contrast Stretch",
7780 "Enter black and white points:",levels);
7781 if (*levels == '\0')
7782 break;
7783 /*
7784 Contrast stretch image.
7785 */
7786 XSetCursorState(display,windows,MagickTrue);
7787 XCheckRefreshWindows(display,windows);
7788 flags=ParseGeometry(levels,&geometry_info);
7789 black_point=geometry_info.rho;
7790 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7791 if ((flags & PercentValue) != 0)
7792 {
7793 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7794 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7795 }
7796 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7797 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7798 white_point);
7799 XSetCursorState(display,windows,MagickFalse);
7800 if (windows->image.orphan != MagickFalse)
7801 break;
7802 XConfigureImageColormap(display,resource_info,windows,*image);
7803 (void) XConfigureImage(display,resource_info,windows,*image);
7804 break;
7805 }
7806 case SigmoidalContrastCommand:
7807 {
7808 static char
7809 levels[MaxTextExtent] = "3x50%";
7810
7811 /*
7812 Query user for gamma value.
7813 */
7814 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7815 "Enter contrast and midpoint:",levels);
7816 if (*levels == '\0')
7817 break;
7818 /*
7819 Contrast stretch image.
7820 */
7821 XSetCursorState(display,windows,MagickTrue);
7822 XCheckRefreshWindows(display,windows);
7823 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
7824 XSetCursorState(display,windows,MagickFalse);
7825 if (windows->image.orphan != MagickFalse)
7826 break;
7827 XConfigureImageColormap(display,resource_info,windows,*image);
7828 (void) XConfigureImage(display,resource_info,windows,*image);
7829 break;
7830 }
7831 case NormalizeCommand:
7832 {
7833 /*
7834 Perform histogram normalization on the image.
7835 */
7836 XSetCursorState(display,windows,MagickTrue);
7837 XCheckRefreshWindows(display,windows);
7838 (void) NormalizeImage(*image);
7839 XSetCursorState(display,windows,MagickFalse);
7840 if (windows->image.orphan != MagickFalse)
7841 break;
7842 XConfigureImageColormap(display,resource_info,windows,*image);
7843 (void) XConfigureImage(display,resource_info,windows,*image);
7844 break;
7845 }
7846 case EqualizeCommand:
7847 {
7848 /*
7849 Perform histogram equalization on the image.
7850 */
7851 XSetCursorState(display,windows,MagickTrue);
7852 XCheckRefreshWindows(display,windows);
7853 (void) EqualizeImage(*image);
7854 XSetCursorState(display,windows,MagickFalse);
7855 if (windows->image.orphan != MagickFalse)
7856 break;
7857 XConfigureImageColormap(display,resource_info,windows,*image);
7858 (void) XConfigureImage(display,resource_info,windows,*image);
7859 break;
7860 }
7861 case NegateCommand:
7862 {
7863 /*
7864 Negate colors in image.
7865 */
7866 XSetCursorState(display,windows,MagickTrue);
7867 XCheckRefreshWindows(display,windows);
7868 (void) NegateImage(*image,MagickFalse);
7869 XSetCursorState(display,windows,MagickFalse);
7870 if (windows->image.orphan != MagickFalse)
7871 break;
7872 XConfigureImageColormap(display,resource_info,windows,*image);
7873 (void) XConfigureImage(display,resource_info,windows,*image);
7874 break;
7875 }
7876 case GrayscaleCommand:
7877 {
7878 /*
7879 Convert image to grayscale.
7880 */
7881 XSetCursorState(display,windows,MagickTrue);
7882 XCheckRefreshWindows(display,windows);
7883 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7884 GrayscaleType : GrayscaleMatteType);
7885 XSetCursorState(display,windows,MagickFalse);
7886 if (windows->image.orphan != MagickFalse)
7887 break;
7888 XConfigureImageColormap(display,resource_info,windows,*image);
7889 (void) XConfigureImage(display,resource_info,windows,*image);
7890 break;
7891 }
7892 case MapCommand:
7893 {
7894 Image
7895 *affinity_image;
7896
7897 static char
7898 filename[MaxTextExtent] = "\0";
7899
7900 /*
7901 Request image file name from user.
7902 */
7903 XFileBrowserWidget(display,windows,"Map",filename);
7904 if (*filename == '\0')
7905 break;
7906 /*
7907 Map image.
7908 */
7909 XSetCursorState(display,windows,MagickTrue);
7910 XCheckRefreshWindows(display,windows);
7911 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7912 affinity_image=ReadImage(image_info,&(*image)->exception);
7913 if (affinity_image != (Image *) NULL)
7914 {
7915 (void) RemapImage(&quantize_info,*image,affinity_image);
7916 affinity_image=DestroyImage(affinity_image);
7917 }
7918 CatchException(&(*image)->exception);
7919 XSetCursorState(display,windows,MagickFalse);
7920 if (windows->image.orphan != MagickFalse)
7921 break;
7922 XConfigureImageColormap(display,resource_info,windows,*image);
7923 (void) XConfigureImage(display,resource_info,windows,*image);
7924 break;
7925 }
7926 case QuantizeCommand:
7927 {
7928 int
7929 status;
7930
7931 static char
7932 colors[MaxTextExtent] = "256";
7933
7934 /*
7935 Query user for maximum number of colors.
7936 */
7937 status=XDialogWidget(display,windows,"Quantize",
7938 "Maximum number of colors:",colors);
7939 if (*colors == '\0')
7940 break;
7941 /*
7942 Color reduce the image.
7943 */
7944 XSetCursorState(display,windows,MagickTrue);
7945 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00007946 quantize_info.number_colors=StringToUnsignedLong(colors);
cristy3ed852e2009-09-05 21:47:34 +00007947 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7948 (void) QuantizeImage(&quantize_info,*image);
7949 XSetCursorState(display,windows,MagickFalse);
7950 if (windows->image.orphan != MagickFalse)
7951 break;
7952 XConfigureImageColormap(display,resource_info,windows,*image);
7953 (void) XConfigureImage(display,resource_info,windows,*image);
7954 break;
7955 }
7956 case DespeckleCommand:
7957 {
7958 Image
7959 *despeckle_image;
7960
7961 /*
7962 Despeckle image.
7963 */
7964 XSetCursorState(display,windows,MagickTrue);
7965 XCheckRefreshWindows(display,windows);
7966 despeckle_image=DespeckleImage(*image,&(*image)->exception);
7967 if (despeckle_image != (Image *) NULL)
7968 {
7969 *image=DestroyImage(*image);
7970 *image=despeckle_image;
7971 }
7972 CatchException(&(*image)->exception);
7973 XSetCursorState(display,windows,MagickFalse);
7974 if (windows->image.orphan != MagickFalse)
7975 break;
7976 XConfigureImageColormap(display,resource_info,windows,*image);
7977 (void) XConfigureImage(display,resource_info,windows,*image);
7978 break;
7979 }
7980 case EmbossCommand:
7981 {
7982 Image
7983 *emboss_image;
7984
7985 static char
7986 radius[MaxTextExtent] = "0.0x1.0";
7987
7988 /*
7989 Query user for emboss radius.
7990 */
7991 (void) XDialogWidget(display,windows,"Emboss",
7992 "Enter the emboss radius and standard deviation:",radius);
7993 if (*radius == '\0')
7994 break;
7995 /*
7996 Reduce noise in the image.
7997 */
7998 XSetCursorState(display,windows,MagickTrue);
7999 XCheckRefreshWindows(display,windows);
8000 flags=ParseGeometry(radius,&geometry_info);
8001 if ((flags & SigmaValue) == 0)
8002 geometry_info.sigma=1.0;
8003 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8004 &(*image)->exception);
8005 if (emboss_image != (Image *) NULL)
8006 {
8007 *image=DestroyImage(*image);
8008 *image=emboss_image;
8009 }
8010 CatchException(&(*image)->exception);
8011 XSetCursorState(display,windows,MagickFalse);
8012 if (windows->image.orphan != MagickFalse)
8013 break;
8014 XConfigureImageColormap(display,resource_info,windows,*image);
8015 (void) XConfigureImage(display,resource_info,windows,*image);
8016 break;
8017 }
8018 case ReduceNoiseCommand:
8019 {
8020 Image
8021 *noise_image;
8022
8023 static char
8024 radius[MaxTextExtent] = "0";
8025
8026 /*
8027 Query user for noise radius.
8028 */
8029 (void) XDialogWidget(display,windows,"Reduce Noise",
8030 "Enter the noise radius:",radius);
8031 if (*radius == '\0')
8032 break;
8033 /*
8034 Reduce noise in the image.
8035 */
8036 XSetCursorState(display,windows,MagickTrue);
8037 XCheckRefreshWindows(display,windows);
8038 flags=ParseGeometry(radius,&geometry_info);
8039 noise_image=ReduceNoiseImage(*image,geometry_info.rho,
8040 &(*image)->exception);
8041 if (noise_image != (Image *) NULL)
8042 {
8043 *image=DestroyImage(*image);
8044 *image=noise_image;
8045 }
8046 CatchException(&(*image)->exception);
8047 XSetCursorState(display,windows,MagickFalse);
8048 if (windows->image.orphan != MagickFalse)
8049 break;
8050 XConfigureImageColormap(display,resource_info,windows,*image);
8051 (void) XConfigureImage(display,resource_info,windows,*image);
8052 break;
8053 }
8054 case AddNoiseCommand:
8055 {
8056 char
8057 **noises;
8058
8059 Image
8060 *noise_image;
8061
8062 static char
8063 noise_type[MaxTextExtent] = "Gaussian";
8064
8065 /*
8066 Add noise to the image.
8067 */
8068 noises=GetMagickOptions(MagickNoiseOptions);
8069 if (noises == (char **) NULL)
8070 break;
8071 XListBrowserWidget(display,windows,&windows->widget,
8072 (const char **) noises,"Add Noise",
8073 "Select a type of noise to add to your image:",noise_type);
8074 noises=DestroyStringList(noises);
8075 if (*noise_type == '\0')
8076 break;
8077 XSetCursorState(display,windows,MagickTrue);
8078 XCheckRefreshWindows(display,windows);
8079 noise_image=AddNoiseImage(*image,(NoiseType) ParseMagickOption(
8080 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8081 if (noise_image != (Image *) NULL)
8082 {
8083 *image=DestroyImage(*image);
8084 *image=noise_image;
8085 }
8086 CatchException(&(*image)->exception);
8087 XSetCursorState(display,windows,MagickFalse);
8088 if (windows->image.orphan != MagickFalse)
8089 break;
8090 XConfigureImageColormap(display,resource_info,windows,*image);
8091 (void) XConfigureImage(display,resource_info,windows,*image);
8092 break;
8093 }
8094 case SharpenCommand:
8095 {
8096 Image
8097 *sharp_image;
8098
8099 static char
8100 radius[MaxTextExtent] = "0.0x1.0";
8101
8102 /*
8103 Query user for sharpen radius.
8104 */
8105 (void) XDialogWidget(display,windows,"Sharpen",
8106 "Enter the sharpen radius and standard deviation:",radius);
8107 if (*radius == '\0')
8108 break;
8109 /*
8110 Sharpen image scanlines.
8111 */
8112 XSetCursorState(display,windows,MagickTrue);
8113 XCheckRefreshWindows(display,windows);
8114 flags=ParseGeometry(radius,&geometry_info);
8115 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8116 &(*image)->exception);
8117 if (sharp_image != (Image *) NULL)
8118 {
8119 *image=DestroyImage(*image);
8120 *image=sharp_image;
8121 }
8122 CatchException(&(*image)->exception);
8123 XSetCursorState(display,windows,MagickFalse);
8124 if (windows->image.orphan != MagickFalse)
8125 break;
8126 XConfigureImageColormap(display,resource_info,windows,*image);
8127 (void) XConfigureImage(display,resource_info,windows,*image);
8128 break;
8129 }
8130 case BlurCommand:
8131 {
8132 Image
8133 *blur_image;
8134
8135 static char
8136 radius[MaxTextExtent] = "0.0x1.0";
8137
8138 /*
8139 Query user for blur radius.
8140 */
8141 (void) XDialogWidget(display,windows,"Blur",
8142 "Enter the blur radius and standard deviation:",radius);
8143 if (*radius == '\0')
8144 break;
8145 /*
8146 Blur an image.
8147 */
8148 XSetCursorState(display,windows,MagickTrue);
8149 XCheckRefreshWindows(display,windows);
8150 flags=ParseGeometry(radius,&geometry_info);
8151 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8152 &(*image)->exception);
8153 if (blur_image != (Image *) NULL)
8154 {
8155 *image=DestroyImage(*image);
8156 *image=blur_image;
8157 }
8158 CatchException(&(*image)->exception);
8159 XSetCursorState(display,windows,MagickFalse);
8160 if (windows->image.orphan != MagickFalse)
8161 break;
8162 XConfigureImageColormap(display,resource_info,windows,*image);
8163 (void) XConfigureImage(display,resource_info,windows,*image);
8164 break;
8165 }
8166 case ThresholdCommand:
8167 {
8168 double
8169 threshold;
8170
8171 static char
8172 factor[MaxTextExtent] = "128";
8173
8174 /*
8175 Query user for threshold value.
8176 */
8177 (void) XDialogWidget(display,windows,"Threshold",
8178 "Enter threshold value:",factor);
8179 if (*factor == '\0')
8180 break;
8181 /*
8182 Gamma correct image.
8183 */
8184 XSetCursorState(display,windows,MagickTrue);
8185 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008186 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008187 (void) BilevelImage(*image,threshold);
8188 XSetCursorState(display,windows,MagickFalse);
8189 if (windows->image.orphan != MagickFalse)
8190 break;
8191 XConfigureImageColormap(display,resource_info,windows,*image);
8192 (void) XConfigureImage(display,resource_info,windows,*image);
8193 break;
8194 }
8195 case EdgeDetectCommand:
8196 {
8197 Image
8198 *edge_image;
8199
8200 static char
8201 radius[MaxTextExtent] = "0";
8202
8203 /*
8204 Query user for edge factor.
8205 */
8206 (void) XDialogWidget(display,windows,"Detect Edges",
8207 "Enter the edge detect radius:",radius);
8208 if (*radius == '\0')
8209 break;
8210 /*
8211 Detect edge in image.
8212 */
8213 XSetCursorState(display,windows,MagickTrue);
8214 XCheckRefreshWindows(display,windows);
8215 flags=ParseGeometry(radius,&geometry_info);
8216 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8217 if (edge_image != (Image *) NULL)
8218 {
8219 *image=DestroyImage(*image);
8220 *image=edge_image;
8221 }
8222 CatchException(&(*image)->exception);
8223 XSetCursorState(display,windows,MagickFalse);
8224 if (windows->image.orphan != MagickFalse)
8225 break;
8226 XConfigureImageColormap(display,resource_info,windows,*image);
8227 (void) XConfigureImage(display,resource_info,windows,*image);
8228 break;
8229 }
8230 case SpreadCommand:
8231 {
8232 Image
8233 *spread_image;
8234
8235 static char
8236 amount[MaxTextExtent] = "2";
8237
8238 /*
8239 Query user for spread amount.
8240 */
8241 (void) XDialogWidget(display,windows,"Spread",
8242 "Enter the displacement amount:",amount);
8243 if (*amount == '\0')
8244 break;
8245 /*
8246 Displace image pixels by a random amount.
8247 */
8248 XSetCursorState(display,windows,MagickTrue);
8249 XCheckRefreshWindows(display,windows);
8250 flags=ParseGeometry(amount,&geometry_info);
8251 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8252 if (spread_image != (Image *) NULL)
8253 {
8254 *image=DestroyImage(*image);
8255 *image=spread_image;
8256 }
8257 CatchException(&(*image)->exception);
8258 XSetCursorState(display,windows,MagickFalse);
8259 if (windows->image.orphan != MagickFalse)
8260 break;
8261 XConfigureImageColormap(display,resource_info,windows,*image);
8262 (void) XConfigureImage(display,resource_info,windows,*image);
8263 break;
8264 }
8265 case ShadeCommand:
8266 {
8267 Image
8268 *shade_image;
8269
8270 int
8271 status;
8272
8273 static char
8274 geometry[MaxTextExtent] = "30x30";
8275
8276 /*
8277 Query user for the shade geometry.
8278 */
8279 status=XDialogWidget(display,windows,"Shade",
8280 "Enter the azimuth and elevation of the light source:",geometry);
8281 if (*geometry == '\0')
8282 break;
8283 /*
8284 Shade image pixels.
8285 */
8286 XSetCursorState(display,windows,MagickTrue);
8287 XCheckRefreshWindows(display,windows);
8288 flags=ParseGeometry(geometry,&geometry_info);
8289 if ((flags & SigmaValue) == 0)
8290 geometry_info.sigma=1.0;
8291 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8292 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8293 if (shade_image != (Image *) NULL)
8294 {
8295 *image=DestroyImage(*image);
8296 *image=shade_image;
8297 }
8298 CatchException(&(*image)->exception);
8299 XSetCursorState(display,windows,MagickFalse);
8300 if (windows->image.orphan != MagickFalse)
8301 break;
8302 XConfigureImageColormap(display,resource_info,windows,*image);
8303 (void) XConfigureImage(display,resource_info,windows,*image);
8304 break;
8305 }
8306 case RaiseCommand:
8307 {
8308 static char
8309 bevel_width[MaxTextExtent] = "10";
8310
8311 /*
8312 Query user for bevel width.
8313 */
8314 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8315 if (*bevel_width == '\0')
8316 break;
8317 /*
8318 Raise an image.
8319 */
8320 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8321 XSetCursorState(display,windows,MagickTrue);
8322 XCheckRefreshWindows(display,windows);
8323 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8324 &(*image)->exception);
8325 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8326 XSetCursorState(display,windows,MagickFalse);
8327 if (windows->image.orphan != MagickFalse)
8328 break;
8329 XConfigureImageColormap(display,resource_info,windows,*image);
8330 (void) XConfigureImage(display,resource_info,windows,*image);
8331 break;
8332 }
8333 case SegmentCommand:
8334 {
8335 static char
8336 threshold[MaxTextExtent] = "1.0x1.5";
8337
8338 /*
8339 Query user for smoothing threshold.
8340 */
8341 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8342 threshold);
8343 if (*threshold == '\0')
8344 break;
8345 /*
8346 Segment an image.
8347 */
8348 XSetCursorState(display,windows,MagickTrue);
8349 XCheckRefreshWindows(display,windows);
8350 flags=ParseGeometry(threshold,&geometry_info);
8351 if ((flags & SigmaValue) == 0)
8352 geometry_info.sigma=1.0;
8353 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8354 geometry_info.sigma);
8355 XSetCursorState(display,windows,MagickFalse);
8356 if (windows->image.orphan != MagickFalse)
8357 break;
8358 XConfigureImageColormap(display,resource_info,windows,*image);
8359 (void) XConfigureImage(display,resource_info,windows,*image);
8360 break;
8361 }
8362 case SepiaToneCommand:
8363 {
8364 double
8365 threshold;
8366
8367 Image
8368 *sepia_image;
8369
8370 static char
8371 factor[MaxTextExtent] = "80%";
8372
8373 /*
8374 Query user for sepia-tone factor.
8375 */
8376 (void) XDialogWidget(display,windows,"Sepia Tone",
8377 "Enter the sepia tone factor (0 - 99.9%):",factor);
8378 if (*factor == '\0')
8379 break;
8380 /*
8381 Sepia tone image pixels.
8382 */
8383 XSetCursorState(display,windows,MagickTrue);
8384 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008385 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008386 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8387 if (sepia_image != (Image *) NULL)
8388 {
8389 *image=DestroyImage(*image);
8390 *image=sepia_image;
8391 }
8392 CatchException(&(*image)->exception);
8393 XSetCursorState(display,windows,MagickFalse);
8394 if (windows->image.orphan != MagickFalse)
8395 break;
8396 XConfigureImageColormap(display,resource_info,windows,*image);
8397 (void) XConfigureImage(display,resource_info,windows,*image);
8398 break;
8399 }
8400 case SolarizeCommand:
8401 {
8402 double
8403 threshold;
8404
8405 static char
8406 factor[MaxTextExtent] = "60%";
8407
8408 /*
8409 Query user for solarize factor.
8410 */
8411 (void) XDialogWidget(display,windows,"Solarize",
8412 "Enter the solarize factor (0 - 99.9%):",factor);
8413 if (*factor == '\0')
8414 break;
8415 /*
8416 Solarize image pixels.
8417 */
8418 XSetCursorState(display,windows,MagickTrue);
8419 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008420 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008421 (void) SolarizeImage(*image,threshold);
8422 XSetCursorState(display,windows,MagickFalse);
8423 if (windows->image.orphan != MagickFalse)
8424 break;
8425 XConfigureImageColormap(display,resource_info,windows,*image);
8426 (void) XConfigureImage(display,resource_info,windows,*image);
8427 break;
8428 }
8429 case SwirlCommand:
8430 {
8431 Image
8432 *swirl_image;
8433
8434 static char
8435 degrees[MaxTextExtent] = "60";
8436
8437 /*
8438 Query user for swirl angle.
8439 */
8440 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8441 degrees);
8442 if (*degrees == '\0')
8443 break;
8444 /*
8445 Swirl image pixels about the center.
8446 */
8447 XSetCursorState(display,windows,MagickTrue);
8448 XCheckRefreshWindows(display,windows);
8449 flags=ParseGeometry(degrees,&geometry_info);
8450 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8451 if (swirl_image != (Image *) NULL)
8452 {
8453 *image=DestroyImage(*image);
8454 *image=swirl_image;
8455 }
8456 CatchException(&(*image)->exception);
8457 XSetCursorState(display,windows,MagickFalse);
8458 if (windows->image.orphan != MagickFalse)
8459 break;
8460 XConfigureImageColormap(display,resource_info,windows,*image);
8461 (void) XConfigureImage(display,resource_info,windows,*image);
8462 break;
8463 }
8464 case ImplodeCommand:
8465 {
8466 Image
8467 *implode_image;
8468
8469 static char
8470 factor[MaxTextExtent] = "0.3";
8471
8472 /*
8473 Query user for implode factor.
8474 */
8475 (void) XDialogWidget(display,windows,"Implode",
8476 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8477 if (*factor == '\0')
8478 break;
8479 /*
8480 Implode image pixels about the center.
8481 */
8482 XSetCursorState(display,windows,MagickTrue);
8483 XCheckRefreshWindows(display,windows);
8484 flags=ParseGeometry(factor,&geometry_info);
8485 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8486 if (implode_image != (Image *) NULL)
8487 {
8488 *image=DestroyImage(*image);
8489 *image=implode_image;
8490 }
8491 CatchException(&(*image)->exception);
8492 XSetCursorState(display,windows,MagickFalse);
8493 if (windows->image.orphan != MagickFalse)
8494 break;
8495 XConfigureImageColormap(display,resource_info,windows,*image);
8496 (void) XConfigureImage(display,resource_info,windows,*image);
8497 break;
8498 }
8499 case VignetteCommand:
8500 {
8501 Image
8502 *vignette_image;
8503
8504 static char
8505 geometry[MaxTextExtent] = "0x20";
8506
8507 /*
8508 Query user for the vignette geometry.
8509 */
8510 (void) XDialogWidget(display,windows,"Vignette",
8511 "Enter the radius, sigma, and x and y offsets:",geometry);
8512 if (*geometry == '\0')
8513 break;
8514 /*
8515 Soften the edges of the image in vignette style
8516 */
8517 XSetCursorState(display,windows,MagickTrue);
8518 XCheckRefreshWindows(display,windows);
8519 flags=ParseGeometry(geometry,&geometry_info);
8520 if ((flags & SigmaValue) == 0)
8521 geometry_info.sigma=1.0;
8522 if ((flags & XiValue) == 0)
8523 geometry_info.xi=0.1*(*image)->columns;
8524 if ((flags & PsiValue) == 0)
8525 geometry_info.psi=0.1*(*image)->rows;
8526 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
cristyb70a4862010-06-18 01:18:44 +00008527 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8528 0.5),&(*image)->exception);
cristy3ed852e2009-09-05 21:47:34 +00008529 if (vignette_image != (Image *) NULL)
8530 {
8531 *image=DestroyImage(*image);
8532 *image=vignette_image;
8533 }
8534 CatchException(&(*image)->exception);
8535 XSetCursorState(display,windows,MagickFalse);
8536 if (windows->image.orphan != MagickFalse)
8537 break;
8538 XConfigureImageColormap(display,resource_info,windows,*image);
8539 (void) XConfigureImage(display,resource_info,windows,*image);
8540 break;
8541 }
8542 case WaveCommand:
8543 {
8544 Image
8545 *wave_image;
8546
8547 static char
8548 geometry[MaxTextExtent] = "25x150";
8549
8550 /*
8551 Query user for the wave geometry.
8552 */
8553 (void) XDialogWidget(display,windows,"Wave",
8554 "Enter the amplitude and length of the wave:",geometry);
8555 if (*geometry == '\0')
8556 break;
8557 /*
cristycee97112010-05-28 00:44:52 +00008558 Alter an image along a sine wave.
cristy3ed852e2009-09-05 21:47:34 +00008559 */
8560 XSetCursorState(display,windows,MagickTrue);
8561 XCheckRefreshWindows(display,windows);
8562 flags=ParseGeometry(geometry,&geometry_info);
8563 if ((flags & SigmaValue) == 0)
8564 geometry_info.sigma=1.0;
8565 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8566 &(*image)->exception);
8567 if (wave_image != (Image *) NULL)
8568 {
8569 *image=DestroyImage(*image);
8570 *image=wave_image;
8571 }
8572 CatchException(&(*image)->exception);
8573 XSetCursorState(display,windows,MagickFalse);
8574 if (windows->image.orphan != MagickFalse)
8575 break;
8576 XConfigureImageColormap(display,resource_info,windows,*image);
8577 (void) XConfigureImage(display,resource_info,windows,*image);
8578 break;
8579 }
8580 case OilPaintCommand:
8581 {
8582 Image
8583 *paint_image;
8584
8585 static char
8586 radius[MaxTextExtent] = "0";
8587
8588 /*
8589 Query user for circular neighborhood radius.
8590 */
8591 (void) XDialogWidget(display,windows,"Oil Paint",
8592 "Enter the mask radius:",radius);
8593 if (*radius == '\0')
8594 break;
8595 /*
8596 OilPaint image scanlines.
8597 */
8598 XSetCursorState(display,windows,MagickTrue);
8599 XCheckRefreshWindows(display,windows);
8600 flags=ParseGeometry(radius,&geometry_info);
8601 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8602 if (paint_image != (Image *) NULL)
8603 {
8604 *image=DestroyImage(*image);
8605 *image=paint_image;
8606 }
8607 CatchException(&(*image)->exception);
8608 XSetCursorState(display,windows,MagickFalse);
8609 if (windows->image.orphan != MagickFalse)
8610 break;
8611 XConfigureImageColormap(display,resource_info,windows,*image);
8612 (void) XConfigureImage(display,resource_info,windows,*image);
8613 break;
8614 }
8615 case CharcoalDrawCommand:
8616 {
8617 Image
8618 *charcoal_image;
8619
8620 static char
8621 radius[MaxTextExtent] = "0x1";
8622
8623 /*
8624 Query user for charcoal radius.
8625 */
8626 (void) XDialogWidget(display,windows,"Charcoal Draw",
8627 "Enter the charcoal radius and sigma:",radius);
8628 if (*radius == '\0')
8629 break;
8630 /*
8631 Charcoal the image.
8632 */
8633 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8634 XSetCursorState(display,windows,MagickTrue);
8635 XCheckRefreshWindows(display,windows);
8636 flags=ParseGeometry(radius,&geometry_info);
8637 if ((flags & SigmaValue) == 0)
8638 geometry_info.sigma=geometry_info.rho;
8639 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8640 &(*image)->exception);
8641 if (charcoal_image != (Image *) NULL)
8642 {
8643 *image=DestroyImage(*image);
8644 *image=charcoal_image;
8645 }
8646 CatchException(&(*image)->exception);
8647 XSetCursorState(display,windows,MagickFalse);
8648 if (windows->image.orphan != MagickFalse)
8649 break;
8650 XConfigureImageColormap(display,resource_info,windows,*image);
8651 (void) XConfigureImage(display,resource_info,windows,*image);
8652 break;
8653 }
8654 case AnnotateCommand:
8655 {
8656 /*
8657 Annotate the image with text.
8658 */
8659 status=XAnnotateEditImage(display,resource_info,windows,*image);
8660 if (status == MagickFalse)
8661 {
8662 XNoticeWidget(display,windows,"Unable to annotate X image",
8663 (*image)->filename);
8664 break;
8665 }
8666 break;
8667 }
8668 case DrawCommand:
8669 {
8670 /*
8671 Draw image.
8672 */
8673 status=XDrawEditImage(display,resource_info,windows,image);
8674 if (status == MagickFalse)
8675 {
8676 XNoticeWidget(display,windows,"Unable to draw on the X image",
8677 (*image)->filename);
8678 break;
8679 }
8680 break;
8681 }
8682 case ColorCommand:
8683 {
8684 /*
8685 Color edit.
8686 */
8687 status=XColorEditImage(display,resource_info,windows,image);
8688 if (status == MagickFalse)
8689 {
8690 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8691 (*image)->filename);
8692 break;
8693 }
8694 break;
8695 }
8696 case MatteCommand:
8697 {
8698 /*
8699 Matte edit.
8700 */
8701 status=XMatteEditImage(display,resource_info,windows,image);
8702 if (status == MagickFalse)
8703 {
8704 XNoticeWidget(display,windows,"Unable to matte edit X image",
8705 (*image)->filename);
8706 break;
8707 }
8708 break;
8709 }
8710 case CompositeCommand:
8711 {
8712 /*
8713 Composite image.
8714 */
8715 status=XCompositeImage(display,resource_info,windows,*image);
8716 if (status == MagickFalse)
8717 {
8718 XNoticeWidget(display,windows,"Unable to composite X image",
8719 (*image)->filename);
8720 break;
8721 }
8722 break;
8723 }
8724 case AddBorderCommand:
8725 {
8726 Image
8727 *border_image;
8728
8729 static char
8730 geometry[MaxTextExtent] = "6x6";
8731
8732 /*
8733 Query user for border color and geometry.
8734 */
8735 XColorBrowserWidget(display,windows,"Select",color);
8736 if (*color == '\0')
8737 break;
8738 (void) XDialogWidget(display,windows,"Add Border",
8739 "Enter border geometry:",geometry);
8740 if (*geometry == '\0')
8741 break;
8742 /*
8743 Add a border to the image.
8744 */
8745 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8746 XSetCursorState(display,windows,MagickTrue);
8747 XCheckRefreshWindows(display,windows);
8748 (void) QueryColorDatabase(color,&(*image)->border_color,
8749 &(*image)->exception);
8750 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8751 &(*image)->exception);
8752 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8753 if (border_image != (Image *) NULL)
8754 {
8755 *image=DestroyImage(*image);
8756 *image=border_image;
8757 }
8758 CatchException(&(*image)->exception);
8759 XSetCursorState(display,windows,MagickFalse);
8760 if (windows->image.orphan != MagickFalse)
8761 break;
8762 windows->image.window_changes.width=(int) (*image)->columns;
8763 windows->image.window_changes.height=(int) (*image)->rows;
8764 XConfigureImageColormap(display,resource_info,windows,*image);
8765 (void) XConfigureImage(display,resource_info,windows,*image);
8766 break;
8767 }
8768 case AddFrameCommand:
8769 {
8770 FrameInfo
8771 frame_info;
8772
8773 Image
8774 *frame_image;
8775
8776 static char
8777 geometry[MaxTextExtent] = "6x6";
8778
8779 /*
8780 Query user for frame color and geometry.
8781 */
8782 XColorBrowserWidget(display,windows,"Select",color);
8783 if (*color == '\0')
8784 break;
8785 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8786 geometry);
8787 if (*geometry == '\0')
8788 break;
8789 /*
8790 Surround image with an ornamental border.
8791 */
8792 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8793 XSetCursorState(display,windows,MagickTrue);
8794 XCheckRefreshWindows(display,windows);
8795 (void) QueryColorDatabase(color,&(*image)->matte_color,
8796 &(*image)->exception);
8797 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8798 &(*image)->exception);
8799 frame_info.width=page_geometry.width;
8800 frame_info.height=page_geometry.height;
8801 frame_info.outer_bevel=page_geometry.x;
8802 frame_info.inner_bevel=page_geometry.y;
cristybb503372010-05-27 20:51:26 +00008803 frame_info.x=(ssize_t) frame_info.width;
8804 frame_info.y=(ssize_t) frame_info.height;
cristy3ed852e2009-09-05 21:47:34 +00008805 frame_info.width=(*image)->columns+2*frame_info.width;
8806 frame_info.height=(*image)->rows+2*frame_info.height;
8807 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8808 if (frame_image != (Image *) NULL)
8809 {
8810 *image=DestroyImage(*image);
8811 *image=frame_image;
8812 }
8813 CatchException(&(*image)->exception);
8814 XSetCursorState(display,windows,MagickFalse);
8815 if (windows->image.orphan != MagickFalse)
8816 break;
8817 windows->image.window_changes.width=(int) (*image)->columns;
8818 windows->image.window_changes.height=(int) (*image)->rows;
8819 XConfigureImageColormap(display,resource_info,windows,*image);
8820 (void) XConfigureImage(display,resource_info,windows,*image);
8821 break;
8822 }
8823 case CommentCommand:
8824 {
8825 const char
8826 *value;
8827
8828 FILE
8829 *file;
8830
8831 int
8832 unique_file;
8833
8834 /*
8835 Edit image comment.
8836 */
8837 unique_file=AcquireUniqueFileResource(image_info->filename);
8838 if (unique_file == -1)
8839 XNoticeWidget(display,windows,"Unable to edit image comment",
8840 image_info->filename);
8841 value=GetImageProperty(*image,"comment");
8842 if (value == (char *) NULL)
8843 unique_file=close(unique_file)-1;
8844 else
8845 {
8846 register const char
8847 *p;
8848
8849 file=fdopen(unique_file,"w");
8850 if (file == (FILE *) NULL)
8851 {
8852 XNoticeWidget(display,windows,"Unable to edit image comment",
8853 image_info->filename);
8854 break;
8855 }
8856 for (p=value; *p != '\0'; p++)
8857 (void) fputc((int) *p,file);
8858 (void) fputc('\n',file);
8859 (void) fclose(file);
8860 }
8861 XSetCursorState(display,windows,MagickTrue);
8862 XCheckRefreshWindows(display,windows);
8863 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8864 &(*image)->exception);
8865 if (status == MagickFalse)
8866 XNoticeWidget(display,windows,"Unable to edit image comment",
8867 (char *) NULL);
8868 else
8869 {
8870 char
8871 *comment;
8872
8873 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8874 if (comment != (char *) NULL)
8875 {
8876 (void) SetImageProperty(*image,"comment",comment);
8877 (*image)->taint=MagickTrue;
8878 }
8879 }
8880 (void) RelinquishUniqueFileResource(image_info->filename);
8881 XSetCursorState(display,windows,MagickFalse);
8882 break;
8883 }
8884 case LaunchCommand:
8885 {
8886 /*
8887 Launch program.
8888 */
8889 XSetCursorState(display,windows,MagickTrue);
8890 XCheckRefreshWindows(display,windows);
8891 (void) AcquireUniqueFilename(filename);
8892 (void) FormatMagickString((*image)->filename,MaxTextExtent,"launch:%s",
8893 filename);
8894 status=WriteImage(image_info,*image);
8895 if (status == MagickFalse)
8896 XNoticeWidget(display,windows,"Unable to launch image editor",
8897 (char *) NULL);
8898 else
8899 {
8900 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8901 CatchException(&(*image)->exception);
8902 XClientMessage(display,windows->image.id,windows->im_protocols,
8903 windows->im_next_image,CurrentTime);
8904 }
8905 (void) RelinquishUniqueFileResource(filename);
8906 XSetCursorState(display,windows,MagickFalse);
8907 break;
8908 }
8909 case RegionofInterestCommand:
8910 {
8911 /*
8912 Apply an image processing technique to a region of interest.
8913 */
8914 (void) XROIImage(display,resource_info,windows,image);
8915 break;
8916 }
8917 case InfoCommand:
8918 break;
8919 case ZoomCommand:
8920 {
8921 /*
8922 Zoom image.
8923 */
8924 if (windows->magnify.mapped != MagickFalse)
8925 (void) XRaiseWindow(display,windows->magnify.id);
8926 else
8927 {
8928 /*
8929 Make magnify image.
8930 */
8931 XSetCursorState(display,windows,MagickTrue);
8932 (void) XMapRaised(display,windows->magnify.id);
8933 XSetCursorState(display,windows,MagickFalse);
8934 }
8935 break;
8936 }
8937 case ShowPreviewCommand:
8938 {
8939 char
8940 **previews;
8941
8942 Image
8943 *preview_image;
8944
8945 static char
8946 preview_type[MaxTextExtent] = "Gamma";
8947
8948 /*
8949 Select preview type from menu.
8950 */
8951 previews=GetMagickOptions(MagickPreviewOptions);
8952 if (previews == (char **) NULL)
8953 break;
8954 XListBrowserWidget(display,windows,&windows->widget,
8955 (const char **) previews,"Preview",
8956 "Select an enhancement, effect, or F/X:",preview_type);
8957 previews=DestroyStringList(previews);
8958 if (*preview_type == '\0')
8959 break;
8960 /*
8961 Show image preview.
8962 */
8963 XSetCursorState(display,windows,MagickTrue);
8964 XCheckRefreshWindows(display,windows);
8965 image_info->preview_type=(PreviewType)
8966 ParseMagickOption(MagickPreviewOptions,MagickFalse,preview_type);
cristybb503372010-05-27 20:51:26 +00008967 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00008968 (void) DeleteImageProperty(*image,"label");
8969 (void) SetImageProperty(*image,"label","Preview");
8970 (void) AcquireUniqueFilename(filename);
8971 (void) FormatMagickString((*image)->filename,MaxTextExtent,"preview:%s",
8972 filename);
8973 status=WriteImage(image_info,*image);
8974 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
8975 preview_image=ReadImage(image_info,&(*image)->exception);
8976 (void) RelinquishUniqueFileResource(filename);
8977 if (preview_image == (Image *) NULL)
8978 break;
8979 (void) FormatMagickString(preview_image->filename,MaxTextExtent,"show:%s",
8980 filename);
8981 status=WriteImage(image_info,preview_image);
8982 preview_image=DestroyImage(preview_image);
8983 if (status == MagickFalse)
8984 XNoticeWidget(display,windows,"Unable to show image preview",
8985 (*image)->filename);
8986 XDelay(display,1500);
8987 XSetCursorState(display,windows,MagickFalse);
8988 break;
8989 }
8990 case ShowHistogramCommand:
8991 {
8992 Image
8993 *histogram_image;
8994
8995 /*
8996 Show image histogram.
8997 */
8998 XSetCursorState(display,windows,MagickTrue);
8999 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009000 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009001 (void) DeleteImageProperty(*image,"label");
9002 (void) SetImageProperty(*image,"label","Histogram");
9003 (void) AcquireUniqueFilename(filename);
9004 (void) FormatMagickString((*image)->filename,MaxTextExtent,"histogram:%s",
9005 filename);
9006 status=WriteImage(image_info,*image);
9007 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9008 histogram_image=ReadImage(image_info,&(*image)->exception);
9009 (void) RelinquishUniqueFileResource(filename);
9010 if (histogram_image == (Image *) NULL)
9011 break;
9012 (void) FormatMagickString(histogram_image->filename,MaxTextExtent,
9013 "show:%s",filename);
9014 status=WriteImage(image_info,histogram_image);
9015 histogram_image=DestroyImage(histogram_image);
9016 if (status == MagickFalse)
9017 XNoticeWidget(display,windows,"Unable to show histogram",
9018 (*image)->filename);
9019 XDelay(display,1500);
9020 XSetCursorState(display,windows,MagickFalse);
9021 break;
9022 }
9023 case ShowMatteCommand:
9024 {
9025 Image
9026 *matte_image;
9027
9028 if ((*image)->matte == MagickFalse)
9029 {
9030 XNoticeWidget(display,windows,
9031 "Image does not have any matte information",(*image)->filename);
9032 break;
9033 }
9034 /*
9035 Show image matte.
9036 */
9037 XSetCursorState(display,windows,MagickTrue);
9038 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009039 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009040 (void) DeleteImageProperty(*image,"label");
9041 (void) SetImageProperty(*image,"label","Matte");
9042 (void) AcquireUniqueFilename(filename);
9043 (void) FormatMagickString((*image)->filename,MaxTextExtent,"matte:%s",
9044 filename);
9045 status=WriteImage(image_info,*image);
9046 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9047 matte_image=ReadImage(image_info,&(*image)->exception);
9048 (void) RelinquishUniqueFileResource(filename);
9049 if (matte_image == (Image *) NULL)
9050 break;
9051 (void) FormatMagickString(matte_image->filename,MaxTextExtent,"show:%s",
9052 filename);
9053 status=WriteImage(image_info,matte_image);
9054 matte_image=DestroyImage(matte_image);
9055 if (status == MagickFalse)
9056 XNoticeWidget(display,windows,"Unable to show matte",
9057 (*image)->filename);
9058 XDelay(display,1500);
9059 XSetCursorState(display,windows,MagickFalse);
9060 break;
9061 }
9062 case BackgroundCommand:
9063 {
9064 /*
9065 Background image.
9066 */
9067 status=XBackgroundImage(display,resource_info,windows,image);
9068 if (status == MagickFalse)
9069 break;
9070 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9071 if (nexus != (Image *) NULL)
9072 XClientMessage(display,windows->image.id,windows->im_protocols,
9073 windows->im_next_image,CurrentTime);
9074 break;
9075 }
9076 case SlideShowCommand:
9077 {
9078 static char
9079 delay[MaxTextExtent] = "5";
9080
9081 /*
9082 Display next image after pausing.
9083 */
9084 (void) XDialogWidget(display,windows,"Slide Show",
9085 "Pause how many 1/100ths of a second between images:",delay);
9086 if (*delay == '\0')
9087 break;
cristye27293e2009-12-18 02:53:20 +00009088 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009089 XClientMessage(display,windows->image.id,windows->im_protocols,
9090 windows->im_next_image,CurrentTime);
9091 break;
9092 }
9093 case PreferencesCommand:
9094 {
9095 /*
9096 Set user preferences.
9097 */
9098 status=XPreferencesWidget(display,resource_info,windows);
9099 if (status == MagickFalse)
9100 break;
9101 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9102 if (nexus != (Image *) NULL)
9103 XClientMessage(display,windows->image.id,windows->im_protocols,
9104 windows->im_next_image,CurrentTime);
9105 break;
9106 }
9107 case HelpCommand:
9108 {
9109 /*
9110 User requested help.
9111 */
9112 XTextViewWidget(display,resource_info,windows,MagickFalse,
9113 "Help Viewer - Display",DisplayHelp);
9114 break;
9115 }
9116 case BrowseDocumentationCommand:
9117 {
9118 Atom
9119 mozilla_atom;
9120
9121 Window
9122 mozilla_window,
9123 root_window;
9124
9125 /*
9126 Browse the ImageMagick documentation.
9127 */
9128 root_window=XRootWindow(display,XDefaultScreen(display));
9129 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9130 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9131 if (mozilla_window != (Window) NULL)
9132 {
9133 char
9134 command[MaxTextExtent],
9135 *url;
9136
9137 /*
9138 Display documentation using Netscape remote control.
9139 */
9140 url=GetMagickHomeURL();
9141 (void) FormatMagickString(command,MaxTextExtent,
9142 "openurl(%s,new-tab)",url);
9143 url=DestroyString(url);
9144 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9145 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9146 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9147 XSetCursorState(display,windows,MagickFalse);
9148 break;
9149 }
9150 XSetCursorState(display,windows,MagickTrue);
9151 XCheckRefreshWindows(display,windows);
9152 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9153 &(*image)->exception);
9154 if (status == MagickFalse)
9155 XNoticeWidget(display,windows,"Unable to browse documentation",
9156 (char *) NULL);
9157 XDelay(display,1500);
9158 XSetCursorState(display,windows,MagickFalse);
9159 break;
9160 }
9161 case VersionCommand:
9162 {
cristybb503372010-05-27 20:51:26 +00009163 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +00009164 GetMagickCopyright());
9165 break;
9166 }
9167 case SaveToUndoBufferCommand:
9168 break;
9169 default:
9170 {
9171 (void) XBell(display,0);
9172 break;
9173 }
9174 }
9175 image_info=DestroyImageInfo(image_info);
9176 return(nexus);
9177}
9178
9179/*
9180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9181% %
9182% %
9183% %
9184+ X M a g n i f y I m a g e %
9185% %
9186% %
9187% %
9188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9189%
9190% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9191% The magnified portion is displayed in a separate window.
9192%
9193% The format of the XMagnifyImage method is:
9194%
9195% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9196%
9197% A description of each parameter follows:
9198%
9199% o display: Specifies a connection to an X server; returned from
9200% XOpenDisplay.
9201%
9202% o windows: Specifies a pointer to a XWindows structure.
9203%
9204% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9205% the entire image is refreshed.
9206%
9207*/
9208static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9209{
9210 char
9211 text[MaxTextExtent];
9212
9213 register int
9214 x,
9215 y;
9216
cristybb503372010-05-27 20:51:26 +00009217 size_t
cristy3ed852e2009-09-05 21:47:34 +00009218 state;
9219
9220 /*
9221 Update magnified image until the mouse button is released.
9222 */
9223 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9224 state=DefaultState;
9225 x=event->xbutton.x;
9226 y=event->xbutton.y;
9227 windows->magnify.x=windows->image.x+x;
9228 windows->magnify.y=windows->image.y+y;
9229 do
9230 {
9231 /*
9232 Map and unmap Info widget as text cursor crosses its boundaries.
9233 */
9234 if (windows->info.mapped != MagickFalse)
9235 {
9236 if ((x < (int) (windows->info.x+windows->info.width)) &&
9237 (y < (int) (windows->info.y+windows->info.height)))
9238 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9239 }
9240 else
9241 if ((x > (int) (windows->info.x+windows->info.width)) ||
9242 (y > (int) (windows->info.y+windows->info.height)))
9243 (void) XMapWindow(display,windows->info.id);
9244 if (windows->info.mapped != MagickFalse)
9245 {
9246 /*
9247 Display pointer position.
9248 */
9249 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9250 windows->magnify.x,windows->magnify.y);
9251 XInfoWidget(display,windows,text);
9252 }
9253 /*
9254 Wait for next event.
9255 */
9256 XScreenEvent(display,windows,event);
9257 switch (event->type)
9258 {
9259 case ButtonPress:
9260 break;
9261 case ButtonRelease:
9262 {
9263 /*
9264 User has finished magnifying image.
9265 */
9266 x=event->xbutton.x;
9267 y=event->xbutton.y;
9268 state|=ExitState;
9269 break;
9270 }
9271 case Expose:
9272 break;
9273 case MotionNotify:
9274 {
9275 x=event->xmotion.x;
9276 y=event->xmotion.y;
9277 break;
9278 }
9279 default:
9280 break;
9281 }
9282 /*
9283 Check boundary conditions.
9284 */
9285 if (x < 0)
9286 x=0;
9287 else
9288 if (x >= (int) windows->image.width)
9289 x=(int) windows->image.width-1;
9290 if (y < 0)
9291 y=0;
9292 else
9293 if (y >= (int) windows->image.height)
9294 y=(int) windows->image.height-1;
9295 } while ((state & ExitState) == 0);
9296 /*
9297 Display magnified image.
9298 */
9299 XSetCursorState(display,windows,MagickFalse);
9300}
9301
9302/*
9303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9304% %
9305% %
9306% %
9307+ X M a g n i f y W i n d o w C o m m a n d %
9308% %
9309% %
9310% %
9311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9312%
9313% XMagnifyWindowCommand() moves the image within an Magnify window by one
9314% pixel as specified by the key symbol.
9315%
9316% The format of the XMagnifyWindowCommand method is:
9317%
9318% void XMagnifyWindowCommand(Display *display,XWindows *windows,
9319% const MagickStatusType state,const KeySym key_symbol)
9320%
9321% A description of each parameter follows:
9322%
9323% o display: Specifies a connection to an X server; returned from
9324% XOpenDisplay.
9325%
9326% o windows: Specifies a pointer to a XWindows structure.
9327%
9328% o state: key mask.
9329%
9330% o key_symbol: Specifies a KeySym which indicates which side of the image
9331% to trim.
9332%
9333*/
9334static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9335 const MagickStatusType state,const KeySym key_symbol)
9336{
9337 unsigned int
9338 quantum;
9339
9340 /*
9341 User specified a magnify factor or position.
9342 */
9343 quantum=1;
9344 if ((state & Mod1Mask) != 0)
9345 quantum=10;
9346 switch ((int) key_symbol)
9347 {
9348 case QuitCommand:
9349 {
9350 (void) XWithdrawWindow(display,windows->magnify.id,
9351 windows->magnify.screen);
9352 break;
9353 }
9354 case XK_Home:
9355 case XK_KP_Home:
9356 {
9357 windows->magnify.x=(int) windows->image.width/2;
9358 windows->magnify.y=(int) windows->image.height/2;
9359 break;
9360 }
9361 case XK_Left:
9362 case XK_KP_Left:
9363 {
9364 if (windows->magnify.x > 0)
9365 windows->magnify.x-=quantum;
9366 break;
9367 }
9368 case XK_Up:
9369 case XK_KP_Up:
9370 {
9371 if (windows->magnify.y > 0)
9372 windows->magnify.y-=quantum;
9373 break;
9374 }
9375 case XK_Right:
9376 case XK_KP_Right:
9377 {
9378 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9379 windows->magnify.x+=quantum;
9380 break;
9381 }
9382 case XK_Down:
9383 case XK_KP_Down:
9384 {
9385 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9386 windows->magnify.y+=quantum;
9387 break;
9388 }
9389 case XK_0:
9390 case XK_1:
9391 case XK_2:
9392 case XK_3:
9393 case XK_4:
9394 case XK_5:
9395 case XK_6:
9396 case XK_7:
9397 case XK_8:
9398 case XK_9:
9399 {
9400 windows->magnify.data=(key_symbol-XK_0);
9401 break;
9402 }
9403 case XK_KP_0:
9404 case XK_KP_1:
9405 case XK_KP_2:
9406 case XK_KP_3:
9407 case XK_KP_4:
9408 case XK_KP_5:
9409 case XK_KP_6:
9410 case XK_KP_7:
9411 case XK_KP_8:
9412 case XK_KP_9:
9413 {
9414 windows->magnify.data=(key_symbol-XK_KP_0);
9415 break;
9416 }
9417 default:
9418 break;
9419 }
9420 XMakeMagnifyImage(display,windows);
9421}
9422
9423/*
9424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9425% %
9426% %
9427% %
9428+ X M a k e P a n I m a g e %
9429% %
9430% %
9431% %
9432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9433%
9434% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9435% icon window.
9436%
9437% The format of the XMakePanImage method is:
9438%
9439% void XMakePanImage(Display *display,XResourceInfo *resource_info,
9440% XWindows *windows,Image *image)
9441%
9442% A description of each parameter follows:
9443%
9444% o display: Specifies a connection to an X server; returned from
9445% XOpenDisplay.
9446%
9447% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9448%
9449% o windows: Specifies a pointer to a XWindows structure.
9450%
9451% o image: the image.
9452%
9453*/
9454static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9455 XWindows *windows,Image *image)
9456{
9457 MagickStatusType
9458 status;
9459
9460 /*
9461 Create and display image for panning icon.
9462 */
9463 XSetCursorState(display,windows,MagickTrue);
9464 XCheckRefreshWindows(display,windows);
9465 windows->pan.x=windows->image.x;
9466 windows->pan.y=windows->image.y;
9467 status=XMakeImage(display,resource_info,&windows->pan,image,
9468 windows->pan.width,windows->pan.height);
9469 if (status == MagickFalse)
9470 ThrowXWindowFatalException(XServerError,image->exception.reason,
9471 image->exception.description);
9472 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9473 windows->pan.pixmap);
9474 (void) XClearWindow(display,windows->pan.id);
9475 XDrawPanRectangle(display,windows);
9476 XSetCursorState(display,windows,MagickFalse);
9477}
9478
9479/*
9480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9481% %
9482% %
9483% %
9484+ X M a t t a E d i t I m a g e %
9485% %
9486% %
9487% %
9488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9489%
9490% XMatteEditImage() allows the user to interactively change the Matte channel
9491% of an image. If the image is PseudoClass it is promoted to DirectClass
9492% before the matte information is stored.
9493%
9494% The format of the XMatteEditImage method is:
9495%
9496% MagickBooleanType XMatteEditImage(Display *display,
9497% XResourceInfo *resource_info,XWindows *windows,Image **image)
9498%
9499% A description of each parameter follows:
9500%
9501% o display: Specifies a connection to an X server; returned from
9502% XOpenDisplay.
9503%
9504% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9505%
9506% o windows: Specifies a pointer to a XWindows structure.
9507%
9508% o image: the image; returned from ReadImage.
9509%
9510*/
9511static MagickBooleanType XMatteEditImage(Display *display,
9512 XResourceInfo *resource_info,XWindows *windows,Image **image)
9513{
9514 static char
9515 matte[MaxTextExtent] = "0";
9516
9517 static const char
9518 *MatteEditMenu[] =
9519 {
9520 "Method",
9521 "Border Color",
9522 "Fuzz",
9523 "Matte Value",
9524 "Undo",
9525 "Help",
9526 "Dismiss",
9527 (char *) NULL
9528 };
9529
9530 static const ModeType
9531 MatteEditCommands[] =
9532 {
9533 MatteEditMethod,
9534 MatteEditBorderCommand,
9535 MatteEditFuzzCommand,
9536 MatteEditValueCommand,
9537 MatteEditUndoCommand,
9538 MatteEditHelpCommand,
9539 MatteEditDismissCommand
9540 };
9541
9542 static PaintMethod
9543 method = PointMethod;
9544
9545 static XColor
9546 border_color = { 0, 0, 0, 0, 0, 0 };
9547
9548 char
9549 command[MaxTextExtent],
9550 text[MaxTextExtent];
9551
9552 Cursor
9553 cursor;
9554
9555 int
9556 entry,
9557 id,
9558 x,
9559 x_offset,
9560 y,
9561 y_offset;
9562
9563 register int
9564 i;
9565
9566 register PixelPacket
9567 *q;
9568
9569 unsigned int
9570 height,
9571 width;
9572
cristybb503372010-05-27 20:51:26 +00009573 size_t
cristy3ed852e2009-09-05 21:47:34 +00009574 state;
9575
9576 XEvent
9577 event;
9578
9579 /*
9580 Map Command widget.
9581 */
9582 (void) CloneString(&windows->command.name,"Matte Edit");
9583 windows->command.data=4;
9584 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9585 (void) XMapRaised(display,windows->command.id);
9586 XClientMessage(display,windows->image.id,windows->im_protocols,
9587 windows->im_update_widget,CurrentTime);
9588 /*
9589 Make cursor.
9590 */
9591 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9592 resource_info->background_color,resource_info->foreground_color);
9593 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9594 /*
9595 Track pointer until button 1 is pressed.
9596 */
9597 XQueryPosition(display,windows->image.id,&x,&y);
9598 (void) XSelectInput(display,windows->image.id,
9599 windows->image.attributes.event_mask | PointerMotionMask);
9600 state=DefaultState;
9601 do
9602 {
9603 if (windows->info.mapped != MagickFalse)
9604 {
9605 /*
9606 Display pointer position.
9607 */
9608 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9609 x+windows->image.x,y+windows->image.y);
9610 XInfoWidget(display,windows,text);
9611 }
9612 /*
9613 Wait for next event.
9614 */
9615 XScreenEvent(display,windows,&event);
9616 if (event.xany.window == windows->command.id)
9617 {
9618 /*
9619 Select a command from the Command widget.
9620 */
9621 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9622 if (id < 0)
9623 {
9624 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9625 continue;
9626 }
9627 switch (MatteEditCommands[id])
9628 {
9629 case MatteEditMethod:
9630 {
9631 char
9632 **methods;
9633
9634 /*
9635 Select a method from the pop-up menu.
9636 */
9637 methods=GetMagickOptions(MagickMethodOptions);
9638 if (methods == (char **) NULL)
9639 break;
9640 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9641 (const char **) methods,command);
9642 if (entry >= 0)
9643 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
9644 MagickFalse,methods[entry]);
9645 methods=DestroyStringList(methods);
9646 break;
9647 }
9648 case MatteEditBorderCommand:
9649 {
9650 const char
9651 *ColorMenu[MaxNumberPens];
9652
9653 int
9654 pen_number;
9655
9656 /*
9657 Initialize menu selections.
9658 */
9659 for (i=0; i < (int) (MaxNumberPens-2); i++)
9660 ColorMenu[i]=resource_info->pen_colors[i];
9661 ColorMenu[MaxNumberPens-2]="Browser...";
9662 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9663 /*
9664 Select a pen color from the pop-up menu.
9665 */
9666 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9667 (const char **) ColorMenu,command);
9668 if (pen_number < 0)
9669 break;
9670 if (pen_number == (MaxNumberPens-2))
9671 {
9672 static char
9673 color_name[MaxTextExtent] = "gray";
9674
9675 /*
9676 Select a pen color from a dialog.
9677 */
9678 resource_info->pen_colors[pen_number]=color_name;
9679 XColorBrowserWidget(display,windows,"Select",color_name);
9680 if (*color_name == '\0')
9681 break;
9682 }
9683 /*
9684 Set border color.
9685 */
9686 (void) XParseColor(display,windows->map_info->colormap,
9687 resource_info->pen_colors[pen_number],&border_color);
9688 break;
9689 }
9690 case MatteEditFuzzCommand:
9691 {
9692 static char
9693 fuzz[MaxTextExtent];
9694
9695 static const char
9696 *FuzzMenu[] =
9697 {
9698 "0%",
9699 "2%",
9700 "5%",
9701 "10%",
9702 "15%",
9703 "Dialog...",
9704 (char *) NULL,
9705 };
9706
9707 /*
9708 Select a command from the pop-up menu.
9709 */
9710 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9711 command);
9712 if (entry < 0)
9713 break;
9714 if (entry != 5)
9715 {
cristyf2f27272009-12-17 14:48:46 +00009716 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*QuantumRange+
cristy3ed852e2009-09-05 21:47:34 +00009717 1.0);
9718 break;
9719 }
9720 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9721 (void) XDialogWidget(display,windows,"Ok",
9722 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9723 if (*fuzz == '\0')
9724 break;
9725 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00009726 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009727 break;
9728 }
9729 case MatteEditValueCommand:
9730 {
9731 static char
9732 message[MaxTextExtent];
9733
9734 static const char
9735 *MatteMenu[] =
9736 {
9737 "Opaque",
9738 "Transparent",
9739 "Dialog...",
9740 (char *) NULL,
9741 };
9742
9743 /*
9744 Select a command from the pop-up menu.
9745 */
9746 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9747 command);
9748 if (entry < 0)
9749 break;
9750 if (entry != 2)
9751 {
9752 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9753 OpaqueOpacity);
9754 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9755 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9756 (Quantum) TransparentOpacity);
9757 break;
9758 }
9759 (void) FormatMagickString(message,MaxTextExtent,
9760 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9761 QuantumRange);
9762 (void) XDialogWidget(display,windows,"Matte",message,matte);
9763 if (*matte == '\0')
9764 break;
9765 break;
9766 }
9767 case MatteEditUndoCommand:
9768 {
9769 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9770 image);
9771 break;
9772 }
9773 case MatteEditHelpCommand:
9774 {
9775 XTextViewWidget(display,resource_info,windows,MagickFalse,
9776 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9777 break;
9778 }
9779 case MatteEditDismissCommand:
9780 {
9781 /*
9782 Prematurely exit.
9783 */
9784 state|=EscapeState;
9785 state|=ExitState;
9786 break;
9787 }
9788 default:
9789 break;
9790 }
9791 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9792 continue;
9793 }
9794 switch (event.type)
9795 {
9796 case ButtonPress:
9797 {
9798 if (event.xbutton.button != Button1)
9799 break;
9800 if ((event.xbutton.window != windows->image.id) &&
9801 (event.xbutton.window != windows->magnify.id))
9802 break;
9803 /*
9804 Update matte data.
9805 */
9806 x=event.xbutton.x;
9807 y=event.xbutton.y;
9808 (void) XMagickCommand(display,resource_info,windows,
9809 SaveToUndoBufferCommand,image);
9810 state|=UpdateConfigurationState;
9811 break;
9812 }
9813 case ButtonRelease:
9814 {
9815 if (event.xbutton.button != Button1)
9816 break;
9817 if ((event.xbutton.window != windows->image.id) &&
9818 (event.xbutton.window != windows->magnify.id))
9819 break;
9820 /*
9821 Update colormap information.
9822 */
9823 x=event.xbutton.x;
9824 y=event.xbutton.y;
9825 XConfigureImageColormap(display,resource_info,windows,*image);
9826 (void) XConfigureImage(display,resource_info,windows,*image);
9827 XInfoWidget(display,windows,text);
9828 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9829 state&=(~UpdateConfigurationState);
9830 break;
9831 }
9832 case Expose:
9833 break;
9834 case KeyPress:
9835 {
9836 char
9837 command[MaxTextExtent];
9838
9839 KeySym
9840 key_symbol;
9841
9842 if (event.xkey.window == windows->magnify.id)
9843 {
9844 Window
9845 window;
9846
9847 window=windows->magnify.id;
9848 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9849 }
9850 if (event.xkey.window != windows->image.id)
9851 break;
9852 /*
9853 Respond to a user key press.
9854 */
9855 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9856 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9857 switch ((int) key_symbol)
9858 {
9859 case XK_Escape:
9860 case XK_F20:
9861 {
9862 /*
9863 Prematurely exit.
9864 */
9865 state|=ExitState;
9866 break;
9867 }
9868 case XK_F1:
9869 case XK_Help:
9870 {
9871 XTextViewWidget(display,resource_info,windows,MagickFalse,
9872 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9873 break;
9874 }
9875 default:
9876 {
9877 (void) XBell(display,0);
9878 break;
9879 }
9880 }
9881 break;
9882 }
9883 case MotionNotify:
9884 {
9885 /*
9886 Map and unmap Info widget as cursor crosses its boundaries.
9887 */
9888 x=event.xmotion.x;
9889 y=event.xmotion.y;
9890 if (windows->info.mapped != MagickFalse)
9891 {
9892 if ((x < (int) (windows->info.x+windows->info.width)) &&
9893 (y < (int) (windows->info.y+windows->info.height)))
9894 (void) XWithdrawWindow(display,windows->info.id,
9895 windows->info.screen);
9896 }
9897 else
9898 if ((x > (int) (windows->info.x+windows->info.width)) ||
9899 (y > (int) (windows->info.y+windows->info.height)))
9900 (void) XMapWindow(display,windows->info.id);
9901 break;
9902 }
9903 default:
9904 break;
9905 }
9906 if (event.xany.window == windows->magnify.id)
9907 {
9908 x=windows->magnify.x-windows->image.x;
9909 y=windows->magnify.y-windows->image.y;
9910 }
9911 x_offset=x;
9912 y_offset=y;
9913 if ((state & UpdateConfigurationState) != 0)
9914 {
9915 ExceptionInfo
9916 *exception;
9917
9918 int
9919 x,
9920 y;
9921
9922 /*
9923 Matte edit is relative to image configuration.
9924 */
9925 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9926 MagickTrue);
9927 XPutPixel(windows->image.ximage,x_offset,y_offset,
9928 windows->pixel_info->background_color.pixel);
9929 width=(unsigned int) (*image)->columns;
9930 height=(unsigned int) (*image)->rows;
9931 x=0;
9932 y=0;
9933 if (windows->image.crop_geometry != (char *) NULL)
9934 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9935 &width,&height);
9936 x_offset=(int)
9937 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9938 y_offset=(int)
9939 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9940 if ((x_offset < 0) || (y_offset < 0))
9941 continue;
9942 if ((x_offset >= (int) (*image)->columns) ||
9943 (y_offset >= (int) (*image)->rows))
9944 continue;
9945 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9946 return(MagickFalse);
9947 (*image)->matte=MagickTrue;
9948 exception=(&(*image)->exception);
9949 switch (method)
9950 {
9951 case PointMethod:
9952 default:
9953 {
9954 /*
9955 Update matte information using point algorithm.
9956 */
9957 q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
9958 if (q == (PixelPacket *) NULL)
9959 break;
cristyf2f27272009-12-17 14:48:46 +00009960 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +00009961 (void) SyncAuthenticPixels(*image,exception);
9962 break;
9963 }
9964 case ReplaceMethod:
9965 {
9966 PixelPacket
9967 target;
9968
9969 /*
9970 Update matte information using replace algorithm.
9971 */
9972 (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
9973 exception);
cristybb503372010-05-27 20:51:26 +00009974 for (y=0; y < (ssize_t) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00009975 {
9976 q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,
9977 &(*image)->exception);
9978 if (q == (PixelPacket *) NULL)
9979 break;
9980 for (x=0; x < (int) (*image)->columns; x++)
9981 {
9982 if (IsColorSimilar(*image,q,&target))
cristyf2f27272009-12-17 14:48:46 +00009983 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +00009984 q++;
9985 }
9986 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
9987 break;
9988 }
9989 break;
9990 }
9991 case FloodfillMethod:
9992 case FillToBorderMethod:
9993 {
9994 DrawInfo
9995 *draw_info;
9996
9997 MagickPixelPacket
9998 target;
9999
10000 /*
10001 Update matte information using floodfill algorithm.
10002 */
10003 (void) GetOneVirtualMagickPixel(*image,x_offset,y_offset,&target,
10004 exception);
10005 if (method == FillToBorderMethod)
10006 {
10007 target.red=(MagickRealType)
10008 ScaleShortToQuantum(border_color.red);
10009 target.green=(MagickRealType)
10010 ScaleShortToQuantum(border_color.green);
10011 target.blue=(MagickRealType)
10012 ScaleShortToQuantum(border_color.blue);
10013 }
10014 draw_info=CloneDrawInfo(resource_info->image_info,
10015 (DrawInfo *) NULL);
cristyce70c172010-01-07 17:15:30 +000010016 draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte));
cristy3ed852e2009-09-05 21:47:34 +000010017 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10018 x_offset,y_offset,method == FloodfillMethod ? MagickFalse :
10019 MagickTrue);
10020 draw_info=DestroyDrawInfo(draw_info);
10021 break;
10022 }
10023 case ResetMethod:
10024 {
10025 /*
10026 Update matte information using reset algorithm.
10027 */
10028 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10029 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +000010030 for (y=0; y < (ssize_t) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010031 {
10032 q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
10033 if (q == (PixelPacket *) NULL)
10034 break;
10035 for (x=0; x < (int) (*image)->columns; x++)
10036 {
cristyf2f27272009-12-17 14:48:46 +000010037 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +000010038 q++;
10039 }
10040 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
10041 break;
10042 }
cristyf2f27272009-12-17 14:48:46 +000010043 if (StringToLong(matte) == OpaqueOpacity)
cristy3ed852e2009-09-05 21:47:34 +000010044 (*image)->matte=MagickFalse;
10045 break;
10046 }
10047 }
10048 state&=(~UpdateConfigurationState);
10049 }
10050 } while ((state & ExitState) == 0);
10051 (void) XSelectInput(display,windows->image.id,
10052 windows->image.attributes.event_mask);
10053 XSetCursorState(display,windows,MagickFalse);
10054 (void) XFreeCursor(display,cursor);
10055 return(MagickTrue);
10056}
10057
10058/*
10059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10060% %
10061% %
10062% %
10063+ X O p e n I m a g e %
10064% %
10065% %
10066% %
10067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10068%
10069% XOpenImage() loads an image from a file.
10070%
10071% The format of the XOpenImage method is:
10072%
10073% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10074% XWindows *windows,const unsigned int command)
10075%
10076% A description of each parameter follows:
10077%
10078% o display: Specifies a connection to an X server; returned from
10079% XOpenDisplay.
10080%
10081% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10082%
10083% o windows: Specifies a pointer to a XWindows structure.
10084%
10085% o command: A value other than zero indicates that the file is selected
10086% from the command line argument list.
10087%
10088*/
10089static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10090 XWindows *windows,const MagickBooleanType command)
10091{
10092 const MagickInfo
10093 *magick_info;
10094
10095 ExceptionInfo
10096 *exception;
10097
10098 Image
10099 *nexus;
10100
10101 ImageInfo
10102 *image_info;
10103
10104 static char
10105 filename[MaxTextExtent] = "\0";
10106
10107 /*
10108 Request file name from user.
10109 */
10110 if (command == MagickFalse)
10111 XFileBrowserWidget(display,windows,"Open",filename);
10112 else
10113 {
10114 char
10115 **filelist,
10116 **files;
10117
10118 int
10119 count,
10120 status;
10121
10122 register int
10123 i,
10124 j;
10125
10126 /*
10127 Select next image from the command line.
10128 */
10129 status=XGetCommand(display,windows->image.id,&files,&count);
10130 if (status == 0)
10131 {
10132 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10133 return((Image *) NULL);
10134 }
10135 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10136 if (filelist == (char **) NULL)
10137 {
10138 ThrowXWindowFatalException(ResourceLimitError,
10139 "MemoryAllocationFailed","...");
10140 (void) XFreeStringList(files);
10141 return((Image *) NULL);
10142 }
10143 j=0;
10144 for (i=1; i < count; i++)
10145 if (*files[i] != '-')
10146 filelist[j++]=files[i];
10147 filelist[j]=(char *) NULL;
10148 XListBrowserWidget(display,windows,&windows->widget,
10149 (const char **) filelist,"Load","Select Image to Load:",filename);
10150 filelist=(char **) RelinquishMagickMemory(filelist);
10151 (void) XFreeStringList(files);
10152 }
10153 if (*filename == '\0')
10154 return((Image *) NULL);
10155 image_info=CloneImageInfo(resource_info->image_info);
10156 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10157 (void *) NULL);
10158 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10159 exception=AcquireExceptionInfo();
cristyd965a422010-03-03 17:47:35 +000010160 (void) SetImageInfo(image_info,0,exception);
cristy3ed852e2009-09-05 21:47:34 +000010161 if (LocaleCompare(image_info->magick,"X") == 0)
10162 {
10163 char
10164 seconds[MaxTextExtent];
10165
10166 /*
10167 User may want to delay the X server screen grab.
10168 */
10169 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10170 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10171 seconds);
10172 if (*seconds == '\0')
10173 return((Image *) NULL);
cristybb503372010-05-27 20:51:26 +000010174 XDelay(display,(size_t) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010175 }
10176 magick_info=GetMagickInfo(image_info->magick,exception);
10177 if ((magick_info != (const MagickInfo *) NULL) &&
10178 (magick_info->raw != MagickFalse))
10179 {
10180 char
10181 geometry[MaxTextExtent];
10182
10183 /*
10184 Request image size from the user.
10185 */
10186 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10187 if (image_info->size != (char *) NULL)
10188 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10189 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10190 geometry);
10191 (void) CloneString(&image_info->size,geometry);
10192 }
10193 /*
10194 Load the image.
10195 */
10196 XSetCursorState(display,windows,MagickTrue);
10197 XCheckRefreshWindows(display,windows);
10198 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10199 nexus=ReadImage(image_info,exception);
10200 CatchException(exception);
10201 XSetCursorState(display,windows,MagickFalse);
10202 if (nexus != (Image *) NULL)
10203 XClientMessage(display,windows->image.id,windows->im_protocols,
10204 windows->im_next_image,CurrentTime);
10205 else
10206 {
10207 char
10208 *text,
10209 **textlist;
10210
10211 /*
10212 Unknown image format.
10213 */
10214 text=FileToString(filename,~0,exception);
10215 if (text == (char *) NULL)
10216 return((Image *) NULL);
10217 textlist=StringToList(text);
10218 if (textlist != (char **) NULL)
10219 {
10220 char
10221 title[MaxTextExtent];
10222
10223 register int
10224 i;
10225
10226 (void) FormatMagickString(title,MaxTextExtent,
10227 "Unknown format: %s",filename);
10228 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10229 (const char **) textlist);
10230 for (i=0; textlist[i] != (char *) NULL; i++)
10231 textlist[i]=DestroyString(textlist[i]);
10232 textlist=(char **) RelinquishMagickMemory(textlist);
10233 }
10234 text=DestroyString(text);
10235 }
10236 exception=DestroyExceptionInfo(exception);
10237 image_info=DestroyImageInfo(image_info);
10238 return(nexus);
10239}
10240
10241/*
10242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10243% %
10244% %
10245% %
10246+ X P a n I m a g e %
10247% %
10248% %
10249% %
10250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10251%
10252% XPanImage() pans the image until the mouse button is released.
10253%
10254% The format of the XPanImage method is:
10255%
10256% void XPanImage(Display *display,XWindows *windows,XEvent *event)
10257%
10258% A description of each parameter follows:
10259%
10260% o display: Specifies a connection to an X server; returned from
10261% XOpenDisplay.
10262%
10263% o windows: Specifies a pointer to a XWindows structure.
10264%
10265% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10266% the entire image is refreshed.
10267%
10268*/
10269static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10270{
10271 char
10272 text[MaxTextExtent];
10273
10274 Cursor
10275 cursor;
10276
10277 MagickRealType
10278 x_factor,
10279 y_factor;
10280
10281 RectangleInfo
10282 pan_info;
10283
cristybb503372010-05-27 20:51:26 +000010284 size_t
cristy3ed852e2009-09-05 21:47:34 +000010285 state;
10286
10287 /*
10288 Define cursor.
10289 */
10290 if ((windows->image.ximage->width > (int) windows->image.width) &&
10291 (windows->image.ximage->height > (int) windows->image.height))
10292 cursor=XCreateFontCursor(display,XC_fleur);
10293 else
10294 if (windows->image.ximage->width > (int) windows->image.width)
10295 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10296 else
10297 if (windows->image.ximage->height > (int) windows->image.height)
10298 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10299 else
10300 cursor=XCreateFontCursor(display,XC_arrow);
10301 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10302 /*
10303 Pan image as pointer moves until the mouse button is released.
10304 */
10305 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10306 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10307 pan_info.width=windows->pan.width*windows->image.width/
10308 windows->image.ximage->width;
10309 pan_info.height=windows->pan.height*windows->image.height/
10310 windows->image.ximage->height;
10311 pan_info.x=0;
10312 pan_info.y=0;
10313 state=UpdateConfigurationState;
10314 do
10315 {
10316 switch (event->type)
10317 {
10318 case ButtonPress:
10319 {
10320 /*
10321 User choose an initial pan location.
10322 */
10323 pan_info.x=event->xbutton.x;
10324 pan_info.y=event->xbutton.y;
10325 state|=UpdateConfigurationState;
10326 break;
10327 }
10328 case ButtonRelease:
10329 {
10330 /*
10331 User has finished panning the image.
10332 */
10333 pan_info.x=event->xbutton.x;
10334 pan_info.y=event->xbutton.y;
10335 state|=UpdateConfigurationState | ExitState;
10336 break;
10337 }
10338 case MotionNotify:
10339 {
10340 pan_info.x=event->xmotion.x;
10341 pan_info.y=event->xmotion.y;
10342 state|=UpdateConfigurationState;
10343 }
10344 default:
10345 break;
10346 }
10347 if ((state & UpdateConfigurationState) != 0)
10348 {
10349 /*
10350 Check boundary conditions.
10351 */
10352 if (pan_info.x < (int) (pan_info.width/2))
10353 pan_info.x=0;
10354 else
10355 pan_info.x=(int) (x_factor*(pan_info.x-(pan_info.width/2)));
10356 if (pan_info.x < 0)
10357 pan_info.x=0;
10358 else
10359 if ((int) (pan_info.x+windows->image.width) >
10360 windows->image.ximage->width)
cristybb503372010-05-27 20:51:26 +000010361 pan_info.x=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010362 (windows->image.ximage->width-windows->image.width);
cristybb503372010-05-27 20:51:26 +000010363 if (pan_info.y < (ssize_t) (pan_info.height/2))
cristy3ed852e2009-09-05 21:47:34 +000010364 pan_info.y=0;
10365 else
cristybb503372010-05-27 20:51:26 +000010366 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
cristy3ed852e2009-09-05 21:47:34 +000010367 if (pan_info.y < 0)
10368 pan_info.y=0;
10369 else
10370 if ((int) (pan_info.y+windows->image.height) >
10371 windows->image.ximage->height)
cristybb503372010-05-27 20:51:26 +000010372 pan_info.y=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010373 (windows->image.ximage->height-windows->image.height);
10374 if ((windows->image.x != (int) pan_info.x) ||
10375 (windows->image.y != (int) pan_info.y))
10376 {
10377 /*
10378 Display image pan offset.
10379 */
10380 windows->image.x=(int) pan_info.x;
10381 windows->image.y=(int) pan_info.y;
10382 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
10383 windows->image.width,windows->image.height,windows->image.x,
10384 windows->image.y);
10385 XInfoWidget(display,windows,text);
10386 /*
10387 Refresh Image window.
10388 */
10389 XDrawPanRectangle(display,windows);
10390 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10391 }
10392 state&=(~UpdateConfigurationState);
10393 }
10394 /*
10395 Wait for next event.
10396 */
10397 if ((state & ExitState) == 0)
10398 XScreenEvent(display,windows,event);
10399 } while ((state & ExitState) == 0);
10400 /*
10401 Restore cursor.
10402 */
10403 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10404 (void) XFreeCursor(display,cursor);
10405 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10406}
10407
10408/*
10409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10410% %
10411% %
10412% %
10413+ X P a s t e I m a g e %
10414% %
10415% %
10416% %
10417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10418%
10419% XPasteImage() pastes an image previously saved with XCropImage in the X
10420% window image at a location the user chooses with the pointer.
10421%
10422% The format of the XPasteImage method is:
10423%
10424% MagickBooleanType XPasteImage(Display *display,
10425% XResourceInfo *resource_info,XWindows *windows,Image *image)
10426%
10427% A description of each parameter follows:
10428%
10429% o display: Specifies a connection to an X server; returned from
10430% XOpenDisplay.
10431%
10432% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10433%
10434% o windows: Specifies a pointer to a XWindows structure.
10435%
10436% o image: the image; returned from ReadImage.
10437%
10438*/
10439static MagickBooleanType XPasteImage(Display *display,
10440 XResourceInfo *resource_info,XWindows *windows,Image *image)
10441{
10442 static const char
10443 *PasteMenu[] =
10444 {
10445 "Operator",
10446 "Help",
10447 "Dismiss",
10448 (char *) NULL
10449 };
10450
10451 static const ModeType
10452 PasteCommands[] =
10453 {
10454 PasteOperatorsCommand,
10455 PasteHelpCommand,
10456 PasteDismissCommand
10457 };
10458
10459 static CompositeOperator
10460 compose = CopyCompositeOp;
10461
10462 char
10463 text[MaxTextExtent];
10464
10465 Cursor
10466 cursor;
10467
10468 Image
10469 *paste_image;
10470
10471 int
10472 entry,
10473 id,
10474 x,
10475 y;
10476
10477 MagickRealType
10478 scale_factor;
10479
10480 RectangleInfo
10481 highlight_info,
10482 paste_info;
10483
10484 unsigned int
10485 height,
10486 width;
10487
cristybb503372010-05-27 20:51:26 +000010488 size_t
cristy3ed852e2009-09-05 21:47:34 +000010489 state;
10490
10491 XEvent
10492 event;
10493
10494 /*
10495 Copy image.
10496 */
10497 if (resource_info->copy_image == (Image *) NULL)
10498 return(MagickFalse);
10499 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10500 &image->exception);
10501 /*
10502 Map Command widget.
10503 */
10504 (void) CloneString(&windows->command.name,"Paste");
10505 windows->command.data=1;
10506 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10507 (void) XMapRaised(display,windows->command.id);
10508 XClientMessage(display,windows->image.id,windows->im_protocols,
10509 windows->im_update_widget,CurrentTime);
10510 /*
10511 Track pointer until button 1 is pressed.
10512 */
10513 XSetCursorState(display,windows,MagickFalse);
10514 XQueryPosition(display,windows->image.id,&x,&y);
10515 (void) XSelectInput(display,windows->image.id,
10516 windows->image.attributes.event_mask | PointerMotionMask);
10517 paste_info.x=windows->image.x+x;
10518 paste_info.y=windows->image.y+y;
10519 paste_info.width=0;
10520 paste_info.height=0;
10521 cursor=XCreateFontCursor(display,XC_ul_angle);
10522 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10523 state=DefaultState;
10524 do
10525 {
10526 if (windows->info.mapped != MagickFalse)
10527 {
10528 /*
10529 Display pointer position.
10530 */
10531 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000010532 (long) paste_info.x,(long) paste_info.y);
cristy3ed852e2009-09-05 21:47:34 +000010533 XInfoWidget(display,windows,text);
10534 }
10535 highlight_info=paste_info;
10536 highlight_info.x=paste_info.x-windows->image.x;
10537 highlight_info.y=paste_info.y-windows->image.y;
10538 XHighlightRectangle(display,windows->image.id,
10539 windows->image.highlight_context,&highlight_info);
10540 /*
10541 Wait for next event.
10542 */
10543 XScreenEvent(display,windows,&event);
10544 XHighlightRectangle(display,windows->image.id,
10545 windows->image.highlight_context,&highlight_info);
10546 if (event.xany.window == windows->command.id)
10547 {
10548 /*
10549 Select a command from the Command widget.
10550 */
10551 id=XCommandWidget(display,windows,PasteMenu,&event);
10552 if (id < 0)
10553 continue;
10554 switch (PasteCommands[id])
10555 {
10556 case PasteOperatorsCommand:
10557 {
10558 char
10559 command[MaxTextExtent],
10560 **operators;
10561
10562 /*
10563 Select a command from the pop-up menu.
10564 */
10565 operators=GetMagickOptions(MagickComposeOptions);
10566 if (operators == (char **) NULL)
10567 break;
10568 entry=XMenuWidget(display,windows,PasteMenu[id],
10569 (const char **) operators,command);
10570 if (entry >= 0)
10571 compose=(CompositeOperator) ParseMagickOption(
10572 MagickComposeOptions,MagickFalse,operators[entry]);
10573 operators=DestroyStringList(operators);
10574 break;
10575 }
10576 case PasteHelpCommand:
10577 {
10578 XTextViewWidget(display,resource_info,windows,MagickFalse,
10579 "Help Viewer - Image Composite",ImagePasteHelp);
10580 break;
10581 }
10582 case PasteDismissCommand:
10583 {
10584 /*
10585 Prematurely exit.
10586 */
10587 state|=EscapeState;
10588 state|=ExitState;
10589 break;
10590 }
10591 default:
10592 break;
10593 }
10594 continue;
10595 }
10596 switch (event.type)
10597 {
10598 case ButtonPress:
10599 {
10600 if (image->debug != MagickFalse)
10601 (void) LogMagickEvent(X11Event,GetMagickModule(),
10602 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10603 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10604 if (event.xbutton.button != Button1)
10605 break;
10606 if (event.xbutton.window != windows->image.id)
10607 break;
10608 /*
10609 Paste rectangle is relative to image configuration.
10610 */
10611 width=(unsigned int) image->columns;
10612 height=(unsigned int) image->rows;
10613 x=0;
10614 y=0;
10615 if (windows->image.crop_geometry != (char *) NULL)
10616 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10617 &width,&height);
10618 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10619 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10620 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10621 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10622 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10623 paste_info.x=windows->image.x+event.xbutton.x;
10624 paste_info.y=windows->image.y+event.xbutton.y;
10625 break;
10626 }
10627 case ButtonRelease:
10628 {
10629 if (image->debug != MagickFalse)
10630 (void) LogMagickEvent(X11Event,GetMagickModule(),
10631 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10632 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10633 if (event.xbutton.button != Button1)
10634 break;
10635 if (event.xbutton.window != windows->image.id)
10636 break;
10637 if ((paste_info.width != 0) && (paste_info.height != 0))
10638 {
10639 /*
10640 User has selected the location of the paste image.
10641 */
10642 paste_info.x=windows->image.x+event.xbutton.x;
10643 paste_info.y=windows->image.y+event.xbutton.y;
10644 state|=ExitState;
10645 }
10646 break;
10647 }
10648 case Expose:
10649 break;
10650 case KeyPress:
10651 {
10652 char
10653 command[MaxTextExtent];
10654
10655 KeySym
10656 key_symbol;
10657
10658 int
10659 length;
10660
10661 if (event.xkey.window != windows->image.id)
10662 break;
10663 /*
10664 Respond to a user key press.
10665 */
10666 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10667 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10668 *(command+length)='\0';
10669 if (image->debug != MagickFalse)
10670 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000010671 "Key press: 0x%lx (%s)",(long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +000010672 switch ((int) key_symbol)
10673 {
10674 case XK_Escape:
10675 case XK_F20:
10676 {
10677 /*
10678 Prematurely exit.
10679 */
10680 paste_image=DestroyImage(paste_image);
10681 state|=EscapeState;
10682 state|=ExitState;
10683 break;
10684 }
10685 case XK_F1:
10686 case XK_Help:
10687 {
10688 (void) XSetFunction(display,windows->image.highlight_context,
10689 GXcopy);
10690 XTextViewWidget(display,resource_info,windows,MagickFalse,
10691 "Help Viewer - Image Composite",ImagePasteHelp);
10692 (void) XSetFunction(display,windows->image.highlight_context,
10693 GXinvert);
10694 break;
10695 }
10696 default:
10697 {
10698 (void) XBell(display,0);
10699 break;
10700 }
10701 }
10702 break;
10703 }
10704 case MotionNotify:
10705 {
10706 /*
10707 Map and unmap Info widget as text cursor crosses its boundaries.
10708 */
10709 x=event.xmotion.x;
10710 y=event.xmotion.y;
10711 if (windows->info.mapped != MagickFalse)
10712 {
10713 if ((x < (int) (windows->info.x+windows->info.width)) &&
10714 (y < (int) (windows->info.y+windows->info.height)))
10715 (void) XWithdrawWindow(display,windows->info.id,
10716 windows->info.screen);
10717 }
10718 else
10719 if ((x > (int) (windows->info.x+windows->info.width)) ||
10720 (y > (int) (windows->info.y+windows->info.height)))
10721 (void) XMapWindow(display,windows->info.id);
10722 paste_info.x=windows->image.x+x;
10723 paste_info.y=windows->image.y+y;
10724 break;
10725 }
10726 default:
10727 {
10728 if (image->debug != MagickFalse)
10729 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10730 event.type);
10731 break;
10732 }
10733 }
10734 } while ((state & ExitState) == 0);
10735 (void) XSelectInput(display,windows->image.id,
10736 windows->image.attributes.event_mask);
10737 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10738 XSetCursorState(display,windows,MagickFalse);
10739 (void) XFreeCursor(display,cursor);
10740 if ((state & EscapeState) != 0)
10741 return(MagickTrue);
10742 /*
10743 Image pasting is relative to image configuration.
10744 */
10745 XSetCursorState(display,windows,MagickTrue);
10746 XCheckRefreshWindows(display,windows);
10747 width=(unsigned int) image->columns;
10748 height=(unsigned int) image->rows;
10749 x=0;
10750 y=0;
10751 if (windows->image.crop_geometry != (char *) NULL)
10752 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10753 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10754 paste_info.x+=x;
10755 paste_info.x=(int) (scale_factor*paste_info.x+0.5);
10756 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10757 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10758 paste_info.y+=y;
10759 paste_info.y=(int) (scale_factor*paste_info.y*scale_factor+0.5);
10760 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10761 /*
10762 Paste image with X Image window.
10763 */
10764 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10765 paste_image=DestroyImage(paste_image);
10766 XSetCursorState(display,windows,MagickFalse);
10767 /*
10768 Update image colormap.
10769 */
10770 XConfigureImageColormap(display,resource_info,windows,image);
10771 (void) XConfigureImage(display,resource_info,windows,image);
10772 return(MagickTrue);
10773}
10774
10775/*
10776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10777% %
10778% %
10779% %
10780+ X P r i n t I m a g e %
10781% %
10782% %
10783% %
10784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10785%
10786% XPrintImage() prints an image to a Postscript printer.
10787%
10788% The format of the XPrintImage method is:
10789%
10790% MagickBooleanType XPrintImage(Display *display,
10791% XResourceInfo *resource_info,XWindows *windows,Image *image)
10792%
10793% A description of each parameter follows:
10794%
10795% o display: Specifies a connection to an X server; returned from
10796% XOpenDisplay.
10797%
10798% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10799%
10800% o windows: Specifies a pointer to a XWindows structure.
10801%
10802% o image: the image.
10803%
10804*/
10805static MagickBooleanType XPrintImage(Display *display,
10806 XResourceInfo *resource_info,XWindows *windows,Image *image)
10807{
10808 char
10809 filename[MaxTextExtent],
10810 geometry[MaxTextExtent];
10811
10812 Image
10813 *print_image;
10814
10815 ImageInfo
10816 *image_info;
10817
10818 MagickStatusType
10819 status;
10820
10821 /*
10822 Request Postscript page geometry from user.
10823 */
10824 image_info=CloneImageInfo(resource_info->image_info);
10825 (void) FormatMagickString(geometry,MaxTextExtent,"Letter");
10826 if (image_info->page != (char *) NULL)
10827 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10828 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10829 "Select Postscript Page Geometry:",geometry);
10830 if (*geometry == '\0')
10831 return(MagickTrue);
10832 image_info->page=GetPageGeometry(geometry);
10833 /*
10834 Apply image transforms.
10835 */
10836 XSetCursorState(display,windows,MagickTrue);
10837 XCheckRefreshWindows(display,windows);
10838 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10839 if (print_image == (Image *) NULL)
10840 return(MagickFalse);
10841 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
10842 windows->image.ximage->width,windows->image.ximage->height);
10843 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10844 /*
10845 Print image.
10846 */
10847 (void) AcquireUniqueFilename(filename);
10848 (void) FormatMagickString(print_image->filename,MaxTextExtent,"print:%s",
10849 filename);
10850 status=WriteImage(image_info,print_image);
10851 (void) RelinquishUniqueFileResource(filename);
10852 print_image=DestroyImage(print_image);
10853 image_info=DestroyImageInfo(image_info);
10854 XSetCursorState(display,windows,MagickFalse);
10855 return(status != 0 ? MagickTrue : MagickFalse);
10856}
10857
10858/*
10859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10860% %
10861% %
10862% %
10863+ X R O I I m a g e %
10864% %
10865% %
10866% %
10867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10868%
10869% XROIImage() applies an image processing technique to a region of interest.
10870%
10871% The format of the XROIImage method is:
10872%
10873% MagickBooleanType XROIImage(Display *display,
10874% XResourceInfo *resource_info,XWindows *windows,Image **image)
10875%
10876% A description of each parameter follows:
10877%
10878% o display: Specifies a connection to an X server; returned from
10879% XOpenDisplay.
10880%
10881% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10882%
10883% o windows: Specifies a pointer to a XWindows structure.
10884%
10885% o image: the image; returned from ReadImage.
10886%
10887*/
10888static MagickBooleanType XROIImage(Display *display,
10889 XResourceInfo *resource_info,XWindows *windows,Image **image)
10890{
10891#define ApplyMenus 7
10892
10893 static const char
10894 *ROIMenu[] =
10895 {
10896 "Help",
10897 "Dismiss",
10898 (char *) NULL
10899 },
10900 *ApplyMenu[] =
10901 {
10902 "File",
10903 "Edit",
10904 "Transform",
10905 "Enhance",
10906 "Effects",
10907 "F/X",
10908 "Miscellany",
10909 "Help",
10910 "Dismiss",
10911 (char *) NULL
10912 },
10913 *FileMenu[] =
10914 {
10915 "Save...",
10916 "Print...",
10917 (char *) NULL
10918 },
10919 *EditMenu[] =
10920 {
10921 "Undo",
10922 "Redo",
10923 (char *) NULL
10924 },
10925 *TransformMenu[] =
10926 {
10927 "Flop",
10928 "Flip",
10929 "Rotate Right",
10930 "Rotate Left",
10931 (char *) NULL
10932 },
10933 *EnhanceMenu[] =
10934 {
10935 "Hue...",
10936 "Saturation...",
10937 "Brightness...",
10938 "Gamma...",
10939 "Spiff",
10940 "Dull",
10941 "Contrast Stretch...",
10942 "Sigmoidal Contrast...",
10943 "Normalize",
10944 "Equalize",
10945 "Negate",
10946 "Grayscale",
10947 "Map...",
10948 "Quantize...",
10949 (char *) NULL
10950 },
10951 *EffectsMenu[] =
10952 {
10953 "Despeckle",
10954 "Emboss",
10955 "Reduce Noise",
10956 "Add Noise",
10957 "Sharpen...",
10958 "Blur...",
10959 "Threshold...",
10960 "Edge Detect...",
10961 "Spread...",
10962 "Shade...",
10963 "Raise...",
10964 "Segment...",
10965 (char *) NULL
10966 },
10967 *FXMenu[] =
10968 {
10969 "Solarize...",
10970 "Sepia Tone...",
10971 "Swirl...",
10972 "Implode...",
10973 "Vignette...",
10974 "Wave...",
10975 "Oil Paint...",
10976 "Charcoal Draw...",
10977 (char *) NULL
10978 },
10979 *MiscellanyMenu[] =
10980 {
10981 "Image Info",
10982 "Zoom Image",
10983 "Show Preview...",
10984 "Show Histogram",
10985 "Show Matte",
10986 (char *) NULL
10987 };
10988
10989 static const char
10990 **Menus[ApplyMenus] =
10991 {
10992 FileMenu,
10993 EditMenu,
10994 TransformMenu,
10995 EnhanceMenu,
10996 EffectsMenu,
10997 FXMenu,
10998 MiscellanyMenu
10999 };
11000
11001 static const CommandType
11002 ApplyCommands[] =
11003 {
11004 NullCommand,
11005 NullCommand,
11006 NullCommand,
11007 NullCommand,
11008 NullCommand,
11009 NullCommand,
11010 NullCommand,
11011 HelpCommand,
11012 QuitCommand
11013 },
11014 FileCommands[] =
11015 {
11016 SaveCommand,
11017 PrintCommand
11018 },
11019 EditCommands[] =
11020 {
11021 UndoCommand,
11022 RedoCommand
11023 },
11024 TransformCommands[] =
11025 {
11026 FlopCommand,
11027 FlipCommand,
11028 RotateRightCommand,
11029 RotateLeftCommand
11030 },
11031 EnhanceCommands[] =
11032 {
11033 HueCommand,
11034 SaturationCommand,
11035 BrightnessCommand,
11036 GammaCommand,
11037 SpiffCommand,
11038 DullCommand,
11039 ContrastStretchCommand,
11040 SigmoidalContrastCommand,
11041 NormalizeCommand,
11042 EqualizeCommand,
11043 NegateCommand,
11044 GrayscaleCommand,
11045 MapCommand,
11046 QuantizeCommand
11047 },
11048 EffectsCommands[] =
11049 {
11050 DespeckleCommand,
11051 EmbossCommand,
11052 ReduceNoiseCommand,
11053 AddNoiseCommand,
11054 SharpenCommand,
11055 BlurCommand,
11056 EdgeDetectCommand,
11057 SpreadCommand,
11058 ShadeCommand,
11059 RaiseCommand,
11060 SegmentCommand
11061 },
11062 FXCommands[] =
11063 {
11064 SolarizeCommand,
11065 SepiaToneCommand,
11066 SwirlCommand,
11067 ImplodeCommand,
11068 VignetteCommand,
11069 WaveCommand,
11070 OilPaintCommand,
11071 CharcoalDrawCommand
11072 },
11073 MiscellanyCommands[] =
11074 {
11075 InfoCommand,
11076 ZoomCommand,
11077 ShowPreviewCommand,
11078 ShowHistogramCommand,
11079 ShowMatteCommand
11080 },
11081 ROICommands[] =
11082 {
11083 ROIHelpCommand,
11084 ROIDismissCommand
11085 };
11086
11087 static const CommandType
11088 *Commands[ApplyMenus] =
11089 {
11090 FileCommands,
11091 EditCommands,
11092 TransformCommands,
11093 EnhanceCommands,
11094 EffectsCommands,
11095 FXCommands,
11096 MiscellanyCommands
11097 };
11098
11099 char
11100 command[MaxTextExtent],
11101 text[MaxTextExtent];
11102
11103 CommandType
11104 command_type;
11105
11106 Cursor
11107 cursor;
11108
11109 Image
11110 *roi_image;
11111
11112 int
11113 entry,
11114 id,
11115 x,
11116 y;
11117
11118 MagickRealType
11119 scale_factor;
11120
11121 MagickProgressMonitor
11122 progress_monitor;
11123
11124 RectangleInfo
11125 crop_info,
11126 highlight_info,
11127 roi_info;
11128
11129 unsigned int
11130 height,
11131 width;
11132
cristybb503372010-05-27 20:51:26 +000011133 size_t
cristy3ed852e2009-09-05 21:47:34 +000011134 state;
11135
11136 XEvent
11137 event;
11138
11139 /*
11140 Map Command widget.
11141 */
11142 (void) CloneString(&windows->command.name,"ROI");
11143 windows->command.data=0;
11144 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11145 (void) XMapRaised(display,windows->command.id);
11146 XClientMessage(display,windows->image.id,windows->im_protocols,
11147 windows->im_update_widget,CurrentTime);
11148 /*
11149 Track pointer until button 1 is pressed.
11150 */
11151 XQueryPosition(display,windows->image.id,&x,&y);
11152 (void) XSelectInput(display,windows->image.id,
11153 windows->image.attributes.event_mask | PointerMotionMask);
11154 roi_info.x=windows->image.x+x;
11155 roi_info.y=windows->image.y+y;
11156 roi_info.width=0;
11157 roi_info.height=0;
11158 cursor=XCreateFontCursor(display,XC_fleur);
11159 state=DefaultState;
11160 do
11161 {
11162 if (windows->info.mapped != MagickFalse)
11163 {
11164 /*
11165 Display pointer position.
11166 */
11167 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000011168 (long) roi_info.x,(long) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011169 XInfoWidget(display,windows,text);
11170 }
11171 /*
11172 Wait for next event.
11173 */
11174 XScreenEvent(display,windows,&event);
11175 if (event.xany.window == windows->command.id)
11176 {
11177 /*
11178 Select a command from the Command widget.
11179 */
11180 id=XCommandWidget(display,windows,ROIMenu,&event);
11181 if (id < 0)
11182 continue;
11183 switch (ROICommands[id])
11184 {
11185 case ROIHelpCommand:
11186 {
11187 XTextViewWidget(display,resource_info,windows,MagickFalse,
11188 "Help Viewer - Region of Interest",ImageROIHelp);
11189 break;
11190 }
11191 case ROIDismissCommand:
11192 {
11193 /*
11194 Prematurely exit.
11195 */
11196 state|=EscapeState;
11197 state|=ExitState;
11198 break;
11199 }
11200 default:
11201 break;
11202 }
11203 continue;
11204 }
11205 switch (event.type)
11206 {
11207 case ButtonPress:
11208 {
11209 if (event.xbutton.button != Button1)
11210 break;
11211 if (event.xbutton.window != windows->image.id)
11212 break;
11213 /*
11214 Note first corner of region of interest rectangle-- exit loop.
11215 */
11216 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11217 roi_info.x=windows->image.x+event.xbutton.x;
11218 roi_info.y=windows->image.y+event.xbutton.y;
11219 state|=ExitState;
11220 break;
11221 }
11222 case ButtonRelease:
11223 break;
11224 case Expose:
11225 break;
11226 case KeyPress:
11227 {
11228 KeySym
11229 key_symbol;
11230
11231 if (event.xkey.window != windows->image.id)
11232 break;
11233 /*
11234 Respond to a user key press.
11235 */
11236 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11237 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11238 switch ((int) key_symbol)
11239 {
11240 case XK_Escape:
11241 case XK_F20:
11242 {
11243 /*
11244 Prematurely exit.
11245 */
11246 state|=EscapeState;
11247 state|=ExitState;
11248 break;
11249 }
11250 case XK_F1:
11251 case XK_Help:
11252 {
11253 XTextViewWidget(display,resource_info,windows,MagickFalse,
11254 "Help Viewer - Region of Interest",ImageROIHelp);
11255 break;
11256 }
11257 default:
11258 {
11259 (void) XBell(display,0);
11260 break;
11261 }
11262 }
11263 break;
11264 }
11265 case MotionNotify:
11266 {
11267 /*
11268 Map and unmap Info widget as text cursor crosses its boundaries.
11269 */
11270 x=event.xmotion.x;
11271 y=event.xmotion.y;
11272 if (windows->info.mapped != MagickFalse)
11273 {
11274 if ((x < (int) (windows->info.x+windows->info.width)) &&
11275 (y < (int) (windows->info.y+windows->info.height)))
11276 (void) XWithdrawWindow(display,windows->info.id,
11277 windows->info.screen);
11278 }
11279 else
11280 if ((x > (int) (windows->info.x+windows->info.width)) ||
11281 (y > (int) (windows->info.y+windows->info.height)))
11282 (void) XMapWindow(display,windows->info.id);
11283 roi_info.x=windows->image.x+x;
11284 roi_info.y=windows->image.y+y;
11285 break;
11286 }
11287 default:
11288 break;
11289 }
11290 } while ((state & ExitState) == 0);
11291 (void) XSelectInput(display,windows->image.id,
11292 windows->image.attributes.event_mask);
11293 if ((state & EscapeState) != 0)
11294 {
11295 /*
11296 User want to exit without region of interest.
11297 */
11298 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11299 (void) XFreeCursor(display,cursor);
11300 return(MagickTrue);
11301 }
11302 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11303 do
11304 {
11305 /*
11306 Size rectangle as pointer moves until the mouse button is released.
11307 */
11308 x=(int) roi_info.x;
11309 y=(int) roi_info.y;
11310 roi_info.width=0;
11311 roi_info.height=0;
11312 state=DefaultState;
11313 do
11314 {
11315 highlight_info=roi_info;
11316 highlight_info.x=roi_info.x-windows->image.x;
11317 highlight_info.y=roi_info.y-windows->image.y;
11318 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11319 {
11320 /*
11321 Display info and draw region of interest rectangle.
11322 */
11323 if (windows->info.mapped == MagickFalse)
11324 (void) XMapWindow(display,windows->info.id);
cristye8c25f92010-06-03 00:53:06 +000011325 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011326 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011327 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011328 XInfoWidget(display,windows,text);
11329 XHighlightRectangle(display,windows->image.id,
11330 windows->image.highlight_context,&highlight_info);
11331 }
11332 else
11333 if (windows->info.mapped != MagickFalse)
11334 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11335 /*
11336 Wait for next event.
11337 */
11338 XScreenEvent(display,windows,&event);
11339 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11340 XHighlightRectangle(display,windows->image.id,
11341 windows->image.highlight_context,&highlight_info);
11342 switch (event.type)
11343 {
11344 case ButtonPress:
11345 {
11346 roi_info.x=windows->image.x+event.xbutton.x;
11347 roi_info.y=windows->image.y+event.xbutton.y;
11348 break;
11349 }
11350 case ButtonRelease:
11351 {
11352 /*
11353 User has committed to region of interest rectangle.
11354 */
11355 roi_info.x=windows->image.x+event.xbutton.x;
11356 roi_info.y=windows->image.y+event.xbutton.y;
11357 XSetCursorState(display,windows,MagickFalse);
11358 state|=ExitState;
11359 if (LocaleCompare(windows->command.name,"Apply") == 0)
11360 break;
11361 (void) CloneString(&windows->command.name,"Apply");
11362 windows->command.data=ApplyMenus;
11363 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11364 break;
11365 }
11366 case Expose:
11367 break;
11368 case MotionNotify:
11369 {
11370 roi_info.x=windows->image.x+event.xmotion.x;
11371 roi_info.y=windows->image.y+event.xmotion.y;
11372 }
11373 default:
11374 break;
11375 }
11376 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11377 ((state & ExitState) != 0))
11378 {
11379 /*
11380 Check boundary conditions.
11381 */
11382 if (roi_info.x < 0)
11383 roi_info.x=0;
11384 else
11385 if (roi_info.x > (int) windows->image.ximage->width)
11386 roi_info.x=windows->image.ximage->width;
11387 if ((int) roi_info.x < x)
11388 roi_info.width=(unsigned int) (x-roi_info.x);
11389 else
11390 {
11391 roi_info.width=(unsigned int) (roi_info.x-x);
11392 roi_info.x=x;
11393 }
11394 if (roi_info.y < 0)
11395 roi_info.y=0;
11396 else
11397 if (roi_info.y > (int) windows->image.ximage->height)
11398 roi_info.y=windows->image.ximage->height;
11399 if ((int) roi_info.y < y)
11400 roi_info.height=(unsigned int) (y-roi_info.y);
11401 else
11402 {
11403 roi_info.height=(unsigned int) (roi_info.y-y);
11404 roi_info.y=y;
11405 }
11406 }
11407 } while ((state & ExitState) == 0);
11408 /*
11409 Wait for user to grab a corner of the rectangle or press return.
11410 */
11411 state=DefaultState;
11412 command_type=NullCommand;
11413 (void) XMapWindow(display,windows->info.id);
11414 do
11415 {
11416 if (windows->info.mapped != MagickFalse)
11417 {
11418 /*
11419 Display pointer position.
11420 */
cristye8c25f92010-06-03 00:53:06 +000011421 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011422 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011423 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011424 XInfoWidget(display,windows,text);
11425 }
11426 highlight_info=roi_info;
11427 highlight_info.x=roi_info.x-windows->image.x;
11428 highlight_info.y=roi_info.y-windows->image.y;
11429 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11430 {
11431 state|=EscapeState;
11432 state|=ExitState;
11433 break;
11434 }
11435 if ((state & UpdateRegionState) != 0)
11436 {
11437 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11438 switch (command_type)
11439 {
11440 case UndoCommand:
11441 case RedoCommand:
11442 {
11443 (void) XMagickCommand(display,resource_info,windows,command_type,
11444 image);
11445 break;
11446 }
11447 default:
11448 {
11449 /*
11450 Region of interest is relative to image configuration.
11451 */
11452 progress_monitor=SetImageProgressMonitor(*image,
11453 (MagickProgressMonitor) NULL,(*image)->client_data);
11454 crop_info=roi_info;
11455 width=(unsigned int) (*image)->columns;
11456 height=(unsigned int) (*image)->rows;
11457 x=0;
11458 y=0;
11459 if (windows->image.crop_geometry != (char *) NULL)
11460 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11461 &width,&height);
11462 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11463 crop_info.x+=x;
11464 crop_info.x=(int) (scale_factor*crop_info.x+0.5);
11465 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11466 scale_factor=(MagickRealType)
11467 height/windows->image.ximage->height;
11468 crop_info.y+=y;
11469 crop_info.y=(int) (scale_factor*crop_info.y+0.5);
11470 crop_info.height=(unsigned int)
11471 (scale_factor*crop_info.height+0.5);
11472 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11473 (void) SetImageProgressMonitor(*image,progress_monitor,
11474 (*image)->client_data);
11475 if (roi_image == (Image *) NULL)
11476 continue;
11477 /*
11478 Apply image processing technique to the region of interest.
11479 */
11480 windows->image.orphan=MagickTrue;
11481 (void) XMagickCommand(display,resource_info,windows,command_type,
11482 &roi_image);
11483 progress_monitor=SetImageProgressMonitor(*image,
11484 (MagickProgressMonitor) NULL,(*image)->client_data);
11485 (void) XMagickCommand(display,resource_info,windows,
11486 SaveToUndoBufferCommand,image);
11487 windows->image.orphan=MagickFalse;
11488 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11489 crop_info.x,crop_info.y);
11490 roi_image=DestroyImage(roi_image);
11491 (void) SetImageProgressMonitor(*image,progress_monitor,
11492 (*image)->client_data);
11493 break;
11494 }
11495 }
11496 if (command_type != InfoCommand)
11497 {
11498 XConfigureImageColormap(display,resource_info,windows,*image);
11499 (void) XConfigureImage(display,resource_info,windows,*image);
11500 }
11501 XCheckRefreshWindows(display,windows);
11502 XInfoWidget(display,windows,text);
11503 (void) XSetFunction(display,windows->image.highlight_context,
11504 GXinvert);
11505 state&=(~UpdateRegionState);
11506 }
11507 XHighlightRectangle(display,windows->image.id,
11508 windows->image.highlight_context,&highlight_info);
11509 XScreenEvent(display,windows,&event);
11510 if (event.xany.window == windows->command.id)
11511 {
11512 /*
11513 Select a command from the Command widget.
11514 */
11515 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11516 command_type=NullCommand;
11517 id=XCommandWidget(display,windows,ApplyMenu,&event);
11518 if (id >= 0)
11519 {
11520 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11521 command_type=ApplyCommands[id];
11522 if (id < ApplyMenus)
11523 {
11524 /*
11525 Select a command from a pop-up menu.
11526 */
11527 entry=XMenuWidget(display,windows,ApplyMenu[id],
11528 (const char **) Menus[id],command);
11529 if (entry >= 0)
11530 {
11531 (void) CopyMagickString(command,Menus[id][entry],
11532 MaxTextExtent);
11533 command_type=Commands[id][entry];
11534 }
11535 }
11536 }
11537 (void) XSetFunction(display,windows->image.highlight_context,
11538 GXinvert);
11539 XHighlightRectangle(display,windows->image.id,
11540 windows->image.highlight_context,&highlight_info);
11541 if (command_type == HelpCommand)
11542 {
11543 (void) XSetFunction(display,windows->image.highlight_context,
11544 GXcopy);
11545 XTextViewWidget(display,resource_info,windows,MagickFalse,
11546 "Help Viewer - Region of Interest",ImageROIHelp);
11547 (void) XSetFunction(display,windows->image.highlight_context,
11548 GXinvert);
11549 continue;
11550 }
11551 if (command_type == QuitCommand)
11552 {
11553 /*
11554 exit.
11555 */
11556 state|=EscapeState;
11557 state|=ExitState;
11558 continue;
11559 }
11560 if (command_type != NullCommand)
11561 state|=UpdateRegionState;
11562 continue;
11563 }
11564 XHighlightRectangle(display,windows->image.id,
11565 windows->image.highlight_context,&highlight_info);
11566 switch (event.type)
11567 {
11568 case ButtonPress:
11569 {
11570 x=windows->image.x;
11571 y=windows->image.y;
11572 if (event.xbutton.button != Button1)
11573 break;
11574 if (event.xbutton.window != windows->image.id)
11575 break;
11576 x=windows->image.x+event.xbutton.x;
11577 y=windows->image.y+event.xbutton.y;
11578 if ((x < (int) (roi_info.x+RoiDelta)) &&
11579 (x > (int) (roi_info.x-RoiDelta)) &&
11580 (y < (int) (roi_info.y+RoiDelta)) &&
11581 (y > (int) (roi_info.y-RoiDelta)))
11582 {
cristybb503372010-05-27 20:51:26 +000011583 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11584 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011585 state|=UpdateConfigurationState;
11586 break;
11587 }
11588 if ((x < (int) (roi_info.x+RoiDelta)) &&
11589 (x > (int) (roi_info.x-RoiDelta)) &&
11590 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11591 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11592 {
cristybb503372010-05-27 20:51:26 +000011593 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
cristy3ed852e2009-09-05 21:47:34 +000011594 state|=UpdateConfigurationState;
11595 break;
11596 }
11597 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11598 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11599 (y < (int) (roi_info.y+RoiDelta)) &&
11600 (y > (int) (roi_info.y-RoiDelta)))
11601 {
cristybb503372010-05-27 20:51:26 +000011602 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011603 state|=UpdateConfigurationState;
11604 break;
11605 }
11606 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11607 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11608 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11609 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11610 {
11611 state|=UpdateConfigurationState;
11612 break;
11613 }
11614 }
11615 case ButtonRelease:
11616 {
11617 if (event.xbutton.window == windows->pan.id)
11618 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11619 (highlight_info.y != crop_info.y-windows->image.y))
11620 XHighlightRectangle(display,windows->image.id,
11621 windows->image.highlight_context,&highlight_info);
11622 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11623 event.xbutton.time);
11624 break;
11625 }
11626 case Expose:
11627 {
11628 if (event.xexpose.window == windows->image.id)
11629 if (event.xexpose.count == 0)
11630 {
11631 event.xexpose.x=(int) highlight_info.x;
11632 event.xexpose.y=(int) highlight_info.y;
11633 event.xexpose.width=(int) highlight_info.width;
11634 event.xexpose.height=(int) highlight_info.height;
11635 XRefreshWindow(display,&windows->image,&event);
11636 }
11637 if (event.xexpose.window == windows->info.id)
11638 if (event.xexpose.count == 0)
11639 XInfoWidget(display,windows,text);
11640 break;
11641 }
11642 case KeyPress:
11643 {
11644 KeySym
11645 key_symbol;
11646
11647 if (event.xkey.window != windows->image.id)
11648 break;
11649 /*
11650 Respond to a user key press.
11651 */
11652 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11653 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11654 switch ((int) key_symbol)
11655 {
11656 case XK_Shift_L:
11657 case XK_Shift_R:
11658 break;
11659 case XK_Escape:
11660 case XK_F20:
11661 state|=EscapeState;
11662 case XK_Return:
11663 {
11664 state|=ExitState;
11665 break;
11666 }
11667 case XK_Home:
11668 case XK_KP_Home:
11669 {
cristybb503372010-05-27 20:51:26 +000011670 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11671 roi_info.y=(ssize_t) (windows->image.height/2L-roi_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +000011672 break;
11673 }
11674 case XK_Left:
11675 case XK_KP_Left:
11676 {
11677 roi_info.x--;
11678 break;
11679 }
11680 case XK_Up:
11681 case XK_KP_Up:
11682 case XK_Next:
11683 {
11684 roi_info.y--;
11685 break;
11686 }
11687 case XK_Right:
11688 case XK_KP_Right:
11689 {
11690 roi_info.x++;
11691 break;
11692 }
11693 case XK_Prior:
11694 case XK_Down:
11695 case XK_KP_Down:
11696 {
11697 roi_info.y++;
11698 break;
11699 }
11700 case XK_F1:
11701 case XK_Help:
11702 {
11703 (void) XSetFunction(display,windows->image.highlight_context,
11704 GXcopy);
11705 XTextViewWidget(display,resource_info,windows,MagickFalse,
11706 "Help Viewer - Region of Interest",ImageROIHelp);
11707 (void) XSetFunction(display,windows->image.highlight_context,
11708 GXinvert);
11709 break;
11710 }
11711 default:
11712 {
11713 command_type=XImageWindowCommand(display,resource_info,windows,
11714 event.xkey.state,key_symbol,image);
11715 if (command_type != NullCommand)
11716 state|=UpdateRegionState;
11717 break;
11718 }
11719 }
11720 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11721 event.xkey.time);
11722 break;
11723 }
11724 case KeyRelease:
11725 break;
11726 case MotionNotify:
11727 {
11728 if (event.xbutton.window != windows->image.id)
11729 break;
11730 /*
11731 Map and unmap Info widget as text cursor crosses its boundaries.
11732 */
11733 x=event.xmotion.x;
11734 y=event.xmotion.y;
11735 if (windows->info.mapped != MagickFalse)
11736 {
11737 if ((x < (int) (windows->info.x+windows->info.width)) &&
11738 (y < (int) (windows->info.y+windows->info.height)))
11739 (void) XWithdrawWindow(display,windows->info.id,
11740 windows->info.screen);
11741 }
11742 else
11743 if ((x > (int) (windows->info.x+windows->info.width)) ||
11744 (y > (int) (windows->info.y+windows->info.height)))
11745 (void) XMapWindow(display,windows->info.id);
11746 roi_info.x=windows->image.x+event.xmotion.x;
11747 roi_info.y=windows->image.y+event.xmotion.y;
11748 break;
11749 }
11750 case SelectionRequest:
11751 {
11752 XSelectionEvent
11753 notify;
11754
11755 XSelectionRequestEvent
11756 *request;
11757
11758 /*
11759 Set primary selection.
11760 */
cristye8c25f92010-06-03 00:53:06 +000011761 (void) FormatMagickString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011762 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011763 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011764 request=(&(event.xselectionrequest));
11765 (void) XChangeProperty(request->display,request->requestor,
11766 request->property,request->target,8,PropModeReplace,
11767 (unsigned char *) text,(int) strlen(text));
11768 notify.type=SelectionNotify;
11769 notify.display=request->display;
11770 notify.requestor=request->requestor;
11771 notify.selection=request->selection;
11772 notify.target=request->target;
11773 notify.time=request->time;
11774 if (request->property == None)
11775 notify.property=request->target;
11776 else
11777 notify.property=request->property;
11778 (void) XSendEvent(request->display,request->requestor,False,0,
11779 (XEvent *) &notify);
11780 }
11781 default:
11782 break;
11783 }
11784 if ((state & UpdateConfigurationState) != 0)
11785 {
11786 (void) XPutBackEvent(display,&event);
11787 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11788 break;
11789 }
11790 } while ((state & ExitState) == 0);
11791 } while ((state & ExitState) == 0);
11792 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11793 XSetCursorState(display,windows,MagickFalse);
11794 if ((state & EscapeState) != 0)
11795 return(MagickTrue);
11796 return(MagickTrue);
11797}
11798
11799/*
11800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11801% %
11802% %
11803% %
11804+ X R o t a t e I m a g e %
11805% %
11806% %
11807% %
11808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11809%
11810% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11811% rotation angle is computed from the slope of a line drawn by the user.
11812%
11813% The format of the XRotateImage method is:
11814%
11815% MagickBooleanType XRotateImage(Display *display,
11816% XResourceInfo *resource_info,XWindows *windows,double degrees,
11817% Image **image)
11818%
11819% A description of each parameter follows:
11820%
11821% o display: Specifies a connection to an X server; returned from
11822% XOpenDisplay.
11823%
11824% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11825%
11826% o windows: Specifies a pointer to a XWindows structure.
11827%
11828% o degrees: Specifies the number of degrees to rotate the image.
11829%
11830% o image: the image.
11831%
11832*/
11833static MagickBooleanType XRotateImage(Display *display,
11834 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11835{
11836 static const char
11837 *RotateMenu[] =
11838 {
11839 "Pixel Color",
11840 "Direction",
11841 "Help",
11842 "Dismiss",
11843 (char *) NULL
11844 };
11845
11846 static ModeType
11847 direction = HorizontalRotateCommand;
11848
11849 static const ModeType
11850 DirectionCommands[] =
11851 {
11852 HorizontalRotateCommand,
11853 VerticalRotateCommand
11854 },
11855 RotateCommands[] =
11856 {
11857 RotateColorCommand,
11858 RotateDirectionCommand,
11859 RotateHelpCommand,
11860 RotateDismissCommand
11861 };
11862
11863 static unsigned int
11864 pen_id = 0;
11865
11866 char
11867 command[MaxTextExtent],
11868 text[MaxTextExtent];
11869
11870 Image
11871 *rotate_image;
11872
11873 int
11874 id,
11875 x,
11876 y;
11877
11878 MagickRealType
11879 normalized_degrees;
11880
11881 register int
11882 i;
11883
11884 unsigned int
11885 height,
11886 rotations,
11887 width;
11888
11889 if (degrees == 0.0)
11890 {
11891 unsigned int
11892 distance;
11893
cristybb503372010-05-27 20:51:26 +000011894 size_t
cristy3ed852e2009-09-05 21:47:34 +000011895 state;
11896
11897 XEvent
11898 event;
11899
11900 XSegment
11901 rotate_info;
11902
11903 /*
11904 Map Command widget.
11905 */
11906 (void) CloneString(&windows->command.name,"Rotate");
11907 windows->command.data=2;
11908 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11909 (void) XMapRaised(display,windows->command.id);
11910 XClientMessage(display,windows->image.id,windows->im_protocols,
11911 windows->im_update_widget,CurrentTime);
11912 /*
11913 Wait for first button press.
11914 */
11915 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11916 XQueryPosition(display,windows->image.id,&x,&y);
11917 rotate_info.x1=x;
11918 rotate_info.y1=y;
11919 rotate_info.x2=x;
11920 rotate_info.y2=y;
11921 state=DefaultState;
11922 do
11923 {
11924 XHighlightLine(display,windows->image.id,
11925 windows->image.highlight_context,&rotate_info);
11926 /*
11927 Wait for next event.
11928 */
11929 XScreenEvent(display,windows,&event);
11930 XHighlightLine(display,windows->image.id,
11931 windows->image.highlight_context,&rotate_info);
11932 if (event.xany.window == windows->command.id)
11933 {
11934 /*
11935 Select a command from the Command widget.
11936 */
11937 id=XCommandWidget(display,windows,RotateMenu,&event);
11938 if (id < 0)
11939 continue;
11940 (void) XSetFunction(display,windows->image.highlight_context,
11941 GXcopy);
11942 switch (RotateCommands[id])
11943 {
11944 case RotateColorCommand:
11945 {
11946 const char
11947 *ColorMenu[MaxNumberPens];
11948
11949 int
11950 pen_number;
11951
11952 XColor
11953 color;
11954
11955 /*
11956 Initialize menu selections.
11957 */
11958 for (i=0; i < (int) (MaxNumberPens-2); i++)
11959 ColorMenu[i]=resource_info->pen_colors[i];
11960 ColorMenu[MaxNumberPens-2]="Browser...";
11961 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
11962 /*
11963 Select a pen color from the pop-up menu.
11964 */
11965 pen_number=XMenuWidget(display,windows,RotateMenu[id],
11966 (const char **) ColorMenu,command);
11967 if (pen_number < 0)
11968 break;
11969 if (pen_number == (MaxNumberPens-2))
11970 {
11971 static char
11972 color_name[MaxTextExtent] = "gray";
11973
11974 /*
11975 Select a pen color from a dialog.
11976 */
11977 resource_info->pen_colors[pen_number]=color_name;
11978 XColorBrowserWidget(display,windows,"Select",color_name);
11979 if (*color_name == '\0')
11980 break;
11981 }
11982 /*
11983 Set pen color.
11984 */
11985 (void) XParseColor(display,windows->map_info->colormap,
11986 resource_info->pen_colors[pen_number],&color);
11987 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
11988 (unsigned int) MaxColors,&color);
11989 windows->pixel_info->pen_colors[pen_number]=color;
11990 pen_id=(unsigned int) pen_number;
11991 break;
11992 }
11993 case RotateDirectionCommand:
11994 {
11995 static const char
11996 *Directions[] =
11997 {
11998 "horizontal",
11999 "vertical",
12000 (char *) NULL,
12001 };
12002
12003 /*
12004 Select a command from the pop-up menu.
12005 */
12006 id=XMenuWidget(display,windows,RotateMenu[id],
12007 Directions,command);
12008 if (id >= 0)
12009 direction=DirectionCommands[id];
12010 break;
12011 }
12012 case RotateHelpCommand:
12013 {
12014 XTextViewWidget(display,resource_info,windows,MagickFalse,
12015 "Help Viewer - Image Rotation",ImageRotateHelp);
12016 break;
12017 }
12018 case RotateDismissCommand:
12019 {
12020 /*
12021 Prematurely exit.
12022 */
12023 state|=EscapeState;
12024 state|=ExitState;
12025 break;
12026 }
12027 default:
12028 break;
12029 }
12030 (void) XSetFunction(display,windows->image.highlight_context,
12031 GXinvert);
12032 continue;
12033 }
12034 switch (event.type)
12035 {
12036 case ButtonPress:
12037 {
12038 if (event.xbutton.button != Button1)
12039 break;
12040 if (event.xbutton.window != windows->image.id)
12041 break;
12042 /*
12043 exit loop.
12044 */
12045 (void) XSetFunction(display,windows->image.highlight_context,
12046 GXcopy);
12047 rotate_info.x1=event.xbutton.x;
12048 rotate_info.y1=event.xbutton.y;
12049 state|=ExitState;
12050 break;
12051 }
12052 case ButtonRelease:
12053 break;
12054 case Expose:
12055 break;
12056 case KeyPress:
12057 {
12058 char
12059 command[MaxTextExtent];
12060
12061 KeySym
12062 key_symbol;
12063
12064 if (event.xkey.window != windows->image.id)
12065 break;
12066 /*
12067 Respond to a user key press.
12068 */
12069 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12070 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12071 switch ((int) key_symbol)
12072 {
12073 case XK_Escape:
12074 case XK_F20:
12075 {
12076 /*
12077 Prematurely exit.
12078 */
12079 state|=EscapeState;
12080 state|=ExitState;
12081 break;
12082 }
12083 case XK_F1:
12084 case XK_Help:
12085 {
12086 (void) XSetFunction(display,windows->image.highlight_context,
12087 GXcopy);
12088 XTextViewWidget(display,resource_info,windows,MagickFalse,
12089 "Help Viewer - Image Rotation",ImageRotateHelp);
12090 (void) XSetFunction(display,windows->image.highlight_context,
12091 GXinvert);
12092 break;
12093 }
12094 default:
12095 {
12096 (void) XBell(display,0);
12097 break;
12098 }
12099 }
12100 break;
12101 }
12102 case MotionNotify:
12103 {
12104 rotate_info.x1=event.xmotion.x;
12105 rotate_info.y1=event.xmotion.y;
12106 }
12107 }
12108 rotate_info.x2=rotate_info.x1;
12109 rotate_info.y2=rotate_info.y1;
12110 if (direction == HorizontalRotateCommand)
12111 rotate_info.x2+=32;
12112 else
12113 rotate_info.y2-=32;
12114 } while ((state & ExitState) == 0);
12115 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12116 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12117 if ((state & EscapeState) != 0)
12118 return(MagickTrue);
12119 /*
12120 Draw line as pointer moves until the mouse button is released.
12121 */
12122 distance=0;
12123 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12124 state=DefaultState;
12125 do
12126 {
12127 if (distance > 9)
12128 {
12129 /*
12130 Display info and draw rotation line.
12131 */
12132 if (windows->info.mapped == MagickFalse)
12133 (void) XMapWindow(display,windows->info.id);
cristye7f51092010-01-17 00:39:37 +000012134 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012135 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12136 XInfoWidget(display,windows,text);
12137 XHighlightLine(display,windows->image.id,
12138 windows->image.highlight_context,&rotate_info);
12139 }
12140 else
12141 if (windows->info.mapped != MagickFalse)
12142 (void) XWithdrawWindow(display,windows->info.id,
12143 windows->info.screen);
12144 /*
12145 Wait for next event.
12146 */
12147 XScreenEvent(display,windows,&event);
12148 if (distance > 9)
12149 XHighlightLine(display,windows->image.id,
12150 windows->image.highlight_context,&rotate_info);
12151 switch (event.type)
12152 {
12153 case ButtonPress:
12154 break;
12155 case ButtonRelease:
12156 {
12157 /*
12158 User has committed to rotation line.
12159 */
12160 rotate_info.x2=event.xbutton.x;
12161 rotate_info.y2=event.xbutton.y;
12162 state|=ExitState;
12163 break;
12164 }
12165 case Expose:
12166 break;
12167 case MotionNotify:
12168 {
12169 rotate_info.x2=event.xmotion.x;
12170 rotate_info.y2=event.xmotion.y;
12171 }
12172 default:
12173 break;
12174 }
12175 /*
12176 Check boundary conditions.
12177 */
12178 if (rotate_info.x2 < 0)
12179 rotate_info.x2=0;
12180 else
12181 if (rotate_info.x2 > (int) windows->image.width)
12182 rotate_info.x2=(short) windows->image.width;
12183 if (rotate_info.y2 < 0)
12184 rotate_info.y2=0;
12185 else
12186 if (rotate_info.y2 > (int) windows->image.height)
12187 rotate_info.y2=(short) windows->image.height;
12188 /*
12189 Compute rotation angle from the slope of the line.
12190 */
12191 degrees=0.0;
12192 distance=(unsigned int)
12193 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12194 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12195 if (distance > 9)
12196 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12197 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12198 } while ((state & ExitState) == 0);
12199 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12200 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12201 if (distance <= 9)
12202 return(MagickTrue);
12203 }
12204 if (direction == VerticalRotateCommand)
12205 degrees-=90.0;
12206 if (degrees == 0.0)
12207 return(MagickTrue);
12208 /*
12209 Rotate image.
12210 */
12211 normalized_degrees=degrees;
12212 while (normalized_degrees < -45.0)
12213 normalized_degrees+=360.0;
12214 for (rotations=0; normalized_degrees > 45.0; rotations++)
12215 normalized_degrees-=90.0;
12216 if (normalized_degrees != 0.0)
12217 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12218 XSetCursorState(display,windows,MagickTrue);
12219 XCheckRefreshWindows(display,windows);
12220 (*image)->background_color.red=ScaleShortToQuantum(
12221 windows->pixel_info->pen_colors[pen_id].red);
12222 (*image)->background_color.green=ScaleShortToQuantum(
12223 windows->pixel_info->pen_colors[pen_id].green);
12224 (*image)->background_color.blue=ScaleShortToQuantum(
12225 windows->pixel_info->pen_colors[pen_id].blue);
12226 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12227 XSetCursorState(display,windows,MagickFalse);
12228 if (rotate_image == (Image *) NULL)
12229 return(MagickFalse);
12230 *image=DestroyImage(*image);
12231 *image=rotate_image;
12232 if (windows->image.crop_geometry != (char *) NULL)
12233 {
12234 /*
12235 Rotate crop geometry.
12236 */
12237 width=(unsigned int) (*image)->columns;
12238 height=(unsigned int) (*image)->rows;
12239 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12240 switch (rotations % 4)
12241 {
12242 default:
12243 case 0:
12244 break;
12245 case 1:
12246 {
12247 /*
12248 Rotate 90 degrees.
12249 */
12250 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12251 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12252 (int) height-y,x);
12253 break;
12254 }
12255 case 2:
12256 {
12257 /*
12258 Rotate 180 degrees.
12259 */
12260 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12261 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12262 break;
12263 }
12264 case 3:
12265 {
12266 /*
12267 Rotate 270 degrees.
12268 */
12269 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12270 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12271 break;
12272 }
12273 }
12274 }
12275 if (windows->image.orphan != MagickFalse)
12276 return(MagickTrue);
12277 if (normalized_degrees != 0.0)
12278 {
12279 /*
12280 Update image colormap.
12281 */
12282 windows->image.window_changes.width=(int) (*image)->columns;
12283 windows->image.window_changes.height=(int) (*image)->rows;
12284 if (windows->image.crop_geometry != (char *) NULL)
12285 {
12286 /*
12287 Obtain dimensions of image from crop geometry.
12288 */
12289 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12290 &width,&height);
12291 windows->image.window_changes.width=(int) width;
12292 windows->image.window_changes.height=(int) height;
12293 }
12294 XConfigureImageColormap(display,resource_info,windows,*image);
12295 }
12296 else
12297 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12298 {
12299 windows->image.window_changes.width=windows->image.ximage->height;
12300 windows->image.window_changes.height=windows->image.ximage->width;
12301 }
12302 /*
12303 Update image configuration.
12304 */
12305 (void) XConfigureImage(display,resource_info,windows,*image);
12306 return(MagickTrue);
12307}
12308
12309/*
12310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12311% %
12312% %
12313% %
12314+ X S a v e I m a g e %
12315% %
12316% %
12317% %
12318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12319%
12320% XSaveImage() saves an image to a file.
12321%
12322% The format of the XSaveImage method is:
12323%
12324% MagickBooleanType XSaveImage(Display *display,
12325% XResourceInfo *resource_info,XWindows *windows,Image *image)
12326%
12327% A description of each parameter follows:
12328%
12329% o display: Specifies a connection to an X server; returned from
12330% XOpenDisplay.
12331%
12332% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12333%
12334% o windows: Specifies a pointer to a XWindows structure.
12335%
12336% o image: the image.
12337%
12338*/
12339static MagickBooleanType XSaveImage(Display *display,
12340 XResourceInfo *resource_info,XWindows *windows,Image *image)
12341{
12342 char
12343 filename[MaxTextExtent],
12344 geometry[MaxTextExtent];
12345
12346 Image
12347 *save_image;
12348
12349 ImageInfo
12350 *image_info;
12351
12352 MagickStatusType
12353 status;
12354
12355 /*
12356 Request file name from user.
12357 */
12358 if (resource_info->write_filename != (char *) NULL)
12359 (void) CopyMagickString(filename,resource_info->write_filename,
12360 MaxTextExtent);
12361 else
12362 {
12363 char
12364 path[MaxTextExtent];
12365
12366 int
12367 status;
12368
12369 GetPathComponent(image->filename,HeadPath,path);
12370 GetPathComponent(image->filename,TailPath,filename);
12371 status=chdir(path);
12372 if (status == -1)
12373 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12374 FileOpenError,"UnableToOpenFile","%s",path);
12375 }
12376 XFileBrowserWidget(display,windows,"Save",filename);
12377 if (*filename == '\0')
12378 return(MagickTrue);
12379 if (IsPathAccessible(filename) != MagickFalse)
12380 {
12381 int
12382 status;
12383
12384 /*
12385 File exists-- seek user's permission before overwriting.
12386 */
12387 status=XConfirmWidget(display,windows,"Overwrite",filename);
12388 if (status <= 0)
12389 return(MagickTrue);
12390 }
12391 image_info=CloneImageInfo(resource_info->image_info);
12392 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +000012393 (void) SetImageInfo(image_info,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +000012394 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12395 (LocaleCompare(image_info->magick,"JPG") == 0))
12396 {
12397 char
12398 quality[MaxTextExtent];
12399
12400 int
12401 status;
12402
12403 /*
12404 Request JPEG quality from user.
12405 */
cristye8c25f92010-06-03 00:53:06 +000012406 (void) FormatMagickString(quality,MaxTextExtent,"%.20g",(double)
cristyf2faecf2010-05-28 19:19:36 +000012407 image->quality);
cristy3ed852e2009-09-05 21:47:34 +000012408 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12409 quality);
12410 if (*quality == '\0')
12411 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012412 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012413 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12414 }
12415 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12416 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12417 (LocaleCompare(image_info->magick,"PS") == 0) ||
12418 (LocaleCompare(image_info->magick,"PS2") == 0))
12419 {
12420 char
12421 geometry[MaxTextExtent];
12422
12423 /*
12424 Request page geometry from user.
12425 */
cristyb93d9e72009-09-12 20:02:21 +000012426 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012427 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristyb93d9e72009-09-12 20:02:21 +000012428 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012429 if (image_info->page != (char *) NULL)
12430 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12431 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12432 "Select page geometry:",geometry);
12433 if (*geometry != '\0')
12434 image_info->page=GetPageGeometry(geometry);
12435 }
12436 /*
12437 Apply image transforms.
12438 */
12439 XSetCursorState(display,windows,MagickTrue);
12440 XCheckRefreshWindows(display,windows);
12441 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12442 if (save_image == (Image *) NULL)
12443 return(MagickFalse);
12444 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
12445 windows->image.ximage->width,windows->image.ximage->height);
12446 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12447 /*
12448 Write image.
12449 */
12450 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12451 status=WriteImage(image_info,save_image);
12452 if (status != MagickFalse)
12453 image->taint=MagickFalse;
12454 save_image=DestroyImage(save_image);
12455 image_info=DestroyImageInfo(image_info);
12456 XSetCursorState(display,windows,MagickFalse);
12457 return(status != 0 ? MagickTrue : MagickFalse);
12458}
12459
12460/*
12461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12462% %
12463% %
12464% %
12465+ X S c r e e n E v e n t %
12466% %
12467% %
12468% %
12469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12470%
12471% XScreenEvent() handles global events associated with the Pan and Magnify
12472% windows.
12473%
12474% The format of the XScreenEvent function is:
12475%
12476% void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12477%
12478% A description of each parameter follows:
12479%
12480% o display: Specifies a pointer to the Display structure; returned from
12481% XOpenDisplay.
12482%
12483% o windows: Specifies a pointer to a XWindows structure.
12484%
12485% o event: Specifies a pointer to a X11 XEvent structure.
12486%
12487%
12488*/
12489
12490#if defined(__cplusplus) || defined(c_plusplus)
12491extern "C" {
12492#endif
12493
12494static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12495{
12496 register XWindows
12497 *windows;
12498
12499 windows=(XWindows *) data;
12500 if ((event->type == ClientMessage) &&
12501 (event->xclient.window == windows->image.id))
12502 return(MagickFalse);
12503 return(MagickTrue);
12504}
12505
12506#if defined(__cplusplus) || defined(c_plusplus)
12507}
12508#endif
12509
12510static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12511{
12512 register int
12513 x,
12514 y;
12515
12516 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12517 if (event->xany.window == windows->command.id)
12518 return;
12519 switch (event->type)
12520 {
12521 case ButtonPress:
12522 case ButtonRelease:
12523 {
12524 if ((event->xbutton.button == Button3) &&
12525 (event->xbutton.state & Mod1Mask))
12526 {
12527 /*
12528 Convert Alt-Button3 to Button2.
12529 */
12530 event->xbutton.button=Button2;
12531 event->xbutton.state&=(~Mod1Mask);
12532 }
12533 if (event->xbutton.window == windows->backdrop.id)
12534 {
12535 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12536 event->xbutton.time);
12537 break;
12538 }
12539 if (event->xbutton.window == windows->pan.id)
12540 {
12541 XPanImage(display,windows,event);
12542 break;
12543 }
12544 if (event->xbutton.window == windows->image.id)
12545 if (event->xbutton.button == Button2)
12546 {
12547 /*
12548 Update magnified image.
12549 */
12550 x=event->xbutton.x;
12551 y=event->xbutton.y;
12552 if (x < 0)
12553 x=0;
12554 else
12555 if (x >= (int) windows->image.width)
12556 x=(int) (windows->image.width-1);
12557 windows->magnify.x=windows->image.x+x;
12558 if (y < 0)
12559 y=0;
12560 else
12561 if (y >= (int) windows->image.height)
12562 y=(int) (windows->image.height-1);
12563 windows->magnify.y=windows->image.y+y;
12564 if (windows->magnify.mapped == MagickFalse)
12565 (void) XMapRaised(display,windows->magnify.id);
12566 XMakeMagnifyImage(display,windows);
12567 if (event->type == ButtonRelease)
12568 (void) XWithdrawWindow(display,windows->info.id,
12569 windows->info.screen);
12570 break;
12571 }
12572 break;
12573 }
12574 case ClientMessage:
12575 {
12576 /*
12577 If client window delete message, exit.
12578 */
12579 if (event->xclient.message_type != windows->wm_protocols)
12580 break;
cristyecd0ab52010-05-30 14:59:20 +000012581 if (*event->xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000012582 break;
12583 if (event->xclient.window == windows->magnify.id)
12584 {
12585 (void) XWithdrawWindow(display,windows->magnify.id,
12586 windows->magnify.screen);
12587 break;
12588 }
12589 break;
12590 }
12591 case ConfigureNotify:
12592 {
12593 if (event->xconfigure.window == windows->magnify.id)
12594 {
12595 unsigned int
12596 magnify;
12597
12598 /*
12599 Magnify window has a new configuration.
12600 */
12601 windows->magnify.width=(unsigned int) event->xconfigure.width;
12602 windows->magnify.height=(unsigned int) event->xconfigure.height;
12603 if (windows->magnify.mapped == MagickFalse)
12604 break;
12605 magnify=1;
12606 while ((int) magnify <= event->xconfigure.width)
12607 magnify<<=1;
12608 while ((int) magnify <= event->xconfigure.height)
12609 magnify<<=1;
12610 magnify>>=1;
12611 if (((int) magnify != event->xconfigure.width) ||
12612 ((int) magnify != event->xconfigure.height))
12613 {
12614 XWindowChanges
12615 window_changes;
12616
12617 window_changes.width=(int) magnify;
12618 window_changes.height=(int) magnify;
12619 (void) XReconfigureWMWindow(display,windows->magnify.id,
12620 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12621 &window_changes);
12622 break;
12623 }
12624 XMakeMagnifyImage(display,windows);
12625 break;
12626 }
12627 break;
12628 }
12629 case Expose:
12630 {
12631 if (event->xexpose.window == windows->image.id)
12632 {
12633 XRefreshWindow(display,&windows->image,event);
12634 break;
12635 }
12636 if (event->xexpose.window == windows->pan.id)
12637 if (event->xexpose.count == 0)
12638 {
12639 XDrawPanRectangle(display,windows);
12640 break;
12641 }
12642 if (event->xexpose.window == windows->magnify.id)
12643 if (event->xexpose.count == 0)
12644 {
12645 XMakeMagnifyImage(display,windows);
12646 break;
12647 }
12648 break;
12649 }
12650 case KeyPress:
12651 {
12652 char
12653 command[MaxTextExtent];
12654
12655 KeySym
12656 key_symbol;
12657
12658 if (event->xkey.window != windows->magnify.id)
12659 break;
12660 /*
12661 Respond to a user key press.
12662 */
12663 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12664 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12665 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12666 break;
12667 }
12668 case MapNotify:
12669 {
12670 if (event->xmap.window == windows->magnify.id)
12671 {
12672 windows->magnify.mapped=MagickTrue;
12673 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12674 break;
12675 }
12676 if (event->xmap.window == windows->info.id)
12677 {
12678 windows->info.mapped=MagickTrue;
12679 break;
12680 }
12681 break;
12682 }
12683 case MotionNotify:
12684 {
12685 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12686 if (event->xmotion.window == windows->image.id)
12687 if (windows->magnify.mapped != MagickFalse)
12688 {
12689 /*
12690 Update magnified image.
12691 */
12692 x=event->xmotion.x;
12693 y=event->xmotion.y;
12694 if (x < 0)
12695 x=0;
12696 else
12697 if (x >= (int) windows->image.width)
12698 x=(int) (windows->image.width-1);
12699 windows->magnify.x=windows->image.x+x;
12700 if (y < 0)
12701 y=0;
12702 else
12703 if (y >= (int) windows->image.height)
12704 y=(int) (windows->image.height-1);
12705 windows->magnify.y=windows->image.y+y;
12706 XMakeMagnifyImage(display,windows);
12707 }
12708 break;
12709 }
12710 case UnmapNotify:
12711 {
12712 if (event->xunmap.window == windows->magnify.id)
12713 {
12714 windows->magnify.mapped=MagickFalse;
12715 break;
12716 }
12717 if (event->xunmap.window == windows->info.id)
12718 {
12719 windows->info.mapped=MagickFalse;
12720 break;
12721 }
12722 break;
12723 }
12724 default:
12725 break;
12726 }
12727}
12728
12729/*
12730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12731% %
12732% %
12733% %
12734+ X S e t C r o p G e o m e t r y %
12735% %
12736% %
12737% %
12738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12739%
12740% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12741% and translates it to a cropping geometry relative to the image.
12742%
12743% The format of the XSetCropGeometry method is:
12744%
12745% void XSetCropGeometry(Display *display,XWindows *windows,
12746% RectangleInfo *crop_info,Image *image)
12747%
12748% A description of each parameter follows:
12749%
12750% o display: Specifies a connection to an X server; returned from
12751% XOpenDisplay.
12752%
12753% o windows: Specifies a pointer to a XWindows structure.
12754%
12755% o crop_info: A pointer to a RectangleInfo that defines a region of the
12756% Image window to crop.
12757%
12758% o image: the image.
12759%
12760*/
12761static void XSetCropGeometry(Display *display,XWindows *windows,
12762 RectangleInfo *crop_info,Image *image)
12763{
12764 char
12765 text[MaxTextExtent];
12766
12767 int
12768 x,
12769 y;
12770
12771 MagickRealType
12772 scale_factor;
12773
12774 unsigned int
12775 height,
12776 width;
12777
12778 if (windows->info.mapped != MagickFalse)
12779 {
12780 /*
12781 Display info on cropping rectangle.
12782 */
cristy6d8abba2010-06-03 01:10:47 +000012783 (void) FormatMagickString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
cristye8c25f92010-06-03 00:53:06 +000012784 (double) crop_info->width,(double) crop_info->height,(double)
12785 crop_info->x,(double) crop_info->y);
cristy3ed852e2009-09-05 21:47:34 +000012786 XInfoWidget(display,windows,text);
12787 }
12788 /*
12789 Cropping geometry is relative to any previous crop geometry.
12790 */
12791 x=0;
12792 y=0;
12793 width=(unsigned int) image->columns;
12794 height=(unsigned int) image->rows;
12795 if (windows->image.crop_geometry != (char *) NULL)
12796 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12797 else
12798 windows->image.crop_geometry=AcquireString((char *) NULL);
12799 /*
12800 Define the crop geometry string from the cropping rectangle.
12801 */
12802 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12803 if (crop_info->x > 0)
12804 x+=(int) (scale_factor*crop_info->x+0.5);
12805 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12806 if (width == 0)
12807 width=1;
12808 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12809 if (crop_info->y > 0)
12810 y+=(int) (scale_factor*crop_info->y+0.5);
12811 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12812 if (height == 0)
12813 height=1;
12814 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12815 "%ux%u%+d%+d",width,height,x,y);
12816}
12817
12818/*
12819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12820% %
12821% %
12822% %
12823+ X T i l e I m a g e %
12824% %
12825% %
12826% %
12827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12828%
12829% XTileImage() loads or deletes a selected tile from a visual image directory.
12830% The load or delete command is chosen from a menu.
12831%
12832% The format of the XTileImage method is:
12833%
12834% Image *XTileImage(Display *display,XResourceInfo *resource_info,
12835% XWindows *windows,Image *image,XEvent *event)
12836%
12837% A description of each parameter follows:
12838%
12839% o tile_image: XTileImage reads or deletes the tile image
12840% and returns it. A null image is returned if an error occurs.
12841%
12842% o display: Specifies a connection to an X server; returned from
12843% XOpenDisplay.
12844%
12845% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12846%
12847% o windows: Specifies a pointer to a XWindows structure.
12848%
12849% o image: the image; returned from ReadImage.
12850%
12851% o event: Specifies a pointer to a XEvent structure. If it is NULL,
12852% the entire image is refreshed.
12853%
12854*/
12855static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12856 XWindows *windows,Image *image,XEvent *event)
12857{
12858 static const char
12859 *VerbMenu[] =
12860 {
12861 "Load",
12862 "Next",
12863 "Former",
12864 "Delete",
12865 "Update",
12866 (char *) NULL,
12867 };
12868
12869 static const ModeType
12870 TileCommands[] =
12871 {
12872 TileLoadCommand,
12873 TileNextCommand,
12874 TileFormerCommand,
12875 TileDeleteCommand,
12876 TileUpdateCommand
12877 };
12878
12879 char
12880 command[MaxTextExtent],
12881 filename[MaxTextExtent];
12882
12883 Image
12884 *tile_image;
12885
12886 int
12887 id,
12888 status,
12889 tile,
12890 x,
12891 y;
12892
12893 MagickRealType
12894 scale_factor;
12895
12896 register char
12897 *p,
12898 *q;
12899
12900 register int
12901 i;
12902
12903 unsigned int
12904 height,
12905 width;
12906
12907 /*
12908 Tile image is relative to montage image configuration.
12909 */
12910 x=0;
12911 y=0;
12912 width=(unsigned int) image->columns;
12913 height=(unsigned int) image->rows;
12914 if (windows->image.crop_geometry != (char *) NULL)
12915 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12916 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12917 event->xbutton.x+=windows->image.x;
12918 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12919 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12920 event->xbutton.y+=windows->image.y;
12921 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12922 /*
12923 Determine size and location of each tile in the visual image directory.
12924 */
12925 width=(unsigned int) image->columns;
12926 height=(unsigned int) image->rows;
12927 x=0;
12928 y=0;
12929 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
12930 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
12931 (event->xbutton.x-x)/width;
12932 if (tile < 0)
12933 {
12934 /*
12935 Button press is outside any tile.
12936 */
12937 (void) XBell(display,0);
12938 return((Image *) NULL);
12939 }
12940 /*
12941 Determine file name from the tile directory.
12942 */
12943 p=image->directory;
12944 for (i=tile; (i != 0) && (*p != '\0'); )
12945 {
12946 if (*p == '\n')
12947 i--;
12948 p++;
12949 }
12950 if (*p == '\0')
12951 {
12952 /*
12953 Button press is outside any tile.
12954 */
12955 (void) XBell(display,0);
12956 return((Image *) NULL);
12957 }
12958 /*
12959 Select a command from the pop-up menu.
12960 */
12961 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
12962 if (id < 0)
12963 return((Image *) NULL);
12964 q=p;
12965 while ((*q != '\n') && (*q != '\0'))
12966 q++;
12967 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
12968 /*
12969 Perform command for the selected tile.
12970 */
12971 XSetCursorState(display,windows,MagickTrue);
12972 XCheckRefreshWindows(display,windows);
12973 tile_image=NewImageList();
12974 switch (TileCommands[id])
12975 {
12976 case TileLoadCommand:
12977 {
12978 /*
12979 Load tile image.
12980 */
12981 XCheckRefreshWindows(display,windows);
12982 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
12983 MaxTextExtent);
12984 (void) CopyMagickString(resource_info->image_info->filename,filename,
12985 MaxTextExtent);
12986 tile_image=ReadImage(resource_info->image_info,&image->exception);
12987 CatchException(&image->exception);
12988 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12989 break;
12990 }
12991 case TileNextCommand:
12992 {
12993 /*
12994 Display next image.
12995 */
12996 XClientMessage(display,windows->image.id,windows->im_protocols,
12997 windows->im_next_image,CurrentTime);
12998 break;
12999 }
13000 case TileFormerCommand:
13001 {
13002 /*
13003 Display former image.
13004 */
13005 XClientMessage(display,windows->image.id,windows->im_protocols,
13006 windows->im_former_image,CurrentTime);
13007 break;
13008 }
13009 case TileDeleteCommand:
13010 {
13011 /*
13012 Delete tile image.
13013 */
13014 if (IsPathAccessible(filename) == MagickFalse)
13015 {
13016 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13017 break;
13018 }
13019 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13020 if (status <= 0)
13021 break;
13022 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13023 if (status != MagickFalse)
13024 {
13025 XNoticeWidget(display,windows,"Unable to delete image file:",
13026 filename);
13027 break;
13028 }
13029 }
13030 case TileUpdateCommand:
13031 {
13032 ExceptionInfo
13033 *exception;
13034
13035 int
13036 x_offset,
13037 y_offset;
13038
13039 PixelPacket
13040 pixel;
13041
13042 register int
13043 j;
13044
13045 register PixelPacket
13046 *s;
13047
13048 /*
13049 Ensure all the images exist.
13050 */
13051 tile=0;
13052 for (p=image->directory; *p != '\0'; p++)
13053 {
13054 q=p;
13055 while ((*q != '\n') && (*q != '\0'))
13056 q++;
13057 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13058 p=q;
13059 if (IsPathAccessible(filename) != MagickFalse)
13060 {
13061 tile++;
13062 continue;
13063 }
13064 /*
13065 Overwrite tile with background color.
13066 */
13067 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13068 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13069 exception=(&image->exception);
13070 (void) GetOneVirtualPixel(image,0,0,&pixel,exception);
13071 for (i=0; i < (int) height; i++)
13072 {
13073 s=GetAuthenticPixels(image,x_offset,y_offset+i,width,1,exception);
13074 if (s == (PixelPacket *) NULL)
13075 break;
13076 for (j=0; j < (int) width; j++)
13077 *s++=pixel;
13078 if (SyncAuthenticPixels(image,exception) == MagickFalse)
13079 break;
13080 }
13081 tile++;
13082 }
13083 windows->image.window_changes.width=(int) image->columns;
13084 windows->image.window_changes.height=(int) image->rows;
13085 XConfigureImageColormap(display,resource_info,windows,image);
13086 (void) XConfigureImage(display,resource_info,windows,image);
13087 break;
13088 }
13089 default:
13090 break;
13091 }
13092 XSetCursorState(display,windows,MagickFalse);
13093 return(tile_image);
13094}
13095
13096/*
13097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13098% %
13099% %
13100% %
13101+ X T r a n s l a t e I m a g e %
13102% %
13103% %
13104% %
13105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13106%
13107% XTranslateImage() translates the image within an Image window by one pixel
13108% as specified by the key symbol. If the image has a `montage string the
13109% translation is respect to the width and height contained within the string.
13110%
13111% The format of the XTranslateImage method is:
13112%
13113% void XTranslateImage(Display *display,XWindows *windows,
13114% Image *image,const KeySym key_symbol)
13115%
13116% A description of each parameter follows:
13117%
13118% o display: Specifies a connection to an X server; returned from
13119% XOpenDisplay.
13120%
13121% o windows: Specifies a pointer to a XWindows structure.
13122%
13123% o image: the image.
13124%
13125% o key_symbol: Specifies a KeySym which indicates which side of the image
13126% to trim.
13127%
13128*/
13129static void XTranslateImage(Display *display,XWindows *windows,
13130 Image *image,const KeySym key_symbol)
13131{
13132 char
13133 text[MaxTextExtent];
13134
13135 int
13136 x,
13137 y;
13138
13139 unsigned int
13140 x_offset,
13141 y_offset;
13142
13143 /*
13144 User specified a pan position offset.
13145 */
13146 x_offset=windows->image.width;
13147 y_offset=windows->image.height;
13148 if (image->montage != (char *) NULL)
13149 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13150 switch ((int) key_symbol)
13151 {
13152 case XK_Home:
13153 case XK_KP_Home:
13154 {
13155 windows->image.x=(int) windows->image.width/2;
13156 windows->image.y=(int) windows->image.height/2;
13157 break;
13158 }
13159 case XK_Left:
13160 case XK_KP_Left:
13161 {
13162 windows->image.x-=x_offset;
13163 break;
13164 }
13165 case XK_Next:
13166 case XK_Up:
13167 case XK_KP_Up:
13168 {
13169 windows->image.y-=y_offset;
13170 break;
13171 }
13172 case XK_Right:
13173 case XK_KP_Right:
13174 {
13175 windows->image.x+=x_offset;
13176 break;
13177 }
13178 case XK_Prior:
13179 case XK_Down:
13180 case XK_KP_Down:
13181 {
13182 windows->image.y+=y_offset;
13183 break;
13184 }
13185 default:
13186 return;
13187 }
13188 /*
13189 Check boundary conditions.
13190 */
13191 if (windows->image.x < 0)
13192 windows->image.x=0;
13193 else
13194 if ((int) (windows->image.x+windows->image.width) >
13195 windows->image.ximage->width)
13196 windows->image.x=windows->image.ximage->width-windows->image.width;
13197 if (windows->image.y < 0)
13198 windows->image.y=0;
13199 else
13200 if ((int) (windows->image.y+windows->image.height) >
13201 windows->image.ximage->height)
13202 windows->image.y=windows->image.ximage->height-windows->image.height;
13203 /*
13204 Refresh Image window.
13205 */
13206 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
13207 windows->image.width,windows->image.height,windows->image.x,
13208 windows->image.y);
13209 XInfoWidget(display,windows,text);
13210 XCheckRefreshWindows(display,windows);
13211 XDrawPanRectangle(display,windows);
13212 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13213 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13214}
13215
13216/*
13217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13218% %
13219% %
13220% %
13221+ X T r i m I m a g e %
13222% %
13223% %
13224% %
13225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13226%
13227% XTrimImage() trims the edges from the Image window.
13228%
13229% The format of the XTrimImage method is:
13230%
13231% MagickBooleanType XTrimImage(Display *display,
13232% XResourceInfo *resource_info,XWindows *windows,Image *image)
13233%
13234% A description of each parameter follows:
13235%
13236% o display: Specifies a connection to an X server; returned from
13237% XOpenDisplay.
13238%
13239% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13240%
13241% o windows: Specifies a pointer to a XWindows structure.
13242%
13243% o image: the image.
13244%
13245*/
13246static MagickBooleanType XTrimImage(Display *display,
13247 XResourceInfo *resource_info,XWindows *windows,Image *image)
13248{
13249 RectangleInfo
13250 trim_info;
13251
13252 register int
13253 x,
13254 y;
13255
cristybb503372010-05-27 20:51:26 +000013256 size_t
cristy3ed852e2009-09-05 21:47:34 +000013257 background,
13258 pixel;
13259
13260 /*
13261 Trim edges from image.
13262 */
13263 XSetCursorState(display,windows,MagickTrue);
13264 XCheckRefreshWindows(display,windows);
13265 /*
13266 Crop the left edge.
13267 */
13268 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013269 trim_info.width=(size_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013270 for (x=0; x < windows->image.ximage->width; x++)
13271 {
13272 for (y=0; y < windows->image.ximage->height; y++)
13273 {
13274 pixel=XGetPixel(windows->image.ximage,x,y);
13275 if (pixel != background)
13276 break;
13277 }
13278 if (y < windows->image.ximage->height)
13279 break;
13280 }
13281 trim_info.x=x;
13282 if (trim_info.x == (int) windows->image.ximage->width)
13283 {
13284 XSetCursorState(display,windows,MagickFalse);
13285 return(MagickFalse);
13286 }
13287 /*
13288 Crop the right edge.
13289 */
13290 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13291 for (x=windows->image.ximage->width-1; x != 0; x--)
13292 {
13293 for (y=0; y < windows->image.ximage->height; y++)
13294 {
13295 pixel=XGetPixel(windows->image.ximage,x,y);
13296 if (pixel != background)
13297 break;
13298 }
13299 if (y < windows->image.ximage->height)
13300 break;
13301 }
cristybb503372010-05-27 20:51:26 +000013302 trim_info.width=(size_t) (x-trim_info.x+1);
cristy3ed852e2009-09-05 21:47:34 +000013303 /*
13304 Crop the top edge.
13305 */
13306 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013307 trim_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013308 for (y=0; y < windows->image.ximage->height; y++)
13309 {
13310 for (x=0; x < windows->image.ximage->width; x++)
13311 {
13312 pixel=XGetPixel(windows->image.ximage,x,y);
13313 if (pixel != background)
13314 break;
13315 }
13316 if (x < windows->image.ximage->width)
13317 break;
13318 }
13319 trim_info.y=y;
13320 /*
13321 Crop the bottom edge.
13322 */
13323 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13324 for (y=windows->image.ximage->height-1; y != 0; y--)
13325 {
13326 for (x=0; x < windows->image.ximage->width; x++)
13327 {
13328 pixel=XGetPixel(windows->image.ximage,x,y);
13329 if (pixel != background)
13330 break;
13331 }
13332 if (x < windows->image.ximage->width)
13333 break;
13334 }
cristybb503372010-05-27 20:51:26 +000013335 trim_info.height=(size_t) y-trim_info.y+1;
cristy3ed852e2009-09-05 21:47:34 +000013336 if (((unsigned int) trim_info.width != windows->image.width) ||
13337 ((unsigned int) trim_info.height != windows->image.height))
13338 {
13339 /*
13340 Reconfigure Image window as defined by the trimming rectangle.
13341 */
13342 XSetCropGeometry(display,windows,&trim_info,image);
13343 windows->image.window_changes.width=(int) trim_info.width;
13344 windows->image.window_changes.height=(int) trim_info.height;
13345 (void) XConfigureImage(display,resource_info,windows,image);
13346 }
13347 XSetCursorState(display,windows,MagickFalse);
13348 return(MagickTrue);
13349}
13350
13351/*
13352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13353% %
13354% %
13355% %
13356+ X V i s u a l D i r e c t o r y I m a g e %
13357% %
13358% %
13359% %
13360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13361%
13362% XVisualDirectoryImage() creates a Visual Image Directory.
13363%
13364% The format of the XVisualDirectoryImage method is:
13365%
13366% Image *XVisualDirectoryImage(Display *display,
13367% XResourceInfo *resource_info,XWindows *windows)
13368%
13369% A description of each parameter follows:
13370%
13371% o nexus: Method XVisualDirectoryImage returns a visual image
13372% directory if it can be created successfully. Otherwise a null image
13373% is returned.
13374%
13375% o display: Specifies a connection to an X server; returned from
13376% XOpenDisplay.
13377%
13378% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13379%
13380% o windows: Specifies a pointer to a XWindows structure.
13381%
13382*/
13383static Image *XVisualDirectoryImage(Display *display,
13384 XResourceInfo *resource_info,XWindows *windows)
13385{
13386#define TileImageTag "Scale/Image"
13387#define XClientName "montage"
13388
13389 char
13390 **filelist;
13391
13392 ExceptionInfo
13393 *exception;
13394
13395 Image
13396 *images,
13397 *montage_image,
13398 *next_image,
13399 *thumbnail_image;
13400
13401 ImageInfo
13402 *read_info;
13403
13404 int
13405 number_files;
13406
13407 MagickBooleanType
13408 backdrop;
13409
13410 MagickStatusType
13411 status;
13412
13413 MontageInfo
13414 *montage_info;
13415
13416 RectangleInfo
13417 geometry;
13418
13419 register int
13420 i;
13421
13422 static char
13423 filename[MaxTextExtent] = "\0",
13424 filenames[MaxTextExtent] = "*";
13425
13426 XResourceInfo
13427 background_resources;
13428
13429 /*
13430 Request file name from user.
13431 */
13432 XFileBrowserWidget(display,windows,"Directory",filenames);
13433 if (*filenames == '\0')
13434 return((Image *) NULL);
13435 /*
13436 Expand the filenames.
13437 */
cristy90823212009-12-12 20:48:33 +000013438 filelist=(char **) AcquireAlignedMemory(1,sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013439 if (filelist == (char **) NULL)
13440 {
13441 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13442 filenames);
13443 return((Image *) NULL);
13444 }
13445 number_files=1;
13446 filelist[0]=filenames;
13447 status=ExpandFilenames(&number_files,&filelist);
13448 if ((status == MagickFalse) || (number_files == 0))
13449 {
13450 if (number_files == 0)
13451 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13452 else
13453 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13454 filenames);
13455 return((Image *) NULL);
13456 }
13457 /*
13458 Set image background resources.
13459 */
13460 background_resources=(*resource_info);
13461 background_resources.window_id=AcquireString("");
13462 (void) FormatMagickString(background_resources.window_id,MaxTextExtent,
13463 "0x%lx",windows->image.id);
13464 background_resources.backdrop=MagickTrue;
13465 /*
13466 Read each image and convert them to a tile.
13467 */
13468 backdrop=(windows->visual_info->klass == TrueColor) ||
13469 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13470 read_info=CloneImageInfo(resource_info->image_info);
13471 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13472 (void *) NULL);
13473 images=NewImageList();
13474 exception=AcquireExceptionInfo();
13475 XSetCursorState(display,windows,MagickTrue);
13476 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +000013477 for (i=0; i < (ssize_t) number_files; i++)
cristy3ed852e2009-09-05 21:47:34 +000013478 {
13479 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13480 filelist[i]=DestroyString(filelist[i]);
13481 *read_info->magick='\0';
13482 (void) CloneString(&read_info->size,DefaultTileGeometry);
13483 next_image=ReadImage(read_info,exception);
13484 CatchException(exception);
13485 if (next_image != (Image *) NULL)
13486 {
13487 (void) DeleteImageProperty(next_image,"label");
13488 (void) SetImageProperty(next_image,"label",DefaultTileLabel);
13489 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13490 exception);
13491 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13492 geometry.height,exception);
13493 if (thumbnail_image != (Image *) NULL)
13494 {
13495 next_image=DestroyImage(next_image);
13496 next_image=thumbnail_image;
13497 }
13498 if (backdrop)
13499 {
13500 (void) XDisplayBackgroundImage(display,&background_resources,
13501 next_image);
13502 XSetCursorState(display,windows,MagickTrue);
13503 }
13504 AppendImageToList(&images,next_image);
13505 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13506 {
13507 MagickBooleanType
13508 proceed;
13509
13510 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13511 (MagickSizeType) number_files);
13512 if (proceed == MagickFalse)
13513 break;
13514 }
13515 }
13516 }
13517 exception=DestroyExceptionInfo(exception);
13518 filelist=(char **) RelinquishMagickMemory(filelist);
13519 read_info=DestroyImageInfo(read_info);
13520 if (images == (Image *) NULL)
13521 {
13522 XSetCursorState(display,windows,MagickFalse);
13523 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13524 return((Image *) NULL);
13525 }
13526 /*
13527 Create the Visual Image Directory.
13528 */
13529 montage_info=CloneMontageInfo(resource_info->image_info,(MontageInfo *) NULL);
13530 if (resource_info->font != (char *) NULL)
13531 (void) CloneString(&montage_info->font,resource_info->font);
13532 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13533 montage_image=MontageImageList(resource_info->image_info,montage_info,
13534 GetFirstImageInList(images),&images->exception);
13535 montage_info=DestroyMontageInfo(montage_info);
13536 images=DestroyImageList(images);
13537 XSetCursorState(display,windows,MagickFalse);
13538 if (montage_image == (Image *) NULL)
13539 return(montage_image);
13540 XClientMessage(display,windows->image.id,windows->im_protocols,
13541 windows->im_next_image,CurrentTime);
13542 return(montage_image);
13543}
13544
13545/*
13546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13547% %
13548% %
13549% %
13550% X D i s p l a y B a c k g r o u n d I m a g e %
13551% %
13552% %
13553% %
13554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13555%
13556% XDisplayBackgroundImage() displays an image in the background of a window.
13557%
13558% The format of the XDisplayBackgroundImage method is:
13559%
13560% MagickBooleanType XDisplayBackgroundImage(Display *display,
13561% XResourceInfo *resource_info,Image *image)
13562%
13563% A description of each parameter follows:
13564%
13565% o display: Specifies a connection to an X server; returned from
13566% XOpenDisplay.
13567%
13568% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13569%
13570% o image: the image.
13571%
13572*/
13573MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13574 XResourceInfo *resource_info,Image *image)
13575{
13576 char
13577 geometry[MaxTextExtent],
13578 visual_type[MaxTextExtent];
13579
13580 int
13581 height,
13582 status,
13583 width;
13584
13585 RectangleInfo
13586 geometry_info;
13587
13588 static XPixelInfo
13589 pixel;
13590
13591 static XStandardColormap
13592 *map_info;
13593
13594 static XVisualInfo
13595 *visual_info = (XVisualInfo *) NULL;
13596
13597 static XWindowInfo
13598 window_info;
13599
cristybb503372010-05-27 20:51:26 +000013600 size_t
cristy3ed852e2009-09-05 21:47:34 +000013601 delay;
13602
13603 Window
13604 root_window;
13605
13606 XGCValues
13607 context_values;
13608
13609 XResourceInfo
13610 resources;
13611
13612 XWindowAttributes
13613 window_attributes;
13614
13615 /*
13616 Determine target window.
13617 */
13618 assert(image != (Image *) NULL);
13619 assert(image->signature == MagickSignature);
13620 if (image->debug != MagickFalse)
13621 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13622 resources=(*resource_info);
13623 window_info.id=(Window) NULL;
13624 root_window=XRootWindow(display,XDefaultScreen(display));
13625 if (LocaleCompare(resources.window_id,"root") == 0)
13626 window_info.id=root_window;
13627 else
13628 {
13629 if (isdigit((unsigned char) *resources.window_id) != 0)
13630 window_info.id=XWindowByID(display,root_window,
13631 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13632 if (window_info.id == (Window) NULL)
13633 window_info.id=XWindowByName(display,root_window,resources.window_id);
13634 }
13635 if (window_info.id == (Window) NULL)
13636 {
13637 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13638 resources.window_id);
13639 return(MagickFalse);
13640 }
13641 /*
13642 Determine window visual id.
13643 */
13644 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13645 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13646 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13647 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13648 if (status != 0)
13649 (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
13650 XVisualIDFromVisual(window_attributes.visual));
13651 if (visual_info == (XVisualInfo *) NULL)
13652 {
13653 /*
13654 Allocate standard colormap.
13655 */
13656 map_info=XAllocStandardColormap();
13657 if (map_info == (XStandardColormap *) NULL)
13658 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13659 image->filename);
13660 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +000013661 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000013662 /*
13663 Initialize visual info.
13664 */
13665 resources.map_type=(char *) NULL;
13666 resources.visual_type=visual_type;
13667 visual_info=XBestVisualInfo(display,map_info,&resources);
13668 if (visual_info == (XVisualInfo *) NULL)
13669 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13670 resources.visual_type);
13671 /*
13672 Initialize window info.
13673 */
13674 window_info.ximage=(XImage *) NULL;
13675 window_info.matte_image=(XImage *) NULL;
13676 window_info.pixmap=(Pixmap) NULL;
13677 window_info.matte_pixmap=(Pixmap) NULL;
13678 }
13679 /*
13680 Free previous root colors.
13681 */
13682 if (window_info.id == root_window)
13683 (void) XDestroyWindowColors(display,root_window);
13684 /*
13685 Initialize Standard Colormap.
13686 */
13687 resources.colormap=SharedColormap;
13688 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13689 /*
13690 Graphic context superclass.
13691 */
13692 context_values.background=pixel.background_color.pixel;
13693 context_values.foreground=pixel.foreground_color.pixel;
13694 pixel.annotate_context=XCreateGC(display,window_info.id,
cristybb503372010-05-27 20:51:26 +000013695 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000013696 if (pixel.annotate_context == (GC) NULL)
13697 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13698 image->filename);
13699 /*
13700 Initialize Image window attributes.
13701 */
13702 window_info.name=AcquireString("\0");
13703 window_info.icon_name=AcquireString("\0");
13704 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13705 &resources,&window_info);
13706 /*
13707 Create the X image.
13708 */
13709 window_info.width=(unsigned int) image->columns;
13710 window_info.height=(unsigned int) image->rows;
13711 if ((image->columns != window_info.width) ||
13712 (image->rows != window_info.height))
13713 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13714 image->filename);
13715 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
13716 window_attributes.width,window_attributes.height);
13717 geometry_info.width=window_info.width;
13718 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +000013719 geometry_info.x=(ssize_t) window_info.x;
13720 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +000013721 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13722 &geometry_info.width,&geometry_info.height);
13723 window_info.width=(unsigned int) geometry_info.width;
13724 window_info.height=(unsigned int) geometry_info.height;
13725 window_info.x=(int) geometry_info.x;
13726 window_info.y=(int) geometry_info.y;
13727 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13728 window_info.height);
13729 if (status == MagickFalse)
13730 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13731 image->filename);
13732 window_info.x=0;
13733 window_info.y=0;
13734 if (image->debug != MagickFalse)
13735 {
13736 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000013737 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13738 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +000013739 if (image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000013740 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13741 image->colors);
cristy3ed852e2009-09-05 21:47:34 +000013742 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13743 }
13744 /*
13745 Adjust image dimensions as specified by backdrop or geometry options.
13746 */
13747 width=(int) window_info.width;
13748 height=(int) window_info.height;
13749 if (resources.backdrop != MagickFalse)
13750 {
13751 /*
13752 Center image on window.
13753 */
13754 window_info.x=(window_attributes.width/2)-
13755 (window_info.ximage->width/2);
13756 window_info.y=(window_attributes.height/2)-
13757 (window_info.ximage->height/2);
13758 width=window_attributes.width;
13759 height=window_attributes.height;
13760 }
13761 if ((resources.image_geometry != (char *) NULL) &&
13762 (*resources.image_geometry != '\0'))
13763 {
13764 char
13765 default_geometry[MaxTextExtent];
13766
13767 int
13768 flags,
13769 gravity;
13770
13771 XSizeHints
13772 *size_hints;
13773
13774 /*
13775 User specified geometry.
13776 */
13777 size_hints=XAllocSizeHints();
13778 if (size_hints == (XSizeHints *) NULL)
13779 ThrowXWindowFatalException(ResourceLimitFatalError,
13780 "MemoryAllocationFailed",image->filename);
13781 size_hints->flags=0L;
13782 (void) FormatMagickString(default_geometry,MaxTextExtent,"%dx%d",
13783 width,height);
13784 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13785 default_geometry,window_info.border_width,size_hints,&window_info.x,
13786 &window_info.y,&width,&height,&gravity);
13787 if (flags & (XValue | YValue))
13788 {
13789 width=window_attributes.width;
13790 height=window_attributes.height;
13791 }
13792 (void) XFree((void *) size_hints);
13793 }
13794 /*
13795 Create the X pixmap.
13796 */
13797 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13798 (unsigned int) height,window_info.depth);
13799 if (window_info.pixmap == (Pixmap) NULL)
13800 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13801 image->filename);
13802 /*
13803 Display pixmap on the window.
13804 */
13805 if (((unsigned int) width > window_info.width) ||
13806 ((unsigned int) height > window_info.height))
13807 (void) XFillRectangle(display,window_info.pixmap,
13808 window_info.annotate_context,0,0,(unsigned int) width,
13809 (unsigned int) height);
13810 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13811 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13812 window_info.width,(unsigned int) window_info.height);
13813 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13814 (void) XClearWindow(display,window_info.id);
13815 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13816 XDelay(display,delay == 0UL ? 10UL : delay);
13817 (void) XSync(display,MagickFalse);
13818 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13819}
13820
13821/*
13822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13823% %
13824% %
13825% %
13826+ X D i s p l a y I m a g e %
13827% %
13828% %
13829% %
13830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13831%
13832% XDisplayImage() displays an image via X11. A new image is created and
13833% returned if the user interactively transforms the displayed image.
13834%
13835% The format of the XDisplayImage method is:
13836%
13837% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristybb503372010-05-27 20:51:26 +000013838% char **argv,int argc,Image **image,size_t *state)
cristy3ed852e2009-09-05 21:47:34 +000013839%
13840% A description of each parameter follows:
13841%
13842% o nexus: Method XDisplayImage returns an image when the
13843% user chooses 'Open Image' from the command menu or picks a tile
13844% from the image directory. Otherwise a null image is returned.
13845%
13846% o display: Specifies a connection to an X server; returned from
13847% XOpenDisplay.
13848%
13849% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13850%
13851% o argv: Specifies the application's argument list.
13852%
13853% o argc: Specifies the number of arguments.
13854%
13855% o image: Specifies an address to an address of an Image structure;
13856%
13857*/
13858MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristybb503372010-05-27 20:51:26 +000013859 char **argv,int argc,Image **image,size_t *state)
cristy3ed852e2009-09-05 21:47:34 +000013860{
13861#define MagnifySize 256 /* must be a power of 2 */
13862#define MagickMenus 10
13863#define MagickTitle "Commands"
13864
13865 static const char
13866 *CommandMenu[] =
13867 {
13868 "File",
13869 "Edit",
13870 "View",
13871 "Transform",
13872 "Enhance",
13873 "Effects",
13874 "F/X",
13875 "Image Edit",
13876 "Miscellany",
13877 "Help",
13878 (char *) NULL
13879 },
13880 *FileMenu[] =
13881 {
13882 "Open...",
13883 "Next",
13884 "Former",
13885 "Select...",
13886 "Save...",
13887 "Print...",
13888 "Delete...",
13889 "New...",
13890 "Visual Directory...",
13891 "Quit",
13892 (char *) NULL
13893 },
13894 *EditMenu[] =
13895 {
13896 "Undo",
13897 "Redo",
13898 "Cut",
13899 "Copy",
13900 "Paste",
13901 (char *) NULL
13902 },
13903 *ViewMenu[] =
13904 {
13905 "Half Size",
13906 "Original Size",
13907 "Double Size",
13908 "Resize...",
13909 "Apply",
13910 "Refresh",
13911 "Restore",
13912 (char *) NULL
13913 },
13914 *TransformMenu[] =
13915 {
13916 "Crop",
13917 "Chop",
13918 "Flop",
13919 "Flip",
13920 "Rotate Right",
13921 "Rotate Left",
13922 "Rotate...",
13923 "Shear...",
13924 "Roll...",
13925 "Trim Edges",
13926 (char *) NULL
13927 },
13928 *EnhanceMenu[] =
13929 {
13930 "Hue...",
13931 "Saturation...",
13932 "Brightness...",
13933 "Gamma...",
13934 "Spiff",
13935 "Dull",
13936 "Contrast Stretch...",
13937 "Sigmoidal Contrast...",
13938 "Normalize",
13939 "Equalize",
13940 "Negate",
13941 "Grayscale",
13942 "Map...",
13943 "Quantize...",
13944 (char *) NULL
13945 },
13946 *EffectsMenu[] =
13947 {
13948 "Despeckle",
13949 "Emboss",
13950 "Reduce Noise",
13951 "Add Noise...",
13952 "Sharpen...",
13953 "Blur...",
13954 "Threshold...",
13955 "Edge Detect...",
13956 "Spread...",
13957 "Shade...",
13958 "Raise...",
13959 "Segment...",
13960 (char *) NULL
13961 },
13962 *FXMenu[] =
13963 {
13964 "Solarize...",
13965 "Sepia Tone...",
13966 "Swirl...",
13967 "Implode...",
13968 "Vignette...",
13969 "Wave...",
13970 "Oil Paint...",
13971 "Charcoal Draw...",
13972 (char *) NULL
13973 },
13974 *ImageEditMenu[] =
13975 {
13976 "Annotate...",
13977 "Draw...",
13978 "Color...",
13979 "Matte...",
13980 "Composite...",
13981 "Add Border...",
13982 "Add Frame...",
13983 "Comment...",
13984 "Launch...",
13985 "Region of Interest...",
13986 (char *) NULL
13987 },
13988 *MiscellanyMenu[] =
13989 {
13990 "Image Info",
13991 "Zoom Image",
13992 "Show Preview...",
13993 "Show Histogram",
13994 "Show Matte",
13995 "Background...",
13996 "Slide Show...",
13997 "Preferences...",
13998 (char *) NULL
13999 },
14000 *HelpMenu[] =
14001 {
14002 "Overview",
14003 "Browse Documentation",
14004 "About Display",
14005 (char *) NULL
14006 },
14007 *ShortCutsMenu[] =
14008 {
14009 "Next",
14010 "Former",
14011 "Open...",
14012 "Save...",
14013 "Print...",
14014 "Undo",
14015 "Restore",
14016 "Image Info",
14017 "Quit",
14018 (char *) NULL
14019 },
14020 *VirtualMenu[] =
14021 {
14022 "Image Info",
14023 "Print",
14024 "Next",
14025 "Quit",
14026 (char *) NULL
14027 };
14028
14029 static const char
14030 **Menus[MagickMenus] =
14031 {
14032 FileMenu,
14033 EditMenu,
14034 ViewMenu,
14035 TransformMenu,
14036 EnhanceMenu,
14037 EffectsMenu,
14038 FXMenu,
14039 ImageEditMenu,
14040 MiscellanyMenu,
14041 HelpMenu
14042 };
14043
14044 static CommandType
14045 CommandMenus[] =
14046 {
14047 NullCommand,
14048 NullCommand,
14049 NullCommand,
14050 NullCommand,
14051 NullCommand,
14052 NullCommand,
14053 NullCommand,
14054 NullCommand,
14055 NullCommand,
14056 NullCommand,
14057 },
14058 FileCommands[] =
14059 {
14060 OpenCommand,
14061 NextCommand,
14062 FormerCommand,
14063 SelectCommand,
14064 SaveCommand,
14065 PrintCommand,
14066 DeleteCommand,
14067 NewCommand,
14068 VisualDirectoryCommand,
14069 QuitCommand
14070 },
14071 EditCommands[] =
14072 {
14073 UndoCommand,
14074 RedoCommand,
14075 CutCommand,
14076 CopyCommand,
14077 PasteCommand
14078 },
14079 ViewCommands[] =
14080 {
14081 HalfSizeCommand,
14082 OriginalSizeCommand,
14083 DoubleSizeCommand,
14084 ResizeCommand,
14085 ApplyCommand,
14086 RefreshCommand,
14087 RestoreCommand
14088 },
14089 TransformCommands[] =
14090 {
14091 CropCommand,
14092 ChopCommand,
14093 FlopCommand,
14094 FlipCommand,
14095 RotateRightCommand,
14096 RotateLeftCommand,
14097 RotateCommand,
14098 ShearCommand,
14099 RollCommand,
14100 TrimCommand
14101 },
14102 EnhanceCommands[] =
14103 {
14104 HueCommand,
14105 SaturationCommand,
14106 BrightnessCommand,
14107 GammaCommand,
14108 SpiffCommand,
14109 DullCommand,
14110 ContrastStretchCommand,
14111 SigmoidalContrastCommand,
14112 NormalizeCommand,
14113 EqualizeCommand,
14114 NegateCommand,
14115 GrayscaleCommand,
14116 MapCommand,
14117 QuantizeCommand
14118 },
14119 EffectsCommands[] =
14120 {
14121 DespeckleCommand,
14122 EmbossCommand,
14123 ReduceNoiseCommand,
14124 AddNoiseCommand,
14125 SharpenCommand,
14126 BlurCommand,
14127 ThresholdCommand,
14128 EdgeDetectCommand,
14129 SpreadCommand,
14130 ShadeCommand,
14131 RaiseCommand,
14132 SegmentCommand
14133 },
14134 FXCommands[] =
14135 {
14136 SolarizeCommand,
14137 SepiaToneCommand,
14138 SwirlCommand,
14139 ImplodeCommand,
14140 VignetteCommand,
14141 WaveCommand,
14142 OilPaintCommand,
14143 CharcoalDrawCommand
14144 },
14145 ImageEditCommands[] =
14146 {
14147 AnnotateCommand,
14148 DrawCommand,
14149 ColorCommand,
14150 MatteCommand,
14151 CompositeCommand,
14152 AddBorderCommand,
14153 AddFrameCommand,
14154 CommentCommand,
14155 LaunchCommand,
14156 RegionofInterestCommand
14157 },
14158 MiscellanyCommands[] =
14159 {
14160 InfoCommand,
14161 ZoomCommand,
14162 ShowPreviewCommand,
14163 ShowHistogramCommand,
14164 ShowMatteCommand,
14165 BackgroundCommand,
14166 SlideShowCommand,
14167 PreferencesCommand
14168 },
14169 HelpCommands[] =
14170 {
14171 HelpCommand,
14172 BrowseDocumentationCommand,
14173 VersionCommand
14174 },
14175 ShortCutsCommands[] =
14176 {
14177 NextCommand,
14178 FormerCommand,
14179 OpenCommand,
14180 SaveCommand,
14181 PrintCommand,
14182 UndoCommand,
14183 RestoreCommand,
14184 InfoCommand,
14185 QuitCommand
14186 },
14187 VirtualCommands[] =
14188 {
14189 InfoCommand,
14190 PrintCommand,
14191 NextCommand,
14192 QuitCommand
14193 };
14194
14195 static CommandType
14196 *Commands[MagickMenus] =
14197 {
14198 FileCommands,
14199 EditCommands,
14200 ViewCommands,
14201 TransformCommands,
14202 EnhanceCommands,
14203 EffectsCommands,
14204 FXCommands,
14205 ImageEditCommands,
14206 MiscellanyCommands,
14207 HelpCommands
14208 };
14209
14210 char
14211 command[MaxTextExtent],
14212 *cwd,
14213 geometry[MaxTextExtent],
14214 resource_name[MaxTextExtent];
14215
14216 CommandType
14217 command_type;
14218
14219 Image
14220 *display_image,
14221 *nexus;
14222
14223 int
14224 entry,
14225 id;
14226
14227 KeySym
14228 key_symbol;
14229
14230 MagickStatusType
14231 context_mask,
14232 status;
14233
14234 RectangleInfo
14235 geometry_info;
14236
14237 register int
14238 i;
14239
14240 static char
14241 working_directory[MaxTextExtent];
14242
14243 static XPoint
14244 vid_info;
14245
14246 static XWindowInfo
14247 *magick_windows[MaxXWindows];
14248
14249 static unsigned int
14250 number_windows;
14251
14252 struct stat
14253 attributes;
14254
14255 time_t
14256 timer,
14257 timestamp,
14258 update_time;
14259
14260 unsigned int
14261 height,
14262 width;
14263
cristybb503372010-05-27 20:51:26 +000014264 size_t
cristy3ed852e2009-09-05 21:47:34 +000014265 delay;
14266
14267 WarningHandler
14268 warning_handler;
14269
14270 Window
14271 root_window;
14272
14273 XClassHint
14274 *class_hints;
14275
14276 XEvent
14277 event;
14278
14279 XFontStruct
14280 *font_info;
14281
14282 XGCValues
14283 context_values;
14284
14285 XPixelInfo
14286 *icon_pixel,
14287 *pixel;
14288
14289 XResourceInfo
14290 *icon_resources;
14291
14292 XStandardColormap
14293 *icon_map,
14294 *map_info;
14295
14296 XVisualInfo
14297 *icon_visual,
14298 *visual_info;
14299
14300 XWindowChanges
14301 window_changes;
14302
14303 XWindows
14304 *windows;
14305
14306 XWMHints
14307 *manager_hints;
14308
14309 assert(image != (Image **) NULL);
14310 assert((*image)->signature == MagickSignature);
14311 if ((*image)->debug != MagickFalse)
14312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14313 display_image=(*image);
14314 warning_handler=(WarningHandler) NULL;
14315 windows=XSetWindows((XWindows *) ~0);
14316 if (windows != (XWindows *) NULL)
14317 {
14318 int
14319 status;
14320
14321 status=chdir(working_directory);
14322 if (status == -1)
14323 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14324 FileOpenError,"UnableToOpenFile","%s",working_directory);
14325 warning_handler=resource_info->display_warnings ?
14326 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14327 warning_handler=resource_info->display_warnings ?
14328 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14329 }
14330 else
14331 {
14332 /*
14333 Allocate windows structure.
14334 */
14335 resource_info->colors=display_image->colors;
14336 windows=XSetWindows(XInitializeWindows(display,resource_info));
14337 if (windows == (XWindows *) NULL)
14338 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14339 (*image)->filename);
14340 /*
14341 Initialize window id's.
14342 */
14343 number_windows=0;
14344 magick_windows[number_windows++]=(&windows->icon);
14345 magick_windows[number_windows++]=(&windows->backdrop);
14346 magick_windows[number_windows++]=(&windows->image);
14347 magick_windows[number_windows++]=(&windows->info);
14348 magick_windows[number_windows++]=(&windows->command);
14349 magick_windows[number_windows++]=(&windows->widget);
14350 magick_windows[number_windows++]=(&windows->popup);
14351 magick_windows[number_windows++]=(&windows->magnify);
14352 magick_windows[number_windows++]=(&windows->pan);
14353 for (i=0; i < (int) number_windows; i++)
14354 magick_windows[i]->id=(Window) NULL;
14355 vid_info.x=0;
14356 vid_info.y=0;
14357 }
14358 /*
14359 Initialize font info.
14360 */
14361 if (windows->font_info != (XFontStruct *) NULL)
14362 (void) XFreeFont(display,windows->font_info);
14363 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14364 if (windows->font_info == (XFontStruct *) NULL)
14365 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14366 resource_info->font);
14367 /*
14368 Initialize Standard Colormap.
14369 */
14370 map_info=windows->map_info;
14371 icon_map=windows->icon_map;
14372 visual_info=windows->visual_info;
14373 icon_visual=windows->icon_visual;
14374 pixel=windows->pixel_info;
14375 icon_pixel=windows->icon_pixel;
14376 font_info=windows->font_info;
14377 icon_resources=windows->icon_resources;
14378 class_hints=windows->class_hints;
14379 manager_hints=windows->manager_hints;
14380 root_window=XRootWindow(display,visual_info->screen);
14381 nexus=NewImageList();
14382 if (display_image->debug != MagickFalse)
14383 {
14384 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000014385 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14386 (double) display_image->scene,(double) display_image->columns,
14387 (double) display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +000014388 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000014389 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14390 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +000014391 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14392 display_image->magick);
14393 }
14394 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14395 map_info,pixel);
14396 display_image->taint=MagickFalse;
14397 /*
14398 Initialize graphic context.
14399 */
14400 windows->context.id=(Window) NULL;
14401 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14402 resource_info,&windows->context);
14403 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14404 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14405 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14406 manager_hints->flags=InputHint | StateHint;
14407 manager_hints->input=MagickFalse;
14408 manager_hints->initial_state=WithdrawnState;
14409 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14410 &windows->context);
14411 if (display_image->debug != MagickFalse)
14412 (void) LogMagickEvent(X11Event,GetMagickModule(),
14413 "Window id: 0x%lx (context)",windows->context.id);
14414 context_values.background=pixel->background_color.pixel;
14415 context_values.font=font_info->fid;
14416 context_values.foreground=pixel->foreground_color.pixel;
14417 context_values.graphics_exposures=MagickFalse;
14418 context_mask=(MagickStatusType)
14419 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14420 if (pixel->annotate_context != (GC) NULL)
14421 (void) XFreeGC(display,pixel->annotate_context);
14422 pixel->annotate_context=XCreateGC(display,windows->context.id,
14423 context_mask,&context_values);
14424 if (pixel->annotate_context == (GC) NULL)
14425 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14426 display_image->filename);
14427 context_values.background=pixel->depth_color.pixel;
14428 if (pixel->widget_context != (GC) NULL)
14429 (void) XFreeGC(display,pixel->widget_context);
14430 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14431 &context_values);
14432 if (pixel->widget_context == (GC) NULL)
14433 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14434 display_image->filename);
14435 context_values.background=pixel->foreground_color.pixel;
14436 context_values.foreground=pixel->background_color.pixel;
14437 context_values.plane_mask=context_values.background ^
14438 context_values.foreground;
14439 if (pixel->highlight_context != (GC) NULL)
14440 (void) XFreeGC(display,pixel->highlight_context);
14441 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +000014442 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014443 if (pixel->highlight_context == (GC) NULL)
14444 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14445 display_image->filename);
14446 (void) XDestroyWindow(display,windows->context.id);
14447 /*
14448 Initialize icon window.
14449 */
14450 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14451 icon_resources,&windows->icon);
14452 windows->icon.geometry=resource_info->icon_geometry;
14453 XBestIconSize(display,&windows->icon,display_image);
14454 windows->icon.attributes.colormap=XDefaultColormap(display,
14455 icon_visual->screen);
14456 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14457 manager_hints->flags=InputHint | StateHint;
14458 manager_hints->input=MagickFalse;
14459 manager_hints->initial_state=IconicState;
14460 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14461 &windows->icon);
14462 if (display_image->debug != MagickFalse)
14463 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14464 windows->icon.id);
14465 /*
14466 Initialize graphic context for icon window.
14467 */
14468 if (icon_pixel->annotate_context != (GC) NULL)
14469 (void) XFreeGC(display,icon_pixel->annotate_context);
14470 context_values.background=icon_pixel->background_color.pixel;
14471 context_values.foreground=icon_pixel->foreground_color.pixel;
14472 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +000014473 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014474 if (icon_pixel->annotate_context == (GC) NULL)
14475 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14476 display_image->filename);
14477 windows->icon.annotate_context=icon_pixel->annotate_context;
14478 /*
14479 Initialize Image window.
14480 */
14481 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14482 &windows->image);
14483 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14484 if (resource_info->use_shared_memory == MagickFalse)
14485 windows->image.shared_memory=MagickFalse;
14486 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14487 {
14488 char
14489 *title;
14490
14491 title=InterpretImageProperties(resource_info->image_info,display_image,
14492 resource_info->title);
14493 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14494 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14495 title=DestroyString(title);
14496 }
14497 else
14498 {
14499 char
14500 filename[MaxTextExtent];
14501
14502 /*
14503 Window name is the base of the filename.
14504 */
14505 GetPathComponent(display_image->magick_filename,TailPath,filename);
14506 if (GetImageListLength(display_image) == 1)
14507 (void) FormatMagickString(windows->image.name,MaxTextExtent,
cristy40a08ad2010-02-09 02:27:44 +000014508 "%s: %s",MagickPackageName,filename);
cristy3ed852e2009-09-05 21:47:34 +000014509 else
14510 (void) FormatMagickString(windows->image.name,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +000014511 "%s: %s[%.20g of %.20g]",MagickPackageName,filename,(double)
14512 display_image->scene,(double) GetImageListLength(display_image));
cristy3ed852e2009-09-05 21:47:34 +000014513 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14514 }
14515 if (resource_info->immutable)
14516 windows->image.immutable=MagickTrue;
14517 windows->image.use_pixmap=resource_info->use_pixmap;
14518 windows->image.geometry=resource_info->image_geometry;
14519 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14520 XDisplayWidth(display,visual_info->screen),
14521 XDisplayHeight(display,visual_info->screen));
14522 geometry_info.width=display_image->columns;
14523 geometry_info.height=display_image->rows;
14524 geometry_info.x=0;
14525 geometry_info.y=0;
14526 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14527 &geometry_info.width,&geometry_info.height);
14528 windows->image.width=(unsigned int) geometry_info.width;
14529 windows->image.height=(unsigned int) geometry_info.height;
14530 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14531 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14532 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14533 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14534 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14535 resource_info,&windows->backdrop);
14536 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14537 {
14538 /*
14539 Initialize backdrop window.
14540 */
14541 windows->backdrop.x=0;
14542 windows->backdrop.y=0;
cristy40a08ad2010-02-09 02:27:44 +000014543 (void) CloneString(&windows->backdrop.name,"Backdrop");
cristybb503372010-05-27 20:51:26 +000014544 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +000014545 windows->backdrop.width=(unsigned int)
14546 XDisplayWidth(display,visual_info->screen);
14547 windows->backdrop.height=(unsigned int)
14548 XDisplayHeight(display,visual_info->screen);
14549 windows->backdrop.border_width=0;
14550 windows->backdrop.immutable=MagickTrue;
14551 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14552 ButtonReleaseMask;
14553 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14554 StructureNotifyMask;
14555 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14556 manager_hints->icon_window=windows->icon.id;
14557 manager_hints->input=MagickTrue;
14558 manager_hints->initial_state=resource_info->iconic ? IconicState :
14559 NormalState;
14560 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14561 &windows->backdrop);
14562 if (display_image->debug != MagickFalse)
14563 (void) LogMagickEvent(X11Event,GetMagickModule(),
14564 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14565 (void) XMapWindow(display,windows->backdrop.id);
14566 (void) XClearWindow(display,windows->backdrop.id);
14567 if (windows->image.id != (Window) NULL)
14568 {
14569 (void) XDestroyWindow(display,windows->image.id);
14570 windows->image.id=(Window) NULL;
14571 }
14572 /*
14573 Position image in the center the backdrop.
14574 */
14575 windows->image.flags|=USPosition;
14576 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14577 (windows->image.width/2);
14578 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14579 (windows->image.height/2);
14580 }
14581 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14582 manager_hints->icon_window=windows->icon.id;
14583 manager_hints->input=MagickTrue;
14584 manager_hints->initial_state=resource_info->iconic ? IconicState :
14585 NormalState;
14586 if (windows->group_leader.id != (Window) NULL)
14587 {
14588 /*
14589 Follow the leader.
14590 */
14591 manager_hints->flags|=WindowGroupHint;
14592 manager_hints->window_group=windows->group_leader.id;
14593 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14594 if (display_image->debug != MagickFalse)
14595 (void) LogMagickEvent(X11Event,GetMagickModule(),
14596 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14597 }
14598 XMakeWindow(display,
14599 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14600 argv,argc,class_hints,manager_hints,&windows->image);
14601 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14602 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14603 if (windows->group_leader.id != (Window) NULL)
14604 (void) XSetTransientForHint(display,windows->image.id,
14605 windows->group_leader.id);
14606 if (display_image->debug != MagickFalse)
14607 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14608 windows->image.id);
14609 /*
14610 Initialize Info widget.
14611 */
14612 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14613 &windows->info);
14614 (void) CloneString(&windows->info.name,"Info");
14615 (void) CloneString(&windows->info.icon_name,"Info");
14616 windows->info.border_width=1;
14617 windows->info.x=2;
14618 windows->info.y=2;
14619 windows->info.flags|=PPosition;
14620 windows->info.attributes.win_gravity=UnmapGravity;
14621 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14622 StructureNotifyMask;
14623 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14624 manager_hints->input=MagickFalse;
14625 manager_hints->initial_state=NormalState;
14626 manager_hints->window_group=windows->image.id;
14627 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14628 &windows->info);
14629 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14630 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14631 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14632 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14633 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14634 if (windows->image.mapped != MagickFalse)
14635 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14636 if (display_image->debug != MagickFalse)
14637 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14638 windows->info.id);
14639 /*
14640 Initialize Command widget.
14641 */
14642 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14643 resource_info,&windows->command);
14644 windows->command.data=MagickMenus;
14645 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14646 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
14647 resource_info->client_name);
14648 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14649 resource_name,"geometry",(char *) NULL);
14650 (void) CloneString(&windows->command.name,MagickTitle);
14651 windows->command.border_width=0;
14652 windows->command.flags|=PPosition;
14653 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14654 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14655 OwnerGrabButtonMask | StructureNotifyMask;
14656 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14657 manager_hints->input=MagickTrue;
14658 manager_hints->initial_state=NormalState;
14659 manager_hints->window_group=windows->image.id;
14660 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14661 &windows->command);
14662 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14663 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14664 HighlightHeight);
14665 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14666 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14667 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14668 if (windows->command.mapped != MagickFalse)
14669 (void) XMapRaised(display,windows->command.id);
14670 if (display_image->debug != MagickFalse)
14671 (void) LogMagickEvent(X11Event,GetMagickModule(),
14672 "Window id: 0x%lx (command)",windows->command.id);
14673 /*
14674 Initialize Widget window.
14675 */
14676 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14677 resource_info,&windows->widget);
14678 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
14679 resource_info->client_name);
14680 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14681 resource_name,"geometry",(char *) NULL);
14682 windows->widget.border_width=0;
14683 windows->widget.flags|=PPosition;
14684 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14685 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14686 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14687 StructureNotifyMask;
14688 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14689 manager_hints->input=MagickTrue;
14690 manager_hints->initial_state=NormalState;
14691 manager_hints->window_group=windows->image.id;
14692 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14693 &windows->widget);
14694 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14695 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14696 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14697 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14698 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14699 if (display_image->debug != MagickFalse)
14700 (void) LogMagickEvent(X11Event,GetMagickModule(),
14701 "Window id: 0x%lx (widget)",windows->widget.id);
14702 /*
14703 Initialize popup window.
14704 */
14705 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14706 resource_info,&windows->popup);
14707 windows->popup.border_width=0;
14708 windows->popup.flags|=PPosition;
14709 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14710 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14711 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14712 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14713 manager_hints->input=MagickTrue;
14714 manager_hints->initial_state=NormalState;
14715 manager_hints->window_group=windows->image.id;
14716 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14717 &windows->popup);
14718 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14719 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14720 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14721 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14722 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14723 if (display_image->debug != MagickFalse)
14724 (void) LogMagickEvent(X11Event,GetMagickModule(),
14725 "Window id: 0x%lx (pop up)",windows->popup.id);
14726 /*
14727 Initialize Magnify window and cursor.
14728 */
14729 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14730 resource_info,&windows->magnify);
14731 if (resource_info->use_shared_memory == MagickFalse)
14732 windows->magnify.shared_memory=MagickFalse;
14733 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.magnify",
14734 resource_info->client_name);
14735 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14736 resource_name,"geometry",(char *) NULL);
14737 (void) FormatMagickString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14738 resource_info->magnify);
14739 if (windows->magnify.cursor != (Cursor) NULL)
14740 (void) XFreeCursor(display,windows->magnify.cursor);
14741 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14742 map_info->colormap,resource_info->background_color,
14743 resource_info->foreground_color);
14744 if (windows->magnify.cursor == (Cursor) NULL)
14745 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14746 display_image->filename);
14747 windows->magnify.width=MagnifySize;
14748 windows->magnify.height=MagnifySize;
14749 windows->magnify.flags|=PPosition;
14750 windows->magnify.min_width=MagnifySize;
14751 windows->magnify.min_height=MagnifySize;
14752 windows->magnify.width_inc=MagnifySize;
14753 windows->magnify.height_inc=MagnifySize;
14754 windows->magnify.data=resource_info->magnify;
14755 windows->magnify.attributes.cursor=windows->magnify.cursor;
14756 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14757 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14758 StructureNotifyMask;
14759 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14760 manager_hints->input=MagickTrue;
14761 manager_hints->initial_state=NormalState;
14762 manager_hints->window_group=windows->image.id;
14763 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14764 &windows->magnify);
14765 if (display_image->debug != MagickFalse)
14766 (void) LogMagickEvent(X11Event,GetMagickModule(),
14767 "Window id: 0x%lx (magnify)",windows->magnify.id);
14768 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14769 /*
14770 Initialize panning window.
14771 */
14772 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14773 resource_info,&windows->pan);
14774 (void) CloneString(&windows->pan.name,"Pan Icon");
14775 windows->pan.width=windows->icon.width;
14776 windows->pan.height=windows->icon.height;
14777 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.pan",
14778 resource_info->client_name);
14779 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14780 resource_name,"geometry",(char *) NULL);
14781 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14782 &windows->pan.width,&windows->pan.height);
14783 windows->pan.flags|=PPosition;
14784 windows->pan.immutable=MagickTrue;
14785 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14786 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14787 StructureNotifyMask;
14788 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14789 manager_hints->input=MagickFalse;
14790 manager_hints->initial_state=NormalState;
14791 manager_hints->window_group=windows->image.id;
14792 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14793 &windows->pan);
14794 if (display_image->debug != MagickFalse)
14795 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14796 windows->pan.id);
14797 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14798 if (windows->info.mapped != MagickFalse)
14799 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14800 if ((windows->image.mapped == MagickFalse) ||
14801 (windows->backdrop.id != (Window) NULL))
14802 (void) XMapWindow(display,windows->image.id);
14803 /*
14804 Set our progress monitor and warning handlers.
14805 */
14806 if (warning_handler == (WarningHandler) NULL)
14807 {
14808 warning_handler=resource_info->display_warnings ?
14809 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14810 warning_handler=resource_info->display_warnings ?
14811 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14812 }
14813 /*
14814 Initialize Image and Magnify X images.
14815 */
14816 windows->image.x=0;
14817 windows->image.y=0;
14818 windows->magnify.shape=MagickFalse;
14819 width=(unsigned int) display_image->columns;
14820 height=(unsigned int) display_image->rows;
14821 if ((display_image->columns != width) || (display_image->rows != height))
14822 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14823 display_image->filename);
14824 status=XMakeImage(display,resource_info,&windows->image,display_image,
14825 width,height);
14826 if (status == MagickFalse)
14827 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14828 display_image->filename);
14829 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14830 windows->magnify.width,windows->magnify.height);
14831 if (status == MagickFalse)
14832 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14833 display_image->filename);
14834 if (windows->magnify.mapped != MagickFalse)
14835 (void) XMapRaised(display,windows->magnify.id);
14836 if (windows->pan.mapped != MagickFalse)
14837 (void) XMapRaised(display,windows->pan.id);
14838 windows->image.window_changes.width=(int) display_image->columns;
14839 windows->image.window_changes.height=(int) display_image->rows;
14840 (void) XConfigureImage(display,resource_info,windows,display_image);
14841 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14842 (void) XSync(display,MagickFalse);
14843 /*
14844 Respond to events.
14845 */
14846 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14847 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14848 update_time=0;
14849 if (resource_info->update != MagickFalse)
14850 {
14851 MagickBooleanType
14852 status;
14853
14854 /*
14855 Determine when file data was last modified.
14856 */
14857 status=GetPathAttributes(display_image->filename,&attributes);
14858 if (status != MagickFalse)
14859 update_time=attributes.st_mtime;
14860 }
14861 *state&=(~FormerImageState);
14862 *state&=(~MontageImageState);
14863 *state&=(~NextImageState);
14864 do
14865 {
14866 /*
14867 Handle a window event.
14868 */
14869 if (windows->image.mapped != MagickFalse)
14870 if ((display_image->delay != 0) || (resource_info->update != 0))
14871 {
14872 if (timer < time((time_t *) NULL))
14873 {
14874 if (resource_info->update == MagickFalse)
14875 *state|=NextImageState | ExitState;
14876 else
14877 {
14878 MagickBooleanType
14879 status;
14880
14881 /*
14882 Determine if image file was modified.
14883 */
14884 status=GetPathAttributes(display_image->filename,&attributes);
14885 if (status != MagickFalse)
14886 if (update_time != attributes.st_mtime)
14887 {
14888 /*
14889 Redisplay image.
14890 */
14891 (void) FormatMagickString(
14892 resource_info->image_info->filename,MaxTextExtent,
14893 "%s:%s",display_image->magick,
14894 display_image->filename);
14895 nexus=ReadImage(resource_info->image_info,
14896 &display_image->exception);
14897 if (nexus != (Image *) NULL)
14898 {
14899 nexus=DestroyImage(nexus);
14900 *state|=NextImageState | ExitState;
14901 }
14902 }
14903 delay=display_image->delay/MagickMax(
14904 display_image->ticks_per_second,1L);
14905 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14906 }
14907 }
14908 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14909 {
14910 /*
14911 Do not block if delay > 0.
14912 */
14913 XDelay(display,SuspendTime << 2);
14914 continue;
14915 }
14916 }
14917 timestamp=time((time_t *) NULL);
14918 (void) XNextEvent(display,&event);
14919 if (windows->image.stasis == MagickFalse)
14920 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14921 MagickTrue : MagickFalse;
14922 if (windows->magnify.stasis == MagickFalse)
14923 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14924 MagickTrue : MagickFalse;
14925 if (event.xany.window == windows->command.id)
14926 {
14927 /*
14928 Select a command from the Command widget.
14929 */
14930 id=XCommandWidget(display,windows,CommandMenu,&event);
14931 if (id < 0)
14932 continue;
14933 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
14934 command_type=CommandMenus[id];
14935 if (id < MagickMenus)
14936 {
14937 /*
14938 Select a command from a pop-up menu.
14939 */
14940 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
14941 command);
14942 if (entry < 0)
14943 continue;
14944 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
14945 command_type=Commands[id][entry];
14946 }
14947 if (command_type != NullCommand)
14948 nexus=XMagickCommand(display,resource_info,windows,command_type,
14949 &display_image);
14950 continue;
14951 }
14952 switch (event.type)
14953 {
14954 case ButtonPress:
14955 {
14956 if (display_image->debug != MagickFalse)
14957 (void) LogMagickEvent(X11Event,GetMagickModule(),
14958 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
14959 event.xbutton.button,event.xbutton.x,event.xbutton.y);
14960 if ((event.xbutton.button == Button3) &&
14961 (event.xbutton.state & Mod1Mask))
14962 {
14963 /*
14964 Convert Alt-Button3 to Button2.
14965 */
14966 event.xbutton.button=Button2;
14967 event.xbutton.state&=(~Mod1Mask);
14968 }
14969 if (event.xbutton.window == windows->backdrop.id)
14970 {
14971 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
14972 event.xbutton.time);
14973 break;
14974 }
14975 if (event.xbutton.window == windows->image.id)
14976 {
14977 switch (event.xbutton.button)
14978 {
14979 case Button1:
14980 {
14981 if (resource_info->immutable)
14982 {
14983 /*
14984 Select a command from the Virtual menu.
14985 */
14986 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
14987 command);
14988 if (entry >= 0)
14989 nexus=XMagickCommand(display,resource_info,windows,
14990 VirtualCommands[entry],&display_image);
14991 break;
14992 }
14993 /*
14994 Map/unmap Command widget.
14995 */
14996 if (windows->command.mapped != MagickFalse)
14997 (void) XWithdrawWindow(display,windows->command.id,
14998 windows->command.screen);
14999 else
15000 {
15001 (void) XCommandWidget(display,windows,CommandMenu,
15002 (XEvent *) NULL);
15003 (void) XMapRaised(display,windows->command.id);
15004 }
15005 break;
15006 }
15007 case Button2:
15008 {
15009 /*
15010 User pressed the image magnify button.
15011 */
15012 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15013 &display_image);
15014 XMagnifyImage(display,windows,&event);
15015 break;
15016 }
15017 case Button3:
15018 {
15019 if (resource_info->immutable)
15020 {
15021 /*
15022 Select a command from the Virtual menu.
15023 */
15024 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15025 command);
15026 if (entry >= 0)
15027 nexus=XMagickCommand(display,resource_info,windows,
15028 VirtualCommands[entry],&display_image);
15029 break;
15030 }
15031 if (display_image->montage != (char *) NULL)
15032 {
15033 /*
15034 Open or delete a tile from a visual image directory.
15035 */
15036 nexus=XTileImage(display,resource_info,windows,
15037 display_image,&event);
15038 if (nexus != (Image *) NULL)
15039 *state|=MontageImageState | NextImageState | ExitState;
15040 vid_info.x=windows->image.x;
15041 vid_info.y=windows->image.y;
15042 break;
15043 }
15044 /*
15045 Select a command from the Short Cuts menu.
15046 */
15047 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15048 command);
15049 if (entry >= 0)
15050 nexus=XMagickCommand(display,resource_info,windows,
15051 ShortCutsCommands[entry],&display_image);
15052 break;
15053 }
15054 case Button4:
15055 {
15056 /*
15057 Wheel up.
15058 */
15059 XTranslateImage(display,windows,*image,XK_Up);
15060 break;
15061 }
15062 case Button5:
15063 {
15064 /*
15065 Wheel down.
15066 */
15067 XTranslateImage(display,windows,*image,XK_Down);
15068 break;
15069 }
15070 default:
15071 break;
15072 }
15073 break;
15074 }
15075 if (event.xbutton.window == windows->magnify.id)
15076 {
15077 int
15078 factor;
15079
15080 static const char
15081 *MagnifyMenu[] =
15082 {
15083 "2",
15084 "4",
15085 "5",
15086 "6",
15087 "7",
15088 "8",
15089 "9",
15090 "3",
15091 (char *) NULL,
15092 };
15093
15094 static KeySym
15095 MagnifyCommands[] =
15096 {
15097 XK_2,
15098 XK_4,
15099 XK_5,
15100 XK_6,
15101 XK_7,
15102 XK_8,
15103 XK_9,
15104 XK_3
15105 };
15106
15107 /*
15108 Select a magnify factor from the pop-up menu.
15109 */
15110 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15111 if (factor >= 0)
15112 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15113 break;
15114 }
15115 if (event.xbutton.window == windows->pan.id)
15116 {
15117 switch (event.xbutton.button)
15118 {
15119 case Button4:
15120 {
15121 /*
15122 Wheel up.
15123 */
15124 XTranslateImage(display,windows,*image,XK_Up);
15125 break;
15126 }
15127 case Button5:
15128 {
15129 /*
15130 Wheel down.
15131 */
15132 XTranslateImage(display,windows,*image,XK_Down);
15133 break;
15134 }
15135 default:
15136 {
15137 XPanImage(display,windows,&event);
15138 break;
15139 }
15140 }
15141 break;
15142 }
15143 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15144 1L);
15145 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15146 break;
15147 }
15148 case ButtonRelease:
15149 {
15150 if (display_image->debug != MagickFalse)
15151 (void) LogMagickEvent(X11Event,GetMagickModule(),
15152 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15153 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15154 break;
15155 }
15156 case ClientMessage:
15157 {
15158 if (display_image->debug != MagickFalse)
15159 (void) LogMagickEvent(X11Event,GetMagickModule(),
15160 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
cristyf2faecf2010-05-28 19:19:36 +000015161 event.xclient.message_type,event.xclient.format,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015162 event.xclient.data.l[0]);
15163 if (event.xclient.message_type == windows->im_protocols)
15164 {
cristyecd0ab52010-05-30 14:59:20 +000015165 if (*event.xclient.data.l == (long) windows->im_update_widget)
cristy3ed852e2009-09-05 21:47:34 +000015166 {
15167 (void) CloneString(&windows->command.name,MagickTitle);
15168 windows->command.data=MagickMenus;
15169 (void) XCommandWidget(display,windows,CommandMenu,
15170 (XEvent *) NULL);
15171 break;
15172 }
cristyecd0ab52010-05-30 14:59:20 +000015173 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +000015174 {
15175 /*
15176 Update graphic context and window colormap.
15177 */
15178 for (i=0; i < (int) number_windows; i++)
15179 {
15180 if (magick_windows[i]->id == windows->icon.id)
15181 continue;
15182 context_values.background=pixel->background_color.pixel;
15183 context_values.foreground=pixel->foreground_color.pixel;
15184 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15185 context_mask,&context_values);
15186 (void) XChangeGC(display,magick_windows[i]->widget_context,
15187 context_mask,&context_values);
15188 context_values.background=pixel->foreground_color.pixel;
15189 context_values.foreground=pixel->background_color.pixel;
15190 context_values.plane_mask=context_values.background ^
15191 context_values.foreground;
15192 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +000015193 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +000015194 &context_values);
15195 magick_windows[i]->attributes.background_pixel=
15196 pixel->background_color.pixel;
15197 magick_windows[i]->attributes.border_pixel=
15198 pixel->border_color.pixel;
15199 magick_windows[i]->attributes.colormap=map_info->colormap;
15200 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15201 magick_windows[i]->mask,&magick_windows[i]->attributes);
15202 }
15203 if (windows->pan.mapped != MagickFalse)
15204 {
15205 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15206 windows->pan.pixmap);
15207 (void) XClearWindow(display,windows->pan.id);
15208 XDrawPanRectangle(display,windows);
15209 }
15210 if (windows->backdrop.id != (Window) NULL)
15211 (void) XInstallColormap(display,map_info->colormap);
15212 break;
15213 }
cristyecd0ab52010-05-30 14:59:20 +000015214 if (*event.xclient.data.l == (long) windows->im_former_image)
cristy3ed852e2009-09-05 21:47:34 +000015215 {
15216 *state|=FormerImageState | ExitState;
15217 break;
15218 }
cristyecd0ab52010-05-30 14:59:20 +000015219 if (*event.xclient.data.l == (long) windows->im_next_image)
cristy3ed852e2009-09-05 21:47:34 +000015220 {
15221 *state|=NextImageState | ExitState;
15222 break;
15223 }
cristyecd0ab52010-05-30 14:59:20 +000015224 if (*event.xclient.data.l == (long) windows->im_retain_colors)
cristy3ed852e2009-09-05 21:47:34 +000015225 {
15226 *state|=RetainColorsState;
15227 break;
15228 }
cristyecd0ab52010-05-30 14:59:20 +000015229 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +000015230 {
15231 *state|=ExitState;
15232 break;
15233 }
15234 break;
15235 }
15236 if (event.xclient.message_type == windows->dnd_protocols)
15237 {
15238 Atom
15239 selection,
15240 type;
15241
15242 int
15243 format,
15244 status;
15245
15246 unsigned char
15247 *data;
15248
cristyf2faecf2010-05-28 19:19:36 +000015249 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015250 after,
15251 length;
15252
15253 /*
15254 Display image named by the Drag-and-Drop selection.
15255 */
15256 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15257 break;
15258 selection=XInternAtom(display,"DndSelection",MagickFalse);
cristyecd0ab52010-05-30 14:59:20 +000015259 status=XGetWindowProperty(display,root_window,selection,0L,(long)
cristy3ed852e2009-09-05 21:47:34 +000015260 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15261 &length,&after,&data);
15262 if ((status != Success) || (length == 0))
15263 break;
15264 if (*event.xclient.data.l == 2)
15265 {
15266 /*
15267 Offix DND.
15268 */
15269 (void) CopyMagickString(resource_info->image_info->filename,
15270 (char *) data,MaxTextExtent);
15271 }
15272 else
15273 {
15274 /*
15275 XDND.
15276 */
15277 if (strncmp((char *) data, "file:", 5) != 0)
15278 {
15279 (void) XFree((void *) data);
15280 break;
15281 }
15282 (void) CopyMagickString(resource_info->image_info->filename,
15283 ((char *) data)+5,MaxTextExtent);
15284 }
15285 nexus=ReadImage(resource_info->image_info,
15286 &display_image->exception);
15287 CatchException(&display_image->exception);
15288 if (nexus != (Image *) NULL)
15289 *state|=NextImageState | ExitState;
15290 (void) XFree((void *) data);
15291 break;
15292 }
15293 /*
15294 If client window delete message, exit.
15295 */
15296 if (event.xclient.message_type != windows->wm_protocols)
15297 break;
cristyecd0ab52010-05-30 14:59:20 +000015298 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000015299 break;
15300 (void) XWithdrawWindow(display,event.xclient.window,
15301 visual_info->screen);
15302 if (event.xclient.window == windows->image.id)
15303 {
15304 *state|=ExitState;
15305 break;
15306 }
15307 if (event.xclient.window == windows->pan.id)
15308 {
15309 /*
15310 Restore original image size when pan window is deleted.
15311 */
15312 windows->image.window_changes.width=windows->image.ximage->width;
15313 windows->image.window_changes.height=windows->image.ximage->height;
15314 (void) XConfigureImage(display,resource_info,windows,
15315 display_image);
15316 }
15317 break;
15318 }
15319 case ConfigureNotify:
15320 {
15321 if (display_image->debug != MagickFalse)
15322 (void) LogMagickEvent(X11Event,GetMagickModule(),
15323 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15324 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15325 event.xconfigure.y,event.xconfigure.send_event);
15326 if (event.xconfigure.window == windows->image.id)
15327 {
15328 /*
15329 Image window has a new configuration.
15330 */
15331 if (event.xconfigure.send_event != 0)
15332 {
15333 XWindowChanges
15334 window_changes;
15335
15336 /*
15337 Position the transient windows relative of the Image window.
15338 */
15339 if (windows->command.geometry == (char *) NULL)
15340 if (windows->command.mapped == MagickFalse)
15341 {
15342 windows->command.x=event.xconfigure.x-
15343 windows->command.width-25;
15344 windows->command.y=event.xconfigure.y;
15345 XConstrainWindowPosition(display,&windows->command);
15346 window_changes.x=windows->command.x;
15347 window_changes.y=windows->command.y;
15348 (void) XReconfigureWMWindow(display,windows->command.id,
15349 windows->command.screen,(unsigned int) (CWX | CWY),
15350 &window_changes);
15351 }
15352 if (windows->widget.geometry == (char *) NULL)
15353 if (windows->widget.mapped == MagickFalse)
15354 {
15355 windows->widget.x=event.xconfigure.x+
15356 event.xconfigure.width/10;
15357 windows->widget.y=event.xconfigure.y+
15358 event.xconfigure.height/10;
15359 XConstrainWindowPosition(display,&windows->widget);
15360 window_changes.x=windows->widget.x;
15361 window_changes.y=windows->widget.y;
15362 (void) XReconfigureWMWindow(display,windows->widget.id,
15363 windows->widget.screen,(unsigned int) (CWX | CWY),
15364 &window_changes);
15365 }
15366 if (windows->magnify.geometry == (char *) NULL)
15367 if (windows->magnify.mapped == MagickFalse)
15368 {
15369 windows->magnify.x=event.xconfigure.x+
15370 event.xconfigure.width+25;
15371 windows->magnify.y=event.xconfigure.y;
15372 XConstrainWindowPosition(display,&windows->magnify);
15373 window_changes.x=windows->magnify.x;
15374 window_changes.y=windows->magnify.y;
15375 (void) XReconfigureWMWindow(display,windows->magnify.id,
15376 windows->magnify.screen,(unsigned int) (CWX | CWY),
15377 &window_changes);
15378 }
15379 if (windows->pan.geometry == (char *) NULL)
15380 if (windows->pan.mapped == MagickFalse)
15381 {
15382 windows->pan.x=event.xconfigure.x+
15383 event.xconfigure.width+25;
15384 windows->pan.y=event.xconfigure.y+
15385 windows->magnify.height+50;
15386 XConstrainWindowPosition(display,&windows->pan);
15387 window_changes.x=windows->pan.x;
15388 window_changes.y=windows->pan.y;
15389 (void) XReconfigureWMWindow(display,windows->pan.id,
15390 windows->pan.screen,(unsigned int) (CWX | CWY),
15391 &window_changes);
15392 }
15393 }
cristyecd0ab52010-05-30 14:59:20 +000015394 if ((event.xconfigure.width == (int) windows->image.width) &&
15395 (event.xconfigure.height == (int) windows->image.height))
cristy3ed852e2009-09-05 21:47:34 +000015396 break;
15397 windows->image.width=(unsigned int) event.xconfigure.width;
15398 windows->image.height=(unsigned int) event.xconfigure.height;
15399 windows->image.x=0;
15400 windows->image.y=0;
15401 if (display_image->montage != (char *) NULL)
15402 {
15403 windows->image.x=vid_info.x;
15404 windows->image.y=vid_info.y;
15405 }
cristy34b9f452010-01-06 20:04:29 +000015406 if ((windows->image.mapped != MagickFalse) &&
15407 (windows->image.stasis != MagickFalse))
15408 {
15409 /*
15410 Update image window configuration.
15411 */
15412 windows->image.window_changes.width=event.xconfigure.width;
15413 windows->image.window_changes.height=event.xconfigure.height;
15414 (void) XConfigureImage(display,resource_info,windows,
15415 display_image);
15416 }
cristy3ed852e2009-09-05 21:47:34 +000015417 /*
15418 Update pan window configuration.
15419 */
15420 if ((event.xconfigure.width < windows->image.ximage->width) ||
15421 (event.xconfigure.height < windows->image.ximage->height))
15422 {
15423 (void) XMapRaised(display,windows->pan.id);
15424 XDrawPanRectangle(display,windows);
15425 }
15426 else
15427 if (windows->pan.mapped != MagickFalse)
15428 (void) XWithdrawWindow(display,windows->pan.id,
15429 windows->pan.screen);
15430 break;
15431 }
15432 if (event.xconfigure.window == windows->magnify.id)
15433 {
15434 unsigned int
15435 magnify;
15436
15437 /*
15438 Magnify window has a new configuration.
15439 */
15440 windows->magnify.width=(unsigned int) event.xconfigure.width;
15441 windows->magnify.height=(unsigned int) event.xconfigure.height;
15442 if (windows->magnify.mapped == MagickFalse)
15443 break;
15444 magnify=1;
15445 while ((int) magnify <= event.xconfigure.width)
15446 magnify<<=1;
15447 while ((int) magnify <= event.xconfigure.height)
15448 magnify<<=1;
15449 magnify>>=1;
15450 if (((int) magnify != event.xconfigure.width) ||
15451 ((int) magnify != event.xconfigure.height))
15452 {
15453 window_changes.width=(int) magnify;
15454 window_changes.height=(int) magnify;
15455 (void) XReconfigureWMWindow(display,windows->magnify.id,
15456 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15457 &window_changes);
15458 break;
15459 }
15460 if ((windows->magnify.mapped != MagickFalse) &&
15461 (windows->magnify.stasis != MagickFalse))
15462 {
15463 status=XMakeImage(display,resource_info,&windows->magnify,
15464 display_image,windows->magnify.width,windows->magnify.height);
15465 XMakeMagnifyImage(display,windows);
15466 }
15467 break;
15468 }
15469 if ((windows->magnify.mapped != MagickFalse) &&
15470 (event.xconfigure.window == windows->pan.id))
15471 {
15472 /*
15473 Pan icon window has a new configuration.
15474 */
15475 if (event.xconfigure.send_event != 0)
15476 {
15477 windows->pan.x=event.xconfigure.x;
15478 windows->pan.y=event.xconfigure.y;
15479 }
15480 windows->pan.width=(unsigned int) event.xconfigure.width;
15481 windows->pan.height=(unsigned int) event.xconfigure.height;
15482 break;
15483 }
15484 if (event.xconfigure.window == windows->icon.id)
15485 {
15486 /*
15487 Icon window has a new configuration.
15488 */
15489 windows->icon.width=(unsigned int) event.xconfigure.width;
15490 windows->icon.height=(unsigned int) event.xconfigure.height;
15491 break;
15492 }
15493 break;
15494 }
15495 case DestroyNotify:
15496 {
15497 /*
15498 Group leader has exited.
15499 */
15500 if (display_image->debug != MagickFalse)
15501 (void) LogMagickEvent(X11Event,GetMagickModule(),
15502 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15503 if (event.xdestroywindow.window == windows->group_leader.id)
15504 {
15505 *state|=ExitState;
15506 break;
15507 }
15508 break;
15509 }
15510 case EnterNotify:
15511 {
15512 /*
15513 Selectively install colormap.
15514 */
15515 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15516 if (event.xcrossing.mode != NotifyUngrab)
15517 XInstallColormap(display,map_info->colormap);
15518 break;
15519 }
15520 case Expose:
15521 {
15522 if (display_image->debug != MagickFalse)
15523 (void) LogMagickEvent(X11Event,GetMagickModule(),
15524 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15525 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15526 event.xexpose.y);
15527 /*
15528 Refresh windows that are now exposed.
15529 */
cristy6bee4042010-01-30 15:27:14 +000015530 if ((event.xexpose.window == windows->image.id) &&
15531 (windows->image.mapped != MagickFalse))
15532 {
15533 XRefreshWindow(display,&windows->image,&event);
15534 delay=display_image->delay/MagickMax(
15535 display_image->ticks_per_second,1L);
15536 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15537 break;
15538 }
15539 if ((event.xexpose.window == windows->magnify.id) &&
15540 (windows->magnify.mapped != MagickFalse))
15541 {
15542 XMakeMagnifyImage(display,windows);
15543 break;
15544 }
cristy3ed852e2009-09-05 21:47:34 +000015545 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015546 {
15547 XDrawPanRectangle(display,windows);
15548 break;
15549 }
cristy3ed852e2009-09-05 21:47:34 +000015550 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015551 {
15552 XRefreshWindow(display,&windows->icon,&event);
15553 break;
15554 }
cristy3ed852e2009-09-05 21:47:34 +000015555 break;
15556 }
15557 case KeyPress:
15558 {
15559 int
15560 length;
15561
15562 /*
15563 Respond to a user key press.
15564 */
15565 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15566 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15567 *(command+length)='\0';
15568 if (display_image->debug != MagickFalse)
15569 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015570 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015571 key_symbol,command);
15572 if (event.xkey.window == windows->image.id)
15573 {
15574 command_type=XImageWindowCommand(display,resource_info,windows,
15575 event.xkey.state,key_symbol,&display_image);
15576 if (command_type != NullCommand)
15577 nexus=XMagickCommand(display,resource_info,windows,command_type,
15578 &display_image);
15579 }
15580 if (event.xkey.window == windows->magnify.id)
15581 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15582 if (event.xkey.window == windows->pan.id)
15583 {
15584 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15585 (void) XWithdrawWindow(display,windows->pan.id,
15586 windows->pan.screen);
15587 else
15588 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15589 XTextViewWidget(display,resource_info,windows,MagickFalse,
15590 "Help Viewer - Image Pan",ImagePanHelp);
15591 else
15592 XTranslateImage(display,windows,*image,key_symbol);
15593 }
15594 delay=display_image->delay/MagickMax(
15595 display_image->ticks_per_second,1L);
15596 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15597 break;
15598 }
15599 case KeyRelease:
15600 {
15601 /*
15602 Respond to a user key release.
15603 */
15604 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15605 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15606 if (display_image->debug != MagickFalse)
15607 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015608 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +000015609 break;
15610 }
15611 case LeaveNotify:
15612 {
15613 /*
15614 Selectively uninstall colormap.
15615 */
15616 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15617 if (event.xcrossing.mode != NotifyUngrab)
15618 XUninstallColormap(display,map_info->colormap);
15619 break;
15620 }
15621 case MapNotify:
15622 {
15623 if (display_image->debug != MagickFalse)
15624 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15625 event.xmap.window);
15626 if (event.xmap.window == windows->backdrop.id)
15627 {
15628 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15629 CurrentTime);
15630 windows->backdrop.mapped=MagickTrue;
15631 break;
15632 }
15633 if (event.xmap.window == windows->image.id)
15634 {
15635 if (windows->backdrop.id != (Window) NULL)
15636 (void) XInstallColormap(display,map_info->colormap);
15637 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15638 {
15639 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15640 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15641 }
15642 if (((int) windows->image.width < windows->image.ximage->width) ||
15643 ((int) windows->image.height < windows->image.ximage->height))
15644 (void) XMapRaised(display,windows->pan.id);
15645 windows->image.mapped=MagickTrue;
15646 break;
15647 }
15648 if (event.xmap.window == windows->magnify.id)
15649 {
15650 XMakeMagnifyImage(display,windows);
15651 windows->magnify.mapped=MagickTrue;
15652 (void) XWithdrawWindow(display,windows->info.id,
15653 windows->info.screen);
15654 break;
15655 }
15656 if (event.xmap.window == windows->pan.id)
15657 {
15658 XMakePanImage(display,resource_info,windows,display_image);
15659 windows->pan.mapped=MagickTrue;
15660 break;
15661 }
15662 if (event.xmap.window == windows->info.id)
15663 {
15664 windows->info.mapped=MagickTrue;
15665 break;
15666 }
15667 if (event.xmap.window == windows->icon.id)
15668 {
15669 MagickBooleanType
15670 taint;
15671
15672 /*
15673 Create an icon image.
15674 */
15675 taint=display_image->taint;
15676 XMakeStandardColormap(display,icon_visual,icon_resources,
15677 display_image,icon_map,icon_pixel);
15678 (void) XMakeImage(display,icon_resources,&windows->icon,
15679 display_image,windows->icon.width,windows->icon.height);
15680 display_image->taint=taint;
15681 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15682 windows->icon.pixmap);
15683 (void) XClearWindow(display,windows->icon.id);
15684 (void) XWithdrawWindow(display,windows->info.id,
15685 windows->info.screen);
15686 windows->icon.mapped=MagickTrue;
15687 break;
15688 }
15689 if (event.xmap.window == windows->command.id)
15690 {
15691 windows->command.mapped=MagickTrue;
15692 break;
15693 }
15694 if (event.xmap.window == windows->popup.id)
15695 {
15696 windows->popup.mapped=MagickTrue;
15697 break;
15698 }
15699 if (event.xmap.window == windows->widget.id)
15700 {
15701 windows->widget.mapped=MagickTrue;
15702 break;
15703 }
15704 break;
15705 }
15706 case MappingNotify:
15707 {
15708 (void) XRefreshKeyboardMapping(&event.xmapping);
15709 break;
15710 }
15711 case NoExpose:
15712 break;
15713 case PropertyNotify:
15714 {
15715 Atom
15716 type;
15717
15718 int
15719 format,
15720 status;
15721
15722 unsigned char
15723 *data;
15724
cristyf2faecf2010-05-28 19:19:36 +000015725 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015726 after,
15727 length;
15728
15729 if (display_image->debug != MagickFalse)
15730 (void) LogMagickEvent(X11Event,GetMagickModule(),
15731 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15732 event.xproperty.atom,event.xproperty.state);
15733 if (event.xproperty.atom != windows->im_remote_command)
15734 break;
15735 /*
15736 Display image named by the remote command protocol.
15737 */
15738 status=XGetWindowProperty(display,event.xproperty.window,
cristyecd0ab52010-05-30 14:59:20 +000015739 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +000015740 AnyPropertyType,&type,&format,&length,&after,&data);
15741 if ((status != Success) || (length == 0))
15742 break;
15743 if (LocaleCompare((char *) data,"-quit") == 0)
15744 {
15745 XClientMessage(display,windows->image.id,windows->im_protocols,
15746 windows->im_exit,CurrentTime);
15747 (void) XFree((void *) data);
15748 break;
15749 }
15750 (void) CopyMagickString(resource_info->image_info->filename,
15751 (char *) data,MaxTextExtent);
15752 (void) XFree((void *) data);
15753 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15754 CatchException(&display_image->exception);
15755 if (nexus != (Image *) NULL)
15756 *state|=NextImageState | ExitState;
15757 break;
15758 }
15759 case ReparentNotify:
15760 {
15761 if (display_image->debug != MagickFalse)
15762 (void) LogMagickEvent(X11Event,GetMagickModule(),
15763 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15764 event.xreparent.window);
15765 break;
15766 }
15767 case UnmapNotify:
15768 {
15769 if (display_image->debug != MagickFalse)
15770 (void) LogMagickEvent(X11Event,GetMagickModule(),
15771 "Unmap Notify: 0x%lx",event.xunmap.window);
15772 if (event.xunmap.window == windows->backdrop.id)
15773 {
15774 windows->backdrop.mapped=MagickFalse;
15775 break;
15776 }
15777 if (event.xunmap.window == windows->image.id)
15778 {
15779 windows->image.mapped=MagickFalse;
15780 break;
15781 }
15782 if (event.xunmap.window == windows->magnify.id)
15783 {
15784 windows->magnify.mapped=MagickFalse;
15785 break;
15786 }
15787 if (event.xunmap.window == windows->pan.id)
15788 {
15789 windows->pan.mapped=MagickFalse;
15790 break;
15791 }
15792 if (event.xunmap.window == windows->info.id)
15793 {
15794 windows->info.mapped=MagickFalse;
15795 break;
15796 }
15797 if (event.xunmap.window == windows->icon.id)
15798 {
15799 if (map_info->colormap == icon_map->colormap)
15800 XConfigureImageColormap(display,resource_info,windows,
15801 display_image);
15802 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15803 icon_pixel);
15804 windows->icon.mapped=MagickFalse;
15805 break;
15806 }
15807 if (event.xunmap.window == windows->command.id)
15808 {
15809 windows->command.mapped=MagickFalse;
15810 break;
15811 }
15812 if (event.xunmap.window == windows->popup.id)
15813 {
15814 if (windows->backdrop.id != (Window) NULL)
15815 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15816 CurrentTime);
15817 windows->popup.mapped=MagickFalse;
15818 break;
15819 }
15820 if (event.xunmap.window == windows->widget.id)
15821 {
15822 if (windows->backdrop.id != (Window) NULL)
15823 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15824 CurrentTime);
15825 windows->widget.mapped=MagickFalse;
15826 break;
15827 }
15828 break;
15829 }
15830 default:
15831 {
15832 if (display_image->debug != MagickFalse)
15833 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15834 event.type);
15835 break;
15836 }
15837 }
15838 } while (!(*state & ExitState));
15839 if ((*state & ExitState) == 0)
15840 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15841 &display_image);
15842 else
15843 if (resource_info->confirm_edit != MagickFalse)
15844 {
15845 /*
15846 Query user if image has changed.
15847 */
15848 if ((resource_info->immutable == MagickFalse) &&
15849 (display_image->taint != MagickFalse))
15850 {
15851 int
15852 status;
15853
15854 status=XConfirmWidget(display,windows,"Your image changed.",
15855 "Do you want to save it");
15856 if (status == 0)
15857 *state&=(~ExitState);
15858 else
15859 if (status > 0)
15860 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15861 &display_image);
15862 }
15863 }
15864 if ((windows->visual_info->klass == GrayScale) ||
15865 (windows->visual_info->klass == PseudoColor) ||
15866 (windows->visual_info->klass == DirectColor))
15867 {
15868 /*
15869 Withdraw pan and Magnify window.
15870 */
15871 if (windows->info.mapped != MagickFalse)
15872 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15873 if (windows->magnify.mapped != MagickFalse)
15874 (void) XWithdrawWindow(display,windows->magnify.id,
15875 windows->magnify.screen);
15876 if (windows->command.mapped != MagickFalse)
15877 (void) XWithdrawWindow(display,windows->command.id,
15878 windows->command.screen);
15879 }
15880 if (windows->pan.mapped != MagickFalse)
15881 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15882 if (resource_info->backdrop == MagickFalse)
15883 if (windows->backdrop.mapped)
15884 {
15885 (void) XWithdrawWindow(display,windows->backdrop.id,
15886 windows->backdrop.screen);
15887 (void) XDestroyWindow(display,windows->backdrop.id);
15888 windows->backdrop.id=(Window) NULL;
15889 (void) XWithdrawWindow(display,windows->image.id,
15890 windows->image.screen);
15891 (void) XDestroyWindow(display,windows->image.id);
15892 windows->image.id=(Window) NULL;
15893 }
15894 XSetCursorState(display,windows,MagickTrue);
15895 XCheckRefreshWindows(display,windows);
15896 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15897 *state&=(~ExitState);
15898 if (*state & ExitState)
15899 {
15900 /*
15901 Free Standard Colormap.
15902 */
15903 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15904 if (resource_info->map_type == (char *) NULL)
15905 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15906 /*
15907 Free X resources.
15908 */
15909 if (resource_info->copy_image != (Image *) NULL)
15910 {
15911 resource_info->copy_image=DestroyImage(resource_info->copy_image);
15912 resource_info->copy_image=NewImageList();
15913 }
15914 DestroyXResources();
15915 }
15916 (void) XSync(display,MagickFalse);
15917 /*
15918 Restore our progress monitor and warning handlers.
15919 */
15920 (void) SetErrorHandler(warning_handler);
15921 (void) SetWarningHandler(warning_handler);
15922 /*
15923 Change to home directory.
15924 */
15925 cwd=getcwd(working_directory,MaxTextExtent);
15926 {
15927 int
15928 status;
15929
15930 status=chdir(resource_info->home_directory);
15931 if (status == -1)
15932 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
15933 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
15934 }
15935 *image=display_image;
15936 return(nexus);
15937}
15938#else
15939
15940/*
15941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15942% %
15943% %
15944% %
15945+ D i s p l a y I m a g e s %
15946% %
15947% %
15948% %
15949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15950%
15951% DisplayImages() displays an image sequence to any X window screen. It
15952% returns a value other than 0 if successful. Check the exception member
15953% of image to determine the reason for any failure.
15954%
15955% The format of the DisplayImages method is:
15956%
15957% MagickBooleanType DisplayImages(const ImageInfo *image_info,
15958% Image *images)
15959%
15960% A description of each parameter follows:
15961%
15962% o image_info: the image info.
15963%
15964% o image: the image.
15965%
15966*/
15967MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
15968 Image *image)
15969{
15970 assert(image_info != (const ImageInfo *) NULL);
15971 assert(image_info->signature == MagickSignature);
15972 assert(image != (Image *) NULL);
15973 assert(image->signature == MagickSignature);
15974 if (image->debug != MagickFalse)
15975 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
15976 (void) ThrowMagickException(&image->exception,GetMagickModule(),
15977 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
15978 image->filename);
15979 return(MagickFalse);
15980}
15981
15982/*
15983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15984% %
15985% %
15986% %
15987+ R e m o t e D i s p l a y C o m m a n d %
15988% %
15989% %
15990% %
15991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15992%
15993% RemoteDisplayCommand() encourages a remote display program to display the
15994% specified image filename.
15995%
15996% The format of the RemoteDisplayCommand method is:
15997%
15998% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
15999% const char *window,const char *filename,ExceptionInfo *exception)
16000%
16001% A description of each parameter follows:
16002%
16003% o image_info: the image info.
16004%
16005% o window: Specifies the name or id of an X window.
16006%
16007% o filename: the name of the image filename to display.
16008%
16009% o exception: return any errors or warnings in this structure.
16010%
16011*/
16012MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16013 const char *window,const char *filename,ExceptionInfo *exception)
16014{
16015 assert(image_info != (const ImageInfo *) NULL);
16016 assert(image_info->signature == MagickSignature);
16017 assert(filename != (char *) NULL);
16018 (void) window;
16019 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16020 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16021 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16022 return(MagickFalse);
16023}
16024#endif