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-2011 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) FormatLocaleString(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=LocaleToDouble(RotateMenu[entry],(char **) NULL);
2111 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2115 degrees=LocaleToDouble(angle,(char **) NULL);
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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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 **) GetCommandOptions(MagickMethodOptions);
3389 if (methods == (char **) NULL)
3391 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3392 (const char **) methods,command);
3394 method=(PaintMethod) ParseCommandOption(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) FormatLocaleString(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=GetCommandOptions(MagickComposeOptions);
4019 if (operators == (char **) NULL)
4021 entry=XMenuWidget(display,windows,CompositeMenu[id],
4022 (const char **) operators,command);
4024 compose=(CompositeOperator) ParseCommandOption(
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=LocaleToDouble(factor,(char **) NULL);
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) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
4424 resource_info->image_geometry);
4426 (void) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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 may transform the image and return a new
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 image_geometry[MaxTextExtent];
6420 Undo the last image transformation.
6422 if (undo_image == (Image *) NULL)
6424 (void) XBell(display,0);
6427 cache_image=undo_image;
6428 undo_image=GetPreviousImageInList(undo_image);
6429 windows->image.window_changes.width=(int) cache_image->columns;
6430 windows->image.window_changes.height=(int) cache_image->rows;
6431 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
6432 windows->image.ximage->width,windows->image.ximage->height);
6433 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
6434 if (windows->image.crop_geometry != (char *) NULL)
6435 windows->image.crop_geometry=(char *)
6436 RelinquishMagickMemory(windows->image.crop_geometry);
6437 windows->image.crop_geometry=cache_image->geometry;
6438 if (redo_image != (Image *) NULL)
6439 redo_image=DestroyImage(redo_image);
6440 redo_image=(*image);
6441 *image=cache_image->list;
6442 cache_image=DestroyImage(cache_image);
6443 if (windows->image.orphan != MagickFalse)
6445 XConfigureImageColormap(display,resource_info,windows,*image);
6446 (void) XConfigureImage(display,resource_info,windows,*image);
6452 case HalfSizeCommand:
6453 case OriginalSizeCommand:
6454 case DoubleSizeCommand:
6461 case RotateRightCommand:
6462 case RotateLeftCommand:
6467 case ContrastStretchCommand:
6468 case SigmoidalContrastCommand:
6469 case NormalizeCommand:
6470 case EqualizeCommand:
6472 case SaturationCommand:
6473 case BrightnessCommand:
6477 case GrayscaleCommand:
6479 case QuantizeCommand:
6480 case DespeckleCommand:
6482 case ReduceNoiseCommand:
6483 case AddNoiseCommand:
6484 case SharpenCommand:
6486 case ThresholdCommand:
6487 case EdgeDetectCommand:
6491 case SegmentCommand:
6492 case SolarizeCommand:
6493 case SepiaToneCommand:
6495 case ImplodeCommand:
6496 case VignetteCommand:
6498 case OilPaintCommand:
6499 case CharcoalDrawCommand:
6500 case AnnotateCommand:
6501 case AddBorderCommand:
6502 case AddFrameCommand:
6503 case CompositeCommand:
6504 case CommentCommand:
6506 case RegionofInterestCommand:
6507 case SaveToUndoBufferCommand:
6516 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6517 if (undo_image != (Image *) NULL)
6520 Ensure the undo cache has enough memory available.
6522 previous_image=undo_image;
6523 while (previous_image != (Image *) NULL)
6525 bytes+=previous_image->list->columns*previous_image->list->rows*
6526 sizeof(PixelPacket);
6527 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6529 previous_image=GetPreviousImageInList(previous_image);
6532 bytes-=previous_image->list->columns*previous_image->list->rows*
6533 sizeof(PixelPacket);
6534 if (previous_image == undo_image)
6535 undo_image=NewImageList();
6537 previous_image->next->previous=NewImageList();
6540 while (previous_image != (Image *) NULL)
6543 Delete any excess memory from undo cache.
6545 cache_image=previous_image;
6546 previous_image=GetPreviousImageInList(previous_image);
6547 cache_image->list=DestroyImage(cache_image->list);
6548 cache_image=DestroyImage(cache_image);
6551 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6554 Save image before transformations are applied.
6556 cache_image=AcquireImage((ImageInfo *) NULL);
6557 if (cache_image == (Image *) NULL)
6559 XSetCursorState(display,windows,MagickTrue);
6560 XCheckRefreshWindows(display,windows);
6561 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6562 XSetCursorState(display,windows,MagickFalse);
6563 if (cache_image->list == (Image *) NULL)
6565 cache_image=DestroyImage(cache_image);
6568 cache_image->columns=(size_t) windows->image.ximage->width;
6569 cache_image->rows=(size_t) windows->image.ximage->height;
6570 cache_image->geometry=windows->image.crop_geometry;
6571 if (windows->image.crop_geometry != (char *) NULL)
6573 cache_image->geometry=AcquireString((char *) NULL);
6574 (void) CopyMagickString(cache_image->geometry,
6575 windows->image.crop_geometry,MaxTextExtent);
6577 if (undo_image == (Image *) NULL)
6579 undo_image=cache_image;
6582 undo_image->next=cache_image;
6583 undo_image->next->previous=undo_image;
6584 undo_image=undo_image->next;
6590 if (command == RedoCommand)
6593 Redo the last image transformation.
6595 if (redo_image == (Image *) NULL)
6597 (void) XBell(display,0);
6600 windows->image.window_changes.width=(int) redo_image->columns;
6601 windows->image.window_changes.height=(int) redo_image->rows;
6602 if (windows->image.crop_geometry != (char *) NULL)
6603 windows->image.crop_geometry=(char *)
6604 RelinquishMagickMemory(windows->image.crop_geometry);
6605 windows->image.crop_geometry=redo_image->geometry;
6606 *image=DestroyImage(*image);
6608 redo_image=NewImageList();
6609 if (windows->image.orphan != MagickFalse)
6611 XConfigureImageColormap(display,resource_info,windows,*image);
6612 (void) XConfigureImage(display,resource_info,windows,*image);
6615 if (command != InfoCommand)
6620 XSetCursorState(display,windows,MagickTrue);
6621 XCheckRefreshWindows(display,windows);
6622 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6623 XSetCursorState(display,windows,MagickFalse);
6627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6631 + X I m a g e W i n d o w C o m m a n d %
6635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6637 % XImageWindowCommand() makes a transform to the image or Image window as
6638 % specified by a user menu button or keyboard command.
6640 % The format of the XMagickCommand method is:
6642 % CommandType XImageWindowCommand(Display *display,
6643 % XResourceInfo *resource_info,XWindows *windows,
6644 % const MagickStatusType state,KeySym key_symbol,Image **image)
6646 % A description of each parameter follows:
6648 % o nexus: Method XImageWindowCommand returns an image when the
6649 % user chooses 'Open Image' from the command menu. Otherwise a null
6650 % image is returned.
6652 % o display: Specifies a connection to an X server; returned from
6655 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6657 % o windows: Specifies a pointer to a XWindows structure.
6659 % o state: key mask.
6661 % o key_symbol: Specifies a command to perform.
6663 % o image: the image; XImageWIndowCommand
6664 % may transform the image and return a new image pointer.
6667 static CommandType XImageWindowCommand(Display *display,
6668 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6669 KeySym key_symbol,Image **image)
6672 delta[MaxTextExtent] = "";
6675 Digits[] = "01234567890";
6680 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6682 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6685 resource_info->quantum=1;
6687 last_symbol=key_symbol;
6688 delta[strlen(delta)+1]='\0';
6689 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6690 resource_info->quantum=StringToLong(delta);
6691 return(NullCommand);
6693 last_symbol=key_symbol;
6694 if (resource_info->immutable)
6697 Virtual image window has a restricted command set.
6702 return(InfoCommand);
6705 return(PrintCommand);
6707 return(NextCommand);
6710 return(QuitCommand);
6714 return(NullCommand);
6716 switch ((int) key_symbol)
6720 if ((state & ControlMask) == 0)
6722 return(OpenCommand);
6725 return(NextCommand);
6727 return(FormerCommand);
6730 if ((state & Mod1Mask) != 0)
6731 return(SwirlCommand);
6732 if ((state & ControlMask) == 0)
6733 return(ShearCommand);
6734 return(SaveCommand);
6739 if ((state & Mod1Mask) != 0)
6740 return(OilPaintCommand);
6741 if ((state & Mod4Mask) != 0)
6742 return(ColorCommand);
6743 if ((state & ControlMask) == 0)
6744 return(NullCommand);
6745 return(PrintCommand);
6749 if ((state & Mod4Mask) != 0)
6750 return(DrawCommand);
6751 if ((state & ControlMask) == 0)
6752 return(NullCommand);
6753 return(DeleteCommand);
6757 if ((state & ControlMask) == 0)
6758 return(NullCommand);
6759 return(SelectCommand);
6763 if ((state & ControlMask) == 0)
6764 return(NullCommand);
6769 return(QuitCommand);
6773 if ((state & ControlMask) == 0)
6774 return(NullCommand);
6775 return(UndoCommand);
6780 if ((state & ControlMask) == 0)
6781 return(RollCommand);
6782 return(RedoCommand);
6786 if ((state & ControlMask) == 0)
6787 return(NullCommand);
6792 if ((state & Mod1Mask) != 0)
6793 return(CharcoalDrawCommand);
6794 if ((state & ControlMask) == 0)
6795 return(CropCommand);
6796 return(CopyCommand);
6801 if ((state & Mod4Mask) != 0)
6802 return(CompositeCommand);
6803 if ((state & ControlMask) == 0)
6804 return(FlipCommand);
6805 return(PasteCommand);
6808 return(HalfSizeCommand);
6810 return(OriginalSizeCommand);
6812 return(DoubleSizeCommand);
6814 return(ResizeCommand);
6816 return(RefreshCommand);
6817 case XK_bracketleft:
6818 return(ChopCommand);
6820 return(FlopCommand);
6822 return(RotateRightCommand);
6824 return(RotateLeftCommand);
6826 return(RotateCommand);
6828 return(TrimCommand);
6832 return(SaturationCommand);
6834 return(BrightnessCommand);
6836 return(GammaCommand);
6838 return(SpiffCommand);
6840 return(DullCommand);
6842 return(NormalizeCommand);
6844 return(EqualizeCommand);
6846 return(NegateCommand);
6848 return(GrayscaleCommand);
6850 return(QuantizeCommand);
6852 return(DespeckleCommand);
6854 return(EmbossCommand);
6856 return(ReduceNoiseCommand);
6858 return(AddNoiseCommand);
6860 return(SharpenCommand);
6862 return(BlurCommand);
6864 return(ThresholdCommand);
6866 return(EdgeDetectCommand);
6868 return(SpreadCommand);
6870 return(ShadeCommand);
6872 return(RaiseCommand);
6874 return(SegmentCommand);
6877 if ((state & Mod1Mask) == 0)
6878 return(NullCommand);
6879 return(ImplodeCommand);
6883 if ((state & Mod1Mask) == 0)
6884 return(NullCommand);
6885 return(WaveCommand);
6889 if ((state & Mod4Mask) == 0)
6890 return(NullCommand);
6891 return(MatteCommand);
6895 if ((state & Mod4Mask) == 0)
6896 return(NullCommand);
6897 return(AddBorderCommand);
6901 if ((state & Mod4Mask) == 0)
6902 return(NullCommand);
6903 return(AddFrameCommand);
6907 if ((state & Mod4Mask) == 0)
6908 return(NullCommand);
6909 return(CommentCommand);
6913 if ((state & Mod1Mask) != 0)
6914 return(ApplyCommand);
6915 if ((state & Mod4Mask) != 0)
6916 return(AnnotateCommand);
6917 if ((state & ControlMask) == 0)
6918 return(NullCommand);
6919 return(RegionofInterestCommand);
6922 return(InfoCommand);
6924 return(ZoomCommand);
6927 if ((state & ShiftMask) == 0)
6928 return(NullCommand);
6929 return(ShowPreviewCommand);
6932 return(LaunchCommand);
6934 return(HelpCommand);
6936 return(BrowseDocumentationCommand);
6939 (void) XMapRaised(display,windows->command.id);
6940 return(NullCommand);
6947 XTranslateImage(display,windows,*image,key_symbol);
6948 return(NullCommand);
6959 if ((state & Mod1Mask) != 0)
6965 Trim one pixel from edge of image.
6969 crop_info.width=(size_t) windows->image.ximage->width;
6970 crop_info.height=(size_t) windows->image.ximage->height;
6971 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6973 if (resource_info->quantum >= (int) crop_info.height)
6974 resource_info->quantum=(int) crop_info.height-1;
6975 crop_info.height-=resource_info->quantum;
6977 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6979 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6980 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6981 crop_info.y+=resource_info->quantum;
6982 crop_info.height-=resource_info->quantum;
6984 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6986 if (resource_info->quantum >= (int) crop_info.width)
6987 resource_info->quantum=(int) crop_info.width-1;
6988 crop_info.width-=resource_info->quantum;
6990 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6992 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6993 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6994 crop_info.x+=resource_info->quantum;
6995 crop_info.width-=resource_info->quantum;
6997 if ((int) (windows->image.x+windows->image.width) >
6998 (int) crop_info.width)
6999 windows->image.x=(int) (crop_info.width-windows->image.width);
7000 if ((int) (windows->image.y+windows->image.height) >
7001 (int) crop_info.height)
7002 windows->image.y=(int) (crop_info.height-windows->image.height);
7003 XSetCropGeometry(display,windows,&crop_info,*image);
7004 windows->image.window_changes.width=(int) crop_info.width;
7005 windows->image.window_changes.height=(int) crop_info.height;
7006 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7007 (void) XConfigureImage(display,resource_info,windows,*image);
7008 return(NullCommand);
7010 XTranslateImage(display,windows,*image,key_symbol);
7011 return(NullCommand);
7014 return(NullCommand);
7016 return(NullCommand);
7020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7024 + X M a g i c k C o m m a n d %
7028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7030 % XMagickCommand() makes a transform to the image or Image window as
7031 % specified by a user menu button or keyboard command.
7033 % The format of the XMagickCommand method is:
7035 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7036 % XWindows *windows,const CommandType command,Image **image)
7038 % A description of each parameter follows:
7040 % o nexus: Method XMagickCommand returns an image when the
7041 % user chooses 'Load Image' from the command menu. Otherwise a null
7042 % image is returned.
7044 % o display: Specifies a connection to an X server; returned from
7047 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7049 % o windows: Specifies a pointer to a XWindows structure.
7051 % o command: Specifies a command to perform.
7053 % o image: the image; XMagickCommand
7054 % may transform the image and return a new image pointer.
7057 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7058 XWindows *windows,const CommandType command,Image **image)
7061 filename[MaxTextExtent],
7062 geometry[MaxTextExtent],
7063 modulate_factors[MaxTextExtent];
7092 color[MaxTextExtent] = "gray";
7099 Process user command.
7101 XCheckRefreshWindows(display,windows);
7102 XImageCache(display,resource_info,windows,command,image);
7103 nexus=NewImageList();
7104 windows->image.window_changes.width=windows->image.ximage->width;
7105 windows->image.window_changes.height=windows->image.ximage->height;
7106 image_info=CloneImageInfo(resource_info->image_info);
7107 SetGeometryInfo(&geometry_info);
7108 GetQuantizeInfo(&quantize_info);
7116 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7124 for (i=0; i < resource_info->quantum; i++)
7125 XClientMessage(display,windows->image.id,windows->im_protocols,
7126 windows->im_next_image,CurrentTime);
7132 Display former image.
7134 for (i=0; i < resource_info->quantum; i++)
7135 XClientMessage(display,windows->image.id,windows->im_protocols,
7136 windows->im_former_image,CurrentTime);
7147 status=chdir(resource_info->home_directory);
7149 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7150 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7151 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7159 status=XSaveImage(display,resource_info,windows,*image);
7160 if (status == MagickFalse)
7162 XNoticeWidget(display,windows,"Unable to write X image:",
7163 (*image)->filename);
7173 status=XPrintImage(display,resource_info,windows,*image);
7174 if (status == MagickFalse)
7176 XNoticeWidget(display,windows,"Unable to print X image:",
7177 (*image)->filename);
7185 filename[MaxTextExtent] = "\0";
7190 XFileBrowserWidget(display,windows,"Delete",filename);
7191 if (*filename == '\0')
7193 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7194 if (status != MagickFalse)
7195 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7204 color[MaxTextExtent] = "gray",
7205 geometry[MaxTextExtent] = "640x480";
7208 *format = "gradient";
7211 Query user for canvas geometry.
7213 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7215 if (*geometry == '\0')
7219 XColorBrowserWidget(display,windows,"Select",color);
7225 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
7226 "%s:%s",format,color);
7227 (void) CloneString(&image_info->size,geometry);
7228 nexus=ReadImage(image_info,&(*image)->exception);
7229 CatchException(&(*image)->exception);
7230 XClientMessage(display,windows->image.id,windows->im_protocols,
7231 windows->im_next_image,CurrentTime);
7234 case VisualDirectoryCommand:
7237 Visual Image directory.
7239 nexus=XVisualDirectoryImage(display,resource_info,windows);
7247 if (resource_info->confirm_exit == MagickFalse)
7248 XClientMessage(display,windows->image.id,windows->im_protocols,
7249 windows->im_exit,CurrentTime);
7256 Confirm program exit.
7258 status=XConfirmWidget(display,windows,"Do you really want to exit",
7259 resource_info->client_name);
7261 XClientMessage(display,windows->image.id,windows->im_protocols,
7262 windows->im_exit,CurrentTime);
7271 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7279 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7287 status=XPasteImage(display,resource_info,windows,*image);
7288 if (status == MagickFalse)
7290 XNoticeWidget(display,windows,"Unable to paste X image",
7291 (*image)->filename);
7296 case HalfSizeCommand:
7301 windows->image.window_changes.width=windows->image.ximage->width/2;
7302 windows->image.window_changes.height=windows->image.ximage->height/2;
7303 (void) XConfigureImage(display,resource_info,windows,*image);
7306 case OriginalSizeCommand:
7309 Original image size.
7311 windows->image.window_changes.width=(int) (*image)->columns;
7312 windows->image.window_changes.height=(int) (*image)->rows;
7313 (void) XConfigureImage(display,resource_info,windows,*image);
7316 case DoubleSizeCommand:
7319 Double the image size.
7321 windows->image.window_changes.width=windows->image.ximage->width << 1;
7322 windows->image.window_changes.height=windows->image.ximage->height << 1;
7323 (void) XConfigureImage(display,resource_info,windows,*image);
7342 width=(size_t) windows->image.ximage->width;
7343 height=(size_t) windows->image.ximage->height;
7346 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7347 (double) width,(double) height);
7348 status=XDialogWidget(display,windows,"Resize",
7349 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7350 if (*geometry == '\0')
7353 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7354 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7355 windows->image.window_changes.width=(int) width;
7356 windows->image.window_changes.height=(int) height;
7357 (void) XConfigureImage(display,resource_info,windows,*image);
7363 image_geometry[MaxTextExtent];
7365 if ((windows->image.crop_geometry == (char *) NULL) &&
7366 ((int) (*image)->columns == windows->image.ximage->width) &&
7367 ((int) (*image)->rows == windows->image.ximage->height))
7370 Apply size transforms to image.
7372 XSetCursorState(display,windows,MagickTrue);
7373 XCheckRefreshWindows(display,windows);
7375 Crop and/or scale displayed image.
7377 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
7378 windows->image.ximage->width,windows->image.ximage->height);
7379 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7380 if (windows->image.crop_geometry != (char *) NULL)
7381 windows->image.crop_geometry=(char *)
7382 RelinquishMagickMemory(windows->image.crop_geometry);
7385 XConfigureImageColormap(display,resource_info,windows,*image);
7386 (void) XConfigureImage(display,resource_info,windows,*image);
7389 case RefreshCommand:
7391 (void) XConfigureImage(display,resource_info,windows,*image);
7394 case RestoreCommand:
7397 Restore Image window to its original size.
7399 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7400 (windows->image.height == (unsigned int) (*image)->rows) &&
7401 (windows->image.crop_geometry == (char *) NULL))
7403 (void) XBell(display,0);
7406 windows->image.window_changes.width=(int) (*image)->columns;
7407 windows->image.window_changes.height=(int) (*image)->rows;
7408 if (windows->image.crop_geometry != (char *) NULL)
7410 windows->image.crop_geometry=(char *)
7411 RelinquishMagickMemory(windows->image.crop_geometry);
7412 windows->image.crop_geometry=(char *) NULL;
7416 XConfigureImageColormap(display,resource_info,windows,*image);
7417 (void) XConfigureImage(display,resource_info,windows,*image);
7425 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7433 status=XChopImage(display,resource_info,windows,image);
7434 if (status == MagickFalse)
7436 XNoticeWidget(display,windows,"Unable to cut X image",
7437 (*image)->filename);
7448 Flop image scanlines.
7450 XSetCursorState(display,windows,MagickTrue);
7451 XCheckRefreshWindows(display,windows);
7452 flop_image=FlopImage(*image,&(*image)->exception);
7453 if (flop_image != (Image *) NULL)
7455 *image=DestroyImage(*image);
7458 CatchException(&(*image)->exception);
7459 XSetCursorState(display,windows,MagickFalse);
7460 if (windows->image.crop_geometry != (char *) NULL)
7465 width=(unsigned int) (*image)->columns;
7466 height=(unsigned int) (*image)->rows;
7467 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7469 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7470 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7472 if (windows->image.orphan != MagickFalse)
7474 (void) XConfigureImage(display,resource_info,windows,*image);
7483 Flip image scanlines.
7485 XSetCursorState(display,windows,MagickTrue);
7486 XCheckRefreshWindows(display,windows);
7487 flip_image=FlipImage(*image,&(*image)->exception);
7488 if (flip_image != (Image *) NULL)
7490 *image=DestroyImage(*image);
7493 CatchException(&(*image)->exception);
7494 XSetCursorState(display,windows,MagickFalse);
7495 if (windows->image.crop_geometry != (char *) NULL)
7500 width=(unsigned int) (*image)->columns;
7501 height=(unsigned int) (*image)->rows;
7502 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7504 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7505 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7507 if (windows->image.orphan != MagickFalse)
7509 (void) XConfigureImage(display,resource_info,windows,*image);
7512 case RotateRightCommand:
7515 Rotate image 90 degrees clockwise.
7517 status=XRotateImage(display,resource_info,windows,90.0,image);
7518 if (status == MagickFalse)
7520 XNoticeWidget(display,windows,"Unable to rotate X image",
7521 (*image)->filename);
7526 case RotateLeftCommand:
7529 Rotate image 90 degrees counter-clockwise.
7531 status=XRotateImage(display,resource_info,windows,-90.0,image);
7532 if (status == MagickFalse)
7534 XNoticeWidget(display,windows,"Unable to rotate X image",
7535 (*image)->filename);
7545 status=XRotateImage(display,resource_info,windows,0.0,image);
7546 if (status == MagickFalse)
7548 XNoticeWidget(display,windows,"Unable to rotate X image",
7549 (*image)->filename);
7560 geometry[MaxTextExtent] = "45.0x45.0";
7563 Query user for shear color and geometry.
7565 XColorBrowserWidget(display,windows,"Select",color);
7568 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7570 if (*geometry == '\0')
7575 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7576 XSetCursorState(display,windows,MagickTrue);
7577 XCheckRefreshWindows(display,windows);
7578 (void) QueryColorDatabase(color,&(*image)->background_color,
7579 &(*image)->exception);
7580 flags=ParseGeometry(geometry,&geometry_info);
7581 if ((flags & SigmaValue) == 0)
7582 geometry_info.sigma=geometry_info.rho;
7583 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7584 &(*image)->exception);
7585 if (shear_image != (Image *) NULL)
7587 *image=DestroyImage(*image);
7590 CatchException(&(*image)->exception);
7591 XSetCursorState(display,windows,MagickFalse);
7592 if (windows->image.orphan != MagickFalse)
7594 windows->image.window_changes.width=(int) (*image)->columns;
7595 windows->image.window_changes.height=(int) (*image)->rows;
7596 XConfigureImageColormap(display,resource_info,windows,*image);
7597 (void) XConfigureImage(display,resource_info,windows,*image);
7606 geometry[MaxTextExtent] = "+2+2";
7609 Query user for the roll geometry.
7611 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7613 if (*geometry == '\0')
7618 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7619 XSetCursorState(display,windows,MagickTrue);
7620 XCheckRefreshWindows(display,windows);
7621 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7622 &(*image)->exception);
7623 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7624 &(*image)->exception);
7625 if (roll_image != (Image *) NULL)
7627 *image=DestroyImage(*image);
7630 CatchException(&(*image)->exception);
7631 XSetCursorState(display,windows,MagickFalse);
7632 if (windows->image.orphan != MagickFalse)
7634 windows->image.window_changes.width=(int) (*image)->columns;
7635 windows->image.window_changes.height=(int) (*image)->rows;
7636 XConfigureImageColormap(display,resource_info,windows,*image);
7637 (void) XConfigureImage(display,resource_info,windows,*image);
7643 fuzz[MaxTextExtent];
7646 Query user for the fuzz factor.
7648 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
7649 (*image)->fuzz/(QuantumRange+1.0));
7650 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7653 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
7657 status=XTrimImage(display,resource_info,windows,*image);
7658 if (status == MagickFalse)
7660 XNoticeWidget(display,windows,"Unable to trim X image",
7661 (*image)->filename);
7669 hue_percent[MaxTextExtent] = "110";
7672 Query user for percent hue change.
7674 (void) XDialogWidget(display,windows,"Apply",
7675 "Enter percent change in image hue (0-200):",hue_percent);
7676 if (*hue_percent == '\0')
7681 XSetCursorState(display,windows,MagickTrue);
7682 XCheckRefreshWindows(display,windows);
7683 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7684 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7686 (void) ModulateImage(*image,modulate_factors);
7687 XSetCursorState(display,windows,MagickFalse);
7688 if (windows->image.orphan != MagickFalse)
7690 XConfigureImageColormap(display,resource_info,windows,*image);
7691 (void) XConfigureImage(display,resource_info,windows,*image);
7694 case SaturationCommand:
7697 saturation_percent[MaxTextExtent] = "110";
7700 Query user for percent saturation change.
7702 (void) XDialogWidget(display,windows,"Apply",
7703 "Enter percent change in color saturation (0-200):",saturation_percent);
7704 if (*saturation_percent == '\0')
7707 Vary color saturation.
7709 XSetCursorState(display,windows,MagickTrue);
7710 XCheckRefreshWindows(display,windows);
7711 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7712 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7714 (void) ModulateImage(*image,modulate_factors);
7715 XSetCursorState(display,windows,MagickFalse);
7716 if (windows->image.orphan != MagickFalse)
7718 XConfigureImageColormap(display,resource_info,windows,*image);
7719 (void) XConfigureImage(display,resource_info,windows,*image);
7722 case BrightnessCommand:
7725 brightness_percent[MaxTextExtent] = "110";
7728 Query user for percent brightness change.
7730 (void) XDialogWidget(display,windows,"Apply",
7731 "Enter percent change in color brightness (0-200):",brightness_percent);
7732 if (*brightness_percent == '\0')
7735 Vary the color brightness.
7737 XSetCursorState(display,windows,MagickTrue);
7738 XCheckRefreshWindows(display,windows);
7739 (void) CopyMagickString(modulate_factors,brightness_percent,
7741 (void) ModulateImage(*image,modulate_factors);
7742 XSetCursorState(display,windows,MagickFalse);
7743 if (windows->image.orphan != MagickFalse)
7745 XConfigureImageColormap(display,resource_info,windows,*image);
7746 (void) XConfigureImage(display,resource_info,windows,*image);
7752 factor[MaxTextExtent] = "1.6";
7755 Query user for gamma value.
7757 (void) XDialogWidget(display,windows,"Gamma",
7758 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7759 if (*factor == '\0')
7762 Gamma correct image.
7764 XSetCursorState(display,windows,MagickTrue);
7765 XCheckRefreshWindows(display,windows);
7766 (void) GammaImage(*image,factor);
7767 XSetCursorState(display,windows,MagickFalse);
7768 if (windows->image.orphan != MagickFalse)
7770 XConfigureImageColormap(display,resource_info,windows,*image);
7771 (void) XConfigureImage(display,resource_info,windows,*image);
7777 Sharpen the image contrast.
7779 XSetCursorState(display,windows,MagickTrue);
7780 XCheckRefreshWindows(display,windows);
7781 (void) ContrastImage(*image,MagickTrue);
7782 XSetCursorState(display,windows,MagickFalse);
7783 if (windows->image.orphan != MagickFalse)
7785 XConfigureImageColormap(display,resource_info,windows,*image);
7786 (void) XConfigureImage(display,resource_info,windows,*image);
7792 Dull the image contrast.
7794 XSetCursorState(display,windows,MagickTrue);
7795 XCheckRefreshWindows(display,windows);
7796 (void) ContrastImage(*image,MagickFalse);
7797 XSetCursorState(display,windows,MagickFalse);
7798 if (windows->image.orphan != MagickFalse)
7800 XConfigureImageColormap(display,resource_info,windows,*image);
7801 (void) XConfigureImage(display,resource_info,windows,*image);
7804 case ContrastStretchCommand:
7811 levels[MaxTextExtent] = "1%";
7814 Query user for gamma value.
7816 (void) XDialogWidget(display,windows,"Contrast Stretch",
7817 "Enter black and white points:",levels);
7818 if (*levels == '\0')
7821 Contrast stretch image.
7823 XSetCursorState(display,windows,MagickTrue);
7824 XCheckRefreshWindows(display,windows);
7825 flags=ParseGeometry(levels,&geometry_info);
7826 black_point=geometry_info.rho;
7827 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7828 if ((flags & PercentValue) != 0)
7830 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7831 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7833 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7834 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7836 XSetCursorState(display,windows,MagickFalse);
7837 if (windows->image.orphan != MagickFalse)
7839 XConfigureImageColormap(display,resource_info,windows,*image);
7840 (void) XConfigureImage(display,resource_info,windows,*image);
7843 case SigmoidalContrastCommand:
7846 levels[MaxTextExtent] = "3x50%";
7849 Query user for gamma value.
7851 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7852 "Enter contrast and midpoint:",levels);
7853 if (*levels == '\0')
7856 Contrast stretch image.
7858 XSetCursorState(display,windows,MagickTrue);
7859 XCheckRefreshWindows(display,windows);
7860 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
7861 XSetCursorState(display,windows,MagickFalse);
7862 if (windows->image.orphan != MagickFalse)
7864 XConfigureImageColormap(display,resource_info,windows,*image);
7865 (void) XConfigureImage(display,resource_info,windows,*image);
7868 case NormalizeCommand:
7871 Perform histogram normalization on the image.
7873 XSetCursorState(display,windows,MagickTrue);
7874 XCheckRefreshWindows(display,windows);
7875 (void) NormalizeImage(*image);
7876 XSetCursorState(display,windows,MagickFalse);
7877 if (windows->image.orphan != MagickFalse)
7879 XConfigureImageColormap(display,resource_info,windows,*image);
7880 (void) XConfigureImage(display,resource_info,windows,*image);
7883 case EqualizeCommand:
7886 Perform histogram equalization on the image.
7888 XSetCursorState(display,windows,MagickTrue);
7889 XCheckRefreshWindows(display,windows);
7890 (void) EqualizeImage(*image);
7891 XSetCursorState(display,windows,MagickFalse);
7892 if (windows->image.orphan != MagickFalse)
7894 XConfigureImageColormap(display,resource_info,windows,*image);
7895 (void) XConfigureImage(display,resource_info,windows,*image);
7901 Negate colors in image.
7903 XSetCursorState(display,windows,MagickTrue);
7904 XCheckRefreshWindows(display,windows);
7905 (void) NegateImage(*image,MagickFalse);
7906 XSetCursorState(display,windows,MagickFalse);
7907 if (windows->image.orphan != MagickFalse)
7909 XConfigureImageColormap(display,resource_info,windows,*image);
7910 (void) XConfigureImage(display,resource_info,windows,*image);
7913 case GrayscaleCommand:
7916 Convert image to grayscale.
7918 XSetCursorState(display,windows,MagickTrue);
7919 XCheckRefreshWindows(display,windows);
7920 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7921 GrayscaleType : GrayscaleMatteType);
7922 XSetCursorState(display,windows,MagickFalse);
7923 if (windows->image.orphan != MagickFalse)
7925 XConfigureImageColormap(display,resource_info,windows,*image);
7926 (void) XConfigureImage(display,resource_info,windows,*image);
7935 filename[MaxTextExtent] = "\0";
7938 Request image file name from user.
7940 XFileBrowserWidget(display,windows,"Map",filename);
7941 if (*filename == '\0')
7946 XSetCursorState(display,windows,MagickTrue);
7947 XCheckRefreshWindows(display,windows);
7948 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7949 affinity_image=ReadImage(image_info,&(*image)->exception);
7950 if (affinity_image != (Image *) NULL)
7952 (void) RemapImage(&quantize_info,*image,affinity_image);
7953 affinity_image=DestroyImage(affinity_image);
7955 CatchException(&(*image)->exception);
7956 XSetCursorState(display,windows,MagickFalse);
7957 if (windows->image.orphan != MagickFalse)
7959 XConfigureImageColormap(display,resource_info,windows,*image);
7960 (void) XConfigureImage(display,resource_info,windows,*image);
7963 case QuantizeCommand:
7969 colors[MaxTextExtent] = "256";
7972 Query user for maximum number of colors.
7974 status=XDialogWidget(display,windows,"Quantize",
7975 "Maximum number of colors:",colors);
7976 if (*colors == '\0')
7979 Color reduce the image.
7981 XSetCursorState(display,windows,MagickTrue);
7982 XCheckRefreshWindows(display,windows);
7983 quantize_info.number_colors=StringToUnsignedLong(colors);
7984 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7985 (void) QuantizeImage(&quantize_info,*image);
7986 XSetCursorState(display,windows,MagickFalse);
7987 if (windows->image.orphan != MagickFalse)
7989 XConfigureImageColormap(display,resource_info,windows,*image);
7990 (void) XConfigureImage(display,resource_info,windows,*image);
7993 case DespeckleCommand:
8001 XSetCursorState(display,windows,MagickTrue);
8002 XCheckRefreshWindows(display,windows);
8003 despeckle_image=DespeckleImage(*image,&(*image)->exception);
8004 if (despeckle_image != (Image *) NULL)
8006 *image=DestroyImage(*image);
8007 *image=despeckle_image;
8009 CatchException(&(*image)->exception);
8010 XSetCursorState(display,windows,MagickFalse);
8011 if (windows->image.orphan != MagickFalse)
8013 XConfigureImageColormap(display,resource_info,windows,*image);
8014 (void) XConfigureImage(display,resource_info,windows,*image);
8023 radius[MaxTextExtent] = "0.0x1.0";
8026 Query user for emboss radius.
8028 (void) XDialogWidget(display,windows,"Emboss",
8029 "Enter the emboss radius and standard deviation:",radius);
8030 if (*radius == '\0')
8033 Reduce noise in the image.
8035 XSetCursorState(display,windows,MagickTrue);
8036 XCheckRefreshWindows(display,windows);
8037 flags=ParseGeometry(radius,&geometry_info);
8038 if ((flags & SigmaValue) == 0)
8039 geometry_info.sigma=1.0;
8040 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8041 &(*image)->exception);
8042 if (emboss_image != (Image *) NULL)
8044 *image=DestroyImage(*image);
8045 *image=emboss_image;
8047 CatchException(&(*image)->exception);
8048 XSetCursorState(display,windows,MagickFalse);
8049 if (windows->image.orphan != MagickFalse)
8051 XConfigureImageColormap(display,resource_info,windows,*image);
8052 (void) XConfigureImage(display,resource_info,windows,*image);
8055 case ReduceNoiseCommand:
8061 radius[MaxTextExtent] = "0";
8064 Query user for noise radius.
8066 (void) XDialogWidget(display,windows,"Reduce Noise",
8067 "Enter the noise radius:",radius);
8068 if (*radius == '\0')
8071 Reduce noise in the image.
8073 XSetCursorState(display,windows,MagickTrue);
8074 XCheckRefreshWindows(display,windows);
8075 flags=ParseGeometry(radius,&geometry_info);
8076 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8077 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
8078 if (noise_image != (Image *) NULL)
8080 *image=DestroyImage(*image);
8083 CatchException(&(*image)->exception);
8084 XSetCursorState(display,windows,MagickFalse);
8085 if (windows->image.orphan != MagickFalse)
8087 XConfigureImageColormap(display,resource_info,windows,*image);
8088 (void) XConfigureImage(display,resource_info,windows,*image);
8091 case AddNoiseCommand:
8100 noise_type[MaxTextExtent] = "Gaussian";
8103 Add noise to the image.
8105 noises=GetCommandOptions(MagickNoiseOptions);
8106 if (noises == (char **) NULL)
8108 XListBrowserWidget(display,windows,&windows->widget,
8109 (const char **) noises,"Add Noise",
8110 "Select a type of noise to add to your image:",noise_type);
8111 noises=DestroyStringList(noises);
8112 if (*noise_type == '\0')
8114 XSetCursorState(display,windows,MagickTrue);
8115 XCheckRefreshWindows(display,windows);
8116 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8117 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8118 if (noise_image != (Image *) NULL)
8120 *image=DestroyImage(*image);
8123 CatchException(&(*image)->exception);
8124 XSetCursorState(display,windows,MagickFalse);
8125 if (windows->image.orphan != MagickFalse)
8127 XConfigureImageColormap(display,resource_info,windows,*image);
8128 (void) XConfigureImage(display,resource_info,windows,*image);
8131 case SharpenCommand:
8137 radius[MaxTextExtent] = "0.0x1.0";
8140 Query user for sharpen radius.
8142 (void) XDialogWidget(display,windows,"Sharpen",
8143 "Enter the sharpen radius and standard deviation:",radius);
8144 if (*radius == '\0')
8147 Sharpen image scanlines.
8149 XSetCursorState(display,windows,MagickTrue);
8150 XCheckRefreshWindows(display,windows);
8151 flags=ParseGeometry(radius,&geometry_info);
8152 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8153 &(*image)->exception);
8154 if (sharp_image != (Image *) NULL)
8156 *image=DestroyImage(*image);
8159 CatchException(&(*image)->exception);
8160 XSetCursorState(display,windows,MagickFalse);
8161 if (windows->image.orphan != MagickFalse)
8163 XConfigureImageColormap(display,resource_info,windows,*image);
8164 (void) XConfigureImage(display,resource_info,windows,*image);
8173 radius[MaxTextExtent] = "0.0x1.0";
8176 Query user for blur radius.
8178 (void) XDialogWidget(display,windows,"Blur",
8179 "Enter the blur radius and standard deviation:",radius);
8180 if (*radius == '\0')
8185 XSetCursorState(display,windows,MagickTrue);
8186 XCheckRefreshWindows(display,windows);
8187 flags=ParseGeometry(radius,&geometry_info);
8188 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8189 &(*image)->exception);
8190 if (blur_image != (Image *) NULL)
8192 *image=DestroyImage(*image);
8195 CatchException(&(*image)->exception);
8196 XSetCursorState(display,windows,MagickFalse);
8197 if (windows->image.orphan != MagickFalse)
8199 XConfigureImageColormap(display,resource_info,windows,*image);
8200 (void) XConfigureImage(display,resource_info,windows,*image);
8203 case ThresholdCommand:
8209 factor[MaxTextExtent] = "128";
8212 Query user for threshold value.
8214 (void) XDialogWidget(display,windows,"Threshold",
8215 "Enter threshold value:",factor);
8216 if (*factor == '\0')
8219 Gamma correct image.
8221 XSetCursorState(display,windows,MagickTrue);
8222 XCheckRefreshWindows(display,windows);
8223 threshold=SiPrefixToDouble(factor,QuantumRange);
8224 (void) BilevelImage(*image,threshold);
8225 XSetCursorState(display,windows,MagickFalse);
8226 if (windows->image.orphan != MagickFalse)
8228 XConfigureImageColormap(display,resource_info,windows,*image);
8229 (void) XConfigureImage(display,resource_info,windows,*image);
8232 case EdgeDetectCommand:
8238 radius[MaxTextExtent] = "0";
8241 Query user for edge factor.
8243 (void) XDialogWidget(display,windows,"Detect Edges",
8244 "Enter the edge detect radius:",radius);
8245 if (*radius == '\0')
8248 Detect edge in image.
8250 XSetCursorState(display,windows,MagickTrue);
8251 XCheckRefreshWindows(display,windows);
8252 flags=ParseGeometry(radius,&geometry_info);
8253 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8254 if (edge_image != (Image *) NULL)
8256 *image=DestroyImage(*image);
8259 CatchException(&(*image)->exception);
8260 XSetCursorState(display,windows,MagickFalse);
8261 if (windows->image.orphan != MagickFalse)
8263 XConfigureImageColormap(display,resource_info,windows,*image);
8264 (void) XConfigureImage(display,resource_info,windows,*image);
8273 amount[MaxTextExtent] = "2";
8276 Query user for spread amount.
8278 (void) XDialogWidget(display,windows,"Spread",
8279 "Enter the displacement amount:",amount);
8280 if (*amount == '\0')
8283 Displace image pixels by a random amount.
8285 XSetCursorState(display,windows,MagickTrue);
8286 XCheckRefreshWindows(display,windows);
8287 flags=ParseGeometry(amount,&geometry_info);
8288 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8289 if (spread_image != (Image *) NULL)
8291 *image=DestroyImage(*image);
8292 *image=spread_image;
8294 CatchException(&(*image)->exception);
8295 XSetCursorState(display,windows,MagickFalse);
8296 if (windows->image.orphan != MagickFalse)
8298 XConfigureImageColormap(display,resource_info,windows,*image);
8299 (void) XConfigureImage(display,resource_info,windows,*image);
8311 geometry[MaxTextExtent] = "30x30";
8314 Query user for the shade geometry.
8316 status=XDialogWidget(display,windows,"Shade",
8317 "Enter the azimuth and elevation of the light source:",geometry);
8318 if (*geometry == '\0')
8323 XSetCursorState(display,windows,MagickTrue);
8324 XCheckRefreshWindows(display,windows);
8325 flags=ParseGeometry(geometry,&geometry_info);
8326 if ((flags & SigmaValue) == 0)
8327 geometry_info.sigma=1.0;
8328 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8329 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8330 if (shade_image != (Image *) NULL)
8332 *image=DestroyImage(*image);
8335 CatchException(&(*image)->exception);
8336 XSetCursorState(display,windows,MagickFalse);
8337 if (windows->image.orphan != MagickFalse)
8339 XConfigureImageColormap(display,resource_info,windows,*image);
8340 (void) XConfigureImage(display,resource_info,windows,*image);
8346 bevel_width[MaxTextExtent] = "10";
8349 Query user for bevel width.
8351 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8352 if (*bevel_width == '\0')
8357 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8358 XSetCursorState(display,windows,MagickTrue);
8359 XCheckRefreshWindows(display,windows);
8360 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8361 &(*image)->exception);
8362 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8363 XSetCursorState(display,windows,MagickFalse);
8364 if (windows->image.orphan != MagickFalse)
8366 XConfigureImageColormap(display,resource_info,windows,*image);
8367 (void) XConfigureImage(display,resource_info,windows,*image);
8370 case SegmentCommand:
8373 threshold[MaxTextExtent] = "1.0x1.5";
8376 Query user for smoothing threshold.
8378 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8380 if (*threshold == '\0')
8385 XSetCursorState(display,windows,MagickTrue);
8386 XCheckRefreshWindows(display,windows);
8387 flags=ParseGeometry(threshold,&geometry_info);
8388 if ((flags & SigmaValue) == 0)
8389 geometry_info.sigma=1.0;
8390 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8391 geometry_info.sigma);
8392 XSetCursorState(display,windows,MagickFalse);
8393 if (windows->image.orphan != MagickFalse)
8395 XConfigureImageColormap(display,resource_info,windows,*image);
8396 (void) XConfigureImage(display,resource_info,windows,*image);
8399 case SepiaToneCommand:
8408 factor[MaxTextExtent] = "80%";
8411 Query user for sepia-tone factor.
8413 (void) XDialogWidget(display,windows,"Sepia Tone",
8414 "Enter the sepia tone factor (0 - 99.9%):",factor);
8415 if (*factor == '\0')
8418 Sepia tone image pixels.
8420 XSetCursorState(display,windows,MagickTrue);
8421 XCheckRefreshWindows(display,windows);
8422 threshold=SiPrefixToDouble(factor,QuantumRange);
8423 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8424 if (sepia_image != (Image *) NULL)
8426 *image=DestroyImage(*image);
8429 CatchException(&(*image)->exception);
8430 XSetCursorState(display,windows,MagickFalse);
8431 if (windows->image.orphan != MagickFalse)
8433 XConfigureImageColormap(display,resource_info,windows,*image);
8434 (void) XConfigureImage(display,resource_info,windows,*image);
8437 case SolarizeCommand:
8443 factor[MaxTextExtent] = "60%";
8446 Query user for solarize factor.
8448 (void) XDialogWidget(display,windows,"Solarize",
8449 "Enter the solarize factor (0 - 99.9%):",factor);
8450 if (*factor == '\0')
8453 Solarize image pixels.
8455 XSetCursorState(display,windows,MagickTrue);
8456 XCheckRefreshWindows(display,windows);
8457 threshold=SiPrefixToDouble(factor,QuantumRange);
8458 (void) SolarizeImage(*image,threshold);
8459 XSetCursorState(display,windows,MagickFalse);
8460 if (windows->image.orphan != MagickFalse)
8462 XConfigureImageColormap(display,resource_info,windows,*image);
8463 (void) XConfigureImage(display,resource_info,windows,*image);
8472 degrees[MaxTextExtent] = "60";
8475 Query user for swirl angle.
8477 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8479 if (*degrees == '\0')
8482 Swirl image pixels about the center.
8484 XSetCursorState(display,windows,MagickTrue);
8485 XCheckRefreshWindows(display,windows);
8486 flags=ParseGeometry(degrees,&geometry_info);
8487 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8488 if (swirl_image != (Image *) NULL)
8490 *image=DestroyImage(*image);
8493 CatchException(&(*image)->exception);
8494 XSetCursorState(display,windows,MagickFalse);
8495 if (windows->image.orphan != MagickFalse)
8497 XConfigureImageColormap(display,resource_info,windows,*image);
8498 (void) XConfigureImage(display,resource_info,windows,*image);
8501 case ImplodeCommand:
8507 factor[MaxTextExtent] = "0.3";
8510 Query user for implode factor.
8512 (void) XDialogWidget(display,windows,"Implode",
8513 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8514 if (*factor == '\0')
8517 Implode image pixels about the center.
8519 XSetCursorState(display,windows,MagickTrue);
8520 XCheckRefreshWindows(display,windows);
8521 flags=ParseGeometry(factor,&geometry_info);
8522 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8523 if (implode_image != (Image *) NULL)
8525 *image=DestroyImage(*image);
8526 *image=implode_image;
8528 CatchException(&(*image)->exception);
8529 XSetCursorState(display,windows,MagickFalse);
8530 if (windows->image.orphan != MagickFalse)
8532 XConfigureImageColormap(display,resource_info,windows,*image);
8533 (void) XConfigureImage(display,resource_info,windows,*image);
8536 case VignetteCommand:
8542 geometry[MaxTextExtent] = "0x20";
8545 Query user for the vignette geometry.
8547 (void) XDialogWidget(display,windows,"Vignette",
8548 "Enter the radius, sigma, and x and y offsets:",geometry);
8549 if (*geometry == '\0')
8552 Soften the edges of the image in vignette style
8554 XSetCursorState(display,windows,MagickTrue);
8555 XCheckRefreshWindows(display,windows);
8556 flags=ParseGeometry(geometry,&geometry_info);
8557 if ((flags & SigmaValue) == 0)
8558 geometry_info.sigma=1.0;
8559 if ((flags & XiValue) == 0)
8560 geometry_info.xi=0.1*(*image)->columns;
8561 if ((flags & PsiValue) == 0)
8562 geometry_info.psi=0.1*(*image)->rows;
8563 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8564 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8565 0.5),&(*image)->exception);
8566 if (vignette_image != (Image *) NULL)
8568 *image=DestroyImage(*image);
8569 *image=vignette_image;
8571 CatchException(&(*image)->exception);
8572 XSetCursorState(display,windows,MagickFalse);
8573 if (windows->image.orphan != MagickFalse)
8575 XConfigureImageColormap(display,resource_info,windows,*image);
8576 (void) XConfigureImage(display,resource_info,windows,*image);
8585 geometry[MaxTextExtent] = "25x150";
8588 Query user for the wave geometry.
8590 (void) XDialogWidget(display,windows,"Wave",
8591 "Enter the amplitude and length of the wave:",geometry);
8592 if (*geometry == '\0')
8595 Alter an image along a sine wave.
8597 XSetCursorState(display,windows,MagickTrue);
8598 XCheckRefreshWindows(display,windows);
8599 flags=ParseGeometry(geometry,&geometry_info);
8600 if ((flags & SigmaValue) == 0)
8601 geometry_info.sigma=1.0;
8602 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8603 &(*image)->exception);
8604 if (wave_image != (Image *) NULL)
8606 *image=DestroyImage(*image);
8609 CatchException(&(*image)->exception);
8610 XSetCursorState(display,windows,MagickFalse);
8611 if (windows->image.orphan != MagickFalse)
8613 XConfigureImageColormap(display,resource_info,windows,*image);
8614 (void) XConfigureImage(display,resource_info,windows,*image);
8617 case OilPaintCommand:
8623 radius[MaxTextExtent] = "0";
8626 Query user for circular neighborhood radius.
8628 (void) XDialogWidget(display,windows,"Oil Paint",
8629 "Enter the mask radius:",radius);
8630 if (*radius == '\0')
8633 OilPaint image scanlines.
8635 XSetCursorState(display,windows,MagickTrue);
8636 XCheckRefreshWindows(display,windows);
8637 flags=ParseGeometry(radius,&geometry_info);
8638 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8639 if (paint_image != (Image *) NULL)
8641 *image=DestroyImage(*image);
8644 CatchException(&(*image)->exception);
8645 XSetCursorState(display,windows,MagickFalse);
8646 if (windows->image.orphan != MagickFalse)
8648 XConfigureImageColormap(display,resource_info,windows,*image);
8649 (void) XConfigureImage(display,resource_info,windows,*image);
8652 case CharcoalDrawCommand:
8658 radius[MaxTextExtent] = "0x1";
8661 Query user for charcoal radius.
8663 (void) XDialogWidget(display,windows,"Charcoal Draw",
8664 "Enter the charcoal radius and sigma:",radius);
8665 if (*radius == '\0')
8670 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8671 XSetCursorState(display,windows,MagickTrue);
8672 XCheckRefreshWindows(display,windows);
8673 flags=ParseGeometry(radius,&geometry_info);
8674 if ((flags & SigmaValue) == 0)
8675 geometry_info.sigma=geometry_info.rho;
8676 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8677 &(*image)->exception);
8678 if (charcoal_image != (Image *) NULL)
8680 *image=DestroyImage(*image);
8681 *image=charcoal_image;
8683 CatchException(&(*image)->exception);
8684 XSetCursorState(display,windows,MagickFalse);
8685 if (windows->image.orphan != MagickFalse)
8687 XConfigureImageColormap(display,resource_info,windows,*image);
8688 (void) XConfigureImage(display,resource_info,windows,*image);
8691 case AnnotateCommand:
8694 Annotate the image with text.
8696 status=XAnnotateEditImage(display,resource_info,windows,*image);
8697 if (status == MagickFalse)
8699 XNoticeWidget(display,windows,"Unable to annotate X image",
8700 (*image)->filename);
8710 status=XDrawEditImage(display,resource_info,windows,image);
8711 if (status == MagickFalse)
8713 XNoticeWidget(display,windows,"Unable to draw on the X image",
8714 (*image)->filename);
8724 status=XColorEditImage(display,resource_info,windows,image);
8725 if (status == MagickFalse)
8727 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8728 (*image)->filename);
8738 status=XMatteEditImage(display,resource_info,windows,image);
8739 if (status == MagickFalse)
8741 XNoticeWidget(display,windows,"Unable to matte edit X image",
8742 (*image)->filename);
8747 case CompositeCommand:
8752 status=XCompositeImage(display,resource_info,windows,*image);
8753 if (status == MagickFalse)
8755 XNoticeWidget(display,windows,"Unable to composite X image",
8756 (*image)->filename);
8761 case AddBorderCommand:
8767 geometry[MaxTextExtent] = "6x6";
8770 Query user for border color and geometry.
8772 XColorBrowserWidget(display,windows,"Select",color);
8775 (void) XDialogWidget(display,windows,"Add Border",
8776 "Enter border geometry:",geometry);
8777 if (*geometry == '\0')
8780 Add a border to the image.
8782 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8783 XSetCursorState(display,windows,MagickTrue);
8784 XCheckRefreshWindows(display,windows);
8785 (void) QueryColorDatabase(color,&(*image)->border_color,
8786 &(*image)->exception);
8787 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8788 &(*image)->exception);
8789 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8790 if (border_image != (Image *) NULL)
8792 *image=DestroyImage(*image);
8793 *image=border_image;
8795 CatchException(&(*image)->exception);
8796 XSetCursorState(display,windows,MagickFalse);
8797 if (windows->image.orphan != MagickFalse)
8799 windows->image.window_changes.width=(int) (*image)->columns;
8800 windows->image.window_changes.height=(int) (*image)->rows;
8801 XConfigureImageColormap(display,resource_info,windows,*image);
8802 (void) XConfigureImage(display,resource_info,windows,*image);
8805 case AddFrameCommand:
8814 geometry[MaxTextExtent] = "6x6";
8817 Query user for frame color and geometry.
8819 XColorBrowserWidget(display,windows,"Select",color);
8822 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8824 if (*geometry == '\0')
8827 Surround image with an ornamental border.
8829 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8830 XSetCursorState(display,windows,MagickTrue);
8831 XCheckRefreshWindows(display,windows);
8832 (void) QueryColorDatabase(color,&(*image)->matte_color,
8833 &(*image)->exception);
8834 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8835 &(*image)->exception);
8836 frame_info.width=page_geometry.width;
8837 frame_info.height=page_geometry.height;
8838 frame_info.outer_bevel=page_geometry.x;
8839 frame_info.inner_bevel=page_geometry.y;
8840 frame_info.x=(ssize_t) frame_info.width;
8841 frame_info.y=(ssize_t) frame_info.height;
8842 frame_info.width=(*image)->columns+2*frame_info.width;
8843 frame_info.height=(*image)->rows+2*frame_info.height;
8844 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8845 if (frame_image != (Image *) NULL)
8847 *image=DestroyImage(*image);
8850 CatchException(&(*image)->exception);
8851 XSetCursorState(display,windows,MagickFalse);
8852 if (windows->image.orphan != MagickFalse)
8854 windows->image.window_changes.width=(int) (*image)->columns;
8855 windows->image.window_changes.height=(int) (*image)->rows;
8856 XConfigureImageColormap(display,resource_info,windows,*image);
8857 (void) XConfigureImage(display,resource_info,windows,*image);
8860 case CommentCommand:
8874 unique_file=AcquireUniqueFileResource(image_info->filename);
8875 if (unique_file == -1)
8876 XNoticeWidget(display,windows,"Unable to edit image comment",
8877 image_info->filename);
8878 value=GetImageProperty(*image,"comment");
8879 if (value == (char *) NULL)
8880 unique_file=close(unique_file)-1;
8886 file=fdopen(unique_file,"w");
8887 if (file == (FILE *) NULL)
8889 XNoticeWidget(display,windows,"Unable to edit image comment",
8890 image_info->filename);
8893 for (p=value; *p != '\0'; p++)
8894 (void) fputc((int) *p,file);
8895 (void) fputc('\n',file);
8896 (void) fclose(file);
8898 XSetCursorState(display,windows,MagickTrue);
8899 XCheckRefreshWindows(display,windows);
8900 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8901 &(*image)->exception);
8902 if (status == MagickFalse)
8903 XNoticeWidget(display,windows,"Unable to edit image comment",
8910 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8911 if (comment != (char *) NULL)
8913 (void) SetImageProperty(*image,"comment",comment);
8914 (*image)->taint=MagickTrue;
8917 (void) RelinquishUniqueFileResource(image_info->filename);
8918 XSetCursorState(display,windows,MagickFalse);
8926 XSetCursorState(display,windows,MagickTrue);
8927 XCheckRefreshWindows(display,windows);
8928 (void) AcquireUniqueFilename(filename);
8929 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
8931 status=WriteImage(image_info,*image);
8932 if (status == MagickFalse)
8933 XNoticeWidget(display,windows,"Unable to launch image editor",
8937 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8938 CatchException(&(*image)->exception);
8939 XClientMessage(display,windows->image.id,windows->im_protocols,
8940 windows->im_next_image,CurrentTime);
8942 (void) RelinquishUniqueFileResource(filename);
8943 XSetCursorState(display,windows,MagickFalse);
8946 case RegionofInterestCommand:
8949 Apply an image processing technique to a region of interest.
8951 (void) XROIImage(display,resource_info,windows,image);
8961 if (windows->magnify.mapped != MagickFalse)
8962 (void) XRaiseWindow(display,windows->magnify.id);
8968 XSetCursorState(display,windows,MagickTrue);
8969 (void) XMapRaised(display,windows->magnify.id);
8970 XSetCursorState(display,windows,MagickFalse);
8974 case ShowPreviewCommand:
8983 preview_type[MaxTextExtent] = "Gamma";
8986 Select preview type from menu.
8988 previews=GetCommandOptions(MagickPreviewOptions);
8989 if (previews == (char **) NULL)
8991 XListBrowserWidget(display,windows,&windows->widget,
8992 (const char **) previews,"Preview",
8993 "Select an enhancement, effect, or F/X:",preview_type);
8994 previews=DestroyStringList(previews);
8995 if (*preview_type == '\0')
9000 XSetCursorState(display,windows,MagickTrue);
9001 XCheckRefreshWindows(display,windows);
9002 image_info->preview_type=(PreviewType)
9003 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
9004 image_info->group=(ssize_t) windows->image.id;
9005 (void) DeleteImageProperty(*image,"label");
9006 (void) SetImageProperty(*image,"label","Preview");
9007 (void) AcquireUniqueFilename(filename);
9008 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
9010 status=WriteImage(image_info,*image);
9011 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9012 preview_image=ReadImage(image_info,&(*image)->exception);
9013 (void) RelinquishUniqueFileResource(filename);
9014 if (preview_image == (Image *) NULL)
9016 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
9018 status=WriteImage(image_info,preview_image);
9019 preview_image=DestroyImage(preview_image);
9020 if (status == MagickFalse)
9021 XNoticeWidget(display,windows,"Unable to show image preview",
9022 (*image)->filename);
9023 XDelay(display,1500);
9024 XSetCursorState(display,windows,MagickFalse);
9027 case ShowHistogramCommand:
9033 Show image histogram.
9035 XSetCursorState(display,windows,MagickTrue);
9036 XCheckRefreshWindows(display,windows);
9037 image_info->group=(ssize_t) windows->image.id;
9038 (void) DeleteImageProperty(*image,"label");
9039 (void) SetImageProperty(*image,"label","Histogram");
9040 (void) AcquireUniqueFilename(filename);
9041 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
9043 status=WriteImage(image_info,*image);
9044 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9045 histogram_image=ReadImage(image_info,&(*image)->exception);
9046 (void) RelinquishUniqueFileResource(filename);
9047 if (histogram_image == (Image *) NULL)
9049 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
9050 "show:%s",filename);
9051 status=WriteImage(image_info,histogram_image);
9052 histogram_image=DestroyImage(histogram_image);
9053 if (status == MagickFalse)
9054 XNoticeWidget(display,windows,"Unable to show histogram",
9055 (*image)->filename);
9056 XDelay(display,1500);
9057 XSetCursorState(display,windows,MagickFalse);
9060 case ShowMatteCommand:
9065 if ((*image)->matte == MagickFalse)
9067 XNoticeWidget(display,windows,
9068 "Image does not have any matte information",(*image)->filename);
9074 XSetCursorState(display,windows,MagickTrue);
9075 XCheckRefreshWindows(display,windows);
9076 image_info->group=(ssize_t) windows->image.id;
9077 (void) DeleteImageProperty(*image,"label");
9078 (void) SetImageProperty(*image,"label","Matte");
9079 (void) AcquireUniqueFilename(filename);
9080 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
9082 status=WriteImage(image_info,*image);
9083 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9084 matte_image=ReadImage(image_info,&(*image)->exception);
9085 (void) RelinquishUniqueFileResource(filename);
9086 if (matte_image == (Image *) NULL)
9088 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
9090 status=WriteImage(image_info,matte_image);
9091 matte_image=DestroyImage(matte_image);
9092 if (status == MagickFalse)
9093 XNoticeWidget(display,windows,"Unable to show matte",
9094 (*image)->filename);
9095 XDelay(display,1500);
9096 XSetCursorState(display,windows,MagickFalse);
9099 case BackgroundCommand:
9104 status=XBackgroundImage(display,resource_info,windows,image);
9105 if (status == MagickFalse)
9107 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9108 if (nexus != (Image *) NULL)
9109 XClientMessage(display,windows->image.id,windows->im_protocols,
9110 windows->im_next_image,CurrentTime);
9113 case SlideShowCommand:
9116 delay[MaxTextExtent] = "5";
9119 Display next image after pausing.
9121 (void) XDialogWidget(display,windows,"Slide Show",
9122 "Pause how many 1/100ths of a second between images:",delay);
9125 resource_info->delay=StringToUnsignedLong(delay);
9126 XClientMessage(display,windows->image.id,windows->im_protocols,
9127 windows->im_next_image,CurrentTime);
9130 case PreferencesCommand:
9133 Set user preferences.
9135 status=XPreferencesWidget(display,resource_info,windows);
9136 if (status == MagickFalse)
9138 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9139 if (nexus != (Image *) NULL)
9140 XClientMessage(display,windows->image.id,windows->im_protocols,
9141 windows->im_next_image,CurrentTime);
9147 User requested help.
9149 XTextViewWidget(display,resource_info,windows,MagickFalse,
9150 "Help Viewer - Display",DisplayHelp);
9153 case BrowseDocumentationCommand:
9163 Browse the ImageMagick documentation.
9165 root_window=XRootWindow(display,XDefaultScreen(display));
9166 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9167 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9168 if (mozilla_window != (Window) NULL)
9171 command[MaxTextExtent],
9175 Display documentation using Netscape remote control.
9177 url=GetMagickHomeURL();
9178 (void) FormatLocaleString(command,MaxTextExtent,
9179 "openurl(%s,new-tab)",url);
9180 url=DestroyString(url);
9181 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9182 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9183 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9184 XSetCursorState(display,windows,MagickFalse);
9187 XSetCursorState(display,windows,MagickTrue);
9188 XCheckRefreshWindows(display,windows);
9189 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9190 &(*image)->exception);
9191 if (status == MagickFalse)
9192 XNoticeWidget(display,windows,"Unable to browse documentation",
9194 XDelay(display,1500);
9195 XSetCursorState(display,windows,MagickFalse);
9198 case VersionCommand:
9200 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9201 GetMagickCopyright());
9204 case SaveToUndoBufferCommand:
9208 (void) XBell(display,0);
9212 image_info=DestroyImageInfo(image_info);
9217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9221 + X M a g n i f y I m a g e %
9225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9227 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9228 % The magnified portion is displayed in a separate window.
9230 % The format of the XMagnifyImage method is:
9232 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9234 % A description of each parameter follows:
9236 % o display: Specifies a connection to an X server; returned from
9239 % o windows: Specifies a pointer to a XWindows structure.
9241 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9242 % the entire image is refreshed.
9245 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9248 text[MaxTextExtent];
9258 Update magnified image until the mouse button is released.
9260 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9264 windows->magnify.x=(int) windows->image.x+x;
9265 windows->magnify.y=(int) windows->image.y+y;
9269 Map and unmap Info widget as text cursor crosses its boundaries.
9271 if (windows->info.mapped != MagickFalse)
9273 if ((x < (int) (windows->info.x+windows->info.width)) &&
9274 (y < (int) (windows->info.y+windows->info.height)))
9275 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9278 if ((x > (int) (windows->info.x+windows->info.width)) ||
9279 (y > (int) (windows->info.y+windows->info.height)))
9280 (void) XMapWindow(display,windows->info.id);
9281 if (windows->info.mapped != MagickFalse)
9284 Display pointer position.
9286 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9287 windows->magnify.x,windows->magnify.y);
9288 XInfoWidget(display,windows,text);
9291 Wait for next event.
9293 XScreenEvent(display,windows,event);
9294 switch (event->type)
9301 User has finished magnifying image.
9320 Check boundary conditions.
9325 if (x >= (int) windows->image.width)
9326 x=(int) windows->image.width-1;
9330 if (y >= (int) windows->image.height)
9331 y=(int) windows->image.height-1;
9332 } while ((state & ExitState) == 0);
9334 Display magnified image.
9336 XSetCursorState(display,windows,MagickFalse);
9340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9344 + X M a g n i f y W i n d o w C o m m a n d %
9348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9350 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9351 % pixel as specified by the key symbol.
9353 % The format of the XMagnifyWindowCommand method is:
9355 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9356 % const MagickStatusType state,const KeySym key_symbol)
9358 % A description of each parameter follows:
9360 % o display: Specifies a connection to an X server; returned from
9363 % o windows: Specifies a pointer to a XWindows structure.
9365 % o state: key mask.
9367 % o key_symbol: Specifies a KeySym which indicates which side of the image
9371 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9372 const MagickStatusType state,const KeySym key_symbol)
9378 User specified a magnify factor or position.
9381 if ((state & Mod1Mask) != 0)
9383 switch ((int) key_symbol)
9387 (void) XWithdrawWindow(display,windows->magnify.id,
9388 windows->magnify.screen);
9394 windows->magnify.x=(int) windows->image.width/2;
9395 windows->magnify.y=(int) windows->image.height/2;
9401 if (windows->magnify.x > 0)
9402 windows->magnify.x-=quantum;
9408 if (windows->magnify.y > 0)
9409 windows->magnify.y-=quantum;
9415 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9416 windows->magnify.x+=quantum;
9422 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9423 windows->magnify.y+=quantum;
9437 windows->magnify.data=(key_symbol-XK_0);
9451 windows->magnify.data=(key_symbol-XK_KP_0);
9457 XMakeMagnifyImage(display,windows);
9461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9465 + X M a k e P a n I m a g e %
9469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9471 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9474 % The format of the XMakePanImage method is:
9476 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9477 % XWindows *windows,Image *image)
9479 % A description of each parameter follows:
9481 % o display: Specifies a connection to an X server; returned from
9484 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9486 % o windows: Specifies a pointer to a XWindows structure.
9488 % o image: the image.
9491 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9492 XWindows *windows,Image *image)
9498 Create and display image for panning icon.
9500 XSetCursorState(display,windows,MagickTrue);
9501 XCheckRefreshWindows(display,windows);
9502 windows->pan.x=(int) windows->image.x;
9503 windows->pan.y=(int) windows->image.y;
9504 status=XMakeImage(display,resource_info,&windows->pan,image,
9505 windows->pan.width,windows->pan.height);
9506 if (status == MagickFalse)
9507 ThrowXWindowFatalException(XServerError,image->exception.reason,
9508 image->exception.description);
9509 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9510 windows->pan.pixmap);
9511 (void) XClearWindow(display,windows->pan.id);
9512 XDrawPanRectangle(display,windows);
9513 XSetCursorState(display,windows,MagickFalse);
9517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9521 + X M a t t a E d i t I m a g e %
9525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9527 % XMatteEditImage() allows the user to interactively change the Matte channel
9528 % of an image. If the image is PseudoClass it is promoted to DirectClass
9529 % before the matte information is stored.
9531 % The format of the XMatteEditImage method is:
9533 % MagickBooleanType XMatteEditImage(Display *display,
9534 % XResourceInfo *resource_info,XWindows *windows,Image **image)
9536 % A description of each parameter follows:
9538 % o display: Specifies a connection to an X server; returned from
9541 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9543 % o windows: Specifies a pointer to a XWindows structure.
9545 % o image: the image; returned from ReadImage.
9548 static MagickBooleanType XMatteEditImage(Display *display,
9549 XResourceInfo *resource_info,XWindows *windows,Image **image)
9552 matte[MaxTextExtent] = "0";
9567 static const ModeType
9568 MatteEditCommands[] =
9571 MatteEditBorderCommand,
9572 MatteEditFuzzCommand,
9573 MatteEditValueCommand,
9574 MatteEditUndoCommand,
9575 MatteEditHelpCommand,
9576 MatteEditDismissCommand
9580 method = PointMethod;
9583 border_color = { 0, 0, 0, 0, 0, 0 };
9586 command[MaxTextExtent],
9587 text[MaxTextExtent];
9603 register PixelPacket
9619 (void) CloneString(&windows->command.name,"Matte Edit");
9620 windows->command.data=4;
9621 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9622 (void) XMapRaised(display,windows->command.id);
9623 XClientMessage(display,windows->image.id,windows->im_protocols,
9624 windows->im_update_widget,CurrentTime);
9628 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9629 resource_info->background_color,resource_info->foreground_color);
9630 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9632 Track pointer until button 1 is pressed.
9634 XQueryPosition(display,windows->image.id,&x,&y);
9635 (void) XSelectInput(display,windows->image.id,
9636 windows->image.attributes.event_mask | PointerMotionMask);
9640 if (windows->info.mapped != MagickFalse)
9643 Display pointer position.
9645 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9646 x+windows->image.x,y+windows->image.y);
9647 XInfoWidget(display,windows,text);
9650 Wait for next event.
9652 XScreenEvent(display,windows,&event);
9653 if (event.xany.window == windows->command.id)
9656 Select a command from the Command widget.
9658 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9661 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9664 switch (MatteEditCommands[id])
9666 case MatteEditMethod:
9672 Select a method from the pop-up menu.
9674 methods=GetCommandOptions(MagickMethodOptions);
9675 if (methods == (char **) NULL)
9677 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9678 (const char **) methods,command);
9680 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9681 MagickFalse,methods[entry]);
9682 methods=DestroyStringList(methods);
9685 case MatteEditBorderCommand:
9688 *ColorMenu[MaxNumberPens];
9694 Initialize menu selections.
9696 for (i=0; i < (int) (MaxNumberPens-2); i++)
9697 ColorMenu[i]=resource_info->pen_colors[i];
9698 ColorMenu[MaxNumberPens-2]="Browser...";
9699 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9701 Select a pen color from the pop-up menu.
9703 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9704 (const char **) ColorMenu,command);
9707 if (pen_number == (MaxNumberPens-2))
9710 color_name[MaxTextExtent] = "gray";
9713 Select a pen color from a dialog.
9715 resource_info->pen_colors[pen_number]=color_name;
9716 XColorBrowserWidget(display,windows,"Select",color_name);
9717 if (*color_name == '\0')
9723 (void) XParseColor(display,windows->map_info->colormap,
9724 resource_info->pen_colors[pen_number],&border_color);
9727 case MatteEditFuzzCommand:
9730 fuzz[MaxTextExtent];
9745 Select a command from the pop-up menu.
9747 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9753 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*QuantumRange+
9757 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9758 (void) XDialogWidget(display,windows,"Ok",
9759 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9762 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9763 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
9766 case MatteEditValueCommand:
9769 message[MaxTextExtent];
9781 Select a command from the pop-up menu.
9783 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9789 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9791 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9792 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9793 (Quantum) TransparentOpacity);
9796 (void) FormatLocaleString(message,MaxTextExtent,
9797 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9799 (void) XDialogWidget(display,windows,"Matte",message,matte);
9804 case MatteEditUndoCommand:
9806 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9810 case MatteEditHelpCommand:
9812 XTextViewWidget(display,resource_info,windows,MagickFalse,
9813 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9816 case MatteEditDismissCommand:
9828 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9835 if (event.xbutton.button != Button1)
9837 if ((event.xbutton.window != windows->image.id) &&
9838 (event.xbutton.window != windows->magnify.id))
9845 (void) XMagickCommand(display,resource_info,windows,
9846 SaveToUndoBufferCommand,image);
9847 state|=UpdateConfigurationState;
9852 if (event.xbutton.button != Button1)
9854 if ((event.xbutton.window != windows->image.id) &&
9855 (event.xbutton.window != windows->magnify.id))
9858 Update colormap information.
9862 XConfigureImageColormap(display,resource_info,windows,*image);
9863 (void) XConfigureImage(display,resource_info,windows,*image);
9864 XInfoWidget(display,windows,text);
9865 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9866 state&=(~UpdateConfigurationState);
9874 command[MaxTextExtent];
9879 if (event.xkey.window == windows->magnify.id)
9884 window=windows->magnify.id;
9885 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9887 if (event.xkey.window != windows->image.id)
9890 Respond to a user key press.
9892 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9893 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9894 switch ((int) key_symbol)
9908 XTextViewWidget(display,resource_info,windows,MagickFalse,
9909 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9914 (void) XBell(display,0);
9923 Map and unmap Info widget as cursor crosses its boundaries.
9927 if (windows->info.mapped != MagickFalse)
9929 if ((x < (int) (windows->info.x+windows->info.width)) &&
9930 (y < (int) (windows->info.y+windows->info.height)))
9931 (void) XWithdrawWindow(display,windows->info.id,
9932 windows->info.screen);
9935 if ((x > (int) (windows->info.x+windows->info.width)) ||
9936 (y > (int) (windows->info.y+windows->info.height)))
9937 (void) XMapWindow(display,windows->info.id);
9943 if (event.xany.window == windows->magnify.id)
9945 x=windows->magnify.x-windows->image.x;
9946 y=windows->magnify.y-windows->image.y;
9950 if ((state & UpdateConfigurationState) != 0)
9963 Matte edit is relative to image configuration.
9965 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9967 XPutPixel(windows->image.ximage,x_offset,y_offset,
9968 windows->pixel_info->background_color.pixel);
9969 width=(unsigned int) (*image)->columns;
9970 height=(unsigned int) (*image)->rows;
9973 if (windows->image.crop_geometry != (char *) NULL)
9974 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9977 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9979 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9980 if ((x_offset < 0) || (y_offset < 0))
9982 if ((x_offset >= (int) (*image)->columns) ||
9983 (y_offset >= (int) (*image)->rows))
9985 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9986 return(MagickFalse);
9987 (*image)->matte=MagickTrue;
9988 exception=(&(*image)->exception);
9989 image_view=AcquireCacheView(*image);
9996 Update matte information using point algorithm.
9998 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
9999 (ssize_t) y_offset,1,1,exception);
10000 if (q == (PixelPacket *) NULL)
10002 q->opacity=(Quantum) StringToLong(matte);
10003 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10006 case ReplaceMethod:
10012 Update matte information using replace algorithm.
10014 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
10015 (ssize_t) y_offset,&target,exception);
10016 for (y=0; y < (int) (*image)->rows; y++)
10018 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10019 (*image)->columns,1,&(*image)->exception);
10020 if (q == (PixelPacket *) NULL)
10022 for (x=0; x < (int) (*image)->columns; x++)
10024 if (IsColorSimilar(*image,q,&target))
10025 q->opacity=(Quantum) StringToLong(matte);
10028 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10033 case FloodfillMethod:
10034 case FillToBorderMethod:
10043 Update matte information using floodfill algorithm.
10045 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10046 (ssize_t) y_offset,&target,exception);
10047 if (method == FillToBorderMethod)
10049 target.red=(MagickRealType)
10050 ScaleShortToQuantum(border_color.red);
10051 target.green=(MagickRealType)
10052 ScaleShortToQuantum(border_color.green);
10053 target.blue=(MagickRealType)
10054 ScaleShortToQuantum(border_color.blue);
10056 draw_info=CloneDrawInfo(resource_info->image_info,
10057 (DrawInfo *) NULL);
10058 draw_info->fill.opacity=ClampToQuantum(LocaleToDouble(matte,
10060 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10061 (ssize_t) x_offset,(ssize_t) y_offset,
10062 method == FloodfillMethod ? MagickFalse : MagickTrue);
10063 draw_info=DestroyDrawInfo(draw_info);
10069 Update matte information using reset algorithm.
10071 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10072 return(MagickFalse);
10073 for (y=0; y < (int) (*image)->rows; y++)
10075 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10076 (*image)->columns,1,exception);
10077 if (q == (PixelPacket *) NULL)
10079 for (x=0; x < (int) (*image)->columns; x++)
10081 q->opacity=(Quantum) StringToLong(matte);
10084 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10087 if (StringToLong(matte) == OpaqueOpacity)
10088 (*image)->matte=MagickFalse;
10092 image_view=DestroyCacheView(image_view);
10093 state&=(~UpdateConfigurationState);
10095 } while ((state & ExitState) == 0);
10096 (void) XSelectInput(display,windows->image.id,
10097 windows->image.attributes.event_mask);
10098 XSetCursorState(display,windows,MagickFalse);
10099 (void) XFreeCursor(display,cursor);
10100 return(MagickTrue);
10104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10108 + X O p e n I m a g e %
10112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10114 % XOpenImage() loads an image from a file.
10116 % The format of the XOpenImage method is:
10118 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10119 % XWindows *windows,const unsigned int command)
10121 % A description of each parameter follows:
10123 % o display: Specifies a connection to an X server; returned from
10126 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10128 % o windows: Specifies a pointer to a XWindows structure.
10130 % o command: A value other than zero indicates that the file is selected
10131 % from the command line argument list.
10134 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10135 XWindows *windows,const MagickBooleanType command)
10150 filename[MaxTextExtent] = "\0";
10153 Request file name from user.
10155 if (command == MagickFalse)
10156 XFileBrowserWidget(display,windows,"Open",filename);
10172 Select next image from the command line.
10174 status=XGetCommand(display,windows->image.id,&files,&count);
10177 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10178 return((Image *) NULL);
10180 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10181 if (filelist == (char **) NULL)
10183 ThrowXWindowFatalException(ResourceLimitError,
10184 "MemoryAllocationFailed","...");
10185 (void) XFreeStringList(files);
10186 return((Image *) NULL);
10189 for (i=1; i < count; i++)
10190 if (*files[i] != '-')
10191 filelist[j++]=files[i];
10192 filelist[j]=(char *) NULL;
10193 XListBrowserWidget(display,windows,&windows->widget,
10194 (const char **) filelist,"Load","Select Image to Load:",filename);
10195 filelist=(char **) RelinquishMagickMemory(filelist);
10196 (void) XFreeStringList(files);
10198 if (*filename == '\0')
10199 return((Image *) NULL);
10200 image_info=CloneImageInfo(resource_info->image_info);
10201 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10203 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10204 exception=AcquireExceptionInfo();
10205 (void) SetImageInfo(image_info,0,exception);
10206 if (LocaleCompare(image_info->magick,"X") == 0)
10209 seconds[MaxTextExtent];
10212 User may want to delay the X server screen grab.
10214 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10215 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10217 if (*seconds == '\0')
10218 return((Image *) NULL);
10219 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10221 magick_info=GetMagickInfo(image_info->magick,exception);
10222 if ((magick_info != (const MagickInfo *) NULL) &&
10223 (magick_info->raw != MagickFalse))
10226 geometry[MaxTextExtent];
10229 Request image size from the user.
10231 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10232 if (image_info->size != (char *) NULL)
10233 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10234 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10236 (void) CloneString(&image_info->size,geometry);
10241 XSetCursorState(display,windows,MagickTrue);
10242 XCheckRefreshWindows(display,windows);
10243 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10244 nexus=ReadImage(image_info,exception);
10245 CatchException(exception);
10246 XSetCursorState(display,windows,MagickFalse);
10247 if (nexus != (Image *) NULL)
10248 XClientMessage(display,windows->image.id,windows->im_protocols,
10249 windows->im_next_image,CurrentTime);
10257 Unknown image format.
10259 text=FileToString(filename,~0,exception);
10260 if (text == (char *) NULL)
10261 return((Image *) NULL);
10262 textlist=StringToList(text);
10263 if (textlist != (char **) NULL)
10266 title[MaxTextExtent];
10271 (void) FormatLocaleString(title,MaxTextExtent,
10272 "Unknown format: %s",filename);
10273 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10274 (const char **) textlist);
10275 for (i=0; textlist[i] != (char *) NULL; i++)
10276 textlist[i]=DestroyString(textlist[i]);
10277 textlist=(char **) RelinquishMagickMemory(textlist);
10279 text=DestroyString(text);
10281 exception=DestroyExceptionInfo(exception);
10282 image_info=DestroyImageInfo(image_info);
10287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10291 + X P a n I m a g e %
10295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10297 % XPanImage() pans the image until the mouse button is released.
10299 % The format of the XPanImage method is:
10301 % void XPanImage(Display *display,XWindows *windows,XEvent *event)
10303 % A description of each parameter follows:
10305 % o display: Specifies a connection to an X server; returned from
10308 % o windows: Specifies a pointer to a XWindows structure.
10310 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10311 % the entire image is refreshed.
10314 static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10317 text[MaxTextExtent];
10335 if ((windows->image.ximage->width > (int) windows->image.width) &&
10336 (windows->image.ximage->height > (int) windows->image.height))
10337 cursor=XCreateFontCursor(display,XC_fleur);
10339 if (windows->image.ximage->width > (int) windows->image.width)
10340 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10342 if (windows->image.ximage->height > (int) windows->image.height)
10343 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10345 cursor=XCreateFontCursor(display,XC_arrow);
10346 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10348 Pan image as pointer moves until the mouse button is released.
10350 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10351 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10352 pan_info.width=windows->pan.width*windows->image.width/
10353 windows->image.ximage->width;
10354 pan_info.height=windows->pan.height*windows->image.height/
10355 windows->image.ximage->height;
10358 state=UpdateConfigurationState;
10361 switch (event->type)
10366 User choose an initial pan location.
10368 pan_info.x=(ssize_t) event->xbutton.x;
10369 pan_info.y=(ssize_t) event->xbutton.y;
10370 state|=UpdateConfigurationState;
10373 case ButtonRelease:
10376 User has finished panning the image.
10378 pan_info.x=(ssize_t) event->xbutton.x;
10379 pan_info.y=(ssize_t) event->xbutton.y;
10380 state|=UpdateConfigurationState | ExitState;
10385 pan_info.x=(ssize_t) event->xmotion.x;
10386 pan_info.y=(ssize_t) event->xmotion.y;
10387 state|=UpdateConfigurationState;
10392 if ((state & UpdateConfigurationState) != 0)
10395 Check boundary conditions.
10397 if (pan_info.x < (ssize_t) (pan_info.width/2))
10400 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10401 if (pan_info.x < 0)
10404 if ((int) (pan_info.x+windows->image.width) >
10405 windows->image.ximage->width)
10406 pan_info.x=(ssize_t)
10407 (windows->image.ximage->width-windows->image.width);
10408 if (pan_info.y < (ssize_t) (pan_info.height/2))
10411 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10412 if (pan_info.y < 0)
10415 if ((int) (pan_info.y+windows->image.height) >
10416 windows->image.ximage->height)
10417 pan_info.y=(ssize_t)
10418 (windows->image.ximage->height-windows->image.height);
10419 if ((windows->image.x != (int) pan_info.x) ||
10420 (windows->image.y != (int) pan_info.y))
10423 Display image pan offset.
10425 windows->image.x=(int) pan_info.x;
10426 windows->image.y=(int) pan_info.y;
10427 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
10428 windows->image.width,windows->image.height,windows->image.x,
10430 XInfoWidget(display,windows,text);
10432 Refresh Image window.
10434 XDrawPanRectangle(display,windows);
10435 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10437 state&=(~UpdateConfigurationState);
10440 Wait for next event.
10442 if ((state & ExitState) == 0)
10443 XScreenEvent(display,windows,event);
10444 } while ((state & ExitState) == 0);
10448 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10449 (void) XFreeCursor(display,cursor);
10450 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10458 + X P a s t e I m a g e %
10462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10464 % XPasteImage() pastes an image previously saved with XCropImage in the X
10465 % window image at a location the user chooses with the pointer.
10467 % The format of the XPasteImage method is:
10469 % MagickBooleanType XPasteImage(Display *display,
10470 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10472 % A description of each parameter follows:
10474 % o display: Specifies a connection to an X server; returned from
10477 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10479 % o windows: Specifies a pointer to a XWindows structure.
10481 % o image: the image; returned from ReadImage.
10484 static MagickBooleanType XPasteImage(Display *display,
10485 XResourceInfo *resource_info,XWindows *windows,Image *image)
10496 static const ModeType
10499 PasteOperatorsCommand,
10501 PasteDismissCommand
10504 static CompositeOperator
10505 compose = CopyCompositeOp;
10508 text[MaxTextExtent];
10542 if (resource_info->copy_image == (Image *) NULL)
10543 return(MagickFalse);
10544 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10545 &image->exception);
10547 Map Command widget.
10549 (void) CloneString(&windows->command.name,"Paste");
10550 windows->command.data=1;
10551 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10552 (void) XMapRaised(display,windows->command.id);
10553 XClientMessage(display,windows->image.id,windows->im_protocols,
10554 windows->im_update_widget,CurrentTime);
10556 Track pointer until button 1 is pressed.
10558 XSetCursorState(display,windows,MagickFalse);
10559 XQueryPosition(display,windows->image.id,&x,&y);
10560 (void) XSelectInput(display,windows->image.id,
10561 windows->image.attributes.event_mask | PointerMotionMask);
10562 paste_info.x=(ssize_t) windows->image.x+x;
10563 paste_info.y=(ssize_t) windows->image.y+y;
10564 paste_info.width=0;
10565 paste_info.height=0;
10566 cursor=XCreateFontCursor(display,XC_ul_angle);
10567 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10568 state=DefaultState;
10571 if (windows->info.mapped != MagickFalse)
10574 Display pointer position.
10576 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
10577 (long) paste_info.x,(long) paste_info.y);
10578 XInfoWidget(display,windows,text);
10580 highlight_info=paste_info;
10581 highlight_info.x=paste_info.x-windows->image.x;
10582 highlight_info.y=paste_info.y-windows->image.y;
10583 XHighlightRectangle(display,windows->image.id,
10584 windows->image.highlight_context,&highlight_info);
10586 Wait for next event.
10588 XScreenEvent(display,windows,&event);
10589 XHighlightRectangle(display,windows->image.id,
10590 windows->image.highlight_context,&highlight_info);
10591 if (event.xany.window == windows->command.id)
10594 Select a command from the Command widget.
10596 id=XCommandWidget(display,windows,PasteMenu,&event);
10599 switch (PasteCommands[id])
10601 case PasteOperatorsCommand:
10604 command[MaxTextExtent],
10608 Select a command from the pop-up menu.
10610 operators=GetCommandOptions(MagickComposeOptions);
10611 if (operators == (char **) NULL)
10613 entry=XMenuWidget(display,windows,PasteMenu[id],
10614 (const char **) operators,command);
10616 compose=(CompositeOperator) ParseCommandOption(
10617 MagickComposeOptions,MagickFalse,operators[entry]);
10618 operators=DestroyStringList(operators);
10621 case PasteHelpCommand:
10623 XTextViewWidget(display,resource_info,windows,MagickFalse,
10624 "Help Viewer - Image Composite",ImagePasteHelp);
10627 case PasteDismissCommand:
10632 state|=EscapeState;
10641 switch (event.type)
10645 if (image->debug != MagickFalse)
10646 (void) LogMagickEvent(X11Event,GetMagickModule(),
10647 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10648 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10649 if (event.xbutton.button != Button1)
10651 if (event.xbutton.window != windows->image.id)
10654 Paste rectangle is relative to image configuration.
10656 width=(unsigned int) image->columns;
10657 height=(unsigned int) image->rows;
10660 if (windows->image.crop_geometry != (char *) NULL)
10661 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10663 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10664 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10665 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10666 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10667 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10668 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10669 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10672 case ButtonRelease:
10674 if (image->debug != MagickFalse)
10675 (void) LogMagickEvent(X11Event,GetMagickModule(),
10676 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10677 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10678 if (event.xbutton.button != Button1)
10680 if (event.xbutton.window != windows->image.id)
10682 if ((paste_info.width != 0) && (paste_info.height != 0))
10685 User has selected the location of the paste image.
10687 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10688 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10698 command[MaxTextExtent];
10706 if (event.xkey.window != windows->image.id)
10709 Respond to a user key press.
10711 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10712 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10713 *(command+length)='\0';
10714 if (image->debug != MagickFalse)
10715 (void) LogMagickEvent(X11Event,GetMagickModule(),
10716 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10717 switch ((int) key_symbol)
10725 paste_image=DestroyImage(paste_image);
10726 state|=EscapeState;
10733 (void) XSetFunction(display,windows->image.highlight_context,
10735 XTextViewWidget(display,resource_info,windows,MagickFalse,
10736 "Help Viewer - Image Composite",ImagePasteHelp);
10737 (void) XSetFunction(display,windows->image.highlight_context,
10743 (void) XBell(display,0);
10752 Map and unmap Info widget as text cursor crosses its boundaries.
10756 if (windows->info.mapped != MagickFalse)
10758 if ((x < (int) (windows->info.x+windows->info.width)) &&
10759 (y < (int) (windows->info.y+windows->info.height)))
10760 (void) XWithdrawWindow(display,windows->info.id,
10761 windows->info.screen);
10764 if ((x > (int) (windows->info.x+windows->info.width)) ||
10765 (y > (int) (windows->info.y+windows->info.height)))
10766 (void) XMapWindow(display,windows->info.id);
10767 paste_info.x=(ssize_t) windows->image.x+x;
10768 paste_info.y=(ssize_t) windows->image.y+y;
10773 if (image->debug != MagickFalse)
10774 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10779 } while ((state & ExitState) == 0);
10780 (void) XSelectInput(display,windows->image.id,
10781 windows->image.attributes.event_mask);
10782 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10783 XSetCursorState(display,windows,MagickFalse);
10784 (void) XFreeCursor(display,cursor);
10785 if ((state & EscapeState) != 0)
10786 return(MagickTrue);
10788 Image pasting is relative to image configuration.
10790 XSetCursorState(display,windows,MagickTrue);
10791 XCheckRefreshWindows(display,windows);
10792 width=(unsigned int) image->columns;
10793 height=(unsigned int) image->rows;
10796 if (windows->image.crop_geometry != (char *) NULL)
10797 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10798 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10800 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10801 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10802 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10804 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10805 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10807 Paste image with X Image window.
10809 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10810 paste_image=DestroyImage(paste_image);
10811 XSetCursorState(display,windows,MagickFalse);
10813 Update image colormap.
10815 XConfigureImageColormap(display,resource_info,windows,image);
10816 (void) XConfigureImage(display,resource_info,windows,image);
10817 return(MagickTrue);
10821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10825 + X P r i n t I m a g e %
10829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10831 % XPrintImage() prints an image to a Postscript printer.
10833 % The format of the XPrintImage method is:
10835 % MagickBooleanType XPrintImage(Display *display,
10836 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10838 % A description of each parameter follows:
10840 % o display: Specifies a connection to an X server; returned from
10843 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10845 % o windows: Specifies a pointer to a XWindows structure.
10847 % o image: the image.
10850 static MagickBooleanType XPrintImage(Display *display,
10851 XResourceInfo *resource_info,XWindows *windows,Image *image)
10854 filename[MaxTextExtent],
10855 geometry[MaxTextExtent];
10867 Request Postscript page geometry from user.
10869 image_info=CloneImageInfo(resource_info->image_info);
10870 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
10871 if (image_info->page != (char *) NULL)
10872 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10873 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10874 "Select Postscript Page Geometry:",geometry);
10875 if (*geometry == '\0')
10876 return(MagickTrue);
10877 image_info->page=GetPageGeometry(geometry);
10879 Apply image transforms.
10881 XSetCursorState(display,windows,MagickTrue);
10882 XCheckRefreshWindows(display,windows);
10883 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10884 if (print_image == (Image *) NULL)
10885 return(MagickFalse);
10886 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
10887 windows->image.ximage->width,windows->image.ximage->height);
10888 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10892 (void) AcquireUniqueFilename(filename);
10893 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
10895 status=WriteImage(image_info,print_image);
10896 (void) RelinquishUniqueFileResource(filename);
10897 print_image=DestroyImage(print_image);
10898 image_info=DestroyImageInfo(image_info);
10899 XSetCursorState(display,windows,MagickFalse);
10900 return(status != 0 ? MagickTrue : MagickFalse);
10904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10908 + X R O I I m a g e %
10912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10914 % XROIImage() applies an image processing technique to a region of interest.
10916 % The format of the XROIImage method is:
10918 % MagickBooleanType XROIImage(Display *display,
10919 % XResourceInfo *resource_info,XWindows *windows,Image **image)
10921 % A description of each parameter follows:
10923 % o display: Specifies a connection to an X server; returned from
10926 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10928 % o windows: Specifies a pointer to a XWindows structure.
10930 % o image: the image; returned from ReadImage.
10933 static MagickBooleanType XROIImage(Display *display,
10934 XResourceInfo *resource_info,XWindows *windows,Image **image)
10936 #define ApplyMenus 7
10986 "Contrast Stretch...",
10987 "Sigmoidal Contrast...",
11021 "Charcoal Draw...",
11024 *MiscellanyMenu[] =
11035 **Menus[ApplyMenus] =
11046 static const CommandType
11069 TransformCommands[] =
11073 RotateRightCommand,
11076 EnhanceCommands[] =
11084 ContrastStretchCommand,
11085 SigmoidalContrastCommand,
11093 EffectsCommands[] =
11097 ReduceNoiseCommand,
11116 CharcoalDrawCommand
11118 MiscellanyCommands[] =
11122 ShowPreviewCommand,
11123 ShowHistogramCommand,
11132 static const CommandType
11133 *Commands[ApplyMenus] =
11145 command[MaxTextExtent],
11146 text[MaxTextExtent];
11166 MagickProgressMonitor
11185 Map Command widget.
11187 (void) CloneString(&windows->command.name,"ROI");
11188 windows->command.data=0;
11189 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11190 (void) XMapRaised(display,windows->command.id);
11191 XClientMessage(display,windows->image.id,windows->im_protocols,
11192 windows->im_update_widget,CurrentTime);
11194 Track pointer until button 1 is pressed.
11196 XQueryPosition(display,windows->image.id,&x,&y);
11197 (void) XSelectInput(display,windows->image.id,
11198 windows->image.attributes.event_mask | PointerMotionMask);
11199 roi_info.x=(ssize_t) windows->image.x+x;
11200 roi_info.y=(ssize_t) windows->image.y+y;
11203 cursor=XCreateFontCursor(display,XC_fleur);
11204 state=DefaultState;
11207 if (windows->info.mapped != MagickFalse)
11210 Display pointer position.
11212 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
11213 (long) roi_info.x,(long) roi_info.y);
11214 XInfoWidget(display,windows,text);
11217 Wait for next event.
11219 XScreenEvent(display,windows,&event);
11220 if (event.xany.window == windows->command.id)
11223 Select a command from the Command widget.
11225 id=XCommandWidget(display,windows,ROIMenu,&event);
11228 switch (ROICommands[id])
11230 case ROIHelpCommand:
11232 XTextViewWidget(display,resource_info,windows,MagickFalse,
11233 "Help Viewer - Region of Interest",ImageROIHelp);
11236 case ROIDismissCommand:
11241 state|=EscapeState;
11250 switch (event.type)
11254 if (event.xbutton.button != Button1)
11256 if (event.xbutton.window != windows->image.id)
11259 Note first corner of region of interest rectangle-- exit loop.
11261 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11262 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11263 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11267 case ButtonRelease:
11276 if (event.xkey.window != windows->image.id)
11279 Respond to a user key press.
11281 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11282 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11283 switch ((int) key_symbol)
11291 state|=EscapeState;
11298 XTextViewWidget(display,resource_info,windows,MagickFalse,
11299 "Help Viewer - Region of Interest",ImageROIHelp);
11304 (void) XBell(display,0);
11313 Map and unmap Info widget as text cursor crosses its boundaries.
11317 if (windows->info.mapped != MagickFalse)
11319 if ((x < (int) (windows->info.x+windows->info.width)) &&
11320 (y < (int) (windows->info.y+windows->info.height)))
11321 (void) XWithdrawWindow(display,windows->info.id,
11322 windows->info.screen);
11325 if ((x > (int) (windows->info.x+windows->info.width)) ||
11326 (y > (int) (windows->info.y+windows->info.height)))
11327 (void) XMapWindow(display,windows->info.id);
11328 roi_info.x=(ssize_t) windows->image.x+x;
11329 roi_info.y=(ssize_t) windows->image.y+y;
11335 } while ((state & ExitState) == 0);
11336 (void) XSelectInput(display,windows->image.id,
11337 windows->image.attributes.event_mask);
11338 if ((state & EscapeState) != 0)
11341 User want to exit without region of interest.
11343 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11344 (void) XFreeCursor(display,cursor);
11345 return(MagickTrue);
11347 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11351 Size rectangle as pointer moves until the mouse button is released.
11353 x=(int) roi_info.x;
11354 y=(int) roi_info.y;
11357 state=DefaultState;
11360 highlight_info=roi_info;
11361 highlight_info.x=roi_info.x-windows->image.x;
11362 highlight_info.y=roi_info.y-windows->image.y;
11363 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11366 Display info and draw region of interest rectangle.
11368 if (windows->info.mapped == MagickFalse)
11369 (void) XMapWindow(display,windows->info.id);
11370 (void) FormatLocaleString(text,MaxTextExtent,
11371 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11372 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11373 XInfoWidget(display,windows,text);
11374 XHighlightRectangle(display,windows->image.id,
11375 windows->image.highlight_context,&highlight_info);
11378 if (windows->info.mapped != MagickFalse)
11379 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11381 Wait for next event.
11383 XScreenEvent(display,windows,&event);
11384 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11385 XHighlightRectangle(display,windows->image.id,
11386 windows->image.highlight_context,&highlight_info);
11387 switch (event.type)
11391 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11392 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11395 case ButtonRelease:
11398 User has committed to region of interest rectangle.
11400 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11401 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11402 XSetCursorState(display,windows,MagickFalse);
11404 if (LocaleCompare(windows->command.name,"Apply") == 0)
11406 (void) CloneString(&windows->command.name,"Apply");
11407 windows->command.data=ApplyMenus;
11408 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11415 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11416 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11421 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11422 ((state & ExitState) != 0))
11425 Check boundary conditions.
11427 if (roi_info.x < 0)
11430 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11431 roi_info.x=(ssize_t) windows->image.ximage->width;
11432 if ((int) roi_info.x < x)
11433 roi_info.width=(unsigned int) (x-roi_info.x);
11436 roi_info.width=(unsigned int) (roi_info.x-x);
11437 roi_info.x=(ssize_t) x;
11439 if (roi_info.y < 0)
11442 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11443 roi_info.y=(ssize_t) windows->image.ximage->height;
11444 if ((int) roi_info.y < y)
11445 roi_info.height=(unsigned int) (y-roi_info.y);
11448 roi_info.height=(unsigned int) (roi_info.y-y);
11449 roi_info.y=(ssize_t) y;
11452 } while ((state & ExitState) == 0);
11454 Wait for user to grab a corner of the rectangle or press return.
11456 state=DefaultState;
11457 command_type=NullCommand;
11458 (void) XMapWindow(display,windows->info.id);
11461 if (windows->info.mapped != MagickFalse)
11464 Display pointer position.
11466 (void) FormatLocaleString(text,MaxTextExtent,
11467 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11468 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11469 XInfoWidget(display,windows,text);
11471 highlight_info=roi_info;
11472 highlight_info.x=roi_info.x-windows->image.x;
11473 highlight_info.y=roi_info.y-windows->image.y;
11474 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11476 state|=EscapeState;
11480 if ((state & UpdateRegionState) != 0)
11482 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11483 switch (command_type)
11488 (void) XMagickCommand(display,resource_info,windows,command_type,
11495 Region of interest is relative to image configuration.
11497 progress_monitor=SetImageProgressMonitor(*image,
11498 (MagickProgressMonitor) NULL,(*image)->client_data);
11499 crop_info=roi_info;
11500 width=(unsigned int) (*image)->columns;
11501 height=(unsigned int) (*image)->rows;
11504 if (windows->image.crop_geometry != (char *) NULL)
11505 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11507 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11509 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11510 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11511 scale_factor=(MagickRealType)
11512 height/windows->image.ximage->height;
11514 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11515 crop_info.height=(unsigned int)
11516 (scale_factor*crop_info.height+0.5);
11517 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11518 (void) SetImageProgressMonitor(*image,progress_monitor,
11519 (*image)->client_data);
11520 if (roi_image == (Image *) NULL)
11523 Apply image processing technique to the region of interest.
11525 windows->image.orphan=MagickTrue;
11526 (void) XMagickCommand(display,resource_info,windows,command_type,
11528 progress_monitor=SetImageProgressMonitor(*image,
11529 (MagickProgressMonitor) NULL,(*image)->client_data);
11530 (void) XMagickCommand(display,resource_info,windows,
11531 SaveToUndoBufferCommand,image);
11532 windows->image.orphan=MagickFalse;
11533 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11534 crop_info.x,crop_info.y);
11535 roi_image=DestroyImage(roi_image);
11536 (void) SetImageProgressMonitor(*image,progress_monitor,
11537 (*image)->client_data);
11541 if (command_type != InfoCommand)
11543 XConfigureImageColormap(display,resource_info,windows,*image);
11544 (void) XConfigureImage(display,resource_info,windows,*image);
11546 XCheckRefreshWindows(display,windows);
11547 XInfoWidget(display,windows,text);
11548 (void) XSetFunction(display,windows->image.highlight_context,
11550 state&=(~UpdateRegionState);
11552 XHighlightRectangle(display,windows->image.id,
11553 windows->image.highlight_context,&highlight_info);
11554 XScreenEvent(display,windows,&event);
11555 if (event.xany.window == windows->command.id)
11558 Select a command from the Command widget.
11560 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11561 command_type=NullCommand;
11562 id=XCommandWidget(display,windows,ApplyMenu,&event);
11565 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11566 command_type=ApplyCommands[id];
11567 if (id < ApplyMenus)
11570 Select a command from a pop-up menu.
11572 entry=XMenuWidget(display,windows,ApplyMenu[id],
11573 (const char **) Menus[id],command);
11576 (void) CopyMagickString(command,Menus[id][entry],
11578 command_type=Commands[id][entry];
11582 (void) XSetFunction(display,windows->image.highlight_context,
11584 XHighlightRectangle(display,windows->image.id,
11585 windows->image.highlight_context,&highlight_info);
11586 if (command_type == HelpCommand)
11588 (void) XSetFunction(display,windows->image.highlight_context,
11590 XTextViewWidget(display,resource_info,windows,MagickFalse,
11591 "Help Viewer - Region of Interest",ImageROIHelp);
11592 (void) XSetFunction(display,windows->image.highlight_context,
11596 if (command_type == QuitCommand)
11601 state|=EscapeState;
11605 if (command_type != NullCommand)
11606 state|=UpdateRegionState;
11609 XHighlightRectangle(display,windows->image.id,
11610 windows->image.highlight_context,&highlight_info);
11611 switch (event.type)
11615 x=windows->image.x;
11616 y=windows->image.y;
11617 if (event.xbutton.button != Button1)
11619 if (event.xbutton.window != windows->image.id)
11621 x=windows->image.x+event.xbutton.x;
11622 y=windows->image.y+event.xbutton.y;
11623 if ((x < (int) (roi_info.x+RoiDelta)) &&
11624 (x > (int) (roi_info.x-RoiDelta)) &&
11625 (y < (int) (roi_info.y+RoiDelta)) &&
11626 (y > (int) (roi_info.y-RoiDelta)))
11628 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11629 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11630 state|=UpdateConfigurationState;
11633 if ((x < (int) (roi_info.x+RoiDelta)) &&
11634 (x > (int) (roi_info.x-RoiDelta)) &&
11635 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11636 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11638 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11639 state|=UpdateConfigurationState;
11642 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11643 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11644 (y < (int) (roi_info.y+RoiDelta)) &&
11645 (y > (int) (roi_info.y-RoiDelta)))
11647 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11648 state|=UpdateConfigurationState;
11651 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11652 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11653 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11654 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11656 state|=UpdateConfigurationState;
11660 case ButtonRelease:
11662 if (event.xbutton.window == windows->pan.id)
11663 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11664 (highlight_info.y != crop_info.y-windows->image.y))
11665 XHighlightRectangle(display,windows->image.id,
11666 windows->image.highlight_context,&highlight_info);
11667 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11668 event.xbutton.time);
11673 if (event.xexpose.window == windows->image.id)
11674 if (event.xexpose.count == 0)
11676 event.xexpose.x=(int) highlight_info.x;
11677 event.xexpose.y=(int) highlight_info.y;
11678 event.xexpose.width=(int) highlight_info.width;
11679 event.xexpose.height=(int) highlight_info.height;
11680 XRefreshWindow(display,&windows->image,&event);
11682 if (event.xexpose.window == windows->info.id)
11683 if (event.xexpose.count == 0)
11684 XInfoWidget(display,windows,text);
11692 if (event.xkey.window != windows->image.id)
11695 Respond to a user key press.
11697 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11698 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11699 switch ((int) key_symbol)
11706 state|=EscapeState;
11715 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11716 roi_info.y=(ssize_t) (windows->image.height/2L-
11717 roi_info.height/2L);
11749 (void) XSetFunction(display,windows->image.highlight_context,
11751 XTextViewWidget(display,resource_info,windows,MagickFalse,
11752 "Help Viewer - Region of Interest",ImageROIHelp);
11753 (void) XSetFunction(display,windows->image.highlight_context,
11759 command_type=XImageWindowCommand(display,resource_info,windows,
11760 event.xkey.state,key_symbol,image);
11761 if (command_type != NullCommand)
11762 state|=UpdateRegionState;
11766 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11774 if (event.xbutton.window != windows->image.id)
11777 Map and unmap Info widget as text cursor crosses its boundaries.
11781 if (windows->info.mapped != MagickFalse)
11783 if ((x < (int) (windows->info.x+windows->info.width)) &&
11784 (y < (int) (windows->info.y+windows->info.height)))
11785 (void) XWithdrawWindow(display,windows->info.id,
11786 windows->info.screen);
11789 if ((x > (int) (windows->info.x+windows->info.width)) ||
11790 (y > (int) (windows->info.y+windows->info.height)))
11791 (void) XMapWindow(display,windows->info.id);
11792 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11793 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11796 case SelectionRequest:
11801 XSelectionRequestEvent
11805 Set primary selection.
11807 (void) FormatLocaleString(text,MaxTextExtent,
11808 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11809 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11810 request=(&(event.xselectionrequest));
11811 (void) XChangeProperty(request->display,request->requestor,
11812 request->property,request->target,8,PropModeReplace,
11813 (unsigned char *) text,(int) strlen(text));
11814 notify.type=SelectionNotify;
11815 notify.display=request->display;
11816 notify.requestor=request->requestor;
11817 notify.selection=request->selection;
11818 notify.target=request->target;
11819 notify.time=request->time;
11820 if (request->property == None)
11821 notify.property=request->target;
11823 notify.property=request->property;
11824 (void) XSendEvent(request->display,request->requestor,False,0,
11825 (XEvent *) ¬ify);
11830 if ((state & UpdateConfigurationState) != 0)
11832 (void) XPutBackEvent(display,&event);
11833 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11836 } while ((state & ExitState) == 0);
11837 } while ((state & ExitState) == 0);
11838 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11839 XSetCursorState(display,windows,MagickFalse);
11840 if ((state & EscapeState) != 0)
11841 return(MagickTrue);
11842 return(MagickTrue);
11846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11850 + X R o t a t e I m a g e %
11854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11856 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11857 % rotation angle is computed from the slope of a line drawn by the user.
11859 % The format of the XRotateImage method is:
11861 % MagickBooleanType XRotateImage(Display *display,
11862 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11865 % A description of each parameter follows:
11867 % o display: Specifies a connection to an X server; returned from
11870 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11872 % o windows: Specifies a pointer to a XWindows structure.
11874 % o degrees: Specifies the number of degrees to rotate the image.
11876 % o image: the image.
11879 static MagickBooleanType XRotateImage(Display *display,
11880 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11893 direction = HorizontalRotateCommand;
11895 static const ModeType
11896 DirectionCommands[] =
11898 HorizontalRotateCommand,
11899 VerticalRotateCommand
11903 RotateColorCommand,
11904 RotateDirectionCommand,
11906 RotateDismissCommand
11909 static unsigned int
11913 command[MaxTextExtent],
11914 text[MaxTextExtent];
11925 normalized_degrees;
11935 if (degrees == 0.0)
11950 Map Command widget.
11952 (void) CloneString(&windows->command.name,"Rotate");
11953 windows->command.data=2;
11954 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11955 (void) XMapRaised(display,windows->command.id);
11956 XClientMessage(display,windows->image.id,windows->im_protocols,
11957 windows->im_update_widget,CurrentTime);
11959 Wait for first button press.
11961 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11962 XQueryPosition(display,windows->image.id,&x,&y);
11967 state=DefaultState;
11970 XHighlightLine(display,windows->image.id,
11971 windows->image.highlight_context,&rotate_info);
11973 Wait for next event.
11975 XScreenEvent(display,windows,&event);
11976 XHighlightLine(display,windows->image.id,
11977 windows->image.highlight_context,&rotate_info);
11978 if (event.xany.window == windows->command.id)
11981 Select a command from the Command widget.
11983 id=XCommandWidget(display,windows,RotateMenu,&event);
11986 (void) XSetFunction(display,windows->image.highlight_context,
11988 switch (RotateCommands[id])
11990 case RotateColorCommand:
11993 *ColorMenu[MaxNumberPens];
12002 Initialize menu selections.
12004 for (i=0; i < (int) (MaxNumberPens-2); i++)
12005 ColorMenu[i]=resource_info->pen_colors[i];
12006 ColorMenu[MaxNumberPens-2]="Browser...";
12007 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12009 Select a pen color from the pop-up menu.
12011 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12012 (const char **) ColorMenu,command);
12013 if (pen_number < 0)
12015 if (pen_number == (MaxNumberPens-2))
12018 color_name[MaxTextExtent] = "gray";
12021 Select a pen color from a dialog.
12023 resource_info->pen_colors[pen_number]=color_name;
12024 XColorBrowserWidget(display,windows,"Select",color_name);
12025 if (*color_name == '\0')
12031 (void) XParseColor(display,windows->map_info->colormap,
12032 resource_info->pen_colors[pen_number],&color);
12033 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12034 (unsigned int) MaxColors,&color);
12035 windows->pixel_info->pen_colors[pen_number]=color;
12036 pen_id=(unsigned int) pen_number;
12039 case RotateDirectionCommand:
12050 Select a command from the pop-up menu.
12052 id=XMenuWidget(display,windows,RotateMenu[id],
12053 Directions,command);
12055 direction=DirectionCommands[id];
12058 case RotateHelpCommand:
12060 XTextViewWidget(display,resource_info,windows,MagickFalse,
12061 "Help Viewer - Image Rotation",ImageRotateHelp);
12064 case RotateDismissCommand:
12069 state|=EscapeState;
12076 (void) XSetFunction(display,windows->image.highlight_context,
12080 switch (event.type)
12084 if (event.xbutton.button != Button1)
12086 if (event.xbutton.window != windows->image.id)
12091 (void) XSetFunction(display,windows->image.highlight_context,
12093 rotate_info.x1=event.xbutton.x;
12094 rotate_info.y1=event.xbutton.y;
12098 case ButtonRelease:
12105 command[MaxTextExtent];
12110 if (event.xkey.window != windows->image.id)
12113 Respond to a user key press.
12115 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12116 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12117 switch ((int) key_symbol)
12125 state|=EscapeState;
12132 (void) XSetFunction(display,windows->image.highlight_context,
12134 XTextViewWidget(display,resource_info,windows,MagickFalse,
12135 "Help Viewer - Image Rotation",ImageRotateHelp);
12136 (void) XSetFunction(display,windows->image.highlight_context,
12142 (void) XBell(display,0);
12150 rotate_info.x1=event.xmotion.x;
12151 rotate_info.y1=event.xmotion.y;
12154 rotate_info.x2=rotate_info.x1;
12155 rotate_info.y2=rotate_info.y1;
12156 if (direction == HorizontalRotateCommand)
12157 rotate_info.x2+=32;
12159 rotate_info.y2-=32;
12160 } while ((state & ExitState) == 0);
12161 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12162 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12163 if ((state & EscapeState) != 0)
12164 return(MagickTrue);
12166 Draw line as pointer moves until the mouse button is released.
12169 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12170 state=DefaultState;
12176 Display info and draw rotation line.
12178 if (windows->info.mapped == MagickFalse)
12179 (void) XMapWindow(display,windows->info.id);
12180 (void) FormatLocaleString(text,MaxTextExtent," %g",
12181 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12182 XInfoWidget(display,windows,text);
12183 XHighlightLine(display,windows->image.id,
12184 windows->image.highlight_context,&rotate_info);
12187 if (windows->info.mapped != MagickFalse)
12188 (void) XWithdrawWindow(display,windows->info.id,
12189 windows->info.screen);
12191 Wait for next event.
12193 XScreenEvent(display,windows,&event);
12195 XHighlightLine(display,windows->image.id,
12196 windows->image.highlight_context,&rotate_info);
12197 switch (event.type)
12201 case ButtonRelease:
12204 User has committed to rotation line.
12206 rotate_info.x2=event.xbutton.x;
12207 rotate_info.y2=event.xbutton.y;
12215 rotate_info.x2=event.xmotion.x;
12216 rotate_info.y2=event.xmotion.y;
12222 Check boundary conditions.
12224 if (rotate_info.x2 < 0)
12227 if (rotate_info.x2 > (int) windows->image.width)
12228 rotate_info.x2=(short) windows->image.width;
12229 if (rotate_info.y2 < 0)
12232 if (rotate_info.y2 > (int) windows->image.height)
12233 rotate_info.y2=(short) windows->image.height;
12235 Compute rotation angle from the slope of the line.
12238 distance=(unsigned int)
12239 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12240 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12242 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12243 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12244 } while ((state & ExitState) == 0);
12245 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12246 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12248 return(MagickTrue);
12250 if (direction == VerticalRotateCommand)
12252 if (degrees == 0.0)
12253 return(MagickTrue);
12257 normalized_degrees=degrees;
12258 while (normalized_degrees < -45.0)
12259 normalized_degrees+=360.0;
12260 for (rotations=0; normalized_degrees > 45.0; rotations++)
12261 normalized_degrees-=90.0;
12262 if (normalized_degrees != 0.0)
12263 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12264 XSetCursorState(display,windows,MagickTrue);
12265 XCheckRefreshWindows(display,windows);
12266 (*image)->background_color.red=ScaleShortToQuantum(
12267 windows->pixel_info->pen_colors[pen_id].red);
12268 (*image)->background_color.green=ScaleShortToQuantum(
12269 windows->pixel_info->pen_colors[pen_id].green);
12270 (*image)->background_color.blue=ScaleShortToQuantum(
12271 windows->pixel_info->pen_colors[pen_id].blue);
12272 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12273 XSetCursorState(display,windows,MagickFalse);
12274 if (rotate_image == (Image *) NULL)
12275 return(MagickFalse);
12276 *image=DestroyImage(*image);
12277 *image=rotate_image;
12278 if (windows->image.crop_geometry != (char *) NULL)
12281 Rotate crop geometry.
12283 width=(unsigned int) (*image)->columns;
12284 height=(unsigned int) (*image)->rows;
12285 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12286 switch (rotations % 4)
12296 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12297 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12304 Rotate 180 degrees.
12306 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12307 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12313 Rotate 270 degrees.
12315 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12316 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12321 if (windows->image.orphan != MagickFalse)
12322 return(MagickTrue);
12323 if (normalized_degrees != 0.0)
12326 Update image colormap.
12328 windows->image.window_changes.width=(int) (*image)->columns;
12329 windows->image.window_changes.height=(int) (*image)->rows;
12330 if (windows->image.crop_geometry != (char *) NULL)
12333 Obtain dimensions of image from crop geometry.
12335 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12337 windows->image.window_changes.width=(int) width;
12338 windows->image.window_changes.height=(int) height;
12340 XConfigureImageColormap(display,resource_info,windows,*image);
12343 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12345 windows->image.window_changes.width=windows->image.ximage->height;
12346 windows->image.window_changes.height=windows->image.ximage->width;
12349 Update image configuration.
12351 (void) XConfigureImage(display,resource_info,windows,*image);
12352 return(MagickTrue);
12356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12360 + X S a v e I m a g e %
12364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12366 % XSaveImage() saves an image to a file.
12368 % The format of the XSaveImage method is:
12370 % MagickBooleanType XSaveImage(Display *display,
12371 % XResourceInfo *resource_info,XWindows *windows,Image *image)
12373 % A description of each parameter follows:
12375 % o display: Specifies a connection to an X server; returned from
12378 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12380 % o windows: Specifies a pointer to a XWindows structure.
12382 % o image: the image.
12385 static MagickBooleanType XSaveImage(Display *display,
12386 XResourceInfo *resource_info,XWindows *windows,Image *image)
12389 filename[MaxTextExtent],
12390 geometry[MaxTextExtent];
12402 Request file name from user.
12404 if (resource_info->write_filename != (char *) NULL)
12405 (void) CopyMagickString(filename,resource_info->write_filename,
12410 path[MaxTextExtent];
12415 GetPathComponent(image->filename,HeadPath,path);
12416 GetPathComponent(image->filename,TailPath,filename);
12417 status=chdir(path);
12419 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12420 FileOpenError,"UnableToOpenFile","%s",path);
12422 XFileBrowserWidget(display,windows,"Save",filename);
12423 if (*filename == '\0')
12424 return(MagickTrue);
12425 if (IsPathAccessible(filename) != MagickFalse)
12431 File exists-- seek user's permission before overwriting.
12433 status=XConfirmWidget(display,windows,"Overwrite",filename);
12435 return(MagickTrue);
12437 image_info=CloneImageInfo(resource_info->image_info);
12438 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12439 (void) SetImageInfo(image_info,1,&image->exception);
12440 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12441 (LocaleCompare(image_info->magick,"JPG") == 0))
12444 quality[MaxTextExtent];
12450 Request JPEG quality from user.
12452 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
12454 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12456 if (*quality == '\0')
12457 return(MagickTrue);
12458 image->quality=StringToUnsignedLong(quality);
12459 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12461 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12462 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12463 (LocaleCompare(image_info->magick,"PS") == 0) ||
12464 (LocaleCompare(image_info->magick,"PS2") == 0))
12467 geometry[MaxTextExtent];
12470 Request page geometry from user.
12472 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12473 if (LocaleCompare(image_info->magick,"PDF") == 0)
12474 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12475 if (image_info->page != (char *) NULL)
12476 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12477 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12478 "Select page geometry:",geometry);
12479 if (*geometry != '\0')
12480 image_info->page=GetPageGeometry(geometry);
12483 Apply image transforms.
12485 XSetCursorState(display,windows,MagickTrue);
12486 XCheckRefreshWindows(display,windows);
12487 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12488 if (save_image == (Image *) NULL)
12489 return(MagickFalse);
12490 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
12491 windows->image.ximage->width,windows->image.ximage->height);
12492 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12496 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12497 status=WriteImage(image_info,save_image);
12498 if (status != MagickFalse)
12499 image->taint=MagickFalse;
12500 save_image=DestroyImage(save_image);
12501 image_info=DestroyImageInfo(image_info);
12502 XSetCursorState(display,windows,MagickFalse);
12503 return(status != 0 ? MagickTrue : MagickFalse);
12507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12511 + X S c r e e n E v e n t %
12515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12517 % XScreenEvent() handles global events associated with the Pan and Magnify
12520 % The format of the XScreenEvent function is:
12522 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12524 % A description of each parameter follows:
12526 % o display: Specifies a pointer to the Display structure; returned from
12529 % o windows: Specifies a pointer to a XWindows structure.
12531 % o event: Specifies a pointer to a X11 XEvent structure.
12536 #if defined(__cplusplus) || defined(c_plusplus)
12540 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12545 windows=(XWindows *) data;
12546 if ((event->type == ClientMessage) &&
12547 (event->xclient.window == windows->image.id))
12548 return(MagickFalse);
12549 return(MagickTrue);
12552 #if defined(__cplusplus) || defined(c_plusplus)
12556 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12562 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12563 if (event->xany.window == windows->command.id)
12565 switch (event->type)
12568 case ButtonRelease:
12570 if ((event->xbutton.button == Button3) &&
12571 (event->xbutton.state & Mod1Mask))
12574 Convert Alt-Button3 to Button2.
12576 event->xbutton.button=Button2;
12577 event->xbutton.state&=(~Mod1Mask);
12579 if (event->xbutton.window == windows->backdrop.id)
12581 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12582 event->xbutton.time);
12585 if (event->xbutton.window == windows->pan.id)
12587 XPanImage(display,windows,event);
12590 if (event->xbutton.window == windows->image.id)
12591 if (event->xbutton.button == Button2)
12594 Update magnified image.
12596 x=event->xbutton.x;
12597 y=event->xbutton.y;
12601 if (x >= (int) windows->image.width)
12602 x=(int) (windows->image.width-1);
12603 windows->magnify.x=(int) windows->image.x+x;
12607 if (y >= (int) windows->image.height)
12608 y=(int) (windows->image.height-1);
12609 windows->magnify.y=windows->image.y+y;
12610 if (windows->magnify.mapped == MagickFalse)
12611 (void) XMapRaised(display,windows->magnify.id);
12612 XMakeMagnifyImage(display,windows);
12613 if (event->type == ButtonRelease)
12614 (void) XWithdrawWindow(display,windows->info.id,
12615 windows->info.screen);
12620 case ClientMessage:
12623 If client window delete message, exit.
12625 if (event->xclient.message_type != windows->wm_protocols)
12627 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12629 if (event->xclient.window == windows->magnify.id)
12631 (void) XWithdrawWindow(display,windows->magnify.id,
12632 windows->magnify.screen);
12637 case ConfigureNotify:
12639 if (event->xconfigure.window == windows->magnify.id)
12645 Magnify window has a new configuration.
12647 windows->magnify.width=(unsigned int) event->xconfigure.width;
12648 windows->magnify.height=(unsigned int) event->xconfigure.height;
12649 if (windows->magnify.mapped == MagickFalse)
12652 while ((int) magnify <= event->xconfigure.width)
12654 while ((int) magnify <= event->xconfigure.height)
12657 if (((int) magnify != event->xconfigure.width) ||
12658 ((int) magnify != event->xconfigure.height))
12663 window_changes.width=(int) magnify;
12664 window_changes.height=(int) magnify;
12665 (void) XReconfigureWMWindow(display,windows->magnify.id,
12666 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12670 XMakeMagnifyImage(display,windows);
12677 if (event->xexpose.window == windows->image.id)
12679 XRefreshWindow(display,&windows->image,event);
12682 if (event->xexpose.window == windows->pan.id)
12683 if (event->xexpose.count == 0)
12685 XDrawPanRectangle(display,windows);
12688 if (event->xexpose.window == windows->magnify.id)
12689 if (event->xexpose.count == 0)
12691 XMakeMagnifyImage(display,windows);
12699 command[MaxTextExtent];
12704 if (event->xkey.window != windows->magnify.id)
12707 Respond to a user key press.
12709 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12710 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12711 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12716 if (event->xmap.window == windows->magnify.id)
12718 windows->magnify.mapped=MagickTrue;
12719 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12722 if (event->xmap.window == windows->info.id)
12724 windows->info.mapped=MagickTrue;
12731 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12732 if (event->xmotion.window == windows->image.id)
12733 if (windows->magnify.mapped != MagickFalse)
12736 Update magnified image.
12738 x=event->xmotion.x;
12739 y=event->xmotion.y;
12743 if (x >= (int) windows->image.width)
12744 x=(int) (windows->image.width-1);
12745 windows->magnify.x=(int) windows->image.x+x;
12749 if (y >= (int) windows->image.height)
12750 y=(int) (windows->image.height-1);
12751 windows->magnify.y=windows->image.y+y;
12752 XMakeMagnifyImage(display,windows);
12758 if (event->xunmap.window == windows->magnify.id)
12760 windows->magnify.mapped=MagickFalse;
12763 if (event->xunmap.window == windows->info.id)
12765 windows->info.mapped=MagickFalse;
12776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12780 + X S e t C r o p G e o m e t r y %
12784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12786 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12787 % and translates it to a cropping geometry relative to the image.
12789 % The format of the XSetCropGeometry method is:
12791 % void XSetCropGeometry(Display *display,XWindows *windows,
12792 % RectangleInfo *crop_info,Image *image)
12794 % A description of each parameter follows:
12796 % o display: Specifies a connection to an X server; returned from
12799 % o windows: Specifies a pointer to a XWindows structure.
12801 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12802 % Image window to crop.
12804 % o image: the image.
12807 static void XSetCropGeometry(Display *display,XWindows *windows,
12808 RectangleInfo *crop_info,Image *image)
12811 text[MaxTextExtent];
12824 if (windows->info.mapped != MagickFalse)
12827 Display info on cropping rectangle.
12829 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12830 (double) crop_info->width,(double) crop_info->height,(double)
12831 crop_info->x,(double) crop_info->y);
12832 XInfoWidget(display,windows,text);
12835 Cropping geometry is relative to any previous crop geometry.
12839 width=(unsigned int) image->columns;
12840 height=(unsigned int) image->rows;
12841 if (windows->image.crop_geometry != (char *) NULL)
12842 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12844 windows->image.crop_geometry=AcquireString((char *) NULL);
12846 Define the crop geometry string from the cropping rectangle.
12848 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12849 if (crop_info->x > 0)
12850 x+=(int) (scale_factor*crop_info->x+0.5);
12851 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12854 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12855 if (crop_info->y > 0)
12856 y+=(int) (scale_factor*crop_info->y+0.5);
12857 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12860 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12861 "%ux%u%+d%+d",width,height,x,y);
12865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12869 + X T i l e I m a g e %
12873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12875 % XTileImage() loads or deletes a selected tile from a visual image directory.
12876 % The load or delete command is chosen from a menu.
12878 % The format of the XTileImage method is:
12880 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
12881 % XWindows *windows,Image *image,XEvent *event)
12883 % A description of each parameter follows:
12885 % o tile_image: XTileImage reads or deletes the tile image
12886 % and returns it. A null image is returned if an error occurs.
12888 % o display: Specifies a connection to an X server; returned from
12891 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12893 % o windows: Specifies a pointer to a XWindows structure.
12895 % o image: the image; returned from ReadImage.
12897 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
12898 % the entire image is refreshed.
12901 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12902 XWindows *windows,Image *image,XEvent *event)
12915 static const ModeType
12926 command[MaxTextExtent],
12927 filename[MaxTextExtent];
12954 Tile image is relative to montage image configuration.
12958 width=(unsigned int) image->columns;
12959 height=(unsigned int) image->rows;
12960 if (windows->image.crop_geometry != (char *) NULL)
12961 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12962 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12963 event->xbutton.x+=windows->image.x;
12964 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12965 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12966 event->xbutton.y+=windows->image.y;
12967 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12969 Determine size and location of each tile in the visual image directory.
12971 width=(unsigned int) image->columns;
12972 height=(unsigned int) image->rows;
12975 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
12976 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
12977 (event->xbutton.x-x)/width;
12981 Button press is outside any tile.
12983 (void) XBell(display,0);
12984 return((Image *) NULL);
12987 Determine file name from the tile directory.
12989 p=image->directory;
12990 for (i=tile; (i != 0) && (*p != '\0'); )
12999 Button press is outside any tile.
13001 (void) XBell(display,0);
13002 return((Image *) NULL);
13005 Select a command from the pop-up menu.
13007 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13009 return((Image *) NULL);
13011 while ((*q != '\n') && (*q != '\0'))
13013 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13015 Perform command for the selected tile.
13017 XSetCursorState(display,windows,MagickTrue);
13018 XCheckRefreshWindows(display,windows);
13019 tile_image=NewImageList();
13020 switch (TileCommands[id])
13022 case TileLoadCommand:
13027 XCheckRefreshWindows(display,windows);
13028 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13030 (void) CopyMagickString(resource_info->image_info->filename,filename,
13032 tile_image=ReadImage(resource_info->image_info,&image->exception);
13033 CatchException(&image->exception);
13034 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13037 case TileNextCommand:
13040 Display next image.
13042 XClientMessage(display,windows->image.id,windows->im_protocols,
13043 windows->im_next_image,CurrentTime);
13046 case TileFormerCommand:
13049 Display former image.
13051 XClientMessage(display,windows->image.id,windows->im_protocols,
13052 windows->im_former_image,CurrentTime);
13055 case TileDeleteCommand:
13060 if (IsPathAccessible(filename) == MagickFalse)
13062 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13065 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13068 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13069 if (status != MagickFalse)
13071 XNoticeWidget(display,windows,"Unable to delete image file:",
13076 case TileUpdateCommand:
13091 register PixelPacket
13095 Ensure all the images exist.
13098 for (p=image->directory; *p != '\0'; p++)
13104 while ((*q != '\n') && (*q != '\0'))
13106 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13108 if (IsPathAccessible(filename) != MagickFalse)
13114 Overwrite tile with background color.
13116 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13117 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13118 exception=(&image->exception);
13119 image_view=AcquireCacheView(image);
13120 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13121 for (i=0; i < (int) height; i++)
13123 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13124 y_offset+i,width,1,exception);
13125 if (s == (PixelPacket *) NULL)
13127 for (j=0; j < (int) width; j++)
13129 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13132 image_view=DestroyCacheView(image_view);
13135 windows->image.window_changes.width=(int) image->columns;
13136 windows->image.window_changes.height=(int) image->rows;
13137 XConfigureImageColormap(display,resource_info,windows,image);
13138 (void) XConfigureImage(display,resource_info,windows,image);
13144 XSetCursorState(display,windows,MagickFalse);
13145 return(tile_image);
13149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13153 + X T r a n s l a t e I m a g e %
13157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13159 % XTranslateImage() translates the image within an Image window by one pixel
13160 % as specified by the key symbol. If the image has a `montage string the
13161 % translation is respect to the width and height contained within the string.
13163 % The format of the XTranslateImage method is:
13165 % void XTranslateImage(Display *display,XWindows *windows,
13166 % Image *image,const KeySym key_symbol)
13168 % A description of each parameter follows:
13170 % o display: Specifies a connection to an X server; returned from
13173 % o windows: Specifies a pointer to a XWindows structure.
13175 % o image: the image.
13177 % o key_symbol: Specifies a KeySym which indicates which side of the image
13181 static void XTranslateImage(Display *display,XWindows *windows,
13182 Image *image,const KeySym key_symbol)
13185 text[MaxTextExtent];
13196 User specified a pan position offset.
13198 x_offset=windows->image.width;
13199 y_offset=windows->image.height;
13200 if (image->montage != (char *) NULL)
13201 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13202 switch ((int) key_symbol)
13207 windows->image.x=(int) windows->image.width/2;
13208 windows->image.y=(int) windows->image.height/2;
13214 windows->image.x-=x_offset;
13221 windows->image.y-=y_offset;
13227 windows->image.x+=x_offset;
13234 windows->image.y+=y_offset;
13241 Check boundary conditions.
13243 if (windows->image.x < 0)
13244 windows->image.x=0;
13246 if ((int) (windows->image.x+windows->image.width) >
13247 windows->image.ximage->width)
13248 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13249 if (windows->image.y < 0)
13250 windows->image.y=0;
13252 if ((int) (windows->image.y+windows->image.height) >
13253 windows->image.ximage->height)
13254 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13256 Refresh Image window.
13258 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
13259 windows->image.width,windows->image.height,windows->image.x,
13261 XInfoWidget(display,windows,text);
13262 XCheckRefreshWindows(display,windows);
13263 XDrawPanRectangle(display,windows);
13264 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13265 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13273 + X T r i m I m a g e %
13277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13279 % XTrimImage() trims the edges from the Image window.
13281 % The format of the XTrimImage method is:
13283 % MagickBooleanType XTrimImage(Display *display,
13284 % XResourceInfo *resource_info,XWindows *windows,Image *image)
13286 % A description of each parameter follows:
13288 % o display: Specifies a connection to an X server; returned from
13291 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13293 % o windows: Specifies a pointer to a XWindows structure.
13295 % o image: the image.
13298 static MagickBooleanType XTrimImage(Display *display,
13299 XResourceInfo *resource_info,XWindows *windows,Image *image)
13313 Trim edges from image.
13315 XSetCursorState(display,windows,MagickTrue);
13316 XCheckRefreshWindows(display,windows);
13318 Crop the left edge.
13320 background=XGetPixel(windows->image.ximage,0,0);
13321 trim_info.width=(size_t) windows->image.ximage->width;
13322 for (x=0; x < windows->image.ximage->width; x++)
13324 for (y=0; y < windows->image.ximage->height; y++)
13326 pixel=XGetPixel(windows->image.ximage,x,y);
13327 if (pixel != background)
13330 if (y < windows->image.ximage->height)
13333 trim_info.x=(ssize_t) x;
13334 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13336 XSetCursorState(display,windows,MagickFalse);
13337 return(MagickFalse);
13340 Crop the right edge.
13342 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13343 for (x=windows->image.ximage->width-1; x != 0; x--)
13345 for (y=0; y < windows->image.ximage->height; y++)
13347 pixel=XGetPixel(windows->image.ximage,x,y);
13348 if (pixel != background)
13351 if (y < windows->image.ximage->height)
13354 trim_info.width=(size_t) (x-trim_info.x+1);
13358 background=XGetPixel(windows->image.ximage,0,0);
13359 trim_info.height=(size_t) windows->image.ximage->height;
13360 for (y=0; y < windows->image.ximage->height; y++)
13362 for (x=0; x < windows->image.ximage->width; x++)
13364 pixel=XGetPixel(windows->image.ximage,x,y);
13365 if (pixel != background)
13368 if (x < windows->image.ximage->width)
13371 trim_info.y=(ssize_t) y;
13373 Crop the bottom edge.
13375 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13376 for (y=windows->image.ximage->height-1; y != 0; y--)
13378 for (x=0; x < windows->image.ximage->width; x++)
13380 pixel=XGetPixel(windows->image.ximage,x,y);
13381 if (pixel != background)
13384 if (x < windows->image.ximage->width)
13387 trim_info.height=(size_t) y-trim_info.y+1;
13388 if (((unsigned int) trim_info.width != windows->image.width) ||
13389 ((unsigned int) trim_info.height != windows->image.height))
13392 Reconfigure Image window as defined by the trimming rectangle.
13394 XSetCropGeometry(display,windows,&trim_info,image);
13395 windows->image.window_changes.width=(int) trim_info.width;
13396 windows->image.window_changes.height=(int) trim_info.height;
13397 (void) XConfigureImage(display,resource_info,windows,image);
13399 XSetCursorState(display,windows,MagickFalse);
13400 return(MagickTrue);
13404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13408 + X V i s u a l D i r e c t o r y I m a g e %
13412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13414 % XVisualDirectoryImage() creates a Visual Image Directory.
13416 % The format of the XVisualDirectoryImage method is:
13418 % Image *XVisualDirectoryImage(Display *display,
13419 % XResourceInfo *resource_info,XWindows *windows)
13421 % A description of each parameter follows:
13423 % o nexus: Method XVisualDirectoryImage returns a visual image
13424 % directory if it can be created successfully. Otherwise a null image
13427 % o display: Specifies a connection to an X server; returned from
13430 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13432 % o windows: Specifies a pointer to a XWindows structure.
13435 static Image *XVisualDirectoryImage(Display *display,
13436 XResourceInfo *resource_info,XWindows *windows)
13438 #define TileImageTag "Scale/Image"
13439 #define XClientName "montage"
13475 filename[MaxTextExtent] = "\0",
13476 filenames[MaxTextExtent] = "*";
13479 background_resources;
13482 Request file name from user.
13484 XFileBrowserWidget(display,windows,"Directory",filenames);
13485 if (*filenames == '\0')
13486 return((Image *) NULL);
13488 Expand the filenames.
13490 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13491 if (filelist == (char **) NULL)
13493 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13495 return((Image *) NULL);
13498 filelist[0]=filenames;
13499 status=ExpandFilenames(&number_files,&filelist);
13500 if ((status == MagickFalse) || (number_files == 0))
13502 if (number_files == 0)
13503 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13505 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13507 return((Image *) NULL);
13510 Set image background resources.
13512 background_resources=(*resource_info);
13513 background_resources.window_id=AcquireString("");
13514 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
13515 "0x%lx",windows->image.id);
13516 background_resources.backdrop=MagickTrue;
13518 Read each image and convert them to a tile.
13520 backdrop=(windows->visual_info->klass == TrueColor) ||
13521 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13522 read_info=CloneImageInfo(resource_info->image_info);
13523 (void) SetImageOption(read_info,"jpeg:size","120x120");
13524 (void) CloneString(&read_info->size,DefaultTileGeometry);
13525 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13527 images=NewImageList();
13528 exception=AcquireExceptionInfo();
13529 XSetCursorState(display,windows,MagickTrue);
13530 XCheckRefreshWindows(display,windows);
13531 for (i=0; i < (int) number_files; i++)
13533 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13534 filelist[i]=DestroyString(filelist[i]);
13535 *read_info->magick='\0';
13536 next_image=ReadImage(read_info,exception);
13537 CatchException(exception);
13538 if (next_image != (Image *) NULL)
13540 (void) DeleteImageProperty(next_image,"label");
13541 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13542 read_info,next_image,DefaultTileLabel));
13543 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13545 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13546 geometry.height,exception);
13547 if (thumbnail_image != (Image *) NULL)
13549 next_image=DestroyImage(next_image);
13550 next_image=thumbnail_image;
13554 (void) XDisplayBackgroundImage(display,&background_resources,
13556 XSetCursorState(display,windows,MagickTrue);
13558 AppendImageToList(&images,next_image);
13559 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13564 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13565 (MagickSizeType) number_files);
13566 if (proceed == MagickFalse)
13571 exception=DestroyExceptionInfo(exception);
13572 filelist=(char **) RelinquishMagickMemory(filelist);
13573 if (images == (Image *) NULL)
13575 read_info=DestroyImageInfo(read_info);
13576 XSetCursorState(display,windows,MagickFalse);
13577 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13578 return((Image *) NULL);
13581 Create the Visual Image Directory.
13583 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13584 montage_info->pointsize=10;
13585 if (resource_info->font != (char *) NULL)
13586 (void) CloneString(&montage_info->font,resource_info->font);
13587 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13588 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13589 images),&images->exception);
13590 images=DestroyImageList(images);
13591 montage_info=DestroyMontageInfo(montage_info);
13592 read_info=DestroyImageInfo(read_info);
13593 XSetCursorState(display,windows,MagickFalse);
13594 if (montage_image == (Image *) NULL)
13595 return(montage_image);
13596 XClientMessage(display,windows->image.id,windows->im_protocols,
13597 windows->im_next_image,CurrentTime);
13598 return(montage_image);
13602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13606 % X D i s p l a y B a c k g r o u n d I m a g e %
13610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13612 % XDisplayBackgroundImage() displays an image in the background of a window.
13614 % The format of the XDisplayBackgroundImage method is:
13616 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13617 % XResourceInfo *resource_info,Image *image)
13619 % A description of each parameter follows:
13621 % o display: Specifies a connection to an X server; returned from
13624 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13626 % o image: the image.
13629 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13630 XResourceInfo *resource_info,Image *image)
13633 geometry[MaxTextExtent],
13634 visual_type[MaxTextExtent];
13647 static XStandardColormap
13651 *visual_info = (XVisualInfo *) NULL;
13672 Determine target window.
13674 assert(image != (Image *) NULL);
13675 assert(image->signature == MagickSignature);
13676 if (image->debug != MagickFalse)
13677 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13678 resources=(*resource_info);
13679 window_info.id=(Window) NULL;
13680 root_window=XRootWindow(display,XDefaultScreen(display));
13681 if (LocaleCompare(resources.window_id,"root") == 0)
13682 window_info.id=root_window;
13685 if (isdigit((unsigned char) *resources.window_id) != 0)
13686 window_info.id=XWindowByID(display,root_window,
13687 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13688 if (window_info.id == (Window) NULL)
13689 window_info.id=XWindowByName(display,root_window,resources.window_id);
13691 if (window_info.id == (Window) NULL)
13693 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13694 resources.window_id);
13695 return(MagickFalse);
13698 Determine window visual id.
13700 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13701 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13702 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13703 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13705 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
13706 XVisualIDFromVisual(window_attributes.visual));
13707 if (visual_info == (XVisualInfo *) NULL)
13710 Allocate standard colormap.
13712 map_info=XAllocStandardColormap();
13713 if (map_info == (XStandardColormap *) NULL)
13714 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13716 map_info->colormap=(Colormap) NULL;
13717 pixel.pixels=(unsigned long *) NULL;
13719 Initialize visual info.
13721 resources.map_type=(char *) NULL;
13722 resources.visual_type=visual_type;
13723 visual_info=XBestVisualInfo(display,map_info,&resources);
13724 if (visual_info == (XVisualInfo *) NULL)
13725 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13726 resources.visual_type);
13728 Initialize window info.
13730 window_info.ximage=(XImage *) NULL;
13731 window_info.matte_image=(XImage *) NULL;
13732 window_info.pixmap=(Pixmap) NULL;
13733 window_info.matte_pixmap=(Pixmap) NULL;
13736 Free previous root colors.
13738 if (window_info.id == root_window)
13739 (void) XDestroyWindowColors(display,root_window);
13741 Initialize Standard Colormap.
13743 resources.colormap=SharedColormap;
13744 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13746 Graphic context superclass.
13748 context_values.background=pixel.background_color.pixel;
13749 context_values.foreground=pixel.foreground_color.pixel;
13750 pixel.annotate_context=XCreateGC(display,window_info.id,
13751 (size_t) (GCBackground | GCForeground),&context_values);
13752 if (pixel.annotate_context == (GC) NULL)
13753 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13756 Initialize Image window attributes.
13758 window_info.name=AcquireString("\0");
13759 window_info.icon_name=AcquireString("\0");
13760 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13761 &resources,&window_info);
13763 Create the X image.
13765 window_info.width=(unsigned int) image->columns;
13766 window_info.height=(unsigned int) image->rows;
13767 if ((image->columns != window_info.width) ||
13768 (image->rows != window_info.height))
13769 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13771 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
13772 window_attributes.width,window_attributes.height);
13773 geometry_info.width=window_info.width;
13774 geometry_info.height=window_info.height;
13775 geometry_info.x=(ssize_t) window_info.x;
13776 geometry_info.y=(ssize_t) window_info.y;
13777 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13778 &geometry_info.width,&geometry_info.height);
13779 window_info.width=(unsigned int) geometry_info.width;
13780 window_info.height=(unsigned int) geometry_info.height;
13781 window_info.x=(int) geometry_info.x;
13782 window_info.y=(int) geometry_info.y;
13783 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13784 window_info.height);
13785 if (status == MagickFalse)
13786 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13790 if (image->debug != MagickFalse)
13792 (void) LogMagickEvent(X11Event,GetMagickModule(),
13793 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13794 (double) image->columns,(double) image->rows);
13795 if (image->colors != 0)
13796 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13798 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13801 Adjust image dimensions as specified by backdrop or geometry options.
13803 width=(int) window_info.width;
13804 height=(int) window_info.height;
13805 if (resources.backdrop != MagickFalse)
13808 Center image on window.
13810 window_info.x=(window_attributes.width/2)-
13811 (window_info.ximage->width/2);
13812 window_info.y=(window_attributes.height/2)-
13813 (window_info.ximage->height/2);
13814 width=window_attributes.width;
13815 height=window_attributes.height;
13817 if ((resources.image_geometry != (char *) NULL) &&
13818 (*resources.image_geometry != '\0'))
13821 default_geometry[MaxTextExtent];
13831 User specified geometry.
13833 size_hints=XAllocSizeHints();
13834 if (size_hints == (XSizeHints *) NULL)
13835 ThrowXWindowFatalException(ResourceLimitFatalError,
13836 "MemoryAllocationFailed",image->filename);
13837 size_hints->flags=0L;
13838 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
13840 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13841 default_geometry,window_info.border_width,size_hints,&window_info.x,
13842 &window_info.y,&width,&height,&gravity);
13843 if (flags & (XValue | YValue))
13845 width=window_attributes.width;
13846 height=window_attributes.height;
13848 (void) XFree((void *) size_hints);
13851 Create the X pixmap.
13853 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13854 (unsigned int) height,window_info.depth);
13855 if (window_info.pixmap == (Pixmap) NULL)
13856 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13859 Display pixmap on the window.
13861 if (((unsigned int) width > window_info.width) ||
13862 ((unsigned int) height > window_info.height))
13863 (void) XFillRectangle(display,window_info.pixmap,
13864 window_info.annotate_context,0,0,(unsigned int) width,
13865 (unsigned int) height);
13866 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13867 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13868 window_info.width,(unsigned int) window_info.height);
13869 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13870 (void) XClearWindow(display,window_info.id);
13871 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13872 XDelay(display,delay == 0UL ? 10UL : delay);
13873 (void) XSync(display,MagickFalse);
13874 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13882 + X D i s p l a y I m a g e %
13886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13888 % XDisplayImage() displays an image via X11. A new image is created and
13889 % returned if the user interactively transforms the displayed image.
13891 % The format of the XDisplayImage method is:
13893 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13894 % char **argv,int argc,Image **image,size_t *state)
13896 % A description of each parameter follows:
13898 % o nexus: Method XDisplayImage returns an image when the
13899 % user chooses 'Open Image' from the command menu or picks a tile
13900 % from the image directory. Otherwise a null image is returned.
13902 % o display: Specifies a connection to an X server; returned from
13905 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13907 % o argv: Specifies the application's argument list.
13909 % o argc: Specifies the number of arguments.
13911 % o image: Specifies an address to an address of an Image structure;
13914 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13915 char **argv,int argc,Image **image,size_t *state)
13917 #define MagnifySize 256 /* must be a power of 2 */
13918 #define MagickMenus 10
13919 #define MagickTitle "Commands"
13946 "Visual Directory...",
13992 "Contrast Stretch...",
13993 "Sigmoidal Contrast...",
14027 "Charcoal Draw...",
14041 "Region of Interest...",
14044 *MiscellanyMenu[] =
14059 "Browse Documentation",
14086 **Menus[MagickMenus] =
14124 VisualDirectoryCommand,
14138 OriginalSizeCommand,
14145 TransformCommands[] =
14151 RotateRightCommand,
14158 EnhanceCommands[] =
14166 ContrastStretchCommand,
14167 SigmoidalContrastCommand,
14175 EffectsCommands[] =
14179 ReduceNoiseCommand,
14199 CharcoalDrawCommand
14201 ImageEditCommands[] =
14212 RegionofInterestCommand
14214 MiscellanyCommands[] =
14218 ShowPreviewCommand,
14219 ShowHistogramCommand,
14228 BrowseDocumentationCommand,
14231 ShortCutsCommands[] =
14243 VirtualCommands[] =
14252 *Commands[MagickMenus] =
14262 MiscellanyCommands,
14267 command[MaxTextExtent],
14269 geometry[MaxTextExtent],
14270 resource_name[MaxTextExtent];
14297 working_directory[MaxTextExtent];
14303 *magick_windows[MaxXWindows];
14305 static unsigned int
14365 assert(image != (Image **) NULL);
14366 assert((*image)->signature == MagickSignature);
14367 if ((*image)->debug != MagickFalse)
14368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14369 display_image=(*image);
14370 warning_handler=(WarningHandler) NULL;
14371 windows=XSetWindows((XWindows *) ~0);
14372 if (windows != (XWindows *) NULL)
14377 status=chdir(working_directory);
14379 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14380 FileOpenError,"UnableToOpenFile","%s",working_directory);
14381 warning_handler=resource_info->display_warnings ?
14382 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14383 warning_handler=resource_info->display_warnings ?
14384 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14389 Allocate windows structure.
14391 resource_info->colors=display_image->colors;
14392 windows=XSetWindows(XInitializeWindows(display,resource_info));
14393 if (windows == (XWindows *) NULL)
14394 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14395 (*image)->filename);
14397 Initialize window id's.
14400 magick_windows[number_windows++]=(&windows->icon);
14401 magick_windows[number_windows++]=(&windows->backdrop);
14402 magick_windows[number_windows++]=(&windows->image);
14403 magick_windows[number_windows++]=(&windows->info);
14404 magick_windows[number_windows++]=(&windows->command);
14405 magick_windows[number_windows++]=(&windows->widget);
14406 magick_windows[number_windows++]=(&windows->popup);
14407 magick_windows[number_windows++]=(&windows->magnify);
14408 magick_windows[number_windows++]=(&windows->pan);
14409 for (i=0; i < (int) number_windows; i++)
14410 magick_windows[i]->id=(Window) NULL;
14415 Initialize font info.
14417 if (windows->font_info != (XFontStruct *) NULL)
14418 (void) XFreeFont(display,windows->font_info);
14419 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14420 if (windows->font_info == (XFontStruct *) NULL)
14421 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14422 resource_info->font);
14424 Initialize Standard Colormap.
14426 map_info=windows->map_info;
14427 icon_map=windows->icon_map;
14428 visual_info=windows->visual_info;
14429 icon_visual=windows->icon_visual;
14430 pixel=windows->pixel_info;
14431 icon_pixel=windows->icon_pixel;
14432 font_info=windows->font_info;
14433 icon_resources=windows->icon_resources;
14434 class_hints=windows->class_hints;
14435 manager_hints=windows->manager_hints;
14436 root_window=XRootWindow(display,visual_info->screen);
14437 nexus=NewImageList();
14438 if (display_image->debug != MagickFalse)
14440 (void) LogMagickEvent(X11Event,GetMagickModule(),
14441 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14442 (double) display_image->scene,(double) display_image->columns,
14443 (double) display_image->rows);
14444 if (display_image->colors != 0)
14445 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14446 display_image->colors);
14447 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14448 display_image->magick);
14450 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14452 display_image->taint=MagickFalse;
14454 Initialize graphic context.
14456 windows->context.id=(Window) NULL;
14457 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14458 resource_info,&windows->context);
14459 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14460 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14461 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14462 manager_hints->flags=InputHint | StateHint;
14463 manager_hints->input=MagickFalse;
14464 manager_hints->initial_state=WithdrawnState;
14465 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14466 &windows->context);
14467 if (display_image->debug != MagickFalse)
14468 (void) LogMagickEvent(X11Event,GetMagickModule(),
14469 "Window id: 0x%lx (context)",windows->context.id);
14470 context_values.background=pixel->background_color.pixel;
14471 context_values.font=font_info->fid;
14472 context_values.foreground=pixel->foreground_color.pixel;
14473 context_values.graphics_exposures=MagickFalse;
14474 context_mask=(MagickStatusType)
14475 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14476 if (pixel->annotate_context != (GC) NULL)
14477 (void) XFreeGC(display,pixel->annotate_context);
14478 pixel->annotate_context=XCreateGC(display,windows->context.id,
14479 context_mask,&context_values);
14480 if (pixel->annotate_context == (GC) NULL)
14481 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14482 display_image->filename);
14483 context_values.background=pixel->depth_color.pixel;
14484 if (pixel->widget_context != (GC) NULL)
14485 (void) XFreeGC(display,pixel->widget_context);
14486 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14488 if (pixel->widget_context == (GC) NULL)
14489 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14490 display_image->filename);
14491 context_values.background=pixel->foreground_color.pixel;
14492 context_values.foreground=pixel->background_color.pixel;
14493 context_values.plane_mask=context_values.background ^
14494 context_values.foreground;
14495 if (pixel->highlight_context != (GC) NULL)
14496 (void) XFreeGC(display,pixel->highlight_context);
14497 pixel->highlight_context=XCreateGC(display,windows->context.id,
14498 (size_t) (context_mask | GCPlaneMask),&context_values);
14499 if (pixel->highlight_context == (GC) NULL)
14500 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14501 display_image->filename);
14502 (void) XDestroyWindow(display,windows->context.id);
14504 Initialize icon window.
14506 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14507 icon_resources,&windows->icon);
14508 windows->icon.geometry=resource_info->icon_geometry;
14509 XBestIconSize(display,&windows->icon,display_image);
14510 windows->icon.attributes.colormap=XDefaultColormap(display,
14511 icon_visual->screen);
14512 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14513 manager_hints->flags=InputHint | StateHint;
14514 manager_hints->input=MagickFalse;
14515 manager_hints->initial_state=IconicState;
14516 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14518 if (display_image->debug != MagickFalse)
14519 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14522 Initialize graphic context for icon window.
14524 if (icon_pixel->annotate_context != (GC) NULL)
14525 (void) XFreeGC(display,icon_pixel->annotate_context);
14526 context_values.background=icon_pixel->background_color.pixel;
14527 context_values.foreground=icon_pixel->foreground_color.pixel;
14528 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14529 (size_t) (GCBackground | GCForeground),&context_values);
14530 if (icon_pixel->annotate_context == (GC) NULL)
14531 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14532 display_image->filename);
14533 windows->icon.annotate_context=icon_pixel->annotate_context;
14535 Initialize Image window.
14537 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14539 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14540 if (resource_info->use_shared_memory == MagickFalse)
14541 windows->image.shared_memory=MagickFalse;
14542 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14547 title=InterpretImageProperties(resource_info->image_info,display_image,
14548 resource_info->title);
14549 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14550 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14551 title=DestroyString(title);
14556 filename[MaxTextExtent];
14559 Window name is the base of the filename.
14561 GetPathComponent(display_image->magick_filename,TailPath,filename);
14562 if (GetImageListLength(display_image) == 1)
14563 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14564 "%s: %s",MagickPackageName,filename);
14566 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14567 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14568 (double) display_image->scene,(double) GetImageListLength(
14570 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14572 if (resource_info->immutable)
14573 windows->image.immutable=MagickTrue;
14574 windows->image.use_pixmap=resource_info->use_pixmap;
14575 windows->image.geometry=resource_info->image_geometry;
14576 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14577 XDisplayWidth(display,visual_info->screen),
14578 XDisplayHeight(display,visual_info->screen));
14579 geometry_info.width=display_image->columns;
14580 geometry_info.height=display_image->rows;
14583 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14584 &geometry_info.width,&geometry_info.height);
14585 windows->image.width=(unsigned int) geometry_info.width;
14586 windows->image.height=(unsigned int) geometry_info.height;
14587 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14588 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14589 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14590 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14591 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14592 resource_info,&windows->backdrop);
14593 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14596 Initialize backdrop window.
14598 windows->backdrop.x=0;
14599 windows->backdrop.y=0;
14600 (void) CloneString(&windows->backdrop.name,"Backdrop");
14601 windows->backdrop.flags=(size_t) (USSize | USPosition);
14602 windows->backdrop.width=(unsigned int)
14603 XDisplayWidth(display,visual_info->screen);
14604 windows->backdrop.height=(unsigned int)
14605 XDisplayHeight(display,visual_info->screen);
14606 windows->backdrop.border_width=0;
14607 windows->backdrop.immutable=MagickTrue;
14608 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14610 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14611 StructureNotifyMask;
14612 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14613 manager_hints->icon_window=windows->icon.id;
14614 manager_hints->input=MagickTrue;
14615 manager_hints->initial_state=resource_info->iconic ? IconicState :
14617 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14618 &windows->backdrop);
14619 if (display_image->debug != MagickFalse)
14620 (void) LogMagickEvent(X11Event,GetMagickModule(),
14621 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14622 (void) XMapWindow(display,windows->backdrop.id);
14623 (void) XClearWindow(display,windows->backdrop.id);
14624 if (windows->image.id != (Window) NULL)
14626 (void) XDestroyWindow(display,windows->image.id);
14627 windows->image.id=(Window) NULL;
14630 Position image in the center the backdrop.
14632 windows->image.flags|=USPosition;
14633 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14634 (windows->image.width/2);
14635 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14636 (windows->image.height/2);
14638 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14639 manager_hints->icon_window=windows->icon.id;
14640 manager_hints->input=MagickTrue;
14641 manager_hints->initial_state=resource_info->iconic ? IconicState :
14643 if (windows->group_leader.id != (Window) NULL)
14648 manager_hints->flags|=WindowGroupHint;
14649 manager_hints->window_group=windows->group_leader.id;
14650 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14651 if (display_image->debug != MagickFalse)
14652 (void) LogMagickEvent(X11Event,GetMagickModule(),
14653 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14655 XMakeWindow(display,
14656 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14657 argv,argc,class_hints,manager_hints,&windows->image);
14658 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14659 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14660 if (windows->group_leader.id != (Window) NULL)
14661 (void) XSetTransientForHint(display,windows->image.id,
14662 windows->group_leader.id);
14663 if (display_image->debug != MagickFalse)
14664 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14665 windows->image.id);
14667 Initialize Info widget.
14669 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14671 (void) CloneString(&windows->info.name,"Info");
14672 (void) CloneString(&windows->info.icon_name,"Info");
14673 windows->info.border_width=1;
14676 windows->info.flags|=PPosition;
14677 windows->info.attributes.win_gravity=UnmapGravity;
14678 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14679 StructureNotifyMask;
14680 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14681 manager_hints->input=MagickFalse;
14682 manager_hints->initial_state=NormalState;
14683 manager_hints->window_group=windows->image.id;
14684 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14686 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14687 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14688 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14689 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14690 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14691 if (windows->image.mapped != MagickFalse)
14692 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14693 if (display_image->debug != MagickFalse)
14694 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14697 Initialize Command widget.
14699 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14700 resource_info,&windows->command);
14701 windows->command.data=MagickMenus;
14702 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14703 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
14704 resource_info->client_name);
14705 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14706 resource_name,"geometry",(char *) NULL);
14707 (void) CloneString(&windows->command.name,MagickTitle);
14708 windows->command.border_width=0;
14709 windows->command.flags|=PPosition;
14710 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14711 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14712 OwnerGrabButtonMask | StructureNotifyMask;
14713 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14714 manager_hints->input=MagickTrue;
14715 manager_hints->initial_state=NormalState;
14716 manager_hints->window_group=windows->image.id;
14717 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14718 &windows->command);
14719 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14720 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14722 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14723 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14724 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14725 if (windows->command.mapped != MagickFalse)
14726 (void) XMapRaised(display,windows->command.id);
14727 if (display_image->debug != MagickFalse)
14728 (void) LogMagickEvent(X11Event,GetMagickModule(),
14729 "Window id: 0x%lx (command)",windows->command.id);
14731 Initialize Widget window.
14733 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14734 resource_info,&windows->widget);
14735 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
14736 resource_info->client_name);
14737 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14738 resource_name,"geometry",(char *) NULL);
14739 windows->widget.border_width=0;
14740 windows->widget.flags|=PPosition;
14741 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14742 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14743 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14744 StructureNotifyMask;
14745 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14746 manager_hints->input=MagickTrue;
14747 manager_hints->initial_state=NormalState;
14748 manager_hints->window_group=windows->image.id;
14749 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14751 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14752 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14753 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14754 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14755 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14756 if (display_image->debug != MagickFalse)
14757 (void) LogMagickEvent(X11Event,GetMagickModule(),
14758 "Window id: 0x%lx (widget)",windows->widget.id);
14760 Initialize popup window.
14762 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14763 resource_info,&windows->popup);
14764 windows->popup.border_width=0;
14765 windows->popup.flags|=PPosition;
14766 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14767 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14768 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14769 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14770 manager_hints->input=MagickTrue;
14771 manager_hints->initial_state=NormalState;
14772 manager_hints->window_group=windows->image.id;
14773 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14775 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14776 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14777 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14778 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14779 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14780 if (display_image->debug != MagickFalse)
14781 (void) LogMagickEvent(X11Event,GetMagickModule(),
14782 "Window id: 0x%lx (pop up)",windows->popup.id);
14784 Initialize Magnify window and cursor.
14786 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14787 resource_info,&windows->magnify);
14788 if (resource_info->use_shared_memory == MagickFalse)
14789 windows->magnify.shared_memory=MagickFalse;
14790 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
14791 resource_info->client_name);
14792 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14793 resource_name,"geometry",(char *) NULL);
14794 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14795 resource_info->magnify);
14796 if (windows->magnify.cursor != (Cursor) NULL)
14797 (void) XFreeCursor(display,windows->magnify.cursor);
14798 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14799 map_info->colormap,resource_info->background_color,
14800 resource_info->foreground_color);
14801 if (windows->magnify.cursor == (Cursor) NULL)
14802 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14803 display_image->filename);
14804 windows->magnify.width=MagnifySize;
14805 windows->magnify.height=MagnifySize;
14806 windows->magnify.flags|=PPosition;
14807 windows->magnify.min_width=MagnifySize;
14808 windows->magnify.min_height=MagnifySize;
14809 windows->magnify.width_inc=MagnifySize;
14810 windows->magnify.height_inc=MagnifySize;
14811 windows->magnify.data=resource_info->magnify;
14812 windows->magnify.attributes.cursor=windows->magnify.cursor;
14813 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14814 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14815 StructureNotifyMask;
14816 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14817 manager_hints->input=MagickTrue;
14818 manager_hints->initial_state=NormalState;
14819 manager_hints->window_group=windows->image.id;
14820 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14821 &windows->magnify);
14822 if (display_image->debug != MagickFalse)
14823 (void) LogMagickEvent(X11Event,GetMagickModule(),
14824 "Window id: 0x%lx (magnify)",windows->magnify.id);
14825 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14827 Initialize panning window.
14829 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14830 resource_info,&windows->pan);
14831 (void) CloneString(&windows->pan.name,"Pan Icon");
14832 windows->pan.width=windows->icon.width;
14833 windows->pan.height=windows->icon.height;
14834 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
14835 resource_info->client_name);
14836 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14837 resource_name,"geometry",(char *) NULL);
14838 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14839 &windows->pan.width,&windows->pan.height);
14840 windows->pan.flags|=PPosition;
14841 windows->pan.immutable=MagickTrue;
14842 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14843 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14844 StructureNotifyMask;
14845 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14846 manager_hints->input=MagickFalse;
14847 manager_hints->initial_state=NormalState;
14848 manager_hints->window_group=windows->image.id;
14849 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14851 if (display_image->debug != MagickFalse)
14852 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14854 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14855 if (windows->info.mapped != MagickFalse)
14856 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14857 if ((windows->image.mapped == MagickFalse) ||
14858 (windows->backdrop.id != (Window) NULL))
14859 (void) XMapWindow(display,windows->image.id);
14861 Set our progress monitor and warning handlers.
14863 if (warning_handler == (WarningHandler) NULL)
14865 warning_handler=resource_info->display_warnings ?
14866 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14867 warning_handler=resource_info->display_warnings ?
14868 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14871 Initialize Image and Magnify X images.
14873 windows->image.x=0;
14874 windows->image.y=0;
14875 windows->magnify.shape=MagickFalse;
14876 width=(unsigned int) display_image->columns;
14877 height=(unsigned int) display_image->rows;
14878 if ((display_image->columns != width) || (display_image->rows != height))
14879 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14880 display_image->filename);
14881 status=XMakeImage(display,resource_info,&windows->image,display_image,
14883 if (status == MagickFalse)
14884 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14885 display_image->filename);
14886 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14887 windows->magnify.width,windows->magnify.height);
14888 if (status == MagickFalse)
14889 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14890 display_image->filename);
14891 if (windows->magnify.mapped != MagickFalse)
14892 (void) XMapRaised(display,windows->magnify.id);
14893 if (windows->pan.mapped != MagickFalse)
14894 (void) XMapRaised(display,windows->pan.id);
14895 windows->image.window_changes.width=(int) display_image->columns;
14896 windows->image.window_changes.height=(int) display_image->rows;
14897 (void) XConfigureImage(display,resource_info,windows,display_image);
14898 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14899 (void) XSync(display,MagickFalse);
14903 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14904 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14906 if (resource_info->update != MagickFalse)
14912 Determine when file data was last modified.
14914 status=GetPathAttributes(display_image->filename,&attributes);
14915 if (status != MagickFalse)
14916 update_time=attributes.st_mtime;
14918 *state&=(~FormerImageState);
14919 *state&=(~MontageImageState);
14920 *state&=(~NextImageState);
14924 Handle a window event.
14926 if (windows->image.mapped != MagickFalse)
14927 if ((display_image->delay != 0) || (resource_info->update != 0))
14929 if (timer < time((time_t *) NULL))
14931 if (resource_info->update == MagickFalse)
14932 *state|=NextImageState | ExitState;
14939 Determine if image file was modified.
14941 status=GetPathAttributes(display_image->filename,&attributes);
14942 if (status != MagickFalse)
14943 if (update_time != attributes.st_mtime)
14948 (void) FormatLocaleString(
14949 resource_info->image_info->filename,MaxTextExtent,
14950 "%s:%s",display_image->magick,
14951 display_image->filename);
14952 nexus=ReadImage(resource_info->image_info,
14953 &display_image->exception);
14954 if (nexus != (Image *) NULL)
14956 nexus=DestroyImage(nexus);
14957 *state|=NextImageState | ExitState;
14960 delay=display_image->delay/MagickMax(
14961 display_image->ticks_per_second,1L);
14962 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14965 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14968 Do not block if delay > 0.
14970 XDelay(display,SuspendTime << 2);
14974 timestamp=time((time_t *) NULL);
14975 (void) XNextEvent(display,&event);
14976 if (windows->image.stasis == MagickFalse)
14977 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14978 MagickTrue : MagickFalse;
14979 if (windows->magnify.stasis == MagickFalse)
14980 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14981 MagickTrue : MagickFalse;
14982 if (event.xany.window == windows->command.id)
14985 Select a command from the Command widget.
14987 id=XCommandWidget(display,windows,CommandMenu,&event);
14990 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
14991 command_type=CommandMenus[id];
14992 if (id < MagickMenus)
14995 Select a command from a pop-up menu.
14997 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15001 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15002 command_type=Commands[id][entry];
15004 if (command_type != NullCommand)
15005 nexus=XMagickCommand(display,resource_info,windows,command_type,
15009 switch (event.type)
15013 if (display_image->debug != MagickFalse)
15014 (void) LogMagickEvent(X11Event,GetMagickModule(),
15015 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15016 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15017 if ((event.xbutton.button == Button3) &&
15018 (event.xbutton.state & Mod1Mask))
15021 Convert Alt-Button3 to Button2.
15023 event.xbutton.button=Button2;
15024 event.xbutton.state&=(~Mod1Mask);
15026 if (event.xbutton.window == windows->backdrop.id)
15028 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15029 event.xbutton.time);
15032 if (event.xbutton.window == windows->image.id)
15034 switch (event.xbutton.button)
15038 if (resource_info->immutable)
15041 Select a command from the Virtual menu.
15043 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15046 nexus=XMagickCommand(display,resource_info,windows,
15047 VirtualCommands[entry],&display_image);
15051 Map/unmap Command widget.
15053 if (windows->command.mapped != MagickFalse)
15054 (void) XWithdrawWindow(display,windows->command.id,
15055 windows->command.screen);
15058 (void) XCommandWidget(display,windows,CommandMenu,
15060 (void) XMapRaised(display,windows->command.id);
15067 User pressed the image magnify button.
15069 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15071 XMagnifyImage(display,windows,&event);
15076 if (resource_info->immutable)
15079 Select a command from the Virtual menu.
15081 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15084 nexus=XMagickCommand(display,resource_info,windows,
15085 VirtualCommands[entry],&display_image);
15088 if (display_image->montage != (char *) NULL)
15091 Open or delete a tile from a visual image directory.
15093 nexus=XTileImage(display,resource_info,windows,
15094 display_image,&event);
15095 if (nexus != (Image *) NULL)
15096 *state|=MontageImageState | NextImageState | ExitState;
15097 vid_info.x=(short int) windows->image.x;
15098 vid_info.y=(short int) windows->image.y;
15102 Select a command from the Short Cuts menu.
15104 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15107 nexus=XMagickCommand(display,resource_info,windows,
15108 ShortCutsCommands[entry],&display_image);
15116 XTranslateImage(display,windows,*image,XK_Up);
15124 XTranslateImage(display,windows,*image,XK_Down);
15132 if (event.xbutton.window == windows->magnify.id)
15152 MagnifyCommands[] =
15165 Select a magnify factor from the pop-up menu.
15167 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15169 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15172 if (event.xbutton.window == windows->pan.id)
15174 switch (event.xbutton.button)
15181 XTranslateImage(display,windows,*image,XK_Up);
15189 XTranslateImage(display,windows,*image,XK_Down);
15194 XPanImage(display,windows,&event);
15200 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15202 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15205 case ButtonRelease:
15207 if (display_image->debug != MagickFalse)
15208 (void) LogMagickEvent(X11Event,GetMagickModule(),
15209 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15210 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15213 case ClientMessage:
15215 if (display_image->debug != MagickFalse)
15216 (void) LogMagickEvent(X11Event,GetMagickModule(),
15217 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15218 event.xclient.message_type,event.xclient.format,(unsigned long)
15219 event.xclient.data.l[0]);
15220 if (event.xclient.message_type == windows->im_protocols)
15222 if (*event.xclient.data.l == (long) windows->im_update_widget)
15224 (void) CloneString(&windows->command.name,MagickTitle);
15225 windows->command.data=MagickMenus;
15226 (void) XCommandWidget(display,windows,CommandMenu,
15230 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15233 Update graphic context and window colormap.
15235 for (i=0; i < (int) number_windows; i++)
15237 if (magick_windows[i]->id == windows->icon.id)
15239 context_values.background=pixel->background_color.pixel;
15240 context_values.foreground=pixel->foreground_color.pixel;
15241 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15242 context_mask,&context_values);
15243 (void) XChangeGC(display,magick_windows[i]->widget_context,
15244 context_mask,&context_values);
15245 context_values.background=pixel->foreground_color.pixel;
15246 context_values.foreground=pixel->background_color.pixel;
15247 context_values.plane_mask=context_values.background ^
15248 context_values.foreground;
15249 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15250 (size_t) (context_mask | GCPlaneMask),
15252 magick_windows[i]->attributes.background_pixel=
15253 pixel->background_color.pixel;
15254 magick_windows[i]->attributes.border_pixel=
15255 pixel->border_color.pixel;
15256 magick_windows[i]->attributes.colormap=map_info->colormap;
15257 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15258 (unsigned long) magick_windows[i]->mask,
15259 &magick_windows[i]->attributes);
15261 if (windows->pan.mapped != MagickFalse)
15263 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15264 windows->pan.pixmap);
15265 (void) XClearWindow(display,windows->pan.id);
15266 XDrawPanRectangle(display,windows);
15268 if (windows->backdrop.id != (Window) NULL)
15269 (void) XInstallColormap(display,map_info->colormap);
15272 if (*event.xclient.data.l == (long) windows->im_former_image)
15274 *state|=FormerImageState | ExitState;
15277 if (*event.xclient.data.l == (long) windows->im_next_image)
15279 *state|=NextImageState | ExitState;
15282 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15284 *state|=RetainColorsState;
15287 if (*event.xclient.data.l == (long) windows->im_exit)
15294 if (event.xclient.message_type == windows->dnd_protocols)
15312 Display image named by the Drag-and-Drop selection.
15314 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15316 selection=XInternAtom(display,"DndSelection",MagickFalse);
15317 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15318 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15319 &length,&after,&data);
15320 if ((status != Success) || (length == 0))
15322 if (*event.xclient.data.l == 2)
15327 (void) CopyMagickString(resource_info->image_info->filename,
15328 (char *) data,MaxTextExtent);
15335 if (strncmp((char *) data, "file:", 5) != 0)
15337 (void) XFree((void *) data);
15340 (void) CopyMagickString(resource_info->image_info->filename,
15341 ((char *) data)+5,MaxTextExtent);
15343 nexus=ReadImage(resource_info->image_info,
15344 &display_image->exception);
15345 CatchException(&display_image->exception);
15346 if (nexus != (Image *) NULL)
15347 *state|=NextImageState | ExitState;
15348 (void) XFree((void *) data);
15352 If client window delete message, exit.
15354 if (event.xclient.message_type != windows->wm_protocols)
15356 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15358 (void) XWithdrawWindow(display,event.xclient.window,
15359 visual_info->screen);
15360 if (event.xclient.window == windows->image.id)
15365 if (event.xclient.window == windows->pan.id)
15368 Restore original image size when pan window is deleted.
15370 windows->image.window_changes.width=windows->image.ximage->width;
15371 windows->image.window_changes.height=windows->image.ximage->height;
15372 (void) XConfigureImage(display,resource_info,windows,
15377 case ConfigureNotify:
15379 if (display_image->debug != MagickFalse)
15380 (void) LogMagickEvent(X11Event,GetMagickModule(),
15381 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15382 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15383 event.xconfigure.y,event.xconfigure.send_event);
15384 if (event.xconfigure.window == windows->image.id)
15387 Image window has a new configuration.
15389 if (event.xconfigure.send_event != 0)
15395 Position the transient windows relative of the Image window.
15397 if (windows->command.geometry == (char *) NULL)
15398 if (windows->command.mapped == MagickFalse)
15400 windows->command.x=event.xconfigure.x-
15401 windows->command.width-25;
15402 windows->command.y=event.xconfigure.y;
15403 XConstrainWindowPosition(display,&windows->command);
15404 window_changes.x=windows->command.x;
15405 window_changes.y=windows->command.y;
15406 (void) XReconfigureWMWindow(display,windows->command.id,
15407 windows->command.screen,(unsigned int) (CWX | CWY),
15410 if (windows->widget.geometry == (char *) NULL)
15411 if (windows->widget.mapped == MagickFalse)
15413 windows->widget.x=event.xconfigure.x+
15414 event.xconfigure.width/10;
15415 windows->widget.y=event.xconfigure.y+
15416 event.xconfigure.height/10;
15417 XConstrainWindowPosition(display,&windows->widget);
15418 window_changes.x=windows->widget.x;
15419 window_changes.y=windows->widget.y;
15420 (void) XReconfigureWMWindow(display,windows->widget.id,
15421 windows->widget.screen,(unsigned int) (CWX | CWY),
15424 if (windows->magnify.geometry == (char *) NULL)
15425 if (windows->magnify.mapped == MagickFalse)
15427 windows->magnify.x=event.xconfigure.x+
15428 event.xconfigure.width+25;
15429 windows->magnify.y=event.xconfigure.y;
15430 XConstrainWindowPosition(display,&windows->magnify);
15431 window_changes.x=windows->magnify.x;
15432 window_changes.y=windows->magnify.y;
15433 (void) XReconfigureWMWindow(display,windows->magnify.id,
15434 windows->magnify.screen,(unsigned int) (CWX | CWY),
15437 if (windows->pan.geometry == (char *) NULL)
15438 if (windows->pan.mapped == MagickFalse)
15440 windows->pan.x=event.xconfigure.x+
15441 event.xconfigure.width+25;
15442 windows->pan.y=event.xconfigure.y+
15443 windows->magnify.height+50;
15444 XConstrainWindowPosition(display,&windows->pan);
15445 window_changes.x=windows->pan.x;
15446 window_changes.y=windows->pan.y;
15447 (void) XReconfigureWMWindow(display,windows->pan.id,
15448 windows->pan.screen,(unsigned int) (CWX | CWY),
15452 if ((event.xconfigure.width == (int) windows->image.width) &&
15453 (event.xconfigure.height == (int) windows->image.height))
15455 windows->image.width=(unsigned int) event.xconfigure.width;
15456 windows->image.height=(unsigned int) event.xconfigure.height;
15457 windows->image.x=0;
15458 windows->image.y=0;
15459 if (display_image->montage != (char *) NULL)
15461 windows->image.x=vid_info.x;
15462 windows->image.y=vid_info.y;
15464 if ((windows->image.mapped != MagickFalse) &&
15465 (windows->image.stasis != MagickFalse))
15468 Update image window configuration.
15470 windows->image.window_changes.width=event.xconfigure.width;
15471 windows->image.window_changes.height=event.xconfigure.height;
15472 (void) XConfigureImage(display,resource_info,windows,
15476 Update pan window configuration.
15478 if ((event.xconfigure.width < windows->image.ximage->width) ||
15479 (event.xconfigure.height < windows->image.ximage->height))
15481 (void) XMapRaised(display,windows->pan.id);
15482 XDrawPanRectangle(display,windows);
15485 if (windows->pan.mapped != MagickFalse)
15486 (void) XWithdrawWindow(display,windows->pan.id,
15487 windows->pan.screen);
15490 if (event.xconfigure.window == windows->magnify.id)
15496 Magnify window has a new configuration.
15498 windows->magnify.width=(unsigned int) event.xconfigure.width;
15499 windows->magnify.height=(unsigned int) event.xconfigure.height;
15500 if (windows->magnify.mapped == MagickFalse)
15503 while ((int) magnify <= event.xconfigure.width)
15505 while ((int) magnify <= event.xconfigure.height)
15508 if (((int) magnify != event.xconfigure.width) ||
15509 ((int) magnify != event.xconfigure.height))
15511 window_changes.width=(int) magnify;
15512 window_changes.height=(int) magnify;
15513 (void) XReconfigureWMWindow(display,windows->magnify.id,
15514 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15518 if ((windows->magnify.mapped != MagickFalse) &&
15519 (windows->magnify.stasis != MagickFalse))
15521 status=XMakeImage(display,resource_info,&windows->magnify,
15522 display_image,windows->magnify.width,windows->magnify.height);
15523 XMakeMagnifyImage(display,windows);
15527 if ((windows->magnify.mapped != MagickFalse) &&
15528 (event.xconfigure.window == windows->pan.id))
15531 Pan icon window has a new configuration.
15533 if (event.xconfigure.send_event != 0)
15535 windows->pan.x=event.xconfigure.x;
15536 windows->pan.y=event.xconfigure.y;
15538 windows->pan.width=(unsigned int) event.xconfigure.width;
15539 windows->pan.height=(unsigned int) event.xconfigure.height;
15542 if (event.xconfigure.window == windows->icon.id)
15545 Icon window has a new configuration.
15547 windows->icon.width=(unsigned int) event.xconfigure.width;
15548 windows->icon.height=(unsigned int) event.xconfigure.height;
15553 case DestroyNotify:
15556 Group leader has exited.
15558 if (display_image->debug != MagickFalse)
15559 (void) LogMagickEvent(X11Event,GetMagickModule(),
15560 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15561 if (event.xdestroywindow.window == windows->group_leader.id)
15571 Selectively install colormap.
15573 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15574 if (event.xcrossing.mode != NotifyUngrab)
15575 XInstallColormap(display,map_info->colormap);
15580 if (display_image->debug != MagickFalse)
15581 (void) LogMagickEvent(X11Event,GetMagickModule(),
15582 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15583 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15586 Refresh windows that are now exposed.
15588 if ((event.xexpose.window == windows->image.id) &&
15589 (windows->image.mapped != MagickFalse))
15591 XRefreshWindow(display,&windows->image,&event);
15592 delay=display_image->delay/MagickMax(
15593 display_image->ticks_per_second,1L);
15594 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15597 if ((event.xexpose.window == windows->magnify.id) &&
15598 (windows->magnify.mapped != MagickFalse))
15600 XMakeMagnifyImage(display,windows);
15603 if (event.xexpose.window == windows->pan.id)
15605 XDrawPanRectangle(display,windows);
15608 if (event.xexpose.window == windows->icon.id)
15610 XRefreshWindow(display,&windows->icon,&event);
15621 Respond to a user key press.
15623 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15624 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15625 *(command+length)='\0';
15626 if (display_image->debug != MagickFalse)
15627 (void) LogMagickEvent(X11Event,GetMagickModule(),
15628 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15629 key_symbol,command);
15630 if (event.xkey.window == windows->image.id)
15632 command_type=XImageWindowCommand(display,resource_info,windows,
15633 event.xkey.state,key_symbol,&display_image);
15634 if (command_type != NullCommand)
15635 nexus=XMagickCommand(display,resource_info,windows,command_type,
15638 if (event.xkey.window == windows->magnify.id)
15639 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15640 if (event.xkey.window == windows->pan.id)
15642 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15643 (void) XWithdrawWindow(display,windows->pan.id,
15644 windows->pan.screen);
15646 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15647 XTextViewWidget(display,resource_info,windows,MagickFalse,
15648 "Help Viewer - Image Pan",ImagePanHelp);
15650 XTranslateImage(display,windows,*image,key_symbol);
15652 delay=display_image->delay/MagickMax(
15653 display_image->ticks_per_second,1L);
15654 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15660 Respond to a user key release.
15662 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15663 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15664 if (display_image->debug != MagickFalse)
15665 (void) LogMagickEvent(X11Event,GetMagickModule(),
15666 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15672 Selectively uninstall colormap.
15674 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15675 if (event.xcrossing.mode != NotifyUngrab)
15676 XUninstallColormap(display,map_info->colormap);
15681 if (display_image->debug != MagickFalse)
15682 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15683 event.xmap.window);
15684 if (event.xmap.window == windows->backdrop.id)
15686 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15688 windows->backdrop.mapped=MagickTrue;
15691 if (event.xmap.window == windows->image.id)
15693 if (windows->backdrop.id != (Window) NULL)
15694 (void) XInstallColormap(display,map_info->colormap);
15695 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15697 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15698 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15700 if (((int) windows->image.width < windows->image.ximage->width) ||
15701 ((int) windows->image.height < windows->image.ximage->height))
15702 (void) XMapRaised(display,windows->pan.id);
15703 windows->image.mapped=MagickTrue;
15706 if (event.xmap.window == windows->magnify.id)
15708 XMakeMagnifyImage(display,windows);
15709 windows->magnify.mapped=MagickTrue;
15710 (void) XWithdrawWindow(display,windows->info.id,
15711 windows->info.screen);
15714 if (event.xmap.window == windows->pan.id)
15716 XMakePanImage(display,resource_info,windows,display_image);
15717 windows->pan.mapped=MagickTrue;
15720 if (event.xmap.window == windows->info.id)
15722 windows->info.mapped=MagickTrue;
15725 if (event.xmap.window == windows->icon.id)
15731 Create an icon image.
15733 taint=display_image->taint;
15734 XMakeStandardColormap(display,icon_visual,icon_resources,
15735 display_image,icon_map,icon_pixel);
15736 (void) XMakeImage(display,icon_resources,&windows->icon,
15737 display_image,windows->icon.width,windows->icon.height);
15738 display_image->taint=taint;
15739 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15740 windows->icon.pixmap);
15741 (void) XClearWindow(display,windows->icon.id);
15742 (void) XWithdrawWindow(display,windows->info.id,
15743 windows->info.screen);
15744 windows->icon.mapped=MagickTrue;
15747 if (event.xmap.window == windows->command.id)
15749 windows->command.mapped=MagickTrue;
15752 if (event.xmap.window == windows->popup.id)
15754 windows->popup.mapped=MagickTrue;
15757 if (event.xmap.window == windows->widget.id)
15759 windows->widget.mapped=MagickTrue;
15764 case MappingNotify:
15766 (void) XRefreshKeyboardMapping(&event.xmapping);
15771 case PropertyNotify:
15787 if (display_image->debug != MagickFalse)
15788 (void) LogMagickEvent(X11Event,GetMagickModule(),
15789 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15790 event.xproperty.atom,event.xproperty.state);
15791 if (event.xproperty.atom != windows->im_remote_command)
15794 Display image named by the remote command protocol.
15796 status=XGetWindowProperty(display,event.xproperty.window,
15797 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15798 AnyPropertyType,&type,&format,&length,&after,&data);
15799 if ((status != Success) || (length == 0))
15801 if (LocaleCompare((char *) data,"-quit") == 0)
15803 XClientMessage(display,windows->image.id,windows->im_protocols,
15804 windows->im_exit,CurrentTime);
15805 (void) XFree((void *) data);
15808 (void) CopyMagickString(resource_info->image_info->filename,
15809 (char *) data,MaxTextExtent);
15810 (void) XFree((void *) data);
15811 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15812 CatchException(&display_image->exception);
15813 if (nexus != (Image *) NULL)
15814 *state|=NextImageState | ExitState;
15817 case ReparentNotify:
15819 if (display_image->debug != MagickFalse)
15820 (void) LogMagickEvent(X11Event,GetMagickModule(),
15821 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15822 event.xreparent.window);
15827 if (display_image->debug != MagickFalse)
15828 (void) LogMagickEvent(X11Event,GetMagickModule(),
15829 "Unmap Notify: 0x%lx",event.xunmap.window);
15830 if (event.xunmap.window == windows->backdrop.id)
15832 windows->backdrop.mapped=MagickFalse;
15835 if (event.xunmap.window == windows->image.id)
15837 windows->image.mapped=MagickFalse;
15840 if (event.xunmap.window == windows->magnify.id)
15842 windows->magnify.mapped=MagickFalse;
15845 if (event.xunmap.window == windows->pan.id)
15847 windows->pan.mapped=MagickFalse;
15850 if (event.xunmap.window == windows->info.id)
15852 windows->info.mapped=MagickFalse;
15855 if (event.xunmap.window == windows->icon.id)
15857 if (map_info->colormap == icon_map->colormap)
15858 XConfigureImageColormap(display,resource_info,windows,
15860 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15862 windows->icon.mapped=MagickFalse;
15865 if (event.xunmap.window == windows->command.id)
15867 windows->command.mapped=MagickFalse;
15870 if (event.xunmap.window == windows->popup.id)
15872 if (windows->backdrop.id != (Window) NULL)
15873 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15875 windows->popup.mapped=MagickFalse;
15878 if (event.xunmap.window == windows->widget.id)
15880 if (windows->backdrop.id != (Window) NULL)
15881 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15883 windows->widget.mapped=MagickFalse;
15890 if (display_image->debug != MagickFalse)
15891 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15896 } while (!(*state & ExitState));
15897 if ((*state & ExitState) == 0)
15898 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15901 if (resource_info->confirm_edit != MagickFalse)
15904 Query user if image has changed.
15906 if ((resource_info->immutable == MagickFalse) &&
15907 (display_image->taint != MagickFalse))
15912 status=XConfirmWidget(display,windows,"Your image changed.",
15913 "Do you want to save it");
15915 *state&=(~ExitState);
15918 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15922 if ((windows->visual_info->klass == GrayScale) ||
15923 (windows->visual_info->klass == PseudoColor) ||
15924 (windows->visual_info->klass == DirectColor))
15927 Withdraw pan and Magnify window.
15929 if (windows->info.mapped != MagickFalse)
15930 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15931 if (windows->magnify.mapped != MagickFalse)
15932 (void) XWithdrawWindow(display,windows->magnify.id,
15933 windows->magnify.screen);
15934 if (windows->command.mapped != MagickFalse)
15935 (void) XWithdrawWindow(display,windows->command.id,
15936 windows->command.screen);
15938 if (windows->pan.mapped != MagickFalse)
15939 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15940 if (resource_info->backdrop == MagickFalse)
15941 if (windows->backdrop.mapped)
15943 (void) XWithdrawWindow(display,windows->backdrop.id,
15944 windows->backdrop.screen);
15945 (void) XDestroyWindow(display,windows->backdrop.id);
15946 windows->backdrop.id=(Window) NULL;
15947 (void) XWithdrawWindow(display,windows->image.id,
15948 windows->image.screen);
15949 (void) XDestroyWindow(display,windows->image.id);
15950 windows->image.id=(Window) NULL;
15952 XSetCursorState(display,windows,MagickTrue);
15953 XCheckRefreshWindows(display,windows);
15954 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15955 *state&=(~ExitState);
15956 if (*state & ExitState)
15959 Free Standard Colormap.
15961 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15962 if (resource_info->map_type == (char *) NULL)
15963 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15967 if (resource_info->copy_image != (Image *) NULL)
15969 resource_info->copy_image=DestroyImage(resource_info->copy_image);
15970 resource_info->copy_image=NewImageList();
15972 DestroyXResources();
15974 (void) XSync(display,MagickFalse);
15976 Restore our progress monitor and warning handlers.
15978 (void) SetErrorHandler(warning_handler);
15979 (void) SetWarningHandler(warning_handler);
15981 Change to home directory.
15983 directory=getcwd(working_directory,MaxTextExtent);
15989 status=chdir(resource_info->home_directory);
15991 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
15992 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
15994 *image=display_image;
16000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16004 + D i s p l a y I m a g e s %
16008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16010 % DisplayImages() displays an image sequence to any X window screen. It
16011 % returns a value other than 0 if successful. Check the exception member
16012 % of image to determine the reason for any failure.
16014 % The format of the DisplayImages method is:
16016 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16019 % A description of each parameter follows:
16021 % o image_info: the image info.
16023 % o image: the image.
16026 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16029 assert(image_info != (const ImageInfo *) NULL);
16030 assert(image_info->signature == MagickSignature);
16031 assert(image != (Image *) NULL);
16032 assert(image->signature == MagickSignature);
16033 if (image->debug != MagickFalse)
16034 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16035 (void) ThrowMagickException(&image->exception,GetMagickModule(),
16036 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
16038 return(MagickFalse);
16042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16046 + R e m o t e D i s p l a y C o m m a n d %
16050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16052 % RemoteDisplayCommand() encourages a remote display program to display the
16053 % specified image filename.
16055 % The format of the RemoteDisplayCommand method is:
16057 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16058 % const char *window,const char *filename,ExceptionInfo *exception)
16060 % A description of each parameter follows:
16062 % o image_info: the image info.
16064 % o window: Specifies the name or id of an X window.
16066 % o filename: the name of the image filename to display.
16068 % o exception: return any errors or warnings in this structure.
16071 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16072 const char *window,const char *filename,ExceptionInfo *exception)
16074 assert(image_info != (const ImageInfo *) NULL);
16075 assert(image_info->signature == MagickSignature);
16076 assert(filename != (char *) NULL);
16078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16079 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16080 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16081 return(MagickFalse);