2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
10 % DDDD IIIII SSSSS P LLLLL A A Y %
13 % MagickCore Methods to Interactively Display and Edit an Image %
20 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
83 #include "magick/string-private.h"
84 #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"
91 #if defined(MAGICKCORE_X11_DELEGATE)
95 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
98 Constant declarations.
100 static const unsigned char
103 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
135 Help widget declarations.
138 *ImageAnnotateHelp[] =
140 "In annotate mode, the Command widget has these options:",
190 "Choose a font name from the Font Name sub-menu. Additional",
191 "font names can be specified with the font browser. You can",
192 "change the menu names by setting the X resources font1",
195 "Choose a font color from the Font Color sub-menu.",
196 "Additional font colors can be specified with the color",
197 "browser. You can change the menu colors by setting the X",
198 "resources pen1 through pen9.",
200 "If you select the color browser and press Grab, you can",
201 "choose the font color by moving the pointer to the desired",
202 "color on the screen and press any button.",
204 "If you choose to rotate the text, choose Rotate Text from the",
205 "menu and select an angle. Typically you will only want to",
206 "rotate one line of text at a time. Depending on the angle you",
207 "choose, subsequent lines may end up overwriting each other.",
209 "Choosing a font and its color is optional. The default font",
210 "is fixed and the default color is black. However, you must",
211 "choose a location to begin entering text and press button 1.",
212 "An underscore character will appear at the location of the",
213 "pointer. The cursor changes to a pencil to indicate you are",
214 "in text mode. To exit immediately, press Dismiss.",
216 "In text mode, any key presses will display the character at",
217 "the location of the underscore and advance the underscore",
218 "cursor. Enter your text and once completed press Apply to",
219 "finish your image annotation. To correct errors press BACK",
220 "SPACE. To delete an entire line of text, press DELETE. Any",
221 "text that exceeds the boundaries of the image window is",
222 "automagically continued onto the next line.",
224 "The actual color you request for the font is saved in the",
225 "image. However, the color that appears in your image window",
226 "may be different. For example, on a monochrome screen the",
227 "text will appear black or white even if you choose the color",
228 "red as the font color. However, the image saved to a file",
229 "with -write is written with red lettering. To assure the",
230 "correct color text in the final image, any PseudoClass image",
231 "is promoted to DirectClass (see miff(5)). To force a",
232 "PseudoClass image to remain PseudoClass, use -colors.",
237 "In chop mode, the Command widget has these options:",
245 "If the you choose the horizontal direction (this the",
246 "default), the area of the image between the two horizontal",
247 "endpoints of the chop line is removed. Otherwise, the area",
248 "of the image between the two vertical endpoints of the chop",
251 "Select a location within the image window to begin your chop,",
252 "press and hold any button. Next, move the pointer to",
253 "another location in the image. As you move a line will",
254 "connect the initial location and the pointer. When you",
255 "release the button, the area within the image to chop is",
256 "determined by which direction you choose from the Command",
259 "To cancel the image chopping, move the pointer back to the",
260 "starting point of the line and release the button.",
263 *ImageColorEditHelp[] =
265 "In color edit mode, the Command widget has these options:",
306 "Choose a color editing method from the Method sub-menu",
307 "of the Command widget. The point method recolors any pixel",
308 "selected with the pointer until the button is released. The",
309 "replace method recolors any pixel that matches the color of",
310 "the pixel you select with a button press. Floodfill recolors",
311 "any pixel that matches the color of the pixel you select with",
312 "a button press and is a neighbor. Whereas filltoborder recolors",
313 "any neighbor pixel that is not the border color. Finally reset",
314 "changes the entire image to the designated color.",
316 "Next, choose a pixel color from the Pixel Color sub-menu.",
317 "Additional pixel colors can be specified with the color",
318 "browser. You can change the menu colors by setting the X",
319 "resources pen1 through pen9.",
321 "Now press button 1 to select a pixel within the image window",
322 "to change its color. Additional pixels may be recolored as",
323 "prescribed by the method you choose.",
325 "If the Magnify widget is mapped, it can be helpful in positioning",
326 "your pointer within the image (refer to button 2).",
328 "The actual color you request for the pixels is saved in the",
329 "image. However, the color that appears in your image window",
330 "may be different. For example, on a monochrome screen the",
331 "pixel will appear black or white even if you choose the",
332 "color red as the pixel color. However, the image saved to a",
333 "file with -write is written with red pixels. To assure the",
334 "correct color text in the final image, any PseudoClass image",
335 "is promoted to DirectClass (see miff(5)). To force a",
336 "PseudoClass image to remain PseudoClass, use -colors.",
339 *ImageCompositeHelp[] =
341 "First a widget window is displayed requesting you to enter an",
342 "image name. Press Composite, Grab or type a file name.",
343 "Press Cancel if you choose not to create a composite image.",
344 "When you choose Grab, move the pointer to the desired window",
345 "and press any button.",
347 "If the Composite image does not have any matte information,",
348 "you are informed and the file browser is displayed again.",
349 "Enter the name of a mask image. The image is typically",
350 "grayscale and the same size as the composite image. If the",
351 "image is not grayscale, it is converted to grayscale and the",
352 "resulting intensities are used as matte information.",
354 "A small window appears showing the location of the cursor in",
355 "the image window. You are now in composite mode. To exit",
356 "immediately, press Dismiss. In composite mode, the Command",
357 "widget has these options:",
383 "Choose a composite operation from the Operators sub-menu of",
384 "the Command widget. How each operator behaves is described",
385 "below. Image window is the image currently displayed on",
386 "your X server and image is the image obtained with the File",
389 "Over The result is the union of the two image shapes,",
390 " with image obscuring image window in the region of",
393 "In The result is simply image cut by the shape of",
394 " image window. None of the image data of image",
395 " window is in the result.",
397 "Out The resulting image is image with the shape of",
398 " image window cut out.",
400 "Atop The result is the same shape as image image window,",
401 " with image obscuring image window where the image",
402 " shapes overlap. Note this differs from over",
403 " because the portion of image outside image window's",
404 " shape does not appear in the result.",
406 "Xor The result is the image data from both image and",
407 " image window that is outside the overlap region.",
408 " The overlap region is blank.",
410 "Plus The result is just the sum of the image data.",
411 " Output values are cropped to QuantumRange (no overflow).",
413 "Minus The result of image - image window, with underflow",
416 "Add The result of image + image window, with overflow",
417 " wrapping around (mod 256).",
419 "Subtract The result of image - image window, with underflow",
420 " wrapping around (mod 256). The add and subtract",
421 " operators can be used to perform reversible",
425 " The result of abs(image - image window). This",
426 " useful for comparing two very similar images.",
429 " The result of image * image window. This",
430 " useful for the creation of drop-shadows.",
432 "Bumpmap The result of surface normals from image * image",
435 "Copy The resulting image is image window replaced with",
436 " image. Here the matte information is ignored.",
438 "CopyRed The red layer of the image window is replace with",
439 " the red layer of the image. The other layers are",
443 " The green layer of the image window is replace with",
444 " the green layer of the image. The other layers are",
447 "CopyBlue The blue layer of the image window is replace with",
448 " the blue layer of the image. The other layers are",
452 " The matte layer of the image window is replace with",
453 " the matte layer of the image. The other layers are",
456 "The image compositor requires a matte, or alpha channel in",
457 "the image for some operations. This extra channel usually",
458 "defines a mask which represents a sort of a cookie-cutter",
459 "for the image. This the case when matte is opaque (full",
460 "coverage) for pixels inside the shape, zero outside, and",
461 "between 0 and QuantumRange on the boundary. If image does not",
462 "have a matte channel, it is initialized with 0 for any pixel",
463 "matching in color to pixel location (0,0), otherwise QuantumRange.",
465 "If you choose Dissolve, the composite operator becomes Over. The",
466 "image matte channel percent transparency is initialized to factor.",
467 "The image window is initialized to (100-factor). Where factor is the",
468 "value you specify in the Dialog widget.",
470 "Displace shifts the image pixels as defined by a displacement",
471 "map. With this option, image is used as a displacement map.",
472 "Black, within the displacement map, is a maximum positive",
473 "displacement. White is a maximum negative displacement and",
474 "middle gray is neutral. The displacement is scaled to determine",
475 "the pixel shift. By default, the displacement applies in both the",
476 "horizontal and vertical directions. However, if you specify a mask,",
477 "image is the horizontal X displacement and mask the vertical Y",
480 "Note that matte information for image window is not retained",
481 "for colormapped X server visuals (e.g. StaticColor,",
482 "StaticColor, GrayScale, PseudoColor). Correct compositing",
483 "behavior may require a TrueColor or DirectColor visual or a",
484 "Standard Colormap.",
486 "Choosing a composite operator is optional. The default",
487 "operator is replace. However, you must choose a location to",
488 "composite your image and press button 1. Press and hold the",
489 "button before releasing and an outline of the image will",
490 "appear to help you identify your location.",
492 "The actual colors of the composite image is saved. However,",
493 "the color that appears in image window may be different.",
494 "For example, on a monochrome screen image window will appear",
495 "black or white even though your composited image may have",
496 "many colors. If the image is saved to a file it is written",
497 "with the correct colors. To assure the correct colors are",
498 "saved in the final image, any PseudoClass image is promoted",
499 "to DirectClass (see miff(5)). To force a PseudoClass image",
500 "to remain PseudoClass, use -colors.",
505 "In cut mode, the Command widget has these options:",
510 "To define a cut region, press button 1 and drag. The",
511 "cut region is defined by a highlighted rectangle that",
512 "expands or contracts as it follows the pointer. Once you",
513 "are satisfied with the cut region, release the button.",
514 "You are now in rectify mode. In rectify mode, the Command",
515 "widget has these options:",
521 "You can make adjustments by moving the pointer to one of the",
522 "cut rectangle corners, pressing a button, and dragging.",
523 "Finally, press Cut to commit your copy region. To",
524 "exit without cutting the image, press Dismiss.",
529 "In copy mode, the Command widget has these options:",
534 "To define a copy region, press button 1 and drag. The",
535 "copy region is defined by a highlighted rectangle that",
536 "expands or contracts as it follows the pointer. Once you",
537 "are satisfied with the copy region, release the button.",
538 "You are now in rectify mode. In rectify mode, the Command",
539 "widget has these options:",
545 "You can make adjustments by moving the pointer to one of the",
546 "copy rectangle corners, pressing a button, and dragging.",
547 "Finally, press Copy to commit your copy region. To",
548 "exit without copying the image, press Dismiss.",
553 "In crop mode, the Command widget has these options:",
558 "To define a cropping region, press button 1 and drag. The",
559 "cropping region is defined by a highlighted rectangle that",
560 "expands or contracts as it follows the pointer. Once you",
561 "are satisfied with the cropping region, release the button.",
562 "You are now in rectify mode. In rectify mode, the Command",
563 "widget has these options:",
569 "You can make adjustments by moving the pointer to one of the",
570 "cropping rectangle corners, pressing a button, and dragging.",
571 "Finally, press Crop to commit your cropping region. To",
572 "exit without cropping the image, press Dismiss.",
577 "The cursor changes to a crosshair to indicate you are in",
578 "draw mode. To exit immediately, press Dismiss. In draw mode,",
579 "the Command widget has these options:",
624 "Choose a drawing primitive from the Element sub-menu.",
626 "Choose a color from the Color sub-menu. Additional",
627 "colors can be specified with the color browser.",
629 "If you choose the color browser and press Grab, you can",
630 "select the color by moving the pointer to the desired",
631 "color on the screen and press any button. The transparent",
632 "color updates the image matte channel and is useful for",
633 "image compositing.",
635 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
636 "Additional stipples can be specified with the file browser.",
637 "Stipples obtained from the file browser must be on disk in the",
638 "X11 bitmap format.",
640 "Choose a width, if appropriate, from the Width sub-menu. To",
641 "choose a specific width select the Dialog widget.",
643 "Choose a point in the Image window and press button 1 and",
644 "hold. Next, move the pointer to another location in the",
645 "image. As you move, a line connects the initial location and",
646 "the pointer. When you release the button, the image is",
647 "updated with the primitive you just drew. For polygons, the",
648 "image is updated when you press and release the button without",
649 "moving the pointer.",
651 "To cancel image drawing, move the pointer back to the",
652 "starting point of the line and release the button.",
658 " The effects of each button press is described below. Three",
659 " buttons are required. If you have a two button mouse,",
660 " button 1 and 3 are returned. Press ALT and button 3 to",
661 " simulate button 2.",
663 " 1 Press this button to map or unmap the Command widget.",
665 " 2 Press and drag to define a region of the image to",
668 " 3 Press and drag to choose from a select set of commands.",
669 " This button behaves differently if the image being",
670 " displayed is a visual image directory. Here, choose a",
671 " particular tile of the directory and press this button and",
672 " drag to select a command from a pop-up menu. Choose from",
673 " these menu items:",
681 " If you choose Open, the image represented by the tile is",
682 " displayed. To return to the visual image directory, choose",
683 " Next from the Command widget. Next and Former moves to the",
684 " next or former image respectively. Choose Delete to delete",
685 " a particular image tile. Finally, choose Update to",
686 " synchronize all the image tiles with their respective",
690 " The Command widget lists a number of sub-menus and commands.",
702 " Visual Directory...",
736 " Contrast Stretch...",
737 " Sigmoidal Contrast...",
765 " Charcoal Drawing...",
776 " Region of Interest...",
788 " Browse Documentation",
791 " Menu items with a indented triangle have a sub-menu. They",
792 " are represented above as the indented items. To access a",
793 " sub-menu item, move the pointer to the appropriate menu and",
794 " press a button and drag. When you find the desired sub-menu",
795 " item, release the button and the command is executed. Move",
796 " the pointer away from the sub-menu if you decide not to",
797 " execute a particular command.",
799 "KEYBOARD ACCELERATORS",
800 " Accelerators are one or two key presses that effect a",
801 " particular command. The keyboard accelerators that",
802 " display(1) understands is:",
804 " Ctl+O Press to open an image from a file.",
806 " space Press to display the next image.",
808 " If the image is a multi-paged document such as a Postscript",
809 " document, you can skip ahead several pages by preceding",
810 " this command with a number. For example to display the",
811 " third page beyond the current page, press 3<space>.",
813 " backspace Press to display the former image.",
815 " If the image is a multi-paged document such as a Postscript",
816 " document, you can skip behind several pages by preceding",
817 " this command with a number. For example to display the",
818 " third page preceding the current page, press 3<backspace>.",
820 " Ctl+S Press to write the image to a file.",
822 " Ctl+P Press to print the image to a Postscript printer.",
824 " Ctl+D Press to delete an image file.",
826 " Ctl+N Press to create a blank canvas.",
828 " Ctl+Q Press to discard all images and exit program.",
830 " Ctl+Z Press to undo last image transformation.",
832 " Ctl+R Press to redo last image transformation.",
834 " Ctl+X Press to cut a region of the image.",
836 " Ctl+C Press to copy a region of the image.",
838 " Ctl+V Press to paste a region to the image.",
840 " < Press to half the image size.",
842 " - Press to return to the original image size.",
844 " > Press to double the image size.",
846 " % Press to resize the image to a width and height you",
849 "Cmd-A Press to make any image transformations permanent."
851 " By default, any image size transformations are applied",
852 " to the original image to create the image displayed on",
853 " the X server. However, the transformations are not",
854 " permanent (i.e. the original image does not change",
855 " size only the X image does). For example, if you",
856 " press > the X image will appear to double in size,",
857 " but the original image will in fact remain the same size.",
858 " To force the original image to double in size, press >",
859 " followed by Cmd-A.",
861 " @ Press to refresh the image window.",
863 " C Press to cut out a rectangular region of the image.",
865 " [ Press to chop the image.",
867 " H Press to flop image in the horizontal direction.",
869 " V Press to flip image in the vertical direction.",
871 " / Press to rotate the image 90 degrees clockwise.",
873 " \\ Press to rotate the image 90 degrees counter-clockwise.",
875 " * Press to rotate the image the number of degrees you",
878 " S Press to shear the image the number of degrees you",
881 " R Press to roll the image.",
883 " T Press to trim the image edges.",
885 " Shft-H Press to vary the image hue.",
887 " Shft-S Press to vary the color saturation.",
889 " Shft-L Press to vary the color brightness.",
891 " Shft-G Press to gamma correct the image.",
893 " Shft-C Press to sharpen the image contrast.",
895 " Shft-Z Press to dull the image contrast.",
897 " = Press to perform histogram equalization on the image.",
899 " Shft-N Press to perform histogram normalization on the image.",
901 " Shft-~ Press to negate the colors of the image.",
903 " . Press to convert the image colors to gray.",
905 " Shft-# Press to set the maximum number of unique colors in the",
908 " F2 Press to reduce the speckles in an image.",
910 " F3 Press to eliminate peak noise from an image.",
912 " F4 Press to add noise to an image.",
914 " F5 Press to sharpen an image.",
916 " F6 Press to delete an image file.",
918 " F7 Press to threshold the image.",
920 " F8 Press to detect edges within an image.",
922 " F9 Press to emboss an image.",
924 " F10 Press to displace pixels by a random amount.",
926 " F11 Press to negate all pixels above the threshold level.",
928 " F12 Press to shade the image using a distant light source.",
930 " F13 Press to lighten or darken image edges to create a 3-D effect.",
932 " F14 Press to segment the image by color.",
934 " Meta-S Press to swirl image pixels about the center.",
936 " Meta-I Press to implode image pixels about the center.",
938 " Meta-W Press to alter an image along a sine wave.",
940 " Meta-P Press to simulate an oil painting.",
942 " Meta-C Press to simulate a charcoal drawing.",
944 " Alt-A Press to annotate the image with text.",
946 " Alt-D Press to draw on an image.",
948 " Alt-P Press to edit an image pixel color.",
950 " Alt-M Press to edit the image matte information.",
952 " Alt-V Press to composite the image with another.",
954 " Alt-B Press to add a border to the image.",
956 " Alt-F Press to add an ornamental border to the image.",
959 " Press to add an image comment.",
961 " Ctl-A Press to apply image processing techniques to a region",
964 " Shft-? Press to display information about the image.",
966 " Shft-+ Press to map the zoom image window.",
968 " Shft-P Press to preview an image enhancement, effect, or f/x.",
970 " F1 Press to display helpful information about display(1).",
972 " Find Press to browse documentation about ImageMagick.",
974 " 1-9 Press to change the level of magnification.",
976 " Use the arrow keys to move the image one pixel up, down,",
977 " left, or right within the magnify window. Be sure to first",
978 " map the magnify window by pressing button 2.",
980 " Press ALT and one of the arrow keys to trim off one pixel",
981 " from any side of the image.",
984 *ImageMatteEditHelp[] =
986 "Matte information within an image is useful for some",
987 "operations such as image compositing (See IMAGE",
988 "COMPOSITING). This extra channel usually defines a mask",
989 "which represents a sort of a cookie-cutter for the image.",
990 "This the case when matte is opaque (full coverage) for",
991 "pixels inside the shape, zero outside, and between 0 and",
992 "QuantumRange on the boundary.",
994 "A small window appears showing the location of the cursor in",
995 "the image window. You are now in matte edit mode. To exit",
996 "immediately, press Dismiss. In matte edit mode, the Command",
997 "widget has these options:",
1031 "Choose a matte editing method from the Method sub-menu of",
1032 "the Command widget. The point method changes the matte value",
1033 "of any pixel selected with the pointer until the button is",
1034 "is released. The replace method changes the matte value of",
1035 "any pixel that matches the color of the pixel you select with",
1036 "a button press. Floodfill changes the matte value of any pixel",
1037 "that matches the color of the pixel you select with a button",
1038 "press and is a neighbor. Whereas filltoborder changes the matte",
1039 "value any neighbor pixel that is not the border color. Finally",
1040 "reset changes the entire image to the designated matte value.",
1042 "Choose Matte Value and pick Opaque or Transarent. For other values",
1043 "select the Dialog entry. Here a dialog appears requesting a matte",
1044 "value. The value you select is assigned as the opacity value of the",
1045 "selected pixel or pixels.",
1047 "Now, press any button to select a pixel within the image",
1048 "window to change its matte value.",
1050 "If the Magnify widget is mapped, it can be helpful in positioning",
1051 "your pointer within the image (refer to button 2).",
1053 "Matte information is only valid in a DirectClass image.",
1054 "Therefore, any PseudoClass image is promoted to DirectClass",
1055 "(see miff(5)). Note that matte information for PseudoClass",
1056 "is not retained for colormapped X server visuals (e.g.",
1057 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1058 "immediately save your image to a file (refer to Write).",
1059 "Correct matte editing behavior may require a TrueColor or",
1060 "DirectColor visual or a Standard Colormap.",
1065 "When an image exceeds the width or height of the X server",
1066 "screen, display maps a small panning icon. The rectangle",
1067 "within the panning icon shows the area that is currently",
1068 "displayed in the image window. To pan about the image,",
1069 "press any button and drag the pointer within the panning",
1070 "icon. The pan rectangle moves with the pointer and the",
1071 "image window is updated to reflect the location of the",
1072 "rectangle within the panning icon. When you have selected",
1073 "the area of the image you wish to view, release the button.",
1075 "Use the arrow keys to pan the image one pixel up, down,",
1076 "left, or right within the image window.",
1078 "The panning icon is withdrawn if the image becomes smaller",
1079 "than the dimensions of the X server screen.",
1084 "A small window appears showing the location of the cursor in",
1085 "the image window. You are now in paste mode. To exit",
1086 "immediately, press Dismiss. In paste mode, the Command",
1087 "widget has these options:",
1104 "Choose a composite operation from the Operators sub-menu of",
1105 "the Command widget. How each operator behaves is described",
1106 "below. Image window is the image currently displayed on",
1107 "your X server and image is the image obtained with the File",
1110 "Over The result is the union of the two image shapes,",
1111 " with image obscuring image window in the region of",
1114 "In The result is simply image cut by the shape of",
1115 " image window. None of the image data of image",
1116 " window is in the result.",
1118 "Out The resulting image is image with the shape of",
1119 " image window cut out.",
1121 "Atop The result is the same shape as image image window,",
1122 " with image obscuring image window where the image",
1123 " shapes overlap. Note this differs from over",
1124 " because the portion of image outside image window's",
1125 " shape does not appear in the result.",
1127 "Xor The result is the image data from both image and",
1128 " image window that is outside the overlap region.",
1129 " The overlap region is blank.",
1131 "Plus The result is just the sum of the image data.",
1132 " Output values are cropped to QuantumRange (no overflow).",
1133 " This operation is independent of the matte",
1136 "Minus The result of image - image window, with underflow",
1137 " cropped to zero.",
1139 "Add The result of image + image window, with overflow",
1140 " wrapping around (mod 256).",
1142 "Subtract The result of image - image window, with underflow",
1143 " wrapping around (mod 256). The add and subtract",
1144 " operators can be used to perform reversible",
1145 " transformations.",
1148 " The result of abs(image - image window). This",
1149 " useful for comparing two very similar images.",
1151 "Copy The resulting image is image window replaced with",
1152 " image. Here the matte information is ignored.",
1154 "CopyRed The red layer of the image window is replace with",
1155 " the red layer of the image. The other layers are",
1159 " The green layer of the image window is replace with",
1160 " the green layer of the image. The other layers are",
1163 "CopyBlue The blue layer of the image window is replace with",
1164 " the blue layer of the image. The other layers are",
1168 " The matte layer of the image window is replace with",
1169 " the matte layer of the image. The other layers are",
1172 "The image compositor requires a matte, or alpha channel in",
1173 "the image for some operations. This extra channel usually",
1174 "defines a mask which represents a sort of a cookie-cutter",
1175 "for the image. This the case when matte is opaque (full",
1176 "coverage) for pixels inside the shape, zero outside, and",
1177 "between 0 and QuantumRange on the boundary. If image does not",
1178 "have a matte channel, it is initialized with 0 for any pixel",
1179 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1181 "Note that matte information for image window is not retained",
1182 "for colormapped X server visuals (e.g. StaticColor,",
1183 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1184 "behavior may require a TrueColor or DirectColor visual or a",
1185 "Standard Colormap.",
1187 "Choosing a composite operator is optional. The default",
1188 "operator is replace. However, you must choose a location to",
1189 "paste your image and press button 1. Press and hold the",
1190 "button before releasing and an outline of the image will",
1191 "appear to help you identify your location.",
1193 "The actual colors of the pasted image is saved. However,",
1194 "the color that appears in image window may be different.",
1195 "For example, on a monochrome screen image window will appear",
1196 "black or white even though your pasted image may have",
1197 "many colors. If the image is saved to a file it is written",
1198 "with the correct colors. To assure the correct colors are",
1199 "saved in the final image, any PseudoClass image is promoted",
1200 "to DirectClass (see miff(5)). To force a PseudoClass image",
1201 "to remain PseudoClass, use -colors.",
1206 "In region of interest mode, the Command widget has these",
1212 "To define a region of interest, press button 1 and drag.",
1213 "The region of interest is defined by a highlighted rectangle",
1214 "that expands or contracts as it follows the pointer. Once",
1215 "you are satisfied with the region of interest, release the",
1216 "button. You are now in apply mode. In apply mode the",
1217 "Command widget has these options:",
1237 " Contrast Stretch",
1238 " Sigmoidal Contrast...",
1265 " Charcoal Drawing...",
1275 "You can make adjustments to the region of interest by moving",
1276 "the pointer to one of the rectangle corners, pressing a",
1277 "button, and dragging. Finally, choose an image processing",
1278 "technique from the Command widget. You can choose more than",
1279 "one image processing technique to apply to an area.",
1280 "Alternatively, you can move the region of interest before",
1281 "applying another image processing technique. To exit, press",
1285 *ImageRotateHelp[] =
1287 "In rotate mode, the Command widget has these options:",
1306 "Choose a background color from the Pixel Color sub-menu.",
1307 "Additional background colors can be specified with the color",
1308 "browser. You can change the menu colors by setting the X",
1309 "resources pen1 through pen9.",
1311 "If you choose the color browser and press Grab, you can",
1312 "select the background color by moving the pointer to the",
1313 "desired color on the screen and press any button.",
1315 "Choose a point in the image window and press this button and",
1316 "hold. Next, move the pointer to another location in the",
1317 "image. As you move a line connects the initial location and",
1318 "the pointer. When you release the button, the degree of",
1319 "image rotation is determined by the slope of the line you",
1320 "just drew. The slope is relative to the direction you",
1321 "choose from the Direction sub-menu of the Command widget.",
1323 "To cancel the image rotation, move the pointer back to the",
1324 "starting point of the line and release the button.",
1329 Enumeration declarations.
1348 VisualDirectoryCommand,
1356 OriginalSizeCommand,
1378 ContrastStretchCommand,
1379 SigmoidalContrastCommand,
1405 CharcoalDrawCommand,
1415 RegionofInterestCommand,
1421 ShowHistogramCommand,
1427 BrowseDocumentationCommand,
1429 SaveToUndoBufferCommand,
1436 AnnotateNameCommand,
1437 AnnotateFontColorCommand,
1438 AnnotateBackgroundColorCommand,
1439 AnnotateRotateCommand,
1440 AnnotateHelpCommand,
1441 AnnotateDismissCommand,
1444 ChopDirectionCommand,
1447 HorizontalChopCommand,
1448 VerticalChopCommand,
1449 ColorEditMethodCommand,
1450 ColorEditColorCommand,
1451 ColorEditBorderCommand,
1452 ColorEditFuzzCommand,
1453 ColorEditUndoCommand,
1454 ColorEditHelpCommand,
1455 ColorEditDismissCommand,
1456 CompositeOperatorsCommand,
1457 CompositeDissolveCommand,
1458 CompositeDisplaceCommand,
1459 CompositeHelpCommand,
1460 CompositeDismissCommand,
1465 RectifyDismissCommand,
1474 MatteEditBorderCommand,
1475 MatteEditFuzzCommand,
1476 MatteEditValueCommand,
1477 MatteEditUndoCommand,
1478 MatteEditHelpCommand,
1479 MatteEditDismissCommand,
1480 PasteOperatorsCommand,
1482 PasteDismissCommand,
1484 RotateDirectionCommand,
1486 RotateSharpenCommand,
1488 RotateDismissCommand,
1489 HorizontalRotateCommand,
1490 VerticalRotateCommand,
1501 #define BricksWidth 20
1502 #define BricksHeight 20
1503 #define DiagonalWidth 16
1504 #define DiagonalHeight 16
1505 #define HighlightWidth 8
1506 #define HighlightHeight 8
1507 #define OpaqueWidth 8
1508 #define OpaqueHeight 8
1509 #define ScalesWidth 16
1510 #define ScalesHeight 16
1511 #define ShadowWidth 8
1512 #define ShadowHeight 8
1513 #define VerticalWidth 16
1514 #define VerticalHeight 16
1515 #define WavyWidth 16
1516 #define WavyHeight 16
1519 Constant declaration.
1524 static const unsigned char
1527 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1528 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1529 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1530 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1531 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1535 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1536 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1537 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1541 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1542 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1543 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1547 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1548 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1549 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1553 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1554 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1555 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1559 Function prototypes.
1562 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1563 const MagickStatusType,KeySym,Image **);
1566 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1568 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1569 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1570 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1572 static MagickBooleanType
1573 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1574 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1575 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1576 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1577 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1578 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1579 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1580 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1581 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1582 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1583 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1584 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1585 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1586 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1587 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1590 XDrawPanRectangle(Display *,XWindows *),
1591 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
1592 XMagnifyImage(Display *,XWindows *,XEvent *),
1593 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1594 XPanImage(Display *,XWindows *,XEvent *),
1595 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1597 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1598 XScreenEvent(Display *,XWindows *,XEvent *),
1599 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606 % D i s p l a y I m a g e s %
1610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1612 % DisplayImages() displays an image sequence to any X window screen. It
1613 % returns a value other than 0 if successful. Check the exception member
1614 % of image to determine the reason for any failure.
1616 % The format of the DisplayImages method is:
1618 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1621 % A description of each parameter follows:
1623 % o image_info: the image info.
1625 % o image: the image.
1628 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1652 assert(image_info != (const ImageInfo *) NULL);
1653 assert(image_info->signature == MagickSignature);
1654 assert(images != (Image *) NULL);
1655 assert(images->signature == MagickSignature);
1656 if (images->debug != MagickFalse)
1657 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1658 display=XOpenDisplay(image_info->server_name);
1659 if (display == (Display *) NULL)
1661 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1662 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1663 image_info->server_name));
1664 return(MagickFalse);
1666 if (images->exception.severity != UndefinedException)
1667 CatchException(&images->exception);
1668 (void) XSetErrorHandler(XError);
1669 resource_database=XGetResourceDatabase(display,GetClientName());
1670 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1671 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1672 if (image_info->page != (char *) NULL)
1673 resource_info.image_geometry=AcquireString(image_info->page);
1674 resource_info.immutable=MagickTrue;
1675 argv[0]=AcquireString(GetClientName());
1677 for (i=0; (state & ExitState) == 0; i++)
1679 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1681 image=GetImageFromList(images,i % GetImageListLength(images));
1682 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1684 argv[0]=DestroyString(argv[0]);
1685 (void) XCloseDisplay(display);
1686 XDestroyResourceInfo(&resource_info);
1687 if (images->exception.severity != UndefinedException)
1688 return(MagickFalse);
1693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697 % R e m o t e D i s p l a y C o m m a n d %
1701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 % RemoteDisplayCommand() encourages a remote display program to display the
1704 % specified image filename.
1706 % The format of the RemoteDisplayCommand method is:
1708 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1709 % const char *window,const char *filename,ExceptionInfo *exception)
1711 % A description of each parameter follows:
1713 % o image_info: the image info.
1715 % o window: Specifies the name or id of an X window.
1717 % o filename: the name of the image filename to display.
1719 % o exception: return any errors or warnings in this structure.
1722 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1723 const char *window,const char *filename,ExceptionInfo *exception)
1731 assert(image_info != (const ImageInfo *) NULL);
1732 assert(image_info->signature == MagickSignature);
1733 assert(filename != (char *) NULL);
1734 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1735 display=XOpenDisplay(image_info->server_name);
1736 if (display == (Display *) NULL)
1738 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1739 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1740 return(MagickFalse);
1742 (void) XSetErrorHandler(XError);
1743 status=XRemoteCommand(display,window,filename);
1744 (void) XCloseDisplay(display);
1745 return(status != 0 ? MagickTrue : MagickFalse);
1749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753 + X A n n o t a t e E d i t I m a g e %
1757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759 % XAnnotateEditImage() annotates the image with text.
1761 % The format of the XAnnotateEditImage method is:
1763 % MagickBooleanType XAnnotateEditImage(Display *display,
1764 % XResourceInfo *resource_info,XWindows *windows,Image *image)
1766 % A description of each parameter follows:
1768 % o display: Specifies a connection to an X server; returned from
1771 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1773 % o windows: Specifies a pointer to a XWindows structure.
1775 % o image: the image; returned from ReadImage.
1779 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1786 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1793 static MagickBooleanType XAnnotateEditImage(Display *display,
1794 XResourceInfo *resource_info,XWindows *windows,Image *image)
1814 static const ModeType
1815 AnnotateCommands[] =
1817 AnnotateNameCommand,
1818 AnnotateFontColorCommand,
1819 AnnotateBackgroundColorCommand,
1820 AnnotateRotateCommand,
1821 AnnotateHelpCommand,
1822 AnnotateDismissCommand
1830 static MagickBooleanType
1831 transparent_box = MagickTrue,
1832 transparent_pen = MagickFalse;
1834 static MagickRealType
1838 box_id = MaxNumberPens-2,
1843 command[MaxTextExtent],
1844 text[MaxTextExtent];
1847 *ColorMenu[MaxNumberPens+1];
1895 (void) CloneString(&windows->command.name,"Annotate");
1896 windows->command.data=4;
1897 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1898 (void) XMapRaised(display,windows->command.id);
1899 XClientMessage(display,windows->image.id,windows->im_protocols,
1900 windows->im_update_widget,CurrentTime);
1902 Track pointer until button 1 is pressed.
1904 XQueryPosition(display,windows->image.id,&x,&y);
1905 (void) XSelectInput(display,windows->image.id,
1906 windows->image.attributes.event_mask | PointerMotionMask);
1907 cursor=XCreateFontCursor(display,XC_left_side);
1908 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1912 if (windows->info.mapped != MagickFalse)
1915 Display pointer position.
1917 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
1918 x+windows->image.x,y+windows->image.y);
1919 XInfoWidget(display,windows,text);
1922 Wait for next event.
1924 XScreenEvent(display,windows,&event);
1925 if (event.xany.window == windows->command.id)
1928 Select a command from the Command widget.
1930 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1931 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1934 switch (AnnotateCommands[id])
1936 case AnnotateNameCommand:
1939 *FontMenu[MaxNumberFonts];
1945 Initialize menu selections.
1947 for (i=0; i < MaxNumberFonts; i++)
1948 FontMenu[i]=resource_info->font_name[i];
1949 FontMenu[MaxNumberFonts-2]="Browser...";
1950 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1952 Select a font name from the pop-up menu.
1954 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1955 (const char **) FontMenu,command);
1956 if (font_number < 0)
1958 if (font_number == (MaxNumberFonts-2))
1961 font_name[MaxTextExtent] = "fixed";
1964 Select a font name from a browser.
1966 resource_info->font_name[font_number]=font_name;
1967 XFontBrowserWidget(display,windows,"Select",font_name);
1968 if (*font_name == '\0')
1972 Initialize font info.
1974 font_info=XLoadQueryFont(display,resource_info->font_name[
1976 if (font_info == (XFontStruct *) NULL)
1978 XNoticeWidget(display,windows,"Unable to load font:",
1979 resource_info->font_name[font_number]);
1982 font_id=(unsigned int) font_number;
1983 (void) XFreeFont(display,font_info);
1986 case AnnotateFontColorCommand:
1989 Initialize menu selections.
1991 for (i=0; i < (int) (MaxNumberPens-2); i++)
1992 ColorMenu[i]=resource_info->pen_colors[i];
1993 ColorMenu[MaxNumberPens-2]="transparent";
1994 ColorMenu[MaxNumberPens-1]="Browser...";
1995 ColorMenu[MaxNumberPens]=(const char *) NULL;
1997 Select a pen color from the pop-up menu.
1999 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2000 (const char **) ColorMenu,command);
2003 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2005 if (transparent_pen != MagickFalse)
2007 if (pen_number == (MaxNumberPens-1))
2010 color_name[MaxTextExtent] = "gray";
2013 Select a pen color from a dialog.
2015 resource_info->pen_colors[pen_number]=color_name;
2016 XColorBrowserWidget(display,windows,"Select",color_name);
2017 if (*color_name == '\0')
2023 (void) XParseColor(display,windows->map_info->colormap,
2024 resource_info->pen_colors[pen_number],&color);
2025 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2026 (unsigned int) MaxColors,&color);
2027 windows->pixel_info->pen_colors[pen_number]=color;
2028 pen_id=(unsigned int) pen_number;
2031 case AnnotateBackgroundColorCommand:
2034 Initialize menu selections.
2036 for (i=0; i < (int) (MaxNumberPens-2); i++)
2037 ColorMenu[i]=resource_info->pen_colors[i];
2038 ColorMenu[MaxNumberPens-2]="transparent";
2039 ColorMenu[MaxNumberPens-1]="Browser...";
2040 ColorMenu[MaxNumberPens]=(const char *) NULL;
2042 Select a pen color from the pop-up menu.
2044 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2045 (const char **) ColorMenu,command);
2048 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2050 if (transparent_box != MagickFalse)
2052 if (pen_number == (MaxNumberPens-1))
2055 color_name[MaxTextExtent] = "gray";
2058 Select a pen color from a dialog.
2060 resource_info->pen_colors[pen_number]=color_name;
2061 XColorBrowserWidget(display,windows,"Select",color_name);
2062 if (*color_name == '\0')
2068 (void) XParseColor(display,windows->map_info->colormap,
2069 resource_info->pen_colors[pen_number],&color);
2070 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2071 (unsigned int) MaxColors,&color);
2072 windows->pixel_info->pen_colors[pen_number]=color;
2073 box_id=(unsigned int) pen_number;
2076 case AnnotateRotateCommand:
2082 angle[MaxTextExtent] = "30.0";
2100 Select a command from the pop-up menu.
2102 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2108 degrees=StringToDouble(RotateMenu[entry]);
2111 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2115 degrees=StringToDouble(angle);
2118 case AnnotateHelpCommand:
2120 XTextViewWidget(display,resource_info,windows,MagickFalse,
2121 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2124 case AnnotateDismissCommand:
2142 if (event.xbutton.button != Button1)
2144 if (event.xbutton.window != windows->image.id)
2147 Change to text entering mode.
2160 if (event.xkey.window != windows->image.id)
2163 Respond to a user key press.
2165 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2166 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2167 switch ((int) key_symbol)
2182 XTextViewWidget(display,resource_info,windows,MagickFalse,
2183 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2188 (void) XBell(display,0);
2197 Map and unmap Info widget as cursor crosses its boundaries.
2201 if (windows->info.mapped != MagickFalse)
2203 if ((x < (int) (windows->info.x+windows->info.width)) &&
2204 (y < (int) (windows->info.y+windows->info.height)))
2205 (void) XWithdrawWindow(display,windows->info.id,
2206 windows->info.screen);
2209 if ((x > (int) (windows->info.x+windows->info.width)) ||
2210 (y > (int) (windows->info.y+windows->info.height)))
2211 (void) XMapWindow(display,windows->info.id);
2217 } while ((state & ExitState) == 0);
2218 (void) XSelectInput(display,windows->image.id,
2219 windows->image.attributes.event_mask);
2220 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2221 if ((state & EscapeState) != 0)
2224 Set font info and check boundary conditions.
2226 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2227 if (font_info == (XFontStruct *) NULL)
2229 XNoticeWidget(display,windows,"Unable to load font:",
2230 resource_info->font_name[font_id]);
2231 font_info=windows->font_info;
2233 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2234 x=(int) windows->image.width-font_info->max_bounds.width;
2235 if (y < (int) (font_info->ascent+font_info->descent))
2236 y=(int) font_info->ascent+font_info->descent;
2237 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2238 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2239 return(MagickFalse);
2241 Initialize annotate structure.
2243 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2244 if (annotate_info == (XAnnotateInfo *) NULL)
2245 return(MagickFalse);
2246 XGetAnnotateInfo(annotate_info);
2249 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2250 annotate_info->stencil=OpaqueStencil;
2252 if (transparent_box == MagickFalse)
2253 annotate_info->stencil=BackgroundStencil;
2255 annotate_info->stencil=ForegroundStencil;
2256 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2257 annotate_info->degrees=degrees;
2258 annotate_info->font_info=font_info;
2259 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2260 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2261 sizeof(*annotate_info->text));
2262 if (annotate_info->text == (char *) NULL)
2263 return(MagickFalse);
2265 Create cursor and set graphic context.
2267 cursor=XCreateFontCursor(display,XC_pencil);
2268 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2269 annotate_context=windows->image.annotate_context;
2270 (void) XSetFont(display,annotate_context,font_info->fid);
2271 (void) XSetBackground(display,annotate_context,
2272 windows->pixel_info->pen_colors[box_id].pixel);
2273 (void) XSetForeground(display,annotate_context,
2274 windows->pixel_info->pen_colors[pen_id].pixel);
2276 Begin annotating the image with text.
2278 (void) CloneString(&windows->command.name,"Text");
2279 windows->command.data=0;
2280 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2282 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2283 text_event.xexpose.width=(int) font_info->max_bounds.width;
2284 text_event.xexpose.height=font_info->max_bounds.ascent+
2285 font_info->max_bounds.descent;
2286 p=annotate_info->text;
2290 Display text cursor.
2293 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2295 Wait for next event.
2297 XScreenEvent(display,windows,&event);
2298 if (event.xany.window == windows->command.id)
2301 Select a command from the Command widget.
2303 (void) XSetBackground(display,annotate_context,
2304 windows->pixel_info->background_color.pixel);
2305 (void) XSetForeground(display,annotate_context,
2306 windows->pixel_info->foreground_color.pixel);
2307 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2308 (void) XSetBackground(display,annotate_context,
2309 windows->pixel_info->pen_colors[box_id].pixel);
2310 (void) XSetForeground(display,annotate_context,
2311 windows->pixel_info->pen_colors[pen_id].pixel);
2314 switch (TextCommands[id])
2316 case TextHelpCommand:
2318 XTextViewWidget(display,resource_info,windows,MagickFalse,
2319 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2320 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2323 case TextApplyCommand:
2326 Finished annotating.
2328 annotate_info->width=(unsigned int) XTextWidth(font_info,
2329 annotate_info->text,(int) strlen(annotate_info->text));
2330 XRefreshWindow(display,&windows->image,&text_event);
2342 text_event.xexpose.x=x;
2343 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2344 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2345 (unsigned int) text_event.xexpose.width,(unsigned int)
2346 text_event.xexpose.height,MagickFalse);
2347 XRefreshWindow(display,&windows->image,&text_event);
2352 if (event.xbutton.window != windows->image.id)
2354 if (event.xbutton.button == Button2)
2357 Request primary selection.
2359 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2360 windows->image.id,CurrentTime);
2367 if (event.xexpose.count == 0)
2373 Refresh Image window.
2375 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2376 text_info=annotate_info;
2377 while (text_info != (XAnnotateInfo *) NULL)
2379 if (annotate_info->stencil == ForegroundStencil)
2380 (void) XDrawString(display,windows->image.id,annotate_context,
2381 text_info->x,text_info->y,text_info->text,
2382 (int) strlen(text_info->text));
2384 (void) XDrawImageString(display,windows->image.id,
2385 annotate_context,text_info->x,text_info->y,text_info->text,
2386 (int) strlen(text_info->text));
2387 text_info=text_info->previous;
2389 (void) XDrawString(display,windows->image.id,annotate_context,
2399 if (event.xkey.window != windows->image.id)
2402 Respond to a user key press.
2404 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2405 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2406 *(command+length)='\0';
2407 if (((event.xkey.state & ControlMask) != 0) ||
2408 ((event.xkey.state & Mod1Mask) != 0))
2409 state|=ModifierState;
2410 if ((state & ModifierState) != 0)
2411 switch ((int) key_symbol)
2416 key_symbol=DeleteCommand;
2422 switch ((int) key_symbol)
2427 Erase one character.
2429 if (p == annotate_info->text)
2431 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2436 Go to end of the previous line of text.
2438 annotate_info=annotate_info->previous;
2439 p=annotate_info->text;
2440 x=annotate_info->x+annotate_info->width;
2442 if (annotate_info->width != 0)
2443 p+=strlen(annotate_info->text);
2448 x-=XTextWidth(font_info,p,1);
2449 text_event.xexpose.x=x;
2450 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2451 XRefreshWindow(display,&windows->image,&text_event);
2454 case XK_bracketleft:
2456 key_symbol=XK_Escape;
2462 Erase the entire line of text.
2464 while (p != annotate_info->text)
2467 x-=XTextWidth(font_info,p,1);
2468 text_event.xexpose.x=x;
2469 XRefreshWindow(display,&windows->image,&text_event);
2477 Finished annotating.
2479 annotate_info->width=(unsigned int) XTextWidth(font_info,
2480 annotate_info->text,(int) strlen(annotate_info->text));
2481 XRefreshWindow(display,&windows->image,&text_event);
2488 Draw a single character on the Image window.
2490 if ((state & ModifierState) != 0)
2492 if (*command == '\0')
2495 if (annotate_info->stencil == ForegroundStencil)
2496 (void) XDrawString(display,windows->image.id,annotate_context,
2499 (void) XDrawImageString(display,windows->image.id,
2500 annotate_context,x,y,p,1);
2501 x+=XTextWidth(font_info,p,1);
2503 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2510 Advance to the next line of text.
2513 annotate_info->width=(unsigned int) XTextWidth(font_info,
2514 annotate_info->text,(int) strlen(annotate_info->text));
2515 if (annotate_info->next != (XAnnotateInfo *) NULL)
2518 Line of text already exists.
2520 annotate_info=annotate_info->next;
2523 p=annotate_info->text;
2526 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2527 sizeof(*annotate_info->next));
2528 if (annotate_info->next == (XAnnotateInfo *) NULL)
2529 return(MagickFalse);
2530 *annotate_info->next=(*annotate_info);
2531 annotate_info->next->previous=annotate_info;
2532 annotate_info=annotate_info->next;
2533 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2534 windows->image.width/MagickMax((ssize_t)
2535 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2536 if (annotate_info->text == (char *) NULL)
2537 return(MagickFalse);
2538 annotate_info->y+=annotate_info->height;
2539 if (annotate_info->y > (int) windows->image.height)
2540 annotate_info->y=(int) annotate_info->height;
2541 annotate_info->next=(XAnnotateInfo *) NULL;
2544 p=annotate_info->text;
2553 Respond to a user key release.
2555 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2556 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2557 state&=(~ModifierState);
2560 case SelectionNotify:
2576 Obtain response from primary selection.
2578 if (event.xselection.property == (Atom) None)
2580 status=XGetWindowProperty(display,event.xselection.requestor,
2581 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2582 &type,&format,&length,&after,&data);
2583 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2587 Annotate Image window with primary selection.
2589 for (i=0; i < (ssize_t) length; i++)
2591 if ((char) data[i] != '\n')
2594 Draw a single character on the Image window.
2597 (void) XDrawString(display,windows->image.id,annotate_context,
2599 x+=XTextWidth(font_info,p,1);
2601 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2605 Advance to the next line of text.
2608 annotate_info->width=(unsigned int) XTextWidth(font_info,
2609 annotate_info->text,(int) strlen(annotate_info->text));
2610 if (annotate_info->next != (XAnnotateInfo *) NULL)
2613 Line of text already exists.
2615 annotate_info=annotate_info->next;
2618 p=annotate_info->text;
2621 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2622 sizeof(*annotate_info->next));
2623 if (annotate_info->next == (XAnnotateInfo *) NULL)
2624 return(MagickFalse);
2625 *annotate_info->next=(*annotate_info);
2626 annotate_info->next->previous=annotate_info;
2627 annotate_info=annotate_info->next;
2628 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2629 windows->image.width/MagickMax((ssize_t)
2630 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2631 if (annotate_info->text == (char *) NULL)
2632 return(MagickFalse);
2633 annotate_info->y+=annotate_info->height;
2634 if (annotate_info->y > (int) windows->image.height)
2635 annotate_info->y=(int) annotate_info->height;
2636 annotate_info->next=(XAnnotateInfo *) NULL;
2639 p=annotate_info->text;
2641 (void) XFree((void *) data);
2647 } while ((state & ExitState) == 0);
2648 (void) XFreeCursor(display,cursor);
2650 Annotation is relative to image configuration.
2652 width=(unsigned int) image->columns;
2653 height=(unsigned int) image->rows;
2656 if (windows->image.crop_geometry != (char *) NULL)
2657 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2659 Initialize annotated image.
2661 XSetCursorState(display,windows,MagickTrue);
2662 XCheckRefreshWindows(display,windows);
2663 while (annotate_info != (XAnnotateInfo *) NULL)
2665 if (annotate_info->width == 0)
2668 No text on this line-- go to the next line of text.
2670 previous_info=annotate_info->previous;
2671 annotate_info->text=(char *)
2672 RelinquishMagickMemory(annotate_info->text);
2673 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2674 annotate_info=previous_info;
2678 Determine pixel index for box and pen color.
2680 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2681 if (windows->pixel_info->colors != 0)
2682 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2683 if (windows->pixel_info->pixels[i] ==
2684 windows->pixel_info->pen_colors[box_id].pixel)
2686 windows->pixel_info->box_index=(unsigned short) i;
2689 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2690 if (windows->pixel_info->colors != 0)
2691 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2692 if (windows->pixel_info->pixels[i] ==
2693 windows->pixel_info->pen_colors[pen_id].pixel)
2695 windows->pixel_info->pen_index=(unsigned short) i;
2699 Define the annotate geometry string.
2701 annotate_info->x=(int)
2702 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2703 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2704 windows->image.y)/windows->image.ximage->height;
2705 (void) FormatMagickString(annotate_info->geometry,MaxTextExtent,
2706 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2707 height*annotate_info->height/windows->image.ximage->height,
2708 annotate_info->x+x,annotate_info->y+y);
2710 Annotate image with text.
2712 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2714 return(MagickFalse);
2718 previous_info=annotate_info->previous;
2719 annotate_info->text=DestroyString(annotate_info->text);
2720 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2721 annotate_info=previous_info;
2723 (void) XSetForeground(display,annotate_context,
2724 windows->pixel_info->foreground_color.pixel);
2725 (void) XSetBackground(display,annotate_context,
2726 windows->pixel_info->background_color.pixel);
2727 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2728 XSetCursorState(display,windows,MagickFalse);
2729 (void) XFreeFont(display,font_info);
2731 Update image configuration.
2733 XConfigureImageColormap(display,resource_info,windows,image);
2734 (void) XConfigureImage(display,resource_info,windows,image);
2739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743 + X B a c k g r o u n d I m a g e %
2747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749 % XBackgroundImage() displays the image in the background of a window.
2751 % The format of the XBackgroundImage method is:
2753 % MagickBooleanType XBackgroundImage(Display *display,
2754 % XResourceInfo *resource_info,XWindows *windows,Image **image)
2756 % A description of each parameter follows:
2758 % o display: Specifies a connection to an X server; returned from
2761 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2763 % o windows: Specifies a pointer to a XWindows structure.
2765 % o image: the image.
2768 static MagickBooleanType XBackgroundImage(Display *display,
2769 XResourceInfo *resource_info,XWindows *windows,Image **image)
2771 #define BackgroundImageTag "Background/Image"
2777 window_id[MaxTextExtent] = "root";
2780 background_resources;
2783 Put image in background.
2785 status=XDialogWidget(display,windows,"Background",
2786 "Enter window id (id 0x00 selects window with pointer):",window_id);
2787 if (*window_id == '\0')
2788 return(MagickFalse);
2789 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2790 XInfoWidget(display,windows,BackgroundImageTag);
2791 XSetCursorState(display,windows,MagickTrue);
2792 XCheckRefreshWindows(display,windows);
2793 background_resources=(*resource_info);
2794 background_resources.window_id=window_id;
2795 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2796 status=XDisplayBackgroundImage(display,&background_resources,*image);
2797 if (status != MagickFalse)
2798 XClientMessage(display,windows->image.id,windows->im_protocols,
2799 windows->im_retain_colors,CurrentTime);
2800 XSetCursorState(display,windows,MagickFalse);
2801 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810 + X C h o p I m a g e %
2814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2816 % XChopImage() chops the X image.
2818 % The format of the XChopImage method is:
2820 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2821 % XWindows *windows,Image **image)
2823 % A description of each parameter follows:
2825 % o display: Specifies a connection to an X server; returned from
2828 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2830 % o windows: Specifies a pointer to a XWindows structure.
2832 % o image: the image.
2835 static MagickBooleanType XChopImage(Display *display,
2836 XResourceInfo *resource_info,XWindows *windows,Image **image)
2848 direction = HorizontalChopCommand;
2850 static const ModeType
2853 ChopDirectionCommand,
2857 DirectionCommands[] =
2859 HorizontalChopCommand,
2864 text[MaxTextExtent];
2897 (void) CloneString(&windows->command.name,"Chop");
2898 windows->command.data=1;
2899 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2900 (void) XMapRaised(display,windows->command.id);
2901 XClientMessage(display,windows->image.id,windows->im_protocols,
2902 windows->im_update_widget,CurrentTime);
2904 Track pointer until button 1 is pressed.
2906 XQueryPosition(display,windows->image.id,&x,&y);
2907 (void) XSelectInput(display,windows->image.id,
2908 windows->image.attributes.event_mask | PointerMotionMask);
2912 if (windows->info.mapped != MagickFalse)
2915 Display pointer position.
2917 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
2918 x+windows->image.x,y+windows->image.y);
2919 XInfoWidget(display,windows,text);
2922 Wait for next event.
2924 XScreenEvent(display,windows,&event);
2925 if (event.xany.window == windows->command.id)
2928 Select a command from the Command widget.
2930 id=XCommandWidget(display,windows,ChopMenu,&event);
2933 switch (ChopCommands[id])
2935 case ChopDirectionCommand:
2938 command[MaxTextExtent];
2949 Select a command from the pop-up menu.
2951 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2953 direction=DirectionCommands[id];
2956 case ChopHelpCommand:
2958 XTextViewWidget(display,resource_info,windows,MagickFalse,
2959 "Help Viewer - Image Chop",ImageChopHelp);
2962 case ChopDismissCommand:
2980 if (event.xbutton.button != Button1)
2982 if (event.xbutton.window != windows->image.id)
2985 User has committed to start point of chopping line.
2987 segment_info.x1=(short int) event.xbutton.x;
2988 segment_info.x2=(short int) event.xbutton.x;
2989 segment_info.y1=(short int) event.xbutton.y;
2990 segment_info.y2=(short int) event.xbutton.y;
3001 command[MaxTextExtent];
3006 if (event.xkey.window != windows->image.id)
3009 Respond to a user key press.
3011 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3012 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3013 switch ((int) key_symbol)
3028 (void) XSetFunction(display,windows->image.highlight_context,
3030 XTextViewWidget(display,resource_info,windows,MagickFalse,
3031 "Help Viewer - Image Chop",ImageChopHelp);
3032 (void) XSetFunction(display,windows->image.highlight_context,
3038 (void) XBell(display,0);
3047 Map and unmap Info widget as text cursor crosses its boundaries.
3051 if (windows->info.mapped != MagickFalse)
3053 if ((x < (int) (windows->info.x+windows->info.width)) &&
3054 (y < (int) (windows->info.y+windows->info.height)))
3055 (void) XWithdrawWindow(display,windows->info.id,
3056 windows->info.screen);
3059 if ((x > (int) (windows->info.x+windows->info.width)) ||
3060 (y > (int) (windows->info.y+windows->info.height)))
3061 (void) XMapWindow(display,windows->info.id);
3064 } while ((state & ExitState) == 0);
3065 (void) XSelectInput(display,windows->image.id,
3066 windows->image.attributes.event_mask);
3067 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3068 if ((state & EscapeState) != 0)
3071 Draw line as pointer moves until the mouse button is released.
3078 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3085 Display info and draw chopping line.
3087 if (windows->info.mapped == MagickFalse)
3088 (void) XMapWindow(display,windows->info.id);
3089 (void) FormatMagickString(text,MaxTextExtent,
3090 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3091 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3092 XInfoWidget(display,windows,text);
3093 XHighlightLine(display,windows->image.id,
3094 windows->image.highlight_context,&segment_info);
3097 if (windows->info.mapped != MagickFalse)
3098 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3100 Wait for next event.
3102 XScreenEvent(display,windows,&event);
3104 XHighlightLine(display,windows->image.id,
3105 windows->image.highlight_context,&segment_info);
3110 segment_info.x2=(short int) event.xmotion.x;
3111 segment_info.y2=(short int) event.xmotion.y;
3117 User has committed to chopping line.
3119 segment_info.x2=(short int) event.xbutton.x;
3120 segment_info.y2=(short int) event.xbutton.y;
3128 segment_info.x2=(short int) event.xmotion.x;
3129 segment_info.y2=(short int) event.xmotion.y;
3135 Check boundary conditions.
3137 if (segment_info.x2 < 0)
3140 if (segment_info.x2 > windows->image.ximage->width)
3141 segment_info.x2=windows->image.ximage->width;
3142 if (segment_info.y2 < 0)
3145 if (segment_info.y2 > windows->image.ximage->height)
3146 segment_info.y2=windows->image.ximage->height;
3147 distance=(unsigned int)
3148 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3149 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3151 Compute chopping geometry.
3153 if (direction == HorizontalChopCommand)
3155 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3156 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3159 if (segment_info.x1 > (int) segment_info.x2)
3161 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3162 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3168 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3170 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3171 if (segment_info.y1 > segment_info.y2)
3173 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3174 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3177 } while ((state & ExitState) == 0);
3178 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3179 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3183 Image chopping is relative to image configuration.
3185 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3186 XSetCursorState(display,windows,MagickTrue);
3187 XCheckRefreshWindows(display,windows);
3188 windows->image.window_changes.width=windows->image.ximage->width-
3189 (unsigned int) chop_info.width;
3190 windows->image.window_changes.height=windows->image.ximage->height-
3191 (unsigned int) chop_info.height;
3192 width=(unsigned int) (*image)->columns;
3193 height=(unsigned int) (*image)->rows;
3196 if (windows->image.crop_geometry != (char *) NULL)
3197 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3198 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3200 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3201 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3202 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3204 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3205 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3209 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3210 XSetCursorState(display,windows,MagickFalse);
3211 if (chop_image == (Image *) NULL)
3212 return(MagickFalse);
3213 *image=DestroyImage(*image);
3216 Update image configuration.
3218 XConfigureImageColormap(display,resource_info,windows,*image);
3219 (void) XConfigureImage(display,resource_info,windows,*image);
3224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3228 + X C o l o r E d i t I m a g e %
3232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3234 % XColorEditImage() allows the user to interactively change the color of one
3235 % pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3237 % The format of the XColorEditImage method is:
3239 % MagickBooleanType XColorEditImage(Display *display,
3240 % XResourceInfo *resource_info,XWindows *windows,Image **image)
3242 % A description of each parameter follows:
3244 % o display: Specifies a connection to an X server; returned from
3247 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3249 % o windows: Specifies a pointer to a XWindows structure.
3251 % o image: the image; returned from ReadImage.
3256 static MagickBooleanType XColorEditImage(Display *display,
3257 XResourceInfo *resource_info,XWindows *windows,Image **image)
3272 static const ModeType
3273 ColorEditCommands[] =
3275 ColorEditMethodCommand,
3276 ColorEditColorCommand,
3277 ColorEditBorderCommand,
3278 ColorEditFuzzCommand,
3279 ColorEditUndoCommand,
3280 ColorEditHelpCommand,
3281 ColorEditDismissCommand
3285 method = PointMethod;
3291 border_color = { 0, 0, 0, 0, 0, 0 };
3294 command[MaxTextExtent],
3295 text[MaxTextExtent];
3311 register PixelPacket
3333 (void) CloneString(&windows->command.name,"Color Edit");
3334 windows->command.data=4;
3335 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3336 (void) XMapRaised(display,windows->command.id);
3337 XClientMessage(display,windows->image.id,windows->im_protocols,
3338 windows->im_update_widget,CurrentTime);
3342 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3343 resource_info->background_color,resource_info->foreground_color);
3344 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3346 Track pointer until button 1 is pressed.
3348 XQueryPosition(display,windows->image.id,&x,&y);
3349 (void) XSelectInput(display,windows->image.id,
3350 windows->image.attributes.event_mask | PointerMotionMask);
3354 if (windows->info.mapped != MagickFalse)
3357 Display pointer position.
3359 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
3360 x+windows->image.x,y+windows->image.y);
3361 XInfoWidget(display,windows,text);
3364 Wait for next event.
3366 XScreenEvent(display,windows,&event);
3367 if (event.xany.window == windows->command.id)
3370 Select a command from the Command widget.
3372 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3375 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3378 switch (ColorEditCommands[id])
3380 case ColorEditMethodCommand:
3386 Select a method from the pop-up menu.
3388 methods=(char **) GetMagickOptions(MagickMethodOptions);
3389 if (methods == (char **) NULL)
3391 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3392 (const char **) methods,command);
3394 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
3395 MagickFalse,methods[entry]);
3396 methods=DestroyStringList(methods);
3399 case ColorEditColorCommand:
3402 *ColorMenu[MaxNumberPens];
3408 Initialize menu selections.
3410 for (i=0; i < (int) (MaxNumberPens-2); i++)
3411 ColorMenu[i]=resource_info->pen_colors[i];
3412 ColorMenu[MaxNumberPens-2]="Browser...";
3413 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3415 Select a pen color from the pop-up menu.
3417 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3418 (const char **) ColorMenu,command);
3421 if (pen_number == (MaxNumberPens-2))
3424 color_name[MaxTextExtent] = "gray";
3427 Select a pen color from a dialog.
3429 resource_info->pen_colors[pen_number]=color_name;
3430 XColorBrowserWidget(display,windows,"Select",color_name);
3431 if (*color_name == '\0')
3437 (void) XParseColor(display,windows->map_info->colormap,
3438 resource_info->pen_colors[pen_number],&color);
3439 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3440 (unsigned int) MaxColors,&color);
3441 windows->pixel_info->pen_colors[pen_number]=color;
3442 pen_id=(unsigned int) pen_number;
3445 case ColorEditBorderCommand:
3448 *ColorMenu[MaxNumberPens];
3454 Initialize menu selections.
3456 for (i=0; i < (int) (MaxNumberPens-2); i++)
3457 ColorMenu[i]=resource_info->pen_colors[i];
3458 ColorMenu[MaxNumberPens-2]="Browser...";
3459 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3461 Select a pen color from the pop-up menu.
3463 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3464 (const char **) ColorMenu,command);
3467 if (pen_number == (MaxNumberPens-2))
3470 color_name[MaxTextExtent] = "gray";
3473 Select a pen color from a dialog.
3475 resource_info->pen_colors[pen_number]=color_name;
3476 XColorBrowserWidget(display,windows,"Select",color_name);
3477 if (*color_name == '\0')
3483 (void) XParseColor(display,windows->map_info->colormap,
3484 resource_info->pen_colors[pen_number],&border_color);
3487 case ColorEditFuzzCommand:
3490 fuzz[MaxTextExtent];
3505 Select a command from the pop-up menu.
3507 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3513 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
3517 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3518 (void) XDialogWidget(display,windows,"Ok",
3519 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3522 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
3523 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
3526 case ColorEditUndoCommand:
3528 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3532 case ColorEditHelpCommand:
3535 XTextViewWidget(display,resource_info,windows,MagickFalse,
3536 "Help Viewer - Image Annotation",ImageColorEditHelp);
3539 case ColorEditDismissCommand:
3549 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3556 if (event.xbutton.button != Button1)
3558 if ((event.xbutton.window != windows->image.id) &&
3559 (event.xbutton.window != windows->magnify.id))
3566 (void) XMagickCommand(display,resource_info,windows,
3567 SaveToUndoBufferCommand,image);
3568 state|=UpdateConfigurationState;
3573 if (event.xbutton.button != Button1)
3575 if ((event.xbutton.window != windows->image.id) &&
3576 (event.xbutton.window != windows->magnify.id))
3579 Update colormap information.
3583 XConfigureImageColormap(display,resource_info,windows,*image);
3584 (void) XConfigureImage(display,resource_info,windows,*image);
3585 XInfoWidget(display,windows,text);
3586 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3587 state&=(~UpdateConfigurationState);
3597 if (event.xkey.window == windows->magnify.id)
3602 window=windows->magnify.id;
3603 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3605 if (event.xkey.window != windows->image.id)
3608 Respond to a user key press.
3610 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3611 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3612 switch ((int) key_symbol)
3626 XTextViewWidget(display,resource_info,windows,MagickFalse,
3627 "Help Viewer - Image Annotation",ImageColorEditHelp);
3632 (void) XBell(display,0);
3641 Map and unmap Info widget as cursor crosses its boundaries.
3645 if (windows->info.mapped != MagickFalse)
3647 if ((x < (int) (windows->info.x+windows->info.width)) &&
3648 (y < (int) (windows->info.y+windows->info.height)))
3649 (void) XWithdrawWindow(display,windows->info.id,
3650 windows->info.screen);
3653 if ((x > (int) (windows->info.x+windows->info.width)) ||
3654 (y > (int) (windows->info.y+windows->info.height)))
3655 (void) XMapWindow(display,windows->info.id);
3661 if (event.xany.window == windows->magnify.id)
3663 x=windows->magnify.x-windows->image.x;
3664 y=windows->magnify.y-windows->image.y;
3668 if ((state & UpdateConfigurationState) != 0)
3678 Pixel edit is relative to image configuration.
3680 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3682 color=windows->pixel_info->pen_colors[pen_id];
3683 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3684 width=(unsigned int) (*image)->columns;
3685 height=(unsigned int) (*image)->rows;
3688 if (windows->image.crop_geometry != (char *) NULL)
3689 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3692 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3694 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3695 if ((x_offset < 0) || (y_offset < 0))
3697 if ((x_offset >= (int) (*image)->columns) ||
3698 (y_offset >= (int) (*image)->rows))
3700 exception=(&(*image)->exception);
3701 image_view=AcquireCacheView(*image);
3708 Update color information using point algorithm.
3710 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3711 return(MagickFalse);
3712 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3713 (ssize_t)y_offset,1,1,exception);
3714 if (q == (PixelPacket *) NULL)
3716 q->red=ScaleShortToQuantum(color.red);
3717 q->green=ScaleShortToQuantum(color.green);
3718 q->blue=ScaleShortToQuantum(color.blue);
3719 (void) SyncCacheViewAuthenticPixels(image_view,
3720 &(*image)->exception);
3729 Update color information using replace algorithm.
3731 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
3732 (ssize_t) y_offset,&target,&(*image)->exception);
3733 if ((*image)->storage_class == DirectClass)
3735 for (y=0; y < (int) (*image)->rows; y++)
3737 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3738 (*image)->columns,1,exception);
3739 if (q == (PixelPacket *) NULL)
3741 for (x=0; x < (int) (*image)->columns; x++)
3743 if (IsColorSimilar(*image,q,&target))
3745 q->red=ScaleShortToQuantum(color.red);
3746 q->green=ScaleShortToQuantum(color.green);
3747 q->blue=ScaleShortToQuantum(color.blue);
3751 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3757 for (i=0; i < (ssize_t) (*image)->colors; i++)
3758 if (IsColorSimilar(*image,(*image)->colormap+i,&target))
3760 (*image)->colormap[i].red=ScaleShortToQuantum(color.red);
3761 (*image)->colormap[i].green=ScaleShortToQuantum(
3763 (*image)->colormap[i].blue=ScaleShortToQuantum(
3766 (void) SyncImage(*image);
3770 case FloodfillMethod:
3771 case FillToBorderMethod:
3780 Update color information using floodfill algorithm.
3782 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3783 (ssize_t) y_offset,&target,exception);
3784 if (method == FillToBorderMethod)
3786 target.red=(MagickRealType)
3787 ScaleShortToQuantum(border_color.red);
3788 target.green=(MagickRealType)
3789 ScaleShortToQuantum(border_color.green);
3790 target.blue=(MagickRealType)
3791 ScaleShortToQuantum(border_color.blue);
3793 draw_info=CloneDrawInfo(resource_info->image_info,
3795 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3796 &draw_info->fill,exception);
3797 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
3798 (ssize_t) x_offset,(ssize_t) y_offset,
3799 method == FloodfillMethod ? MagickFalse : MagickTrue);
3800 draw_info=DestroyDrawInfo(draw_info);
3806 Update color information using reset algorithm.
3808 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3809 return(MagickFalse);
3810 for (y=0; y < (int) (*image)->rows; y++)
3812 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3813 (*image)->columns,1,exception);
3814 if (q == (PixelPacket *) NULL)
3816 for (x=0; x < (int) (*image)->columns; x++)
3818 q->red=ScaleShortToQuantum(color.red);
3819 q->green=ScaleShortToQuantum(color.green);
3820 q->blue=ScaleShortToQuantum(color.blue);
3823 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3829 image_view=DestroyCacheView(image_view);
3830 state&=(~UpdateConfigurationState);
3832 } while ((state & ExitState) == 0);
3833 (void) XSelectInput(display,windows->image.id,
3834 windows->image.attributes.event_mask);
3835 XSetCursorState(display,windows,MagickFalse);
3836 (void) XFreeCursor(display,cursor);
3841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845 + X C o m p o s i t e I m a g e %
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3851 % XCompositeImage() requests an image name from the user, reads the image and
3852 % composites it with the X window image at a location the user chooses with
3855 % The format of the XCompositeImage method is:
3857 % MagickBooleanType XCompositeImage(Display *display,
3858 % XResourceInfo *resource_info,XWindows *windows,Image *image)
3860 % A description of each parameter follows:
3862 % o display: Specifies a connection to an X server; returned from
3865 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3867 % o windows: Specifies a pointer to a XWindows structure.
3869 % o image: the image; returned from ReadImage.
3872 static MagickBooleanType XCompositeImage(Display *display,
3873 XResourceInfo *resource_info,XWindows *windows,Image *image)
3876 displacement_geometry[MaxTextExtent] = "30x30",
3877 filename[MaxTextExtent] = "\0";
3890 static CompositeOperator
3891 compose = CopyCompositeOp;
3893 static const ModeType
3894 CompositeCommands[] =
3896 CompositeOperatorsCommand,
3897 CompositeDissolveCommand,
3898 CompositeDisplaceCommand,
3899 CompositeHelpCommand,
3900 CompositeDismissCommand
3904 text[MaxTextExtent];
3937 Request image file name from user.
3939 XFileBrowserWidget(display,windows,"Composite",filename);
3940 if (*filename == '\0')
3945 XSetCursorState(display,windows,MagickTrue);
3946 XCheckRefreshWindows(display,windows);
3947 (void) CopyMagickString(resource_info->image_info->filename,filename,
3949 composite_image=ReadImage(resource_info->image_info,&image->exception);
3950 CatchException(&image->exception);
3951 XSetCursorState(display,windows,MagickFalse);
3952 if (composite_image == (Image *) NULL)
3953 return(MagickFalse);
3957 (void) CloneString(&windows->command.name,"Composite");
3958 windows->command.data=1;
3959 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3960 (void) XMapRaised(display,windows->command.id);
3961 XClientMessage(display,windows->image.id,windows->im_protocols,
3962 windows->im_update_widget,CurrentTime);
3964 Track pointer until button 1 is pressed.
3966 XQueryPosition(display,windows->image.id,&x,&y);
3967 (void) XSelectInput(display,windows->image.id,
3968 windows->image.attributes.event_mask | PointerMotionMask);
3969 composite_info.x=(ssize_t) windows->image.x+x;
3970 composite_info.y=(ssize_t) windows->image.y+y;
3971 composite_info.width=0;
3972 composite_info.height=0;
3973 cursor=XCreateFontCursor(display,XC_ul_angle);
3974 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3979 if (windows->info.mapped != MagickFalse)
3982 Display pointer position.
3984 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
3985 (long) composite_info.x,(long) composite_info.y);
3986 XInfoWidget(display,windows,text);
3988 highlight_info=composite_info;
3989 highlight_info.x=composite_info.x-windows->image.x;
3990 highlight_info.y=composite_info.y-windows->image.y;
3991 XHighlightRectangle(display,windows->image.id,
3992 windows->image.highlight_context,&highlight_info);
3994 Wait for next event.
3996 XScreenEvent(display,windows,&event);
3997 XHighlightRectangle(display,windows->image.id,
3998 windows->image.highlight_context,&highlight_info);
3999 if (event.xany.window == windows->command.id)
4002 Select a command from the Command widget.
4004 id=XCommandWidget(display,windows,CompositeMenu,&event);
4007 switch (CompositeCommands[id])
4009 case CompositeOperatorsCommand:
4012 command[MaxTextExtent],
4016 Select a command from the pop-up menu.
4018 operators=GetMagickOptions(MagickComposeOptions);
4019 if (operators == (char **) NULL)
4021 entry=XMenuWidget(display,windows,CompositeMenu[id],
4022 (const char **) operators,command);
4024 compose=(CompositeOperator) ParseMagickOption(
4025 MagickComposeOptions,MagickFalse,operators[entry]);
4026 operators=DestroyStringList(operators);
4029 case CompositeDissolveCommand:
4032 factor[MaxTextExtent] = "20.0";
4035 Dissolve the two images a given percent.
4037 (void) XSetFunction(display,windows->image.highlight_context,
4039 (void) XDialogWidget(display,windows,"Dissolve",
4040 "Enter the blend factor (0.0 - 99.9%):",factor);
4041 (void) XSetFunction(display,windows->image.highlight_context,
4043 if (*factor == '\0')
4045 blend=StringToDouble(factor);
4046 compose=DissolveCompositeOp;
4049 case CompositeDisplaceCommand:
4052 Get horizontal and vertical scale displacement geometry.
4054 (void) XSetFunction(display,windows->image.highlight_context,
4056 (void) XDialogWidget(display,windows,"Displace",
4057 "Enter the horizontal and vertical scale:",displacement_geometry);
4058 (void) XSetFunction(display,windows->image.highlight_context,
4060 if (*displacement_geometry == '\0')
4062 compose=DisplaceCompositeOp;
4065 case CompositeHelpCommand:
4067 (void) XSetFunction(display,windows->image.highlight_context,
4069 XTextViewWidget(display,resource_info,windows,MagickFalse,
4070 "Help Viewer - Image Composite",ImageCompositeHelp);
4071 (void) XSetFunction(display,windows->image.highlight_context,
4075 case CompositeDismissCommand:
4093 if (image->debug != MagickFalse)
4094 (void) LogMagickEvent(X11Event,GetMagickModule(),
4095 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4096 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4097 if (event.xbutton.button != Button1)
4099 if (event.xbutton.window != windows->image.id)
4104 composite_info.width=composite_image->columns;
4105 composite_info.height=composite_image->rows;
4106 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4107 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4108 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4113 if (image->debug != MagickFalse)
4114 (void) LogMagickEvent(X11Event,GetMagickModule(),
4115 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4116 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4117 if (event.xbutton.button != Button1)
4119 if (event.xbutton.window != windows->image.id)
4121 if ((composite_info.width != 0) && (composite_info.height != 0))
4124 User has selected the location of the composite image.
4126 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4127 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4137 command[MaxTextExtent];
4145 if (event.xkey.window != windows->image.id)
4148 Respond to a user key press.
4150 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4151 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4152 *(command+length)='\0';
4153 if (image->debug != MagickFalse)
4154 (void) LogMagickEvent(X11Event,GetMagickModule(),
4155 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4156 switch ((int) key_symbol)
4164 composite_image=DestroyImage(composite_image);
4172 (void) XSetFunction(display,windows->image.highlight_context,
4174 XTextViewWidget(display,resource_info,windows,MagickFalse,
4175 "Help Viewer - Image Composite",ImageCompositeHelp);
4176 (void) XSetFunction(display,windows->image.highlight_context,
4182 (void) XBell(display,0);
4191 Map and unmap Info widget as text cursor crosses its boundaries.
4195 if (windows->info.mapped != MagickFalse)
4197 if ((x < (int) (windows->info.x+windows->info.width)) &&
4198 (y < (int) (windows->info.y+windows->info.height)))
4199 (void) XWithdrawWindow(display,windows->info.id,
4200 windows->info.screen);
4203 if ((x > (int) (windows->info.x+windows->info.width)) ||
4204 (y > (int) (windows->info.y+windows->info.height)))
4205 (void) XMapWindow(display,windows->info.id);
4206 composite_info.x=(ssize_t) windows->image.x+x;
4207 composite_info.y=(ssize_t) windows->image.y+y;
4212 if (image->debug != MagickFalse)
4213 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4218 } while ((state & ExitState) == 0);
4219 (void) XSelectInput(display,windows->image.id,
4220 windows->image.attributes.event_mask);
4221 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4222 XSetCursorState(display,windows,MagickFalse);
4223 (void) XFreeCursor(display,cursor);
4224 if ((state & EscapeState) != 0)
4227 Image compositing is relative to image configuration.
4229 XSetCursorState(display,windows,MagickTrue);
4230 XCheckRefreshWindows(display,windows);
4231 width=(unsigned int) image->columns;
4232 height=(unsigned int) image->rows;
4235 if (windows->image.crop_geometry != (char *) NULL)
4236 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4237 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4238 composite_info.x+=x;
4239 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4240 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4241 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4242 composite_info.y+=y;
4243 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4244 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4245 if ((composite_info.width != composite_image->columns) ||
4246 (composite_info.height != composite_image->rows))
4252 Scale composite image.
4254 resize_image=ResizeImage(composite_image,composite_info.width,
4255 composite_info.height,composite_image->filter,composite_image->blur,
4257 composite_image=DestroyImage(composite_image);
4258 if (resize_image == (Image *) NULL)
4260 XSetCursorState(display,windows,MagickFalse);
4261 return(MagickFalse);
4263 composite_image=resize_image;
4265 if (compose == DisplaceCompositeOp)
4266 (void) SetImageArtifact(composite_image,"compose:args",
4267 displacement_geometry);
4285 register PixelPacket
4289 Create mattes for blending.
4291 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
4292 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
4293 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
4294 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4295 return(MagickFalse);
4296 image->matte=MagickTrue;
4297 exception=(&image->exception);
4298 image_view=AcquireCacheView(image);
4299 for (y=0; y < (int) image->rows; y++)
4301 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4303 if (q == (PixelPacket *) NULL)
4305 for (x=0; x < (int) image->columns; x++)
4310 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4313 image_view=DestroyCacheView(image_view);
4316 Composite image with X Image window.
4318 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4320 composite_image=DestroyImage(composite_image);
4321 XSetCursorState(display,windows,MagickFalse);
4323 Update image configuration.
4325 XConfigureImageColormap(display,resource_info,windows,image);
4326 (void) XConfigureImage(display,resource_info,windows,image);
4331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335 + X C o n f i g u r e I m a g e %
4339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4341 % XConfigureImage() creates a new X image. It also notifies the window
4342 % manager of the new image size and configures the transient widows.
4344 % The format of the XConfigureImage method is:
4346 % MagickBooleanType XConfigureImage(Display *display,
4347 % XResourceInfo *resource_info,XWindows *windows,Image *image)
4349 % A description of each parameter follows:
4351 % o display: Specifies a connection to an X server; returned from
4354 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4356 % o windows: Specifies a pointer to a XWindows structure.
4358 % o image: the image.
4362 static MagickBooleanType XConfigureImage(Display *display,
4363 XResourceInfo *resource_info,XWindows *windows,Image *image)
4366 geometry[MaxTextExtent];
4387 Dismiss if window dimensions are zero.
4389 width=(unsigned int) windows->image.window_changes.width;
4390 height=(unsigned int) windows->image.window_changes.height;
4391 if (image->debug != MagickFalse)
4392 (void) LogMagickEvent(X11Event,GetMagickModule(),
4393 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4394 windows->image.ximage->height,(double) width,(double) height);
4395 if ((width*height) == 0)
4400 Resize image to fit Image window dimensions.
4402 XSetCursorState(display,windows,MagickTrue);
4403 (void) XFlush(display);
4404 if (((int) width != windows->image.ximage->width) ||
4405 ((int) height != windows->image.ximage->height))
4406 image->taint=MagickTrue;
4407 windows->magnify.x=(int)
4408 width*windows->magnify.x/windows->image.ximage->width;
4409 windows->magnify.y=(int)
4410 height*windows->magnify.y/windows->image.ximage->height;
4411 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4412 windows->image.y=(int)
4413 (height*windows->image.y/windows->image.ximage->height);
4414 status=XMakeImage(display,resource_info,&windows->image,image,
4415 (unsigned int) width,(unsigned int) height);
4416 if (status == MagickFalse)
4417 XNoticeWidget(display,windows,"Unable to configure X image:",
4418 windows->image.name);
4420 Notify window manager of the new configuration.
4422 if (resource_info->image_geometry != (char *) NULL)
4423 (void) FormatMagickString(geometry,MaxTextExtent,"%s>!",
4424 resource_info->image_geometry);
4426 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4427 XDisplayWidth(display,windows->image.screen),
4428 XDisplayHeight(display,windows->image.screen));
4429 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4430 window_changes.width=(int) width;
4431 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4432 window_changes.width=XDisplayWidth(display,windows->image.screen);
4433 window_changes.height=(int) height;
4434 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4435 window_changes.height=XDisplayHeight(display,windows->image.screen);
4436 mask=(size_t) (CWWidth | CWHeight);
4437 if (resource_info->backdrop)
4440 window_changes.x=(int)
4441 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4442 window_changes.y=(int)
4443 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4445 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4446 (unsigned int) mask,&window_changes);
4447 (void) XClearWindow(display,windows->image.id);
4448 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4450 Update Magnify window configuration.
4452 if (windows->magnify.mapped != MagickFalse)
4453 XMakeMagnifyImage(display,windows);
4454 windows->pan.crop_geometry=windows->image.crop_geometry;
4455 XBestIconSize(display,&windows->pan,image);
4456 while (((windows->pan.width << 1) < MaxIconSize) &&
4457 ((windows->pan.height << 1) < MaxIconSize))
4459 windows->pan.width<<=1;
4460 windows->pan.height<<=1;
4462 if (windows->pan.geometry != (char *) NULL)
4463 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4464 &windows->pan.width,&windows->pan.height);
4465 window_changes.width=(int) windows->pan.width;
4466 window_changes.height=(int) windows->pan.height;
4467 size_hints=XAllocSizeHints();
4468 if (size_hints != (XSizeHints *) NULL)
4473 size_hints->flags=PSize | PMinSize | PMaxSize;
4474 size_hints->width=window_changes.width;
4475 size_hints->height=window_changes.height;
4476 size_hints->min_width=size_hints->width;
4477 size_hints->min_height=size_hints->height;
4478 size_hints->max_width=size_hints->width;
4479 size_hints->max_height=size_hints->height;
4480 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4481 (void) XFree((void *) size_hints);
4483 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4484 (unsigned int) (CWWidth | CWHeight),&window_changes);
4486 Update icon window configuration.
4488 windows->icon.crop_geometry=windows->image.crop_geometry;
4489 XBestIconSize(display,&windows->icon,image);
4490 window_changes.width=(int) windows->icon.width;
4491 window_changes.height=(int) windows->icon.height;
4492 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4493 (unsigned int) (CWWidth | CWHeight),&window_changes);
4494 XSetCursorState(display,windows,MagickFalse);
4495 return(status != 0 ? MagickTrue : MagickFalse);
4499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4503 + X C r o p I m a g e %
4507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4509 % XCropImage() allows the user to select a region of the image and crop, copy,
4510 % or cut it. For copy or cut, the image can subsequently be composited onto
4511 % the image with XPasteImage.
4513 % The format of the XCropImage method is:
4515 % MagickBooleanType XCropImage(Display *display,
4516 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4517 % const ClipboardMode mode)
4519 % A description of each parameter follows:
4521 % o display: Specifies a connection to an X server; returned from
4524 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4526 % o windows: Specifies a pointer to a XWindows structure.
4528 % o image: the image; returned from ReadImage.
4530 % o mode: This unsigned value specified whether the image should be
4531 % cropped, copied, or cut.
4534 static MagickBooleanType XCropImage(Display *display,
4535 XResourceInfo *resource_info,XWindows *windows,Image *image,
4536 const ClipboardMode mode)
4545 *RectifyModeMenu[] =
4553 static const ModeType
4563 RectifyDismissCommand
4570 command[MaxTextExtent],
4571 text[MaxTextExtent];
4597 register PixelPacket
4617 (void) CloneString(&windows->command.name,"Copy");
4622 (void) CloneString(&windows->command.name,"Crop");
4627 (void) CloneString(&windows->command.name,"Cut");
4631 RectifyModeMenu[0]=windows->command.name;
4632 windows->command.data=0;
4633 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4634 (void) XMapRaised(display,windows->command.id);
4635 XClientMessage(display,windows->image.id,windows->im_protocols,
4636 windows->im_update_widget,CurrentTime);
4638 Track pointer until button 1 is pressed.
4640 XQueryPosition(display,windows->image.id,&x,&y);
4641 (void) XSelectInput(display,windows->image.id,
4642 windows->image.attributes.event_mask | PointerMotionMask);
4643 crop_info.x=(ssize_t) windows->image.x+x;
4644 crop_info.y=(ssize_t) windows->image.y+y;
4647 cursor=XCreateFontCursor(display,XC_fleur);
4651 if (windows->info.mapped != MagickFalse)
4654 Display pointer position.
4656 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
4657 (long) crop_info.x,(long) crop_info.y);
4658 XInfoWidget(display,windows,text);
4661 Wait for next event.
4663 XScreenEvent(display,windows,&event);
4664 if (event.xany.window == windows->command.id)
4667 Select a command from the Command widget.
4669 id=XCommandWidget(display,windows,CropModeMenu,&event);
4672 switch (CropCommands[id])
4674 case CropHelpCommand:
4680 XTextViewWidget(display,resource_info,windows,MagickFalse,
4681 "Help Viewer - Image Copy",ImageCopyHelp);
4686 XTextViewWidget(display,resource_info,windows,MagickFalse,
4687 "Help Viewer - Image Crop",ImageCropHelp);
4692 XTextViewWidget(display,resource_info,windows,MagickFalse,
4693 "Help Viewer - Image Cut",ImageCutHelp);
4699 case CropDismissCommand:
4717 if (event.xbutton.button != Button1)
4719 if (event.xbutton.window != windows->image.id)
4722 Note first corner of cropping rectangle-- exit loop.
4724 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4725 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4726 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4736 if (event.xkey.window != windows->image.id)
4739 Respond to a user key press.
4741 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4742 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4743 switch ((int) key_symbol)
4762 XTextViewWidget(display,resource_info,windows,MagickFalse,
4763 "Help Viewer - Image Copy",ImageCopyHelp);
4768 XTextViewWidget(display,resource_info,windows,MagickFalse,
4769 "Help Viewer - Image Crop",ImageCropHelp);
4774 XTextViewWidget(display,resource_info,windows,MagickFalse,
4775 "Help Viewer - Image Cut",ImageCutHelp);
4783 (void) XBell(display,0);
4791 if (event.xmotion.window != windows->image.id)
4794 Map and unmap Info widget as text cursor crosses its boundaries.
4798 if (windows->info.mapped != MagickFalse)
4800 if ((x < (int) (windows->info.x+windows->info.width)) &&
4801 (y < (int) (windows->info.y+windows->info.height)))
4802 (void) XWithdrawWindow(display,windows->info.id,
4803 windows->info.screen);
4806 if ((x > (int) (windows->info.x+windows->info.width)) ||
4807 (y > (int) (windows->info.y+windows->info.height)))
4808 (void) XMapWindow(display,windows->info.id);
4809 crop_info.x=(ssize_t) windows->image.x+x;
4810 crop_info.y=(ssize_t) windows->image.y+y;
4816 } while ((state & ExitState) == 0);
4817 (void) XSelectInput(display,windows->image.id,
4818 windows->image.attributes.event_mask);
4819 if ((state & EscapeState) != 0)
4822 User want to exit without cropping.
4824 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4825 (void) XFreeCursor(display,cursor);
4828 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4832 Size rectangle as pointer moves until the mouse button is released.
4834 x=(int) crop_info.x;
4835 y=(int) crop_info.y;
4841 highlight_info=crop_info;
4842 highlight_info.x=crop_info.x-windows->image.x;
4843 highlight_info.y=crop_info.y-windows->image.y;
4844 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4847 Display info and draw cropping rectangle.
4849 if (windows->info.mapped == MagickFalse)
4850 (void) XMapWindow(display,windows->info.id);
4851 (void) FormatMagickString(text,MaxTextExtent,
4852 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4853 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4854 XInfoWidget(display,windows,text);
4855 XHighlightRectangle(display,windows->image.id,
4856 windows->image.highlight_context,&highlight_info);
4859 if (windows->info.mapped != MagickFalse)
4860 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4862 Wait for next event.
4864 XScreenEvent(display,windows,&event);
4865 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4866 XHighlightRectangle(display,windows->image.id,
4867 windows->image.highlight_context,&highlight_info);
4872 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4873 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4879 User has committed to cropping rectangle.
4881 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4882 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4883 XSetCursorState(display,windows,MagickFalse);
4885 windows->command.data=0;
4886 (void) XCommandWidget(display,windows,RectifyModeMenu,
4894 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4895 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4900 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4901 ((state & ExitState) != 0))
4904 Check boundary conditions.
4906 if (crop_info.x < 0)
4909 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4910 crop_info.x=(ssize_t) windows->image.ximage->width;
4911 if ((int) crop_info.x < x)
4912 crop_info.width=(unsigned int) (x-crop_info.x);
4915 crop_info.width=(unsigned int) (crop_info.x-x);
4916 crop_info.x=(ssize_t) x;
4918 if (crop_info.y < 0)
4921 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4922 crop_info.y=(ssize_t) windows->image.ximage->height;
4923 if ((int) crop_info.y < y)
4924 crop_info.height=(unsigned int) (y-crop_info.y);
4927 crop_info.height=(unsigned int) (crop_info.y-y);
4928 crop_info.y=(ssize_t) y;
4931 } while ((state & ExitState) == 0);
4933 Wait for user to grab a corner of the rectangle or press return.
4936 (void) XMapWindow(display,windows->info.id);
4939 if (windows->info.mapped != MagickFalse)
4942 Display pointer position.
4944 (void) FormatMagickString(text,MaxTextExtent,
4945 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4946 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4947 XInfoWidget(display,windows,text);
4949 highlight_info=crop_info;
4950 highlight_info.x=crop_info.x-windows->image.x;
4951 highlight_info.y=crop_info.y-windows->image.y;
4952 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4958 XHighlightRectangle(display,windows->image.id,
4959 windows->image.highlight_context,&highlight_info);
4960 XScreenEvent(display,windows,&event);
4961 if (event.xany.window == windows->command.id)
4964 Select a command from the Command widget.
4966 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4967 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4968 (void) XSetFunction(display,windows->image.highlight_context,
4970 XHighlightRectangle(display,windows->image.id,
4971 windows->image.highlight_context,&highlight_info);
4973 switch (RectifyCommands[id])
4975 case RectifyCopyCommand:
4980 case RectifyHelpCommand:
4982 (void) XSetFunction(display,windows->image.highlight_context,
4988 XTextViewWidget(display,resource_info,windows,MagickFalse,
4989 "Help Viewer - Image Copy",ImageCopyHelp);
4994 XTextViewWidget(display,resource_info,windows,MagickFalse,
4995 "Help Viewer - Image Crop",ImageCropHelp);
5000 XTextViewWidget(display,resource_info,windows,MagickFalse,
5001 "Help Viewer - Image Cut",ImageCutHelp);
5005 (void) XSetFunction(display,windows->image.highlight_context,
5009 case RectifyDismissCommand:
5023 XHighlightRectangle(display,windows->image.id,
5024 windows->image.highlight_context,&highlight_info);
5029 if (event.xbutton.button != Button1)
5031 if (event.xbutton.window != windows->image.id)
5033 x=windows->image.x+event.xbutton.x;
5034 y=windows->image.y+event.xbutton.y;
5035 if ((x < (int) (crop_info.x+RoiDelta)) &&
5036 (x > (int) (crop_info.x-RoiDelta)) &&
5037 (y < (int) (crop_info.y+RoiDelta)) &&
5038 (y > (int) (crop_info.y-RoiDelta)))
5040 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5041 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5042 state|=UpdateConfigurationState;
5045 if ((x < (int) (crop_info.x+RoiDelta)) &&
5046 (x > (int) (crop_info.x-RoiDelta)) &&
5047 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5048 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5050 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5051 state|=UpdateConfigurationState;
5054 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5055 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5056 (y < (int) (crop_info.y+RoiDelta)) &&
5057 (y > (int) (crop_info.y-RoiDelta)))
5059 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5060 state|=UpdateConfigurationState;
5063 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5064 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5065 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5066 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5068 state|=UpdateConfigurationState;
5074 if (event.xbutton.window == windows->pan.id)
5075 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5076 (highlight_info.y != crop_info.y-windows->image.y))
5077 XHighlightRectangle(display,windows->image.id,
5078 windows->image.highlight_context,&highlight_info);
5079 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5080 event.xbutton.time);
5085 if (event.xexpose.window == windows->image.id)
5086 if (event.xexpose.count == 0)
5088 event.xexpose.x=(int) highlight_info.x;
5089 event.xexpose.y=(int) highlight_info.y;
5090 event.xexpose.width=(int) highlight_info.width;
5091 event.xexpose.height=(int) highlight_info.height;
5092 XRefreshWindow(display,&windows->image,&event);
5094 if (event.xexpose.window == windows->info.id)
5095 if (event.xexpose.count == 0)
5096 XInfoWidget(display,windows,text);
5101 if (event.xkey.window != windows->image.id)
5104 Respond to a user key press.
5106 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5107 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5108 switch ((int) key_symbol)
5121 crop_info.x=(ssize_t) (windows->image.width/2L-
5122 crop_info.width/2L);
5123 crop_info.y=(ssize_t) (windows->image.height/2L-
5124 crop_info.height/2L);
5156 (void) XSetFunction(display,windows->image.highlight_context,
5162 XTextViewWidget(display,resource_info,windows,MagickFalse,
5163 "Help Viewer - Image Copy",ImageCopyHelp);
5168 XTextViewWidget(display,resource_info,windows,MagickFalse,
5169 "Help Viewer - Image Cropg",ImageCropHelp);
5174 XTextViewWidget(display,resource_info,windows,MagickFalse,
5175 "Help Viewer - Image Cutg",ImageCutHelp);
5179 (void) XSetFunction(display,windows->image.highlight_context,
5185 (void) XBell(display,0);
5189 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5197 if (event.xmotion.window != windows->image.id)
5200 Map and unmap Info widget as text cursor crosses its boundaries.
5204 if (windows->info.mapped != MagickFalse)
5206 if ((x < (int) (windows->info.x+windows->info.width)) &&
5207 (y < (int) (windows->info.y+windows->info.height)))
5208 (void) XWithdrawWindow(display,windows->info.id,
5209 windows->info.screen);
5212 if ((x > (int) (windows->info.x+windows->info.width)) ||
5213 (y > (int) (windows->info.y+windows->info.height)))
5214 (void) XMapWindow(display,windows->info.id);
5215 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5216 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5219 case SelectionRequest:
5224 XSelectionRequestEvent
5228 Set primary selection.
5230 (void) FormatMagickString(text,MaxTextExtent,
5231 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5232 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5233 request=(&(event.xselectionrequest));
5234 (void) XChangeProperty(request->display,request->requestor,
5235 request->property,request->target,8,PropModeReplace,
5236 (unsigned char *) text,(int) strlen(text));
5237 notify.type=SelectionNotify;
5238 notify.display=request->display;
5239 notify.requestor=request->requestor;
5240 notify.selection=request->selection;
5241 notify.target=request->target;
5242 notify.time=request->time;
5243 if (request->property == None)
5244 notify.property=request->target;
5246 notify.property=request->property;
5247 (void) XSendEvent(request->display,request->requestor,False,0,
5248 (XEvent *) ¬ify);
5253 if ((state & UpdateConfigurationState) != 0)
5255 (void) XPutBackEvent(display,&event);
5256 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5259 } while ((state & ExitState) == 0);
5260 } while ((state & ExitState) == 0);
5261 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5262 XSetCursorState(display,windows,MagickFalse);
5263 if ((state & EscapeState) != 0)
5265 if (mode == CropMode)
5266 if (((int) crop_info.width != windows->image.ximage->width) ||
5267 ((int) crop_info.height != windows->image.ximage->height))
5270 Reconfigure Image window as defined by cropping rectangle.
5272 XSetCropGeometry(display,windows,&crop_info,image);
5273 windows->image.window_changes.width=(int) crop_info.width;
5274 windows->image.window_changes.height=(int) crop_info.height;
5275 (void) XConfigureImage(display,resource_info,windows,image);
5279 Copy image before applying image transforms.
5281 XSetCursorState(display,windows,MagickTrue);
5282 XCheckRefreshWindows(display,windows);
5283 width=(unsigned int) image->columns;
5284 height=(unsigned int) image->rows;
5287 if (windows->image.crop_geometry != (char *) NULL)
5288 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5289 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5291 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5292 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5293 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5295 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5296 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5297 crop_image=CropImage(image,&crop_info,&image->exception);
5298 XSetCursorState(display,windows,MagickFalse);
5299 if (crop_image == (Image *) NULL)
5300 return(MagickFalse);
5301 if (resource_info->copy_image != (Image *) NULL)
5302 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5303 resource_info->copy_image=crop_image;
5304 if (mode == CopyMode)
5306 (void) XConfigureImage(display,resource_info,windows,image);
5312 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
5313 return(MagickFalse);
5314 image->matte=MagickTrue;
5315 exception=(&image->exception);
5316 image_view=AcquireCacheView(image);
5317 for (y=0; y < (int) crop_info.height; y++)
5319 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5320 crop_info.width,1,exception);
5321 if (q == (PixelPacket *) NULL)
5323 for (x=0; x < (int) crop_info.width; x++)
5325 q->opacity=(Quantum) TransparentOpacity;
5328 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5331 image_view=DestroyCacheView(image_view);
5333 Update image configuration.
5335 XConfigureImageColormap(display,resource_info,windows,image);
5336 (void) XConfigureImage(display,resource_info,windows,image);
5341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5345 + X D r a w I m a g e %
5349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5351 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5354 % The format of the XDrawEditImage method is:
5356 % MagickBooleanType XDrawEditImage(Display *display,
5357 % XResourceInfo *resource_info,XWindows *windows,Image **image)
5359 % A description of each parameter follows:
5361 % o display: Specifies a connection to an X server; returned from
5364 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5366 % o windows: Specifies a pointer to a XWindows structure.
5368 % o image: the image.
5371 static MagickBooleanType XDrawEditImage(Display *display,
5372 XResourceInfo *resource_info,XWindows *windows,Image **image)
5388 element = PointElement;
5390 static const ModeType
5403 stipple = (Pixmap) NULL;
5410 command[MaxTextExtent],
5411 text[MaxTextExtent];
5460 Allocate polygon info.
5462 max_coordinates=2048;
5463 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5464 sizeof(*coordinate_info));
5465 if (coordinate_info == (XPoint *) NULL)
5467 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5468 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5469 return(MagickFalse);
5474 (void) CloneString(&windows->command.name,"Draw");
5475 windows->command.data=4;
5476 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5477 (void) XMapRaised(display,windows->command.id);
5478 XClientMessage(display,windows->image.id,windows->im_protocols,
5479 windows->im_update_widget,CurrentTime);
5481 Wait for first button press.
5483 root_window=XRootWindow(display,XDefaultScreen(display));
5484 draw_info.stencil=OpaqueStencil;
5486 cursor=XCreateFontCursor(display,XC_tcross);
5489 XQueryPosition(display,windows->image.id,&x,&y);
5490 (void) XSelectInput(display,windows->image.id,
5491 windows->image.attributes.event_mask | PointerMotionMask);
5492 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5496 if (windows->info.mapped != MagickFalse)
5499 Display pointer position.
5501 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
5502 x+windows->image.x,y+windows->image.y);
5503 XInfoWidget(display,windows,text);
5506 Wait for next event.
5508 XScreenEvent(display,windows,&event);
5509 if (event.xany.window == windows->command.id)
5512 Select a command from the Command widget.
5514 id=XCommandWidget(display,windows,DrawMenu,&event);
5517 switch (DrawCommands[id])
5519 case DrawElementCommand:
5538 Select a command from the pop-up menu.
5540 element=(ElementType) (XMenuWidget(display,windows,
5541 DrawMenu[id],Elements,command)+1);
5544 case DrawColorCommand:
5547 *ColorMenu[MaxNumberPens+1];
5559 Initialize menu selections.
5561 for (i=0; i < (int) (MaxNumberPens-2); i++)
5562 ColorMenu[i]=resource_info->pen_colors[i];
5563 ColorMenu[MaxNumberPens-2]="transparent";
5564 ColorMenu[MaxNumberPens-1]="Browser...";
5565 ColorMenu[MaxNumberPens]=(char *) NULL;
5567 Select a pen color from the pop-up menu.
5569 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5570 (const char **) ColorMenu,command);
5573 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5575 if (transparent != MagickFalse)
5577 draw_info.stencil=TransparentStencil;
5580 if (pen_number == (MaxNumberPens-1))
5583 color_name[MaxTextExtent] = "gray";
5586 Select a pen color from a dialog.
5588 resource_info->pen_colors[pen_number]=color_name;
5589 XColorBrowserWidget(display,windows,"Select",color_name);
5590 if (*color_name == '\0')
5596 (void) XParseColor(display,windows->map_info->colormap,
5597 resource_info->pen_colors[pen_number],&color);
5598 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5599 (unsigned int) MaxColors,&color);
5600 windows->pixel_info->pen_colors[pen_number]=color;
5601 pen_id=(unsigned int) pen_number;
5602 draw_info.stencil=OpaqueStencil;
5605 case DrawStippleCommand:
5617 filename[MaxTextExtent] = "\0";
5634 Select a command from the pop-up menu.
5636 StipplesMenu[7]="Open...";
5637 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5641 if (stipple != (Pixmap) NULL)
5642 (void) XFreePixmap(display,stipple);
5643 stipple=(Pixmap) NULL;
5650 stipple=XCreateBitmapFromData(display,root_window,
5651 (char *) BricksBitmap,BricksWidth,BricksHeight);
5656 stipple=XCreateBitmapFromData(display,root_window,
5657 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5662 stipple=XCreateBitmapFromData(display,root_window,
5663 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5668 stipple=XCreateBitmapFromData(display,root_window,
5669 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5674 stipple=XCreateBitmapFromData(display,root_window,
5675 (char *) WavyBitmap,WavyWidth,WavyHeight);
5680 stipple=XCreateBitmapFromData(display,root_window,
5681 (char *) HighlightBitmap,HighlightWidth,
5688 stipple=XCreateBitmapFromData(display,root_window,
5689 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5695 XFileBrowserWidget(display,windows,"Stipple",filename);
5696 if (*filename == '\0')
5701 XSetCursorState(display,windows,MagickTrue);
5702 XCheckRefreshWindows(display,windows);
5703 image_info=AcquireImageInfo();
5704 (void) CopyMagickString(image_info->filename,filename,
5706 stipple_image=ReadImage(image_info,&(*image)->exception);
5707 CatchException(&(*image)->exception);
5708 XSetCursorState(display,windows,MagickFalse);
5709 if (stipple_image == (Image *) NULL)
5711 (void) AcquireUniqueFileResource(filename);
5712 (void) FormatMagickString(stipple_image->filename,MaxTextExtent,
5714 (void) WriteImage(image_info,stipple_image);
5715 stipple_image=DestroyImage(stipple_image);
5716 image_info=DestroyImageInfo(image_info);
5717 status=XReadBitmapFile(display,root_window,filename,&width,
5718 &height,&stipple,&x,&y);
5719 (void) RelinquishUniqueFileResource(filename);
5720 if ((status != BitmapSuccess) != 0)
5721 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5725 case DrawWidthCommand:
5728 width[MaxTextExtent] = "0";
5743 Select a command from the pop-up menu.
5745 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5751 line_width=(unsigned int) StringToUnsignedLong(
5755 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5759 line_width=(unsigned int) StringToUnsignedLong(width);
5762 case DrawUndoCommand:
5764 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5768 case DrawHelpCommand:
5770 XTextViewWidget(display,resource_info,windows,MagickFalse,
5771 "Help Viewer - Image Rotation",ImageDrawHelp);
5772 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5775 case DrawDismissCommand:
5787 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5794 if (event.xbutton.button != Button1)
5796 if (event.xbutton.window != windows->image.id)
5815 if (event.xkey.window != windows->image.id)
5818 Respond to a user key press.
5820 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5821 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5822 switch ((int) key_symbol)
5837 XTextViewWidget(display,resource_info,windows,MagickFalse,
5838 "Help Viewer - Image Rotation",ImageDrawHelp);
5843 (void) XBell(display,0);
5852 Map and unmap Info widget as text cursor crosses its boundaries.
5856 if (windows->info.mapped != MagickFalse)
5858 if ((x < (int) (windows->info.x+windows->info.width)) &&
5859 (y < (int) (windows->info.y+windows->info.height)))
5860 (void) XWithdrawWindow(display,windows->info.id,
5861 windows->info.screen);
5864 if ((x > (int) (windows->info.x+windows->info.width)) ||
5865 (y > (int) (windows->info.y+windows->info.height)))
5866 (void) XMapWindow(display,windows->info.id);
5870 } while ((state & ExitState) == 0);
5871 (void) XSelectInput(display,windows->image.id,
5872 windows->image.attributes.event_mask);
5873 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5874 if ((state & EscapeState) != 0)
5877 Draw element as pointer moves until the button is released.
5885 rectangle_info.x=(ssize_t) x;
5886 rectangle_info.y=(ssize_t) y;
5887 rectangle_info.width=0;
5888 rectangle_info.height=0;
5889 number_coordinates=1;
5890 coordinate_info->x=x;
5891 coordinate_info->y=y;
5892 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5901 if (number_coordinates > 1)
5903 (void) XDrawLines(display,windows->image.id,
5904 windows->image.highlight_context,coordinate_info,
5905 number_coordinates,CoordModeOrigin);
5906 (void) FormatMagickString(text,MaxTextExtent," %+d%+d",
5907 coordinate_info[number_coordinates-1].x,
5908 coordinate_info[number_coordinates-1].y);
5909 XInfoWidget(display,windows,text);
5918 Display angle of the line.
5920 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5921 line_info.y1),(double) (line_info.x2-line_info.x1)));
5922 (void) FormatMagickString(text,MaxTextExtent," %g",
5924 XInfoWidget(display,windows,text);
5925 XHighlightLine(display,windows->image.id,
5926 windows->image.highlight_context,&line_info);
5929 if (windows->info.mapped != MagickFalse)
5930 (void) XWithdrawWindow(display,windows->info.id,
5931 windows->info.screen);
5934 case RectangleElement:
5935 case FillRectangleElement:
5937 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5940 Display info and draw drawing rectangle.
5942 (void) FormatMagickString(text,MaxTextExtent,
5943 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5944 (double) rectangle_info.height,(double) rectangle_info.x,
5945 (double) rectangle_info.y);
5946 XInfoWidget(display,windows,text);
5947 XHighlightRectangle(display,windows->image.id,
5948 windows->image.highlight_context,&rectangle_info);
5951 if (windows->info.mapped != MagickFalse)
5952 (void) XWithdrawWindow(display,windows->info.id,
5953 windows->info.screen);
5957 case FillCircleElement:
5958 case EllipseElement:
5959 case FillEllipseElement:
5961 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5964 Display info and draw drawing rectangle.
5966 (void) FormatMagickString(text,MaxTextExtent,
5967 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5968 (double) rectangle_info.height,(double) rectangle_info.x,
5969 (double) rectangle_info.y);
5970 XInfoWidget(display,windows,text);
5971 XHighlightEllipse(display,windows->image.id,
5972 windows->image.highlight_context,&rectangle_info);
5975 if (windows->info.mapped != MagickFalse)
5976 (void) XWithdrawWindow(display,windows->info.id,
5977 windows->info.screen);
5980 case PolygonElement:
5981 case FillPolygonElement:
5983 if (number_coordinates > 1)
5984 (void) XDrawLines(display,windows->image.id,
5985 windows->image.highlight_context,coordinate_info,
5986 number_coordinates,CoordModeOrigin);
5990 Display angle of the line.
5992 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5993 line_info.y1),(double) (line_info.x2-line_info.x1)));
5994 (void) FormatMagickString(text,MaxTextExtent," %g",
5996 XInfoWidget(display,windows,text);
5997 XHighlightLine(display,windows->image.id,
5998 windows->image.highlight_context,&line_info);
6001 if (windows->info.mapped != MagickFalse)
6002 (void) XWithdrawWindow(display,windows->info.id,
6003 windows->info.screen);
6008 Wait for next event.
6010 XScreenEvent(display,windows,&event);
6016 if (number_coordinates > 1)
6017 (void) XDrawLines(display,windows->image.id,
6018 windows->image.highlight_context,coordinate_info,
6019 number_coordinates,CoordModeOrigin);
6025 XHighlightLine(display,windows->image.id,
6026 windows->image.highlight_context,&line_info);
6029 case RectangleElement:
6030 case FillRectangleElement:
6032 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6033 XHighlightRectangle(display,windows->image.id,
6034 windows->image.highlight_context,&rectangle_info);
6038 case FillCircleElement:
6039 case EllipseElement:
6040 case FillEllipseElement:
6042 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6043 XHighlightEllipse(display,windows->image.id,
6044 windows->image.highlight_context,&rectangle_info);
6047 case PolygonElement:
6048 case FillPolygonElement:
6050 if (number_coordinates > 1)
6051 (void) XDrawLines(display,windows->image.id,
6052 windows->image.highlight_context,coordinate_info,
6053 number_coordinates,CoordModeOrigin);
6055 XHighlightLine(display,windows->image.id,
6056 windows->image.highlight_context,&line_info);
6067 User has committed to element.
6069 line_info.x2=event.xbutton.x;
6070 line_info.y2=event.xbutton.y;
6071 rectangle_info.x=(ssize_t) event.xbutton.x;
6072 rectangle_info.y=(ssize_t) event.xbutton.y;
6073 coordinate_info[number_coordinates].x=event.xbutton.x;
6074 coordinate_info[number_coordinates].y=event.xbutton.y;
6075 if (((element != PolygonElement) &&
6076 (element != FillPolygonElement)) || (distance <= 9))
6081 number_coordinates++;
6082 if (number_coordinates < (int) max_coordinates)
6084 line_info.x1=event.xbutton.x;
6085 line_info.y1=event.xbutton.y;
6088 max_coordinates<<=1;
6089 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6090 max_coordinates,sizeof(*coordinate_info));
6091 if (coordinate_info == (XPoint *) NULL)
6092 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6093 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6100 if (event.xmotion.window != windows->image.id)
6102 if (element != PointElement)
6104 line_info.x2=event.xmotion.x;
6105 line_info.y2=event.xmotion.y;
6106 rectangle_info.x=(ssize_t) event.xmotion.x;
6107 rectangle_info.y=(ssize_t) event.xmotion.y;
6110 coordinate_info[number_coordinates].x=event.xbutton.x;
6111 coordinate_info[number_coordinates].y=event.xbutton.y;
6112 number_coordinates++;
6113 if (number_coordinates < (int) max_coordinates)
6115 max_coordinates<<=1;
6116 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6117 max_coordinates,sizeof(*coordinate_info));
6118 if (coordinate_info == (XPoint *) NULL)
6119 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6120 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6127 Check boundary conditions.
6129 if (line_info.x2 < 0)
6132 if (line_info.x2 > (int) windows->image.width)
6133 line_info.x2=(short) windows->image.width;
6134 if (line_info.y2 < 0)
6137 if (line_info.y2 > (int) windows->image.height)
6138 line_info.y2=(short) windows->image.height;
6139 distance=(unsigned int)
6140 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6141 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6142 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6143 ((state & ExitState) != 0))
6145 if (rectangle_info.x < 0)
6148 if (rectangle_info.x > (ssize_t) windows->image.width)
6149 rectangle_info.x=(ssize_t) windows->image.width;
6150 if ((int) rectangle_info.x < x)
6151 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6154 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6155 rectangle_info.x=(ssize_t) x;
6157 if (rectangle_info.y < 0)
6160 if (rectangle_info.y > (ssize_t) windows->image.height)
6161 rectangle_info.y=(ssize_t) windows->image.height;
6162 if ((int) rectangle_info.y < y)
6163 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6166 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6167 rectangle_info.y=(ssize_t) y;
6170 } while ((state & ExitState) == 0);
6171 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6172 if ((element == PointElement) || (element == PolygonElement) ||
6173 (element == FillPolygonElement))
6176 Determine polygon bounding box.
6178 rectangle_info.x=(ssize_t) coordinate_info->x;
6179 rectangle_info.y=(ssize_t) coordinate_info->y;
6180 x=coordinate_info->x;
6181 y=coordinate_info->y;
6182 for (i=1; i < number_coordinates; i++)
6184 if (coordinate_info[i].x > x)
6185 x=coordinate_info[i].x;
6186 if (coordinate_info[i].y > y)
6187 y=coordinate_info[i].y;
6188 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6189 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6190 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6191 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6193 rectangle_info.width=(size_t) (x-rectangle_info.x);
6194 rectangle_info.height=(size_t) (y-rectangle_info.y);
6195 for (i=0; i < number_coordinates; i++)
6197 coordinate_info[i].x-=rectangle_info.x;
6198 coordinate_info[i].y-=rectangle_info.y;
6205 if ((element == RectangleElement) ||
6206 (element == CircleElement) || (element == EllipseElement))
6208 rectangle_info.width--;
6209 rectangle_info.height--;
6212 Drawing is relative to image configuration.
6214 draw_info.x=(int) rectangle_info.x;
6215 draw_info.y=(int) rectangle_info.y;
6216 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6218 width=(unsigned int) (*image)->columns;
6219 height=(unsigned int) (*image)->rows;
6222 if (windows->image.crop_geometry != (char *) NULL)
6223 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6224 draw_info.x+=windows->image.x-(line_width/2);
6225 if (draw_info.x < 0)
6227 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6228 draw_info.y+=windows->image.y-(line_width/2);
6229 if (draw_info.y < 0)
6231 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6232 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6233 if (draw_info.width > (unsigned int) (*image)->columns)
6234 draw_info.width=(unsigned int) (*image)->columns;
6235 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6236 if (draw_info.height > (unsigned int) (*image)->rows)
6237 draw_info.height=(unsigned int) (*image)->rows;
6238 (void) FormatMagickString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6239 width*draw_info.width/windows->image.ximage->width,
6240 height*draw_info.height/windows->image.ximage->height,
6241 draw_info.x+x,draw_info.y+y);
6243 Initialize drawing attributes.
6245 draw_info.degrees=0.0;
6246 draw_info.element=element;
6247 draw_info.stipple=stipple;
6248 draw_info.line_width=line_width;
6249 draw_info.line_info=line_info;
6250 if (line_info.x1 > (int) (line_width/2))
6251 draw_info.line_info.x1=(short) line_width/2;
6252 if (line_info.y1 > (int) (line_width/2))
6253 draw_info.line_info.y1=(short) line_width/2;
6254 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6255 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6256 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6258 draw_info.line_info.x2=(-draw_info.line_info.x2);
6259 draw_info.line_info.y2=(-draw_info.line_info.y2);
6261 if (draw_info.line_info.x2 < 0)
6263 draw_info.line_info.x2=(-draw_info.line_info.x2);
6264 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6266 if (draw_info.line_info.y2 < 0)
6268 draw_info.line_info.y2=(-draw_info.line_info.y2);
6269 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6271 draw_info.rectangle_info=rectangle_info;
6272 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6273 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6274 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6275 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6276 draw_info.number_coordinates=(unsigned int) number_coordinates;
6277 draw_info.coordinate_info=coordinate_info;
6278 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6280 Draw element on image.
6282 XSetCursorState(display,windows,MagickTrue);
6283 XCheckRefreshWindows(display,windows);
6284 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6285 XSetCursorState(display,windows,MagickFalse);
6287 Update image colormap and return to image drawing.
6289 XConfigureImageColormap(display,resource_info,windows,*image);
6290 (void) XConfigureImage(display,resource_info,windows,*image);
6292 XSetCursorState(display,windows,MagickFalse);
6293 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6294 return(status != 0 ? MagickTrue : MagickFalse);
6298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6302 + X D r a w P a n R e c t a n g l e %
6306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6308 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6309 % displays a zoom image and the rectangle shows which portion of the image is
6310 % displayed in the Image window.
6312 % The format of the XDrawPanRectangle method is:
6314 % XDrawPanRectangle(Display *display,XWindows *windows)
6316 % A description of each parameter follows:
6318 % o display: Specifies a connection to an X server; returned from
6321 % o windows: Specifies a pointer to a XWindows structure.
6324 static void XDrawPanRectangle(Display *display,XWindows *windows)
6333 Determine dimensions of the panning rectangle.
6335 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6336 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6337 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6338 scale_factor=(MagickRealType)
6339 windows->pan.height/windows->image.ximage->height;
6340 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6341 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6343 Display the panning rectangle.
6345 (void) XClearWindow(display,windows->pan.id);
6346 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6355 + X I m a g e C a c h e %
6359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6361 % XImageCache() handles the creation, manipulation, and destruction of the
6362 % image cache (undo and redo buffers).
6364 % The format of the XImageCache method is:
6366 % void XImageCache(Display *display,XResourceInfo *resource_info,
6367 % XWindows *windows,const CommandType command,Image **image)
6369 % A description of each parameter follows:
6371 % o display: Specifies a connection to an X server; returned from
6374 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6376 % o windows: Specifies a pointer to a XWindows structure.
6378 % o command: Specifies a command to perform.
6380 % o image: the image; XImageCache
6381 % may transform the image and return a new image pointer.
6384 static void XImageCache(Display *display,XResourceInfo *resource_info,
6385 XWindows *windows,const CommandType command,Image **image)
6391 *redo_image = (Image *) NULL,
6392 *undo_image = (Image *) NULL;
6396 case FreeBuffersCommand:
6399 Free memory from the undo and redo cache.
6401 while (undo_image != (Image *) NULL)
6403 cache_image=undo_image;
6404 undo_image=GetPreviousImageInList(undo_image);
6405 cache_image->list=DestroyImage(cache_image->list);
6406 cache_image=DestroyImage(cache_image);
6408 undo_image=NewImageList();
6409 if (redo_image != (Image *) NULL)
6410 redo_image=DestroyImage(redo_image);
6411 redo_image=NewImageList();
6417 Undo the last image transformation.
6419 if (undo_image == (Image *) NULL)
6421 (void) XBell(display,0);
6424 cache_image=undo_image;
6425 undo_image=GetPreviousImageInList(undo_image);
6426 windows->image.window_changes.width=(int) cache_image->columns;
6427 windows->image.window_changes.height=(int) cache_image->rows;
6428 if (windows->image.crop_geometry != (char *) NULL)
6429 windows->image.crop_geometry=(char *)
6430 RelinquishMagickMemory(windows->image.crop_geometry);
6431 windows->image.crop_geometry=cache_image->geometry;
6432 if (redo_image != (Image *) NULL)
6433 redo_image=DestroyImage(redo_image);
6434 redo_image=(*image);
6435 *image=cache_image->list;
6436 cache_image=DestroyImage(cache_image);
6437 if (windows->image.orphan != MagickFalse)
6439 XConfigureImageColormap(display,resource_info,windows,*image);
6440 (void) XConfigureImage(display,resource_info,windows,*image);
6446 case HalfSizeCommand:
6447 case OriginalSizeCommand:
6448 case DoubleSizeCommand:
6455 case RotateRightCommand:
6456 case RotateLeftCommand:
6461 case ContrastStretchCommand:
6462 case SigmoidalContrastCommand:
6463 case NormalizeCommand:
6464 case EqualizeCommand:
6466 case SaturationCommand:
6467 case BrightnessCommand:
6471 case GrayscaleCommand:
6473 case QuantizeCommand:
6474 case DespeckleCommand:
6476 case ReduceNoiseCommand:
6477 case AddNoiseCommand:
6478 case SharpenCommand:
6480 case ThresholdCommand:
6481 case EdgeDetectCommand:
6485 case SegmentCommand:
6486 case SolarizeCommand:
6487 case SepiaToneCommand:
6489 case ImplodeCommand:
6490 case VignetteCommand:
6492 case OilPaintCommand:
6493 case CharcoalDrawCommand:
6494 case AnnotateCommand:
6495 case AddBorderCommand:
6496 case AddFrameCommand:
6497 case CompositeCommand:
6498 case CommentCommand:
6500 case RegionofInterestCommand:
6501 case SaveToUndoBufferCommand:
6510 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6511 if (undo_image != (Image *) NULL)
6514 Ensure the undo stash.has enough memory available.
6516 previous_image=undo_image;
6517 while (previous_image != (Image *) NULL)
6519 bytes+=previous_image->list->columns*previous_image->list->rows*
6520 sizeof(PixelPacket);
6521 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6523 previous_image=GetPreviousImageInList(previous_image);
6526 bytes-=previous_image->list->columns*previous_image->list->rows*
6527 sizeof(PixelPacket);
6528 if (previous_image == undo_image)
6529 undo_image=NewImageList();
6531 previous_image->next->previous=NewImageList();
6534 while (previous_image != (Image *) NULL)
6537 Delete any excess memory from undo cache.
6539 cache_image=previous_image;
6540 previous_image=GetPreviousImageInList(previous_image);
6541 cache_image->list=DestroyImage(cache_image->list);
6542 cache_image=DestroyImage(cache_image);
6545 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6548 Save image before transformations are applied.
6550 cache_image=AcquireImage((ImageInfo *) NULL);
6551 if (cache_image == (Image *) NULL)
6553 XSetCursorState(display,windows,MagickTrue);
6554 XCheckRefreshWindows(display,windows);
6555 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6556 XSetCursorState(display,windows,MagickFalse);
6557 if (cache_image->list == (Image *) NULL)
6559 cache_image=DestroyImage(cache_image);
6562 cache_image->columns=(size_t) windows->image.ximage->width;
6563 cache_image->rows=(size_t) windows->image.ximage->height;
6564 cache_image->geometry=windows->image.crop_geometry;
6565 if (windows->image.crop_geometry != (char *) NULL)
6567 cache_image->geometry=AcquireString((char *) NULL);
6568 (void) CopyMagickString(cache_image->geometry,
6569 windows->image.crop_geometry,MaxTextExtent);
6571 if (undo_image == (Image *) NULL)
6573 undo_image=cache_image;
6576 undo_image->next=cache_image;
6577 undo_image->next->previous=undo_image;
6578 undo_image=undo_image->next;
6584 if (command == RedoCommand)
6587 Redo the last image transformation.
6589 if (redo_image == (Image *) NULL)
6591 (void) XBell(display,0);
6594 windows->image.window_changes.width=(int) redo_image->columns;
6595 windows->image.window_changes.height=(int) redo_image->rows;
6596 if (windows->image.crop_geometry != (char *) NULL)
6597 windows->image.crop_geometry=(char *)
6598 RelinquishMagickMemory(windows->image.crop_geometry);
6599 windows->image.crop_geometry=redo_image->geometry;
6600 *image=DestroyImage(*image);
6602 redo_image=NewImageList();
6603 if (windows->image.orphan != MagickFalse)
6605 XConfigureImageColormap(display,resource_info,windows,*image);
6606 (void) XConfigureImage(display,resource_info,windows,*image);
6609 if (command != InfoCommand)
6614 XSetCursorState(display,windows,MagickTrue);
6615 XCheckRefreshWindows(display,windows);
6616 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6617 XSetCursorState(display,windows,MagickFalse);
6621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6625 + X I m a g e W i n d o w C o m m a n d %
6629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6631 % XImageWindowCommand() makes a transform to the image or Image window as
6632 % specified by a user menu button or keyboard command.
6634 % The format of the XMagickCommand method is:
6636 % CommandType XImageWindowCommand(Display *display,
6637 % XResourceInfo *resource_info,XWindows *windows,
6638 % const MagickStatusType state,KeySym key_symbol,Image **image)
6640 % A description of each parameter follows:
6642 % o nexus: Method XImageWindowCommand returns an image when the
6643 % user chooses 'Open Image' from the command menu. Otherwise a null
6644 % image is returned.
6646 % o display: Specifies a connection to an X server; returned from
6649 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6651 % o windows: Specifies a pointer to a XWindows structure.
6653 % o state: key mask.
6655 % o key_symbol: Specifies a command to perform.
6657 % o image: the image; XImageWIndowCommand
6658 % may transform the image and return a new image pointer.
6661 static CommandType XImageWindowCommand(Display *display,
6662 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6663 KeySym key_symbol,Image **image)
6666 delta[MaxTextExtent] = "";
6669 Digits[] = "01234567890";
6674 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6676 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6679 resource_info->quantum=1;
6681 last_symbol=key_symbol;
6682 delta[strlen(delta)+1]='\0';
6683 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6684 resource_info->quantum=StringToLong(delta);
6685 return(NullCommand);
6687 last_symbol=key_symbol;
6688 if (resource_info->immutable)
6691 Virtual image window has a restricted command set.
6696 return(InfoCommand);
6699 return(PrintCommand);
6701 return(NextCommand);
6704 return(QuitCommand);
6708 return(NullCommand);
6710 switch ((int) key_symbol)
6714 if ((state & ControlMask) == 0)
6716 return(OpenCommand);
6719 return(NextCommand);
6721 return(FormerCommand);
6724 if ((state & Mod1Mask) != 0)
6725 return(SwirlCommand);
6726 if ((state & ControlMask) == 0)
6727 return(ShearCommand);
6728 return(SaveCommand);
6733 if ((state & Mod1Mask) != 0)
6734 return(OilPaintCommand);
6735 if ((state & Mod4Mask) != 0)
6736 return(ColorCommand);
6737 if ((state & ControlMask) == 0)
6738 return(NullCommand);
6739 return(PrintCommand);
6743 if ((state & Mod4Mask) != 0)
6744 return(DrawCommand);
6745 if ((state & ControlMask) == 0)
6746 return(NullCommand);
6747 return(DeleteCommand);
6751 if ((state & ControlMask) == 0)
6752 return(NullCommand);
6753 return(SelectCommand);
6757 if ((state & ControlMask) == 0)
6758 return(NullCommand);
6763 return(QuitCommand);
6767 if ((state & ControlMask) == 0)
6768 return(NullCommand);
6769 return(UndoCommand);
6774 if ((state & ControlMask) == 0)
6775 return(RollCommand);
6776 return(RedoCommand);
6780 if ((state & ControlMask) == 0)
6781 return(NullCommand);
6786 if ((state & Mod1Mask) != 0)
6787 return(CharcoalDrawCommand);
6788 if ((state & ControlMask) == 0)
6789 return(CropCommand);
6790 return(CopyCommand);
6795 if ((state & Mod4Mask) != 0)
6796 return(CompositeCommand);
6797 if ((state & ControlMask) == 0)
6798 return(FlipCommand);
6799 return(PasteCommand);
6802 return(HalfSizeCommand);
6804 return(OriginalSizeCommand);
6806 return(DoubleSizeCommand);
6808 return(ResizeCommand);
6810 return(RefreshCommand);
6811 case XK_bracketleft:
6812 return(ChopCommand);
6814 return(FlopCommand);
6816 return(RotateRightCommand);
6818 return(RotateLeftCommand);
6820 return(RotateCommand);
6822 return(TrimCommand);
6826 return(SaturationCommand);
6828 return(BrightnessCommand);
6830 return(GammaCommand);
6832 return(SpiffCommand);
6834 return(DullCommand);
6836 return(NormalizeCommand);
6838 return(EqualizeCommand);
6840 return(NegateCommand);
6842 return(GrayscaleCommand);
6844 return(QuantizeCommand);
6846 return(DespeckleCommand);
6848 return(EmbossCommand);
6850 return(ReduceNoiseCommand);
6852 return(AddNoiseCommand);
6854 return(SharpenCommand);
6856 return(BlurCommand);
6858 return(ThresholdCommand);
6860 return(EdgeDetectCommand);
6862 return(SpreadCommand);
6864 return(ShadeCommand);
6866 return(RaiseCommand);
6868 return(SegmentCommand);
6871 if ((state & Mod1Mask) == 0)
6872 return(NullCommand);
6873 return(ImplodeCommand);
6877 if ((state & Mod1Mask) == 0)
6878 return(NullCommand);
6879 return(WaveCommand);
6883 if ((state & Mod4Mask) == 0)
6884 return(NullCommand);
6885 return(MatteCommand);
6889 if ((state & Mod4Mask) == 0)
6890 return(NullCommand);
6891 return(AddBorderCommand);
6895 if ((state & Mod4Mask) == 0)
6896 return(NullCommand);
6897 return(AddFrameCommand);
6901 if ((state & Mod4Mask) == 0)
6902 return(NullCommand);
6903 return(CommentCommand);
6907 if ((state & Mod1Mask) != 0)
6908 return(ApplyCommand);
6909 if ((state & Mod4Mask) != 0)
6910 return(AnnotateCommand);
6911 if ((state & ControlMask) == 0)
6912 return(NullCommand);
6913 return(RegionofInterestCommand);
6916 return(InfoCommand);
6918 return(ZoomCommand);
6921 if ((state & ShiftMask) == 0)
6922 return(NullCommand);
6923 return(ShowPreviewCommand);
6926 return(LaunchCommand);
6928 return(HelpCommand);
6930 return(BrowseDocumentationCommand);
6933 (void) XMapRaised(display,windows->command.id);
6934 return(NullCommand);
6941 XTranslateImage(display,windows,*image,key_symbol);
6942 return(NullCommand);
6953 if ((state & Mod1Mask) != 0)
6959 Trim one pixel from edge of image.
6963 crop_info.width=(size_t) windows->image.ximage->width;
6964 crop_info.height=(size_t) windows->image.ximage->height;
6965 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6967 if (resource_info->quantum >= (int) crop_info.height)
6968 resource_info->quantum=(int) crop_info.height-1;
6969 crop_info.height-=resource_info->quantum;
6971 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6973 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6974 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6975 crop_info.y+=resource_info->quantum;
6976 crop_info.height-=resource_info->quantum;
6978 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6980 if (resource_info->quantum >= (int) crop_info.width)
6981 resource_info->quantum=(int) crop_info.width-1;
6982 crop_info.width-=resource_info->quantum;
6984 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6986 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6987 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6988 crop_info.x+=resource_info->quantum;
6989 crop_info.width-=resource_info->quantum;
6991 if ((int) (windows->image.x+windows->image.width) >
6992 (int) crop_info.width)
6993 windows->image.x=(int) (crop_info.width-windows->image.width);
6994 if ((int) (windows->image.y+windows->image.height) >
6995 (int) crop_info.height)
6996 windows->image.y=(int) (crop_info.height-windows->image.height);
6997 XSetCropGeometry(display,windows,&crop_info,*image);
6998 windows->image.window_changes.width=(int) crop_info.width;
6999 windows->image.window_changes.height=(int) crop_info.height;
7000 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7001 (void) XConfigureImage(display,resource_info,windows,*image);
7002 return(NullCommand);
7004 XTranslateImage(display,windows,*image,key_symbol);
7005 return(NullCommand);
7008 return(NullCommand);
7010 return(NullCommand);
7014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7018 + X M a g i c k C o m m a n d %
7022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7024 % XMagickCommand() makes a transform to the image or Image window as
7025 % specified by a user menu button or keyboard command.
7027 % The format of the XMagickCommand method is:
7029 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7030 % XWindows *windows,const CommandType command,Image **image)
7032 % A description of each parameter follows:
7034 % o nexus: Method XMagickCommand returns an image when the
7035 % user chooses 'Load Image' from the command menu. Otherwise a null
7036 % image is returned.
7038 % o display: Specifies a connection to an X server; returned from
7041 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7043 % o windows: Specifies a pointer to a XWindows structure.
7045 % o command: Specifies a command to perform.
7047 % o image: the image; XMagickCommand
7048 % may transform the image and return a new image pointer.
7051 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7052 XWindows *windows,const CommandType command,Image **image)
7055 filename[MaxTextExtent],
7056 geometry[MaxTextExtent],
7057 modulate_factors[MaxTextExtent];
7086 color[MaxTextExtent] = "gray";
7093 Process user command.
7095 XCheckRefreshWindows(display,windows);
7096 XImageCache(display,resource_info,windows,command,image);
7097 nexus=NewImageList();
7098 windows->image.window_changes.width=windows->image.ximage->width;
7099 windows->image.window_changes.height=windows->image.ximage->height;
7100 image_info=CloneImageInfo(resource_info->image_info);
7101 SetGeometryInfo(&geometry_info);
7102 GetQuantizeInfo(&quantize_info);
7110 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7118 for (i=0; i < resource_info->quantum; i++)
7119 XClientMessage(display,windows->image.id,windows->im_protocols,
7120 windows->im_next_image,CurrentTime);
7126 Display former image.
7128 for (i=0; i < resource_info->quantum; i++)
7129 XClientMessage(display,windows->image.id,windows->im_protocols,
7130 windows->im_former_image,CurrentTime);
7141 status=chdir(resource_info->home_directory);
7143 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7144 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7145 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7153 status=XSaveImage(display,resource_info,windows,*image);
7154 if (status == MagickFalse)
7156 XNoticeWidget(display,windows,"Unable to write X image:",
7157 (*image)->filename);
7167 status=XPrintImage(display,resource_info,windows,*image);
7168 if (status == MagickFalse)
7170 XNoticeWidget(display,windows,"Unable to print X image:",
7171 (*image)->filename);
7179 filename[MaxTextExtent] = "\0";
7184 XFileBrowserWidget(display,windows,"Delete",filename);
7185 if (*filename == '\0')
7187 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7188 if (status != MagickFalse)
7189 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7198 color[MaxTextExtent] = "gray",
7199 geometry[MaxTextExtent] = "640x480";
7202 *format = "gradient";
7205 Query user for canvas geometry.
7207 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7209 if (*geometry == '\0')
7213 XColorBrowserWidget(display,windows,"Select",color);
7219 (void) FormatMagickString(image_info->filename,MaxTextExtent,
7220 "%s:%s",format,color);
7221 (void) CloneString(&image_info->size,geometry);
7222 nexus=ReadImage(image_info,&(*image)->exception);
7223 CatchException(&(*image)->exception);
7224 XClientMessage(display,windows->image.id,windows->im_protocols,
7225 windows->im_next_image,CurrentTime);
7228 case VisualDirectoryCommand:
7231 Visual Image directory.
7233 nexus=XVisualDirectoryImage(display,resource_info,windows);
7241 if (resource_info->confirm_exit == MagickFalse)
7242 XClientMessage(display,windows->image.id,windows->im_protocols,
7243 windows->im_exit,CurrentTime);
7250 Confirm program exit.
7252 status=XConfirmWidget(display,windows,"Do you really want to exit",
7253 resource_info->client_name);
7255 XClientMessage(display,windows->image.id,windows->im_protocols,
7256 windows->im_exit,CurrentTime);
7265 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7273 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7281 status=XPasteImage(display,resource_info,windows,*image);
7282 if (status == MagickFalse)
7284 XNoticeWidget(display,windows,"Unable to paste X image",
7285 (*image)->filename);
7290 case HalfSizeCommand:
7295 windows->image.window_changes.width=windows->image.ximage->width/2;
7296 windows->image.window_changes.height=windows->image.ximage->height/2;
7297 (void) XConfigureImage(display,resource_info,windows,*image);
7300 case OriginalSizeCommand:
7303 Original image size.
7305 windows->image.window_changes.width=(int) (*image)->columns;
7306 windows->image.window_changes.height=(int) (*image)->rows;
7307 (void) XConfigureImage(display,resource_info,windows,*image);
7310 case DoubleSizeCommand:
7313 Double the image size.
7315 windows->image.window_changes.width=windows->image.ximage->width << 1;
7316 windows->image.window_changes.height=windows->image.ximage->height << 1;
7317 (void) XConfigureImage(display,resource_info,windows,*image);
7336 width=(size_t) windows->image.ximage->width;
7337 height=(size_t) windows->image.ximage->height;
7340 (void) FormatMagickString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7341 (double) width,(double) height);
7342 status=XDialogWidget(display,windows,"Resize",
7343 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7344 if (*geometry == '\0')
7347 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7348 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7349 windows->image.window_changes.width=(int) width;
7350 windows->image.window_changes.height=(int) height;
7351 (void) XConfigureImage(display,resource_info,windows,*image);
7357 image_geometry[MaxTextExtent];
7359 if ((windows->image.crop_geometry == (char *) NULL) &&
7360 ((int) (*image)->columns == windows->image.ximage->width) &&
7361 ((int) (*image)->rows == windows->image.ximage->height))
7364 Apply size transforms to image.
7366 XSetCursorState(display,windows,MagickTrue);
7367 XCheckRefreshWindows(display,windows);
7369 Crop and/or scale displayed image.
7371 (void) FormatMagickString(image_geometry,MaxTextExtent,"%dx%d!",
7372 windows->image.ximage->width,windows->image.ximage->height);
7373 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7374 if (windows->image.crop_geometry != (char *) NULL)
7375 windows->image.crop_geometry=(char *)
7376 RelinquishMagickMemory(windows->image.crop_geometry);
7379 XConfigureImageColormap(display,resource_info,windows,*image);
7380 (void) XConfigureImage(display,resource_info,windows,*image);
7383 case RefreshCommand:
7385 (void) XConfigureImage(display,resource_info,windows,*image);
7388 case RestoreCommand:
7391 Restore Image window to its original size.
7393 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7394 (windows->image.height == (unsigned int) (*image)->rows) &&
7395 (windows->image.crop_geometry == (char *) NULL))
7397 (void) XBell(display,0);
7400 windows->image.window_changes.width=(int) (*image)->columns;
7401 windows->image.window_changes.height=(int) (*image)->rows;
7402 if (windows->image.crop_geometry != (char *) NULL)
7404 windows->image.crop_geometry=(char *)
7405 RelinquishMagickMemory(windows->image.crop_geometry);
7406 windows->image.crop_geometry=(char *) NULL;
7410 XConfigureImageColormap(display,resource_info,windows,*image);
7411 (void) XConfigureImage(display,resource_info,windows,*image);
7419 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7427 status=XChopImage(display,resource_info,windows,image);
7428 if (status == MagickFalse)
7430 XNoticeWidget(display,windows,"Unable to cut X image",
7431 (*image)->filename);
7442 Flop image scanlines.
7444 XSetCursorState(display,windows,MagickTrue);
7445 XCheckRefreshWindows(display,windows);
7446 flop_image=FlopImage(*image,&(*image)->exception);
7447 if (flop_image != (Image *) NULL)
7449 *image=DestroyImage(*image);
7452 CatchException(&(*image)->exception);
7453 XSetCursorState(display,windows,MagickFalse);
7454 if (windows->image.crop_geometry != (char *) NULL)
7459 width=(unsigned int) (*image)->columns;
7460 height=(unsigned int) (*image)->rows;
7461 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7463 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7464 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7466 if (windows->image.orphan != MagickFalse)
7468 (void) XConfigureImage(display,resource_info,windows,*image);
7477 Flip image scanlines.
7479 XSetCursorState(display,windows,MagickTrue);
7480 XCheckRefreshWindows(display,windows);
7481 flip_image=FlipImage(*image,&(*image)->exception);
7482 if (flip_image != (Image *) NULL)
7484 *image=DestroyImage(*image);
7487 CatchException(&(*image)->exception);
7488 XSetCursorState(display,windows,MagickFalse);
7489 if (windows->image.crop_geometry != (char *) NULL)
7494 width=(unsigned int) (*image)->columns;
7495 height=(unsigned int) (*image)->rows;
7496 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7498 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7499 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7501 if (windows->image.orphan != MagickFalse)
7503 (void) XConfigureImage(display,resource_info,windows,*image);
7506 case RotateRightCommand:
7509 Rotate image 90 degrees clockwise.
7511 status=XRotateImage(display,resource_info,windows,90.0,image);
7512 if (status == MagickFalse)
7514 XNoticeWidget(display,windows,"Unable to rotate X image",
7515 (*image)->filename);
7520 case RotateLeftCommand:
7523 Rotate image 90 degrees counter-clockwise.
7525 status=XRotateImage(display,resource_info,windows,-90.0,image);
7526 if (status == MagickFalse)
7528 XNoticeWidget(display,windows,"Unable to rotate X image",
7529 (*image)->filename);
7539 status=XRotateImage(display,resource_info,windows,0.0,image);
7540 if (status == MagickFalse)
7542 XNoticeWidget(display,windows,"Unable to rotate X image",
7543 (*image)->filename);
7554 geometry[MaxTextExtent] = "45.0x45.0";
7557 Query user for shear color and geometry.
7559 XColorBrowserWidget(display,windows,"Select",color);
7562 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7564 if (*geometry == '\0')
7569 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7570 XSetCursorState(display,windows,MagickTrue);
7571 XCheckRefreshWindows(display,windows);
7572 (void) QueryColorDatabase(color,&(*image)->background_color,
7573 &(*image)->exception);
7574 flags=ParseGeometry(geometry,&geometry_info);
7575 if ((flags & SigmaValue) == 0)
7576 geometry_info.sigma=geometry_info.rho;
7577 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7578 &(*image)->exception);
7579 if (shear_image != (Image *) NULL)
7581 *image=DestroyImage(*image);
7584 CatchException(&(*image)->exception);
7585 XSetCursorState(display,windows,MagickFalse);
7586 if (windows->image.orphan != MagickFalse)
7588 windows->image.window_changes.width=(int) (*image)->columns;
7589 windows->image.window_changes.height=(int) (*image)->rows;
7590 XConfigureImageColormap(display,resource_info,windows,*image);
7591 (void) XConfigureImage(display,resource_info,windows,*image);
7600 geometry[MaxTextExtent] = "+2+2";
7603 Query user for the roll geometry.
7605 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7607 if (*geometry == '\0')
7612 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7613 XSetCursorState(display,windows,MagickTrue);
7614 XCheckRefreshWindows(display,windows);
7615 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7616 &(*image)->exception);
7617 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7618 &(*image)->exception);
7619 if (roll_image != (Image *) NULL)
7621 *image=DestroyImage(*image);
7624 CatchException(&(*image)->exception);
7625 XSetCursorState(display,windows,MagickFalse);
7626 if (windows->image.orphan != MagickFalse)
7628 windows->image.window_changes.width=(int) (*image)->columns;
7629 windows->image.window_changes.height=(int) (*image)->rows;
7630 XConfigureImageColormap(display,resource_info,windows,*image);
7631 (void) XConfigureImage(display,resource_info,windows,*image);
7637 fuzz[MaxTextExtent];
7640 Query user for the fuzz factor.
7642 (void) FormatMagickString(fuzz,MaxTextExtent,"%g%%",100.0*
7643 (*image)->fuzz/(QuantumRange+1.0));
7644 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7647 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
7651 status=XTrimImage(display,resource_info,windows,*image);
7652 if (status == MagickFalse)
7654 XNoticeWidget(display,windows,"Unable to trim X image",
7655 (*image)->filename);
7663 hue_percent[MaxTextExtent] = "110";
7666 Query user for percent hue change.
7668 (void) XDialogWidget(display,windows,"Apply",
7669 "Enter percent change in image hue (0-200):",hue_percent);
7670 if (*hue_percent == '\0')
7675 XSetCursorState(display,windows,MagickTrue);
7676 XCheckRefreshWindows(display,windows);
7677 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7678 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7680 (void) ModulateImage(*image,modulate_factors);
7681 XSetCursorState(display,windows,MagickFalse);
7682 if (windows->image.orphan != MagickFalse)
7684 XConfigureImageColormap(display,resource_info,windows,*image);
7685 (void) XConfigureImage(display,resource_info,windows,*image);
7688 case SaturationCommand:
7691 saturation_percent[MaxTextExtent] = "110";
7694 Query user for percent saturation change.
7696 (void) XDialogWidget(display,windows,"Apply",
7697 "Enter percent change in color saturation (0-200):",saturation_percent);
7698 if (*saturation_percent == '\0')
7701 Vary color saturation.
7703 XSetCursorState(display,windows,MagickTrue);
7704 XCheckRefreshWindows(display,windows);
7705 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7706 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7708 (void) ModulateImage(*image,modulate_factors);
7709 XSetCursorState(display,windows,MagickFalse);
7710 if (windows->image.orphan != MagickFalse)
7712 XConfigureImageColormap(display,resource_info,windows,*image);
7713 (void) XConfigureImage(display,resource_info,windows,*image);
7716 case BrightnessCommand:
7719 brightness_percent[MaxTextExtent] = "110";
7722 Query user for percent brightness change.
7724 (void) XDialogWidget(display,windows,"Apply",
7725 "Enter percent change in color brightness (0-200):",brightness_percent);
7726 if (*brightness_percent == '\0')
7729 Vary the color brightness.
7731 XSetCursorState(display,windows,MagickTrue);
7732 XCheckRefreshWindows(display,windows);
7733 (void) CopyMagickString(modulate_factors,brightness_percent,
7735 (void) ModulateImage(*image,modulate_factors);
7736 XSetCursorState(display,windows,MagickFalse);
7737 if (windows->image.orphan != MagickFalse)
7739 XConfigureImageColormap(display,resource_info,windows,*image);
7740 (void) XConfigureImage(display,resource_info,windows,*image);
7746 factor[MaxTextExtent] = "1.6";
7749 Query user for gamma value.
7751 (void) XDialogWidget(display,windows,"Gamma",
7752 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7753 if (*factor == '\0')
7756 Gamma correct image.
7758 XSetCursorState(display,windows,MagickTrue);
7759 XCheckRefreshWindows(display,windows);
7760 (void) GammaImage(*image,factor);
7761 XSetCursorState(display,windows,MagickFalse);
7762 if (windows->image.orphan != MagickFalse)
7764 XConfigureImageColormap(display,resource_info,windows,*image);
7765 (void) XConfigureImage(display,resource_info,windows,*image);
7771 Sharpen the image contrast.
7773 XSetCursorState(display,windows,MagickTrue);
7774 XCheckRefreshWindows(display,windows);
7775 (void) ContrastImage(*image,MagickTrue);
7776 XSetCursorState(display,windows,MagickFalse);
7777 if (windows->image.orphan != MagickFalse)
7779 XConfigureImageColormap(display,resource_info,windows,*image);
7780 (void) XConfigureImage(display,resource_info,windows,*image);
7786 Dull the image contrast.
7788 XSetCursorState(display,windows,MagickTrue);
7789 XCheckRefreshWindows(display,windows);
7790 (void) ContrastImage(*image,MagickFalse);
7791 XSetCursorState(display,windows,MagickFalse);
7792 if (windows->image.orphan != MagickFalse)
7794 XConfigureImageColormap(display,resource_info,windows,*image);
7795 (void) XConfigureImage(display,resource_info,windows,*image);
7798 case ContrastStretchCommand:
7805 levels[MaxTextExtent] = "1%";
7808 Query user for gamma value.
7810 (void) XDialogWidget(display,windows,"Contrast Stretch",
7811 "Enter black and white points:",levels);
7812 if (*levels == '\0')
7815 Contrast stretch image.
7817 XSetCursorState(display,windows,MagickTrue);
7818 XCheckRefreshWindows(display,windows);
7819 flags=ParseGeometry(levels,&geometry_info);
7820 black_point=geometry_info.rho;
7821 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7822 if ((flags & PercentValue) != 0)
7824 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7825 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7827 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7828 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7830 XSetCursorState(display,windows,MagickFalse);
7831 if (windows->image.orphan != MagickFalse)
7833 XConfigureImageColormap(display,resource_info,windows,*image);
7834 (void) XConfigureImage(display,resource_info,windows,*image);
7837 case SigmoidalContrastCommand:
7840 levels[MaxTextExtent] = "3x50%";
7843 Query user for gamma value.
7845 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7846 "Enter contrast and midpoint:",levels);
7847 if (*levels == '\0')
7850 Contrast stretch image.
7852 XSetCursorState(display,windows,MagickTrue);
7853 XCheckRefreshWindows(display,windows);
7854 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
7855 XSetCursorState(display,windows,MagickFalse);
7856 if (windows->image.orphan != MagickFalse)
7858 XConfigureImageColormap(display,resource_info,windows,*image);
7859 (void) XConfigureImage(display,resource_info,windows,*image);
7862 case NormalizeCommand:
7865 Perform histogram normalization on the image.
7867 XSetCursorState(display,windows,MagickTrue);
7868 XCheckRefreshWindows(display,windows);
7869 (void) NormalizeImage(*image);
7870 XSetCursorState(display,windows,MagickFalse);
7871 if (windows->image.orphan != MagickFalse)
7873 XConfigureImageColormap(display,resource_info,windows,*image);
7874 (void) XConfigureImage(display,resource_info,windows,*image);
7877 case EqualizeCommand:
7880 Perform histogram equalization on the image.
7882 XSetCursorState(display,windows,MagickTrue);
7883 XCheckRefreshWindows(display,windows);
7884 (void) EqualizeImage(*image);
7885 XSetCursorState(display,windows,MagickFalse);
7886 if (windows->image.orphan != MagickFalse)
7888 XConfigureImageColormap(display,resource_info,windows,*image);
7889 (void) XConfigureImage(display,resource_info,windows,*image);
7895 Negate colors in image.
7897 XSetCursorState(display,windows,MagickTrue);
7898 XCheckRefreshWindows(display,windows);
7899 (void) NegateImage(*image,MagickFalse);
7900 XSetCursorState(display,windows,MagickFalse);
7901 if (windows->image.orphan != MagickFalse)
7903 XConfigureImageColormap(display,resource_info,windows,*image);
7904 (void) XConfigureImage(display,resource_info,windows,*image);
7907 case GrayscaleCommand:
7910 Convert image to grayscale.
7912 XSetCursorState(display,windows,MagickTrue);
7913 XCheckRefreshWindows(display,windows);
7914 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7915 GrayscaleType : GrayscaleMatteType);
7916 XSetCursorState(display,windows,MagickFalse);
7917 if (windows->image.orphan != MagickFalse)
7919 XConfigureImageColormap(display,resource_info,windows,*image);
7920 (void) XConfigureImage(display,resource_info,windows,*image);
7929 filename[MaxTextExtent] = "\0";
7932 Request image file name from user.
7934 XFileBrowserWidget(display,windows,"Map",filename);
7935 if (*filename == '\0')
7940 XSetCursorState(display,windows,MagickTrue);
7941 XCheckRefreshWindows(display,windows);
7942 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7943 affinity_image=ReadImage(image_info,&(*image)->exception);
7944 if (affinity_image != (Image *) NULL)
7946 (void) RemapImage(&quantize_info,*image,affinity_image);
7947 affinity_image=DestroyImage(affinity_image);
7949 CatchException(&(*image)->exception);
7950 XSetCursorState(display,windows,MagickFalse);
7951 if (windows->image.orphan != MagickFalse)
7953 XConfigureImageColormap(display,resource_info,windows,*image);
7954 (void) XConfigureImage(display,resource_info,windows,*image);
7957 case QuantizeCommand:
7963 colors[MaxTextExtent] = "256";
7966 Query user for maximum number of colors.
7968 status=XDialogWidget(display,windows,"Quantize",
7969 "Maximum number of colors:",colors);
7970 if (*colors == '\0')
7973 Color reduce the image.
7975 XSetCursorState(display,windows,MagickTrue);
7976 XCheckRefreshWindows(display,windows);
7977 quantize_info.number_colors=StringToUnsignedLong(colors);
7978 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7979 (void) QuantizeImage(&quantize_info,*image);
7980 XSetCursorState(display,windows,MagickFalse);
7981 if (windows->image.orphan != MagickFalse)
7983 XConfigureImageColormap(display,resource_info,windows,*image);
7984 (void) XConfigureImage(display,resource_info,windows,*image);
7987 case DespeckleCommand:
7995 XSetCursorState(display,windows,MagickTrue);
7996 XCheckRefreshWindows(display,windows);
7997 despeckle_image=DespeckleImage(*image,&(*image)->exception);
7998 if (despeckle_image != (Image *) NULL)
8000 *image=DestroyImage(*image);
8001 *image=despeckle_image;
8003 CatchException(&(*image)->exception);
8004 XSetCursorState(display,windows,MagickFalse);
8005 if (windows->image.orphan != MagickFalse)
8007 XConfigureImageColormap(display,resource_info,windows,*image);
8008 (void) XConfigureImage(display,resource_info,windows,*image);
8017 radius[MaxTextExtent] = "0.0x1.0";
8020 Query user for emboss radius.
8022 (void) XDialogWidget(display,windows,"Emboss",
8023 "Enter the emboss radius and standard deviation:",radius);
8024 if (*radius == '\0')
8027 Reduce noise in the image.
8029 XSetCursorState(display,windows,MagickTrue);
8030 XCheckRefreshWindows(display,windows);
8031 flags=ParseGeometry(radius,&geometry_info);
8032 if ((flags & SigmaValue) == 0)
8033 geometry_info.sigma=1.0;
8034 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8035 &(*image)->exception);
8036 if (emboss_image != (Image *) NULL)
8038 *image=DestroyImage(*image);
8039 *image=emboss_image;
8041 CatchException(&(*image)->exception);
8042 XSetCursorState(display,windows,MagickFalse);
8043 if (windows->image.orphan != MagickFalse)
8045 XConfigureImageColormap(display,resource_info,windows,*image);
8046 (void) XConfigureImage(display,resource_info,windows,*image);
8049 case ReduceNoiseCommand:
8055 radius[MaxTextExtent] = "0";
8058 Query user for noise radius.
8060 (void) XDialogWidget(display,windows,"Reduce Noise",
8061 "Enter the noise radius:",radius);
8062 if (*radius == '\0')
8065 Reduce noise in the image.
8067 XSetCursorState(display,windows,MagickTrue);
8068 XCheckRefreshWindows(display,windows);
8069 flags=ParseGeometry(radius,&geometry_info);
8070 noise_image=ReduceNoiseImage(*image,geometry_info.rho,
8071 &(*image)->exception);
8072 if (noise_image != (Image *) NULL)
8074 *image=DestroyImage(*image);
8077 CatchException(&(*image)->exception);
8078 XSetCursorState(display,windows,MagickFalse);
8079 if (windows->image.orphan != MagickFalse)
8081 XConfigureImageColormap(display,resource_info,windows,*image);
8082 (void) XConfigureImage(display,resource_info,windows,*image);
8085 case AddNoiseCommand:
8094 noise_type[MaxTextExtent] = "Gaussian";
8097 Add noise to the image.
8099 noises=GetMagickOptions(MagickNoiseOptions);
8100 if (noises == (char **) NULL)
8102 XListBrowserWidget(display,windows,&windows->widget,
8103 (const char **) noises,"Add Noise",
8104 "Select a type of noise to add to your image:",noise_type);
8105 noises=DestroyStringList(noises);
8106 if (*noise_type == '\0')
8108 XSetCursorState(display,windows,MagickTrue);
8109 XCheckRefreshWindows(display,windows);
8110 noise_image=AddNoiseImage(*image,(NoiseType) ParseMagickOption(
8111 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8112 if (noise_image != (Image *) NULL)
8114 *image=DestroyImage(*image);
8117 CatchException(&(*image)->exception);
8118 XSetCursorState(display,windows,MagickFalse);
8119 if (windows->image.orphan != MagickFalse)
8121 XConfigureImageColormap(display,resource_info,windows,*image);
8122 (void) XConfigureImage(display,resource_info,windows,*image);
8125 case SharpenCommand:
8131 radius[MaxTextExtent] = "0.0x1.0";
8134 Query user for sharpen radius.
8136 (void) XDialogWidget(display,windows,"Sharpen",
8137 "Enter the sharpen radius and standard deviation:",radius);
8138 if (*radius == '\0')
8141 Sharpen image scanlines.
8143 XSetCursorState(display,windows,MagickTrue);
8144 XCheckRefreshWindows(display,windows);
8145 flags=ParseGeometry(radius,&geometry_info);
8146 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8147 &(*image)->exception);
8148 if (sharp_image != (Image *) NULL)
8150 *image=DestroyImage(*image);
8153 CatchException(&(*image)->exception);
8154 XSetCursorState(display,windows,MagickFalse);
8155 if (windows->image.orphan != MagickFalse)
8157 XConfigureImageColormap(display,resource_info,windows,*image);
8158 (void) XConfigureImage(display,resource_info,windows,*image);
8167 radius[MaxTextExtent] = "0.0x1.0";
8170 Query user for blur radius.
8172 (void) XDialogWidget(display,windows,"Blur",
8173 "Enter the blur radius and standard deviation:",radius);
8174 if (*radius == '\0')
8179 XSetCursorState(display,windows,MagickTrue);
8180 XCheckRefreshWindows(display,windows);
8181 flags=ParseGeometry(radius,&geometry_info);
8182 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8183 &(*image)->exception);
8184 if (blur_image != (Image *) NULL)
8186 *image=DestroyImage(*image);
8189 CatchException(&(*image)->exception);
8190 XSetCursorState(display,windows,MagickFalse);
8191 if (windows->image.orphan != MagickFalse)
8193 XConfigureImageColormap(display,resource_info,windows,*image);
8194 (void) XConfigureImage(display,resource_info,windows,*image);
8197 case ThresholdCommand:
8203 factor[MaxTextExtent] = "128";
8206 Query user for threshold value.
8208 (void) XDialogWidget(display,windows,"Threshold",
8209 "Enter threshold value:",factor);
8210 if (*factor == '\0')
8213 Gamma correct image.
8215 XSetCursorState(display,windows,MagickTrue);
8216 XCheckRefreshWindows(display,windows);
8217 threshold=SiPrefixToDouble(factor,QuantumRange);
8218 (void) BilevelImage(*image,threshold);
8219 XSetCursorState(display,windows,MagickFalse);
8220 if (windows->image.orphan != MagickFalse)
8222 XConfigureImageColormap(display,resource_info,windows,*image);
8223 (void) XConfigureImage(display,resource_info,windows,*image);
8226 case EdgeDetectCommand:
8232 radius[MaxTextExtent] = "0";
8235 Query user for edge factor.
8237 (void) XDialogWidget(display,windows,"Detect Edges",
8238 "Enter the edge detect radius:",radius);
8239 if (*radius == '\0')
8242 Detect edge in image.
8244 XSetCursorState(display,windows,MagickTrue);
8245 XCheckRefreshWindows(display,windows);
8246 flags=ParseGeometry(radius,&geometry_info);
8247 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8248 if (edge_image != (Image *) NULL)
8250 *image=DestroyImage(*image);
8253 CatchException(&(*image)->exception);
8254 XSetCursorState(display,windows,MagickFalse);
8255 if (windows->image.orphan != MagickFalse)
8257 XConfigureImageColormap(display,resource_info,windows,*image);
8258 (void) XConfigureImage(display,resource_info,windows,*image);
8267 amount[MaxTextExtent] = "2";
8270 Query user for spread amount.
8272 (void) XDialogWidget(display,windows,"Spread",
8273 "Enter the displacement amount:",amount);
8274 if (*amount == '\0')
8277 Displace image pixels by a random amount.
8279 XSetCursorState(display,windows,MagickTrue);
8280 XCheckRefreshWindows(display,windows);
8281 flags=ParseGeometry(amount,&geometry_info);
8282 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8283 if (spread_image != (Image *) NULL)
8285 *image=DestroyImage(*image);
8286 *image=spread_image;
8288 CatchException(&(*image)->exception);
8289 XSetCursorState(display,windows,MagickFalse);
8290 if (windows->image.orphan != MagickFalse)
8292 XConfigureImageColormap(display,resource_info,windows,*image);
8293 (void) XConfigureImage(display,resource_info,windows,*image);
8305 geometry[MaxTextExtent] = "30x30";
8308 Query user for the shade geometry.
8310 status=XDialogWidget(display,windows,"Shade",
8311 "Enter the azimuth and elevation of the light source:",geometry);
8312 if (*geometry == '\0')
8317 XSetCursorState(display,windows,MagickTrue);
8318 XCheckRefreshWindows(display,windows);
8319 flags=ParseGeometry(geometry,&geometry_info);
8320 if ((flags & SigmaValue) == 0)
8321 geometry_info.sigma=1.0;
8322 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8323 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8324 if (shade_image != (Image *) NULL)
8326 *image=DestroyImage(*image);
8329 CatchException(&(*image)->exception);
8330 XSetCursorState(display,windows,MagickFalse);
8331 if (windows->image.orphan != MagickFalse)
8333 XConfigureImageColormap(display,resource_info,windows,*image);
8334 (void) XConfigureImage(display,resource_info,windows,*image);
8340 bevel_width[MaxTextExtent] = "10";
8343 Query user for bevel width.
8345 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8346 if (*bevel_width == '\0')
8351 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8352 XSetCursorState(display,windows,MagickTrue);
8353 XCheckRefreshWindows(display,windows);
8354 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8355 &(*image)->exception);
8356 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8357 XSetCursorState(display,windows,MagickFalse);
8358 if (windows->image.orphan != MagickFalse)
8360 XConfigureImageColormap(display,resource_info,windows,*image);
8361 (void) XConfigureImage(display,resource_info,windows,*image);
8364 case SegmentCommand:
8367 threshold[MaxTextExtent] = "1.0x1.5";
8370 Query user for smoothing threshold.
8372 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8374 if (*threshold == '\0')
8379 XSetCursorState(display,windows,MagickTrue);
8380 XCheckRefreshWindows(display,windows);
8381 flags=ParseGeometry(threshold,&geometry_info);
8382 if ((flags & SigmaValue) == 0)
8383 geometry_info.sigma=1.0;
8384 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8385 geometry_info.sigma);
8386 XSetCursorState(display,windows,MagickFalse);
8387 if (windows->image.orphan != MagickFalse)
8389 XConfigureImageColormap(display,resource_info,windows,*image);
8390 (void) XConfigureImage(display,resource_info,windows,*image);
8393 case SepiaToneCommand:
8402 factor[MaxTextExtent] = "80%";
8405 Query user for sepia-tone factor.
8407 (void) XDialogWidget(display,windows,"Sepia Tone",
8408 "Enter the sepia tone factor (0 - 99.9%):",factor);
8409 if (*factor == '\0')
8412 Sepia tone image pixels.
8414 XSetCursorState(display,windows,MagickTrue);
8415 XCheckRefreshWindows(display,windows);
8416 threshold=SiPrefixToDouble(factor,QuantumRange);
8417 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8418 if (sepia_image != (Image *) NULL)
8420 *image=DestroyImage(*image);
8423 CatchException(&(*image)->exception);
8424 XSetCursorState(display,windows,MagickFalse);
8425 if (windows->image.orphan != MagickFalse)
8427 XConfigureImageColormap(display,resource_info,windows,*image);
8428 (void) XConfigureImage(display,resource_info,windows,*image);
8431 case SolarizeCommand:
8437 factor[MaxTextExtent] = "60%";
8440 Query user for solarize factor.
8442 (void) XDialogWidget(display,windows,"Solarize",
8443 "Enter the solarize factor (0 - 99.9%):",factor);
8444 if (*factor == '\0')
8447 Solarize image pixels.
8449 XSetCursorState(display,windows,MagickTrue);
8450 XCheckRefreshWindows(display,windows);
8451 threshold=SiPrefixToDouble(factor,QuantumRange);
8452 (void) SolarizeImage(*image,threshold);
8453 XSetCursorState(display,windows,MagickFalse);
8454 if (windows->image.orphan != MagickFalse)
8456 XConfigureImageColormap(display,resource_info,windows,*image);
8457 (void) XConfigureImage(display,resource_info,windows,*image);
8466 degrees[MaxTextExtent] = "60";
8469 Query user for swirl angle.
8471 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8473 if (*degrees == '\0')
8476 Swirl image pixels about the center.
8478 XSetCursorState(display,windows,MagickTrue);
8479 XCheckRefreshWindows(display,windows);
8480 flags=ParseGeometry(degrees,&geometry_info);
8481 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8482 if (swirl_image != (Image *) NULL)
8484 *image=DestroyImage(*image);
8487 CatchException(&(*image)->exception);
8488 XSetCursorState(display,windows,MagickFalse);
8489 if (windows->image.orphan != MagickFalse)
8491 XConfigureImageColormap(display,resource_info,windows,*image);
8492 (void) XConfigureImage(display,resource_info,windows,*image);
8495 case ImplodeCommand:
8501 factor[MaxTextExtent] = "0.3";
8504 Query user for implode factor.
8506 (void) XDialogWidget(display,windows,"Implode",
8507 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8508 if (*factor == '\0')
8511 Implode image pixels about the center.
8513 XSetCursorState(display,windows,MagickTrue);
8514 XCheckRefreshWindows(display,windows);
8515 flags=ParseGeometry(factor,&geometry_info);
8516 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8517 if (implode_image != (Image *) NULL)
8519 *image=DestroyImage(*image);
8520 *image=implode_image;
8522 CatchException(&(*image)->exception);
8523 XSetCursorState(display,windows,MagickFalse);
8524 if (windows->image.orphan != MagickFalse)
8526 XConfigureImageColormap(display,resource_info,windows,*image);
8527 (void) XConfigureImage(display,resource_info,windows,*image);
8530 case VignetteCommand:
8536 geometry[MaxTextExtent] = "0x20";
8539 Query user for the vignette geometry.
8541 (void) XDialogWidget(display,windows,"Vignette",
8542 "Enter the radius, sigma, and x and y offsets:",geometry);
8543 if (*geometry == '\0')
8546 Soften the edges of the image in vignette style
8548 XSetCursorState(display,windows,MagickTrue);
8549 XCheckRefreshWindows(display,windows);
8550 flags=ParseGeometry(geometry,&geometry_info);
8551 if ((flags & SigmaValue) == 0)
8552 geometry_info.sigma=1.0;
8553 if ((flags & XiValue) == 0)
8554 geometry_info.xi=0.1*(*image)->columns;
8555 if ((flags & PsiValue) == 0)
8556 geometry_info.psi=0.1*(*image)->rows;
8557 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8558 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8559 0.5),&(*image)->exception);
8560 if (vignette_image != (Image *) NULL)
8562 *image=DestroyImage(*image);
8563 *image=vignette_image;
8565 CatchException(&(*image)->exception);
8566 XSetCursorState(display,windows,MagickFalse);
8567 if (windows->image.orphan != MagickFalse)
8569 XConfigureImageColormap(display,resource_info,windows,*image);
8570 (void) XConfigureImage(display,resource_info,windows,*image);
8579 geometry[MaxTextExtent] = "25x150";
8582 Query user for the wave geometry.
8584 (void) XDialogWidget(display,windows,"Wave",
8585 "Enter the amplitude and length of the wave:",geometry);
8586 if (*geometry == '\0')
8589 Alter an image along a sine wave.
8591 XSetCursorState(display,windows,MagickTrue);
8592 XCheckRefreshWindows(display,windows);
8593 flags=ParseGeometry(geometry,&geometry_info);
8594 if ((flags & SigmaValue) == 0)
8595 geometry_info.sigma=1.0;
8596 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8597 &(*image)->exception);
8598 if (wave_image != (Image *) NULL)
8600 *image=DestroyImage(*image);
8603 CatchException(&(*image)->exception);
8604 XSetCursorState(display,windows,MagickFalse);
8605 if (windows->image.orphan != MagickFalse)
8607 XConfigureImageColormap(display,resource_info,windows,*image);
8608 (void) XConfigureImage(display,resource_info,windows,*image);
8611 case OilPaintCommand:
8617 radius[MaxTextExtent] = "0";
8620 Query user for circular neighborhood radius.
8622 (void) XDialogWidget(display,windows,"Oil Paint",
8623 "Enter the mask radius:",radius);
8624 if (*radius == '\0')
8627 OilPaint image scanlines.
8629 XSetCursorState(display,windows,MagickTrue);
8630 XCheckRefreshWindows(display,windows);
8631 flags=ParseGeometry(radius,&geometry_info);
8632 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8633 if (paint_image != (Image *) NULL)
8635 *image=DestroyImage(*image);
8638 CatchException(&(*image)->exception);
8639 XSetCursorState(display,windows,MagickFalse);
8640 if (windows->image.orphan != MagickFalse)
8642 XConfigureImageColormap(display,resource_info,windows,*image);
8643 (void) XConfigureImage(display,resource_info,windows,*image);
8646 case CharcoalDrawCommand:
8652 radius[MaxTextExtent] = "0x1";
8655 Query user for charcoal radius.
8657 (void) XDialogWidget(display,windows,"Charcoal Draw",
8658 "Enter the charcoal radius and sigma:",radius);
8659 if (*radius == '\0')
8664 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8665 XSetCursorState(display,windows,MagickTrue);
8666 XCheckRefreshWindows(display,windows);
8667 flags=ParseGeometry(radius,&geometry_info);
8668 if ((flags & SigmaValue) == 0)
8669 geometry_info.sigma=geometry_info.rho;
8670 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8671 &(*image)->exception);
8672 if (charcoal_image != (Image *) NULL)
8674 *image=DestroyImage(*image);
8675 *image=charcoal_image;
8677 CatchException(&(*image)->exception);
8678 XSetCursorState(display,windows,MagickFalse);
8679 if (windows->image.orphan != MagickFalse)
8681 XConfigureImageColormap(display,resource_info,windows,*image);
8682 (void) XConfigureImage(display,resource_info,windows,*image);
8685 case AnnotateCommand:
8688 Annotate the image with text.
8690 status=XAnnotateEditImage(display,resource_info,windows,*image);
8691 if (status == MagickFalse)
8693 XNoticeWidget(display,windows,"Unable to annotate X image",
8694 (*image)->filename);
8704 status=XDrawEditImage(display,resource_info,windows,image);
8705 if (status == MagickFalse)
8707 XNoticeWidget(display,windows,"Unable to draw on the X image",
8708 (*image)->filename);
8718 status=XColorEditImage(display,resource_info,windows,image);
8719 if (status == MagickFalse)
8721 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8722 (*image)->filename);
8732 status=XMatteEditImage(display,resource_info,windows,image);
8733 if (status == MagickFalse)
8735 XNoticeWidget(display,windows,"Unable to matte edit X image",
8736 (*image)->filename);
8741 case CompositeCommand:
8746 status=XCompositeImage(display,resource_info,windows,*image);
8747 if (status == MagickFalse)
8749 XNoticeWidget(display,windows,"Unable to composite X image",
8750 (*image)->filename);
8755 case AddBorderCommand:
8761 geometry[MaxTextExtent] = "6x6";
8764 Query user for border color and geometry.
8766 XColorBrowserWidget(display,windows,"Select",color);
8769 (void) XDialogWidget(display,windows,"Add Border",
8770 "Enter border geometry:",geometry);
8771 if (*geometry == '\0')
8774 Add a border to the image.
8776 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8777 XSetCursorState(display,windows,MagickTrue);
8778 XCheckRefreshWindows(display,windows);
8779 (void) QueryColorDatabase(color,&(*image)->border_color,
8780 &(*image)->exception);
8781 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8782 &(*image)->exception);
8783 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8784 if (border_image != (Image *) NULL)
8786 *image=DestroyImage(*image);
8787 *image=border_image;
8789 CatchException(&(*image)->exception);
8790 XSetCursorState(display,windows,MagickFalse);
8791 if (windows->image.orphan != MagickFalse)
8793 windows->image.window_changes.width=(int) (*image)->columns;
8794 windows->image.window_changes.height=(int) (*image)->rows;
8795 XConfigureImageColormap(display,resource_info,windows,*image);
8796 (void) XConfigureImage(display,resource_info,windows,*image);
8799 case AddFrameCommand:
8808 geometry[MaxTextExtent] = "6x6";
8811 Query user for frame color and geometry.
8813 XColorBrowserWidget(display,windows,"Select",color);
8816 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8818 if (*geometry == '\0')
8821 Surround image with an ornamental border.
8823 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8824 XSetCursorState(display,windows,MagickTrue);
8825 XCheckRefreshWindows(display,windows);
8826 (void) QueryColorDatabase(color,&(*image)->matte_color,
8827 &(*image)->exception);
8828 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8829 &(*image)->exception);
8830 frame_info.width=page_geometry.width;
8831 frame_info.height=page_geometry.height;
8832 frame_info.outer_bevel=page_geometry.x;
8833 frame_info.inner_bevel=page_geometry.y;
8834 frame_info.x=(ssize_t) frame_info.width;
8835 frame_info.y=(ssize_t) frame_info.height;
8836 frame_info.width=(*image)->columns+2*frame_info.width;
8837 frame_info.height=(*image)->rows+2*frame_info.height;
8838 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8839 if (frame_image != (Image *) NULL)
8841 *image=DestroyImage(*image);
8844 CatchException(&(*image)->exception);
8845 XSetCursorState(display,windows,MagickFalse);
8846 if (windows->image.orphan != MagickFalse)
8848 windows->image.window_changes.width=(int) (*image)->columns;
8849 windows->image.window_changes.height=(int) (*image)->rows;
8850 XConfigureImageColormap(display,resource_info,windows,*image);
8851 (void) XConfigureImage(display,resource_info,windows,*image);
8854 case CommentCommand:
8868 unique_file=AcquireUniqueFileResource(image_info->filename);
8869 if (unique_file == -1)
8870 XNoticeWidget(display,windows,"Unable to edit image comment",
8871 image_info->filename);
8872 value=GetImageProperty(*image,"comment");
8873 if (value == (char *) NULL)
8874 unique_file=close(unique_file)-1;
8880 file=fdopen(unique_file,"w");
8881 if (file == (FILE *) NULL)
8883 XNoticeWidget(display,windows,"Unable to edit image comment",
8884 image_info->filename);
8887 for (p=value; *p != '\0'; p++)
8888 (void) fputc((int) *p,file);
8889 (void) fputc('\n',file);
8890 (void) fclose(file);
8892 XSetCursorState(display,windows,MagickTrue);
8893 XCheckRefreshWindows(display,windows);
8894 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8895 &(*image)->exception);
8896 if (status == MagickFalse)
8897 XNoticeWidget(display,windows,"Unable to edit image comment",
8904 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8905 if (comment != (char *) NULL)
8907 (void) SetImageProperty(*image,"comment",comment);
8908 (*image)->taint=MagickTrue;
8911 (void) RelinquishUniqueFileResource(image_info->filename);
8912 XSetCursorState(display,windows,MagickFalse);
8920 XSetCursorState(display,windows,MagickTrue);
8921 XCheckRefreshWindows(display,windows);
8922 (void) AcquireUniqueFilename(filename);
8923 (void) FormatMagickString((*image)->filename,MaxTextExtent,"launch:%s",
8925 status=WriteImage(image_info,*image);
8926 if (status == MagickFalse)
8927 XNoticeWidget(display,windows,"Unable to launch image editor",
8931 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8932 CatchException(&(*image)->exception);
8933 XClientMessage(display,windows->image.id,windows->im_protocols,
8934 windows->im_next_image,CurrentTime);
8936 (void) RelinquishUniqueFileResource(filename);
8937 XSetCursorState(display,windows,MagickFalse);
8940 case RegionofInterestCommand:
8943 Apply an image processing technique to a region of interest.
8945 (void) XROIImage(display,resource_info,windows,image);
8955 if (windows->magnify.mapped != MagickFalse)
8956 (void) XRaiseWindow(display,windows->magnify.id);
8962 XSetCursorState(display,windows,MagickTrue);
8963 (void) XMapRaised(display,windows->magnify.id);
8964 XSetCursorState(display,windows,MagickFalse);
8968 case ShowPreviewCommand:
8977 preview_type[MaxTextExtent] = "Gamma";
8980 Select preview type from menu.
8982 previews=GetMagickOptions(MagickPreviewOptions);
8983 if (previews == (char **) NULL)
8985 XListBrowserWidget(display,windows,&windows->widget,
8986 (const char **) previews,"Preview",
8987 "Select an enhancement, effect, or F/X:",preview_type);
8988 previews=DestroyStringList(previews);
8989 if (*preview_type == '\0')
8994 XSetCursorState(display,windows,MagickTrue);
8995 XCheckRefreshWindows(display,windows);
8996 image_info->preview_type=(PreviewType)
8997 ParseMagickOption(MagickPreviewOptions,MagickFalse,preview_type);
8998 image_info->group=(ssize_t) windows->image.id;
8999 (void) DeleteImageProperty(*image,"label");
9000 (void) SetImageProperty(*image,"label","Preview");
9001 (void) AcquireUniqueFilename(filename);
9002 (void) FormatMagickString((*image)->filename,MaxTextExtent,"preview:%s",
9004 status=WriteImage(image_info,*image);
9005 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9006 preview_image=ReadImage(image_info,&(*image)->exception);
9007 (void) RelinquishUniqueFileResource(filename);
9008 if (preview_image == (Image *) NULL)
9010 (void) FormatMagickString(preview_image->filename,MaxTextExtent,"show:%s",
9012 status=WriteImage(image_info,preview_image);
9013 preview_image=DestroyImage(preview_image);
9014 if (status == MagickFalse)
9015 XNoticeWidget(display,windows,"Unable to show image preview",
9016 (*image)->filename);
9017 XDelay(display,1500);
9018 XSetCursorState(display,windows,MagickFalse);
9021 case ShowHistogramCommand:
9027 Show image histogram.
9029 XSetCursorState(display,windows,MagickTrue);
9030 XCheckRefreshWindows(display,windows);
9031 image_info->group=(ssize_t) windows->image.id;
9032 (void) DeleteImageProperty(*image,"label");
9033 (void) SetImageProperty(*image,"label","Histogram");
9034 (void) AcquireUniqueFilename(filename);
9035 (void) FormatMagickString((*image)->filename,MaxTextExtent,"histogram:%s",
9037 status=WriteImage(image_info,*image);
9038 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9039 histogram_image=ReadImage(image_info,&(*image)->exception);
9040 (void) RelinquishUniqueFileResource(filename);
9041 if (histogram_image == (Image *) NULL)
9043 (void) FormatMagickString(histogram_image->filename,MaxTextExtent,
9044 "show:%s",filename);
9045 status=WriteImage(image_info,histogram_image);
9046 histogram_image=DestroyImage(histogram_image);
9047 if (status == MagickFalse)
9048 XNoticeWidget(display,windows,"Unable to show histogram",
9049 (*image)->filename);
9050 XDelay(display,1500);
9051 XSetCursorState(display,windows,MagickFalse);
9054 case ShowMatteCommand:
9059 if ((*image)->matte == MagickFalse)
9061 XNoticeWidget(display,windows,
9062 "Image does not have any matte information",(*image)->filename);
9068 XSetCursorState(display,windows,MagickTrue);
9069 XCheckRefreshWindows(display,windows);
9070 image_info->group=(ssize_t) windows->image.id;
9071 (void) DeleteImageProperty(*image,"label");
9072 (void) SetImageProperty(*image,"label","Matte");
9073 (void) AcquireUniqueFilename(filename);
9074 (void) FormatMagickString((*image)->filename,MaxTextExtent,"matte:%s",
9076 status=WriteImage(image_info,*image);
9077 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9078 matte_image=ReadImage(image_info,&(*image)->exception);
9079 (void) RelinquishUniqueFileResource(filename);
9080 if (matte_image == (Image *) NULL)
9082 (void) FormatMagickString(matte_image->filename,MaxTextExtent,"show:%s",
9084 status=WriteImage(image_info,matte_image);
9085 matte_image=DestroyImage(matte_image);
9086 if (status == MagickFalse)
9087 XNoticeWidget(display,windows,"Unable to show matte",
9088 (*image)->filename);
9089 XDelay(display,1500);
9090 XSetCursorState(display,windows,MagickFalse);
9093 case BackgroundCommand:
9098 status=XBackgroundImage(display,resource_info,windows,image);
9099 if (status == MagickFalse)
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);
9107 case SlideShowCommand:
9110 delay[MaxTextExtent] = "5";
9113 Display next image after pausing.
9115 (void) XDialogWidget(display,windows,"Slide Show",
9116 "Pause how many 1/100ths of a second between images:",delay);
9119 resource_info->delay=StringToUnsignedLong(delay);
9120 XClientMessage(display,windows->image.id,windows->im_protocols,
9121 windows->im_next_image,CurrentTime);
9124 case PreferencesCommand:
9127 Set user preferences.
9129 status=XPreferencesWidget(display,resource_info,windows);
9130 if (status == MagickFalse)
9132 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9133 if (nexus != (Image *) NULL)
9134 XClientMessage(display,windows->image.id,windows->im_protocols,
9135 windows->im_next_image,CurrentTime);
9141 User requested help.
9143 XTextViewWidget(display,resource_info,windows,MagickFalse,
9144 "Help Viewer - Display",DisplayHelp);
9147 case BrowseDocumentationCommand:
9157 Browse the ImageMagick documentation.
9159 root_window=XRootWindow(display,XDefaultScreen(display));
9160 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9161 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9162 if (mozilla_window != (Window) NULL)
9165 command[MaxTextExtent],
9169 Display documentation using Netscape remote control.
9171 url=GetMagickHomeURL();
9172 (void) FormatMagickString(command,MaxTextExtent,
9173 "openurl(%s,new-tab)",url);
9174 url=DestroyString(url);
9175 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9176 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9177 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9178 XSetCursorState(display,windows,MagickFalse);
9181 XSetCursorState(display,windows,MagickTrue);
9182 XCheckRefreshWindows(display,windows);
9183 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9184 &(*image)->exception);
9185 if (status == MagickFalse)
9186 XNoticeWidget(display,windows,"Unable to browse documentation",
9188 XDelay(display,1500);
9189 XSetCursorState(display,windows,MagickFalse);
9192 case VersionCommand:
9194 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9195 GetMagickCopyright());
9198 case SaveToUndoBufferCommand:
9202 (void) XBell(display,0);
9206 image_info=DestroyImageInfo(image_info);
9211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9215 + X M a g n i f y I m a g e %
9219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9221 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9222 % The magnified portion is displayed in a separate window.
9224 % The format of the XMagnifyImage method is:
9226 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9228 % A description of each parameter follows:
9230 % o display: Specifies a connection to an X server; returned from
9233 % o windows: Specifies a pointer to a XWindows structure.
9235 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9236 % the entire image is refreshed.
9239 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9242 text[MaxTextExtent];
9252 Update magnified image until the mouse button is released.
9254 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9258 windows->magnify.x=(int) windows->image.x+x;
9259 windows->magnify.y=(int) windows->image.y+y;
9263 Map and unmap Info widget as text cursor crosses its boundaries.
9265 if (windows->info.mapped != MagickFalse)
9267 if ((x < (int) (windows->info.x+windows->info.width)) &&
9268 (y < (int) (windows->info.y+windows->info.height)))
9269 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9272 if ((x > (int) (windows->info.x+windows->info.width)) ||
9273 (y > (int) (windows->info.y+windows->info.height)))
9274 (void) XMapWindow(display,windows->info.id);
9275 if (windows->info.mapped != MagickFalse)
9278 Display pointer position.
9280 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9281 windows->magnify.x,windows->magnify.y);
9282 XInfoWidget(display,windows,text);
9285 Wait for next event.
9287 XScreenEvent(display,windows,event);
9288 switch (event->type)
9295 User has finished magnifying image.
9314 Check boundary conditions.
9319 if (x >= (int) windows->image.width)
9320 x=(int) windows->image.width-1;
9324 if (y >= (int) windows->image.height)
9325 y=(int) windows->image.height-1;
9326 } while ((state & ExitState) == 0);
9328 Display magnified image.
9330 XSetCursorState(display,windows,MagickFalse);
9334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9338 + X M a g n i f y W i n d o w C o m m a n d %
9342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9344 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9345 % pixel as specified by the key symbol.
9347 % The format of the XMagnifyWindowCommand method is:
9349 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9350 % const MagickStatusType state,const KeySym key_symbol)
9352 % A description of each parameter follows:
9354 % o display: Specifies a connection to an X server; returned from
9357 % o windows: Specifies a pointer to a XWindows structure.
9359 % o state: key mask.
9361 % o key_symbol: Specifies a KeySym which indicates which side of the image
9365 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9366 const MagickStatusType state,const KeySym key_symbol)
9372 User specified a magnify factor or position.
9375 if ((state & Mod1Mask) != 0)
9377 switch ((int) key_symbol)
9381 (void) XWithdrawWindow(display,windows->magnify.id,
9382 windows->magnify.screen);
9388 windows->magnify.x=(int) windows->image.width/2;
9389 windows->magnify.y=(int) windows->image.height/2;
9395 if (windows->magnify.x > 0)
9396 windows->magnify.x-=quantum;
9402 if (windows->magnify.y > 0)
9403 windows->magnify.y-=quantum;
9409 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9410 windows->magnify.x+=quantum;
9416 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9417 windows->magnify.y+=quantum;
9431 windows->magnify.data=(key_symbol-XK_0);
9445 windows->magnify.data=(key_symbol-XK_KP_0);
9451 XMakeMagnifyImage(display,windows);
9455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9459 + X M a k e P a n I m a g e %
9463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9465 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9468 % The format of the XMakePanImage method is:
9470 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9471 % XWindows *windows,Image *image)
9473 % A description of each parameter follows:
9475 % o display: Specifies a connection to an X server; returned from
9478 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9480 % o windows: Specifies a pointer to a XWindows structure.
9482 % o image: the image.
9485 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9486 XWindows *windows,Image *image)
9492 Create and display image for panning icon.
9494 XSetCursorState(display,windows,MagickTrue);
9495 XCheckRefreshWindows(display,windows);
9496 windows->pan.x=(int) windows->image.x;
9497 windows->pan.y=(int) windows->image.y;
9498 status=XMakeImage(display,resource_info,&windows->pan,image,
9499 windows->pan.width,windows->pan.height);
9500 if (status == MagickFalse)
9501 ThrowXWindowFatalException(XServerError,image->exception.reason,
9502 image->exception.description);
9503 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9504 windows->pan.pixmap);
9505 (void) XClearWindow(display,windows->pan.id);
9506 XDrawPanRectangle(display,windows);
9507 XSetCursorState(display,windows,MagickFalse);
9511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9515 + X M a t t a E d i t I m a g e %
9519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9521 % XMatteEditImage() allows the user to interactively change the Matte channel
9522 % of an image. If the image is PseudoClass it is promoted to DirectClass
9523 % before the matte information is stored.
9525 % The format of the XMatteEditImage method is:
9527 % MagickBooleanType XMatteEditImage(Display *display,
9528 % XResourceInfo *resource_info,XWindows *windows,Image **image)
9530 % A description of each parameter follows:
9532 % o display: Specifies a connection to an X server; returned from
9535 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9537 % o windows: Specifies a pointer to a XWindows structure.
9539 % o image: the image; returned from ReadImage.
9542 static MagickBooleanType XMatteEditImage(Display *display,
9543 XResourceInfo *resource_info,XWindows *windows,Image **image)
9546 matte[MaxTextExtent] = "0";
9561 static const ModeType
9562 MatteEditCommands[] =
9565 MatteEditBorderCommand,
9566 MatteEditFuzzCommand,
9567 MatteEditValueCommand,
9568 MatteEditUndoCommand,
9569 MatteEditHelpCommand,
9570 MatteEditDismissCommand
9574 method = PointMethod;
9577 border_color = { 0, 0, 0, 0, 0, 0 };
9580 command[MaxTextExtent],
9581 text[MaxTextExtent];
9597 register PixelPacket
9613 (void) CloneString(&windows->command.name,"Matte Edit");
9614 windows->command.data=4;
9615 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9616 (void) XMapRaised(display,windows->command.id);
9617 XClientMessage(display,windows->image.id,windows->im_protocols,
9618 windows->im_update_widget,CurrentTime);
9622 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9623 resource_info->background_color,resource_info->foreground_color);
9624 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9626 Track pointer until button 1 is pressed.
9628 XQueryPosition(display,windows->image.id,&x,&y);
9629 (void) XSelectInput(display,windows->image.id,
9630 windows->image.attributes.event_mask | PointerMotionMask);
9634 if (windows->info.mapped != MagickFalse)
9637 Display pointer position.
9639 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9640 x+windows->image.x,y+windows->image.y);
9641 XInfoWidget(display,windows,text);
9644 Wait for next event.
9646 XScreenEvent(display,windows,&event);
9647 if (event.xany.window == windows->command.id)
9650 Select a command from the Command widget.
9652 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9655 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9658 switch (MatteEditCommands[id])
9660 case MatteEditMethod:
9666 Select a method from the pop-up menu.
9668 methods=GetMagickOptions(MagickMethodOptions);
9669 if (methods == (char **) NULL)
9671 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9672 (const char **) methods,command);
9674 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
9675 MagickFalse,methods[entry]);
9676 methods=DestroyStringList(methods);
9679 case MatteEditBorderCommand:
9682 *ColorMenu[MaxNumberPens];
9688 Initialize menu selections.
9690 for (i=0; i < (int) (MaxNumberPens-2); i++)
9691 ColorMenu[i]=resource_info->pen_colors[i];
9692 ColorMenu[MaxNumberPens-2]="Browser...";
9693 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9695 Select a pen color from the pop-up menu.
9697 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9698 (const char **) ColorMenu,command);
9701 if (pen_number == (MaxNumberPens-2))
9704 color_name[MaxTextExtent] = "gray";
9707 Select a pen color from a dialog.
9709 resource_info->pen_colors[pen_number]=color_name;
9710 XColorBrowserWidget(display,windows,"Select",color_name);
9711 if (*color_name == '\0')
9717 (void) XParseColor(display,windows->map_info->colormap,
9718 resource_info->pen_colors[pen_number],&border_color);
9721 case MatteEditFuzzCommand:
9724 fuzz[MaxTextExtent];
9739 Select a command from the pop-up menu.
9741 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9747 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*QuantumRange+
9751 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9752 (void) XDialogWidget(display,windows,"Ok",
9753 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9756 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9757 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
9760 case MatteEditValueCommand:
9763 message[MaxTextExtent];
9775 Select a command from the pop-up menu.
9777 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9783 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9785 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9786 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9787 (Quantum) TransparentOpacity);
9790 (void) FormatMagickString(message,MaxTextExtent,
9791 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9793 (void) XDialogWidget(display,windows,"Matte",message,matte);
9798 case MatteEditUndoCommand:
9800 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9804 case MatteEditHelpCommand:
9806 XTextViewWidget(display,resource_info,windows,MagickFalse,
9807 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9810 case MatteEditDismissCommand:
9822 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9829 if (event.xbutton.button != Button1)
9831 if ((event.xbutton.window != windows->image.id) &&
9832 (event.xbutton.window != windows->magnify.id))
9839 (void) XMagickCommand(display,resource_info,windows,
9840 SaveToUndoBufferCommand,image);
9841 state|=UpdateConfigurationState;
9846 if (event.xbutton.button != Button1)
9848 if ((event.xbutton.window != windows->image.id) &&
9849 (event.xbutton.window != windows->magnify.id))
9852 Update colormap information.
9856 XConfigureImageColormap(display,resource_info,windows,*image);
9857 (void) XConfigureImage(display,resource_info,windows,*image);
9858 XInfoWidget(display,windows,text);
9859 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9860 state&=(~UpdateConfigurationState);
9868 command[MaxTextExtent];
9873 if (event.xkey.window == windows->magnify.id)
9878 window=windows->magnify.id;
9879 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9881 if (event.xkey.window != windows->image.id)
9884 Respond to a user key press.
9886 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9887 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9888 switch ((int) key_symbol)
9902 XTextViewWidget(display,resource_info,windows,MagickFalse,
9903 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9908 (void) XBell(display,0);
9917 Map and unmap Info widget as cursor crosses its boundaries.
9921 if (windows->info.mapped != MagickFalse)
9923 if ((x < (int) (windows->info.x+windows->info.width)) &&
9924 (y < (int) (windows->info.y+windows->info.height)))
9925 (void) XWithdrawWindow(display,windows->info.id,
9926 windows->info.screen);
9929 if ((x > (int) (windows->info.x+windows->info.width)) ||
9930 (y > (int) (windows->info.y+windows->info.height)))
9931 (void) XMapWindow(display,windows->info.id);
9937 if (event.xany.window == windows->magnify.id)
9939 x=windows->magnify.x-windows->image.x;
9940 y=windows->magnify.y-windows->image.y;
9944 if ((state & UpdateConfigurationState) != 0)
9957 Matte edit is relative to image configuration.
9959 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9961 XPutPixel(windows->image.ximage,x_offset,y_offset,
9962 windows->pixel_info->background_color.pixel);
9963 width=(unsigned int) (*image)->columns;
9964 height=(unsigned int) (*image)->rows;
9967 if (windows->image.crop_geometry != (char *) NULL)
9968 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9971 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9973 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9974 if ((x_offset < 0) || (y_offset < 0))
9976 if ((x_offset >= (int) (*image)->columns) ||
9977 (y_offset >= (int) (*image)->rows))
9979 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9980 return(MagickFalse);
9981 (*image)->matte=MagickTrue;
9982 exception=(&(*image)->exception);
9983 image_view=AcquireCacheView(*image);
9990 Update matte information using point algorithm.
9992 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
9993 (ssize_t) y_offset,1,1,exception);
9994 if (q == (PixelPacket *) NULL)
9996 q->opacity=(Quantum) StringToLong(matte);
9997 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10000 case ReplaceMethod:
10006 Update matte information using replace algorithm.
10008 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
10009 (ssize_t) y_offset,&target,exception);
10010 for (y=0; y < (int) (*image)->rows; y++)
10012 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10013 (*image)->columns,1,&(*image)->exception);
10014 if (q == (PixelPacket *) NULL)
10016 for (x=0; x < (int) (*image)->columns; x++)
10018 if (IsColorSimilar(*image,q,&target))
10019 q->opacity=(Quantum) StringToLong(matte);
10022 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10027 case FloodfillMethod:
10028 case FillToBorderMethod:
10037 Update matte information using floodfill algorithm.
10039 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10040 (ssize_t) y_offset,&target,exception);
10041 if (method == FillToBorderMethod)
10043 target.red=(MagickRealType)
10044 ScaleShortToQuantum(border_color.red);
10045 target.green=(MagickRealType)
10046 ScaleShortToQuantum(border_color.green);
10047 target.blue=(MagickRealType)
10048 ScaleShortToQuantum(border_color.blue);
10050 draw_info=CloneDrawInfo(resource_info->image_info,
10051 (DrawInfo *) NULL);
10052 draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte));
10053 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10054 (ssize_t) x_offset,(ssize_t) y_offset,
10055 method == FloodfillMethod ? MagickFalse : MagickTrue);
10056 draw_info=DestroyDrawInfo(draw_info);
10062 Update matte information using reset algorithm.
10064 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10065 return(MagickFalse);
10066 for (y=0; y < (int) (*image)->rows; y++)
10068 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10069 (*image)->columns,1,exception);
10070 if (q == (PixelPacket *) NULL)
10072 for (x=0; x < (int) (*image)->columns; x++)
10074 q->opacity=(Quantum) StringToLong(matte);
10077 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10080 if (StringToLong(matte) == OpaqueOpacity)
10081 (*image)->matte=MagickFalse;
10085 image_view=DestroyCacheView(image_view);
10086 state&=(~UpdateConfigurationState);
10088 } while ((state & ExitState) == 0);
10089 (void) XSelectInput(display,windows->image.id,
10090 windows->image.attributes.event_mask);
10091 XSetCursorState(display,windows,MagickFalse);
10092 (void) XFreeCursor(display,cursor);
10093 return(MagickTrue);
10097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10101 + X O p e n I m a g e %
10105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10107 % XOpenImage() loads an image from a file.
10109 % The format of the XOpenImage method is:
10111 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10112 % XWindows *windows,const unsigned int command)
10114 % A description of each parameter follows:
10116 % o display: Specifies a connection to an X server; returned from
10119 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10121 % o windows: Specifies a pointer to a XWindows structure.
10123 % o command: A value other than zero indicates that the file is selected
10124 % from the command line argument list.
10127 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10128 XWindows *windows,const MagickBooleanType command)
10143 filename[MaxTextExtent] = "\0";
10146 Request file name from user.
10148 if (command == MagickFalse)
10149 XFileBrowserWidget(display,windows,"Open",filename);
10165 Select next image from the command line.
10167 status=XGetCommand(display,windows->image.id,&files,&count);
10170 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10171 return((Image *) NULL);
10173 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10174 if (filelist == (char **) NULL)
10176 ThrowXWindowFatalException(ResourceLimitError,
10177 "MemoryAllocationFailed","...");
10178 (void) XFreeStringList(files);
10179 return((Image *) NULL);
10182 for (i=1; i < count; i++)
10183 if (*files[i] != '-')
10184 filelist[j++]=files[i];
10185 filelist[j]=(char *) NULL;
10186 XListBrowserWidget(display,windows,&windows->widget,
10187 (const char **) filelist,"Load","Select Image to Load:",filename);
10188 filelist=(char **) RelinquishMagickMemory(filelist);
10189 (void) XFreeStringList(files);
10191 if (*filename == '\0')
10192 return((Image *) NULL);
10193 image_info=CloneImageInfo(resource_info->image_info);
10194 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10196 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10197 exception=AcquireExceptionInfo();
10198 (void) SetImageInfo(image_info,0,exception);
10199 if (LocaleCompare(image_info->magick,"X") == 0)
10202 seconds[MaxTextExtent];
10205 User may want to delay the X server screen grab.
10207 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10208 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10210 if (*seconds == '\0')
10211 return((Image *) NULL);
10212 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10214 magick_info=GetMagickInfo(image_info->magick,exception);
10215 if ((magick_info != (const MagickInfo *) NULL) &&
10216 (magick_info->raw != MagickFalse))
10219 geometry[MaxTextExtent];
10222 Request image size from the user.
10224 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10225 if (image_info->size != (char *) NULL)
10226 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10227 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10229 (void) CloneString(&image_info->size,geometry);
10234 XSetCursorState(display,windows,MagickTrue);
10235 XCheckRefreshWindows(display,windows);
10236 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10237 nexus=ReadImage(image_info,exception);
10238 CatchException(exception);
10239 XSetCursorState(display,windows,MagickFalse);
10240 if (nexus != (Image *) NULL)
10241 XClientMessage(display,windows->image.id,windows->im_protocols,
10242 windows->im_next_image,CurrentTime);
10250 Unknown image format.
10252 text=FileToString(filename,~0,exception);
10253 if (text == (char *) NULL)
10254 return((Image *) NULL);
10255 textlist=StringToList(text);
10256 if (textlist != (char **) NULL)
10259 title[MaxTextExtent];
10264 (void) FormatMagickString(title,MaxTextExtent,
10265 "Unknown format: %s",filename);
10266 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10267 (const char **) textlist);
10268 for (i=0; textlist[i] != (char *) NULL; i++)
10269 textlist[i]=DestroyString(textlist[i]);
10270 textlist=(char **) RelinquishMagickMemory(textlist);
10272 text=DestroyString(text);
10274 exception=DestroyExceptionInfo(exception);
10275 image_info=DestroyImageInfo(image_info);
10280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10284 + X P a n I m a g e %
10288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10290 % XPanImage() pans the image until the mouse button is released.
10292 % The format of the XPanImage method is:
10294 % void XPanImage(Display *display,XWindows *windows,XEvent *event)
10296 % A description of each parameter follows:
10298 % o display: Specifies a connection to an X server; returned from
10301 % o windows: Specifies a pointer to a XWindows structure.
10303 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10304 % the entire image is refreshed.
10307 static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10310 text[MaxTextExtent];
10328 if ((windows->image.ximage->width > (int) windows->image.width) &&
10329 (windows->image.ximage->height > (int) windows->image.height))
10330 cursor=XCreateFontCursor(display,XC_fleur);
10332 if (windows->image.ximage->width > (int) windows->image.width)
10333 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10335 if (windows->image.ximage->height > (int) windows->image.height)
10336 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10338 cursor=XCreateFontCursor(display,XC_arrow);
10339 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10341 Pan image as pointer moves until the mouse button is released.
10343 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10344 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10345 pan_info.width=windows->pan.width*windows->image.width/
10346 windows->image.ximage->width;
10347 pan_info.height=windows->pan.height*windows->image.height/
10348 windows->image.ximage->height;
10351 state=UpdateConfigurationState;
10354 switch (event->type)
10359 User choose an initial pan location.
10361 pan_info.x=(ssize_t) event->xbutton.x;
10362 pan_info.y=(ssize_t) event->xbutton.y;
10363 state|=UpdateConfigurationState;
10366 case ButtonRelease:
10369 User has finished panning the image.
10371 pan_info.x=(ssize_t) event->xbutton.x;
10372 pan_info.y=(ssize_t) event->xbutton.y;
10373 state|=UpdateConfigurationState | ExitState;
10378 pan_info.x=(ssize_t) event->xmotion.x;
10379 pan_info.y=(ssize_t) event->xmotion.y;
10380 state|=UpdateConfigurationState;
10385 if ((state & UpdateConfigurationState) != 0)
10388 Check boundary conditions.
10390 if (pan_info.x < (ssize_t) (pan_info.width/2))
10393 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10394 if (pan_info.x < 0)
10397 if ((int) (pan_info.x+windows->image.width) >
10398 windows->image.ximage->width)
10399 pan_info.x=(ssize_t)
10400 (windows->image.ximage->width-windows->image.width);
10401 if (pan_info.y < (ssize_t) (pan_info.height/2))
10404 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10405 if (pan_info.y < 0)
10408 if ((int) (pan_info.y+windows->image.height) >
10409 windows->image.ximage->height)
10410 pan_info.y=(ssize_t)
10411 (windows->image.ximage->height-windows->image.height);
10412 if ((windows->image.x != (int) pan_info.x) ||
10413 (windows->image.y != (int) pan_info.y))
10416 Display image pan offset.
10418 windows->image.x=(int) pan_info.x;
10419 windows->image.y=(int) pan_info.y;
10420 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
10421 windows->image.width,windows->image.height,windows->image.x,
10423 XInfoWidget(display,windows,text);
10425 Refresh Image window.
10427 XDrawPanRectangle(display,windows);
10428 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10430 state&=(~UpdateConfigurationState);
10433 Wait for next event.
10435 if ((state & ExitState) == 0)
10436 XScreenEvent(display,windows,event);
10437 } while ((state & ExitState) == 0);
10441 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10442 (void) XFreeCursor(display,cursor);
10443 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10451 + X P a s t e I m a g e %
10455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10457 % XPasteImage() pastes an image previously saved with XCropImage in the X
10458 % window image at a location the user chooses with the pointer.
10460 % The format of the XPasteImage method is:
10462 % MagickBooleanType XPasteImage(Display *display,
10463 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10465 % A description of each parameter follows:
10467 % o display: Specifies a connection to an X server; returned from
10470 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10472 % o windows: Specifies a pointer to a XWindows structure.
10474 % o image: the image; returned from ReadImage.
10477 static MagickBooleanType XPasteImage(Display *display,
10478 XResourceInfo *resource_info,XWindows *windows,Image *image)
10489 static const ModeType
10492 PasteOperatorsCommand,
10494 PasteDismissCommand
10497 static CompositeOperator
10498 compose = CopyCompositeOp;
10501 text[MaxTextExtent];
10535 if (resource_info->copy_image == (Image *) NULL)
10536 return(MagickFalse);
10537 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10538 &image->exception);
10540 Map Command widget.
10542 (void) CloneString(&windows->command.name,"Paste");
10543 windows->command.data=1;
10544 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10545 (void) XMapRaised(display,windows->command.id);
10546 XClientMessage(display,windows->image.id,windows->im_protocols,
10547 windows->im_update_widget,CurrentTime);
10549 Track pointer until button 1 is pressed.
10551 XSetCursorState(display,windows,MagickFalse);
10552 XQueryPosition(display,windows->image.id,&x,&y);
10553 (void) XSelectInput(display,windows->image.id,
10554 windows->image.attributes.event_mask | PointerMotionMask);
10555 paste_info.x=(ssize_t) windows->image.x+x;
10556 paste_info.y=(ssize_t) windows->image.y+y;
10557 paste_info.width=0;
10558 paste_info.height=0;
10559 cursor=XCreateFontCursor(display,XC_ul_angle);
10560 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10561 state=DefaultState;
10564 if (windows->info.mapped != MagickFalse)
10567 Display pointer position.
10569 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
10570 (long) paste_info.x,(long) paste_info.y);
10571 XInfoWidget(display,windows,text);
10573 highlight_info=paste_info;
10574 highlight_info.x=paste_info.x-windows->image.x;
10575 highlight_info.y=paste_info.y-windows->image.y;
10576 XHighlightRectangle(display,windows->image.id,
10577 windows->image.highlight_context,&highlight_info);
10579 Wait for next event.
10581 XScreenEvent(display,windows,&event);
10582 XHighlightRectangle(display,windows->image.id,
10583 windows->image.highlight_context,&highlight_info);
10584 if (event.xany.window == windows->command.id)
10587 Select a command from the Command widget.
10589 id=XCommandWidget(display,windows,PasteMenu,&event);
10592 switch (PasteCommands[id])
10594 case PasteOperatorsCommand:
10597 command[MaxTextExtent],
10601 Select a command from the pop-up menu.
10603 operators=GetMagickOptions(MagickComposeOptions);
10604 if (operators == (char **) NULL)
10606 entry=XMenuWidget(display,windows,PasteMenu[id],
10607 (const char **) operators,command);
10609 compose=(CompositeOperator) ParseMagickOption(
10610 MagickComposeOptions,MagickFalse,operators[entry]);
10611 operators=DestroyStringList(operators);
10614 case PasteHelpCommand:
10616 XTextViewWidget(display,resource_info,windows,MagickFalse,
10617 "Help Viewer - Image Composite",ImagePasteHelp);
10620 case PasteDismissCommand:
10625 state|=EscapeState;
10634 switch (event.type)
10638 if (image->debug != MagickFalse)
10639 (void) LogMagickEvent(X11Event,GetMagickModule(),
10640 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10641 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10642 if (event.xbutton.button != Button1)
10644 if (event.xbutton.window != windows->image.id)
10647 Paste rectangle is relative to image configuration.
10649 width=(unsigned int) image->columns;
10650 height=(unsigned int) image->rows;
10653 if (windows->image.crop_geometry != (char *) NULL)
10654 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10656 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10657 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10658 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10659 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10660 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10661 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10662 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10665 case ButtonRelease:
10667 if (image->debug != MagickFalse)
10668 (void) LogMagickEvent(X11Event,GetMagickModule(),
10669 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10670 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10671 if (event.xbutton.button != Button1)
10673 if (event.xbutton.window != windows->image.id)
10675 if ((paste_info.width != 0) && (paste_info.height != 0))
10678 User has selected the location of the paste image.
10680 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10681 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10691 command[MaxTextExtent];
10699 if (event.xkey.window != windows->image.id)
10702 Respond to a user key press.
10704 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10705 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10706 *(command+length)='\0';
10707 if (image->debug != MagickFalse)
10708 (void) LogMagickEvent(X11Event,GetMagickModule(),
10709 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10710 switch ((int) key_symbol)
10718 paste_image=DestroyImage(paste_image);
10719 state|=EscapeState;
10726 (void) XSetFunction(display,windows->image.highlight_context,
10728 XTextViewWidget(display,resource_info,windows,MagickFalse,
10729 "Help Viewer - Image Composite",ImagePasteHelp);
10730 (void) XSetFunction(display,windows->image.highlight_context,
10736 (void) XBell(display,0);
10745 Map and unmap Info widget as text cursor crosses its boundaries.
10749 if (windows->info.mapped != MagickFalse)
10751 if ((x < (int) (windows->info.x+windows->info.width)) &&
10752 (y < (int) (windows->info.y+windows->info.height)))
10753 (void) XWithdrawWindow(display,windows->info.id,
10754 windows->info.screen);
10757 if ((x > (int) (windows->info.x+windows->info.width)) ||
10758 (y > (int) (windows->info.y+windows->info.height)))
10759 (void) XMapWindow(display,windows->info.id);
10760 paste_info.x=(ssize_t) windows->image.x+x;
10761 paste_info.y=(ssize_t) windows->image.y+y;
10766 if (image->debug != MagickFalse)
10767 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10772 } while ((state & ExitState) == 0);
10773 (void) XSelectInput(display,windows->image.id,
10774 windows->image.attributes.event_mask);
10775 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10776 XSetCursorState(display,windows,MagickFalse);
10777 (void) XFreeCursor(display,cursor);
10778 if ((state & EscapeState) != 0)
10779 return(MagickTrue);
10781 Image pasting is relative to image configuration.
10783 XSetCursorState(display,windows,MagickTrue);
10784 XCheckRefreshWindows(display,windows);
10785 width=(unsigned int) image->columns;
10786 height=(unsigned int) image->rows;
10789 if (windows->image.crop_geometry != (char *) NULL)
10790 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10791 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10793 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10794 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10795 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10797 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10798 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10800 Paste image with X Image window.
10802 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10803 paste_image=DestroyImage(paste_image);
10804 XSetCursorState(display,windows,MagickFalse);
10806 Update image colormap.
10808 XConfigureImageColormap(display,resource_info,windows,image);
10809 (void) XConfigureImage(display,resource_info,windows,image);
10810 return(MagickTrue);
10814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10818 + X P r i n t I m a g e %
10822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10824 % XPrintImage() prints an image to a Postscript printer.
10826 % The format of the XPrintImage method is:
10828 % MagickBooleanType XPrintImage(Display *display,
10829 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10831 % A description of each parameter follows:
10833 % o display: Specifies a connection to an X server; returned from
10836 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10838 % o windows: Specifies a pointer to a XWindows structure.
10840 % o image: the image.
10843 static MagickBooleanType XPrintImage(Display *display,
10844 XResourceInfo *resource_info,XWindows *windows,Image *image)
10847 filename[MaxTextExtent],
10848 geometry[MaxTextExtent];
10860 Request Postscript page geometry from user.
10862 image_info=CloneImageInfo(resource_info->image_info);
10863 (void) FormatMagickString(geometry,MaxTextExtent,"Letter");
10864 if (image_info->page != (char *) NULL)
10865 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10866 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10867 "Select Postscript Page Geometry:",geometry);
10868 if (*geometry == '\0')
10869 return(MagickTrue);
10870 image_info->page=GetPageGeometry(geometry);
10872 Apply image transforms.
10874 XSetCursorState(display,windows,MagickTrue);
10875 XCheckRefreshWindows(display,windows);
10876 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10877 if (print_image == (Image *) NULL)
10878 return(MagickFalse);
10879 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
10880 windows->image.ximage->width,windows->image.ximage->height);
10881 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10885 (void) AcquireUniqueFilename(filename);
10886 (void) FormatMagickString(print_image->filename,MaxTextExtent,"print:%s",
10888 status=WriteImage(image_info,print_image);
10889 (void) RelinquishUniqueFileResource(filename);
10890 print_image=DestroyImage(print_image);
10891 image_info=DestroyImageInfo(image_info);
10892 XSetCursorState(display,windows,MagickFalse);
10893 return(status != 0 ? MagickTrue : MagickFalse);
10897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10901 + X R O I I m a g e %
10905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10907 % XROIImage() applies an image processing technique to a region of interest.
10909 % The format of the XROIImage method is:
10911 % MagickBooleanType XROIImage(Display *display,
10912 % XResourceInfo *resource_info,XWindows *windows,Image **image)
10914 % A description of each parameter follows:
10916 % o display: Specifies a connection to an X server; returned from
10919 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10921 % o windows: Specifies a pointer to a XWindows structure.
10923 % o image: the image; returned from ReadImage.
10926 static MagickBooleanType XROIImage(Display *display,
10927 XResourceInfo *resource_info,XWindows *windows,Image **image)
10929 #define ApplyMenus 7
10979 "Contrast Stretch...",
10980 "Sigmoidal Contrast...",
11014 "Charcoal Draw...",
11017 *MiscellanyMenu[] =
11028 **Menus[ApplyMenus] =
11039 static const CommandType
11062 TransformCommands[] =
11066 RotateRightCommand,
11069 EnhanceCommands[] =
11077 ContrastStretchCommand,
11078 SigmoidalContrastCommand,
11086 EffectsCommands[] =
11090 ReduceNoiseCommand,
11109 CharcoalDrawCommand
11111 MiscellanyCommands[] =
11115 ShowPreviewCommand,
11116 ShowHistogramCommand,
11125 static const CommandType
11126 *Commands[ApplyMenus] =
11138 command[MaxTextExtent],
11139 text[MaxTextExtent];
11159 MagickProgressMonitor
11178 Map Command widget.
11180 (void) CloneString(&windows->command.name,"ROI");
11181 windows->command.data=0;
11182 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11183 (void) XMapRaised(display,windows->command.id);
11184 XClientMessage(display,windows->image.id,windows->im_protocols,
11185 windows->im_update_widget,CurrentTime);
11187 Track pointer until button 1 is pressed.
11189 XQueryPosition(display,windows->image.id,&x,&y);
11190 (void) XSelectInput(display,windows->image.id,
11191 windows->image.attributes.event_mask | PointerMotionMask);
11192 roi_info.x=(ssize_t) windows->image.x+x;
11193 roi_info.y=(ssize_t) windows->image.y+y;
11196 cursor=XCreateFontCursor(display,XC_fleur);
11197 state=DefaultState;
11200 if (windows->info.mapped != MagickFalse)
11203 Display pointer position.
11205 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
11206 (long) roi_info.x,(long) roi_info.y);
11207 XInfoWidget(display,windows,text);
11210 Wait for next event.
11212 XScreenEvent(display,windows,&event);
11213 if (event.xany.window == windows->command.id)
11216 Select a command from the Command widget.
11218 id=XCommandWidget(display,windows,ROIMenu,&event);
11221 switch (ROICommands[id])
11223 case ROIHelpCommand:
11225 XTextViewWidget(display,resource_info,windows,MagickFalse,
11226 "Help Viewer - Region of Interest",ImageROIHelp);
11229 case ROIDismissCommand:
11234 state|=EscapeState;
11243 switch (event.type)
11247 if (event.xbutton.button != Button1)
11249 if (event.xbutton.window != windows->image.id)
11252 Note first corner of region of interest rectangle-- exit loop.
11254 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11255 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11256 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11260 case ButtonRelease:
11269 if (event.xkey.window != windows->image.id)
11272 Respond to a user key press.
11274 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11275 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11276 switch ((int) key_symbol)
11284 state|=EscapeState;
11291 XTextViewWidget(display,resource_info,windows,MagickFalse,
11292 "Help Viewer - Region of Interest",ImageROIHelp);
11297 (void) XBell(display,0);
11306 Map and unmap Info widget as text cursor crosses its boundaries.
11310 if (windows->info.mapped != MagickFalse)
11312 if ((x < (int) (windows->info.x+windows->info.width)) &&
11313 (y < (int) (windows->info.y+windows->info.height)))
11314 (void) XWithdrawWindow(display,windows->info.id,
11315 windows->info.screen);
11318 if ((x > (int) (windows->info.x+windows->info.width)) ||
11319 (y > (int) (windows->info.y+windows->info.height)))
11320 (void) XMapWindow(display,windows->info.id);
11321 roi_info.x=(ssize_t) windows->image.x+x;
11322 roi_info.y=(ssize_t) windows->image.y+y;
11328 } while ((state & ExitState) == 0);
11329 (void) XSelectInput(display,windows->image.id,
11330 windows->image.attributes.event_mask);
11331 if ((state & EscapeState) != 0)
11334 User want to exit without region of interest.
11336 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11337 (void) XFreeCursor(display,cursor);
11338 return(MagickTrue);
11340 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11344 Size rectangle as pointer moves until the mouse button is released.
11346 x=(int) roi_info.x;
11347 y=(int) roi_info.y;
11350 state=DefaultState;
11353 highlight_info=roi_info;
11354 highlight_info.x=roi_info.x-windows->image.x;
11355 highlight_info.y=roi_info.y-windows->image.y;
11356 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11359 Display info and draw region of interest rectangle.
11361 if (windows->info.mapped == MagickFalse)
11362 (void) XMapWindow(display,windows->info.id);
11363 (void) FormatMagickString(text,MaxTextExtent,
11364 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11365 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11366 XInfoWidget(display,windows,text);
11367 XHighlightRectangle(display,windows->image.id,
11368 windows->image.highlight_context,&highlight_info);
11371 if (windows->info.mapped != MagickFalse)
11372 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11374 Wait for next event.
11376 XScreenEvent(display,windows,&event);
11377 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11378 XHighlightRectangle(display,windows->image.id,
11379 windows->image.highlight_context,&highlight_info);
11380 switch (event.type)
11384 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11385 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11388 case ButtonRelease:
11391 User has committed to region of interest rectangle.
11393 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11394 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11395 XSetCursorState(display,windows,MagickFalse);
11397 if (LocaleCompare(windows->command.name,"Apply") == 0)
11399 (void) CloneString(&windows->command.name,"Apply");
11400 windows->command.data=ApplyMenus;
11401 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11408 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11409 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11414 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11415 ((state & ExitState) != 0))
11418 Check boundary conditions.
11420 if (roi_info.x < 0)
11423 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11424 roi_info.x=(ssize_t) windows->image.ximage->width;
11425 if ((int) roi_info.x < x)
11426 roi_info.width=(unsigned int) (x-roi_info.x);
11429 roi_info.width=(unsigned int) (roi_info.x-x);
11430 roi_info.x=(ssize_t) x;
11432 if (roi_info.y < 0)
11435 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11436 roi_info.y=(ssize_t) windows->image.ximage->height;
11437 if ((int) roi_info.y < y)
11438 roi_info.height=(unsigned int) (y-roi_info.y);
11441 roi_info.height=(unsigned int) (roi_info.y-y);
11442 roi_info.y=(ssize_t) y;
11445 } while ((state & ExitState) == 0);
11447 Wait for user to grab a corner of the rectangle or press return.
11449 state=DefaultState;
11450 command_type=NullCommand;
11451 (void) XMapWindow(display,windows->info.id);
11454 if (windows->info.mapped != MagickFalse)
11457 Display pointer position.
11459 (void) FormatMagickString(text,MaxTextExtent,
11460 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11461 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11462 XInfoWidget(display,windows,text);
11464 highlight_info=roi_info;
11465 highlight_info.x=roi_info.x-windows->image.x;
11466 highlight_info.y=roi_info.y-windows->image.y;
11467 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11469 state|=EscapeState;
11473 if ((state & UpdateRegionState) != 0)
11475 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11476 switch (command_type)
11481 (void) XMagickCommand(display,resource_info,windows,command_type,
11488 Region of interest is relative to image configuration.
11490 progress_monitor=SetImageProgressMonitor(*image,
11491 (MagickProgressMonitor) NULL,(*image)->client_data);
11492 crop_info=roi_info;
11493 width=(unsigned int) (*image)->columns;
11494 height=(unsigned int) (*image)->rows;
11497 if (windows->image.crop_geometry != (char *) NULL)
11498 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11500 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11502 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11503 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11504 scale_factor=(MagickRealType)
11505 height/windows->image.ximage->height;
11507 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11508 crop_info.height=(unsigned int)
11509 (scale_factor*crop_info.height+0.5);
11510 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11511 (void) SetImageProgressMonitor(*image,progress_monitor,
11512 (*image)->client_data);
11513 if (roi_image == (Image *) NULL)
11516 Apply image processing technique to the region of interest.
11518 windows->image.orphan=MagickTrue;
11519 (void) XMagickCommand(display,resource_info,windows,command_type,
11521 progress_monitor=SetImageProgressMonitor(*image,
11522 (MagickProgressMonitor) NULL,(*image)->client_data);
11523 (void) XMagickCommand(display,resource_info,windows,
11524 SaveToUndoBufferCommand,image);
11525 windows->image.orphan=MagickFalse;
11526 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11527 crop_info.x,crop_info.y);
11528 roi_image=DestroyImage(roi_image);
11529 (void) SetImageProgressMonitor(*image,progress_monitor,
11530 (*image)->client_data);
11534 if (command_type != InfoCommand)
11536 XConfigureImageColormap(display,resource_info,windows,*image);
11537 (void) XConfigureImage(display,resource_info,windows,*image);
11539 XCheckRefreshWindows(display,windows);
11540 XInfoWidget(display,windows,text);
11541 (void) XSetFunction(display,windows->image.highlight_context,
11543 state&=(~UpdateRegionState);
11545 XHighlightRectangle(display,windows->image.id,
11546 windows->image.highlight_context,&highlight_info);
11547 XScreenEvent(display,windows,&event);
11548 if (event.xany.window == windows->command.id)
11551 Select a command from the Command widget.
11553 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11554 command_type=NullCommand;
11555 id=XCommandWidget(display,windows,ApplyMenu,&event);
11558 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11559 command_type=ApplyCommands[id];
11560 if (id < ApplyMenus)
11563 Select a command from a pop-up menu.
11565 entry=XMenuWidget(display,windows,ApplyMenu[id],
11566 (const char **) Menus[id],command);
11569 (void) CopyMagickString(command,Menus[id][entry],
11571 command_type=Commands[id][entry];
11575 (void) XSetFunction(display,windows->image.highlight_context,
11577 XHighlightRectangle(display,windows->image.id,
11578 windows->image.highlight_context,&highlight_info);
11579 if (command_type == HelpCommand)
11581 (void) XSetFunction(display,windows->image.highlight_context,
11583 XTextViewWidget(display,resource_info,windows,MagickFalse,
11584 "Help Viewer - Region of Interest",ImageROIHelp);
11585 (void) XSetFunction(display,windows->image.highlight_context,
11589 if (command_type == QuitCommand)
11594 state|=EscapeState;
11598 if (command_type != NullCommand)
11599 state|=UpdateRegionState;
11602 XHighlightRectangle(display,windows->image.id,
11603 windows->image.highlight_context,&highlight_info);
11604 switch (event.type)
11608 x=windows->image.x;
11609 y=windows->image.y;
11610 if (event.xbutton.button != Button1)
11612 if (event.xbutton.window != windows->image.id)
11614 x=windows->image.x+event.xbutton.x;
11615 y=windows->image.y+event.xbutton.y;
11616 if ((x < (int) (roi_info.x+RoiDelta)) &&
11617 (x > (int) (roi_info.x-RoiDelta)) &&
11618 (y < (int) (roi_info.y+RoiDelta)) &&
11619 (y > (int) (roi_info.y-RoiDelta)))
11621 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11622 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11623 state|=UpdateConfigurationState;
11626 if ((x < (int) (roi_info.x+RoiDelta)) &&
11627 (x > (int) (roi_info.x-RoiDelta)) &&
11628 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11629 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11631 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11632 state|=UpdateConfigurationState;
11635 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11636 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11637 (y < (int) (roi_info.y+RoiDelta)) &&
11638 (y > (int) (roi_info.y-RoiDelta)))
11640 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11641 state|=UpdateConfigurationState;
11644 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11645 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11646 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11647 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11649 state|=UpdateConfigurationState;
11653 case ButtonRelease:
11655 if (event.xbutton.window == windows->pan.id)
11656 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11657 (highlight_info.y != crop_info.y-windows->image.y))
11658 XHighlightRectangle(display,windows->image.id,
11659 windows->image.highlight_context,&highlight_info);
11660 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11661 event.xbutton.time);
11666 if (event.xexpose.window == windows->image.id)
11667 if (event.xexpose.count == 0)
11669 event.xexpose.x=(int) highlight_info.x;
11670 event.xexpose.y=(int) highlight_info.y;
11671 event.xexpose.width=(int) highlight_info.width;
11672 event.xexpose.height=(int) highlight_info.height;
11673 XRefreshWindow(display,&windows->image,&event);
11675 if (event.xexpose.window == windows->info.id)
11676 if (event.xexpose.count == 0)
11677 XInfoWidget(display,windows,text);
11685 if (event.xkey.window != windows->image.id)
11688 Respond to a user key press.
11690 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11691 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11692 switch ((int) key_symbol)
11699 state|=EscapeState;
11708 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11709 roi_info.y=(ssize_t) (windows->image.height/2L-
11710 roi_info.height/2L);
11742 (void) XSetFunction(display,windows->image.highlight_context,
11744 XTextViewWidget(display,resource_info,windows,MagickFalse,
11745 "Help Viewer - Region of Interest",ImageROIHelp);
11746 (void) XSetFunction(display,windows->image.highlight_context,
11752 command_type=XImageWindowCommand(display,resource_info,windows,
11753 event.xkey.state,key_symbol,image);
11754 if (command_type != NullCommand)
11755 state|=UpdateRegionState;
11759 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11767 if (event.xbutton.window != windows->image.id)
11770 Map and unmap Info widget as text cursor crosses its boundaries.
11774 if (windows->info.mapped != MagickFalse)
11776 if ((x < (int) (windows->info.x+windows->info.width)) &&
11777 (y < (int) (windows->info.y+windows->info.height)))
11778 (void) XWithdrawWindow(display,windows->info.id,
11779 windows->info.screen);
11782 if ((x > (int) (windows->info.x+windows->info.width)) ||
11783 (y > (int) (windows->info.y+windows->info.height)))
11784 (void) XMapWindow(display,windows->info.id);
11785 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11786 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11789 case SelectionRequest:
11794 XSelectionRequestEvent
11798 Set primary selection.
11800 (void) FormatMagickString(text,MaxTextExtent,
11801 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11802 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11803 request=(&(event.xselectionrequest));
11804 (void) XChangeProperty(request->display,request->requestor,
11805 request->property,request->target,8,PropModeReplace,
11806 (unsigned char *) text,(int) strlen(text));
11807 notify.type=SelectionNotify;
11808 notify.display=request->display;
11809 notify.requestor=request->requestor;
11810 notify.selection=request->selection;
11811 notify.target=request->target;
11812 notify.time=request->time;
11813 if (request->property == None)
11814 notify.property=request->target;
11816 notify.property=request->property;
11817 (void) XSendEvent(request->display,request->requestor,False,0,
11818 (XEvent *) ¬ify);
11823 if ((state & UpdateConfigurationState) != 0)
11825 (void) XPutBackEvent(display,&event);
11826 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11829 } while ((state & ExitState) == 0);
11830 } while ((state & ExitState) == 0);
11831 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11832 XSetCursorState(display,windows,MagickFalse);
11833 if ((state & EscapeState) != 0)
11834 return(MagickTrue);
11835 return(MagickTrue);
11839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11843 + X R o t a t e I m a g e %
11847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11849 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11850 % rotation angle is computed from the slope of a line drawn by the user.
11852 % The format of the XRotateImage method is:
11854 % MagickBooleanType XRotateImage(Display *display,
11855 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11858 % A description of each parameter follows:
11860 % o display: Specifies a connection to an X server; returned from
11863 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11865 % o windows: Specifies a pointer to a XWindows structure.
11867 % o degrees: Specifies the number of degrees to rotate the image.
11869 % o image: the image.
11872 static MagickBooleanType XRotateImage(Display *display,
11873 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11886 direction = HorizontalRotateCommand;
11888 static const ModeType
11889 DirectionCommands[] =
11891 HorizontalRotateCommand,
11892 VerticalRotateCommand
11896 RotateColorCommand,
11897 RotateDirectionCommand,
11899 RotateDismissCommand
11902 static unsigned int
11906 command[MaxTextExtent],
11907 text[MaxTextExtent];
11918 normalized_degrees;
11928 if (degrees == 0.0)
11943 Map Command widget.
11945 (void) CloneString(&windows->command.name,"Rotate");
11946 windows->command.data=2;
11947 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11948 (void) XMapRaised(display,windows->command.id);
11949 XClientMessage(display,windows->image.id,windows->im_protocols,
11950 windows->im_update_widget,CurrentTime);
11952 Wait for first button press.
11954 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11955 XQueryPosition(display,windows->image.id,&x,&y);
11960 state=DefaultState;
11963 XHighlightLine(display,windows->image.id,
11964 windows->image.highlight_context,&rotate_info);
11966 Wait for next event.
11968 XScreenEvent(display,windows,&event);
11969 XHighlightLine(display,windows->image.id,
11970 windows->image.highlight_context,&rotate_info);
11971 if (event.xany.window == windows->command.id)
11974 Select a command from the Command widget.
11976 id=XCommandWidget(display,windows,RotateMenu,&event);
11979 (void) XSetFunction(display,windows->image.highlight_context,
11981 switch (RotateCommands[id])
11983 case RotateColorCommand:
11986 *ColorMenu[MaxNumberPens];
11995 Initialize menu selections.
11997 for (i=0; i < (int) (MaxNumberPens-2); i++)
11998 ColorMenu[i]=resource_info->pen_colors[i];
11999 ColorMenu[MaxNumberPens-2]="Browser...";
12000 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12002 Select a pen color from the pop-up menu.
12004 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12005 (const char **) ColorMenu,command);
12006 if (pen_number < 0)
12008 if (pen_number == (MaxNumberPens-2))
12011 color_name[MaxTextExtent] = "gray";
12014 Select a pen color from a dialog.
12016 resource_info->pen_colors[pen_number]=color_name;
12017 XColorBrowserWidget(display,windows,"Select",color_name);
12018 if (*color_name == '\0')
12024 (void) XParseColor(display,windows->map_info->colormap,
12025 resource_info->pen_colors[pen_number],&color);
12026 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12027 (unsigned int) MaxColors,&color);
12028 windows->pixel_info->pen_colors[pen_number]=color;
12029 pen_id=(unsigned int) pen_number;
12032 case RotateDirectionCommand:
12043 Select a command from the pop-up menu.
12045 id=XMenuWidget(display,windows,RotateMenu[id],
12046 Directions,command);
12048 direction=DirectionCommands[id];
12051 case RotateHelpCommand:
12053 XTextViewWidget(display,resource_info,windows,MagickFalse,
12054 "Help Viewer - Image Rotation",ImageRotateHelp);
12057 case RotateDismissCommand:
12062 state|=EscapeState;
12069 (void) XSetFunction(display,windows->image.highlight_context,
12073 switch (event.type)
12077 if (event.xbutton.button != Button1)
12079 if (event.xbutton.window != windows->image.id)
12084 (void) XSetFunction(display,windows->image.highlight_context,
12086 rotate_info.x1=event.xbutton.x;
12087 rotate_info.y1=event.xbutton.y;
12091 case ButtonRelease:
12098 command[MaxTextExtent];
12103 if (event.xkey.window != windows->image.id)
12106 Respond to a user key press.
12108 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12109 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12110 switch ((int) key_symbol)
12118 state|=EscapeState;
12125 (void) XSetFunction(display,windows->image.highlight_context,
12127 XTextViewWidget(display,resource_info,windows,MagickFalse,
12128 "Help Viewer - Image Rotation",ImageRotateHelp);
12129 (void) XSetFunction(display,windows->image.highlight_context,
12135 (void) XBell(display,0);
12143 rotate_info.x1=event.xmotion.x;
12144 rotate_info.y1=event.xmotion.y;
12147 rotate_info.x2=rotate_info.x1;
12148 rotate_info.y2=rotate_info.y1;
12149 if (direction == HorizontalRotateCommand)
12150 rotate_info.x2+=32;
12152 rotate_info.y2-=32;
12153 } while ((state & ExitState) == 0);
12154 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12155 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12156 if ((state & EscapeState) != 0)
12157 return(MagickTrue);
12159 Draw line as pointer moves until the mouse button is released.
12162 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12163 state=DefaultState;
12169 Display info and draw rotation line.
12171 if (windows->info.mapped == MagickFalse)
12172 (void) XMapWindow(display,windows->info.id);
12173 (void) FormatMagickString(text,MaxTextExtent," %g",
12174 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12175 XInfoWidget(display,windows,text);
12176 XHighlightLine(display,windows->image.id,
12177 windows->image.highlight_context,&rotate_info);
12180 if (windows->info.mapped != MagickFalse)
12181 (void) XWithdrawWindow(display,windows->info.id,
12182 windows->info.screen);
12184 Wait for next event.
12186 XScreenEvent(display,windows,&event);
12188 XHighlightLine(display,windows->image.id,
12189 windows->image.highlight_context,&rotate_info);
12190 switch (event.type)
12194 case ButtonRelease:
12197 User has committed to rotation line.
12199 rotate_info.x2=event.xbutton.x;
12200 rotate_info.y2=event.xbutton.y;
12208 rotate_info.x2=event.xmotion.x;
12209 rotate_info.y2=event.xmotion.y;
12215 Check boundary conditions.
12217 if (rotate_info.x2 < 0)
12220 if (rotate_info.x2 > (int) windows->image.width)
12221 rotate_info.x2=(short) windows->image.width;
12222 if (rotate_info.y2 < 0)
12225 if (rotate_info.y2 > (int) windows->image.height)
12226 rotate_info.y2=(short) windows->image.height;
12228 Compute rotation angle from the slope of the line.
12231 distance=(unsigned int)
12232 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12233 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12235 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12236 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12237 } while ((state & ExitState) == 0);
12238 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12239 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12241 return(MagickTrue);
12243 if (direction == VerticalRotateCommand)
12245 if (degrees == 0.0)
12246 return(MagickTrue);
12250 normalized_degrees=degrees;
12251 while (normalized_degrees < -45.0)
12252 normalized_degrees+=360.0;
12253 for (rotations=0; normalized_degrees > 45.0; rotations++)
12254 normalized_degrees-=90.0;
12255 if (normalized_degrees != 0.0)
12256 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12257 XSetCursorState(display,windows,MagickTrue);
12258 XCheckRefreshWindows(display,windows);
12259 (*image)->background_color.red=ScaleShortToQuantum(
12260 windows->pixel_info->pen_colors[pen_id].red);
12261 (*image)->background_color.green=ScaleShortToQuantum(
12262 windows->pixel_info->pen_colors[pen_id].green);
12263 (*image)->background_color.blue=ScaleShortToQuantum(
12264 windows->pixel_info->pen_colors[pen_id].blue);
12265 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12266 XSetCursorState(display,windows,MagickFalse);
12267 if (rotate_image == (Image *) NULL)
12268 return(MagickFalse);
12269 *image=DestroyImage(*image);
12270 *image=rotate_image;
12271 if (windows->image.crop_geometry != (char *) NULL)
12274 Rotate crop geometry.
12276 width=(unsigned int) (*image)->columns;
12277 height=(unsigned int) (*image)->rows;
12278 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12279 switch (rotations % 4)
12289 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12290 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12297 Rotate 180 degrees.
12299 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12300 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12306 Rotate 270 degrees.
12308 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12309 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12314 if (windows->image.orphan != MagickFalse)
12315 return(MagickTrue);
12316 if (normalized_degrees != 0.0)
12319 Update image colormap.
12321 windows->image.window_changes.width=(int) (*image)->columns;
12322 windows->image.window_changes.height=(int) (*image)->rows;
12323 if (windows->image.crop_geometry != (char *) NULL)
12326 Obtain dimensions of image from crop geometry.
12328 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12330 windows->image.window_changes.width=(int) width;
12331 windows->image.window_changes.height=(int) height;
12333 XConfigureImageColormap(display,resource_info,windows,*image);
12336 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12338 windows->image.window_changes.width=windows->image.ximage->height;
12339 windows->image.window_changes.height=windows->image.ximage->width;
12342 Update image configuration.
12344 (void) XConfigureImage(display,resource_info,windows,*image);
12345 return(MagickTrue);
12349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12353 + X S a v e I m a g e %
12357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12359 % XSaveImage() saves an image to a file.
12361 % The format of the XSaveImage method is:
12363 % MagickBooleanType XSaveImage(Display *display,
12364 % XResourceInfo *resource_info,XWindows *windows,Image *image)
12366 % A description of each parameter follows:
12368 % o display: Specifies a connection to an X server; returned from
12371 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12373 % o windows: Specifies a pointer to a XWindows structure.
12375 % o image: the image.
12378 static MagickBooleanType XSaveImage(Display *display,
12379 XResourceInfo *resource_info,XWindows *windows,Image *image)
12382 filename[MaxTextExtent],
12383 geometry[MaxTextExtent];
12395 Request file name from user.
12397 if (resource_info->write_filename != (char *) NULL)
12398 (void) CopyMagickString(filename,resource_info->write_filename,
12403 path[MaxTextExtent];
12408 GetPathComponent(image->filename,HeadPath,path);
12409 GetPathComponent(image->filename,TailPath,filename);
12410 status=chdir(path);
12412 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12413 FileOpenError,"UnableToOpenFile","%s",path);
12415 XFileBrowserWidget(display,windows,"Save",filename);
12416 if (*filename == '\0')
12417 return(MagickTrue);
12418 if (IsPathAccessible(filename) != MagickFalse)
12424 File exists-- seek user's permission before overwriting.
12426 status=XConfirmWidget(display,windows,"Overwrite",filename);
12428 return(MagickTrue);
12430 image_info=CloneImageInfo(resource_info->image_info);
12431 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12432 (void) SetImageInfo(image_info,1,&image->exception);
12433 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12434 (LocaleCompare(image_info->magick,"JPG") == 0))
12437 quality[MaxTextExtent];
12443 Request JPEG quality from user.
12445 (void) FormatMagickString(quality,MaxTextExtent,"%.20g",(double)
12447 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12449 if (*quality == '\0')
12450 return(MagickTrue);
12451 image->quality=StringToUnsignedLong(quality);
12452 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12454 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12455 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12456 (LocaleCompare(image_info->magick,"PS") == 0) ||
12457 (LocaleCompare(image_info->magick,"PS2") == 0))
12460 geometry[MaxTextExtent];
12463 Request page geometry from user.
12465 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12466 if (LocaleCompare(image_info->magick,"PDF") == 0)
12467 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12468 if (image_info->page != (char *) NULL)
12469 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12470 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12471 "Select page geometry:",geometry);
12472 if (*geometry != '\0')
12473 image_info->page=GetPageGeometry(geometry);
12476 Apply image transforms.
12478 XSetCursorState(display,windows,MagickTrue);
12479 XCheckRefreshWindows(display,windows);
12480 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12481 if (save_image == (Image *) NULL)
12482 return(MagickFalse);
12483 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
12484 windows->image.ximage->width,windows->image.ximage->height);
12485 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12489 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12490 status=WriteImage(image_info,save_image);
12491 if (status != MagickFalse)
12492 image->taint=MagickFalse;
12493 save_image=DestroyImage(save_image);
12494 image_info=DestroyImageInfo(image_info);
12495 XSetCursorState(display,windows,MagickFalse);
12496 return(status != 0 ? MagickTrue : MagickFalse);
12500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12504 + X S c r e e n E v e n t %
12508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12510 % XScreenEvent() handles global events associated with the Pan and Magnify
12513 % The format of the XScreenEvent function is:
12515 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12517 % A description of each parameter follows:
12519 % o display: Specifies a pointer to the Display structure; returned from
12522 % o windows: Specifies a pointer to a XWindows structure.
12524 % o event: Specifies a pointer to a X11 XEvent structure.
12529 #if defined(__cplusplus) || defined(c_plusplus)
12533 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12538 windows=(XWindows *) data;
12539 if ((event->type == ClientMessage) &&
12540 (event->xclient.window == windows->image.id))
12541 return(MagickFalse);
12542 return(MagickTrue);
12545 #if defined(__cplusplus) || defined(c_plusplus)
12549 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12555 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12556 if (event->xany.window == windows->command.id)
12558 switch (event->type)
12561 case ButtonRelease:
12563 if ((event->xbutton.button == Button3) &&
12564 (event->xbutton.state & Mod1Mask))
12567 Convert Alt-Button3 to Button2.
12569 event->xbutton.button=Button2;
12570 event->xbutton.state&=(~Mod1Mask);
12572 if (event->xbutton.window == windows->backdrop.id)
12574 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12575 event->xbutton.time);
12578 if (event->xbutton.window == windows->pan.id)
12580 XPanImage(display,windows,event);
12583 if (event->xbutton.window == windows->image.id)
12584 if (event->xbutton.button == Button2)
12587 Update magnified image.
12589 x=event->xbutton.x;
12590 y=event->xbutton.y;
12594 if (x >= (int) windows->image.width)
12595 x=(int) (windows->image.width-1);
12596 windows->magnify.x=(int) windows->image.x+x;
12600 if (y >= (int) windows->image.height)
12601 y=(int) (windows->image.height-1);
12602 windows->magnify.y=windows->image.y+y;
12603 if (windows->magnify.mapped == MagickFalse)
12604 (void) XMapRaised(display,windows->magnify.id);
12605 XMakeMagnifyImage(display,windows);
12606 if (event->type == ButtonRelease)
12607 (void) XWithdrawWindow(display,windows->info.id,
12608 windows->info.screen);
12613 case ClientMessage:
12616 If client window delete message, exit.
12618 if (event->xclient.message_type != windows->wm_protocols)
12620 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12622 if (event->xclient.window == windows->magnify.id)
12624 (void) XWithdrawWindow(display,windows->magnify.id,
12625 windows->magnify.screen);
12630 case ConfigureNotify:
12632 if (event->xconfigure.window == windows->magnify.id)
12638 Magnify window has a new configuration.
12640 windows->magnify.width=(unsigned int) event->xconfigure.width;
12641 windows->magnify.height=(unsigned int) event->xconfigure.height;
12642 if (windows->magnify.mapped == MagickFalse)
12645 while ((int) magnify <= event->xconfigure.width)
12647 while ((int) magnify <= event->xconfigure.height)
12650 if (((int) magnify != event->xconfigure.width) ||
12651 ((int) magnify != event->xconfigure.height))
12656 window_changes.width=(int) magnify;
12657 window_changes.height=(int) magnify;
12658 (void) XReconfigureWMWindow(display,windows->magnify.id,
12659 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12663 XMakeMagnifyImage(display,windows);
12670 if (event->xexpose.window == windows->image.id)
12672 XRefreshWindow(display,&windows->image,event);
12675 if (event->xexpose.window == windows->pan.id)
12676 if (event->xexpose.count == 0)
12678 XDrawPanRectangle(display,windows);
12681 if (event->xexpose.window == windows->magnify.id)
12682 if (event->xexpose.count == 0)
12684 XMakeMagnifyImage(display,windows);
12692 command[MaxTextExtent];
12697 if (event->xkey.window != windows->magnify.id)
12700 Respond to a user key press.
12702 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12703 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12704 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12709 if (event->xmap.window == windows->magnify.id)
12711 windows->magnify.mapped=MagickTrue;
12712 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12715 if (event->xmap.window == windows->info.id)
12717 windows->info.mapped=MagickTrue;
12724 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12725 if (event->xmotion.window == windows->image.id)
12726 if (windows->magnify.mapped != MagickFalse)
12729 Update magnified image.
12731 x=event->xmotion.x;
12732 y=event->xmotion.y;
12736 if (x >= (int) windows->image.width)
12737 x=(int) (windows->image.width-1);
12738 windows->magnify.x=(int) windows->image.x+x;
12742 if (y >= (int) windows->image.height)
12743 y=(int) (windows->image.height-1);
12744 windows->magnify.y=windows->image.y+y;
12745 XMakeMagnifyImage(display,windows);
12751 if (event->xunmap.window == windows->magnify.id)
12753 windows->magnify.mapped=MagickFalse;
12756 if (event->xunmap.window == windows->info.id)
12758 windows->info.mapped=MagickFalse;
12769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12773 + X S e t C r o p G e o m e t r y %
12777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12779 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12780 % and translates it to a cropping geometry relative to the image.
12782 % The format of the XSetCropGeometry method is:
12784 % void XSetCropGeometry(Display *display,XWindows *windows,
12785 % RectangleInfo *crop_info,Image *image)
12787 % A description of each parameter follows:
12789 % o display: Specifies a connection to an X server; returned from
12792 % o windows: Specifies a pointer to a XWindows structure.
12794 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12795 % Image window to crop.
12797 % o image: the image.
12800 static void XSetCropGeometry(Display *display,XWindows *windows,
12801 RectangleInfo *crop_info,Image *image)
12804 text[MaxTextExtent];
12817 if (windows->info.mapped != MagickFalse)
12820 Display info on cropping rectangle.
12822 (void) FormatMagickString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12823 (double) crop_info->width,(double) crop_info->height,(double)
12824 crop_info->x,(double) crop_info->y);
12825 XInfoWidget(display,windows,text);
12828 Cropping geometry is relative to any previous crop geometry.
12832 width=(unsigned int) image->columns;
12833 height=(unsigned int) image->rows;
12834 if (windows->image.crop_geometry != (char *) NULL)
12835 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12837 windows->image.crop_geometry=AcquireString((char *) NULL);
12839 Define the crop geometry string from the cropping rectangle.
12841 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12842 if (crop_info->x > 0)
12843 x+=(int) (scale_factor*crop_info->x+0.5);
12844 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12847 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12848 if (crop_info->y > 0)
12849 y+=(int) (scale_factor*crop_info->y+0.5);
12850 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12853 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12854 "%ux%u%+d%+d",width,height,x,y);
12858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12862 + X T i l e I m a g e %
12866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12868 % XTileImage() loads or deletes a selected tile from a visual image directory.
12869 % The load or delete command is chosen from a menu.
12871 % The format of the XTileImage method is:
12873 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
12874 % XWindows *windows,Image *image,XEvent *event)
12876 % A description of each parameter follows:
12878 % o tile_image: XTileImage reads or deletes the tile image
12879 % and returns it. A null image is returned if an error occurs.
12881 % o display: Specifies a connection to an X server; returned from
12884 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12886 % o windows: Specifies a pointer to a XWindows structure.
12888 % o image: the image; returned from ReadImage.
12890 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
12891 % the entire image is refreshed.
12894 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12895 XWindows *windows,Image *image,XEvent *event)
12908 static const ModeType
12919 command[MaxTextExtent],
12920 filename[MaxTextExtent];
12947 Tile image is relative to montage image configuration.
12951 width=(unsigned int) image->columns;
12952 height=(unsigned int) image->rows;
12953 if (windows->image.crop_geometry != (char *) NULL)
12954 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12955 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12956 event->xbutton.x+=windows->image.x;
12957 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12958 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12959 event->xbutton.y+=windows->image.y;
12960 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12962 Determine size and location of each tile in the visual image directory.
12964 width=(unsigned int) image->columns;
12965 height=(unsigned int) image->rows;
12968 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
12969 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
12970 (event->xbutton.x-x)/width;
12974 Button press is outside any tile.
12976 (void) XBell(display,0);
12977 return((Image *) NULL);
12980 Determine file name from the tile directory.
12982 p=image->directory;
12983 for (i=tile; (i != 0) && (*p != '\0'); )
12992 Button press is outside any tile.
12994 (void) XBell(display,0);
12995 return((Image *) NULL);
12998 Select a command from the pop-up menu.
13000 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13002 return((Image *) NULL);
13004 while ((*q != '\n') && (*q != '\0'))
13006 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13008 Perform command for the selected tile.
13010 XSetCursorState(display,windows,MagickTrue);
13011 XCheckRefreshWindows(display,windows);
13012 tile_image=NewImageList();
13013 switch (TileCommands[id])
13015 case TileLoadCommand:
13020 XCheckRefreshWindows(display,windows);
13021 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13023 (void) CopyMagickString(resource_info->image_info->filename,filename,
13025 tile_image=ReadImage(resource_info->image_info,&image->exception);
13026 CatchException(&image->exception);
13027 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13030 case TileNextCommand:
13033 Display next image.
13035 XClientMessage(display,windows->image.id,windows->im_protocols,
13036 windows->im_next_image,CurrentTime);
13039 case TileFormerCommand:
13042 Display former image.
13044 XClientMessage(display,windows->image.id,windows->im_protocols,
13045 windows->im_former_image,CurrentTime);
13048 case TileDeleteCommand:
13053 if (IsPathAccessible(filename) == MagickFalse)
13055 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13058 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13061 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13062 if (status != MagickFalse)
13064 XNoticeWidget(display,windows,"Unable to delete image file:",
13069 case TileUpdateCommand:
13084 register PixelPacket
13088 Ensure all the images exist.
13091 for (p=image->directory; *p != '\0'; p++)
13097 while ((*q != '\n') && (*q != '\0'))
13099 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13101 if (IsPathAccessible(filename) != MagickFalse)
13107 Overwrite tile with background color.
13109 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13110 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13111 exception=(&image->exception);
13112 image_view=AcquireCacheView(image);
13113 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13114 for (i=0; i < (int) height; i++)
13116 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13117 y_offset+i,width,1,exception);
13118 if (s == (PixelPacket *) NULL)
13120 for (j=0; j < (int) width; j++)
13122 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13125 image_view=DestroyCacheView(image_view);
13128 windows->image.window_changes.width=(int) image->columns;
13129 windows->image.window_changes.height=(int) image->rows;
13130 XConfigureImageColormap(display,resource_info,windows,image);
13131 (void) XConfigureImage(display,resource_info,windows,image);
13137 XSetCursorState(display,windows,MagickFalse);
13138 return(tile_image);
13142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13146 + X T r a n s l a t e I m a g e %
13150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13152 % XTranslateImage() translates the image within an Image window by one pixel
13153 % as specified by the key symbol. If the image has a `montage string the
13154 % translation is respect to the width and height contained within the string.
13156 % The format of the XTranslateImage method is:
13158 % void XTranslateImage(Display *display,XWindows *windows,
13159 % Image *image,const KeySym key_symbol)
13161 % A description of each parameter follows:
13163 % o display: Specifies a connection to an X server; returned from
13166 % o windows: Specifies a pointer to a XWindows structure.
13168 % o image: the image.
13170 % o key_symbol: Specifies a KeySym which indicates which side of the image
13174 static void XTranslateImage(Display *display,XWindows *windows,
13175 Image *image,const KeySym key_symbol)
13178 text[MaxTextExtent];
13189 User specified a pan position offset.
13191 x_offset=windows->image.width;
13192 y_offset=windows->image.height;
13193 if (image->montage != (char *) NULL)
13194 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13195 switch ((int) key_symbol)
13200 windows->image.x=(int) windows->image.width/2;
13201 windows->image.y=(int) windows->image.height/2;
13207 windows->image.x-=x_offset;
13214 windows->image.y-=y_offset;
13220 windows->image.x+=x_offset;
13227 windows->image.y+=y_offset;
13234 Check boundary conditions.
13236 if (windows->image.x < 0)
13237 windows->image.x=0;
13239 if ((int) (windows->image.x+windows->image.width) >
13240 windows->image.ximage->width)
13241 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13242 if (windows->image.y < 0)
13243 windows->image.y=0;
13245 if ((int) (windows->image.y+windows->image.height) >
13246 windows->image.ximage->height)
13247 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13249 Refresh Image window.
13251 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
13252 windows->image.width,windows->image.height,windows->image.x,
13254 XInfoWidget(display,windows,text);
13255 XCheckRefreshWindows(display,windows);
13256 XDrawPanRectangle(display,windows);
13257 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13258 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13266 + X T r i m I m a g e %
13270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13272 % XTrimImage() trims the edges from the Image window.
13274 % The format of the XTrimImage method is:
13276 % MagickBooleanType XTrimImage(Display *display,
13277 % XResourceInfo *resource_info,XWindows *windows,Image *image)
13279 % A description of each parameter follows:
13281 % o display: Specifies a connection to an X server; returned from
13284 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13286 % o windows: Specifies a pointer to a XWindows structure.
13288 % o image: the image.
13291 static MagickBooleanType XTrimImage(Display *display,
13292 XResourceInfo *resource_info,XWindows *windows,Image *image)
13306 Trim edges from image.
13308 XSetCursorState(display,windows,MagickTrue);
13309 XCheckRefreshWindows(display,windows);
13311 Crop the left edge.
13313 background=XGetPixel(windows->image.ximage,0,0);
13314 trim_info.width=(size_t) windows->image.ximage->width;
13315 for (x=0; x < windows->image.ximage->width; x++)
13317 for (y=0; y < windows->image.ximage->height; y++)
13319 pixel=XGetPixel(windows->image.ximage,x,y);
13320 if (pixel != background)
13323 if (y < windows->image.ximage->height)
13326 trim_info.x=(ssize_t) x;
13327 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13329 XSetCursorState(display,windows,MagickFalse);
13330 return(MagickFalse);
13333 Crop the right edge.
13335 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13336 for (x=windows->image.ximage->width-1; x != 0; x--)
13338 for (y=0; y < windows->image.ximage->height; y++)
13340 pixel=XGetPixel(windows->image.ximage,x,y);
13341 if (pixel != background)
13344 if (y < windows->image.ximage->height)
13347 trim_info.width=(size_t) (x-trim_info.x+1);
13351 background=XGetPixel(windows->image.ximage,0,0);
13352 trim_info.height=(size_t) windows->image.ximage->height;
13353 for (y=0; y < windows->image.ximage->height; y++)
13355 for (x=0; x < windows->image.ximage->width; x++)
13357 pixel=XGetPixel(windows->image.ximage,x,y);
13358 if (pixel != background)
13361 if (x < windows->image.ximage->width)
13364 trim_info.y=(ssize_t) y;
13366 Crop the bottom edge.
13368 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13369 for (y=windows->image.ximage->height-1; y != 0; y--)
13371 for (x=0; x < windows->image.ximage->width; x++)
13373 pixel=XGetPixel(windows->image.ximage,x,y);
13374 if (pixel != background)
13377 if (x < windows->image.ximage->width)
13380 trim_info.height=(size_t) y-trim_info.y+1;
13381 if (((unsigned int) trim_info.width != windows->image.width) ||
13382 ((unsigned int) trim_info.height != windows->image.height))
13385 Reconfigure Image window as defined by the trimming rectangle.
13387 XSetCropGeometry(display,windows,&trim_info,image);
13388 windows->image.window_changes.width=(int) trim_info.width;
13389 windows->image.window_changes.height=(int) trim_info.height;
13390 (void) XConfigureImage(display,resource_info,windows,image);
13392 XSetCursorState(display,windows,MagickFalse);
13393 return(MagickTrue);
13397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13401 + X V i s u a l D i r e c t o r y I m a g e %
13405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13407 % XVisualDirectoryImage() creates a Visual Image Directory.
13409 % The format of the XVisualDirectoryImage method is:
13411 % Image *XVisualDirectoryImage(Display *display,
13412 % XResourceInfo *resource_info,XWindows *windows)
13414 % A description of each parameter follows:
13416 % o nexus: Method XVisualDirectoryImage returns a visual image
13417 % directory if it can be created successfully. Otherwise a null image
13420 % o display: Specifies a connection to an X server; returned from
13423 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13425 % o windows: Specifies a pointer to a XWindows structure.
13428 static Image *XVisualDirectoryImage(Display *display,
13429 XResourceInfo *resource_info,XWindows *windows)
13431 #define TileImageTag "Scale/Image"
13432 #define XClientName "montage"
13468 filename[MaxTextExtent] = "\0",
13469 filenames[MaxTextExtent] = "*";
13472 background_resources;
13475 Request file name from user.
13477 XFileBrowserWidget(display,windows,"Directory",filenames);
13478 if (*filenames == '\0')
13479 return((Image *) NULL);
13481 Expand the filenames.
13483 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13484 if (filelist == (char **) NULL)
13486 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13488 return((Image *) NULL);
13491 filelist[0]=filenames;
13492 status=ExpandFilenames(&number_files,&filelist);
13493 if ((status == MagickFalse) || (number_files == 0))
13495 if (number_files == 0)
13496 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13498 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13500 return((Image *) NULL);
13503 Set image background resources.
13505 background_resources=(*resource_info);
13506 background_resources.window_id=AcquireString("");
13507 (void) FormatMagickString(background_resources.window_id,MaxTextExtent,
13508 "0x%lx",windows->image.id);
13509 background_resources.backdrop=MagickTrue;
13511 Read each image and convert them to a tile.
13513 backdrop=(windows->visual_info->klass == TrueColor) ||
13514 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13515 read_info=CloneImageInfo(resource_info->image_info);
13516 (void) SetImageOption(read_info,"jpeg:size","120x120");
13517 (void) CloneString(&read_info->size,DefaultTileGeometry);
13518 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13520 images=NewImageList();
13521 exception=AcquireExceptionInfo();
13522 XSetCursorState(display,windows,MagickTrue);
13523 XCheckRefreshWindows(display,windows);
13524 for (i=0; i < (int) number_files; i++)
13526 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13527 filelist[i]=DestroyString(filelist[i]);
13528 *read_info->magick='\0';
13529 next_image=ReadImage(read_info,exception);
13530 CatchException(exception);
13531 if (next_image != (Image *) NULL)
13533 (void) DeleteImageProperty(next_image,"label");
13534 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13535 read_info,next_image,DefaultTileLabel));
13536 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13538 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13539 geometry.height,exception);
13540 if (thumbnail_image != (Image *) NULL)
13542 next_image=DestroyImage(next_image);
13543 next_image=thumbnail_image;
13547 (void) XDisplayBackgroundImage(display,&background_resources,
13549 XSetCursorState(display,windows,MagickTrue);
13551 AppendImageToList(&images,next_image);
13552 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13557 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13558 (MagickSizeType) number_files);
13559 if (proceed == MagickFalse)
13564 exception=DestroyExceptionInfo(exception);
13565 filelist=(char **) RelinquishMagickMemory(filelist);
13566 if (images == (Image *) NULL)
13568 read_info=DestroyImageInfo(read_info);
13569 XSetCursorState(display,windows,MagickFalse);
13570 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13571 return((Image *) NULL);
13574 Create the Visual Image Directory.
13576 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13577 montage_info->pointsize=10;
13578 if (resource_info->font != (char *) NULL)
13579 (void) CloneString(&montage_info->font,resource_info->font);
13580 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13581 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13582 images),&images->exception);
13583 images=DestroyImageList(images);
13584 montage_info=DestroyMontageInfo(montage_info);
13585 read_info=DestroyImageInfo(read_info);
13586 XSetCursorState(display,windows,MagickFalse);
13587 if (montage_image == (Image *) NULL)
13588 return(montage_image);
13589 XClientMessage(display,windows->image.id,windows->im_protocols,
13590 windows->im_next_image,CurrentTime);
13591 return(montage_image);
13595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13599 % X D i s p l a y B a c k g r o u n d I m a g e %
13603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13605 % XDisplayBackgroundImage() displays an image in the background of a window.
13607 % The format of the XDisplayBackgroundImage method is:
13609 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13610 % XResourceInfo *resource_info,Image *image)
13612 % A description of each parameter follows:
13614 % o display: Specifies a connection to an X server; returned from
13617 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13619 % o image: the image.
13622 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13623 XResourceInfo *resource_info,Image *image)
13626 geometry[MaxTextExtent],
13627 visual_type[MaxTextExtent];
13640 static XStandardColormap
13644 *visual_info = (XVisualInfo *) NULL;
13665 Determine target window.
13667 assert(image != (Image *) NULL);
13668 assert(image->signature == MagickSignature);
13669 if (image->debug != MagickFalse)
13670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13671 resources=(*resource_info);
13672 window_info.id=(Window) NULL;
13673 root_window=XRootWindow(display,XDefaultScreen(display));
13674 if (LocaleCompare(resources.window_id,"root") == 0)
13675 window_info.id=root_window;
13678 if (isdigit((unsigned char) *resources.window_id) != 0)
13679 window_info.id=XWindowByID(display,root_window,
13680 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13681 if (window_info.id == (Window) NULL)
13682 window_info.id=XWindowByName(display,root_window,resources.window_id);
13684 if (window_info.id == (Window) NULL)
13686 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13687 resources.window_id);
13688 return(MagickFalse);
13691 Determine window visual id.
13693 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13694 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13695 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13696 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13698 (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
13699 XVisualIDFromVisual(window_attributes.visual));
13700 if (visual_info == (XVisualInfo *) NULL)
13703 Allocate standard colormap.
13705 map_info=XAllocStandardColormap();
13706 if (map_info == (XStandardColormap *) NULL)
13707 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13709 map_info->colormap=(Colormap) NULL;
13710 pixel.pixels=(unsigned long *) NULL;
13712 Initialize visual info.
13714 resources.map_type=(char *) NULL;
13715 resources.visual_type=visual_type;
13716 visual_info=XBestVisualInfo(display,map_info,&resources);
13717 if (visual_info == (XVisualInfo *) NULL)
13718 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13719 resources.visual_type);
13721 Initialize window info.
13723 window_info.ximage=(XImage *) NULL;
13724 window_info.matte_image=(XImage *) NULL;
13725 window_info.pixmap=(Pixmap) NULL;
13726 window_info.matte_pixmap=(Pixmap) NULL;
13729 Free previous root colors.
13731 if (window_info.id == root_window)
13732 (void) XDestroyWindowColors(display,root_window);
13734 Initialize Standard Colormap.
13736 resources.colormap=SharedColormap;
13737 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13739 Graphic context superclass.
13741 context_values.background=pixel.background_color.pixel;
13742 context_values.foreground=pixel.foreground_color.pixel;
13743 pixel.annotate_context=XCreateGC(display,window_info.id,
13744 (size_t) (GCBackground | GCForeground),&context_values);
13745 if (pixel.annotate_context == (GC) NULL)
13746 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13749 Initialize Image window attributes.
13751 window_info.name=AcquireString("\0");
13752 window_info.icon_name=AcquireString("\0");
13753 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13754 &resources,&window_info);
13756 Create the X image.
13758 window_info.width=(unsigned int) image->columns;
13759 window_info.height=(unsigned int) image->rows;
13760 if ((image->columns != window_info.width) ||
13761 (image->rows != window_info.height))
13762 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13764 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
13765 window_attributes.width,window_attributes.height);
13766 geometry_info.width=window_info.width;
13767 geometry_info.height=window_info.height;
13768 geometry_info.x=(ssize_t) window_info.x;
13769 geometry_info.y=(ssize_t) window_info.y;
13770 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13771 &geometry_info.width,&geometry_info.height);
13772 window_info.width=(unsigned int) geometry_info.width;
13773 window_info.height=(unsigned int) geometry_info.height;
13774 window_info.x=(int) geometry_info.x;
13775 window_info.y=(int) geometry_info.y;
13776 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13777 window_info.height);
13778 if (status == MagickFalse)
13779 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13783 if (image->debug != MagickFalse)
13785 (void) LogMagickEvent(X11Event,GetMagickModule(),
13786 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13787 (double) image->columns,(double) image->rows);
13788 if (image->colors != 0)
13789 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13791 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13794 Adjust image dimensions as specified by backdrop or geometry options.
13796 width=(int) window_info.width;
13797 height=(int) window_info.height;
13798 if (resources.backdrop != MagickFalse)
13801 Center image on window.
13803 window_info.x=(window_attributes.width/2)-
13804 (window_info.ximage->width/2);
13805 window_info.y=(window_attributes.height/2)-
13806 (window_info.ximage->height/2);
13807 width=window_attributes.width;
13808 height=window_attributes.height;
13810 if ((resources.image_geometry != (char *) NULL) &&
13811 (*resources.image_geometry != '\0'))
13814 default_geometry[MaxTextExtent];
13824 User specified geometry.
13826 size_hints=XAllocSizeHints();
13827 if (size_hints == (XSizeHints *) NULL)
13828 ThrowXWindowFatalException(ResourceLimitFatalError,
13829 "MemoryAllocationFailed",image->filename);
13830 size_hints->flags=0L;
13831 (void) FormatMagickString(default_geometry,MaxTextExtent,"%dx%d",
13833 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13834 default_geometry,window_info.border_width,size_hints,&window_info.x,
13835 &window_info.y,&width,&height,&gravity);
13836 if (flags & (XValue | YValue))
13838 width=window_attributes.width;
13839 height=window_attributes.height;
13841 (void) XFree((void *) size_hints);
13844 Create the X pixmap.
13846 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13847 (unsigned int) height,window_info.depth);
13848 if (window_info.pixmap == (Pixmap) NULL)
13849 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13852 Display pixmap on the window.
13854 if (((unsigned int) width > window_info.width) ||
13855 ((unsigned int) height > window_info.height))
13856 (void) XFillRectangle(display,window_info.pixmap,
13857 window_info.annotate_context,0,0,(unsigned int) width,
13858 (unsigned int) height);
13859 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13860 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13861 window_info.width,(unsigned int) window_info.height);
13862 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13863 (void) XClearWindow(display,window_info.id);
13864 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13865 XDelay(display,delay == 0UL ? 10UL : delay);
13866 (void) XSync(display,MagickFalse);
13867 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13875 + X D i s p l a y I m a g e %
13879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13881 % XDisplayImage() displays an image via X11. A new image is created and
13882 % returned if the user interactively transforms the displayed image.
13884 % The format of the XDisplayImage method is:
13886 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13887 % char **argv,int argc,Image **image,size_t *state)
13889 % A description of each parameter follows:
13891 % o nexus: Method XDisplayImage returns an image when the
13892 % user chooses 'Open Image' from the command menu or picks a tile
13893 % from the image directory. Otherwise a null image is returned.
13895 % o display: Specifies a connection to an X server; returned from
13898 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13900 % o argv: Specifies the application's argument list.
13902 % o argc: Specifies the number of arguments.
13904 % o image: Specifies an address to an address of an Image structure;
13907 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13908 char **argv,int argc,Image **image,size_t *state)
13910 #define MagnifySize 256 /* must be a power of 2 */
13911 #define MagickMenus 10
13912 #define MagickTitle "Commands"
13939 "Visual Directory...",
13985 "Contrast Stretch...",
13986 "Sigmoidal Contrast...",
14020 "Charcoal Draw...",
14034 "Region of Interest...",
14037 *MiscellanyMenu[] =
14052 "Browse Documentation",
14079 **Menus[MagickMenus] =
14117 VisualDirectoryCommand,
14131 OriginalSizeCommand,
14138 TransformCommands[] =
14144 RotateRightCommand,
14151 EnhanceCommands[] =
14159 ContrastStretchCommand,
14160 SigmoidalContrastCommand,
14168 EffectsCommands[] =
14172 ReduceNoiseCommand,
14192 CharcoalDrawCommand
14194 ImageEditCommands[] =
14205 RegionofInterestCommand
14207 MiscellanyCommands[] =
14211 ShowPreviewCommand,
14212 ShowHistogramCommand,
14221 BrowseDocumentationCommand,
14224 ShortCutsCommands[] =
14236 VirtualCommands[] =
14245 *Commands[MagickMenus] =
14255 MiscellanyCommands,
14260 command[MaxTextExtent],
14262 geometry[MaxTextExtent],
14263 resource_name[MaxTextExtent];
14290 working_directory[MaxTextExtent];
14296 *magick_windows[MaxXWindows];
14298 static unsigned int
14358 assert(image != (Image **) NULL);
14359 assert((*image)->signature == MagickSignature);
14360 if ((*image)->debug != MagickFalse)
14361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14362 display_image=(*image);
14363 warning_handler=(WarningHandler) NULL;
14364 windows=XSetWindows((XWindows *) ~0);
14365 if (windows != (XWindows *) NULL)
14370 status=chdir(working_directory);
14372 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14373 FileOpenError,"UnableToOpenFile","%s",working_directory);
14374 warning_handler=resource_info->display_warnings ?
14375 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14376 warning_handler=resource_info->display_warnings ?
14377 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14382 Allocate windows structure.
14384 resource_info->colors=display_image->colors;
14385 windows=XSetWindows(XInitializeWindows(display,resource_info));
14386 if (windows == (XWindows *) NULL)
14387 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14388 (*image)->filename);
14390 Initialize window id's.
14393 magick_windows[number_windows++]=(&windows->icon);
14394 magick_windows[number_windows++]=(&windows->backdrop);
14395 magick_windows[number_windows++]=(&windows->image);
14396 magick_windows[number_windows++]=(&windows->info);
14397 magick_windows[number_windows++]=(&windows->command);
14398 magick_windows[number_windows++]=(&windows->widget);
14399 magick_windows[number_windows++]=(&windows->popup);
14400 magick_windows[number_windows++]=(&windows->magnify);
14401 magick_windows[number_windows++]=(&windows->pan);
14402 for (i=0; i < (int) number_windows; i++)
14403 magick_windows[i]->id=(Window) NULL;
14408 Initialize font info.
14410 if (windows->font_info != (XFontStruct *) NULL)
14411 (void) XFreeFont(display,windows->font_info);
14412 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14413 if (windows->font_info == (XFontStruct *) NULL)
14414 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14415 resource_info->font);
14417 Initialize Standard Colormap.
14419 map_info=windows->map_info;
14420 icon_map=windows->icon_map;
14421 visual_info=windows->visual_info;
14422 icon_visual=windows->icon_visual;
14423 pixel=windows->pixel_info;
14424 icon_pixel=windows->icon_pixel;
14425 font_info=windows->font_info;
14426 icon_resources=windows->icon_resources;
14427 class_hints=windows->class_hints;
14428 manager_hints=windows->manager_hints;
14429 root_window=XRootWindow(display,visual_info->screen);
14430 nexus=NewImageList();
14431 if (display_image->debug != MagickFalse)
14433 (void) LogMagickEvent(X11Event,GetMagickModule(),
14434 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14435 (double) display_image->scene,(double) display_image->columns,
14436 (double) display_image->rows);
14437 if (display_image->colors != 0)
14438 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14439 display_image->colors);
14440 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14441 display_image->magick);
14443 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14445 display_image->taint=MagickFalse;
14447 Initialize graphic context.
14449 windows->context.id=(Window) NULL;
14450 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14451 resource_info,&windows->context);
14452 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14453 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14454 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14455 manager_hints->flags=InputHint | StateHint;
14456 manager_hints->input=MagickFalse;
14457 manager_hints->initial_state=WithdrawnState;
14458 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14459 &windows->context);
14460 if (display_image->debug != MagickFalse)
14461 (void) LogMagickEvent(X11Event,GetMagickModule(),
14462 "Window id: 0x%lx (context)",windows->context.id);
14463 context_values.background=pixel->background_color.pixel;
14464 context_values.font=font_info->fid;
14465 context_values.foreground=pixel->foreground_color.pixel;
14466 context_values.graphics_exposures=MagickFalse;
14467 context_mask=(MagickStatusType)
14468 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14469 if (pixel->annotate_context != (GC) NULL)
14470 (void) XFreeGC(display,pixel->annotate_context);
14471 pixel->annotate_context=XCreateGC(display,windows->context.id,
14472 context_mask,&context_values);
14473 if (pixel->annotate_context == (GC) NULL)
14474 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14475 display_image->filename);
14476 context_values.background=pixel->depth_color.pixel;
14477 if (pixel->widget_context != (GC) NULL)
14478 (void) XFreeGC(display,pixel->widget_context);
14479 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14481 if (pixel->widget_context == (GC) NULL)
14482 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14483 display_image->filename);
14484 context_values.background=pixel->foreground_color.pixel;
14485 context_values.foreground=pixel->background_color.pixel;
14486 context_values.plane_mask=context_values.background ^
14487 context_values.foreground;
14488 if (pixel->highlight_context != (GC) NULL)
14489 (void) XFreeGC(display,pixel->highlight_context);
14490 pixel->highlight_context=XCreateGC(display,windows->context.id,
14491 (size_t) (context_mask | GCPlaneMask),&context_values);
14492 if (pixel->highlight_context == (GC) NULL)
14493 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14494 display_image->filename);
14495 (void) XDestroyWindow(display,windows->context.id);
14497 Initialize icon window.
14499 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14500 icon_resources,&windows->icon);
14501 windows->icon.geometry=resource_info->icon_geometry;
14502 XBestIconSize(display,&windows->icon,display_image);
14503 windows->icon.attributes.colormap=XDefaultColormap(display,
14504 icon_visual->screen);
14505 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14506 manager_hints->flags=InputHint | StateHint;
14507 manager_hints->input=MagickFalse;
14508 manager_hints->initial_state=IconicState;
14509 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14511 if (display_image->debug != MagickFalse)
14512 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14515 Initialize graphic context for icon window.
14517 if (icon_pixel->annotate_context != (GC) NULL)
14518 (void) XFreeGC(display,icon_pixel->annotate_context);
14519 context_values.background=icon_pixel->background_color.pixel;
14520 context_values.foreground=icon_pixel->foreground_color.pixel;
14521 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14522 (size_t) (GCBackground | GCForeground),&context_values);
14523 if (icon_pixel->annotate_context == (GC) NULL)
14524 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14525 display_image->filename);
14526 windows->icon.annotate_context=icon_pixel->annotate_context;
14528 Initialize Image window.
14530 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14532 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14533 if (resource_info->use_shared_memory == MagickFalse)
14534 windows->image.shared_memory=MagickFalse;
14535 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14540 title=InterpretImageProperties(resource_info->image_info,display_image,
14541 resource_info->title);
14542 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14543 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14544 title=DestroyString(title);
14549 filename[MaxTextExtent];
14552 Window name is the base of the filename.
14554 GetPathComponent(display_image->magick_filename,TailPath,filename);
14555 if (GetImageListLength(display_image) == 1)
14556 (void) FormatMagickString(windows->image.name,MaxTextExtent,
14557 "%s: %s",MagickPackageName,filename);
14559 (void) FormatMagickString(windows->image.name,MaxTextExtent,
14560 "%s: %s[%.20g of %.20g]",MagickPackageName,filename,(double)
14561 display_image->scene,(double) GetImageListLength(display_image));
14562 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14564 if (resource_info->immutable)
14565 windows->image.immutable=MagickTrue;
14566 windows->image.use_pixmap=resource_info->use_pixmap;
14567 windows->image.geometry=resource_info->image_geometry;
14568 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14569 XDisplayWidth(display,visual_info->screen),
14570 XDisplayHeight(display,visual_info->screen));
14571 geometry_info.width=display_image->columns;
14572 geometry_info.height=display_image->rows;
14575 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14576 &geometry_info.width,&geometry_info.height);
14577 windows->image.width=(unsigned int) geometry_info.width;
14578 windows->image.height=(unsigned int) geometry_info.height;
14579 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14580 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14581 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14582 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14583 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14584 resource_info,&windows->backdrop);
14585 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14588 Initialize backdrop window.
14590 windows->backdrop.x=0;
14591 windows->backdrop.y=0;
14592 (void) CloneString(&windows->backdrop.name,"Backdrop");
14593 windows->backdrop.flags=(size_t) (USSize | USPosition);
14594 windows->backdrop.width=(unsigned int)
14595 XDisplayWidth(display,visual_info->screen);
14596 windows->backdrop.height=(unsigned int)
14597 XDisplayHeight(display,visual_info->screen);
14598 windows->backdrop.border_width=0;
14599 windows->backdrop.immutable=MagickTrue;
14600 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14602 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14603 StructureNotifyMask;
14604 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14605 manager_hints->icon_window=windows->icon.id;
14606 manager_hints->input=MagickTrue;
14607 manager_hints->initial_state=resource_info->iconic ? IconicState :
14609 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14610 &windows->backdrop);
14611 if (display_image->debug != MagickFalse)
14612 (void) LogMagickEvent(X11Event,GetMagickModule(),
14613 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14614 (void) XMapWindow(display,windows->backdrop.id);
14615 (void) XClearWindow(display,windows->backdrop.id);
14616 if (windows->image.id != (Window) NULL)
14618 (void) XDestroyWindow(display,windows->image.id);
14619 windows->image.id=(Window) NULL;
14622 Position image in the center the backdrop.
14624 windows->image.flags|=USPosition;
14625 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14626 (windows->image.width/2);
14627 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14628 (windows->image.height/2);
14630 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14631 manager_hints->icon_window=windows->icon.id;
14632 manager_hints->input=MagickTrue;
14633 manager_hints->initial_state=resource_info->iconic ? IconicState :
14635 if (windows->group_leader.id != (Window) NULL)
14640 manager_hints->flags|=WindowGroupHint;
14641 manager_hints->window_group=windows->group_leader.id;
14642 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14643 if (display_image->debug != MagickFalse)
14644 (void) LogMagickEvent(X11Event,GetMagickModule(),
14645 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14647 XMakeWindow(display,
14648 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14649 argv,argc,class_hints,manager_hints,&windows->image);
14650 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14651 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14652 if (windows->group_leader.id != (Window) NULL)
14653 (void) XSetTransientForHint(display,windows->image.id,
14654 windows->group_leader.id);
14655 if (display_image->debug != MagickFalse)
14656 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14657 windows->image.id);
14659 Initialize Info widget.
14661 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14663 (void) CloneString(&windows->info.name,"Info");
14664 (void) CloneString(&windows->info.icon_name,"Info");
14665 windows->info.border_width=1;
14668 windows->info.flags|=PPosition;
14669 windows->info.attributes.win_gravity=UnmapGravity;
14670 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14671 StructureNotifyMask;
14672 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14673 manager_hints->input=MagickFalse;
14674 manager_hints->initial_state=NormalState;
14675 manager_hints->window_group=windows->image.id;
14676 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14678 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14679 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14680 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14681 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14682 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14683 if (windows->image.mapped != MagickFalse)
14684 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14685 if (display_image->debug != MagickFalse)
14686 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14689 Initialize Command widget.
14691 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14692 resource_info,&windows->command);
14693 windows->command.data=MagickMenus;
14694 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14695 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
14696 resource_info->client_name);
14697 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14698 resource_name,"geometry",(char *) NULL);
14699 (void) CloneString(&windows->command.name,MagickTitle);
14700 windows->command.border_width=0;
14701 windows->command.flags|=PPosition;
14702 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14703 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14704 OwnerGrabButtonMask | StructureNotifyMask;
14705 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14706 manager_hints->input=MagickTrue;
14707 manager_hints->initial_state=NormalState;
14708 manager_hints->window_group=windows->image.id;
14709 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14710 &windows->command);
14711 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14712 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14714 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14715 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14716 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14717 if (windows->command.mapped != MagickFalse)
14718 (void) XMapRaised(display,windows->command.id);
14719 if (display_image->debug != MagickFalse)
14720 (void) LogMagickEvent(X11Event,GetMagickModule(),
14721 "Window id: 0x%lx (command)",windows->command.id);
14723 Initialize Widget window.
14725 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14726 resource_info,&windows->widget);
14727 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
14728 resource_info->client_name);
14729 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14730 resource_name,"geometry",(char *) NULL);
14731 windows->widget.border_width=0;
14732 windows->widget.flags|=PPosition;
14733 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14734 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14735 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14736 StructureNotifyMask;
14737 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14738 manager_hints->input=MagickTrue;
14739 manager_hints->initial_state=NormalState;
14740 manager_hints->window_group=windows->image.id;
14741 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14743 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14744 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14745 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14746 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14747 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14748 if (display_image->debug != MagickFalse)
14749 (void) LogMagickEvent(X11Event,GetMagickModule(),
14750 "Window id: 0x%lx (widget)",windows->widget.id);
14752 Initialize popup window.
14754 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14755 resource_info,&windows->popup);
14756 windows->popup.border_width=0;
14757 windows->popup.flags|=PPosition;
14758 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14759 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14760 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14761 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14762 manager_hints->input=MagickTrue;
14763 manager_hints->initial_state=NormalState;
14764 manager_hints->window_group=windows->image.id;
14765 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14767 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14768 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14769 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14770 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14771 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14772 if (display_image->debug != MagickFalse)
14773 (void) LogMagickEvent(X11Event,GetMagickModule(),
14774 "Window id: 0x%lx (pop up)",windows->popup.id);
14776 Initialize Magnify window and cursor.
14778 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14779 resource_info,&windows->magnify);
14780 if (resource_info->use_shared_memory == MagickFalse)
14781 windows->magnify.shared_memory=MagickFalse;
14782 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.magnify",
14783 resource_info->client_name);
14784 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14785 resource_name,"geometry",(char *) NULL);
14786 (void) FormatMagickString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14787 resource_info->magnify);
14788 if (windows->magnify.cursor != (Cursor) NULL)
14789 (void) XFreeCursor(display,windows->magnify.cursor);
14790 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14791 map_info->colormap,resource_info->background_color,
14792 resource_info->foreground_color);
14793 if (windows->magnify.cursor == (Cursor) NULL)
14794 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14795 display_image->filename);
14796 windows->magnify.width=MagnifySize;
14797 windows->magnify.height=MagnifySize;
14798 windows->magnify.flags|=PPosition;
14799 windows->magnify.min_width=MagnifySize;
14800 windows->magnify.min_height=MagnifySize;
14801 windows->magnify.width_inc=MagnifySize;
14802 windows->magnify.height_inc=MagnifySize;
14803 windows->magnify.data=resource_info->magnify;
14804 windows->magnify.attributes.cursor=windows->magnify.cursor;
14805 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14806 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14807 StructureNotifyMask;
14808 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14809 manager_hints->input=MagickTrue;
14810 manager_hints->initial_state=NormalState;
14811 manager_hints->window_group=windows->image.id;
14812 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14813 &windows->magnify);
14814 if (display_image->debug != MagickFalse)
14815 (void) LogMagickEvent(X11Event,GetMagickModule(),
14816 "Window id: 0x%lx (magnify)",windows->magnify.id);
14817 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14819 Initialize panning window.
14821 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14822 resource_info,&windows->pan);
14823 (void) CloneString(&windows->pan.name,"Pan Icon");
14824 windows->pan.width=windows->icon.width;
14825 windows->pan.height=windows->icon.height;
14826 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.pan",
14827 resource_info->client_name);
14828 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14829 resource_name,"geometry",(char *) NULL);
14830 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14831 &windows->pan.width,&windows->pan.height);
14832 windows->pan.flags|=PPosition;
14833 windows->pan.immutable=MagickTrue;
14834 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14835 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14836 StructureNotifyMask;
14837 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14838 manager_hints->input=MagickFalse;
14839 manager_hints->initial_state=NormalState;
14840 manager_hints->window_group=windows->image.id;
14841 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14843 if (display_image->debug != MagickFalse)
14844 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14846 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14847 if (windows->info.mapped != MagickFalse)
14848 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14849 if ((windows->image.mapped == MagickFalse) ||
14850 (windows->backdrop.id != (Window) NULL))
14851 (void) XMapWindow(display,windows->image.id);
14853 Set our progress monitor and warning handlers.
14855 if (warning_handler == (WarningHandler) NULL)
14857 warning_handler=resource_info->display_warnings ?
14858 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14859 warning_handler=resource_info->display_warnings ?
14860 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14863 Initialize Image and Magnify X images.
14865 windows->image.x=0;
14866 windows->image.y=0;
14867 windows->magnify.shape=MagickFalse;
14868 width=(unsigned int) display_image->columns;
14869 height=(unsigned int) display_image->rows;
14870 if ((display_image->columns != width) || (display_image->rows != height))
14871 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14872 display_image->filename);
14873 status=XMakeImage(display,resource_info,&windows->image,display_image,
14875 if (status == MagickFalse)
14876 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14877 display_image->filename);
14878 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14879 windows->magnify.width,windows->magnify.height);
14880 if (status == MagickFalse)
14881 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14882 display_image->filename);
14883 if (windows->magnify.mapped != MagickFalse)
14884 (void) XMapRaised(display,windows->magnify.id);
14885 if (windows->pan.mapped != MagickFalse)
14886 (void) XMapRaised(display,windows->pan.id);
14887 windows->image.window_changes.width=(int) display_image->columns;
14888 windows->image.window_changes.height=(int) display_image->rows;
14889 (void) XConfigureImage(display,resource_info,windows,display_image);
14890 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14891 (void) XSync(display,MagickFalse);
14895 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14896 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14898 if (resource_info->update != MagickFalse)
14904 Determine when file data was last modified.
14906 status=GetPathAttributes(display_image->filename,&attributes);
14907 if (status != MagickFalse)
14908 update_time=attributes.st_mtime;
14910 *state&=(~FormerImageState);
14911 *state&=(~MontageImageState);
14912 *state&=(~NextImageState);
14916 Handle a window event.
14918 if (windows->image.mapped != MagickFalse)
14919 if ((display_image->delay != 0) || (resource_info->update != 0))
14921 if (timer < time((time_t *) NULL))
14923 if (resource_info->update == MagickFalse)
14924 *state|=NextImageState | ExitState;
14931 Determine if image file was modified.
14933 status=GetPathAttributes(display_image->filename,&attributes);
14934 if (status != MagickFalse)
14935 if (update_time != attributes.st_mtime)
14940 (void) FormatMagickString(
14941 resource_info->image_info->filename,MaxTextExtent,
14942 "%s:%s",display_image->magick,
14943 display_image->filename);
14944 nexus=ReadImage(resource_info->image_info,
14945 &display_image->exception);
14946 if (nexus != (Image *) NULL)
14948 nexus=DestroyImage(nexus);
14949 *state|=NextImageState | ExitState;
14952 delay=display_image->delay/MagickMax(
14953 display_image->ticks_per_second,1L);
14954 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14957 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14960 Do not block if delay > 0.
14962 XDelay(display,SuspendTime << 2);
14966 timestamp=time((time_t *) NULL);
14967 (void) XNextEvent(display,&event);
14968 if (windows->image.stasis == MagickFalse)
14969 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14970 MagickTrue : MagickFalse;
14971 if (windows->magnify.stasis == MagickFalse)
14972 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14973 MagickTrue : MagickFalse;
14974 if (event.xany.window == windows->command.id)
14977 Select a command from the Command widget.
14979 id=XCommandWidget(display,windows,CommandMenu,&event);
14982 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
14983 command_type=CommandMenus[id];
14984 if (id < MagickMenus)
14987 Select a command from a pop-up menu.
14989 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
14993 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
14994 command_type=Commands[id][entry];
14996 if (command_type != NullCommand)
14997 nexus=XMagickCommand(display,resource_info,windows,command_type,
15001 switch (event.type)
15005 if (display_image->debug != MagickFalse)
15006 (void) LogMagickEvent(X11Event,GetMagickModule(),
15007 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15008 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15009 if ((event.xbutton.button == Button3) &&
15010 (event.xbutton.state & Mod1Mask))
15013 Convert Alt-Button3 to Button2.
15015 event.xbutton.button=Button2;
15016 event.xbutton.state&=(~Mod1Mask);
15018 if (event.xbutton.window == windows->backdrop.id)
15020 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15021 event.xbutton.time);
15024 if (event.xbutton.window == windows->image.id)
15026 switch (event.xbutton.button)
15030 if (resource_info->immutable)
15033 Select a command from the Virtual menu.
15035 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15038 nexus=XMagickCommand(display,resource_info,windows,
15039 VirtualCommands[entry],&display_image);
15043 Map/unmap Command widget.
15045 if (windows->command.mapped != MagickFalse)
15046 (void) XWithdrawWindow(display,windows->command.id,
15047 windows->command.screen);
15050 (void) XCommandWidget(display,windows,CommandMenu,
15052 (void) XMapRaised(display,windows->command.id);
15059 User pressed the image magnify button.
15061 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15063 XMagnifyImage(display,windows,&event);
15068 if (resource_info->immutable)
15071 Select a command from the Virtual menu.
15073 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15076 nexus=XMagickCommand(display,resource_info,windows,
15077 VirtualCommands[entry],&display_image);
15080 if (display_image->montage != (char *) NULL)
15083 Open or delete a tile from a visual image directory.
15085 nexus=XTileImage(display,resource_info,windows,
15086 display_image,&event);
15087 if (nexus != (Image *) NULL)
15088 *state|=MontageImageState | NextImageState | ExitState;
15089 vid_info.x=(short int) windows->image.x;
15090 vid_info.y=(short int) windows->image.y;
15094 Select a command from the Short Cuts menu.
15096 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15099 nexus=XMagickCommand(display,resource_info,windows,
15100 ShortCutsCommands[entry],&display_image);
15108 XTranslateImage(display,windows,*image,XK_Up);
15116 XTranslateImage(display,windows,*image,XK_Down);
15124 if (event.xbutton.window == windows->magnify.id)
15144 MagnifyCommands[] =
15157 Select a magnify factor from the pop-up menu.
15159 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15161 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15164 if (event.xbutton.window == windows->pan.id)
15166 switch (event.xbutton.button)
15173 XTranslateImage(display,windows,*image,XK_Up);
15181 XTranslateImage(display,windows,*image,XK_Down);
15186 XPanImage(display,windows,&event);
15192 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15194 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15197 case ButtonRelease:
15199 if (display_image->debug != MagickFalse)
15200 (void) LogMagickEvent(X11Event,GetMagickModule(),
15201 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15202 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15205 case ClientMessage:
15207 if (display_image->debug != MagickFalse)
15208 (void) LogMagickEvent(X11Event,GetMagickModule(),
15209 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15210 event.xclient.message_type,event.xclient.format,(unsigned long)
15211 event.xclient.data.l[0]);
15212 if (event.xclient.message_type == windows->im_protocols)
15214 if (*event.xclient.data.l == (long) windows->im_update_widget)
15216 (void) CloneString(&windows->command.name,MagickTitle);
15217 windows->command.data=MagickMenus;
15218 (void) XCommandWidget(display,windows,CommandMenu,
15222 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15225 Update graphic context and window colormap.
15227 for (i=0; i < (int) number_windows; i++)
15229 if (magick_windows[i]->id == windows->icon.id)
15231 context_values.background=pixel->background_color.pixel;
15232 context_values.foreground=pixel->foreground_color.pixel;
15233 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15234 context_mask,&context_values);
15235 (void) XChangeGC(display,magick_windows[i]->widget_context,
15236 context_mask,&context_values);
15237 context_values.background=pixel->foreground_color.pixel;
15238 context_values.foreground=pixel->background_color.pixel;
15239 context_values.plane_mask=context_values.background ^
15240 context_values.foreground;
15241 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15242 (size_t) (context_mask | GCPlaneMask),
15244 magick_windows[i]->attributes.background_pixel=
15245 pixel->background_color.pixel;
15246 magick_windows[i]->attributes.border_pixel=
15247 pixel->border_color.pixel;
15248 magick_windows[i]->attributes.colormap=map_info->colormap;
15249 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15250 (unsigned long) magick_windows[i]->mask,
15251 &magick_windows[i]->attributes);
15253 if (windows->pan.mapped != MagickFalse)
15255 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15256 windows->pan.pixmap);
15257 (void) XClearWindow(display,windows->pan.id);
15258 XDrawPanRectangle(display,windows);
15260 if (windows->backdrop.id != (Window) NULL)
15261 (void) XInstallColormap(display,map_info->colormap);
15264 if (*event.xclient.data.l == (long) windows->im_former_image)
15266 *state|=FormerImageState | ExitState;
15269 if (*event.xclient.data.l == (long) windows->im_next_image)
15271 *state|=NextImageState | ExitState;
15274 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15276 *state|=RetainColorsState;
15279 if (*event.xclient.data.l == (long) windows->im_exit)
15286 if (event.xclient.message_type == windows->dnd_protocols)
15304 Display image named by the Drag-and-Drop selection.
15306 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15308 selection=XInternAtom(display,"DndSelection",MagickFalse);
15309 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15310 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15311 &length,&after,&data);
15312 if ((status != Success) || (length == 0))
15314 if (*event.xclient.data.l == 2)
15319 (void) CopyMagickString(resource_info->image_info->filename,
15320 (char *) data,MaxTextExtent);
15327 if (strncmp((char *) data, "file:", 5) != 0)
15329 (void) XFree((void *) data);
15332 (void) CopyMagickString(resource_info->image_info->filename,
15333 ((char *) data)+5,MaxTextExtent);
15335 nexus=ReadImage(resource_info->image_info,
15336 &display_image->exception);
15337 CatchException(&display_image->exception);
15338 if (nexus != (Image *) NULL)
15339 *state|=NextImageState | ExitState;
15340 (void) XFree((void *) data);
15344 If client window delete message, exit.
15346 if (event.xclient.message_type != windows->wm_protocols)
15348 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15350 (void) XWithdrawWindow(display,event.xclient.window,
15351 visual_info->screen);
15352 if (event.xclient.window == windows->image.id)
15357 if (event.xclient.window == windows->pan.id)
15360 Restore original image size when pan window is deleted.
15362 windows->image.window_changes.width=windows->image.ximage->width;
15363 windows->image.window_changes.height=windows->image.ximage->height;
15364 (void) XConfigureImage(display,resource_info,windows,
15369 case ConfigureNotify:
15371 if (display_image->debug != MagickFalse)
15372 (void) LogMagickEvent(X11Event,GetMagickModule(),
15373 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15374 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15375 event.xconfigure.y,event.xconfigure.send_event);
15376 if (event.xconfigure.window == windows->image.id)
15379 Image window has a new configuration.
15381 if (event.xconfigure.send_event != 0)
15387 Position the transient windows relative of the Image window.
15389 if (windows->command.geometry == (char *) NULL)
15390 if (windows->command.mapped == MagickFalse)
15392 windows->command.x=event.xconfigure.x-
15393 windows->command.width-25;
15394 windows->command.y=event.xconfigure.y;
15395 XConstrainWindowPosition(display,&windows->command);
15396 window_changes.x=windows->command.x;
15397 window_changes.y=windows->command.y;
15398 (void) XReconfigureWMWindow(display,windows->command.id,
15399 windows->command.screen,(unsigned int) (CWX | CWY),
15402 if (windows->widget.geometry == (char *) NULL)
15403 if (windows->widget.mapped == MagickFalse)
15405 windows->widget.x=event.xconfigure.x+
15406 event.xconfigure.width/10;
15407 windows->widget.y=event.xconfigure.y+
15408 event.xconfigure.height/10;
15409 XConstrainWindowPosition(display,&windows->widget);
15410 window_changes.x=windows->widget.x;
15411 window_changes.y=windows->widget.y;
15412 (void) XReconfigureWMWindow(display,windows->widget.id,
15413 windows->widget.screen,(unsigned int) (CWX | CWY),
15416 if (windows->magnify.geometry == (char *) NULL)
15417 if (windows->magnify.mapped == MagickFalse)
15419 windows->magnify.x=event.xconfigure.x+
15420 event.xconfigure.width+25;
15421 windows->magnify.y=event.xconfigure.y;
15422 XConstrainWindowPosition(display,&windows->magnify);
15423 window_changes.x=windows->magnify.x;
15424 window_changes.y=windows->magnify.y;
15425 (void) XReconfigureWMWindow(display,windows->magnify.id,
15426 windows->magnify.screen,(unsigned int) (CWX | CWY),
15429 if (windows->pan.geometry == (char *) NULL)
15430 if (windows->pan.mapped == MagickFalse)
15432 windows->pan.x=event.xconfigure.x+
15433 event.xconfigure.width+25;
15434 windows->pan.y=event.xconfigure.y+
15435 windows->magnify.height+50;
15436 XConstrainWindowPosition(display,&windows->pan);
15437 window_changes.x=windows->pan.x;
15438 window_changes.y=windows->pan.y;
15439 (void) XReconfigureWMWindow(display,windows->pan.id,
15440 windows->pan.screen,(unsigned int) (CWX | CWY),
15444 if ((event.xconfigure.width == (int) windows->image.width) &&
15445 (event.xconfigure.height == (int) windows->image.height))
15447 windows->image.width=(unsigned int) event.xconfigure.width;
15448 windows->image.height=(unsigned int) event.xconfigure.height;
15449 windows->image.x=0;
15450 windows->image.y=0;
15451 if (display_image->montage != (char *) NULL)
15453 windows->image.x=vid_info.x;
15454 windows->image.y=vid_info.y;
15456 if ((windows->image.mapped != MagickFalse) &&
15457 (windows->image.stasis != MagickFalse))
15460 Update image window configuration.
15462 windows->image.window_changes.width=event.xconfigure.width;
15463 windows->image.window_changes.height=event.xconfigure.height;
15464 (void) XConfigureImage(display,resource_info,windows,
15468 Update pan window configuration.
15470 if ((event.xconfigure.width < windows->image.ximage->width) ||
15471 (event.xconfigure.height < windows->image.ximage->height))
15473 (void) XMapRaised(display,windows->pan.id);
15474 XDrawPanRectangle(display,windows);
15477 if (windows->pan.mapped != MagickFalse)
15478 (void) XWithdrawWindow(display,windows->pan.id,
15479 windows->pan.screen);
15482 if (event.xconfigure.window == windows->magnify.id)
15488 Magnify window has a new configuration.
15490 windows->magnify.width=(unsigned int) event.xconfigure.width;
15491 windows->magnify.height=(unsigned int) event.xconfigure.height;
15492 if (windows->magnify.mapped == MagickFalse)
15495 while ((int) magnify <= event.xconfigure.width)
15497 while ((int) magnify <= event.xconfigure.height)
15500 if (((int) magnify != event.xconfigure.width) ||
15501 ((int) magnify != event.xconfigure.height))
15503 window_changes.width=(int) magnify;
15504 window_changes.height=(int) magnify;
15505 (void) XReconfigureWMWindow(display,windows->magnify.id,
15506 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15510 if ((windows->magnify.mapped != MagickFalse) &&
15511 (windows->magnify.stasis != MagickFalse))
15513 status=XMakeImage(display,resource_info,&windows->magnify,
15514 display_image,windows->magnify.width,windows->magnify.height);
15515 XMakeMagnifyImage(display,windows);
15519 if ((windows->magnify.mapped != MagickFalse) &&
15520 (event.xconfigure.window == windows->pan.id))
15523 Pan icon window has a new configuration.
15525 if (event.xconfigure.send_event != 0)
15527 windows->pan.x=event.xconfigure.x;
15528 windows->pan.y=event.xconfigure.y;
15530 windows->pan.width=(unsigned int) event.xconfigure.width;
15531 windows->pan.height=(unsigned int) event.xconfigure.height;
15534 if (event.xconfigure.window == windows->icon.id)
15537 Icon window has a new configuration.
15539 windows->icon.width=(unsigned int) event.xconfigure.width;
15540 windows->icon.height=(unsigned int) event.xconfigure.height;
15545 case DestroyNotify:
15548 Group leader has exited.
15550 if (display_image->debug != MagickFalse)
15551 (void) LogMagickEvent(X11Event,GetMagickModule(),
15552 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15553 if (event.xdestroywindow.window == windows->group_leader.id)
15563 Selectively install colormap.
15565 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15566 if (event.xcrossing.mode != NotifyUngrab)
15567 XInstallColormap(display,map_info->colormap);
15572 if (display_image->debug != MagickFalse)
15573 (void) LogMagickEvent(X11Event,GetMagickModule(),
15574 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15575 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15578 Refresh windows that are now exposed.
15580 if ((event.xexpose.window == windows->image.id) &&
15581 (windows->image.mapped != MagickFalse))
15583 XRefreshWindow(display,&windows->image,&event);
15584 delay=display_image->delay/MagickMax(
15585 display_image->ticks_per_second,1L);
15586 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15589 if ((event.xexpose.window == windows->magnify.id) &&
15590 (windows->magnify.mapped != MagickFalse))
15592 XMakeMagnifyImage(display,windows);
15595 if (event.xexpose.window == windows->pan.id)
15597 XDrawPanRectangle(display,windows);
15600 if (event.xexpose.window == windows->icon.id)
15602 XRefreshWindow(display,&windows->icon,&event);
15613 Respond to a user key press.
15615 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15616 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15617 *(command+length)='\0';
15618 if (display_image->debug != MagickFalse)
15619 (void) LogMagickEvent(X11Event,GetMagickModule(),
15620 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15621 key_symbol,command);
15622 if (event.xkey.window == windows->image.id)
15624 command_type=XImageWindowCommand(display,resource_info,windows,
15625 event.xkey.state,key_symbol,&display_image);
15626 if (command_type != NullCommand)
15627 nexus=XMagickCommand(display,resource_info,windows,command_type,
15630 if (event.xkey.window == windows->magnify.id)
15631 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15632 if (event.xkey.window == windows->pan.id)
15634 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15635 (void) XWithdrawWindow(display,windows->pan.id,
15636 windows->pan.screen);
15638 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15639 XTextViewWidget(display,resource_info,windows,MagickFalse,
15640 "Help Viewer - Image Pan",ImagePanHelp);
15642 XTranslateImage(display,windows,*image,key_symbol);
15644 delay=display_image->delay/MagickMax(
15645 display_image->ticks_per_second,1L);
15646 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15652 Respond to a user key release.
15654 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15655 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15656 if (display_image->debug != MagickFalse)
15657 (void) LogMagickEvent(X11Event,GetMagickModule(),
15658 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15664 Selectively uninstall colormap.
15666 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15667 if (event.xcrossing.mode != NotifyUngrab)
15668 XUninstallColormap(display,map_info->colormap);
15673 if (display_image->debug != MagickFalse)
15674 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15675 event.xmap.window);
15676 if (event.xmap.window == windows->backdrop.id)
15678 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15680 windows->backdrop.mapped=MagickTrue;
15683 if (event.xmap.window == windows->image.id)
15685 if (windows->backdrop.id != (Window) NULL)
15686 (void) XInstallColormap(display,map_info->colormap);
15687 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15689 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15690 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15692 if (((int) windows->image.width < windows->image.ximage->width) ||
15693 ((int) windows->image.height < windows->image.ximage->height))
15694 (void) XMapRaised(display,windows->pan.id);
15695 windows->image.mapped=MagickTrue;
15698 if (event.xmap.window == windows->magnify.id)
15700 XMakeMagnifyImage(display,windows);
15701 windows->magnify.mapped=MagickTrue;
15702 (void) XWithdrawWindow(display,windows->info.id,
15703 windows->info.screen);
15706 if (event.xmap.window == windows->pan.id)
15708 XMakePanImage(display,resource_info,windows,display_image);
15709 windows->pan.mapped=MagickTrue;
15712 if (event.xmap.window == windows->info.id)
15714 windows->info.mapped=MagickTrue;
15717 if (event.xmap.window == windows->icon.id)
15723 Create an icon image.
15725 taint=display_image->taint;
15726 XMakeStandardColormap(display,icon_visual,icon_resources,
15727 display_image,icon_map,icon_pixel);
15728 (void) XMakeImage(display,icon_resources,&windows->icon,
15729 display_image,windows->icon.width,windows->icon.height);
15730 display_image->taint=taint;
15731 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15732 windows->icon.pixmap);
15733 (void) XClearWindow(display,windows->icon.id);
15734 (void) XWithdrawWindow(display,windows->info.id,
15735 windows->info.screen);
15736 windows->icon.mapped=MagickTrue;
15739 if (event.xmap.window == windows->command.id)
15741 windows->command.mapped=MagickTrue;
15744 if (event.xmap.window == windows->popup.id)
15746 windows->popup.mapped=MagickTrue;
15749 if (event.xmap.window == windows->widget.id)
15751 windows->widget.mapped=MagickTrue;
15756 case MappingNotify:
15758 (void) XRefreshKeyboardMapping(&event.xmapping);
15763 case PropertyNotify:
15779 if (display_image->debug != MagickFalse)
15780 (void) LogMagickEvent(X11Event,GetMagickModule(),
15781 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15782 event.xproperty.atom,event.xproperty.state);
15783 if (event.xproperty.atom != windows->im_remote_command)
15786 Display image named by the remote command protocol.
15788 status=XGetWindowProperty(display,event.xproperty.window,
15789 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15790 AnyPropertyType,&type,&format,&length,&after,&data);
15791 if ((status != Success) || (length == 0))
15793 if (LocaleCompare((char *) data,"-quit") == 0)
15795 XClientMessage(display,windows->image.id,windows->im_protocols,
15796 windows->im_exit,CurrentTime);
15797 (void) XFree((void *) data);
15800 (void) CopyMagickString(resource_info->image_info->filename,
15801 (char *) data,MaxTextExtent);
15802 (void) XFree((void *) data);
15803 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15804 CatchException(&display_image->exception);
15805 if (nexus != (Image *) NULL)
15806 *state|=NextImageState | ExitState;
15809 case ReparentNotify:
15811 if (display_image->debug != MagickFalse)
15812 (void) LogMagickEvent(X11Event,GetMagickModule(),
15813 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15814 event.xreparent.window);
15819 if (display_image->debug != MagickFalse)
15820 (void) LogMagickEvent(X11Event,GetMagickModule(),
15821 "Unmap Notify: 0x%lx",event.xunmap.window);
15822 if (event.xunmap.window == windows->backdrop.id)
15824 windows->backdrop.mapped=MagickFalse;
15827 if (event.xunmap.window == windows->image.id)
15829 windows->image.mapped=MagickFalse;
15832 if (event.xunmap.window == windows->magnify.id)
15834 windows->magnify.mapped=MagickFalse;
15837 if (event.xunmap.window == windows->pan.id)
15839 windows->pan.mapped=MagickFalse;
15842 if (event.xunmap.window == windows->info.id)
15844 windows->info.mapped=MagickFalse;
15847 if (event.xunmap.window == windows->icon.id)
15849 if (map_info->colormap == icon_map->colormap)
15850 XConfigureImageColormap(display,resource_info,windows,
15852 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15854 windows->icon.mapped=MagickFalse;
15857 if (event.xunmap.window == windows->command.id)
15859 windows->command.mapped=MagickFalse;
15862 if (event.xunmap.window == windows->popup.id)
15864 if (windows->backdrop.id != (Window) NULL)
15865 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15867 windows->popup.mapped=MagickFalse;
15870 if (event.xunmap.window == windows->widget.id)
15872 if (windows->backdrop.id != (Window) NULL)
15873 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15875 windows->widget.mapped=MagickFalse;
15882 if (display_image->debug != MagickFalse)
15883 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15888 } while (!(*state & ExitState));
15889 if ((*state & ExitState) == 0)
15890 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15893 if (resource_info->confirm_edit != MagickFalse)
15896 Query user if image has changed.
15898 if ((resource_info->immutable == MagickFalse) &&
15899 (display_image->taint != MagickFalse))
15904 status=XConfirmWidget(display,windows,"Your image changed.",
15905 "Do you want to save it");
15907 *state&=(~ExitState);
15910 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15914 if ((windows->visual_info->klass == GrayScale) ||
15915 (windows->visual_info->klass == PseudoColor) ||
15916 (windows->visual_info->klass == DirectColor))
15919 Withdraw pan and Magnify window.
15921 if (windows->info.mapped != MagickFalse)
15922 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15923 if (windows->magnify.mapped != MagickFalse)
15924 (void) XWithdrawWindow(display,windows->magnify.id,
15925 windows->magnify.screen);
15926 if (windows->command.mapped != MagickFalse)
15927 (void) XWithdrawWindow(display,windows->command.id,
15928 windows->command.screen);
15930 if (windows->pan.mapped != MagickFalse)
15931 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15932 if (resource_info->backdrop == MagickFalse)
15933 if (windows->backdrop.mapped)
15935 (void) XWithdrawWindow(display,windows->backdrop.id,
15936 windows->backdrop.screen);
15937 (void) XDestroyWindow(display,windows->backdrop.id);
15938 windows->backdrop.id=(Window) NULL;
15939 (void) XWithdrawWindow(display,windows->image.id,
15940 windows->image.screen);
15941 (void) XDestroyWindow(display,windows->image.id);
15942 windows->image.id=(Window) NULL;
15944 XSetCursorState(display,windows,MagickTrue);
15945 XCheckRefreshWindows(display,windows);
15946 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15947 *state&=(~ExitState);
15948 if (*state & ExitState)
15951 Free Standard Colormap.
15953 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15954 if (resource_info->map_type == (char *) NULL)
15955 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15959 if (resource_info->copy_image != (Image *) NULL)
15961 resource_info->copy_image=DestroyImage(resource_info->copy_image);
15962 resource_info->copy_image=NewImageList();
15964 DestroyXResources();
15966 (void) XSync(display,MagickFalse);
15968 Restore our progress monitor and warning handlers.
15970 (void) SetErrorHandler(warning_handler);
15971 (void) SetWarningHandler(warning_handler);
15973 Change to home directory.
15975 cwd=getcwd(working_directory,MaxTextExtent);
15980 status=chdir(resource_info->home_directory);
15982 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
15983 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
15985 *image=display_image;
15991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15995 + D i s p l a y I m a g e s %
15999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16001 % DisplayImages() displays an image sequence to any X window screen. It
16002 % returns a value other than 0 if successful. Check the exception member
16003 % of image to determine the reason for any failure.
16005 % The format of the DisplayImages method is:
16007 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16010 % A description of each parameter follows:
16012 % o image_info: the image info.
16014 % o image: the image.
16017 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16020 assert(image_info != (const ImageInfo *) NULL);
16021 assert(image_info->signature == MagickSignature);
16022 assert(image != (Image *) NULL);
16023 assert(image->signature == MagickSignature);
16024 if (image->debug != MagickFalse)
16025 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16026 (void) ThrowMagickException(&image->exception,GetMagickModule(),
16027 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
16029 return(MagickFalse);
16033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16037 + R e m o t e D i s p l a y C o m m a n d %
16041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16043 % RemoteDisplayCommand() encourages a remote display program to display the
16044 % specified image filename.
16046 % The format of the RemoteDisplayCommand method is:
16048 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16049 % const char *window,const char *filename,ExceptionInfo *exception)
16051 % A description of each parameter follows:
16053 % o image_info: the image info.
16055 % o window: Specifies the name or id of an X window.
16057 % o filename: the name of the image filename to display.
16059 % o exception: return any errors or warnings in this structure.
16062 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16063 const char *window,const char *filename,ExceptionInfo *exception)
16065 assert(image_info != (const ImageInfo *) NULL);
16066 assert(image_info->signature == MagickSignature);
16067 assert(filename != (char *) NULL);
16069 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16070 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16071 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16072 return(MagickFalse);