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 "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/client.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/colorspace.h"
49 #include "MagickCore/composite.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/decorate.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/display.h"
54 #include "MagickCore/display-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/effect.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/fx.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/magick.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/montage.h"
71 #include "MagickCore/option.h"
72 #include "MagickCore/paint.h"
73 #include "MagickCore/pixel.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/PreRvIcccm.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum.h"
78 #include "MagickCore/quantum-private.h"
79 #include "MagickCore/resize.h"
80 #include "MagickCore/resource_.h"
81 #include "MagickCore/shear.h"
82 #include "MagickCore/segment.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/threshold.h"
87 #include "MagickCore/utility.h"
88 #include "MagickCore/version.h"
89 #include "MagickCore/widget.h"
90 #include "MagickCore/xwindow-private.h"
92 #if defined(MAGICKCORE_X11_DELEGATE)
96 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
99 Constant declarations.
101 static const unsigned char
104 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
136 Help widget declarations.
139 *ImageAnnotateHelp[] =
141 "In annotate mode, the Command widget has these options:",
191 "Choose a font name from the Font Name sub-menu. Additional",
192 "font names can be specified with the font browser. You can",
193 "change the menu names by setting the X resources font1",
196 "Choose a font color from the Font Color sub-menu.",
197 "Additional font colors can be specified with the color",
198 "browser. You can change the menu colors by setting the X",
199 "resources pen1 through pen9.",
201 "If you select the color browser and press Grab, you can",
202 "choose the font color by moving the pointer to the desired",
203 "color on the screen and press any button.",
205 "If you choose to rotate the text, choose Rotate Text from the",
206 "menu and select an angle. Typically you will only want to",
207 "rotate one line of text at a time. Depending on the angle you",
208 "choose, subsequent lines may end up overwriting each other.",
210 "Choosing a font and its color is optional. The default font",
211 "is fixed and the default color is black. However, you must",
212 "choose a location to begin entering text and press button 1.",
213 "An underscore character will appear at the location of the",
214 "pointer. The cursor changes to a pencil to indicate you are",
215 "in text mode. To exit immediately, press Dismiss.",
217 "In text mode, any key presses will display the character at",
218 "the location of the underscore and advance the underscore",
219 "cursor. Enter your text and once completed press Apply to",
220 "finish your image annotation. To correct errors press BACK",
221 "SPACE. To delete an entire line of text, press DELETE. Any",
222 "text that exceeds the boundaries of the image window is",
223 "automagically continued onto the next line.",
225 "The actual color you request for the font is saved in the",
226 "image. However, the color that appears in your image window",
227 "may be different. For example, on a monochrome screen the",
228 "text will appear black or white even if you choose the color",
229 "red as the font color. However, the image saved to a file",
230 "with -write is written with red lettering. To assure the",
231 "correct color text in the final image, any PseudoClass image",
232 "is promoted to DirectClass (see miff(5)). To force a",
233 "PseudoClass image to remain PseudoClass, use -colors.",
238 "In chop mode, the Command widget has these options:",
246 "If the you choose the horizontal direction (this the",
247 "default), the area of the image between the two horizontal",
248 "endpoints of the chop line is removed. Otherwise, the area",
249 "of the image between the two vertical endpoints of the chop",
252 "Select a location within the image window to begin your chop,",
253 "press and hold any button. Next, move the pointer to",
254 "another location in the image. As you move a line will",
255 "connect the initial location and the pointer. When you",
256 "release the button, the area within the image to chop is",
257 "determined by which direction you choose from the Command",
260 "To cancel the image chopping, move the pointer back to the",
261 "starting point of the line and release the button.",
264 *ImageColorEditHelp[] =
266 "In color edit mode, the Command widget has these options:",
307 "Choose a color editing method from the Method sub-menu",
308 "of the Command widget. The point method recolors any pixel",
309 "selected with the pointer until the button is released. The",
310 "replace method recolors any pixel that matches the color of",
311 "the pixel you select with a button press. Floodfill recolors",
312 "any pixel that matches the color of the pixel you select with",
313 "a button press and is a neighbor. Whereas filltoborder recolors",
314 "any neighbor pixel that is not the border color. Finally reset",
315 "changes the entire image to the designated color.",
317 "Next, choose a pixel color from the Pixel Color sub-menu.",
318 "Additional pixel colors can be specified with the color",
319 "browser. You can change the menu colors by setting the X",
320 "resources pen1 through pen9.",
322 "Now press button 1 to select a pixel within the image window",
323 "to change its color. Additional pixels may be recolored as",
324 "prescribed by the method you choose.",
326 "If the Magnify widget is mapped, it can be helpful in positioning",
327 "your pointer within the image (refer to button 2).",
329 "The actual color you request for the pixels is saved in the",
330 "image. However, the color that appears in your image window",
331 "may be different. For example, on a monochrome screen the",
332 "pixel will appear black or white even if you choose the",
333 "color red as the pixel color. However, the image saved to a",
334 "file with -write is written with red pixels. To assure the",
335 "correct color text in the final image, any PseudoClass image",
336 "is promoted to DirectClass (see miff(5)). To force a",
337 "PseudoClass image to remain PseudoClass, use -colors.",
340 *ImageCompositeHelp[] =
342 "First a widget window is displayed requesting you to enter an",
343 "image name. Press Composite, Grab or type a file name.",
344 "Press Cancel if you choose not to create a composite image.",
345 "When you choose Grab, move the pointer to the desired window",
346 "and press any button.",
348 "If the Composite image does not have any matte information,",
349 "you are informed and the file browser is displayed again.",
350 "Enter the name of a mask image. The image is typically",
351 "grayscale and the same size as the composite image. If the",
352 "image is not grayscale, it is converted to grayscale and the",
353 "resulting intensities are used as matte information.",
355 "A small window appears showing the location of the cursor in",
356 "the image window. You are now in composite mode. To exit",
357 "immediately, press Dismiss. In composite mode, the Command",
358 "widget has these options:",
384 "Choose a composite operation from the Operators sub-menu of",
385 "the Command widget. How each operator behaves is described",
386 "below. Image window is the image currently displayed on",
387 "your X server and image is the image obtained with the File",
390 "Over The result is the union of the two image shapes,",
391 " with image obscuring image window in the region of",
394 "In The result is simply image cut by the shape of",
395 " image window. None of the image data of image",
396 " window is in the result.",
398 "Out The resulting image is image with the shape of",
399 " image window cut out.",
401 "Atop The result is the same shape as image image window,",
402 " with image obscuring image window where the image",
403 " shapes overlap. Note this differs from over",
404 " because the portion of image outside image window's",
405 " shape does not appear in the result.",
407 "Xor The result is the image data from both image and",
408 " image window that is outside the overlap region.",
409 " The overlap region is blank.",
411 "Plus The result is just the sum of the image data.",
412 " Output values are cropped to QuantumRange (no overflow).",
414 "Minus The result of image - image window, with underflow",
417 "Add The result of image + image window, with overflow",
418 " wrapping around (mod 256).",
420 "Subtract The result of image - image window, with underflow",
421 " wrapping around (mod 256). The add and subtract",
422 " operators can be used to perform reversible",
426 " The result of abs(image - image window). This",
427 " useful for comparing two very similar images.",
430 " The result of image * image window. This",
431 " useful for the creation of drop-shadows.",
433 "Bumpmap The result of surface normals from image * image",
436 "Copy The resulting image is image window replaced with",
437 " image. Here the matte information is ignored.",
439 "CopyRed The red layer of the image window is replace with",
440 " the red layer of the image. The other layers are",
444 " The green layer of the image window is replace with",
445 " the green layer of the image. The other layers are",
448 "CopyBlue The blue layer of the image window is replace with",
449 " the blue layer of the image. The other layers are",
453 " The matte layer of the image window is replace with",
454 " the matte layer of the image. The other layers are",
457 "The image compositor requires a matte, or alpha channel in",
458 "the image for some operations. This extra channel usually",
459 "defines a mask which represents a sort of a cookie-cutter",
460 "for the image. This the case when matte is opaque (full",
461 "coverage) for pixels inside the shape, zero outside, and",
462 "between 0 and QuantumRange on the boundary. If image does not",
463 "have a matte channel, it is initialized with 0 for any pixel",
464 "matching in color to pixel location (0,0), otherwise QuantumRange.",
466 "If you choose Dissolve, the composite operator becomes Over. The",
467 "image matte channel percent transparency is initialized to factor.",
468 "The image window is initialized to (100-factor). Where factor is the",
469 "value you specify in the Dialog widget.",
471 "Displace shifts the image pixels as defined by a displacement",
472 "map. With this option, image is used as a displacement map.",
473 "Black, within the displacement map, is a maximum positive",
474 "displacement. White is a maximum negative displacement and",
475 "middle gray is neutral. The displacement is scaled to determine",
476 "the pixel shift. By default, the displacement applies in both the",
477 "horizontal and vertical directions. However, if you specify a mask,",
478 "image is the horizontal X displacement and mask the vertical Y",
481 "Note that matte information for image window is not retained",
482 "for colormapped X server visuals (e.g. StaticColor,",
483 "StaticColor, GrayScale, PseudoColor). Correct compositing",
484 "behavior may require a TrueColor or DirectColor visual or a",
485 "Standard Colormap.",
487 "Choosing a composite operator is optional. The default",
488 "operator is replace. However, you must choose a location to",
489 "composite your image and press button 1. Press and hold the",
490 "button before releasing and an outline of the image will",
491 "appear to help you identify your location.",
493 "The actual colors of the composite image is saved. However,",
494 "the color that appears in image window may be different.",
495 "For example, on a monochrome screen image window will appear",
496 "black or white even though your composited image may have",
497 "many colors. If the image is saved to a file it is written",
498 "with the correct colors. To assure the correct colors are",
499 "saved in the final image, any PseudoClass image is promoted",
500 "to DirectClass (see miff(5)). To force a PseudoClass image",
501 "to remain PseudoClass, use -colors.",
506 "In cut mode, the Command widget has these options:",
511 "To define a cut region, press button 1 and drag. The",
512 "cut region is defined by a highlighted rectangle that",
513 "expands or contracts as it follows the pointer. Once you",
514 "are satisfied with the cut region, release the button.",
515 "You are now in rectify mode. In rectify mode, the Command",
516 "widget has these options:",
522 "You can make adjustments by moving the pointer to one of the",
523 "cut rectangle corners, pressing a button, and dragging.",
524 "Finally, press Cut to commit your copy region. To",
525 "exit without cutting the image, press Dismiss.",
530 "In copy mode, the Command widget has these options:",
535 "To define a copy region, press button 1 and drag. The",
536 "copy region is defined by a highlighted rectangle that",
537 "expands or contracts as it follows the pointer. Once you",
538 "are satisfied with the copy region, release the button.",
539 "You are now in rectify mode. In rectify mode, the Command",
540 "widget has these options:",
546 "You can make adjustments by moving the pointer to one of the",
547 "copy rectangle corners, pressing a button, and dragging.",
548 "Finally, press Copy to commit your copy region. To",
549 "exit without copying the image, press Dismiss.",
554 "In crop mode, the Command widget has these options:",
559 "To define a cropping region, press button 1 and drag. The",
560 "cropping region is defined by a highlighted rectangle that",
561 "expands or contracts as it follows the pointer. Once you",
562 "are satisfied with the cropping region, release the button.",
563 "You are now in rectify mode. In rectify mode, the Command",
564 "widget has these options:",
570 "You can make adjustments by moving the pointer to one of the",
571 "cropping rectangle corners, pressing a button, and dragging.",
572 "Finally, press Crop to commit your cropping region. To",
573 "exit without cropping the image, press Dismiss.",
578 "The cursor changes to a crosshair to indicate you are in",
579 "draw mode. To exit immediately, press Dismiss. In draw mode,",
580 "the Command widget has these options:",
625 "Choose a drawing primitive from the Element sub-menu.",
627 "Choose a color from the Color sub-menu. Additional",
628 "colors can be specified with the color browser.",
630 "If you choose the color browser and press Grab, you can",
631 "select the color by moving the pointer to the desired",
632 "color on the screen and press any button. The transparent",
633 "color updates the image matte channel and is useful for",
634 "image compositing.",
636 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
637 "Additional stipples can be specified with the file browser.",
638 "Stipples obtained from the file browser must be on disk in the",
639 "X11 bitmap format.",
641 "Choose a width, if appropriate, from the Width sub-menu. To",
642 "choose a specific width select the Dialog widget.",
644 "Choose a point in the Image window and press button 1 and",
645 "hold. Next, move the pointer to another location in the",
646 "image. As you move, a line connects the initial location and",
647 "the pointer. When you release the button, the image is",
648 "updated with the primitive you just drew. For polygons, the",
649 "image is updated when you press and release the button without",
650 "moving the pointer.",
652 "To cancel image drawing, move the pointer back to the",
653 "starting point of the line and release the button.",
659 " The effects of each button press is described below. Three",
660 " buttons are required. If you have a two button mouse,",
661 " button 1 and 3 are returned. Press ALT and button 3 to",
662 " simulate button 2.",
664 " 1 Press this button to map or unmap the Command widget.",
666 " 2 Press and drag to define a region of the image to",
669 " 3 Press and drag to choose from a select set of commands.",
670 " This button behaves differently if the image being",
671 " displayed is a visual image directory. Here, choose a",
672 " particular tile of the directory and press this button and",
673 " drag to select a command from a pop-up menu. Choose from",
674 " these menu items:",
682 " If you choose Open, the image represented by the tile is",
683 " displayed. To return to the visual image directory, choose",
684 " Next from the Command widget. Next and Former moves to the",
685 " next or former image respectively. Choose Delete to delete",
686 " a particular image tile. Finally, choose Update to",
687 " synchronize all the image tiles with their respective",
691 " The Command widget lists a number of sub-menus and commands.",
703 " Visual Directory...",
737 " Contrast Stretch...",
738 " Sigmoidal Contrast...",
766 " Charcoal Drawing...",
777 " Region of Interest...",
789 " Browse Documentation",
792 " Menu items with a indented triangle have a sub-menu. They",
793 " are represented above as the indented items. To access a",
794 " sub-menu item, move the pointer to the appropriate menu and",
795 " press a button and drag. When you find the desired sub-menu",
796 " item, release the button and the command is executed. Move",
797 " the pointer away from the sub-menu if you decide not to",
798 " execute a particular command.",
800 "KEYBOARD ACCELERATORS",
801 " Accelerators are one or two key presses that effect a",
802 " particular command. The keyboard accelerators that",
803 " display(1) understands is:",
805 " Ctl+O Press to open an image from a file.",
807 " space Press to display the next image.",
809 " If the image is a multi-paged document such as a Postscript",
810 " document, you can skip ahead several pages by preceding",
811 " this command with a number. For example to display the",
812 " third page beyond the current page, press 3<space>.",
814 " backspace Press to display the former image.",
816 " If the image is a multi-paged document such as a Postscript",
817 " document, you can skip behind several pages by preceding",
818 " this command with a number. For example to display the",
819 " third page preceding the current page, press 3<backspace>.",
821 " Ctl+S Press to write the image to a file.",
823 " Ctl+P Press to print the image to a Postscript printer.",
825 " Ctl+D Press to delete an image file.",
827 " Ctl+N Press to create a blank canvas.",
829 " Ctl+Q Press to discard all images and exit program.",
831 " Ctl+Z Press to undo last image transformation.",
833 " Ctl+R Press to redo last image transformation.",
835 " Ctl+X Press to cut a region of the image.",
837 " Ctl+C Press to copy a region of the image.",
839 " Ctl+V Press to paste a region to the image.",
841 " < Press to half the image size.",
843 " - Press to return to the original image size.",
845 " > Press to double the image size.",
847 " % Press to resize the image to a width and height you",
850 "Cmd-A Press to make any image transformations permanent."
852 " By default, any image size transformations are applied",
853 " to the original image to create the image displayed on",
854 " the X server. However, the transformations are not",
855 " permanent (i.e. the original image does not change",
856 " size only the X image does). For example, if you",
857 " press > the X image will appear to double in size,",
858 " but the original image will in fact remain the same size.",
859 " To force the original image to double in size, press >",
860 " followed by Cmd-A.",
862 " @ Press to refresh the image window.",
864 " C Press to cut out a rectangular region of the image.",
866 " [ Press to chop the image.",
868 " H Press to flop image in the horizontal direction.",
870 " V Press to flip image in the vertical direction.",
872 " / Press to rotate the image 90 degrees clockwise.",
874 " \\ Press to rotate the image 90 degrees counter-clockwise.",
876 " * Press to rotate the image the number of degrees you",
879 " S Press to shear the image the number of degrees you",
882 " R Press to roll the image.",
884 " T Press to trim the image edges.",
886 " Shft-H Press to vary the image hue.",
888 " Shft-S Press to vary the color saturation.",
890 " Shft-L Press to vary the color brightness.",
892 " Shft-G Press to gamma correct the image.",
894 " Shft-C Press to sharpen the image contrast.",
896 " Shft-Z Press to dull the image contrast.",
898 " = Press to perform histogram equalization on the image.",
900 " Shft-N Press to perform histogram normalization on the image.",
902 " Shft-~ Press to negate the colors of the image.",
904 " . Press to convert the image colors to gray.",
906 " Shft-# Press to set the maximum number of unique colors in the",
909 " F2 Press to reduce the speckles in an image.",
911 " F3 Press to eliminate peak noise from an image.",
913 " F4 Press to add noise to an image.",
915 " F5 Press to sharpen an image.",
917 " F6 Press to delete an image file.",
919 " F7 Press to threshold the image.",
921 " F8 Press to detect edges within an image.",
923 " F9 Press to emboss an image.",
925 " F10 Press to displace pixels by a random amount.",
927 " F11 Press to negate all pixels above the threshold level.",
929 " F12 Press to shade the image using a distant light source.",
931 " F13 Press to lighten or darken image edges to create a 3-D effect.",
933 " F14 Press to segment the image by color.",
935 " Meta-S Press to swirl image pixels about the center.",
937 " Meta-I Press to implode image pixels about the center.",
939 " Meta-W Press to alter an image along a sine wave.",
941 " Meta-P Press to simulate an oil painting.",
943 " Meta-C Press to simulate a charcoal drawing.",
945 " Alt-A Press to annotate the image with text.",
947 " Alt-D Press to draw on an image.",
949 " Alt-P Press to edit an image pixel color.",
951 " Alt-M Press to edit the image matte information.",
953 " Alt-V Press to composite the image with another.",
955 " Alt-B Press to add a border to the image.",
957 " Alt-F Press to add an ornamental border to the image.",
960 " Press to add an image comment.",
962 " Ctl-A Press to apply image processing techniques to a region",
965 " Shft-? Press to display information about the image.",
967 " Shft-+ Press to map the zoom image window.",
969 " Shft-P Press to preview an image enhancement, effect, or f/x.",
971 " F1 Press to display helpful information about display(1).",
973 " Find Press to browse documentation about ImageMagick.",
975 " 1-9 Press to change the level of magnification.",
977 " Use the arrow keys to move the image one pixel up, down,",
978 " left, or right within the magnify window. Be sure to first",
979 " map the magnify window by pressing button 2.",
981 " Press ALT and one of the arrow keys to trim off one pixel",
982 " from any side of the image.",
985 *ImageMatteEditHelp[] =
987 "Matte information within an image is useful for some",
988 "operations such as image compositing (See IMAGE",
989 "COMPOSITING). This extra channel usually defines a mask",
990 "which represents a sort of a cookie-cutter for the image.",
991 "This the case when matte is opaque (full coverage) for",
992 "pixels inside the shape, zero outside, and between 0 and",
993 "QuantumRange on the boundary.",
995 "A small window appears showing the location of the cursor in",
996 "the image window. You are now in matte edit mode. To exit",
997 "immediately, press Dismiss. In matte edit mode, the Command",
998 "widget has these options:",
1032 "Choose a matte editing method from the Method sub-menu of",
1033 "the Command widget. The point method changes the matte value",
1034 "of any pixel selected with the pointer until the button is",
1035 "is released. The replace method changes the matte value of",
1036 "any pixel that matches the color of the pixel you select with",
1037 "a button press. Floodfill changes the matte value of any pixel",
1038 "that matches the color of the pixel you select with a button",
1039 "press and is a neighbor. Whereas filltoborder changes the matte",
1040 "value any neighbor pixel that is not the border color. Finally",
1041 "reset changes the entire image to the designated matte value.",
1043 "Choose Matte Value and pick Opaque or Transarent. For other values",
1044 "select the Dialog entry. Here a dialog appears requesting a matte",
1045 "value. The value you select is assigned as the opacity value of the",
1046 "selected pixel or pixels.",
1048 "Now, press any button to select a pixel within the image",
1049 "window to change its matte value.",
1051 "If the Magnify widget is mapped, it can be helpful in positioning",
1052 "your pointer within the image (refer to button 2).",
1054 "Matte information is only valid in a DirectClass image.",
1055 "Therefore, any PseudoClass image is promoted to DirectClass",
1056 "(see miff(5)). Note that matte information for PseudoClass",
1057 "is not retained for colormapped X server visuals (e.g.",
1058 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1059 "immediately save your image to a file (refer to Write).",
1060 "Correct matte editing behavior may require a TrueColor or",
1061 "DirectColor visual or a Standard Colormap.",
1066 "When an image exceeds the width or height of the X server",
1067 "screen, display maps a small panning icon. The rectangle",
1068 "within the panning icon shows the area that is currently",
1069 "displayed in the image window. To pan about the image,",
1070 "press any button and drag the pointer within the panning",
1071 "icon. The pan rectangle moves with the pointer and the",
1072 "image window is updated to reflect the location of the",
1073 "rectangle within the panning icon. When you have selected",
1074 "the area of the image you wish to view, release the button.",
1076 "Use the arrow keys to pan the image one pixel up, down,",
1077 "left, or right within the image window.",
1079 "The panning icon is withdrawn if the image becomes smaller",
1080 "than the dimensions of the X server screen.",
1085 "A small window appears showing the location of the cursor in",
1086 "the image window. You are now in paste mode. To exit",
1087 "immediately, press Dismiss. In paste mode, the Command",
1088 "widget has these options:",
1105 "Choose a composite operation from the Operators sub-menu of",
1106 "the Command widget. How each operator behaves is described",
1107 "below. Image window is the image currently displayed on",
1108 "your X server and image is the image obtained with the File",
1111 "Over The result is the union of the two image shapes,",
1112 " with image obscuring image window in the region of",
1115 "In The result is simply image cut by the shape of",
1116 " image window. None of the image data of image",
1117 " window is in the result.",
1119 "Out The resulting image is image with the shape of",
1120 " image window cut out.",
1122 "Atop The result is the same shape as image image window,",
1123 " with image obscuring image window where the image",
1124 " shapes overlap. Note this differs from over",
1125 " because the portion of image outside image window's",
1126 " shape does not appear in the result.",
1128 "Xor The result is the image data from both image and",
1129 " image window that is outside the overlap region.",
1130 " The overlap region is blank.",
1132 "Plus The result is just the sum of the image data.",
1133 " Output values are cropped to QuantumRange (no overflow).",
1134 " This operation is independent of the matte",
1137 "Minus The result of image - image window, with underflow",
1138 " cropped to zero.",
1140 "Add The result of image + image window, with overflow",
1141 " wrapping around (mod 256).",
1143 "Subtract The result of image - image window, with underflow",
1144 " wrapping around (mod 256). The add and subtract",
1145 " operators can be used to perform reversible",
1146 " transformations.",
1149 " The result of abs(image - image window). This",
1150 " useful for comparing two very similar images.",
1152 "Copy The resulting image is image window replaced with",
1153 " image. Here the matte information is ignored.",
1155 "CopyRed The red layer of the image window is replace with",
1156 " the red layer of the image. The other layers are",
1160 " The green layer of the image window is replace with",
1161 " the green layer of the image. The other layers are",
1164 "CopyBlue The blue layer of the image window is replace with",
1165 " the blue layer of the image. The other layers are",
1169 " The matte layer of the image window is replace with",
1170 " the matte layer of the image. The other layers are",
1173 "The image compositor requires a matte, or alpha channel in",
1174 "the image for some operations. This extra channel usually",
1175 "defines a mask which represents a sort of a cookie-cutter",
1176 "for the image. This the case when matte is opaque (full",
1177 "coverage) for pixels inside the shape, zero outside, and",
1178 "between 0 and QuantumRange on the boundary. If image does not",
1179 "have a matte channel, it is initialized with 0 for any pixel",
1180 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1182 "Note that matte information for image window is not retained",
1183 "for colormapped X server visuals (e.g. StaticColor,",
1184 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1185 "behavior may require a TrueColor or DirectColor visual or a",
1186 "Standard Colormap.",
1188 "Choosing a composite operator is optional. The default",
1189 "operator is replace. However, you must choose a location to",
1190 "paste your image and press button 1. Press and hold the",
1191 "button before releasing and an outline of the image will",
1192 "appear to help you identify your location.",
1194 "The actual colors of the pasted image is saved. However,",
1195 "the color that appears in image window may be different.",
1196 "For example, on a monochrome screen image window will appear",
1197 "black or white even though your pasted image may have",
1198 "many colors. If the image is saved to a file it is written",
1199 "with the correct colors. To assure the correct colors are",
1200 "saved in the final image, any PseudoClass image is promoted",
1201 "to DirectClass (see miff(5)). To force a PseudoClass image",
1202 "to remain PseudoClass, use -colors.",
1207 "In region of interest mode, the Command widget has these",
1213 "To define a region of interest, press button 1 and drag.",
1214 "The region of interest is defined by a highlighted rectangle",
1215 "that expands or contracts as it follows the pointer. Once",
1216 "you are satisfied with the region of interest, release the",
1217 "button. You are now in apply mode. In apply mode the",
1218 "Command widget has these options:",
1238 " Contrast Stretch",
1239 " Sigmoidal Contrast...",
1266 " Charcoal Drawing...",
1276 "You can make adjustments to the region of interest by moving",
1277 "the pointer to one of the rectangle corners, pressing a",
1278 "button, and dragging. Finally, choose an image processing",
1279 "technique from the Command widget. You can choose more than",
1280 "one image processing technique to apply to an area.",
1281 "Alternatively, you can move the region of interest before",
1282 "applying another image processing technique. To exit, press",
1286 *ImageRotateHelp[] =
1288 "In rotate mode, the Command widget has these options:",
1307 "Choose a background color from the Pixel Color sub-menu.",
1308 "Additional background colors can be specified with the color",
1309 "browser. You can change the menu colors by setting the X",
1310 "resources pen1 through pen9.",
1312 "If you choose the color browser and press Grab, you can",
1313 "select the background color by moving the pointer to the",
1314 "desired color on the screen and press any button.",
1316 "Choose a point in the image window and press this button and",
1317 "hold. Next, move the pointer to another location in the",
1318 "image. As you move a line connects the initial location and",
1319 "the pointer. When you release the button, the degree of",
1320 "image rotation is determined by the slope of the line you",
1321 "just drew. The slope is relative to the direction you",
1322 "choose from the Direction sub-menu of the Command widget.",
1324 "To cancel the image rotation, move the pointer back to the",
1325 "starting point of the line and release the button.",
1330 Enumeration declarations.
1349 VisualDirectoryCommand,
1357 OriginalSizeCommand,
1379 ContrastStretchCommand,
1380 SigmoidalContrastCommand,
1406 CharcoalDrawCommand,
1416 RegionofInterestCommand,
1422 ShowHistogramCommand,
1428 BrowseDocumentationCommand,
1430 SaveToUndoBufferCommand,
1437 AnnotateNameCommand,
1438 AnnotateFontColorCommand,
1439 AnnotateBackgroundColorCommand,
1440 AnnotateRotateCommand,
1441 AnnotateHelpCommand,
1442 AnnotateDismissCommand,
1445 ChopDirectionCommand,
1448 HorizontalChopCommand,
1449 VerticalChopCommand,
1450 ColorEditMethodCommand,
1451 ColorEditColorCommand,
1452 ColorEditBorderCommand,
1453 ColorEditFuzzCommand,
1454 ColorEditUndoCommand,
1455 ColorEditHelpCommand,
1456 ColorEditDismissCommand,
1457 CompositeOperatorsCommand,
1458 CompositeDissolveCommand,
1459 CompositeDisplaceCommand,
1460 CompositeHelpCommand,
1461 CompositeDismissCommand,
1466 RectifyDismissCommand,
1475 MatteEditBorderCommand,
1476 MatteEditFuzzCommand,
1477 MatteEditValueCommand,
1478 MatteEditUndoCommand,
1479 MatteEditHelpCommand,
1480 MatteEditDismissCommand,
1481 PasteOperatorsCommand,
1483 PasteDismissCommand,
1485 RotateDirectionCommand,
1487 RotateSharpenCommand,
1489 RotateDismissCommand,
1490 HorizontalRotateCommand,
1491 VerticalRotateCommand,
1502 #define BricksWidth 20
1503 #define BricksHeight 20
1504 #define DiagonalWidth 16
1505 #define DiagonalHeight 16
1506 #define HighlightWidth 8
1507 #define HighlightHeight 8
1508 #define OpaqueWidth 8
1509 #define OpaqueHeight 8
1510 #define ScalesWidth 16
1511 #define ScalesHeight 16
1512 #define ShadowWidth 8
1513 #define ShadowHeight 8
1514 #define VerticalWidth 16
1515 #define VerticalHeight 16
1516 #define WavyWidth 16
1517 #define WavyHeight 16
1520 Constant declaration.
1525 static const unsigned char
1528 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1529 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1530 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1531 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1532 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1536 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1537 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1538 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1542 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1543 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1544 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1548 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1549 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1550 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1554 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1555 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1556 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1560 Function prototypes.
1563 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1564 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
1567 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1568 Image **,ExceptionInfo *),
1569 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1570 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1572 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1575 static MagickBooleanType
1576 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1578 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1580 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1582 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1584 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1586 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1588 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1589 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1591 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1593 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1594 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1595 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1597 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1598 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1599 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
1602 XDrawPanRectangle(Display *,XWindows *),
1603 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1605 XMagnifyImage(Display *,XWindows *,XEvent *),
1606 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1607 XPanImage(Display *,XWindows *,XEvent *),
1608 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1610 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1611 XScreenEvent(Display *,XWindows *,XEvent *),
1612 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % D i s p l a y I m a g e s %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % DisplayImages() displays an image sequence to any X window screen. It
1626 % returns a value other than 0 if successful. Check the exception member
1627 % of image to determine the reason for any failure.
1629 % The format of the DisplayImages method is:
1631 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1632 % Image *images,ExceptionInfo *exception)
1634 % A description of each parameter follows:
1636 % o image_info: the image info.
1638 % o image: the image.
1640 % o exception: return any errors or warnings in this structure.
1643 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1644 Image *images,ExceptionInfo *exception)
1667 assert(image_info != (const ImageInfo *) NULL);
1668 assert(image_info->signature == MagickSignature);
1669 assert(images != (Image *) NULL);
1670 assert(images->signature == MagickSignature);
1671 if (images->debug != MagickFalse)
1672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1673 display=XOpenDisplay(image_info->server_name);
1674 if (display == (Display *) NULL)
1676 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1677 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1678 return(MagickFalse);
1680 if (exception->severity != UndefinedException)
1681 CatchException(exception);
1682 (void) XSetErrorHandler(XError);
1683 resource_database=XGetResourceDatabase(display,GetClientName());
1684 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1685 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1686 if (image_info->page != (char *) NULL)
1687 resource_info.image_geometry=AcquireString(image_info->page);
1688 resource_info.immutable=MagickTrue;
1689 argv[0]=AcquireString(GetClientName());
1691 for (i=0; (state & ExitState) == 0; i++)
1693 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1695 image=GetImageFromList(images,i % GetImageListLength(images));
1696 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
1698 argv[0]=DestroyString(argv[0]);
1699 (void) XCloseDisplay(display);
1700 XDestroyResourceInfo(&resource_info);
1701 if (exception->severity != UndefinedException)
1702 return(MagickFalse);
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711 % R e m o t e D i s p l a y C o m m a n d %
1715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717 % RemoteDisplayCommand() encourages a remote display program to display the
1718 % specified image filename.
1720 % The format of the RemoteDisplayCommand method is:
1722 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1723 % const char *window,const char *filename,ExceptionInfo *exception)
1725 % A description of each parameter follows:
1727 % o image_info: the image info.
1729 % o window: Specifies the name or id of an X window.
1731 % o filename: the name of the image filename to display.
1733 % o exception: return any errors or warnings in this structure.
1736 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1737 const char *window,const char *filename,ExceptionInfo *exception)
1745 assert(image_info != (const ImageInfo *) NULL);
1746 assert(image_info->signature == MagickSignature);
1747 assert(filename != (char *) NULL);
1748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1749 display=XOpenDisplay(image_info->server_name);
1750 if (display == (Display *) NULL)
1752 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1753 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1754 return(MagickFalse);
1756 (void) XSetErrorHandler(XError);
1757 status=XRemoteCommand(display,window,filename);
1758 (void) XCloseDisplay(display);
1759 return(status != 0 ? MagickTrue : MagickFalse);
1763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1767 + X A n n o t a t e E d i t I m a g e %
1771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773 % XAnnotateEditImage() annotates the image with text.
1775 % The format of the XAnnotateEditImage method is:
1777 % MagickBooleanType XAnnotateEditImage(Display *display,
1778 % XResourceInfo *resource_info,XWindows *windows,Image *image,
1779 % ExceptionInfo *exception)
1781 % A description of each parameter follows:
1783 % o display: Specifies a connection to an X server; returned from
1786 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1788 % o windows: Specifies a pointer to a XWindows structure.
1790 % o image: the image; returned from ReadImage.
1794 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1801 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1808 static MagickBooleanType XAnnotateEditImage(Display *display,
1809 XResourceInfo *resource_info,XWindows *windows,Image *image,
1810 ExceptionInfo *exception)
1830 static const ModeType
1831 AnnotateCommands[] =
1833 AnnotateNameCommand,
1834 AnnotateFontColorCommand,
1835 AnnotateBackgroundColorCommand,
1836 AnnotateRotateCommand,
1837 AnnotateHelpCommand,
1838 AnnotateDismissCommand
1846 static MagickBooleanType
1847 transparent_box = MagickTrue,
1848 transparent_pen = MagickFalse;
1850 static MagickRealType
1854 box_id = MaxNumberPens-2,
1859 command[MaxTextExtent],
1860 text[MaxTextExtent];
1863 *ColorMenu[MaxNumberPens+1];
1911 (void) CloneString(&windows->command.name,"Annotate");
1912 windows->command.data=4;
1913 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1914 (void) XMapRaised(display,windows->command.id);
1915 XClientMessage(display,windows->image.id,windows->im_protocols,
1916 windows->im_update_widget,CurrentTime);
1918 Track pointer until button 1 is pressed.
1920 XQueryPosition(display,windows->image.id,&x,&y);
1921 (void) XSelectInput(display,windows->image.id,
1922 windows->image.attributes.event_mask | PointerMotionMask);
1923 cursor=XCreateFontCursor(display,XC_left_side);
1924 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1928 if (windows->info.mapped != MagickFalse)
1931 Display pointer position.
1933 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
1934 x+windows->image.x,y+windows->image.y);
1935 XInfoWidget(display,windows,text);
1938 Wait for next event.
1940 XScreenEvent(display,windows,&event);
1941 if (event.xany.window == windows->command.id)
1944 Select a command from the Command widget.
1946 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1947 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1950 switch (AnnotateCommands[id])
1952 case AnnotateNameCommand:
1955 *FontMenu[MaxNumberFonts];
1961 Initialize menu selections.
1963 for (i=0; i < MaxNumberFonts; i++)
1964 FontMenu[i]=resource_info->font_name[i];
1965 FontMenu[MaxNumberFonts-2]="Browser...";
1966 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1968 Select a font name from the pop-up menu.
1970 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1971 (const char **) FontMenu,command);
1972 if (font_number < 0)
1974 if (font_number == (MaxNumberFonts-2))
1977 font_name[MaxTextExtent] = "fixed";
1980 Select a font name from a browser.
1982 resource_info->font_name[font_number]=font_name;
1983 XFontBrowserWidget(display,windows,"Select",font_name);
1984 if (*font_name == '\0')
1988 Initialize font info.
1990 font_info=XLoadQueryFont(display,resource_info->font_name[
1992 if (font_info == (XFontStruct *) NULL)
1994 XNoticeWidget(display,windows,"Unable to load font:",
1995 resource_info->font_name[font_number]);
1998 font_id=(unsigned int) font_number;
1999 (void) XFreeFont(display,font_info);
2002 case AnnotateFontColorCommand:
2005 Initialize menu selections.
2007 for (i=0; i < (int) (MaxNumberPens-2); i++)
2008 ColorMenu[i]=resource_info->pen_colors[i];
2009 ColorMenu[MaxNumberPens-2]="transparent";
2010 ColorMenu[MaxNumberPens-1]="Browser...";
2011 ColorMenu[MaxNumberPens]=(const char *) NULL;
2013 Select a pen color from the pop-up menu.
2015 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2016 (const char **) ColorMenu,command);
2019 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2021 if (transparent_pen != MagickFalse)
2023 if (pen_number == (MaxNumberPens-1))
2026 color_name[MaxTextExtent] = "gray";
2029 Select a pen color from a dialog.
2031 resource_info->pen_colors[pen_number]=color_name;
2032 XColorBrowserWidget(display,windows,"Select",color_name);
2033 if (*color_name == '\0')
2039 (void) XParseColor(display,windows->map_info->colormap,
2040 resource_info->pen_colors[pen_number],&color);
2041 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2042 (unsigned int) MaxColors,&color);
2043 windows->pixel_info->pen_colors[pen_number]=color;
2044 pen_id=(unsigned int) pen_number;
2047 case AnnotateBackgroundColorCommand:
2050 Initialize menu selections.
2052 for (i=0; i < (int) (MaxNumberPens-2); i++)
2053 ColorMenu[i]=resource_info->pen_colors[i];
2054 ColorMenu[MaxNumberPens-2]="transparent";
2055 ColorMenu[MaxNumberPens-1]="Browser...";
2056 ColorMenu[MaxNumberPens]=(const char *) NULL;
2058 Select a pen color from the pop-up menu.
2060 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2061 (const char **) ColorMenu,command);
2064 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2066 if (transparent_box != MagickFalse)
2068 if (pen_number == (MaxNumberPens-1))
2071 color_name[MaxTextExtent] = "gray";
2074 Select a pen color from a dialog.
2076 resource_info->pen_colors[pen_number]=color_name;
2077 XColorBrowserWidget(display,windows,"Select",color_name);
2078 if (*color_name == '\0')
2084 (void) XParseColor(display,windows->map_info->colormap,
2085 resource_info->pen_colors[pen_number],&color);
2086 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2087 (unsigned int) MaxColors,&color);
2088 windows->pixel_info->pen_colors[pen_number]=color;
2089 box_id=(unsigned int) pen_number;
2092 case AnnotateRotateCommand:
2098 angle[MaxTextExtent] = "30.0";
2116 Select a command from the pop-up menu.
2118 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2124 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL);
2127 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2131 degrees=InterpretLocaleValue(angle,(char **) NULL);
2134 case AnnotateHelpCommand:
2136 XTextViewWidget(display,resource_info,windows,MagickFalse,
2137 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2140 case AnnotateDismissCommand:
2158 if (event.xbutton.button != Button1)
2160 if (event.xbutton.window != windows->image.id)
2163 Change to text entering mode.
2176 if (event.xkey.window != windows->image.id)
2179 Respond to a user key press.
2181 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2182 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2183 switch ((int) key_symbol)
2198 XTextViewWidget(display,resource_info,windows,MagickFalse,
2199 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2204 (void) XBell(display,0);
2213 Map and unmap Info widget as cursor crosses its boundaries.
2217 if (windows->info.mapped != MagickFalse)
2219 if ((x < (int) (windows->info.x+windows->info.width)) &&
2220 (y < (int) (windows->info.y+windows->info.height)))
2221 (void) XWithdrawWindow(display,windows->info.id,
2222 windows->info.screen);
2225 if ((x > (int) (windows->info.x+windows->info.width)) ||
2226 (y > (int) (windows->info.y+windows->info.height)))
2227 (void) XMapWindow(display,windows->info.id);
2233 } while ((state & ExitState) == 0);
2234 (void) XSelectInput(display,windows->image.id,
2235 windows->image.attributes.event_mask);
2236 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2237 if ((state & EscapeState) != 0)
2240 Set font info and check boundary conditions.
2242 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2243 if (font_info == (XFontStruct *) NULL)
2245 XNoticeWidget(display,windows,"Unable to load font:",
2246 resource_info->font_name[font_id]);
2247 font_info=windows->font_info;
2249 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2250 x=(int) windows->image.width-font_info->max_bounds.width;
2251 if (y < (int) (font_info->ascent+font_info->descent))
2252 y=(int) font_info->ascent+font_info->descent;
2253 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2254 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2255 return(MagickFalse);
2257 Initialize annotate structure.
2259 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2260 if (annotate_info == (XAnnotateInfo *) NULL)
2261 return(MagickFalse);
2262 XGetAnnotateInfo(annotate_info);
2265 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2266 annotate_info->stencil=OpaqueStencil;
2268 if (transparent_box == MagickFalse)
2269 annotate_info->stencil=BackgroundStencil;
2271 annotate_info->stencil=ForegroundStencil;
2272 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2273 annotate_info->degrees=degrees;
2274 annotate_info->font_info=font_info;
2275 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2276 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2277 sizeof(*annotate_info->text));
2278 if (annotate_info->text == (char *) NULL)
2279 return(MagickFalse);
2281 Create cursor and set graphic context.
2283 cursor=XCreateFontCursor(display,XC_pencil);
2284 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2285 annotate_context=windows->image.annotate_context;
2286 (void) XSetFont(display,annotate_context,font_info->fid);
2287 (void) XSetBackground(display,annotate_context,
2288 windows->pixel_info->pen_colors[box_id].pixel);
2289 (void) XSetForeground(display,annotate_context,
2290 windows->pixel_info->pen_colors[pen_id].pixel);
2292 Begin annotating the image with text.
2294 (void) CloneString(&windows->command.name,"Text");
2295 windows->command.data=0;
2296 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2298 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2299 text_event.xexpose.width=(int) font_info->max_bounds.width;
2300 text_event.xexpose.height=font_info->max_bounds.ascent+
2301 font_info->max_bounds.descent;
2302 p=annotate_info->text;
2306 Display text cursor.
2309 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2311 Wait for next event.
2313 XScreenEvent(display,windows,&event);
2314 if (event.xany.window == windows->command.id)
2317 Select a command from the Command widget.
2319 (void) XSetBackground(display,annotate_context,
2320 windows->pixel_info->background_color.pixel);
2321 (void) XSetForeground(display,annotate_context,
2322 windows->pixel_info->foreground_color.pixel);
2323 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2324 (void) XSetBackground(display,annotate_context,
2325 windows->pixel_info->pen_colors[box_id].pixel);
2326 (void) XSetForeground(display,annotate_context,
2327 windows->pixel_info->pen_colors[pen_id].pixel);
2330 switch (TextCommands[id])
2332 case TextHelpCommand:
2334 XTextViewWidget(display,resource_info,windows,MagickFalse,
2335 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2336 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2339 case TextApplyCommand:
2342 Finished annotating.
2344 annotate_info->width=(unsigned int) XTextWidth(font_info,
2345 annotate_info->text,(int) strlen(annotate_info->text));
2346 XRefreshWindow(display,&windows->image,&text_event);
2358 text_event.xexpose.x=x;
2359 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2360 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2361 (unsigned int) text_event.xexpose.width,(unsigned int)
2362 text_event.xexpose.height,MagickFalse);
2363 XRefreshWindow(display,&windows->image,&text_event);
2368 if (event.xbutton.window != windows->image.id)
2370 if (event.xbutton.button == Button2)
2373 Request primary selection.
2375 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2376 windows->image.id,CurrentTime);
2383 if (event.xexpose.count == 0)
2389 Refresh Image window.
2391 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2392 text_info=annotate_info;
2393 while (text_info != (XAnnotateInfo *) NULL)
2395 if (annotate_info->stencil == ForegroundStencil)
2396 (void) XDrawString(display,windows->image.id,annotate_context,
2397 text_info->x,text_info->y,text_info->text,
2398 (int) strlen(text_info->text));
2400 (void) XDrawImageString(display,windows->image.id,
2401 annotate_context,text_info->x,text_info->y,text_info->text,
2402 (int) strlen(text_info->text));
2403 text_info=text_info->previous;
2405 (void) XDrawString(display,windows->image.id,annotate_context,
2415 if (event.xkey.window != windows->image.id)
2418 Respond to a user key press.
2420 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2421 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2422 *(command+length)='\0';
2423 if (((event.xkey.state & ControlMask) != 0) ||
2424 ((event.xkey.state & Mod1Mask) != 0))
2425 state|=ModifierState;
2426 if ((state & ModifierState) != 0)
2427 switch ((int) key_symbol)
2432 key_symbol=DeleteCommand;
2438 switch ((int) key_symbol)
2443 Erase one character.
2445 if (p == annotate_info->text)
2447 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2452 Go to end of the previous line of text.
2454 annotate_info=annotate_info->previous;
2455 p=annotate_info->text;
2456 x=annotate_info->x+annotate_info->width;
2458 if (annotate_info->width != 0)
2459 p+=strlen(annotate_info->text);
2464 x-=XTextWidth(font_info,p,1);
2465 text_event.xexpose.x=x;
2466 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2467 XRefreshWindow(display,&windows->image,&text_event);
2470 case XK_bracketleft:
2472 key_symbol=XK_Escape;
2478 Erase the entire line of text.
2480 while (p != annotate_info->text)
2483 x-=XTextWidth(font_info,p,1);
2484 text_event.xexpose.x=x;
2485 XRefreshWindow(display,&windows->image,&text_event);
2493 Finished annotating.
2495 annotate_info->width=(unsigned int) XTextWidth(font_info,
2496 annotate_info->text,(int) strlen(annotate_info->text));
2497 XRefreshWindow(display,&windows->image,&text_event);
2504 Draw a single character on the Image window.
2506 if ((state & ModifierState) != 0)
2508 if (*command == '\0')
2511 if (annotate_info->stencil == ForegroundStencil)
2512 (void) XDrawString(display,windows->image.id,annotate_context,
2515 (void) XDrawImageString(display,windows->image.id,
2516 annotate_context,x,y,p,1);
2517 x+=XTextWidth(font_info,p,1);
2519 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2526 Advance to the next line of text.
2529 annotate_info->width=(unsigned int) XTextWidth(font_info,
2530 annotate_info->text,(int) strlen(annotate_info->text));
2531 if (annotate_info->next != (XAnnotateInfo *) NULL)
2534 Line of text already exists.
2536 annotate_info=annotate_info->next;
2539 p=annotate_info->text;
2542 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2543 sizeof(*annotate_info->next));
2544 if (annotate_info->next == (XAnnotateInfo *) NULL)
2545 return(MagickFalse);
2546 *annotate_info->next=(*annotate_info);
2547 annotate_info->next->previous=annotate_info;
2548 annotate_info=annotate_info->next;
2549 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2550 windows->image.width/MagickMax((ssize_t)
2551 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2552 if (annotate_info->text == (char *) NULL)
2553 return(MagickFalse);
2554 annotate_info->y+=annotate_info->height;
2555 if (annotate_info->y > (int) windows->image.height)
2556 annotate_info->y=(int) annotate_info->height;
2557 annotate_info->next=(XAnnotateInfo *) NULL;
2560 p=annotate_info->text;
2569 Respond to a user key release.
2571 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2572 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2573 state&=(~ModifierState);
2576 case SelectionNotify:
2592 Obtain response from primary selection.
2594 if (event.xselection.property == (Atom) None)
2596 status=XGetWindowProperty(display,event.xselection.requestor,
2597 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2598 &type,&format,&length,&after,&data);
2599 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2603 Annotate Image window with primary selection.
2605 for (i=0; i < (ssize_t) length; i++)
2607 if ((char) data[i] != '\n')
2610 Draw a single character on the Image window.
2613 (void) XDrawString(display,windows->image.id,annotate_context,
2615 x+=XTextWidth(font_info,p,1);
2617 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2621 Advance to the next line of text.
2624 annotate_info->width=(unsigned int) XTextWidth(font_info,
2625 annotate_info->text,(int) strlen(annotate_info->text));
2626 if (annotate_info->next != (XAnnotateInfo *) NULL)
2629 Line of text already exists.
2631 annotate_info=annotate_info->next;
2634 p=annotate_info->text;
2637 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2638 sizeof(*annotate_info->next));
2639 if (annotate_info->next == (XAnnotateInfo *) NULL)
2640 return(MagickFalse);
2641 *annotate_info->next=(*annotate_info);
2642 annotate_info->next->previous=annotate_info;
2643 annotate_info=annotate_info->next;
2644 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2645 windows->image.width/MagickMax((ssize_t)
2646 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2647 if (annotate_info->text == (char *) NULL)
2648 return(MagickFalse);
2649 annotate_info->y+=annotate_info->height;
2650 if (annotate_info->y > (int) windows->image.height)
2651 annotate_info->y=(int) annotate_info->height;
2652 annotate_info->next=(XAnnotateInfo *) NULL;
2655 p=annotate_info->text;
2657 (void) XFree((void *) data);
2663 } while ((state & ExitState) == 0);
2664 (void) XFreeCursor(display,cursor);
2666 Annotation is relative to image configuration.
2668 width=(unsigned int) image->columns;
2669 height=(unsigned int) image->rows;
2672 if (windows->image.crop_geometry != (char *) NULL)
2673 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2675 Initialize annotated image.
2677 XSetCursorState(display,windows,MagickTrue);
2678 XCheckRefreshWindows(display,windows);
2679 while (annotate_info != (XAnnotateInfo *) NULL)
2681 if (annotate_info->width == 0)
2684 No text on this line-- go to the next line of text.
2686 previous_info=annotate_info->previous;
2687 annotate_info->text=(char *)
2688 RelinquishMagickMemory(annotate_info->text);
2689 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2690 annotate_info=previous_info;
2694 Determine pixel index for box and pen color.
2696 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2697 if (windows->pixel_info->colors != 0)
2698 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2699 if (windows->pixel_info->pixels[i] ==
2700 windows->pixel_info->pen_colors[box_id].pixel)
2702 windows->pixel_info->box_index=(unsigned short) i;
2705 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2706 if (windows->pixel_info->colors != 0)
2707 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2708 if (windows->pixel_info->pixels[i] ==
2709 windows->pixel_info->pen_colors[pen_id].pixel)
2711 windows->pixel_info->pen_index=(unsigned short) i;
2715 Define the annotate geometry string.
2717 annotate_info->x=(int)
2718 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2719 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2720 windows->image.y)/windows->image.ximage->height;
2721 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
2722 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2723 height*annotate_info->height/windows->image.ximage->height,
2724 annotate_info->x+x,annotate_info->y+y);
2726 Annotate image with text.
2728 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2730 return(MagickFalse);
2734 previous_info=annotate_info->previous;
2735 annotate_info->text=DestroyString(annotate_info->text);
2736 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2737 annotate_info=previous_info;
2739 (void) XSetForeground(display,annotate_context,
2740 windows->pixel_info->foreground_color.pixel);
2741 (void) XSetBackground(display,annotate_context,
2742 windows->pixel_info->background_color.pixel);
2743 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2744 XSetCursorState(display,windows,MagickFalse);
2745 (void) XFreeFont(display,font_info);
2747 Update image configuration.
2749 XConfigureImageColormap(display,resource_info,windows,image);
2750 (void) XConfigureImage(display,resource_info,windows,image,exception);
2755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759 + X B a c k g r o u n d I m a g e %
2763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765 % XBackgroundImage() displays the image in the background of a window.
2767 % The format of the XBackgroundImage method is:
2769 % MagickBooleanType XBackgroundImage(Display *display,
2770 % XResourceInfo *resource_info,XWindows *windows,Image **image,
2771 % ExceptionInfo *exception)
2773 % A description of each parameter follows:
2775 % o display: Specifies a connection to an X server; returned from
2778 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2780 % o windows: Specifies a pointer to a XWindows structure.
2782 % o image: the image.
2784 % o exception: return any errors or warnings in this structure.
2787 static MagickBooleanType XBackgroundImage(Display *display,
2788 XResourceInfo *resource_info,XWindows *windows,Image **image,
2789 ExceptionInfo *exception)
2791 #define BackgroundImageTag "Background/Image"
2797 window_id[MaxTextExtent] = "root";
2800 background_resources;
2803 Put image in background.
2805 status=XDialogWidget(display,windows,"Background",
2806 "Enter window id (id 0x00 selects window with pointer):",window_id);
2807 if (*window_id == '\0')
2808 return(MagickFalse);
2809 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2811 XInfoWidget(display,windows,BackgroundImageTag);
2812 XSetCursorState(display,windows,MagickTrue);
2813 XCheckRefreshWindows(display,windows);
2814 background_resources=(*resource_info);
2815 background_resources.window_id=window_id;
2816 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2817 status=XDisplayBackgroundImage(display,&background_resources,*image,
2819 if (status != MagickFalse)
2820 XClientMessage(display,windows->image.id,windows->im_protocols,
2821 windows->im_retain_colors,CurrentTime);
2822 XSetCursorState(display,windows,MagickFalse);
2823 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833 + X C h o p I m a g e %
2837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839 % XChopImage() chops the X image.
2841 % The format of the XChopImage method is:
2843 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2844 % XWindows *windows,Image **image,ExceptionInfo *exception)
2846 % A description of each parameter follows:
2848 % o display: Specifies a connection to an X server; returned from
2851 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2853 % o windows: Specifies a pointer to a XWindows structure.
2855 % o image: the image.
2857 % o exception: return any errors or warnings in this structure.
2860 static MagickBooleanType XChopImage(Display *display,
2861 XResourceInfo *resource_info,XWindows *windows,Image **image,
2862 ExceptionInfo *exception)
2874 direction = HorizontalChopCommand;
2876 static const ModeType
2879 ChopDirectionCommand,
2883 DirectionCommands[] =
2885 HorizontalChopCommand,
2890 text[MaxTextExtent];
2923 (void) CloneString(&windows->command.name,"Chop");
2924 windows->command.data=1;
2925 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2926 (void) XMapRaised(display,windows->command.id);
2927 XClientMessage(display,windows->image.id,windows->im_protocols,
2928 windows->im_update_widget,CurrentTime);
2930 Track pointer until button 1 is pressed.
2932 XQueryPosition(display,windows->image.id,&x,&y);
2933 (void) XSelectInput(display,windows->image.id,
2934 windows->image.attributes.event_mask | PointerMotionMask);
2938 if (windows->info.mapped != MagickFalse)
2941 Display pointer position.
2943 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
2944 x+windows->image.x,y+windows->image.y);
2945 XInfoWidget(display,windows,text);
2948 Wait for next event.
2950 XScreenEvent(display,windows,&event);
2951 if (event.xany.window == windows->command.id)
2954 Select a command from the Command widget.
2956 id=XCommandWidget(display,windows,ChopMenu,&event);
2959 switch (ChopCommands[id])
2961 case ChopDirectionCommand:
2964 command[MaxTextExtent];
2975 Select a command from the pop-up menu.
2977 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2979 direction=DirectionCommands[id];
2982 case ChopHelpCommand:
2984 XTextViewWidget(display,resource_info,windows,MagickFalse,
2985 "Help Viewer - Image Chop",ImageChopHelp);
2988 case ChopDismissCommand:
3006 if (event.xbutton.button != Button1)
3008 if (event.xbutton.window != windows->image.id)
3011 User has committed to start point of chopping line.
3013 segment_info.x1=(short int) event.xbutton.x;
3014 segment_info.x2=(short int) event.xbutton.x;
3015 segment_info.y1=(short int) event.xbutton.y;
3016 segment_info.y2=(short int) event.xbutton.y;
3027 command[MaxTextExtent];
3032 if (event.xkey.window != windows->image.id)
3035 Respond to a user key press.
3037 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3038 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3039 switch ((int) key_symbol)
3054 (void) XSetFunction(display,windows->image.highlight_context,
3056 XTextViewWidget(display,resource_info,windows,MagickFalse,
3057 "Help Viewer - Image Chop",ImageChopHelp);
3058 (void) XSetFunction(display,windows->image.highlight_context,
3064 (void) XBell(display,0);
3073 Map and unmap Info widget as text cursor crosses its boundaries.
3077 if (windows->info.mapped != MagickFalse)
3079 if ((x < (int) (windows->info.x+windows->info.width)) &&
3080 (y < (int) (windows->info.y+windows->info.height)))
3081 (void) XWithdrawWindow(display,windows->info.id,
3082 windows->info.screen);
3085 if ((x > (int) (windows->info.x+windows->info.width)) ||
3086 (y > (int) (windows->info.y+windows->info.height)))
3087 (void) XMapWindow(display,windows->info.id);
3090 } while ((state & ExitState) == 0);
3091 (void) XSelectInput(display,windows->image.id,
3092 windows->image.attributes.event_mask);
3093 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3094 if ((state & EscapeState) != 0)
3097 Draw line as pointer moves until the mouse button is released.
3104 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3111 Display info and draw chopping line.
3113 if (windows->info.mapped == MagickFalse)
3114 (void) XMapWindow(display,windows->info.id);
3115 (void) FormatLocaleString(text,MaxTextExtent,
3116 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3117 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3118 XInfoWidget(display,windows,text);
3119 XHighlightLine(display,windows->image.id,
3120 windows->image.highlight_context,&segment_info);
3123 if (windows->info.mapped != MagickFalse)
3124 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3126 Wait for next event.
3128 XScreenEvent(display,windows,&event);
3130 XHighlightLine(display,windows->image.id,
3131 windows->image.highlight_context,&segment_info);
3136 segment_info.x2=(short int) event.xmotion.x;
3137 segment_info.y2=(short int) event.xmotion.y;
3143 User has committed to chopping line.
3145 segment_info.x2=(short int) event.xbutton.x;
3146 segment_info.y2=(short int) event.xbutton.y;
3154 segment_info.x2=(short int) event.xmotion.x;
3155 segment_info.y2=(short int) event.xmotion.y;
3161 Check boundary conditions.
3163 if (segment_info.x2 < 0)
3166 if (segment_info.x2 > windows->image.ximage->width)
3167 segment_info.x2=windows->image.ximage->width;
3168 if (segment_info.y2 < 0)
3171 if (segment_info.y2 > windows->image.ximage->height)
3172 segment_info.y2=windows->image.ximage->height;
3173 distance=(unsigned int)
3174 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3175 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3177 Compute chopping geometry.
3179 if (direction == HorizontalChopCommand)
3181 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3182 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3185 if (segment_info.x1 > (int) segment_info.x2)
3187 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3188 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3194 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3196 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3197 if (segment_info.y1 > segment_info.y2)
3199 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3200 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3203 } while ((state & ExitState) == 0);
3204 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3205 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3209 Image chopping is relative to image configuration.
3211 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3213 XSetCursorState(display,windows,MagickTrue);
3214 XCheckRefreshWindows(display,windows);
3215 windows->image.window_changes.width=windows->image.ximage->width-
3216 (unsigned int) chop_info.width;
3217 windows->image.window_changes.height=windows->image.ximage->height-
3218 (unsigned int) chop_info.height;
3219 width=(unsigned int) (*image)->columns;
3220 height=(unsigned int) (*image)->rows;
3223 if (windows->image.crop_geometry != (char *) NULL)
3224 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3225 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3227 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3228 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3229 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3231 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3232 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3236 chop_image=ChopImage(*image,&chop_info,exception);
3237 XSetCursorState(display,windows,MagickFalse);
3238 if (chop_image == (Image *) NULL)
3239 return(MagickFalse);
3240 *image=DestroyImage(*image);
3243 Update image configuration.
3245 XConfigureImageColormap(display,resource_info,windows,*image);
3246 (void) XConfigureImage(display,resource_info,windows,*image,exception);
3251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3255 + X C o l o r E d i t I m a g e %
3259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3261 % XColorEditImage() allows the user to interactively change the color of one
3262 % pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3264 % The format of the XColorEditImage method is:
3266 % MagickBooleanType XColorEditImage(Display *display,
3267 % XResourceInfo *resource_info,XWindows *windows,Image **image,
3268 % ExceptionInfo *exception)
3270 % A description of each parameter follows:
3272 % o display: Specifies a connection to an X server; returned from
3275 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3277 % o windows: Specifies a pointer to a XWindows structure.
3279 % o image: the image; returned from ReadImage.
3281 % o exception: return any errors or warnings in this structure.
3284 static MagickBooleanType XColorEditImage(Display *display,
3285 XResourceInfo *resource_info,XWindows *windows,Image **image,
3286 ExceptionInfo *exception)
3301 static const ModeType
3302 ColorEditCommands[] =
3304 ColorEditMethodCommand,
3305 ColorEditColorCommand,
3306 ColorEditBorderCommand,
3307 ColorEditFuzzCommand,
3308 ColorEditUndoCommand,
3309 ColorEditHelpCommand,
3310 ColorEditDismissCommand
3314 method = PointMethod;
3320 border_color = { 0, 0, 0, 0, 0, 0 };
3323 command[MaxTextExtent],
3324 text[MaxTextExtent];
3359 (void) CloneString(&windows->command.name,"Color Edit");
3360 windows->command.data=4;
3361 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3362 (void) XMapRaised(display,windows->command.id);
3363 XClientMessage(display,windows->image.id,windows->im_protocols,
3364 windows->im_update_widget,CurrentTime);
3368 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3369 resource_info->background_color,resource_info->foreground_color);
3370 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3372 Track pointer until button 1 is pressed.
3374 XQueryPosition(display,windows->image.id,&x,&y);
3375 (void) XSelectInput(display,windows->image.id,
3376 windows->image.attributes.event_mask | PointerMotionMask);
3380 if (windows->info.mapped != MagickFalse)
3383 Display pointer position.
3385 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
3386 x+windows->image.x,y+windows->image.y);
3387 XInfoWidget(display,windows,text);
3390 Wait for next event.
3392 XScreenEvent(display,windows,&event);
3393 if (event.xany.window == windows->command.id)
3396 Select a command from the Command widget.
3398 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3401 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3404 switch (ColorEditCommands[id])
3406 case ColorEditMethodCommand:
3412 Select a method from the pop-up menu.
3414 methods=(char **) GetCommandOptions(MagickMethodOptions);
3415 if (methods == (char **) NULL)
3417 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3418 (const char **) methods,command);
3420 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3421 MagickFalse,methods[entry]);
3422 methods=DestroyStringList(methods);
3425 case ColorEditColorCommand:
3428 *ColorMenu[MaxNumberPens];
3434 Initialize menu selections.
3436 for (i=0; i < (int) (MaxNumberPens-2); i++)
3437 ColorMenu[i]=resource_info->pen_colors[i];
3438 ColorMenu[MaxNumberPens-2]="Browser...";
3439 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3441 Select a pen color from the pop-up menu.
3443 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3444 (const char **) ColorMenu,command);
3447 if (pen_number == (MaxNumberPens-2))
3450 color_name[MaxTextExtent] = "gray";
3453 Select a pen color from a dialog.
3455 resource_info->pen_colors[pen_number]=color_name;
3456 XColorBrowserWidget(display,windows,"Select",color_name);
3457 if (*color_name == '\0')
3463 (void) XParseColor(display,windows->map_info->colormap,
3464 resource_info->pen_colors[pen_number],&color);
3465 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3466 (unsigned int) MaxColors,&color);
3467 windows->pixel_info->pen_colors[pen_number]=color;
3468 pen_id=(unsigned int) pen_number;
3471 case ColorEditBorderCommand:
3474 *ColorMenu[MaxNumberPens];
3480 Initialize menu selections.
3482 for (i=0; i < (int) (MaxNumberPens-2); i++)
3483 ColorMenu[i]=resource_info->pen_colors[i];
3484 ColorMenu[MaxNumberPens-2]="Browser...";
3485 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3487 Select a pen color from the pop-up menu.
3489 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3490 (const char **) ColorMenu,command);
3493 if (pen_number == (MaxNumberPens-2))
3496 color_name[MaxTextExtent] = "gray";
3499 Select a pen color from a dialog.
3501 resource_info->pen_colors[pen_number]=color_name;
3502 XColorBrowserWidget(display,windows,"Select",color_name);
3503 if (*color_name == '\0')
3509 (void) XParseColor(display,windows->map_info->colormap,
3510 resource_info->pen_colors[pen_number],&border_color);
3513 case ColorEditFuzzCommand:
3516 fuzz[MaxTextExtent];
3531 Select a command from the pop-up menu.
3533 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3539 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
3543 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3544 (void) XDialogWidget(display,windows,"Ok",
3545 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3548 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
3549 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
3552 case ColorEditUndoCommand:
3554 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3558 case ColorEditHelpCommand:
3561 XTextViewWidget(display,resource_info,windows,MagickFalse,
3562 "Help Viewer - Image Annotation",ImageColorEditHelp);
3565 case ColorEditDismissCommand:
3575 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3582 if (event.xbutton.button != Button1)
3584 if ((event.xbutton.window != windows->image.id) &&
3585 (event.xbutton.window != windows->magnify.id))
3592 (void) XMagickCommand(display,resource_info,windows,
3593 SaveToUndoBufferCommand,image,exception);
3594 state|=UpdateConfigurationState;
3599 if (event.xbutton.button != Button1)
3601 if ((event.xbutton.window != windows->image.id) &&
3602 (event.xbutton.window != windows->magnify.id))
3605 Update colormap information.
3609 XConfigureImageColormap(display,resource_info,windows,*image);
3610 (void) XConfigureImage(display,resource_info,windows,*image,exception);
3611 XInfoWidget(display,windows,text);
3612 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3613 state&=(~UpdateConfigurationState);
3623 if (event.xkey.window == windows->magnify.id)
3628 window=windows->magnify.id;
3629 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3631 if (event.xkey.window != windows->image.id)
3634 Respond to a user key press.
3636 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3637 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3638 switch ((int) key_symbol)
3652 XTextViewWidget(display,resource_info,windows,MagickFalse,
3653 "Help Viewer - Image Annotation",ImageColorEditHelp);
3658 (void) XBell(display,0);
3667 Map and unmap Info widget as cursor crosses its boundaries.
3671 if (windows->info.mapped != MagickFalse)
3673 if ((x < (int) (windows->info.x+windows->info.width)) &&
3674 (y < (int) (windows->info.y+windows->info.height)))
3675 (void) XWithdrawWindow(display,windows->info.id,
3676 windows->info.screen);
3679 if ((x > (int) (windows->info.x+windows->info.width)) ||
3680 (y > (int) (windows->info.y+windows->info.height)))
3681 (void) XMapWindow(display,windows->info.id);
3687 if (event.xany.window == windows->magnify.id)
3689 x=windows->magnify.x-windows->image.x;
3690 y=windows->magnify.y-windows->image.y;
3694 if ((state & UpdateConfigurationState) != 0)
3704 Pixel edit is relative to image configuration.
3706 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3708 color=windows->pixel_info->pen_colors[pen_id];
3709 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3710 width=(unsigned int) (*image)->columns;
3711 height=(unsigned int) (*image)->rows;
3714 if (windows->image.crop_geometry != (char *) NULL)
3715 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3718 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3720 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3721 if ((x_offset < 0) || (y_offset < 0))
3723 if ((x_offset >= (int) (*image)->columns) ||
3724 (y_offset >= (int) (*image)->rows))
3726 image_view=AcquireCacheView(*image);
3733 Update color information using point algorithm.
3735 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3736 return(MagickFalse);
3737 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3738 (ssize_t) y_offset,1,1,exception);
3739 if (q == (Quantum *) NULL)
3741 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3742 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3743 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3744 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3754 Update color information using replace algorithm.
3756 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
3757 (ssize_t) y_offset,&target,exception);
3758 if ((*image)->storage_class == DirectClass)
3760 for (y=0; y < (int) (*image)->rows; y++)
3762 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3763 (*image)->columns,1,exception);
3764 if (q == (Quantum *) NULL)
3766 for (x=0; x < (int) (*image)->columns; x++)
3768 GetPixelPacket(*image,q,&pixel);
3769 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
3771 SetPixelRed(*image,ScaleShortToQuantum(
3773 SetPixelGreen(*image,ScaleShortToQuantum(
3775 SetPixelBlue(*image,ScaleShortToQuantum(
3778 q+=GetPixelChannels(*image);
3780 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3786 for (i=0; i < (ssize_t) (*image)->colors; i++)
3787 if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target))
3789 (*image)->colormap[i].red=ScaleShortToQuantum(
3791 (*image)->colormap[i].green=ScaleShortToQuantum(
3793 (*image)->colormap[i].blue=ScaleShortToQuantum(
3796 (void) SyncImage(*image);
3800 case FloodfillMethod:
3801 case FillToBorderMethod:
3810 Update color information using floodfill algorithm.
3812 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3813 (ssize_t) y_offset,&target,exception);
3814 if (method == FillToBorderMethod)
3816 target.red=(MagickRealType)
3817 ScaleShortToQuantum(border_color.red);
3818 target.green=(MagickRealType)
3819 ScaleShortToQuantum(border_color.green);
3820 target.blue=(MagickRealType)
3821 ScaleShortToQuantum(border_color.blue);
3823 draw_info=CloneDrawInfo(resource_info->image_info,
3825 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3826 &draw_info->fill,exception);
3827 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
3828 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
3829 MagickFalse : MagickTrue,exception);
3830 draw_info=DestroyDrawInfo(draw_info);
3836 Update color information using reset algorithm.
3838 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3839 return(MagickFalse);
3840 for (y=0; y < (int) (*image)->rows; y++)
3842 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3843 (*image)->columns,1,exception);
3844 if (q == (Quantum *) NULL)
3846 for (x=0; x < (int) (*image)->columns; x++)
3848 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3849 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3850 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3851 q+=GetPixelChannels(*image);
3853 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3859 image_view=DestroyCacheView(image_view);
3860 state&=(~UpdateConfigurationState);
3862 } while ((state & ExitState) == 0);
3863 (void) XSelectInput(display,windows->image.id,
3864 windows->image.attributes.event_mask);
3865 XSetCursorState(display,windows,MagickFalse);
3866 (void) XFreeCursor(display,cursor);
3871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3875 + X C o m p o s i t e I m a g e %
3879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3881 % XCompositeImage() requests an image name from the user, reads the image and
3882 % composites it with the X window image at a location the user chooses with
3885 % The format of the XCompositeImage method is:
3887 % MagickBooleanType XCompositeImage(Display *display,
3888 % XResourceInfo *resource_info,XWindows *windows,Image *image,
3889 % ExceptionInfo *exception)
3891 % A description of each parameter follows:
3893 % o display: Specifies a connection to an X server; returned from
3896 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3898 % o windows: Specifies a pointer to a XWindows structure.
3900 % o image: the image; returned from ReadImage.
3902 % o exception: return any errors or warnings in this structure.
3905 static MagickBooleanType XCompositeImage(Display *display,
3906 XResourceInfo *resource_info,XWindows *windows,Image *image,
3907 ExceptionInfo *exception)
3910 displacement_geometry[MaxTextExtent] = "30x30",
3911 filename[MaxTextExtent] = "\0";
3924 static CompositeOperator
3925 compose = CopyCompositeOp;
3927 static const ModeType
3928 CompositeCommands[] =
3930 CompositeOperatorsCommand,
3931 CompositeDissolveCommand,
3932 CompositeDisplaceCommand,
3933 CompositeHelpCommand,
3934 CompositeDismissCommand
3938 text[MaxTextExtent];
3971 Request image file name from user.
3973 XFileBrowserWidget(display,windows,"Composite",filename);
3974 if (*filename == '\0')
3979 XSetCursorState(display,windows,MagickTrue);
3980 XCheckRefreshWindows(display,windows);
3981 (void) CopyMagickString(resource_info->image_info->filename,filename,
3983 composite_image=ReadImage(resource_info->image_info,exception);
3984 CatchException(exception);
3985 XSetCursorState(display,windows,MagickFalse);
3986 if (composite_image == (Image *) NULL)
3987 return(MagickFalse);
3991 (void) CloneString(&windows->command.name,"Composite");
3992 windows->command.data=1;
3993 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3994 (void) XMapRaised(display,windows->command.id);
3995 XClientMessage(display,windows->image.id,windows->im_protocols,
3996 windows->im_update_widget,CurrentTime);
3998 Track pointer until button 1 is pressed.
4000 XQueryPosition(display,windows->image.id,&x,&y);
4001 (void) XSelectInput(display,windows->image.id,
4002 windows->image.attributes.event_mask | PointerMotionMask);
4003 composite_info.x=(ssize_t) windows->image.x+x;
4004 composite_info.y=(ssize_t) windows->image.y+y;
4005 composite_info.width=0;
4006 composite_info.height=0;
4007 cursor=XCreateFontCursor(display,XC_ul_angle);
4008 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4013 if (windows->info.mapped != MagickFalse)
4016 Display pointer position.
4018 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
4019 (long) composite_info.x,(long) composite_info.y);
4020 XInfoWidget(display,windows,text);
4022 highlight_info=composite_info;
4023 highlight_info.x=composite_info.x-windows->image.x;
4024 highlight_info.y=composite_info.y-windows->image.y;
4025 XHighlightRectangle(display,windows->image.id,
4026 windows->image.highlight_context,&highlight_info);
4028 Wait for next event.
4030 XScreenEvent(display,windows,&event);
4031 XHighlightRectangle(display,windows->image.id,
4032 windows->image.highlight_context,&highlight_info);
4033 if (event.xany.window == windows->command.id)
4036 Select a command from the Command widget.
4038 id=XCommandWidget(display,windows,CompositeMenu,&event);
4041 switch (CompositeCommands[id])
4043 case CompositeOperatorsCommand:
4046 command[MaxTextExtent],
4050 Select a command from the pop-up menu.
4052 operators=GetCommandOptions(MagickComposeOptions);
4053 if (operators == (char **) NULL)
4055 entry=XMenuWidget(display,windows,CompositeMenu[id],
4056 (const char **) operators,command);
4058 compose=(CompositeOperator) ParseCommandOption(
4059 MagickComposeOptions,MagickFalse,operators[entry]);
4060 operators=DestroyStringList(operators);
4063 case CompositeDissolveCommand:
4066 factor[MaxTextExtent] = "20.0";
4069 Dissolve the two images a given percent.
4071 (void) XSetFunction(display,windows->image.highlight_context,
4073 (void) XDialogWidget(display,windows,"Dissolve",
4074 "Enter the blend factor (0.0 - 99.9%):",factor);
4075 (void) XSetFunction(display,windows->image.highlight_context,
4077 if (*factor == '\0')
4079 blend=InterpretLocaleValue(factor,(char **) NULL);
4080 compose=DissolveCompositeOp;
4083 case CompositeDisplaceCommand:
4086 Get horizontal and vertical scale displacement geometry.
4088 (void) XSetFunction(display,windows->image.highlight_context,
4090 (void) XDialogWidget(display,windows,"Displace",
4091 "Enter the horizontal and vertical scale:",displacement_geometry);
4092 (void) XSetFunction(display,windows->image.highlight_context,
4094 if (*displacement_geometry == '\0')
4096 compose=DisplaceCompositeOp;
4099 case CompositeHelpCommand:
4101 (void) XSetFunction(display,windows->image.highlight_context,
4103 XTextViewWidget(display,resource_info,windows,MagickFalse,
4104 "Help Viewer - Image Composite",ImageCompositeHelp);
4105 (void) XSetFunction(display,windows->image.highlight_context,
4109 case CompositeDismissCommand:
4127 if (image->debug != MagickFalse)
4128 (void) LogMagickEvent(X11Event,GetMagickModule(),
4129 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4130 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4131 if (event.xbutton.button != Button1)
4133 if (event.xbutton.window != windows->image.id)
4138 composite_info.width=composite_image->columns;
4139 composite_info.height=composite_image->rows;
4140 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4141 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4142 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4147 if (image->debug != MagickFalse)
4148 (void) LogMagickEvent(X11Event,GetMagickModule(),
4149 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4150 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4151 if (event.xbutton.button != Button1)
4153 if (event.xbutton.window != windows->image.id)
4155 if ((composite_info.width != 0) && (composite_info.height != 0))
4158 User has selected the location of the composite image.
4160 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4161 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4171 command[MaxTextExtent];
4179 if (event.xkey.window != windows->image.id)
4182 Respond to a user key press.
4184 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4185 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4186 *(command+length)='\0';
4187 if (image->debug != MagickFalse)
4188 (void) LogMagickEvent(X11Event,GetMagickModule(),
4189 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4190 switch ((int) key_symbol)
4198 composite_image=DestroyImage(composite_image);
4206 (void) XSetFunction(display,windows->image.highlight_context,
4208 XTextViewWidget(display,resource_info,windows,MagickFalse,
4209 "Help Viewer - Image Composite",ImageCompositeHelp);
4210 (void) XSetFunction(display,windows->image.highlight_context,
4216 (void) XBell(display,0);
4225 Map and unmap Info widget as text cursor crosses its boundaries.
4229 if (windows->info.mapped != MagickFalse)
4231 if ((x < (int) (windows->info.x+windows->info.width)) &&
4232 (y < (int) (windows->info.y+windows->info.height)))
4233 (void) XWithdrawWindow(display,windows->info.id,
4234 windows->info.screen);
4237 if ((x > (int) (windows->info.x+windows->info.width)) ||
4238 (y > (int) (windows->info.y+windows->info.height)))
4239 (void) XMapWindow(display,windows->info.id);
4240 composite_info.x=(ssize_t) windows->image.x+x;
4241 composite_info.y=(ssize_t) windows->image.y+y;
4246 if (image->debug != MagickFalse)
4247 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4252 } while ((state & ExitState) == 0);
4253 (void) XSelectInput(display,windows->image.id,
4254 windows->image.attributes.event_mask);
4255 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4256 XSetCursorState(display,windows,MagickFalse);
4257 (void) XFreeCursor(display,cursor);
4258 if ((state & EscapeState) != 0)
4261 Image compositing is relative to image configuration.
4263 XSetCursorState(display,windows,MagickTrue);
4264 XCheckRefreshWindows(display,windows);
4265 width=(unsigned int) image->columns;
4266 height=(unsigned int) image->rows;
4269 if (windows->image.crop_geometry != (char *) NULL)
4270 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4271 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4272 composite_info.x+=x;
4273 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4274 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4275 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4276 composite_info.y+=y;
4277 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4278 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4279 if ((composite_info.width != composite_image->columns) ||
4280 (composite_info.height != composite_image->rows))
4286 Scale composite image.
4288 resize_image=ResizeImage(composite_image,composite_info.width,
4289 composite_info.height,composite_image->filter,composite_image->blur,
4291 composite_image=DestroyImage(composite_image);
4292 if (resize_image == (Image *) NULL)
4294 XSetCursorState(display,windows,MagickFalse);
4295 return(MagickFalse);
4297 composite_image=resize_image;
4299 if (compose == DisplaceCompositeOp)
4300 (void) SetImageArtifact(composite_image,"compose:args",
4301 displacement_geometry);
4320 Create mattes for blending.
4322 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
4323 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
4324 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
4325 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4326 return(MagickFalse);
4327 image->matte=MagickTrue;
4328 image_view=AcquireCacheView(image);
4329 for (y=0; y < (int) image->rows; y++)
4331 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4333 if (q == (Quantum *) NULL)
4335 for (x=0; x < (int) image->columns; x++)
4337 SetPixelAlpha(image,opacity,q);
4338 q+=GetPixelChannels(image);
4340 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4343 image_view=DestroyCacheView(image_view);
4346 Composite image with X Image window.
4348 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4350 composite_image=DestroyImage(composite_image);
4351 XSetCursorState(display,windows,MagickFalse);
4353 Update image configuration.
4355 XConfigureImageColormap(display,resource_info,windows,image);
4356 (void) XConfigureImage(display,resource_info,windows,image,exception);
4361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4365 + X C o n f i g u r e I m a g e %
4369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4371 % XConfigureImage() creates a new X image. It also notifies the window
4372 % manager of the new image size and configures the transient widows.
4374 % The format of the XConfigureImage method is:
4376 % MagickBooleanType XConfigureImage(Display *display,
4377 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4378 % ExceptionInfo *exception)
4380 % A description of each parameter follows:
4382 % o display: Specifies a connection to an X server; returned from
4385 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4387 % o windows: Specifies a pointer to a XWindows structure.
4389 % o image: the image.
4391 % o exception: return any errors or warnings in this structure.
4393 % o exception: return any errors or warnings in this structure.
4396 static MagickBooleanType XConfigureImage(Display *display,
4397 XResourceInfo *resource_info,XWindows *windows,Image *image,
4398 ExceptionInfo *exception)
4401 geometry[MaxTextExtent];
4422 Dismiss if window dimensions are zero.
4424 width=(unsigned int) windows->image.window_changes.width;
4425 height=(unsigned int) windows->image.window_changes.height;
4426 if (image->debug != MagickFalse)
4427 (void) LogMagickEvent(X11Event,GetMagickModule(),
4428 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4429 windows->image.ximage->height,(double) width,(double) height);
4430 if ((width*height) == 0)
4435 Resize image to fit Image window dimensions.
4437 XSetCursorState(display,windows,MagickTrue);
4438 (void) XFlush(display);
4439 if (((int) width != windows->image.ximage->width) ||
4440 ((int) height != windows->image.ximage->height))
4441 image->taint=MagickTrue;
4442 windows->magnify.x=(int)
4443 width*windows->magnify.x/windows->image.ximage->width;
4444 windows->magnify.y=(int)
4445 height*windows->magnify.y/windows->image.ximage->height;
4446 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4447 windows->image.y=(int)
4448 (height*windows->image.y/windows->image.ximage->height);
4449 status=XMakeImage(display,resource_info,&windows->image,image,
4450 (unsigned int) width,(unsigned int) height,exception);
4451 if (status == MagickFalse)
4452 XNoticeWidget(display,windows,"Unable to configure X image:",
4453 windows->image.name);
4455 Notify window manager of the new configuration.
4457 if (resource_info->image_geometry != (char *) NULL)
4458 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
4459 resource_info->image_geometry);
4461 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4462 XDisplayWidth(display,windows->image.screen),
4463 XDisplayHeight(display,windows->image.screen));
4464 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4465 window_changes.width=(int) width;
4466 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4467 window_changes.width=XDisplayWidth(display,windows->image.screen);
4468 window_changes.height=(int) height;
4469 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4470 window_changes.height=XDisplayHeight(display,windows->image.screen);
4471 mask=(size_t) (CWWidth | CWHeight);
4472 if (resource_info->backdrop)
4475 window_changes.x=(int)
4476 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4477 window_changes.y=(int)
4478 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4480 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4481 (unsigned int) mask,&window_changes);
4482 (void) XClearWindow(display,windows->image.id);
4483 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4485 Update Magnify window configuration.
4487 if (windows->magnify.mapped != MagickFalse)
4488 XMakeMagnifyImage(display,windows);
4489 windows->pan.crop_geometry=windows->image.crop_geometry;
4490 XBestIconSize(display,&windows->pan,image);
4491 while (((windows->pan.width << 1) < MaxIconSize) &&
4492 ((windows->pan.height << 1) < MaxIconSize))
4494 windows->pan.width<<=1;
4495 windows->pan.height<<=1;
4497 if (windows->pan.geometry != (char *) NULL)
4498 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4499 &windows->pan.width,&windows->pan.height);
4500 window_changes.width=(int) windows->pan.width;
4501 window_changes.height=(int) windows->pan.height;
4502 size_hints=XAllocSizeHints();
4503 if (size_hints != (XSizeHints *) NULL)
4508 size_hints->flags=PSize | PMinSize | PMaxSize;
4509 size_hints->width=window_changes.width;
4510 size_hints->height=window_changes.height;
4511 size_hints->min_width=size_hints->width;
4512 size_hints->min_height=size_hints->height;
4513 size_hints->max_width=size_hints->width;
4514 size_hints->max_height=size_hints->height;
4515 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4516 (void) XFree((void *) size_hints);
4518 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4519 (unsigned int) (CWWidth | CWHeight),&window_changes);
4521 Update icon window configuration.
4523 windows->icon.crop_geometry=windows->image.crop_geometry;
4524 XBestIconSize(display,&windows->icon,image);
4525 window_changes.width=(int) windows->icon.width;
4526 window_changes.height=(int) windows->icon.height;
4527 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4528 (unsigned int) (CWWidth | CWHeight),&window_changes);
4529 XSetCursorState(display,windows,MagickFalse);
4530 return(status != 0 ? MagickTrue : MagickFalse);
4534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538 + X C r o p I m a g e %
4542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544 % XCropImage() allows the user to select a region of the image and crop, copy,
4545 % or cut it. For copy or cut, the image can subsequently be composited onto
4546 % the image with XPasteImage.
4548 % The format of the XCropImage method is:
4550 % MagickBooleanType XCropImage(Display *display,
4551 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4552 % const ClipboardMode mode,ExceptionInfo *exception)
4554 % A description of each parameter follows:
4556 % o display: Specifies a connection to an X server; returned from
4559 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4561 % o windows: Specifies a pointer to a XWindows structure.
4563 % o image: the image; returned from ReadImage.
4565 % o mode: This unsigned value specified whether the image should be
4566 % cropped, copied, or cut.
4568 % o exception: return any errors or warnings in this structure.
4571 static MagickBooleanType XCropImage(Display *display,
4572 XResourceInfo *resource_info,XWindows *windows,Image *image,
4573 const ClipboardMode mode,ExceptionInfo *exception)
4582 *RectifyModeMenu[] =
4590 static const ModeType
4600 RectifyDismissCommand
4607 command[MaxTextExtent],
4608 text[MaxTextExtent];
4651 (void) CloneString(&windows->command.name,"Copy");
4656 (void) CloneString(&windows->command.name,"Crop");
4661 (void) CloneString(&windows->command.name,"Cut");
4665 RectifyModeMenu[0]=windows->command.name;
4666 windows->command.data=0;
4667 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4668 (void) XMapRaised(display,windows->command.id);
4669 XClientMessage(display,windows->image.id,windows->im_protocols,
4670 windows->im_update_widget,CurrentTime);
4672 Track pointer until button 1 is pressed.
4674 XQueryPosition(display,windows->image.id,&x,&y);
4675 (void) XSelectInput(display,windows->image.id,
4676 windows->image.attributes.event_mask | PointerMotionMask);
4677 crop_info.x=(ssize_t) windows->image.x+x;
4678 crop_info.y=(ssize_t) windows->image.y+y;
4681 cursor=XCreateFontCursor(display,XC_fleur);
4685 if (windows->info.mapped != MagickFalse)
4688 Display pointer position.
4690 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
4691 (long) crop_info.x,(long) crop_info.y);
4692 XInfoWidget(display,windows,text);
4695 Wait for next event.
4697 XScreenEvent(display,windows,&event);
4698 if (event.xany.window == windows->command.id)
4701 Select a command from the Command widget.
4703 id=XCommandWidget(display,windows,CropModeMenu,&event);
4706 switch (CropCommands[id])
4708 case CropHelpCommand:
4714 XTextViewWidget(display,resource_info,windows,MagickFalse,
4715 "Help Viewer - Image Copy",ImageCopyHelp);
4720 XTextViewWidget(display,resource_info,windows,MagickFalse,
4721 "Help Viewer - Image Crop",ImageCropHelp);
4726 XTextViewWidget(display,resource_info,windows,MagickFalse,
4727 "Help Viewer - Image Cut",ImageCutHelp);
4733 case CropDismissCommand:
4751 if (event.xbutton.button != Button1)
4753 if (event.xbutton.window != windows->image.id)
4756 Note first corner of cropping rectangle-- exit loop.
4758 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4759 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4760 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4770 if (event.xkey.window != windows->image.id)
4773 Respond to a user key press.
4775 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4776 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4777 switch ((int) key_symbol)
4796 XTextViewWidget(display,resource_info,windows,MagickFalse,
4797 "Help Viewer - Image Copy",ImageCopyHelp);
4802 XTextViewWidget(display,resource_info,windows,MagickFalse,
4803 "Help Viewer - Image Crop",ImageCropHelp);
4808 XTextViewWidget(display,resource_info,windows,MagickFalse,
4809 "Help Viewer - Image Cut",ImageCutHelp);
4817 (void) XBell(display,0);
4825 if (event.xmotion.window != windows->image.id)
4828 Map and unmap Info widget as text cursor crosses its boundaries.
4832 if (windows->info.mapped != MagickFalse)
4834 if ((x < (int) (windows->info.x+windows->info.width)) &&
4835 (y < (int) (windows->info.y+windows->info.height)))
4836 (void) XWithdrawWindow(display,windows->info.id,
4837 windows->info.screen);
4840 if ((x > (int) (windows->info.x+windows->info.width)) ||
4841 (y > (int) (windows->info.y+windows->info.height)))
4842 (void) XMapWindow(display,windows->info.id);
4843 crop_info.x=(ssize_t) windows->image.x+x;
4844 crop_info.y=(ssize_t) windows->image.y+y;
4850 } while ((state & ExitState) == 0);
4851 (void) XSelectInput(display,windows->image.id,
4852 windows->image.attributes.event_mask);
4853 if ((state & EscapeState) != 0)
4856 User want to exit without cropping.
4858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4859 (void) XFreeCursor(display,cursor);
4862 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4866 Size rectangle as pointer moves until the mouse button is released.
4868 x=(int) crop_info.x;
4869 y=(int) crop_info.y;
4875 highlight_info=crop_info;
4876 highlight_info.x=crop_info.x-windows->image.x;
4877 highlight_info.y=crop_info.y-windows->image.y;
4878 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4881 Display info and draw cropping rectangle.
4883 if (windows->info.mapped == MagickFalse)
4884 (void) XMapWindow(display,windows->info.id);
4885 (void) FormatLocaleString(text,MaxTextExtent,
4886 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4887 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4888 XInfoWidget(display,windows,text);
4889 XHighlightRectangle(display,windows->image.id,
4890 windows->image.highlight_context,&highlight_info);
4893 if (windows->info.mapped != MagickFalse)
4894 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4896 Wait for next event.
4898 XScreenEvent(display,windows,&event);
4899 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4900 XHighlightRectangle(display,windows->image.id,
4901 windows->image.highlight_context,&highlight_info);
4906 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4907 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4913 User has committed to cropping rectangle.
4915 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4916 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4917 XSetCursorState(display,windows,MagickFalse);
4919 windows->command.data=0;
4920 (void) XCommandWidget(display,windows,RectifyModeMenu,
4928 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4929 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4934 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4935 ((state & ExitState) != 0))
4938 Check boundary conditions.
4940 if (crop_info.x < 0)
4943 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4944 crop_info.x=(ssize_t) windows->image.ximage->width;
4945 if ((int) crop_info.x < x)
4946 crop_info.width=(unsigned int) (x-crop_info.x);
4949 crop_info.width=(unsigned int) (crop_info.x-x);
4950 crop_info.x=(ssize_t) x;
4952 if (crop_info.y < 0)
4955 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4956 crop_info.y=(ssize_t) windows->image.ximage->height;
4957 if ((int) crop_info.y < y)
4958 crop_info.height=(unsigned int) (y-crop_info.y);
4961 crop_info.height=(unsigned int) (crop_info.y-y);
4962 crop_info.y=(ssize_t) y;
4965 } while ((state & ExitState) == 0);
4967 Wait for user to grab a corner of the rectangle or press return.
4970 (void) XMapWindow(display,windows->info.id);
4973 if (windows->info.mapped != MagickFalse)
4976 Display pointer position.
4978 (void) FormatLocaleString(text,MaxTextExtent,
4979 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4980 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4981 XInfoWidget(display,windows,text);
4983 highlight_info=crop_info;
4984 highlight_info.x=crop_info.x-windows->image.x;
4985 highlight_info.y=crop_info.y-windows->image.y;
4986 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4992 XHighlightRectangle(display,windows->image.id,
4993 windows->image.highlight_context,&highlight_info);
4994 XScreenEvent(display,windows,&event);
4995 if (event.xany.window == windows->command.id)
4998 Select a command from the Command widget.
5000 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5001 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
5002 (void) XSetFunction(display,windows->image.highlight_context,
5004 XHighlightRectangle(display,windows->image.id,
5005 windows->image.highlight_context,&highlight_info);
5007 switch (RectifyCommands[id])
5009 case RectifyCopyCommand:
5014 case RectifyHelpCommand:
5016 (void) XSetFunction(display,windows->image.highlight_context,
5022 XTextViewWidget(display,resource_info,windows,MagickFalse,
5023 "Help Viewer - Image Copy",ImageCopyHelp);
5028 XTextViewWidget(display,resource_info,windows,MagickFalse,
5029 "Help Viewer - Image Crop",ImageCropHelp);
5034 XTextViewWidget(display,resource_info,windows,MagickFalse,
5035 "Help Viewer - Image Cut",ImageCutHelp);
5039 (void) XSetFunction(display,windows->image.highlight_context,
5043 case RectifyDismissCommand:
5057 XHighlightRectangle(display,windows->image.id,
5058 windows->image.highlight_context,&highlight_info);
5063 if (event.xbutton.button != Button1)
5065 if (event.xbutton.window != windows->image.id)
5067 x=windows->image.x+event.xbutton.x;
5068 y=windows->image.y+event.xbutton.y;
5069 if ((x < (int) (crop_info.x+RoiDelta)) &&
5070 (x > (int) (crop_info.x-RoiDelta)) &&
5071 (y < (int) (crop_info.y+RoiDelta)) &&
5072 (y > (int) (crop_info.y-RoiDelta)))
5074 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5075 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5076 state|=UpdateConfigurationState;
5079 if ((x < (int) (crop_info.x+RoiDelta)) &&
5080 (x > (int) (crop_info.x-RoiDelta)) &&
5081 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5082 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5084 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5085 state|=UpdateConfigurationState;
5088 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5089 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5090 (y < (int) (crop_info.y+RoiDelta)) &&
5091 (y > (int) (crop_info.y-RoiDelta)))
5093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5094 state|=UpdateConfigurationState;
5097 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5098 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5099 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5100 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5102 state|=UpdateConfigurationState;
5108 if (event.xbutton.window == windows->pan.id)
5109 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5110 (highlight_info.y != crop_info.y-windows->image.y))
5111 XHighlightRectangle(display,windows->image.id,
5112 windows->image.highlight_context,&highlight_info);
5113 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5114 event.xbutton.time);
5119 if (event.xexpose.window == windows->image.id)
5120 if (event.xexpose.count == 0)
5122 event.xexpose.x=(int) highlight_info.x;
5123 event.xexpose.y=(int) highlight_info.y;
5124 event.xexpose.width=(int) highlight_info.width;
5125 event.xexpose.height=(int) highlight_info.height;
5126 XRefreshWindow(display,&windows->image,&event);
5128 if (event.xexpose.window == windows->info.id)
5129 if (event.xexpose.count == 0)
5130 XInfoWidget(display,windows,text);
5135 if (event.xkey.window != windows->image.id)
5138 Respond to a user key press.
5140 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5141 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5142 switch ((int) key_symbol)
5155 crop_info.x=(ssize_t) (windows->image.width/2L-
5156 crop_info.width/2L);
5157 crop_info.y=(ssize_t) (windows->image.height/2L-
5158 crop_info.height/2L);
5190 (void) XSetFunction(display,windows->image.highlight_context,
5196 XTextViewWidget(display,resource_info,windows,MagickFalse,
5197 "Help Viewer - Image Copy",ImageCopyHelp);
5202 XTextViewWidget(display,resource_info,windows,MagickFalse,
5203 "Help Viewer - Image Cropg",ImageCropHelp);
5208 XTextViewWidget(display,resource_info,windows,MagickFalse,
5209 "Help Viewer - Image Cutg",ImageCutHelp);
5213 (void) XSetFunction(display,windows->image.highlight_context,
5219 (void) XBell(display,0);
5223 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5231 if (event.xmotion.window != windows->image.id)
5234 Map and unmap Info widget as text cursor crosses its boundaries.
5238 if (windows->info.mapped != MagickFalse)
5240 if ((x < (int) (windows->info.x+windows->info.width)) &&
5241 (y < (int) (windows->info.y+windows->info.height)))
5242 (void) XWithdrawWindow(display,windows->info.id,
5243 windows->info.screen);
5246 if ((x > (int) (windows->info.x+windows->info.width)) ||
5247 (y > (int) (windows->info.y+windows->info.height)))
5248 (void) XMapWindow(display,windows->info.id);
5249 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5250 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5253 case SelectionRequest:
5258 XSelectionRequestEvent
5262 Set primary selection.
5264 (void) FormatLocaleString(text,MaxTextExtent,
5265 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5266 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5267 request=(&(event.xselectionrequest));
5268 (void) XChangeProperty(request->display,request->requestor,
5269 request->property,request->target,8,PropModeReplace,
5270 (unsigned char *) text,(int) strlen(text));
5271 notify.type=SelectionNotify;
5272 notify.display=request->display;
5273 notify.requestor=request->requestor;
5274 notify.selection=request->selection;
5275 notify.target=request->target;
5276 notify.time=request->time;
5277 if (request->property == None)
5278 notify.property=request->target;
5280 notify.property=request->property;
5281 (void) XSendEvent(request->display,request->requestor,False,0,
5282 (XEvent *) ¬ify);
5287 if ((state & UpdateConfigurationState) != 0)
5289 (void) XPutBackEvent(display,&event);
5290 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5293 } while ((state & ExitState) == 0);
5294 } while ((state & ExitState) == 0);
5295 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5296 XSetCursorState(display,windows,MagickFalse);
5297 if ((state & EscapeState) != 0)
5299 if (mode == CropMode)
5300 if (((int) crop_info.width != windows->image.ximage->width) ||
5301 ((int) crop_info.height != windows->image.ximage->height))
5304 Reconfigure Image window as defined by cropping rectangle.
5306 XSetCropGeometry(display,windows,&crop_info,image);
5307 windows->image.window_changes.width=(int) crop_info.width;
5308 windows->image.window_changes.height=(int) crop_info.height;
5309 (void) XConfigureImage(display,resource_info,windows,image,exception);
5313 Copy image before applying image transforms.
5315 XSetCursorState(display,windows,MagickTrue);
5316 XCheckRefreshWindows(display,windows);
5317 width=(unsigned int) image->columns;
5318 height=(unsigned int) image->rows;
5321 if (windows->image.crop_geometry != (char *) NULL)
5322 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5323 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5325 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5326 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5327 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5329 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5330 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5331 crop_image=CropImage(image,&crop_info,exception);
5332 XSetCursorState(display,windows,MagickFalse);
5333 if (crop_image == (Image *) NULL)
5334 return(MagickFalse);
5335 if (resource_info->copy_image != (Image *) NULL)
5336 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5337 resource_info->copy_image=crop_image;
5338 if (mode == CopyMode)
5340 (void) XConfigureImage(display,resource_info,windows,image,exception);
5346 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
5347 return(MagickFalse);
5348 image->matte=MagickTrue;
5349 image_view=AcquireCacheView(image);
5350 for (y=0; y < (int) crop_info.height; y++)
5352 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5353 crop_info.width,1,exception);
5354 if (q == (Quantum *) NULL)
5356 for (x=0; x < (int) crop_info.width; x++)
5358 SetPixelAlpha(image,TransparentAlpha,q);
5359 q+=GetPixelChannels(image);
5361 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5364 image_view=DestroyCacheView(image_view);
5366 Update image configuration.
5368 XConfigureImageColormap(display,resource_info,windows,image);
5369 (void) XConfigureImage(display,resource_info,windows,image,exception);
5374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5378 + X D r a w I m a g e %
5382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5384 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5387 % The format of the XDrawEditImage method is:
5389 % MagickBooleanType XDrawEditImage(Display *display,
5390 % XResourceInfo *resource_info,XWindows *windows,Image **image,
5391 % ExceptionInfo *exception)
5393 % A description of each parameter follows:
5395 % o display: Specifies a connection to an X server; returned from
5398 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5400 % o windows: Specifies a pointer to a XWindows structure.
5402 % o image: the image.
5404 % o exception: return any errors or warnings in this structure.
5407 static MagickBooleanType XDrawEditImage(Display *display,
5408 XResourceInfo *resource_info,XWindows *windows,Image **image,
5409 ExceptionInfo *exception)
5425 element = PointElement;
5427 static const ModeType
5440 stipple = (Pixmap) NULL;
5447 command[MaxTextExtent],
5448 text[MaxTextExtent];
5497 Allocate polygon info.
5499 max_coordinates=2048;
5500 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5501 sizeof(*coordinate_info));
5502 if (coordinate_info == (XPoint *) NULL)
5504 (void) ThrowMagickException(exception,GetMagickModule(),
5505 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5506 return(MagickFalse);
5511 (void) CloneString(&windows->command.name,"Draw");
5512 windows->command.data=4;
5513 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5514 (void) XMapRaised(display,windows->command.id);
5515 XClientMessage(display,windows->image.id,windows->im_protocols,
5516 windows->im_update_widget,CurrentTime);
5518 Wait for first button press.
5520 root_window=XRootWindow(display,XDefaultScreen(display));
5521 draw_info.stencil=OpaqueStencil;
5523 cursor=XCreateFontCursor(display,XC_tcross);
5526 XQueryPosition(display,windows->image.id,&x,&y);
5527 (void) XSelectInput(display,windows->image.id,
5528 windows->image.attributes.event_mask | PointerMotionMask);
5529 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5533 if (windows->info.mapped != MagickFalse)
5536 Display pointer position.
5538 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
5539 x+windows->image.x,y+windows->image.y);
5540 XInfoWidget(display,windows,text);
5543 Wait for next event.
5545 XScreenEvent(display,windows,&event);
5546 if (event.xany.window == windows->command.id)
5549 Select a command from the Command widget.
5551 id=XCommandWidget(display,windows,DrawMenu,&event);
5554 switch (DrawCommands[id])
5556 case DrawElementCommand:
5575 Select a command from the pop-up menu.
5577 element=(ElementType) (XMenuWidget(display,windows,
5578 DrawMenu[id],Elements,command)+1);
5581 case DrawColorCommand:
5584 *ColorMenu[MaxNumberPens+1];
5596 Initialize menu selections.
5598 for (i=0; i < (int) (MaxNumberPens-2); i++)
5599 ColorMenu[i]=resource_info->pen_colors[i];
5600 ColorMenu[MaxNumberPens-2]="transparent";
5601 ColorMenu[MaxNumberPens-1]="Browser...";
5602 ColorMenu[MaxNumberPens]=(char *) NULL;
5604 Select a pen color from the pop-up menu.
5606 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5607 (const char **) ColorMenu,command);
5610 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5612 if (transparent != MagickFalse)
5614 draw_info.stencil=TransparentStencil;
5617 if (pen_number == (MaxNumberPens-1))
5620 color_name[MaxTextExtent] = "gray";
5623 Select a pen color from a dialog.
5625 resource_info->pen_colors[pen_number]=color_name;
5626 XColorBrowserWidget(display,windows,"Select",color_name);
5627 if (*color_name == '\0')
5633 (void) XParseColor(display,windows->map_info->colormap,
5634 resource_info->pen_colors[pen_number],&color);
5635 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5636 (unsigned int) MaxColors,&color);
5637 windows->pixel_info->pen_colors[pen_number]=color;
5638 pen_id=(unsigned int) pen_number;
5639 draw_info.stencil=OpaqueStencil;
5642 case DrawStippleCommand:
5654 filename[MaxTextExtent] = "\0";
5671 Select a command from the pop-up menu.
5673 StipplesMenu[7]="Open...";
5674 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5678 if (stipple != (Pixmap) NULL)
5679 (void) XFreePixmap(display,stipple);
5680 stipple=(Pixmap) NULL;
5687 stipple=XCreateBitmapFromData(display,root_window,
5688 (char *) BricksBitmap,BricksWidth,BricksHeight);
5693 stipple=XCreateBitmapFromData(display,root_window,
5694 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5699 stipple=XCreateBitmapFromData(display,root_window,
5700 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5705 stipple=XCreateBitmapFromData(display,root_window,
5706 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5711 stipple=XCreateBitmapFromData(display,root_window,
5712 (char *) WavyBitmap,WavyWidth,WavyHeight);
5717 stipple=XCreateBitmapFromData(display,root_window,
5718 (char *) HighlightBitmap,HighlightWidth,
5725 stipple=XCreateBitmapFromData(display,root_window,
5726 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5732 XFileBrowserWidget(display,windows,"Stipple",filename);
5733 if (*filename == '\0')
5738 XSetCursorState(display,windows,MagickTrue);
5739 XCheckRefreshWindows(display,windows);
5740 image_info=AcquireImageInfo();
5741 (void) CopyMagickString(image_info->filename,filename,
5743 stipple_image=ReadImage(image_info,exception);
5744 CatchException(exception);
5745 XSetCursorState(display,windows,MagickFalse);
5746 if (stipple_image == (Image *) NULL)
5748 (void) AcquireUniqueFileResource(filename);
5749 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
5751 (void) WriteImage(image_info,stipple_image,exception);
5752 stipple_image=DestroyImage(stipple_image);
5753 image_info=DestroyImageInfo(image_info);
5754 status=XReadBitmapFile(display,root_window,filename,&width,
5755 &height,&stipple,&x,&y);
5756 (void) RelinquishUniqueFileResource(filename);
5757 if ((status != BitmapSuccess) != 0)
5758 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5762 case DrawWidthCommand:
5765 width[MaxTextExtent] = "0";
5780 Select a command from the pop-up menu.
5782 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5788 line_width=(unsigned int) StringToUnsignedLong(
5792 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5796 line_width=(unsigned int) StringToUnsignedLong(width);
5799 case DrawUndoCommand:
5801 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5805 case DrawHelpCommand:
5807 XTextViewWidget(display,resource_info,windows,MagickFalse,
5808 "Help Viewer - Image Rotation",ImageDrawHelp);
5809 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5812 case DrawDismissCommand:
5824 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5831 if (event.xbutton.button != Button1)
5833 if (event.xbutton.window != windows->image.id)
5852 if (event.xkey.window != windows->image.id)
5855 Respond to a user key press.
5857 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5858 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5859 switch ((int) key_symbol)
5874 XTextViewWidget(display,resource_info,windows,MagickFalse,
5875 "Help Viewer - Image Rotation",ImageDrawHelp);
5880 (void) XBell(display,0);
5889 Map and unmap Info widget as text cursor crosses its boundaries.
5893 if (windows->info.mapped != MagickFalse)
5895 if ((x < (int) (windows->info.x+windows->info.width)) &&
5896 (y < (int) (windows->info.y+windows->info.height)))
5897 (void) XWithdrawWindow(display,windows->info.id,
5898 windows->info.screen);
5901 if ((x > (int) (windows->info.x+windows->info.width)) ||
5902 (y > (int) (windows->info.y+windows->info.height)))
5903 (void) XMapWindow(display,windows->info.id);
5907 } while ((state & ExitState) == 0);
5908 (void) XSelectInput(display,windows->image.id,
5909 windows->image.attributes.event_mask);
5910 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5911 if ((state & EscapeState) != 0)
5914 Draw element as pointer moves until the button is released.
5922 rectangle_info.x=(ssize_t) x;
5923 rectangle_info.y=(ssize_t) y;
5924 rectangle_info.width=0;
5925 rectangle_info.height=0;
5926 number_coordinates=1;
5927 coordinate_info->x=x;
5928 coordinate_info->y=y;
5929 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5938 if (number_coordinates > 1)
5940 (void) XDrawLines(display,windows->image.id,
5941 windows->image.highlight_context,coordinate_info,
5942 number_coordinates,CoordModeOrigin);
5943 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
5944 coordinate_info[number_coordinates-1].x,
5945 coordinate_info[number_coordinates-1].y);
5946 XInfoWidget(display,windows,text);
5955 Display angle of the line.
5957 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5958 line_info.y1),(double) (line_info.x2-line_info.x1)));
5959 (void) FormatLocaleString(text,MaxTextExtent," %g",
5961 XInfoWidget(display,windows,text);
5962 XHighlightLine(display,windows->image.id,
5963 windows->image.highlight_context,&line_info);
5966 if (windows->info.mapped != MagickFalse)
5967 (void) XWithdrawWindow(display,windows->info.id,
5968 windows->info.screen);
5971 case RectangleElement:
5972 case FillRectangleElement:
5974 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5977 Display info and draw drawing rectangle.
5979 (void) FormatLocaleString(text,MaxTextExtent,
5980 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5981 (double) rectangle_info.height,(double) rectangle_info.x,
5982 (double) rectangle_info.y);
5983 XInfoWidget(display,windows,text);
5984 XHighlightRectangle(display,windows->image.id,
5985 windows->image.highlight_context,&rectangle_info);
5988 if (windows->info.mapped != MagickFalse)
5989 (void) XWithdrawWindow(display,windows->info.id,
5990 windows->info.screen);
5994 case FillCircleElement:
5995 case EllipseElement:
5996 case FillEllipseElement:
5998 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6001 Display info and draw drawing rectangle.
6003 (void) FormatLocaleString(text,MaxTextExtent,
6004 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
6005 (double) rectangle_info.height,(double) rectangle_info.x,
6006 (double) rectangle_info.y);
6007 XInfoWidget(display,windows,text);
6008 XHighlightEllipse(display,windows->image.id,
6009 windows->image.highlight_context,&rectangle_info);
6012 if (windows->info.mapped != MagickFalse)
6013 (void) XWithdrawWindow(display,windows->info.id,
6014 windows->info.screen);
6017 case PolygonElement:
6018 case FillPolygonElement:
6020 if (number_coordinates > 1)
6021 (void) XDrawLines(display,windows->image.id,
6022 windows->image.highlight_context,coordinate_info,
6023 number_coordinates,CoordModeOrigin);
6027 Display angle of the line.
6029 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6030 line_info.y1),(double) (line_info.x2-line_info.x1)));
6031 (void) FormatLocaleString(text,MaxTextExtent," %g",
6033 XInfoWidget(display,windows,text);
6034 XHighlightLine(display,windows->image.id,
6035 windows->image.highlight_context,&line_info);
6038 if (windows->info.mapped != MagickFalse)
6039 (void) XWithdrawWindow(display,windows->info.id,
6040 windows->info.screen);
6045 Wait for next event.
6047 XScreenEvent(display,windows,&event);
6053 if (number_coordinates > 1)
6054 (void) XDrawLines(display,windows->image.id,
6055 windows->image.highlight_context,coordinate_info,
6056 number_coordinates,CoordModeOrigin);
6062 XHighlightLine(display,windows->image.id,
6063 windows->image.highlight_context,&line_info);
6066 case RectangleElement:
6067 case FillRectangleElement:
6069 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6070 XHighlightRectangle(display,windows->image.id,
6071 windows->image.highlight_context,&rectangle_info);
6075 case FillCircleElement:
6076 case EllipseElement:
6077 case FillEllipseElement:
6079 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6080 XHighlightEllipse(display,windows->image.id,
6081 windows->image.highlight_context,&rectangle_info);
6084 case PolygonElement:
6085 case FillPolygonElement:
6087 if (number_coordinates > 1)
6088 (void) XDrawLines(display,windows->image.id,
6089 windows->image.highlight_context,coordinate_info,
6090 number_coordinates,CoordModeOrigin);
6092 XHighlightLine(display,windows->image.id,
6093 windows->image.highlight_context,&line_info);
6104 User has committed to element.
6106 line_info.x2=event.xbutton.x;
6107 line_info.y2=event.xbutton.y;
6108 rectangle_info.x=(ssize_t) event.xbutton.x;
6109 rectangle_info.y=(ssize_t) event.xbutton.y;
6110 coordinate_info[number_coordinates].x=event.xbutton.x;
6111 coordinate_info[number_coordinates].y=event.xbutton.y;
6112 if (((element != PolygonElement) &&
6113 (element != FillPolygonElement)) || (distance <= 9))
6118 number_coordinates++;
6119 if (number_coordinates < (int) max_coordinates)
6121 line_info.x1=event.xbutton.x;
6122 line_info.y1=event.xbutton.y;
6125 max_coordinates<<=1;
6126 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6127 max_coordinates,sizeof(*coordinate_info));
6128 if (coordinate_info == (XPoint *) NULL)
6129 (void) ThrowMagickException(exception,GetMagickModule(),
6130 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6137 if (event.xmotion.window != windows->image.id)
6139 if (element != PointElement)
6141 line_info.x2=event.xmotion.x;
6142 line_info.y2=event.xmotion.y;
6143 rectangle_info.x=(ssize_t) event.xmotion.x;
6144 rectangle_info.y=(ssize_t) event.xmotion.y;
6147 coordinate_info[number_coordinates].x=event.xbutton.x;
6148 coordinate_info[number_coordinates].y=event.xbutton.y;
6149 number_coordinates++;
6150 if (number_coordinates < (int) max_coordinates)
6152 max_coordinates<<=1;
6153 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6154 max_coordinates,sizeof(*coordinate_info));
6155 if (coordinate_info == (XPoint *) NULL)
6156 (void) ThrowMagickException(exception,GetMagickModule(),
6157 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6164 Check boundary conditions.
6166 if (line_info.x2 < 0)
6169 if (line_info.x2 > (int) windows->image.width)
6170 line_info.x2=(short) windows->image.width;
6171 if (line_info.y2 < 0)
6174 if (line_info.y2 > (int) windows->image.height)
6175 line_info.y2=(short) windows->image.height;
6176 distance=(unsigned int)
6177 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6178 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6179 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6180 ((state & ExitState) != 0))
6182 if (rectangle_info.x < 0)
6185 if (rectangle_info.x > (ssize_t) windows->image.width)
6186 rectangle_info.x=(ssize_t) windows->image.width;
6187 if ((int) rectangle_info.x < x)
6188 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6191 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6192 rectangle_info.x=(ssize_t) x;
6194 if (rectangle_info.y < 0)
6197 if (rectangle_info.y > (ssize_t) windows->image.height)
6198 rectangle_info.y=(ssize_t) windows->image.height;
6199 if ((int) rectangle_info.y < y)
6200 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6203 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6204 rectangle_info.y=(ssize_t) y;
6207 } while ((state & ExitState) == 0);
6208 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6209 if ((element == PointElement) || (element == PolygonElement) ||
6210 (element == FillPolygonElement))
6213 Determine polygon bounding box.
6215 rectangle_info.x=(ssize_t) coordinate_info->x;
6216 rectangle_info.y=(ssize_t) coordinate_info->y;
6217 x=coordinate_info->x;
6218 y=coordinate_info->y;
6219 for (i=1; i < number_coordinates; i++)
6221 if (coordinate_info[i].x > x)
6222 x=coordinate_info[i].x;
6223 if (coordinate_info[i].y > y)
6224 y=coordinate_info[i].y;
6225 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6226 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6227 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6228 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6230 rectangle_info.width=(size_t) (x-rectangle_info.x);
6231 rectangle_info.height=(size_t) (y-rectangle_info.y);
6232 for (i=0; i < number_coordinates; i++)
6234 coordinate_info[i].x-=rectangle_info.x;
6235 coordinate_info[i].y-=rectangle_info.y;
6242 if ((element == RectangleElement) ||
6243 (element == CircleElement) || (element == EllipseElement))
6245 rectangle_info.width--;
6246 rectangle_info.height--;
6249 Drawing is relative to image configuration.
6251 draw_info.x=(int) rectangle_info.x;
6252 draw_info.y=(int) rectangle_info.y;
6253 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6255 width=(unsigned int) (*image)->columns;
6256 height=(unsigned int) (*image)->rows;
6259 if (windows->image.crop_geometry != (char *) NULL)
6260 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6261 draw_info.x+=windows->image.x-(line_width/2);
6262 if (draw_info.x < 0)
6264 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6265 draw_info.y+=windows->image.y-(line_width/2);
6266 if (draw_info.y < 0)
6268 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6269 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6270 if (draw_info.width > (unsigned int) (*image)->columns)
6271 draw_info.width=(unsigned int) (*image)->columns;
6272 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6273 if (draw_info.height > (unsigned int) (*image)->rows)
6274 draw_info.height=(unsigned int) (*image)->rows;
6275 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6276 width*draw_info.width/windows->image.ximage->width,
6277 height*draw_info.height/windows->image.ximage->height,
6278 draw_info.x+x,draw_info.y+y);
6280 Initialize drawing attributes.
6282 draw_info.degrees=0.0;
6283 draw_info.element=element;
6284 draw_info.stipple=stipple;
6285 draw_info.line_width=line_width;
6286 draw_info.line_info=line_info;
6287 if (line_info.x1 > (int) (line_width/2))
6288 draw_info.line_info.x1=(short) line_width/2;
6289 if (line_info.y1 > (int) (line_width/2))
6290 draw_info.line_info.y1=(short) line_width/2;
6291 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6292 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6293 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6295 draw_info.line_info.x2=(-draw_info.line_info.x2);
6296 draw_info.line_info.y2=(-draw_info.line_info.y2);
6298 if (draw_info.line_info.x2 < 0)
6300 draw_info.line_info.x2=(-draw_info.line_info.x2);
6301 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6303 if (draw_info.line_info.y2 < 0)
6305 draw_info.line_info.y2=(-draw_info.line_info.y2);
6306 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6308 draw_info.rectangle_info=rectangle_info;
6309 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6310 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6311 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6312 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6313 draw_info.number_coordinates=(unsigned int) number_coordinates;
6314 draw_info.coordinate_info=coordinate_info;
6315 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6317 Draw element on image.
6319 XSetCursorState(display,windows,MagickTrue);
6320 XCheckRefreshWindows(display,windows);
6321 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6322 XSetCursorState(display,windows,MagickFalse);
6324 Update image colormap and return to image drawing.
6326 XConfigureImageColormap(display,resource_info,windows,*image);
6327 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6329 XSetCursorState(display,windows,MagickFalse);
6330 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6331 return(status != 0 ? MagickTrue : MagickFalse);
6335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6339 + X D r a w P a n R e c t a n g l e %
6343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6345 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6346 % displays a zoom image and the rectangle shows which portion of the image is
6347 % displayed in the Image window.
6349 % The format of the XDrawPanRectangle method is:
6351 % XDrawPanRectangle(Display *display,XWindows *windows)
6353 % A description of each parameter follows:
6355 % o display: Specifies a connection to an X server; returned from
6358 % o windows: Specifies a pointer to a XWindows structure.
6361 static void XDrawPanRectangle(Display *display,XWindows *windows)
6370 Determine dimensions of the panning rectangle.
6372 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6373 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6374 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6375 scale_factor=(MagickRealType)
6376 windows->pan.height/windows->image.ximage->height;
6377 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6378 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6380 Display the panning rectangle.
6382 (void) XClearWindow(display,windows->pan.id);
6383 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6392 + X I m a g e C a c h e %
6396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6398 % XImageCache() handles the creation, manipulation, and destruction of the
6399 % image cache (undo and redo buffers).
6401 % The format of the XImageCache method is:
6403 % void XImageCache(Display *display,XResourceInfo *resource_info,
6404 % XWindows *windows,const CommandType command,Image **image,
6405 % ExceptionInfo *exception)
6407 % A description of each parameter follows:
6409 % o display: Specifies a connection to an X server; returned from
6412 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6414 % o windows: Specifies a pointer to a XWindows structure.
6416 % o command: Specifies a command to perform.
6418 % o image: the image; XImageCache may transform the image and return a new
6421 % o exception: return any errors or warnings in this structure.
6424 static void XImageCache(Display *display,XResourceInfo *resource_info,
6425 XWindows *windows,const CommandType command,Image **image,
6426 ExceptionInfo *exception)
6432 *redo_image = (Image *) NULL,
6433 *undo_image = (Image *) NULL;
6437 case FreeBuffersCommand:
6440 Free memory from the undo and redo cache.
6442 while (undo_image != (Image *) NULL)
6444 cache_image=undo_image;
6445 undo_image=GetPreviousImageInList(undo_image);
6446 cache_image->list=DestroyImage(cache_image->list);
6447 cache_image=DestroyImage(cache_image);
6449 undo_image=NewImageList();
6450 if (redo_image != (Image *) NULL)
6451 redo_image=DestroyImage(redo_image);
6452 redo_image=NewImageList();
6458 image_geometry[MaxTextExtent];
6461 Undo the last image transformation.
6463 if (undo_image == (Image *) NULL)
6465 (void) XBell(display,0);
6468 cache_image=undo_image;
6469 undo_image=GetPreviousImageInList(undo_image);
6470 windows->image.window_changes.width=(int) cache_image->columns;
6471 windows->image.window_changes.height=(int) cache_image->rows;
6472 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
6473 windows->image.ximage->width,windows->image.ximage->height);
6474 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
6475 if (windows->image.crop_geometry != (char *) NULL)
6476 windows->image.crop_geometry=(char *)
6477 RelinquishMagickMemory(windows->image.crop_geometry);
6478 windows->image.crop_geometry=cache_image->geometry;
6479 if (redo_image != (Image *) NULL)
6480 redo_image=DestroyImage(redo_image);
6481 redo_image=(*image);
6482 *image=cache_image->list;
6483 cache_image=DestroyImage(cache_image);
6484 if (windows->image.orphan != MagickFalse)
6486 XConfigureImageColormap(display,resource_info,windows,*image);
6487 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6493 case HalfSizeCommand:
6494 case OriginalSizeCommand:
6495 case DoubleSizeCommand:
6502 case RotateRightCommand:
6503 case RotateLeftCommand:
6508 case ContrastStretchCommand:
6509 case SigmoidalContrastCommand:
6510 case NormalizeCommand:
6511 case EqualizeCommand:
6513 case SaturationCommand:
6514 case BrightnessCommand:
6518 case GrayscaleCommand:
6520 case QuantizeCommand:
6521 case DespeckleCommand:
6523 case ReduceNoiseCommand:
6524 case AddNoiseCommand:
6525 case SharpenCommand:
6527 case ThresholdCommand:
6528 case EdgeDetectCommand:
6532 case SegmentCommand:
6533 case SolarizeCommand:
6534 case SepiaToneCommand:
6536 case ImplodeCommand:
6537 case VignetteCommand:
6539 case OilPaintCommand:
6540 case CharcoalDrawCommand:
6541 case AnnotateCommand:
6542 case AddBorderCommand:
6543 case AddFrameCommand:
6544 case CompositeCommand:
6545 case CommentCommand:
6547 case RegionofInterestCommand:
6548 case SaveToUndoBufferCommand:
6557 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6558 if (undo_image != (Image *) NULL)
6561 Ensure the undo cache has enough memory available.
6563 previous_image=undo_image;
6564 while (previous_image != (Image *) NULL)
6566 bytes+=previous_image->list->columns*previous_image->list->rows*
6567 sizeof(PixelPacket);
6568 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6570 previous_image=GetPreviousImageInList(previous_image);
6573 bytes-=previous_image->list->columns*previous_image->list->rows*
6574 sizeof(PixelPacket);
6575 if (previous_image == undo_image)
6576 undo_image=NewImageList();
6578 previous_image->next->previous=NewImageList();
6581 while (previous_image != (Image *) NULL)
6584 Delete any excess memory from undo cache.
6586 cache_image=previous_image;
6587 previous_image=GetPreviousImageInList(previous_image);
6588 cache_image->list=DestroyImage(cache_image->list);
6589 cache_image=DestroyImage(cache_image);
6592 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6595 Save image before transformations are applied.
6597 cache_image=AcquireImage((ImageInfo *) NULL);
6598 if (cache_image == (Image *) NULL)
6600 XSetCursorState(display,windows,MagickTrue);
6601 XCheckRefreshWindows(display,windows);
6602 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
6603 XSetCursorState(display,windows,MagickFalse);
6604 if (cache_image->list == (Image *) NULL)
6606 cache_image=DestroyImage(cache_image);
6609 cache_image->columns=(size_t) windows->image.ximage->width;
6610 cache_image->rows=(size_t) windows->image.ximage->height;
6611 cache_image->geometry=windows->image.crop_geometry;
6612 if (windows->image.crop_geometry != (char *) NULL)
6614 cache_image->geometry=AcquireString((char *) NULL);
6615 (void) CopyMagickString(cache_image->geometry,
6616 windows->image.crop_geometry,MaxTextExtent);
6618 if (undo_image == (Image *) NULL)
6620 undo_image=cache_image;
6623 undo_image->next=cache_image;
6624 undo_image->next->previous=undo_image;
6625 undo_image=undo_image->next;
6631 if (command == RedoCommand)
6634 Redo the last image transformation.
6636 if (redo_image == (Image *) NULL)
6638 (void) XBell(display,0);
6641 windows->image.window_changes.width=(int) redo_image->columns;
6642 windows->image.window_changes.height=(int) redo_image->rows;
6643 if (windows->image.crop_geometry != (char *) NULL)
6644 windows->image.crop_geometry=(char *)
6645 RelinquishMagickMemory(windows->image.crop_geometry);
6646 windows->image.crop_geometry=redo_image->geometry;
6647 *image=DestroyImage(*image);
6649 redo_image=NewImageList();
6650 if (windows->image.orphan != MagickFalse)
6652 XConfigureImageColormap(display,resource_info,windows,*image);
6653 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6656 if (command != InfoCommand)
6661 XSetCursorState(display,windows,MagickTrue);
6662 XCheckRefreshWindows(display,windows);
6663 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6664 XSetCursorState(display,windows,MagickFalse);
6668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6672 + X I m a g e W i n d o w C o m m a n d %
6676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6678 % XImageWindowCommand() makes a transform to the image or Image window as
6679 % specified by a user menu button or keyboard command.
6681 % The format of the XImageWindowCommand method is:
6683 % CommandType XImageWindowCommand(Display *display,
6684 % XResourceInfo *resource_info,XWindows *windows,
6685 % const MagickStatusType state,KeySym key_symbol,Image **image,
6686 % ExceptionInfo *exception)
6688 % A description of each parameter follows:
6690 % o nexus: Method XImageWindowCommand returns an image when the
6691 % user chooses 'Open Image' from the command menu. Otherwise a null
6692 % image is returned.
6694 % o display: Specifies a connection to an X server; returned from
6697 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6699 % o windows: Specifies a pointer to a XWindows structure.
6701 % o state: key mask.
6703 % o key_symbol: Specifies a command to perform.
6705 % o image: the image; XImageWIndowCommand may transform the image and
6706 % return a new image pointer.
6708 % o exception: return any errors or warnings in this structure.
6711 static CommandType XImageWindowCommand(Display *display,
6712 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6713 KeySym key_symbol,Image **image,ExceptionInfo *exception)
6716 delta[MaxTextExtent] = "";
6719 Digits[] = "01234567890";
6724 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6726 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6729 resource_info->quantum=1;
6731 last_symbol=key_symbol;
6732 delta[strlen(delta)+1]='\0';
6733 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6734 resource_info->quantum=StringToLong(delta);
6735 return(NullCommand);
6737 last_symbol=key_symbol;
6738 if (resource_info->immutable)
6741 Virtual image window has a restricted command set.
6746 return(InfoCommand);
6749 return(PrintCommand);
6751 return(NextCommand);
6754 return(QuitCommand);
6758 return(NullCommand);
6760 switch ((int) key_symbol)
6764 if ((state & ControlMask) == 0)
6766 return(OpenCommand);
6769 return(NextCommand);
6771 return(FormerCommand);
6774 if ((state & Mod1Mask) != 0)
6775 return(SwirlCommand);
6776 if ((state & ControlMask) == 0)
6777 return(ShearCommand);
6778 return(SaveCommand);
6783 if ((state & Mod1Mask) != 0)
6784 return(OilPaintCommand);
6785 if ((state & Mod4Mask) != 0)
6786 return(ColorCommand);
6787 if ((state & ControlMask) == 0)
6788 return(NullCommand);
6789 return(PrintCommand);
6793 if ((state & Mod4Mask) != 0)
6794 return(DrawCommand);
6795 if ((state & ControlMask) == 0)
6796 return(NullCommand);
6797 return(DeleteCommand);
6801 if ((state & ControlMask) == 0)
6802 return(NullCommand);
6803 return(SelectCommand);
6807 if ((state & ControlMask) == 0)
6808 return(NullCommand);
6813 return(QuitCommand);
6817 if ((state & ControlMask) == 0)
6818 return(NullCommand);
6819 return(UndoCommand);
6824 if ((state & ControlMask) == 0)
6825 return(RollCommand);
6826 return(RedoCommand);
6830 if ((state & ControlMask) == 0)
6831 return(NullCommand);
6836 if ((state & Mod1Mask) != 0)
6837 return(CharcoalDrawCommand);
6838 if ((state & ControlMask) == 0)
6839 return(CropCommand);
6840 return(CopyCommand);
6845 if ((state & Mod4Mask) != 0)
6846 return(CompositeCommand);
6847 if ((state & ControlMask) == 0)
6848 return(FlipCommand);
6849 return(PasteCommand);
6852 return(HalfSizeCommand);
6854 return(OriginalSizeCommand);
6856 return(DoubleSizeCommand);
6858 return(ResizeCommand);
6860 return(RefreshCommand);
6861 case XK_bracketleft:
6862 return(ChopCommand);
6864 return(FlopCommand);
6866 return(RotateRightCommand);
6868 return(RotateLeftCommand);
6870 return(RotateCommand);
6872 return(TrimCommand);
6876 return(SaturationCommand);
6878 return(BrightnessCommand);
6880 return(GammaCommand);
6882 return(SpiffCommand);
6884 return(DullCommand);
6886 return(NormalizeCommand);
6888 return(EqualizeCommand);
6890 return(NegateCommand);
6892 return(GrayscaleCommand);
6894 return(QuantizeCommand);
6896 return(DespeckleCommand);
6898 return(EmbossCommand);
6900 return(ReduceNoiseCommand);
6902 return(AddNoiseCommand);
6904 return(SharpenCommand);
6906 return(BlurCommand);
6908 return(ThresholdCommand);
6910 return(EdgeDetectCommand);
6912 return(SpreadCommand);
6914 return(ShadeCommand);
6916 return(RaiseCommand);
6918 return(SegmentCommand);
6921 if ((state & Mod1Mask) == 0)
6922 return(NullCommand);
6923 return(ImplodeCommand);
6927 if ((state & Mod1Mask) == 0)
6928 return(NullCommand);
6929 return(WaveCommand);
6933 if ((state & Mod4Mask) == 0)
6934 return(NullCommand);
6935 return(MatteCommand);
6939 if ((state & Mod4Mask) == 0)
6940 return(NullCommand);
6941 return(AddBorderCommand);
6945 if ((state & Mod4Mask) == 0)
6946 return(NullCommand);
6947 return(AddFrameCommand);
6951 if ((state & Mod4Mask) == 0)
6952 return(NullCommand);
6953 return(CommentCommand);
6957 if ((state & Mod1Mask) != 0)
6958 return(ApplyCommand);
6959 if ((state & Mod4Mask) != 0)
6960 return(AnnotateCommand);
6961 if ((state & ControlMask) == 0)
6962 return(NullCommand);
6963 return(RegionofInterestCommand);
6966 return(InfoCommand);
6968 return(ZoomCommand);
6971 if ((state & ShiftMask) == 0)
6972 return(NullCommand);
6973 return(ShowPreviewCommand);
6976 return(LaunchCommand);
6978 return(HelpCommand);
6980 return(BrowseDocumentationCommand);
6983 (void) XMapRaised(display,windows->command.id);
6984 return(NullCommand);
6991 XTranslateImage(display,windows,*image,key_symbol);
6992 return(NullCommand);
7003 if ((state & Mod1Mask) != 0)
7009 Trim one pixel from edge of image.
7013 crop_info.width=(size_t) windows->image.ximage->width;
7014 crop_info.height=(size_t) windows->image.ximage->height;
7015 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
7017 if (resource_info->quantum >= (int) crop_info.height)
7018 resource_info->quantum=(int) crop_info.height-1;
7019 crop_info.height-=resource_info->quantum;
7021 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
7023 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
7024 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
7025 crop_info.y+=resource_info->quantum;
7026 crop_info.height-=resource_info->quantum;
7028 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7030 if (resource_info->quantum >= (int) crop_info.width)
7031 resource_info->quantum=(int) crop_info.width-1;
7032 crop_info.width-=resource_info->quantum;
7034 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7036 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7037 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7038 crop_info.x+=resource_info->quantum;
7039 crop_info.width-=resource_info->quantum;
7041 if ((int) (windows->image.x+windows->image.width) >
7042 (int) crop_info.width)
7043 windows->image.x=(int) (crop_info.width-windows->image.width);
7044 if ((int) (windows->image.y+windows->image.height) >
7045 (int) crop_info.height)
7046 windows->image.y=(int) (crop_info.height-windows->image.height);
7047 XSetCropGeometry(display,windows,&crop_info,*image);
7048 windows->image.window_changes.width=(int) crop_info.width;
7049 windows->image.window_changes.height=(int) crop_info.height;
7050 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7051 (void) XConfigureImage(display,resource_info,windows,*image,
7053 return(NullCommand);
7055 XTranslateImage(display,windows,*image,key_symbol);
7056 return(NullCommand);
7059 return(NullCommand);
7061 return(NullCommand);
7065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7069 + X M a g i c k C o m m a n d %
7073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7075 % XMagickCommand() makes a transform to the image or Image window as
7076 % specified by a user menu button or keyboard command.
7078 % The format of the XMagickCommand method is:
7080 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7081 % XWindows *windows,const CommandType command,Image **image,
7082 % ExceptionInfo *exception)
7084 % A description of each parameter follows:
7086 % o display: Specifies a connection to an X server; returned from
7089 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7091 % o windows: Specifies a pointer to a XWindows structure.
7093 % o command: Specifies a command to perform.
7095 % o image: the image; XMagickCommand may transform the image and return a
7096 % new image pointer.
7098 % o exception: return any errors or warnings in this structure.
7101 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7102 XWindows *windows,const CommandType command,Image **image,
7103 ExceptionInfo *exception)
7106 filename[MaxTextExtent],
7107 geometry[MaxTextExtent],
7108 modulate_factors[MaxTextExtent];
7137 color[MaxTextExtent] = "gray";
7144 Process user command.
7146 XCheckRefreshWindows(display,windows);
7147 XImageCache(display,resource_info,windows,command,image,exception);
7148 nexus=NewImageList();
7149 windows->image.window_changes.width=windows->image.ximage->width;
7150 windows->image.window_changes.height=windows->image.ximage->height;
7151 image_info=CloneImageInfo(resource_info->image_info);
7152 SetGeometryInfo(&geometry_info);
7153 GetQuantizeInfo(&quantize_info);
7161 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7169 for (i=0; i < resource_info->quantum; i++)
7170 XClientMessage(display,windows->image.id,windows->im_protocols,
7171 windows->im_next_image,CurrentTime);
7177 Display former image.
7179 for (i=0; i < resource_info->quantum; i++)
7180 XClientMessage(display,windows->image.id,windows->im_protocols,
7181 windows->im_former_image,CurrentTime);
7192 status=chdir(resource_info->home_directory);
7194 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7195 "UnableToOpenFile","%s",resource_info->home_directory);
7196 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7204 status=XSaveImage(display,resource_info,windows,*image,exception);
7205 if (status == MagickFalse)
7207 XNoticeWidget(display,windows,"Unable to write X image:",
7208 (*image)->filename);
7218 status=XPrintImage(display,resource_info,windows,*image,exception);
7219 if (status == MagickFalse)
7221 XNoticeWidget(display,windows,"Unable to print X image:",
7222 (*image)->filename);
7230 filename[MaxTextExtent] = "\0";
7235 XFileBrowserWidget(display,windows,"Delete",filename);
7236 if (*filename == '\0')
7238 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7239 if (status != MagickFalse)
7240 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7249 color[MaxTextExtent] = "gray",
7250 geometry[MaxTextExtent] = "640x480";
7253 *format = "gradient";
7256 Query user for canvas geometry.
7258 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7260 if (*geometry == '\0')
7264 XColorBrowserWidget(display,windows,"Select",color);
7270 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
7271 "%s:%s",format,color);
7272 (void) CloneString(&image_info->size,geometry);
7273 nexus=ReadImage(image_info,exception);
7274 CatchException(exception);
7275 XClientMessage(display,windows->image.id,windows->im_protocols,
7276 windows->im_next_image,CurrentTime);
7279 case VisualDirectoryCommand:
7282 Visual Image directory.
7284 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
7292 if (resource_info->confirm_exit == MagickFalse)
7293 XClientMessage(display,windows->image.id,windows->im_protocols,
7294 windows->im_exit,CurrentTime);
7301 Confirm program exit.
7303 status=XConfirmWidget(display,windows,"Do you really want to exit",
7304 resource_info->client_name);
7306 XClientMessage(display,windows->image.id,windows->im_protocols,
7307 windows->im_exit,CurrentTime);
7316 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
7324 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7333 status=XPasteImage(display,resource_info,windows,*image,exception);
7334 if (status == MagickFalse)
7336 XNoticeWidget(display,windows,"Unable to paste X image",
7337 (*image)->filename);
7342 case HalfSizeCommand:
7347 windows->image.window_changes.width=windows->image.ximage->width/2;
7348 windows->image.window_changes.height=windows->image.ximage->height/2;
7349 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7352 case OriginalSizeCommand:
7355 Original image size.
7357 windows->image.window_changes.width=(int) (*image)->columns;
7358 windows->image.window_changes.height=(int) (*image)->rows;
7359 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7362 case DoubleSizeCommand:
7365 Double the image size.
7367 windows->image.window_changes.width=windows->image.ximage->width << 1;
7368 windows->image.window_changes.height=windows->image.ximage->height << 1;
7369 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7388 width=(size_t) windows->image.ximage->width;
7389 height=(size_t) windows->image.ximage->height;
7392 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7393 (double) width,(double) height);
7394 status=XDialogWidget(display,windows,"Resize",
7395 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7396 if (*geometry == '\0')
7399 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7400 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7401 windows->image.window_changes.width=(int) width;
7402 windows->image.window_changes.height=(int) height;
7403 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7409 image_geometry[MaxTextExtent];
7411 if ((windows->image.crop_geometry == (char *) NULL) &&
7412 ((int) (*image)->columns == windows->image.ximage->width) &&
7413 ((int) (*image)->rows == windows->image.ximage->height))
7416 Apply size transforms to image.
7418 XSetCursorState(display,windows,MagickTrue);
7419 XCheckRefreshWindows(display,windows);
7421 Crop and/or scale displayed image.
7423 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
7424 windows->image.ximage->width,windows->image.ximage->height);
7425 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7426 if (windows->image.crop_geometry != (char *) NULL)
7427 windows->image.crop_geometry=(char *)
7428 RelinquishMagickMemory(windows->image.crop_geometry);
7431 XConfigureImageColormap(display,resource_info,windows,*image);
7432 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7435 case RefreshCommand:
7437 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7440 case RestoreCommand:
7443 Restore Image window to its original size.
7445 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7446 (windows->image.height == (unsigned int) (*image)->rows) &&
7447 (windows->image.crop_geometry == (char *) NULL))
7449 (void) XBell(display,0);
7452 windows->image.window_changes.width=(int) (*image)->columns;
7453 windows->image.window_changes.height=(int) (*image)->rows;
7454 if (windows->image.crop_geometry != (char *) NULL)
7456 windows->image.crop_geometry=(char *)
7457 RelinquishMagickMemory(windows->image.crop_geometry);
7458 windows->image.crop_geometry=(char *) NULL;
7462 XConfigureImageColormap(display,resource_info,windows,*image);
7463 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7471 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7480 status=XChopImage(display,resource_info,windows,image,exception);
7481 if (status == MagickFalse)
7483 XNoticeWidget(display,windows,"Unable to cut X image",
7484 (*image)->filename);
7495 Flop image scanlines.
7497 XSetCursorState(display,windows,MagickTrue);
7498 XCheckRefreshWindows(display,windows);
7499 flop_image=FlopImage(*image,exception);
7500 if (flop_image != (Image *) NULL)
7502 *image=DestroyImage(*image);
7505 CatchException(exception);
7506 XSetCursorState(display,windows,MagickFalse);
7507 if (windows->image.crop_geometry != (char *) NULL)
7512 width=(unsigned int) (*image)->columns;
7513 height=(unsigned int) (*image)->rows;
7514 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7516 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7517 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7519 if (windows->image.orphan != MagickFalse)
7521 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7530 Flip image scanlines.
7532 XSetCursorState(display,windows,MagickTrue);
7533 XCheckRefreshWindows(display,windows);
7534 flip_image=FlipImage(*image,exception);
7535 if (flip_image != (Image *) NULL)
7537 *image=DestroyImage(*image);
7540 CatchException(exception);
7541 XSetCursorState(display,windows,MagickFalse);
7542 if (windows->image.crop_geometry != (char *) NULL)
7547 width=(unsigned int) (*image)->columns;
7548 height=(unsigned int) (*image)->rows;
7549 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7551 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7552 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7554 if (windows->image.orphan != MagickFalse)
7556 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7559 case RotateRightCommand:
7562 Rotate image 90 degrees clockwise.
7564 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
7565 if (status == MagickFalse)
7567 XNoticeWidget(display,windows,"Unable to rotate X image",
7568 (*image)->filename);
7573 case RotateLeftCommand:
7576 Rotate image 90 degrees counter-clockwise.
7578 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
7579 if (status == MagickFalse)
7581 XNoticeWidget(display,windows,"Unable to rotate X image",
7582 (*image)->filename);
7592 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
7593 if (status == MagickFalse)
7595 XNoticeWidget(display,windows,"Unable to rotate X image",
7596 (*image)->filename);
7607 geometry[MaxTextExtent] = "45.0x45.0";
7610 Query user for shear color and geometry.
7612 XColorBrowserWidget(display,windows,"Select",color);
7615 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7617 if (*geometry == '\0')
7622 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7624 XSetCursorState(display,windows,MagickTrue);
7625 XCheckRefreshWindows(display,windows);
7626 (void) QueryColorDatabase(color,&(*image)->background_color,
7628 flags=ParseGeometry(geometry,&geometry_info);
7629 if ((flags & SigmaValue) == 0)
7630 geometry_info.sigma=geometry_info.rho;
7631 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7633 if (shear_image != (Image *) NULL)
7635 *image=DestroyImage(*image);
7638 CatchException(exception);
7639 XSetCursorState(display,windows,MagickFalse);
7640 if (windows->image.orphan != MagickFalse)
7642 windows->image.window_changes.width=(int) (*image)->columns;
7643 windows->image.window_changes.height=(int) (*image)->rows;
7644 XConfigureImageColormap(display,resource_info,windows,*image);
7645 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7654 geometry[MaxTextExtent] = "+2+2";
7657 Query user for the roll geometry.
7659 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7661 if (*geometry == '\0')
7666 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7668 XSetCursorState(display,windows,MagickTrue);
7669 XCheckRefreshWindows(display,windows);
7670 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7672 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7674 if (roll_image != (Image *) NULL)
7676 *image=DestroyImage(*image);
7679 CatchException(exception);
7680 XSetCursorState(display,windows,MagickFalse);
7681 if (windows->image.orphan != MagickFalse)
7683 windows->image.window_changes.width=(int) (*image)->columns;
7684 windows->image.window_changes.height=(int) (*image)->rows;
7685 XConfigureImageColormap(display,resource_info,windows,*image);
7686 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7692 fuzz[MaxTextExtent];
7695 Query user for the fuzz factor.
7697 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
7698 (*image)->fuzz/(QuantumRange+1.0));
7699 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7702 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
7706 status=XTrimImage(display,resource_info,windows,*image,exception);
7707 if (status == MagickFalse)
7709 XNoticeWidget(display,windows,"Unable to trim X image",
7710 (*image)->filename);
7718 hue_percent[MaxTextExtent] = "110";
7721 Query user for percent hue change.
7723 (void) XDialogWidget(display,windows,"Apply",
7724 "Enter percent change in image hue (0-200):",hue_percent);
7725 if (*hue_percent == '\0')
7730 XSetCursorState(display,windows,MagickTrue);
7731 XCheckRefreshWindows(display,windows);
7732 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7733 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7735 (void) ModulateImage(*image,modulate_factors,exception);
7736 XSetCursorState(display,windows,MagickFalse);
7737 if (windows->image.orphan != MagickFalse)
7739 XConfigureImageColormap(display,resource_info,windows,*image);
7740 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7743 case SaturationCommand:
7746 saturation_percent[MaxTextExtent] = "110";
7749 Query user for percent saturation change.
7751 (void) XDialogWidget(display,windows,"Apply",
7752 "Enter percent change in color saturation (0-200):",saturation_percent);
7753 if (*saturation_percent == '\0')
7756 Vary color saturation.
7758 XSetCursorState(display,windows,MagickTrue);
7759 XCheckRefreshWindows(display,windows);
7760 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7761 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7763 (void) ModulateImage(*image,modulate_factors,exception);
7764 XSetCursorState(display,windows,MagickFalse);
7765 if (windows->image.orphan != MagickFalse)
7767 XConfigureImageColormap(display,resource_info,windows,*image);
7768 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7771 case BrightnessCommand:
7774 brightness_percent[MaxTextExtent] = "110";
7777 Query user for percent brightness change.
7779 (void) XDialogWidget(display,windows,"Apply",
7780 "Enter percent change in color brightness (0-200):",brightness_percent);
7781 if (*brightness_percent == '\0')
7784 Vary the color brightness.
7786 XSetCursorState(display,windows,MagickTrue);
7787 XCheckRefreshWindows(display,windows);
7788 (void) CopyMagickString(modulate_factors,brightness_percent,
7790 (void) ModulateImage(*image,modulate_factors,exception);
7791 XSetCursorState(display,windows,MagickFalse);
7792 if (windows->image.orphan != MagickFalse)
7794 XConfigureImageColormap(display,resource_info,windows,*image);
7795 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7801 factor[MaxTextExtent] = "1.6";
7804 Query user for gamma value.
7806 (void) XDialogWidget(display,windows,"Gamma",
7807 "Enter gamma value (e.g. 1.2):",factor);
7808 if (*factor == '\0')
7811 Gamma correct image.
7813 XSetCursorState(display,windows,MagickTrue);
7814 XCheckRefreshWindows(display,windows);
7815 (void) GammaImage(*image,atof(factor),exception);
7816 XSetCursorState(display,windows,MagickFalse);
7817 if (windows->image.orphan != MagickFalse)
7819 XConfigureImageColormap(display,resource_info,windows,*image);
7820 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7826 Sharpen the image contrast.
7828 XSetCursorState(display,windows,MagickTrue);
7829 XCheckRefreshWindows(display,windows);
7830 (void) ContrastImage(*image,MagickTrue,exception);
7831 XSetCursorState(display,windows,MagickFalse);
7832 if (windows->image.orphan != MagickFalse)
7834 XConfigureImageColormap(display,resource_info,windows,*image);
7835 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7841 Dull the image contrast.
7843 XSetCursorState(display,windows,MagickTrue);
7844 XCheckRefreshWindows(display,windows);
7845 (void) ContrastImage(*image,MagickFalse,exception);
7846 XSetCursorState(display,windows,MagickFalse);
7847 if (windows->image.orphan != MagickFalse)
7849 XConfigureImageColormap(display,resource_info,windows,*image);
7850 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7853 case ContrastStretchCommand:
7860 levels[MaxTextExtent] = "1%";
7863 Query user for gamma value.
7865 (void) XDialogWidget(display,windows,"Contrast Stretch",
7866 "Enter black and white points:",levels);
7867 if (*levels == '\0')
7870 Contrast stretch image.
7872 XSetCursorState(display,windows,MagickTrue);
7873 XCheckRefreshWindows(display,windows);
7874 flags=ParseGeometry(levels,&geometry_info);
7875 black_point=geometry_info.rho;
7876 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7877 if ((flags & PercentValue) != 0)
7879 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7880 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7882 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7883 (void) ContrastStretchImage(*image,black_point,white_point,
7885 XSetCursorState(display,windows,MagickFalse);
7886 if (windows->image.orphan != MagickFalse)
7888 XConfigureImageColormap(display,resource_info,windows,*image);
7889 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7892 case SigmoidalContrastCommand:
7901 levels[MaxTextExtent] = "3x50%";
7904 Query user for gamma value.
7906 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7907 "Enter contrast and midpoint:",levels);
7908 if (*levels == '\0')
7911 Contrast stretch image.
7913 XSetCursorState(display,windows,MagickTrue);
7914 XCheckRefreshWindows(display,windows);
7915 flags=ParseGeometry(levels,&geometry_info);
7916 if ((flags & SigmaValue) == 0)
7917 geometry_info.sigma=1.0*QuantumRange/2.0;
7918 if ((flags & PercentValue) != 0)
7919 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7920 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7921 geometry_info.sigma,exception);
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,exception);
7929 case NormalizeCommand:
7932 Perform histogram normalization on the image.
7934 XSetCursorState(display,windows,MagickTrue);
7935 XCheckRefreshWindows(display,windows);
7936 (void) NormalizeImage(*image,exception);
7937 XSetCursorState(display,windows,MagickFalse);
7938 if (windows->image.orphan != MagickFalse)
7940 XConfigureImageColormap(display,resource_info,windows,*image);
7941 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7944 case EqualizeCommand:
7947 Perform histogram equalization on the image.
7949 XSetCursorState(display,windows,MagickTrue);
7950 XCheckRefreshWindows(display,windows);
7951 (void) EqualizeImage(*image,exception);
7952 XSetCursorState(display,windows,MagickFalse);
7953 if (windows->image.orphan != MagickFalse)
7955 XConfigureImageColormap(display,resource_info,windows,*image);
7956 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7962 Negate colors in image.
7964 XSetCursorState(display,windows,MagickTrue);
7965 XCheckRefreshWindows(display,windows);
7966 (void) NegateImage(*image,MagickFalse,exception);
7967 XSetCursorState(display,windows,MagickFalse);
7968 if (windows->image.orphan != MagickFalse)
7970 XConfigureImageColormap(display,resource_info,windows,*image);
7971 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7974 case GrayscaleCommand:
7977 Convert image to grayscale.
7979 XSetCursorState(display,windows,MagickTrue);
7980 XCheckRefreshWindows(display,windows);
7981 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7982 GrayscaleType : GrayscaleMatteType);
7983 XSetCursorState(display,windows,MagickFalse);
7984 if (windows->image.orphan != MagickFalse)
7986 XConfigureImageColormap(display,resource_info,windows,*image);
7987 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7996 filename[MaxTextExtent] = "\0";
7999 Request image file name from user.
8001 XFileBrowserWidget(display,windows,"Map",filename);
8002 if (*filename == '\0')
8007 XSetCursorState(display,windows,MagickTrue);
8008 XCheckRefreshWindows(display,windows);
8009 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
8010 affinity_image=ReadImage(image_info,exception);
8011 if (affinity_image != (Image *) NULL)
8013 (void) RemapImage(&quantize_info,*image,affinity_image);
8014 affinity_image=DestroyImage(affinity_image);
8016 CatchException(exception);
8017 XSetCursorState(display,windows,MagickFalse);
8018 if (windows->image.orphan != MagickFalse)
8020 XConfigureImageColormap(display,resource_info,windows,*image);
8021 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8024 case QuantizeCommand:
8030 colors[MaxTextExtent] = "256";
8033 Query user for maximum number of colors.
8035 status=XDialogWidget(display,windows,"Quantize",
8036 "Maximum number of colors:",colors);
8037 if (*colors == '\0')
8040 Color reduce the image.
8042 XSetCursorState(display,windows,MagickTrue);
8043 XCheckRefreshWindows(display,windows);
8044 quantize_info.number_colors=StringToUnsignedLong(colors);
8045 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
8046 (void) QuantizeImage(&quantize_info,*image);
8047 XSetCursorState(display,windows,MagickFalse);
8048 if (windows->image.orphan != MagickFalse)
8050 XConfigureImageColormap(display,resource_info,windows,*image);
8051 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8054 case DespeckleCommand:
8062 XSetCursorState(display,windows,MagickTrue);
8063 XCheckRefreshWindows(display,windows);
8064 despeckle_image=DespeckleImage(*image,exception);
8065 if (despeckle_image != (Image *) NULL)
8067 *image=DestroyImage(*image);
8068 *image=despeckle_image;
8070 CatchException(exception);
8071 XSetCursorState(display,windows,MagickFalse);
8072 if (windows->image.orphan != MagickFalse)
8074 XConfigureImageColormap(display,resource_info,windows,*image);
8075 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8084 radius[MaxTextExtent] = "0.0x1.0";
8087 Query user for emboss radius.
8089 (void) XDialogWidget(display,windows,"Emboss",
8090 "Enter the emboss radius and standard deviation:",radius);
8091 if (*radius == '\0')
8094 Reduce noise in the image.
8096 XSetCursorState(display,windows,MagickTrue);
8097 XCheckRefreshWindows(display,windows);
8098 flags=ParseGeometry(radius,&geometry_info);
8099 if ((flags & SigmaValue) == 0)
8100 geometry_info.sigma=1.0;
8101 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8103 if (emboss_image != (Image *) NULL)
8105 *image=DestroyImage(*image);
8106 *image=emboss_image;
8108 CatchException(exception);
8109 XSetCursorState(display,windows,MagickFalse);
8110 if (windows->image.orphan != MagickFalse)
8112 XConfigureImageColormap(display,resource_info,windows,*image);
8113 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8116 case ReduceNoiseCommand:
8122 radius[MaxTextExtent] = "0";
8125 Query user for noise radius.
8127 (void) XDialogWidget(display,windows,"Reduce Noise",
8128 "Enter the noise radius:",radius);
8129 if (*radius == '\0')
8132 Reduce noise in the image.
8134 XSetCursorState(display,windows,MagickTrue);
8135 XCheckRefreshWindows(display,windows);
8136 flags=ParseGeometry(radius,&geometry_info);
8137 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8138 geometry_info.rho,(size_t) geometry_info.rho,exception);
8139 if (noise_image != (Image *) NULL)
8141 *image=DestroyImage(*image);
8144 CatchException(exception);
8145 XSetCursorState(display,windows,MagickFalse);
8146 if (windows->image.orphan != MagickFalse)
8148 XConfigureImageColormap(display,resource_info,windows,*image);
8149 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8152 case AddNoiseCommand:
8161 noise_type[MaxTextExtent] = "Gaussian";
8164 Add noise to the image.
8166 noises=GetCommandOptions(MagickNoiseOptions);
8167 if (noises == (char **) NULL)
8169 XListBrowserWidget(display,windows,&windows->widget,
8170 (const char **) noises,"Add Noise",
8171 "Select a type of noise to add to your image:",noise_type);
8172 noises=DestroyStringList(noises);
8173 if (*noise_type == '\0')
8175 XSetCursorState(display,windows,MagickTrue);
8176 XCheckRefreshWindows(display,windows);
8177 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8178 MagickNoiseOptions,MagickFalse,noise_type),exception);
8179 if (noise_image != (Image *) NULL)
8181 *image=DestroyImage(*image);
8184 CatchException(exception);
8185 XSetCursorState(display,windows,MagickFalse);
8186 if (windows->image.orphan != MagickFalse)
8188 XConfigureImageColormap(display,resource_info,windows,*image);
8189 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8192 case SharpenCommand:
8198 radius[MaxTextExtent] = "0.0x1.0";
8201 Query user for sharpen radius.
8203 (void) XDialogWidget(display,windows,"Sharpen",
8204 "Enter the sharpen radius and standard deviation:",radius);
8205 if (*radius == '\0')
8208 Sharpen image scanlines.
8210 XSetCursorState(display,windows,MagickTrue);
8211 XCheckRefreshWindows(display,windows);
8212 flags=ParseGeometry(radius,&geometry_info);
8213 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8215 if (sharp_image != (Image *) NULL)
8217 *image=DestroyImage(*image);
8220 CatchException(exception);
8221 XSetCursorState(display,windows,MagickFalse);
8222 if (windows->image.orphan != MagickFalse)
8224 XConfigureImageColormap(display,resource_info,windows,*image);
8225 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8234 radius[MaxTextExtent] = "0.0x1.0";
8237 Query user for blur radius.
8239 (void) XDialogWidget(display,windows,"Blur",
8240 "Enter the blur radius and standard deviation:",radius);
8241 if (*radius == '\0')
8246 XSetCursorState(display,windows,MagickTrue);
8247 XCheckRefreshWindows(display,windows);
8248 flags=ParseGeometry(radius,&geometry_info);
8249 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8251 if (blur_image != (Image *) NULL)
8253 *image=DestroyImage(*image);
8256 CatchException(exception);
8257 XSetCursorState(display,windows,MagickFalse);
8258 if (windows->image.orphan != MagickFalse)
8260 XConfigureImageColormap(display,resource_info,windows,*image);
8261 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8264 case ThresholdCommand:
8270 factor[MaxTextExtent] = "128";
8273 Query user for threshold value.
8275 (void) XDialogWidget(display,windows,"Threshold",
8276 "Enter threshold value:",factor);
8277 if (*factor == '\0')
8280 Gamma correct image.
8282 XSetCursorState(display,windows,MagickTrue);
8283 XCheckRefreshWindows(display,windows);
8284 threshold=SiPrefixToDouble(factor,QuantumRange);
8285 (void) BilevelImage(*image,threshold);
8286 XSetCursorState(display,windows,MagickFalse);
8287 if (windows->image.orphan != MagickFalse)
8289 XConfigureImageColormap(display,resource_info,windows,*image);
8290 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8293 case EdgeDetectCommand:
8299 radius[MaxTextExtent] = "0";
8302 Query user for edge factor.
8304 (void) XDialogWidget(display,windows,"Detect Edges",
8305 "Enter the edge detect radius:",radius);
8306 if (*radius == '\0')
8309 Detect edge in image.
8311 XSetCursorState(display,windows,MagickTrue);
8312 XCheckRefreshWindows(display,windows);
8313 flags=ParseGeometry(radius,&geometry_info);
8314 edge_image=EdgeImage(*image,geometry_info.rho,exception);
8315 if (edge_image != (Image *) NULL)
8317 *image=DestroyImage(*image);
8320 CatchException(exception);
8321 XSetCursorState(display,windows,MagickFalse);
8322 if (windows->image.orphan != MagickFalse)
8324 XConfigureImageColormap(display,resource_info,windows,*image);
8325 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8334 amount[MaxTextExtent] = "2";
8337 Query user for spread amount.
8339 (void) XDialogWidget(display,windows,"Spread",
8340 "Enter the displacement amount:",amount);
8341 if (*amount == '\0')
8344 Displace image pixels by a random amount.
8346 XSetCursorState(display,windows,MagickTrue);
8347 XCheckRefreshWindows(display,windows);
8348 flags=ParseGeometry(amount,&geometry_info);
8349 spread_image=EdgeImage(*image,geometry_info.rho,exception);
8350 if (spread_image != (Image *) NULL)
8352 *image=DestroyImage(*image);
8353 *image=spread_image;
8355 CatchException(exception);
8356 XSetCursorState(display,windows,MagickFalse);
8357 if (windows->image.orphan != MagickFalse)
8359 XConfigureImageColormap(display,resource_info,windows,*image);
8360 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8372 geometry[MaxTextExtent] = "30x30";
8375 Query user for the shade geometry.
8377 status=XDialogWidget(display,windows,"Shade",
8378 "Enter the azimuth and elevation of the light source:",geometry);
8379 if (*geometry == '\0')
8384 XSetCursorState(display,windows,MagickTrue);
8385 XCheckRefreshWindows(display,windows);
8386 flags=ParseGeometry(geometry,&geometry_info);
8387 if ((flags & SigmaValue) == 0)
8388 geometry_info.sigma=1.0;
8389 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8390 geometry_info.rho,geometry_info.sigma,exception);
8391 if (shade_image != (Image *) NULL)
8393 *image=DestroyImage(*image);
8396 CatchException(exception);
8397 XSetCursorState(display,windows,MagickFalse);
8398 if (windows->image.orphan != MagickFalse)
8400 XConfigureImageColormap(display,resource_info,windows,*image);
8401 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8407 bevel_width[MaxTextExtent] = "10";
8410 Query user for bevel width.
8412 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8413 if (*bevel_width == '\0')
8418 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8420 XSetCursorState(display,windows,MagickTrue);
8421 XCheckRefreshWindows(display,windows);
8422 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8424 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
8425 XSetCursorState(display,windows,MagickFalse);
8426 if (windows->image.orphan != MagickFalse)
8428 XConfigureImageColormap(display,resource_info,windows,*image);
8429 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8432 case SegmentCommand:
8435 threshold[MaxTextExtent] = "1.0x1.5";
8438 Query user for smoothing threshold.
8440 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8442 if (*threshold == '\0')
8447 XSetCursorState(display,windows,MagickTrue);
8448 XCheckRefreshWindows(display,windows);
8449 flags=ParseGeometry(threshold,&geometry_info);
8450 if ((flags & SigmaValue) == 0)
8451 geometry_info.sigma=1.0;
8452 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8453 geometry_info.sigma);
8454 XSetCursorState(display,windows,MagickFalse);
8455 if (windows->image.orphan != MagickFalse)
8457 XConfigureImageColormap(display,resource_info,windows,*image);
8458 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8461 case SepiaToneCommand:
8470 factor[MaxTextExtent] = "80%";
8473 Query user for sepia-tone factor.
8475 (void) XDialogWidget(display,windows,"Sepia Tone",
8476 "Enter the sepia tone factor (0 - 99.9%):",factor);
8477 if (*factor == '\0')
8480 Sepia tone image pixels.
8482 XSetCursorState(display,windows,MagickTrue);
8483 XCheckRefreshWindows(display,windows);
8484 threshold=SiPrefixToDouble(factor,QuantumRange);
8485 sepia_image=SepiaToneImage(*image,threshold,exception);
8486 if (sepia_image != (Image *) NULL)
8488 *image=DestroyImage(*image);
8491 CatchException(exception);
8492 XSetCursorState(display,windows,MagickFalse);
8493 if (windows->image.orphan != MagickFalse)
8495 XConfigureImageColormap(display,resource_info,windows,*image);
8496 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8499 case SolarizeCommand:
8505 factor[MaxTextExtent] = "60%";
8508 Query user for solarize factor.
8510 (void) XDialogWidget(display,windows,"Solarize",
8511 "Enter the solarize factor (0 - 99.9%):",factor);
8512 if (*factor == '\0')
8515 Solarize image pixels.
8517 XSetCursorState(display,windows,MagickTrue);
8518 XCheckRefreshWindows(display,windows);
8519 threshold=SiPrefixToDouble(factor,QuantumRange);
8520 (void) SolarizeImage(*image,threshold,exception);
8521 XSetCursorState(display,windows,MagickFalse);
8522 if (windows->image.orphan != MagickFalse)
8524 XConfigureImageColormap(display,resource_info,windows,*image);
8525 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8534 degrees[MaxTextExtent] = "60";
8537 Query user for swirl angle.
8539 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8541 if (*degrees == '\0')
8544 Swirl image pixels about the center.
8546 XSetCursorState(display,windows,MagickTrue);
8547 XCheckRefreshWindows(display,windows);
8548 flags=ParseGeometry(degrees,&geometry_info);
8549 swirl_image=SwirlImage(*image,geometry_info.rho,exception);
8550 if (swirl_image != (Image *) NULL)
8552 *image=DestroyImage(*image);
8555 CatchException(exception);
8556 XSetCursorState(display,windows,MagickFalse);
8557 if (windows->image.orphan != MagickFalse)
8559 XConfigureImageColormap(display,resource_info,windows,*image);
8560 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8563 case ImplodeCommand:
8569 factor[MaxTextExtent] = "0.3";
8572 Query user for implode factor.
8574 (void) XDialogWidget(display,windows,"Implode",
8575 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8576 if (*factor == '\0')
8579 Implode image pixels about the center.
8581 XSetCursorState(display,windows,MagickTrue);
8582 XCheckRefreshWindows(display,windows);
8583 flags=ParseGeometry(factor,&geometry_info);
8584 implode_image=ImplodeImage(*image,geometry_info.rho,exception);
8585 if (implode_image != (Image *) NULL)
8587 *image=DestroyImage(*image);
8588 *image=implode_image;
8590 CatchException(exception);
8591 XSetCursorState(display,windows,MagickFalse);
8592 if (windows->image.orphan != MagickFalse)
8594 XConfigureImageColormap(display,resource_info,windows,*image);
8595 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8598 case VignetteCommand:
8604 geometry[MaxTextExtent] = "0x20";
8607 Query user for the vignette geometry.
8609 (void) XDialogWidget(display,windows,"Vignette",
8610 "Enter the radius, sigma, and x and y offsets:",geometry);
8611 if (*geometry == '\0')
8614 Soften the edges of the image in vignette style
8616 XSetCursorState(display,windows,MagickTrue);
8617 XCheckRefreshWindows(display,windows);
8618 flags=ParseGeometry(geometry,&geometry_info);
8619 if ((flags & SigmaValue) == 0)
8620 geometry_info.sigma=1.0;
8621 if ((flags & XiValue) == 0)
8622 geometry_info.xi=0.1*(*image)->columns;
8623 if ((flags & PsiValue) == 0)
8624 geometry_info.psi=0.1*(*image)->rows;
8625 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8626 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8628 if (vignette_image != (Image *) NULL)
8630 *image=DestroyImage(*image);
8631 *image=vignette_image;
8633 CatchException(exception);
8634 XSetCursorState(display,windows,MagickFalse);
8635 if (windows->image.orphan != MagickFalse)
8637 XConfigureImageColormap(display,resource_info,windows,*image);
8638 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8647 geometry[MaxTextExtent] = "25x150";
8650 Query user for the wave geometry.
8652 (void) XDialogWidget(display,windows,"Wave",
8653 "Enter the amplitude and length of the wave:",geometry);
8654 if (*geometry == '\0')
8657 Alter an image along a sine wave.
8659 XSetCursorState(display,windows,MagickTrue);
8660 XCheckRefreshWindows(display,windows);
8661 flags=ParseGeometry(geometry,&geometry_info);
8662 if ((flags & SigmaValue) == 0)
8663 geometry_info.sigma=1.0;
8664 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8666 if (wave_image != (Image *) NULL)
8668 *image=DestroyImage(*image);
8671 CatchException(exception);
8672 XSetCursorState(display,windows,MagickFalse);
8673 if (windows->image.orphan != MagickFalse)
8675 XConfigureImageColormap(display,resource_info,windows,*image);
8676 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8679 case OilPaintCommand:
8685 radius[MaxTextExtent] = "0";
8688 Query user for circular neighborhood radius.
8690 (void) XDialogWidget(display,windows,"Oil Paint",
8691 "Enter the mask radius:",radius);
8692 if (*radius == '\0')
8695 OilPaint image scanlines.
8697 XSetCursorState(display,windows,MagickTrue);
8698 XCheckRefreshWindows(display,windows);
8699 flags=ParseGeometry(radius,&geometry_info);
8700 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8702 if (paint_image != (Image *) NULL)
8704 *image=DestroyImage(*image);
8707 CatchException(exception);
8708 XSetCursorState(display,windows,MagickFalse);
8709 if (windows->image.orphan != MagickFalse)
8711 XConfigureImageColormap(display,resource_info,windows,*image);
8712 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8715 case CharcoalDrawCommand:
8721 radius[MaxTextExtent] = "0x1";
8724 Query user for charcoal radius.
8726 (void) XDialogWidget(display,windows,"Charcoal Draw",
8727 "Enter the charcoal radius and sigma:",radius);
8728 if (*radius == '\0')
8733 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8735 XSetCursorState(display,windows,MagickTrue);
8736 XCheckRefreshWindows(display,windows);
8737 flags=ParseGeometry(radius,&geometry_info);
8738 if ((flags & SigmaValue) == 0)
8739 geometry_info.sigma=geometry_info.rho;
8740 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8742 if (charcoal_image != (Image *) NULL)
8744 *image=DestroyImage(*image);
8745 *image=charcoal_image;
8747 CatchException(exception);
8748 XSetCursorState(display,windows,MagickFalse);
8749 if (windows->image.orphan != MagickFalse)
8751 XConfigureImageColormap(display,resource_info,windows,*image);
8752 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8755 case AnnotateCommand:
8758 Annotate the image with text.
8760 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
8761 if (status == MagickFalse)
8763 XNoticeWidget(display,windows,"Unable to annotate X image",
8764 (*image)->filename);
8774 status=XDrawEditImage(display,resource_info,windows,image,exception);
8775 if (status == MagickFalse)
8777 XNoticeWidget(display,windows,"Unable to draw on the X image",
8778 (*image)->filename);
8788 status=XColorEditImage(display,resource_info,windows,image,exception);
8789 if (status == MagickFalse)
8791 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8792 (*image)->filename);
8802 status=XMatteEditImage(display,resource_info,windows,image,exception);
8803 if (status == MagickFalse)
8805 XNoticeWidget(display,windows,"Unable to matte edit X image",
8806 (*image)->filename);
8811 case CompositeCommand:
8816 status=XCompositeImage(display,resource_info,windows,*image,
8818 if (status == MagickFalse)
8820 XNoticeWidget(display,windows,"Unable to composite X image",
8821 (*image)->filename);
8826 case AddBorderCommand:
8832 geometry[MaxTextExtent] = "6x6";
8835 Query user for border color and geometry.
8837 XColorBrowserWidget(display,windows,"Select",color);
8840 (void) XDialogWidget(display,windows,"Add Border",
8841 "Enter border geometry:",geometry);
8842 if (*geometry == '\0')
8845 Add a border to the image.
8847 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8849 XSetCursorState(display,windows,MagickTrue);
8850 XCheckRefreshWindows(display,windows);
8851 (void) QueryColorDatabase(color,&(*image)->border_color,
8853 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8855 border_image=BorderImage(*image,&page_geometry,exception);
8856 if (border_image != (Image *) NULL)
8858 *image=DestroyImage(*image);
8859 *image=border_image;
8861 CatchException(exception);
8862 XSetCursorState(display,windows,MagickFalse);
8863 if (windows->image.orphan != MagickFalse)
8865 windows->image.window_changes.width=(int) (*image)->columns;
8866 windows->image.window_changes.height=(int) (*image)->rows;
8867 XConfigureImageColormap(display,resource_info,windows,*image);
8868 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8871 case AddFrameCommand:
8880 geometry[MaxTextExtent] = "6x6";
8883 Query user for frame color and geometry.
8885 XColorBrowserWidget(display,windows,"Select",color);
8888 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8890 if (*geometry == '\0')
8893 Surround image with an ornamental border.
8895 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8897 XSetCursorState(display,windows,MagickTrue);
8898 XCheckRefreshWindows(display,windows);
8899 (void) QueryColorDatabase(color,&(*image)->matte_color,
8901 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8903 frame_info.width=page_geometry.width;
8904 frame_info.height=page_geometry.height;
8905 frame_info.outer_bevel=page_geometry.x;
8906 frame_info.inner_bevel=page_geometry.y;
8907 frame_info.x=(ssize_t) frame_info.width;
8908 frame_info.y=(ssize_t) frame_info.height;
8909 frame_info.width=(*image)->columns+2*frame_info.width;
8910 frame_info.height=(*image)->rows+2*frame_info.height;
8911 frame_image=FrameImage(*image,&frame_info,exception);
8912 if (frame_image != (Image *) NULL)
8914 *image=DestroyImage(*image);
8917 CatchException(exception);
8918 XSetCursorState(display,windows,MagickFalse);
8919 if (windows->image.orphan != MagickFalse)
8921 windows->image.window_changes.width=(int) (*image)->columns;
8922 windows->image.window_changes.height=(int) (*image)->rows;
8923 XConfigureImageColormap(display,resource_info,windows,*image);
8924 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8927 case CommentCommand:
8941 unique_file=AcquireUniqueFileResource(image_info->filename);
8942 if (unique_file == -1)
8943 XNoticeWidget(display,windows,"Unable to edit image comment",
8944 image_info->filename);
8945 value=GetImageProperty(*image,"comment");
8946 if (value == (char *) NULL)
8947 unique_file=close(unique_file)-1;
8953 file=fdopen(unique_file,"w");
8954 if (file == (FILE *) NULL)
8956 XNoticeWidget(display,windows,"Unable to edit image comment",
8957 image_info->filename);
8960 for (p=value; *p != '\0'; p++)
8961 (void) fputc((int) *p,file);
8962 (void) fputc('\n',file);
8963 (void) fclose(file);
8965 XSetCursorState(display,windows,MagickTrue);
8966 XCheckRefreshWindows(display,windows);
8967 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8969 if (status == MagickFalse)
8970 XNoticeWidget(display,windows,"Unable to edit image comment",
8977 comment=FileToString(image_info->filename,~0UL,exception);
8978 if (comment != (char *) NULL)
8980 (void) SetImageProperty(*image,"comment",comment);
8981 (*image)->taint=MagickTrue;
8984 (void) RelinquishUniqueFileResource(image_info->filename);
8985 XSetCursorState(display,windows,MagickFalse);
8993 XSetCursorState(display,windows,MagickTrue);
8994 XCheckRefreshWindows(display,windows);
8995 (void) AcquireUniqueFilename(filename);
8996 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
8998 status=WriteImage(image_info,*image,exception);
8999 if (status == MagickFalse)
9000 XNoticeWidget(display,windows,"Unable to launch image editor",
9004 nexus=ReadImage(resource_info->image_info,exception);
9005 CatchException(exception);
9006 XClientMessage(display,windows->image.id,windows->im_protocols,
9007 windows->im_next_image,CurrentTime);
9009 (void) RelinquishUniqueFileResource(filename);
9010 XSetCursorState(display,windows,MagickFalse);
9013 case RegionofInterestCommand:
9016 Apply an image processing technique to a region of interest.
9018 (void) XROIImage(display,resource_info,windows,image,exception);
9028 if (windows->magnify.mapped != MagickFalse)
9029 (void) XRaiseWindow(display,windows->magnify.id);
9035 XSetCursorState(display,windows,MagickTrue);
9036 (void) XMapRaised(display,windows->magnify.id);
9037 XSetCursorState(display,windows,MagickFalse);
9041 case ShowPreviewCommand:
9050 preview_type[MaxTextExtent] = "Gamma";
9053 Select preview type from menu.
9055 previews=GetCommandOptions(MagickPreviewOptions);
9056 if (previews == (char **) NULL)
9058 XListBrowserWidget(display,windows,&windows->widget,
9059 (const char **) previews,"Preview",
9060 "Select an enhancement, effect, or F/X:",preview_type);
9061 previews=DestroyStringList(previews);
9062 if (*preview_type == '\0')
9067 XSetCursorState(display,windows,MagickTrue);
9068 XCheckRefreshWindows(display,windows);
9069 image_info->preview_type=(PreviewType)
9070 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
9071 image_info->group=(ssize_t) windows->image.id;
9072 (void) DeleteImageProperty(*image,"label");
9073 (void) SetImageProperty(*image,"label","Preview");
9074 (void) AcquireUniqueFilename(filename);
9075 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
9077 status=WriteImage(image_info,*image,exception);
9078 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9079 preview_image=ReadImage(image_info,exception);
9080 (void) RelinquishUniqueFileResource(filename);
9081 if (preview_image == (Image *) NULL)
9083 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
9085 status=WriteImage(image_info,preview_image,exception);
9086 preview_image=DestroyImage(preview_image);
9087 if (status == MagickFalse)
9088 XNoticeWidget(display,windows,"Unable to show image preview",
9089 (*image)->filename);
9090 XDelay(display,1500);
9091 XSetCursorState(display,windows,MagickFalse);
9094 case ShowHistogramCommand:
9100 Show image histogram.
9102 XSetCursorState(display,windows,MagickTrue);
9103 XCheckRefreshWindows(display,windows);
9104 image_info->group=(ssize_t) windows->image.id;
9105 (void) DeleteImageProperty(*image,"label");
9106 (void) SetImageProperty(*image,"label","Histogram");
9107 (void) AcquireUniqueFilename(filename);
9108 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
9110 status=WriteImage(image_info,*image,exception);
9111 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9112 histogram_image=ReadImage(image_info,exception);
9113 (void) RelinquishUniqueFileResource(filename);
9114 if (histogram_image == (Image *) NULL)
9116 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
9117 "show:%s",filename);
9118 status=WriteImage(image_info,histogram_image,exception);
9119 histogram_image=DestroyImage(histogram_image);
9120 if (status == MagickFalse)
9121 XNoticeWidget(display,windows,"Unable to show histogram",
9122 (*image)->filename);
9123 XDelay(display,1500);
9124 XSetCursorState(display,windows,MagickFalse);
9127 case ShowMatteCommand:
9132 if ((*image)->matte == MagickFalse)
9134 XNoticeWidget(display,windows,
9135 "Image does not have any matte information",(*image)->filename);
9141 XSetCursorState(display,windows,MagickTrue);
9142 XCheckRefreshWindows(display,windows);
9143 image_info->group=(ssize_t) windows->image.id;
9144 (void) DeleteImageProperty(*image,"label");
9145 (void) SetImageProperty(*image,"label","Matte");
9146 (void) AcquireUniqueFilename(filename);
9147 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
9149 status=WriteImage(image_info,*image,exception);
9150 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9151 matte_image=ReadImage(image_info,exception);
9152 (void) RelinquishUniqueFileResource(filename);
9153 if (matte_image == (Image *) NULL)
9155 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
9157 status=WriteImage(image_info,matte_image,exception);
9158 matte_image=DestroyImage(matte_image);
9159 if (status == MagickFalse)
9160 XNoticeWidget(display,windows,"Unable to show matte",
9161 (*image)->filename);
9162 XDelay(display,1500);
9163 XSetCursorState(display,windows,MagickFalse);
9166 case BackgroundCommand:
9171 status=XBackgroundImage(display,resource_info,windows,image,exception);
9172 if (status == MagickFalse)
9174 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9175 if (nexus != (Image *) NULL)
9176 XClientMessage(display,windows->image.id,windows->im_protocols,
9177 windows->im_next_image,CurrentTime);
9180 case SlideShowCommand:
9183 delay[MaxTextExtent] = "5";
9186 Display next image after pausing.
9188 (void) XDialogWidget(display,windows,"Slide Show",
9189 "Pause how many 1/100ths of a second between images:",delay);
9192 resource_info->delay=StringToUnsignedLong(delay);
9193 XClientMessage(display,windows->image.id,windows->im_protocols,
9194 windows->im_next_image,CurrentTime);
9197 case PreferencesCommand:
9200 Set user preferences.
9202 status=XPreferencesWidget(display,resource_info,windows);
9203 if (status == MagickFalse)
9205 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9206 if (nexus != (Image *) NULL)
9207 XClientMessage(display,windows->image.id,windows->im_protocols,
9208 windows->im_next_image,CurrentTime);
9214 User requested help.
9216 XTextViewWidget(display,resource_info,windows,MagickFalse,
9217 "Help Viewer - Display",DisplayHelp);
9220 case BrowseDocumentationCommand:
9230 Browse the ImageMagick documentation.
9232 root_window=XRootWindow(display,XDefaultScreen(display));
9233 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9234 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9235 if (mozilla_window != (Window) NULL)
9238 command[MaxTextExtent],
9242 Display documentation using Netscape remote control.
9244 url=GetMagickHomeURL();
9245 (void) FormatLocaleString(command,MaxTextExtent,
9246 "openurl(%s,new-tab)",url);
9247 url=DestroyString(url);
9248 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9249 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9250 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9251 XSetCursorState(display,windows,MagickFalse);
9254 XSetCursorState(display,windows,MagickTrue);
9255 XCheckRefreshWindows(display,windows);
9256 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9258 if (status == MagickFalse)
9259 XNoticeWidget(display,windows,"Unable to browse documentation",
9261 XDelay(display,1500);
9262 XSetCursorState(display,windows,MagickFalse);
9265 case VersionCommand:
9267 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9268 GetMagickCopyright());
9271 case SaveToUndoBufferCommand:
9275 (void) XBell(display,0);
9279 image_info=DestroyImageInfo(image_info);
9284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9288 + X M a g n i f y I m a g e %
9292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9294 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9295 % The magnified portion is displayed in a separate window.
9297 % The format of the XMagnifyImage method is:
9299 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9301 % A description of each parameter follows:
9303 % o display: Specifies a connection to an X server; returned from
9306 % o windows: Specifies a pointer to a XWindows structure.
9308 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9309 % the entire image is refreshed.
9312 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9315 text[MaxTextExtent];
9325 Update magnified image until the mouse button is released.
9327 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9331 windows->magnify.x=(int) windows->image.x+x;
9332 windows->magnify.y=(int) windows->image.y+y;
9336 Map and unmap Info widget as text cursor crosses its boundaries.
9338 if (windows->info.mapped != MagickFalse)
9340 if ((x < (int) (windows->info.x+windows->info.width)) &&
9341 (y < (int) (windows->info.y+windows->info.height)))
9342 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9345 if ((x > (int) (windows->info.x+windows->info.width)) ||
9346 (y > (int) (windows->info.y+windows->info.height)))
9347 (void) XMapWindow(display,windows->info.id);
9348 if (windows->info.mapped != MagickFalse)
9351 Display pointer position.
9353 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9354 windows->magnify.x,windows->magnify.y);
9355 XInfoWidget(display,windows,text);
9358 Wait for next event.
9360 XScreenEvent(display,windows,event);
9361 switch (event->type)
9368 User has finished magnifying image.
9387 Check boundary conditions.
9392 if (x >= (int) windows->image.width)
9393 x=(int) windows->image.width-1;
9397 if (y >= (int) windows->image.height)
9398 y=(int) windows->image.height-1;
9399 } while ((state & ExitState) == 0);
9401 Display magnified image.
9403 XSetCursorState(display,windows,MagickFalse);
9407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9411 + X M a g n i f y W i n d o w C o m m a n d %
9415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9417 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9418 % pixel as specified by the key symbol.
9420 % The format of the XMagnifyWindowCommand method is:
9422 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9423 % const MagickStatusType state,const KeySym key_symbol)
9425 % A description of each parameter follows:
9427 % o display: Specifies a connection to an X server; returned from
9430 % o windows: Specifies a pointer to a XWindows structure.
9432 % o state: key mask.
9434 % o key_symbol: Specifies a KeySym which indicates which side of the image
9438 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9439 const MagickStatusType state,const KeySym key_symbol)
9445 User specified a magnify factor or position.
9448 if ((state & Mod1Mask) != 0)
9450 switch ((int) key_symbol)
9454 (void) XWithdrawWindow(display,windows->magnify.id,
9455 windows->magnify.screen);
9461 windows->magnify.x=(int) windows->image.width/2;
9462 windows->magnify.y=(int) windows->image.height/2;
9468 if (windows->magnify.x > 0)
9469 windows->magnify.x-=quantum;
9475 if (windows->magnify.y > 0)
9476 windows->magnify.y-=quantum;
9482 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9483 windows->magnify.x+=quantum;
9489 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9490 windows->magnify.y+=quantum;
9504 windows->magnify.data=(key_symbol-XK_0);
9518 windows->magnify.data=(key_symbol-XK_KP_0);
9524 XMakeMagnifyImage(display,windows);
9528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9532 + X M a k e P a n I m a g e %
9536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9538 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9541 % The format of the XMakePanImage method is:
9543 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9544 % XWindows *windows,Image *image,ExceptionInfo *exception)
9546 % A description of each parameter follows:
9548 % o display: Specifies a connection to an X server; returned from
9551 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9553 % o windows: Specifies a pointer to a XWindows structure.
9555 % o image: the image.
9557 % o exception: return any errors or warnings in this structure.
9560 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9561 XWindows *windows,Image *image,ExceptionInfo *exception)
9567 Create and display image for panning icon.
9569 XSetCursorState(display,windows,MagickTrue);
9570 XCheckRefreshWindows(display,windows);
9571 windows->pan.x=(int) windows->image.x;
9572 windows->pan.y=(int) windows->image.y;
9573 status=XMakeImage(display,resource_info,&windows->pan,image,
9574 windows->pan.width,windows->pan.height,exception);
9575 if (status == MagickFalse)
9576 ThrowXWindowFatalException(ResourceLimitError,
9577 "MemoryAllocationFailed",image->filename);
9578 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9579 windows->pan.pixmap);
9580 (void) XClearWindow(display,windows->pan.id);
9581 XDrawPanRectangle(display,windows);
9582 XSetCursorState(display,windows,MagickFalse);
9586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9590 + X M a t t a E d i t I m a g e %
9594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9596 % XMatteEditImage() allows the user to interactively change the Matte channel
9597 % of an image. If the image is PseudoClass it is promoted to DirectClass
9598 % before the matte information is stored.
9600 % The format of the XMatteEditImage method is:
9602 % MagickBooleanType XMatteEditImage(Display *display,
9603 % XResourceInfo *resource_info,XWindows *windows,Image **image,
9604 % ExceptionInfo *exception)
9606 % A description of each parameter follows:
9608 % o display: Specifies a connection to an X server; returned from
9611 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9613 % o windows: Specifies a pointer to a XWindows structure.
9615 % o image: the image; returned from ReadImage.
9617 % o exception: return any errors or warnings in this structure.
9620 static MagickBooleanType XMatteEditImage(Display *display,
9621 XResourceInfo *resource_info,XWindows *windows,Image **image,
9622 ExceptionInfo *exception)
9625 matte[MaxTextExtent] = "0";
9640 static const ModeType
9641 MatteEditCommands[] =
9644 MatteEditBorderCommand,
9645 MatteEditFuzzCommand,
9646 MatteEditValueCommand,
9647 MatteEditUndoCommand,
9648 MatteEditHelpCommand,
9649 MatteEditDismissCommand
9653 method = PointMethod;
9656 border_color = { 0, 0, 0, 0, 0, 0 };
9659 command[MaxTextExtent],
9660 text[MaxTextExtent];
9692 (void) CloneString(&windows->command.name,"Matte Edit");
9693 windows->command.data=4;
9694 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9695 (void) XMapRaised(display,windows->command.id);
9696 XClientMessage(display,windows->image.id,windows->im_protocols,
9697 windows->im_update_widget,CurrentTime);
9701 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9702 resource_info->background_color,resource_info->foreground_color);
9703 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9705 Track pointer until button 1 is pressed.
9707 XQueryPosition(display,windows->image.id,&x,&y);
9708 (void) XSelectInput(display,windows->image.id,
9709 windows->image.attributes.event_mask | PointerMotionMask);
9713 if (windows->info.mapped != MagickFalse)
9716 Display pointer position.
9718 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9719 x+windows->image.x,y+windows->image.y);
9720 XInfoWidget(display,windows,text);
9723 Wait for next event.
9725 XScreenEvent(display,windows,&event);
9726 if (event.xany.window == windows->command.id)
9729 Select a command from the Command widget.
9731 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9734 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9737 switch (MatteEditCommands[id])
9739 case MatteEditMethod:
9745 Select a method from the pop-up menu.
9747 methods=GetCommandOptions(MagickMethodOptions);
9748 if (methods == (char **) NULL)
9750 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9751 (const char **) methods,command);
9753 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9754 MagickFalse,methods[entry]);
9755 methods=DestroyStringList(methods);
9758 case MatteEditBorderCommand:
9761 *ColorMenu[MaxNumberPens];
9767 Initialize menu selections.
9769 for (i=0; i < (int) (MaxNumberPens-2); i++)
9770 ColorMenu[i]=resource_info->pen_colors[i];
9771 ColorMenu[MaxNumberPens-2]="Browser...";
9772 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9774 Select a pen color from the pop-up menu.
9776 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9777 (const char **) ColorMenu,command);
9780 if (pen_number == (MaxNumberPens-2))
9783 color_name[MaxTextExtent] = "gray";
9786 Select a pen color from a dialog.
9788 resource_info->pen_colors[pen_number]=color_name;
9789 XColorBrowserWidget(display,windows,"Select",color_name);
9790 if (*color_name == '\0')
9796 (void) XParseColor(display,windows->map_info->colormap,
9797 resource_info->pen_colors[pen_number],&border_color);
9800 case MatteEditFuzzCommand:
9803 fuzz[MaxTextExtent];
9818 Select a command from the pop-up menu.
9820 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9826 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
9830 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9831 (void) XDialogWidget(display,windows,"Ok",
9832 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9835 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9836 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
9839 case MatteEditValueCommand:
9842 message[MaxTextExtent];
9854 Select a command from the pop-up menu.
9856 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9862 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9864 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9865 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9866 (Quantum) TransparentAlpha);
9869 (void) FormatLocaleString(message,MaxTextExtent,
9870 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9872 (void) XDialogWidget(display,windows,"Matte",message,matte);
9877 case MatteEditUndoCommand:
9879 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9883 case MatteEditHelpCommand:
9885 XTextViewWidget(display,resource_info,windows,MagickFalse,
9886 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9889 case MatteEditDismissCommand:
9901 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9908 if (event.xbutton.button != Button1)
9910 if ((event.xbutton.window != windows->image.id) &&
9911 (event.xbutton.window != windows->magnify.id))
9918 (void) XMagickCommand(display,resource_info,windows,
9919 SaveToUndoBufferCommand,image,exception);
9920 state|=UpdateConfigurationState;
9925 if (event.xbutton.button != Button1)
9927 if ((event.xbutton.window != windows->image.id) &&
9928 (event.xbutton.window != windows->magnify.id))
9931 Update colormap information.
9935 XConfigureImageColormap(display,resource_info,windows,*image);
9936 (void) XConfigureImage(display,resource_info,windows,*image,exception);
9937 XInfoWidget(display,windows,text);
9938 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9939 state&=(~UpdateConfigurationState);
9947 command[MaxTextExtent];
9952 if (event.xkey.window == windows->magnify.id)
9957 window=windows->magnify.id;
9958 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9960 if (event.xkey.window != windows->image.id)
9963 Respond to a user key press.
9965 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9966 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9967 switch ((int) key_symbol)
9981 XTextViewWidget(display,resource_info,windows,MagickFalse,
9982 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9987 (void) XBell(display,0);
9996 Map and unmap Info widget as cursor crosses its boundaries.
10000 if (windows->info.mapped != MagickFalse)
10002 if ((x < (int) (windows->info.x+windows->info.width)) &&
10003 (y < (int) (windows->info.y+windows->info.height)))
10004 (void) XWithdrawWindow(display,windows->info.id,
10005 windows->info.screen);
10008 if ((x > (int) (windows->info.x+windows->info.width)) ||
10009 (y > (int) (windows->info.y+windows->info.height)))
10010 (void) XMapWindow(display,windows->info.id);
10016 if (event.xany.window == windows->magnify.id)
10018 x=windows->magnify.x-windows->image.x;
10019 y=windows->magnify.y-windows->image.y;
10023 if ((state & UpdateConfigurationState) != 0)
10033 Matte edit is relative to image configuration.
10035 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10037 XPutPixel(windows->image.ximage,x_offset,y_offset,
10038 windows->pixel_info->background_color.pixel);
10039 width=(unsigned int) (*image)->columns;
10040 height=(unsigned int) (*image)->rows;
10043 if (windows->image.crop_geometry != (char *) NULL)
10044 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10046 x_offset=(int) (width*(windows->image.x+x_offset)/
10047 windows->image.ximage->width+x);
10048 y_offset=(int) (height*(windows->image.y+y_offset)/
10049 windows->image.ximage->height+y);
10050 if ((x_offset < 0) || (y_offset < 0))
10052 if ((x_offset >= (int) (*image)->columns) ||
10053 (y_offset >= (int) (*image)->rows))
10055 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10056 return(MagickFalse);
10057 (*image)->matte=MagickTrue;
10058 image_view=AcquireCacheView(*image);
10065 Update matte information using point algorithm.
10067 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10068 (ssize_t) y_offset,1,1,exception);
10069 if (q == (Quantum *) NULL)
10071 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10072 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10075 case ReplaceMethod:
10082 Update matte information using replace algorithm.
10084 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
10085 (ssize_t) y_offset,&target,exception);
10086 for (y=0; y < (int) (*image)->rows; y++)
10088 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10089 (*image)->columns,1,exception);
10090 if (q == (Quantum *) NULL)
10092 for (x=0; x < (int) (*image)->columns; x++)
10094 GetPixelPacket(*image,q,&pixel);
10095 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
10096 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10097 q+=GetPixelChannels(*image);
10099 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10104 case FloodfillMethod:
10105 case FillToBorderMethod:
10117 Update matte information using floodfill algorithm.
10119 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10120 (ssize_t) y_offset,&target,exception);
10121 if (method == FillToBorderMethod)
10123 target.red=(MagickRealType) ScaleShortToQuantum(
10125 target.green=(MagickRealType) ScaleShortToQuantum(
10126 border_color.green);
10127 target.blue=(MagickRealType) ScaleShortToQuantum(
10128 border_color.blue);
10130 draw_info=CloneDrawInfo(resource_info->image_info,
10131 (DrawInfo *) NULL);
10132 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte,
10134 channel_mask=SetPixelChannelMask(*image,AlphaChannel);
10135 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10136 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
10137 MagickFalse : MagickTrue,exception);
10138 (void) SetPixelChannelMap(*image,channel_mask);
10139 draw_info=DestroyDrawInfo(draw_info);
10145 Update matte information using reset algorithm.
10147 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10148 return(MagickFalse);
10149 for (y=0; y < (int) (*image)->rows; y++)
10151 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10152 (*image)->columns,1,exception);
10153 if (q == (Quantum *) NULL)
10155 for (x=0; x < (int) (*image)->columns; x++)
10157 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10158 q+=GetPixelChannels(*image);
10160 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10163 if (StringToLong(matte) == (long) OpaqueAlpha)
10164 (*image)->matte=MagickFalse;
10168 image_view=DestroyCacheView(image_view);
10169 state&=(~UpdateConfigurationState);
10171 } while ((state & ExitState) == 0);
10172 (void) XSelectInput(display,windows->image.id,
10173 windows->image.attributes.event_mask);
10174 XSetCursorState(display,windows,MagickFalse);
10175 (void) XFreeCursor(display,cursor);
10176 return(MagickTrue);
10180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10184 + X O p e n I m a g e %
10188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10190 % XOpenImage() loads an image from a file.
10192 % The format of the XOpenImage method is:
10194 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10195 % XWindows *windows,const unsigned int command)
10197 % A description of each parameter follows:
10199 % o display: Specifies a connection to an X server; returned from
10202 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10204 % o windows: Specifies a pointer to a XWindows structure.
10206 % o command: A value other than zero indicates that the file is selected
10207 % from the command line argument list.
10210 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10211 XWindows *windows,const MagickBooleanType command)
10226 filename[MaxTextExtent] = "\0";
10229 Request file name from user.
10231 if (command == MagickFalse)
10232 XFileBrowserWidget(display,windows,"Open",filename);
10248 Select next image from the command line.
10250 status=XGetCommand(display,windows->image.id,&files,&count);
10253 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10254 return((Image *) NULL);
10256 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10257 if (filelist == (char **) NULL)
10259 ThrowXWindowFatalException(ResourceLimitError,
10260 "MemoryAllocationFailed","...");
10261 (void) XFreeStringList(files);
10262 return((Image *) NULL);
10265 for (i=1; i < count; i++)
10266 if (*files[i] != '-')
10267 filelist[j++]=files[i];
10268 filelist[j]=(char *) NULL;
10269 XListBrowserWidget(display,windows,&windows->widget,
10270 (const char **) filelist,"Load","Select Image to Load:",filename);
10271 filelist=(char **) RelinquishMagickMemory(filelist);
10272 (void) XFreeStringList(files);
10274 if (*filename == '\0')
10275 return((Image *) NULL);
10276 image_info=CloneImageInfo(resource_info->image_info);
10277 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10279 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10280 exception=AcquireExceptionInfo();
10281 (void) SetImageInfo(image_info,0,exception);
10282 if (LocaleCompare(image_info->magick,"X") == 0)
10285 seconds[MaxTextExtent];
10288 User may want to delay the X server screen grab.
10290 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10291 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10293 if (*seconds == '\0')
10294 return((Image *) NULL);
10295 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10297 magick_info=GetMagickInfo(image_info->magick,exception);
10298 if ((magick_info != (const MagickInfo *) NULL) &&
10299 (magick_info->raw != MagickFalse))
10302 geometry[MaxTextExtent];
10305 Request image size from the user.
10307 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10308 if (image_info->size != (char *) NULL)
10309 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10310 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10312 (void) CloneString(&image_info->size,geometry);
10317 XSetCursorState(display,windows,MagickTrue);
10318 XCheckRefreshWindows(display,windows);
10319 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10320 nexus=ReadImage(image_info,exception);
10321 CatchException(exception);
10322 XSetCursorState(display,windows,MagickFalse);
10323 if (nexus != (Image *) NULL)
10324 XClientMessage(display,windows->image.id,windows->im_protocols,
10325 windows->im_next_image,CurrentTime);
10333 Unknown image format.
10335 text=FileToString(filename,~0,exception);
10336 if (text == (char *) NULL)
10337 return((Image *) NULL);
10338 textlist=StringToList(text);
10339 if (textlist != (char **) NULL)
10342 title[MaxTextExtent];
10347 (void) FormatLocaleString(title,MaxTextExtent,
10348 "Unknown format: %s",filename);
10349 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10350 (const char **) textlist);
10351 for (i=0; textlist[i] != (char *) NULL; i++)
10352 textlist[i]=DestroyString(textlist[i]);
10353 textlist=(char **) RelinquishMagickMemory(textlist);
10355 text=DestroyString(text);
10357 exception=DestroyExceptionInfo(exception);
10358 image_info=DestroyImageInfo(image_info);
10363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10367 + X P a n I m a g e %
10371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10373 % XPanImage() pans the image until the mouse button is released.
10375 % The format of the XPanImage method is:
10377 % void XPanImage(Display *display,XWindows *windows,XEvent *event)
10379 % A description of each parameter follows:
10381 % o display: Specifies a connection to an X server; returned from
10384 % o windows: Specifies a pointer to a XWindows structure.
10386 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10387 % the entire image is refreshed.
10390 static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10393 text[MaxTextExtent];
10411 if ((windows->image.ximage->width > (int) windows->image.width) &&
10412 (windows->image.ximage->height > (int) windows->image.height))
10413 cursor=XCreateFontCursor(display,XC_fleur);
10415 if (windows->image.ximage->width > (int) windows->image.width)
10416 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10418 if (windows->image.ximage->height > (int) windows->image.height)
10419 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10421 cursor=XCreateFontCursor(display,XC_arrow);
10422 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10424 Pan image as pointer moves until the mouse button is released.
10426 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10427 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10428 pan_info.width=windows->pan.width*windows->image.width/
10429 windows->image.ximage->width;
10430 pan_info.height=windows->pan.height*windows->image.height/
10431 windows->image.ximage->height;
10434 state=UpdateConfigurationState;
10437 switch (event->type)
10442 User choose an initial pan location.
10444 pan_info.x=(ssize_t) event->xbutton.x;
10445 pan_info.y=(ssize_t) event->xbutton.y;
10446 state|=UpdateConfigurationState;
10449 case ButtonRelease:
10452 User has finished panning the image.
10454 pan_info.x=(ssize_t) event->xbutton.x;
10455 pan_info.y=(ssize_t) event->xbutton.y;
10456 state|=UpdateConfigurationState | ExitState;
10461 pan_info.x=(ssize_t) event->xmotion.x;
10462 pan_info.y=(ssize_t) event->xmotion.y;
10463 state|=UpdateConfigurationState;
10468 if ((state & UpdateConfigurationState) != 0)
10471 Check boundary conditions.
10473 if (pan_info.x < (ssize_t) (pan_info.width/2))
10476 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10477 if (pan_info.x < 0)
10480 if ((int) (pan_info.x+windows->image.width) >
10481 windows->image.ximage->width)
10482 pan_info.x=(ssize_t)
10483 (windows->image.ximage->width-windows->image.width);
10484 if (pan_info.y < (ssize_t) (pan_info.height/2))
10487 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10488 if (pan_info.y < 0)
10491 if ((int) (pan_info.y+windows->image.height) >
10492 windows->image.ximage->height)
10493 pan_info.y=(ssize_t)
10494 (windows->image.ximage->height-windows->image.height);
10495 if ((windows->image.x != (int) pan_info.x) ||
10496 (windows->image.y != (int) pan_info.y))
10499 Display image pan offset.
10501 windows->image.x=(int) pan_info.x;
10502 windows->image.y=(int) pan_info.y;
10503 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
10504 windows->image.width,windows->image.height,windows->image.x,
10506 XInfoWidget(display,windows,text);
10508 Refresh Image window.
10510 XDrawPanRectangle(display,windows);
10511 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10513 state&=(~UpdateConfigurationState);
10516 Wait for next event.
10518 if ((state & ExitState) == 0)
10519 XScreenEvent(display,windows,event);
10520 } while ((state & ExitState) == 0);
10524 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10525 (void) XFreeCursor(display,cursor);
10526 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10534 + X P a s t e I m a g e %
10538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10540 % XPasteImage() pastes an image previously saved with XCropImage in the X
10541 % window image at a location the user chooses with the pointer.
10543 % The format of the XPasteImage method is:
10545 % MagickBooleanType XPasteImage(Display *display,
10546 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10547 % ExceptionInfo *exception)
10549 % A description of each parameter follows:
10551 % o display: Specifies a connection to an X server; returned from
10554 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10556 % o windows: Specifies a pointer to a XWindows structure.
10558 % o image: the image; returned from ReadImage.
10560 % o exception: return any errors or warnings in this structure.
10563 static MagickBooleanType XPasteImage(Display *display,
10564 XResourceInfo *resource_info,XWindows *windows,Image *image,
10565 ExceptionInfo *exception)
10576 static const ModeType
10579 PasteOperatorsCommand,
10581 PasteDismissCommand
10584 static CompositeOperator
10585 compose = CopyCompositeOp;
10588 text[MaxTextExtent];
10622 if (resource_info->copy_image == (Image *) NULL)
10623 return(MagickFalse);
10624 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
10626 Map Command widget.
10628 (void) CloneString(&windows->command.name,"Paste");
10629 windows->command.data=1;
10630 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10631 (void) XMapRaised(display,windows->command.id);
10632 XClientMessage(display,windows->image.id,windows->im_protocols,
10633 windows->im_update_widget,CurrentTime);
10635 Track pointer until button 1 is pressed.
10637 XSetCursorState(display,windows,MagickFalse);
10638 XQueryPosition(display,windows->image.id,&x,&y);
10639 (void) XSelectInput(display,windows->image.id,
10640 windows->image.attributes.event_mask | PointerMotionMask);
10641 paste_info.x=(ssize_t) windows->image.x+x;
10642 paste_info.y=(ssize_t) windows->image.y+y;
10643 paste_info.width=0;
10644 paste_info.height=0;
10645 cursor=XCreateFontCursor(display,XC_ul_angle);
10646 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10647 state=DefaultState;
10650 if (windows->info.mapped != MagickFalse)
10653 Display pointer position.
10655 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
10656 (long) paste_info.x,(long) paste_info.y);
10657 XInfoWidget(display,windows,text);
10659 highlight_info=paste_info;
10660 highlight_info.x=paste_info.x-windows->image.x;
10661 highlight_info.y=paste_info.y-windows->image.y;
10662 XHighlightRectangle(display,windows->image.id,
10663 windows->image.highlight_context,&highlight_info);
10665 Wait for next event.
10667 XScreenEvent(display,windows,&event);
10668 XHighlightRectangle(display,windows->image.id,
10669 windows->image.highlight_context,&highlight_info);
10670 if (event.xany.window == windows->command.id)
10673 Select a command from the Command widget.
10675 id=XCommandWidget(display,windows,PasteMenu,&event);
10678 switch (PasteCommands[id])
10680 case PasteOperatorsCommand:
10683 command[MaxTextExtent],
10687 Select a command from the pop-up menu.
10689 operators=GetCommandOptions(MagickComposeOptions);
10690 if (operators == (char **) NULL)
10692 entry=XMenuWidget(display,windows,PasteMenu[id],
10693 (const char **) operators,command);
10695 compose=(CompositeOperator) ParseCommandOption(
10696 MagickComposeOptions,MagickFalse,operators[entry]);
10697 operators=DestroyStringList(operators);
10700 case PasteHelpCommand:
10702 XTextViewWidget(display,resource_info,windows,MagickFalse,
10703 "Help Viewer - Image Composite",ImagePasteHelp);
10706 case PasteDismissCommand:
10711 state|=EscapeState;
10720 switch (event.type)
10724 if (image->debug != MagickFalse)
10725 (void) LogMagickEvent(X11Event,GetMagickModule(),
10726 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10727 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10728 if (event.xbutton.button != Button1)
10730 if (event.xbutton.window != windows->image.id)
10733 Paste rectangle is relative to image configuration.
10735 width=(unsigned int) image->columns;
10736 height=(unsigned int) image->rows;
10739 if (windows->image.crop_geometry != (char *) NULL)
10740 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10742 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10743 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10744 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10745 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10746 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10747 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10748 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10751 case ButtonRelease:
10753 if (image->debug != MagickFalse)
10754 (void) LogMagickEvent(X11Event,GetMagickModule(),
10755 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10756 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10757 if (event.xbutton.button != Button1)
10759 if (event.xbutton.window != windows->image.id)
10761 if ((paste_info.width != 0) && (paste_info.height != 0))
10764 User has selected the location of the paste image.
10766 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10767 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10777 command[MaxTextExtent];
10785 if (event.xkey.window != windows->image.id)
10788 Respond to a user key press.
10790 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10791 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10792 *(command+length)='\0';
10793 if (image->debug != MagickFalse)
10794 (void) LogMagickEvent(X11Event,GetMagickModule(),
10795 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10796 switch ((int) key_symbol)
10804 paste_image=DestroyImage(paste_image);
10805 state|=EscapeState;
10812 (void) XSetFunction(display,windows->image.highlight_context,
10814 XTextViewWidget(display,resource_info,windows,MagickFalse,
10815 "Help Viewer - Image Composite",ImagePasteHelp);
10816 (void) XSetFunction(display,windows->image.highlight_context,
10822 (void) XBell(display,0);
10831 Map and unmap Info widget as text cursor crosses its boundaries.
10835 if (windows->info.mapped != MagickFalse)
10837 if ((x < (int) (windows->info.x+windows->info.width)) &&
10838 (y < (int) (windows->info.y+windows->info.height)))
10839 (void) XWithdrawWindow(display,windows->info.id,
10840 windows->info.screen);
10843 if ((x > (int) (windows->info.x+windows->info.width)) ||
10844 (y > (int) (windows->info.y+windows->info.height)))
10845 (void) XMapWindow(display,windows->info.id);
10846 paste_info.x=(ssize_t) windows->image.x+x;
10847 paste_info.y=(ssize_t) windows->image.y+y;
10852 if (image->debug != MagickFalse)
10853 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10858 } while ((state & ExitState) == 0);
10859 (void) XSelectInput(display,windows->image.id,
10860 windows->image.attributes.event_mask);
10861 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10862 XSetCursorState(display,windows,MagickFalse);
10863 (void) XFreeCursor(display,cursor);
10864 if ((state & EscapeState) != 0)
10865 return(MagickTrue);
10867 Image pasting is relative to image configuration.
10869 XSetCursorState(display,windows,MagickTrue);
10870 XCheckRefreshWindows(display,windows);
10871 width=(unsigned int) image->columns;
10872 height=(unsigned int) image->rows;
10875 if (windows->image.crop_geometry != (char *) NULL)
10876 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10877 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10879 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10880 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10881 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10883 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10884 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10886 Paste image with X Image window.
10888 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10889 paste_image=DestroyImage(paste_image);
10890 XSetCursorState(display,windows,MagickFalse);
10892 Update image colormap.
10894 XConfigureImageColormap(display,resource_info,windows,image);
10895 (void) XConfigureImage(display,resource_info,windows,image,exception);
10896 return(MagickTrue);
10900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10904 + X P r i n t I m a g e %
10908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10910 % XPrintImage() prints an image to a Postscript printer.
10912 % The format of the XPrintImage method is:
10914 % MagickBooleanType XPrintImage(Display *display,
10915 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10916 % ExceptionInfo *exception)
10918 % A description of each parameter follows:
10920 % o display: Specifies a connection to an X server; returned from
10923 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10925 % o windows: Specifies a pointer to a XWindows structure.
10927 % o image: the image.
10929 % o exception: return any errors or warnings in this structure.
10932 static MagickBooleanType XPrintImage(Display *display,
10933 XResourceInfo *resource_info,XWindows *windows,Image *image,
10934 ExceptionInfo *exception)
10937 filename[MaxTextExtent],
10938 geometry[MaxTextExtent];
10950 Request Postscript page geometry from user.
10952 image_info=CloneImageInfo(resource_info->image_info);
10953 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
10954 if (image_info->page != (char *) NULL)
10955 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10956 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10957 "Select Postscript Page Geometry:",geometry);
10958 if (*geometry == '\0')
10959 return(MagickTrue);
10960 image_info->page=GetPageGeometry(geometry);
10962 Apply image transforms.
10964 XSetCursorState(display,windows,MagickTrue);
10965 XCheckRefreshWindows(display,windows);
10966 print_image=CloneImage(image,0,0,MagickTrue,exception);
10967 if (print_image == (Image *) NULL)
10968 return(MagickFalse);
10969 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
10970 windows->image.ximage->width,windows->image.ximage->height);
10971 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10975 (void) AcquireUniqueFilename(filename);
10976 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
10978 status=WriteImage(image_info,print_image,exception);
10979 (void) RelinquishUniqueFileResource(filename);
10980 print_image=DestroyImage(print_image);
10981 image_info=DestroyImageInfo(image_info);
10982 XSetCursorState(display,windows,MagickFalse);
10983 return(status != 0 ? MagickTrue : MagickFalse);
10987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10991 + X R O I I m a g e %
10995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10997 % XROIImage() applies an image processing technique to a region of interest.
10999 % The format of the XROIImage method is:
11001 % MagickBooleanType XROIImage(Display *display,
11002 % XResourceInfo *resource_info,XWindows *windows,Image **image,
11003 % ExceptionInfo *exception)
11005 % A description of each parameter follows:
11007 % o display: Specifies a connection to an X server; returned from
11010 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11012 % o windows: Specifies a pointer to a XWindows structure.
11014 % o image: the image; returned from ReadImage.
11016 % o exception: return any errors or warnings in this structure.
11019 static MagickBooleanType XROIImage(Display *display,
11020 XResourceInfo *resource_info,XWindows *windows,Image **image,
11021 ExceptionInfo *exception)
11023 #define ApplyMenus 7
11073 "Contrast Stretch...",
11074 "Sigmoidal Contrast...",
11108 "Charcoal Draw...",
11111 *MiscellanyMenu[] =
11122 **Menus[ApplyMenus] =
11133 static const CommandType
11156 TransformCommands[] =
11160 RotateRightCommand,
11163 EnhanceCommands[] =
11171 ContrastStretchCommand,
11172 SigmoidalContrastCommand,
11180 EffectsCommands[] =
11184 ReduceNoiseCommand,
11203 CharcoalDrawCommand
11205 MiscellanyCommands[] =
11209 ShowPreviewCommand,
11210 ShowHistogramCommand,
11219 static const CommandType
11220 *Commands[ApplyMenus] =
11232 command[MaxTextExtent],
11233 text[MaxTextExtent];
11253 MagickProgressMonitor
11272 Map Command widget.
11274 (void) CloneString(&windows->command.name,"ROI");
11275 windows->command.data=0;
11276 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11277 (void) XMapRaised(display,windows->command.id);
11278 XClientMessage(display,windows->image.id,windows->im_protocols,
11279 windows->im_update_widget,CurrentTime);
11281 Track pointer until button 1 is pressed.
11283 XQueryPosition(display,windows->image.id,&x,&y);
11284 (void) XSelectInput(display,windows->image.id,
11285 windows->image.attributes.event_mask | PointerMotionMask);
11286 roi_info.x=(ssize_t) windows->image.x+x;
11287 roi_info.y=(ssize_t) windows->image.y+y;
11290 cursor=XCreateFontCursor(display,XC_fleur);
11291 state=DefaultState;
11294 if (windows->info.mapped != MagickFalse)
11297 Display pointer position.
11299 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
11300 (long) roi_info.x,(long) roi_info.y);
11301 XInfoWidget(display,windows,text);
11304 Wait for next event.
11306 XScreenEvent(display,windows,&event);
11307 if (event.xany.window == windows->command.id)
11310 Select a command from the Command widget.
11312 id=XCommandWidget(display,windows,ROIMenu,&event);
11315 switch (ROICommands[id])
11317 case ROIHelpCommand:
11319 XTextViewWidget(display,resource_info,windows,MagickFalse,
11320 "Help Viewer - Region of Interest",ImageROIHelp);
11323 case ROIDismissCommand:
11328 state|=EscapeState;
11337 switch (event.type)
11341 if (event.xbutton.button != Button1)
11343 if (event.xbutton.window != windows->image.id)
11346 Note first corner of region of interest rectangle-- exit loop.
11348 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11349 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11350 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11354 case ButtonRelease:
11363 if (event.xkey.window != windows->image.id)
11366 Respond to a user key press.
11368 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11369 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11370 switch ((int) key_symbol)
11378 state|=EscapeState;
11385 XTextViewWidget(display,resource_info,windows,MagickFalse,
11386 "Help Viewer - Region of Interest",ImageROIHelp);
11391 (void) XBell(display,0);
11400 Map and unmap Info widget as text cursor crosses its boundaries.
11404 if (windows->info.mapped != MagickFalse)
11406 if ((x < (int) (windows->info.x+windows->info.width)) &&
11407 (y < (int) (windows->info.y+windows->info.height)))
11408 (void) XWithdrawWindow(display,windows->info.id,
11409 windows->info.screen);
11412 if ((x > (int) (windows->info.x+windows->info.width)) ||
11413 (y > (int) (windows->info.y+windows->info.height)))
11414 (void) XMapWindow(display,windows->info.id);
11415 roi_info.x=(ssize_t) windows->image.x+x;
11416 roi_info.y=(ssize_t) windows->image.y+y;
11422 } while ((state & ExitState) == 0);
11423 (void) XSelectInput(display,windows->image.id,
11424 windows->image.attributes.event_mask);
11425 if ((state & EscapeState) != 0)
11428 User want to exit without region of interest.
11430 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11431 (void) XFreeCursor(display,cursor);
11432 return(MagickTrue);
11434 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11438 Size rectangle as pointer moves until the mouse button is released.
11440 x=(int) roi_info.x;
11441 y=(int) roi_info.y;
11444 state=DefaultState;
11447 highlight_info=roi_info;
11448 highlight_info.x=roi_info.x-windows->image.x;
11449 highlight_info.y=roi_info.y-windows->image.y;
11450 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11453 Display info and draw region of interest rectangle.
11455 if (windows->info.mapped == MagickFalse)
11456 (void) XMapWindow(display,windows->info.id);
11457 (void) FormatLocaleString(text,MaxTextExtent,
11458 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11459 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11460 XInfoWidget(display,windows,text);
11461 XHighlightRectangle(display,windows->image.id,
11462 windows->image.highlight_context,&highlight_info);
11465 if (windows->info.mapped != MagickFalse)
11466 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11468 Wait for next event.
11470 XScreenEvent(display,windows,&event);
11471 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11472 XHighlightRectangle(display,windows->image.id,
11473 windows->image.highlight_context,&highlight_info);
11474 switch (event.type)
11478 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11479 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11482 case ButtonRelease:
11485 User has committed to region of interest rectangle.
11487 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11488 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11489 XSetCursorState(display,windows,MagickFalse);
11491 if (LocaleCompare(windows->command.name,"Apply") == 0)
11493 (void) CloneString(&windows->command.name,"Apply");
11494 windows->command.data=ApplyMenus;
11495 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11502 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11503 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11508 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11509 ((state & ExitState) != 0))
11512 Check boundary conditions.
11514 if (roi_info.x < 0)
11517 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11518 roi_info.x=(ssize_t) windows->image.ximage->width;
11519 if ((int) roi_info.x < x)
11520 roi_info.width=(unsigned int) (x-roi_info.x);
11523 roi_info.width=(unsigned int) (roi_info.x-x);
11524 roi_info.x=(ssize_t) x;
11526 if (roi_info.y < 0)
11529 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11530 roi_info.y=(ssize_t) windows->image.ximage->height;
11531 if ((int) roi_info.y < y)
11532 roi_info.height=(unsigned int) (y-roi_info.y);
11535 roi_info.height=(unsigned int) (roi_info.y-y);
11536 roi_info.y=(ssize_t) y;
11539 } while ((state & ExitState) == 0);
11541 Wait for user to grab a corner of the rectangle or press return.
11543 state=DefaultState;
11544 command_type=NullCommand;
11545 (void) XMapWindow(display,windows->info.id);
11548 if (windows->info.mapped != MagickFalse)
11551 Display pointer position.
11553 (void) FormatLocaleString(text,MaxTextExtent,
11554 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11555 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11556 XInfoWidget(display,windows,text);
11558 highlight_info=roi_info;
11559 highlight_info.x=roi_info.x-windows->image.x;
11560 highlight_info.y=roi_info.y-windows->image.y;
11561 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11563 state|=EscapeState;
11567 if ((state & UpdateRegionState) != 0)
11569 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11570 switch (command_type)
11575 (void) XMagickCommand(display,resource_info,windows,command_type,
11582 Region of interest is relative to image configuration.
11584 progress_monitor=SetImageProgressMonitor(*image,
11585 (MagickProgressMonitor) NULL,(*image)->client_data);
11586 crop_info=roi_info;
11587 width=(unsigned int) (*image)->columns;
11588 height=(unsigned int) (*image)->rows;
11591 if (windows->image.crop_geometry != (char *) NULL)
11592 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11594 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11596 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11597 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11598 scale_factor=(MagickRealType)
11599 height/windows->image.ximage->height;
11601 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11602 crop_info.height=(unsigned int)
11603 (scale_factor*crop_info.height+0.5);
11604 roi_image=CropImage(*image,&crop_info,exception);
11605 (void) SetImageProgressMonitor(*image,progress_monitor,
11606 (*image)->client_data);
11607 if (roi_image == (Image *) NULL)
11610 Apply image processing technique to the region of interest.
11612 windows->image.orphan=MagickTrue;
11613 (void) XMagickCommand(display,resource_info,windows,command_type,
11614 &roi_image,exception);
11615 progress_monitor=SetImageProgressMonitor(*image,
11616 (MagickProgressMonitor) NULL,(*image)->client_data);
11617 (void) XMagickCommand(display,resource_info,windows,
11618 SaveToUndoBufferCommand,image,exception);
11619 windows->image.orphan=MagickFalse;
11620 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11621 crop_info.x,crop_info.y);
11622 roi_image=DestroyImage(roi_image);
11623 (void) SetImageProgressMonitor(*image,progress_monitor,
11624 (*image)->client_data);
11628 if (command_type != InfoCommand)
11630 XConfigureImageColormap(display,resource_info,windows,*image);
11631 (void) XConfigureImage(display,resource_info,windows,*image,exception);
11633 XCheckRefreshWindows(display,windows);
11634 XInfoWidget(display,windows,text);
11635 (void) XSetFunction(display,windows->image.highlight_context,
11637 state&=(~UpdateRegionState);
11639 XHighlightRectangle(display,windows->image.id,
11640 windows->image.highlight_context,&highlight_info);
11641 XScreenEvent(display,windows,&event);
11642 if (event.xany.window == windows->command.id)
11645 Select a command from the Command widget.
11647 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11648 command_type=NullCommand;
11649 id=XCommandWidget(display,windows,ApplyMenu,&event);
11652 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11653 command_type=ApplyCommands[id];
11654 if (id < ApplyMenus)
11657 Select a command from a pop-up menu.
11659 entry=XMenuWidget(display,windows,ApplyMenu[id],
11660 (const char **) Menus[id],command);
11663 (void) CopyMagickString(command,Menus[id][entry],
11665 command_type=Commands[id][entry];
11669 (void) XSetFunction(display,windows->image.highlight_context,
11671 XHighlightRectangle(display,windows->image.id,
11672 windows->image.highlight_context,&highlight_info);
11673 if (command_type == HelpCommand)
11675 (void) XSetFunction(display,windows->image.highlight_context,
11677 XTextViewWidget(display,resource_info,windows,MagickFalse,
11678 "Help Viewer - Region of Interest",ImageROIHelp);
11679 (void) XSetFunction(display,windows->image.highlight_context,
11683 if (command_type == QuitCommand)
11688 state|=EscapeState;
11692 if (command_type != NullCommand)
11693 state|=UpdateRegionState;
11696 XHighlightRectangle(display,windows->image.id,
11697 windows->image.highlight_context,&highlight_info);
11698 switch (event.type)
11702 x=windows->image.x;
11703 y=windows->image.y;
11704 if (event.xbutton.button != Button1)
11706 if (event.xbutton.window != windows->image.id)
11708 x=windows->image.x+event.xbutton.x;
11709 y=windows->image.y+event.xbutton.y;
11710 if ((x < (int) (roi_info.x+RoiDelta)) &&
11711 (x > (int) (roi_info.x-RoiDelta)) &&
11712 (y < (int) (roi_info.y+RoiDelta)) &&
11713 (y > (int) (roi_info.y-RoiDelta)))
11715 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11716 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11717 state|=UpdateConfigurationState;
11720 if ((x < (int) (roi_info.x+RoiDelta)) &&
11721 (x > (int) (roi_info.x-RoiDelta)) &&
11722 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11723 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11725 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11726 state|=UpdateConfigurationState;
11729 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11730 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11731 (y < (int) (roi_info.y+RoiDelta)) &&
11732 (y > (int) (roi_info.y-RoiDelta)))
11734 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11735 state|=UpdateConfigurationState;
11738 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11739 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11740 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11741 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11743 state|=UpdateConfigurationState;
11747 case ButtonRelease:
11749 if (event.xbutton.window == windows->pan.id)
11750 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11751 (highlight_info.y != crop_info.y-windows->image.y))
11752 XHighlightRectangle(display,windows->image.id,
11753 windows->image.highlight_context,&highlight_info);
11754 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11755 event.xbutton.time);
11760 if (event.xexpose.window == windows->image.id)
11761 if (event.xexpose.count == 0)
11763 event.xexpose.x=(int) highlight_info.x;
11764 event.xexpose.y=(int) highlight_info.y;
11765 event.xexpose.width=(int) highlight_info.width;
11766 event.xexpose.height=(int) highlight_info.height;
11767 XRefreshWindow(display,&windows->image,&event);
11769 if (event.xexpose.window == windows->info.id)
11770 if (event.xexpose.count == 0)
11771 XInfoWidget(display,windows,text);
11779 if (event.xkey.window != windows->image.id)
11782 Respond to a user key press.
11784 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11785 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11786 switch ((int) key_symbol)
11793 state|=EscapeState;
11802 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11803 roi_info.y=(ssize_t) (windows->image.height/2L-
11804 roi_info.height/2L);
11836 (void) XSetFunction(display,windows->image.highlight_context,
11838 XTextViewWidget(display,resource_info,windows,MagickFalse,
11839 "Help Viewer - Region of Interest",ImageROIHelp);
11840 (void) XSetFunction(display,windows->image.highlight_context,
11846 command_type=XImageWindowCommand(display,resource_info,windows,
11847 event.xkey.state,key_symbol,image,exception);
11848 if (command_type != NullCommand)
11849 state|=UpdateRegionState;
11853 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11861 if (event.xbutton.window != windows->image.id)
11864 Map and unmap Info widget as text cursor crosses its boundaries.
11868 if (windows->info.mapped != MagickFalse)
11870 if ((x < (int) (windows->info.x+windows->info.width)) &&
11871 (y < (int) (windows->info.y+windows->info.height)))
11872 (void) XWithdrawWindow(display,windows->info.id,
11873 windows->info.screen);
11876 if ((x > (int) (windows->info.x+windows->info.width)) ||
11877 (y > (int) (windows->info.y+windows->info.height)))
11878 (void) XMapWindow(display,windows->info.id);
11879 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11880 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11883 case SelectionRequest:
11888 XSelectionRequestEvent
11892 Set primary selection.
11894 (void) FormatLocaleString(text,MaxTextExtent,
11895 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11896 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11897 request=(&(event.xselectionrequest));
11898 (void) XChangeProperty(request->display,request->requestor,
11899 request->property,request->target,8,PropModeReplace,
11900 (unsigned char *) text,(int) strlen(text));
11901 notify.type=SelectionNotify;
11902 notify.display=request->display;
11903 notify.requestor=request->requestor;
11904 notify.selection=request->selection;
11905 notify.target=request->target;
11906 notify.time=request->time;
11907 if (request->property == None)
11908 notify.property=request->target;
11910 notify.property=request->property;
11911 (void) XSendEvent(request->display,request->requestor,False,0,
11912 (XEvent *) ¬ify);
11917 if ((state & UpdateConfigurationState) != 0)
11919 (void) XPutBackEvent(display,&event);
11920 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11923 } while ((state & ExitState) == 0);
11924 } while ((state & ExitState) == 0);
11925 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11926 XSetCursorState(display,windows,MagickFalse);
11927 if ((state & EscapeState) != 0)
11928 return(MagickTrue);
11929 return(MagickTrue);
11933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11937 + X R o t a t e I m a g e %
11941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11943 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11944 % rotation angle is computed from the slope of a line drawn by the user.
11946 % The format of the XRotateImage method is:
11948 % MagickBooleanType XRotateImage(Display *display,
11949 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11950 % Image **image,ExceptionInfo *exception)
11952 % A description of each parameter follows:
11954 % o display: Specifies a connection to an X server; returned from
11957 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11959 % o windows: Specifies a pointer to a XWindows structure.
11961 % o degrees: Specifies the number of degrees to rotate the image.
11963 % o image: the image.
11965 % o exception: return any errors or warnings in this structure.
11968 static MagickBooleanType XRotateImage(Display *display,
11969 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
11970 ExceptionInfo *exception)
11983 direction = HorizontalRotateCommand;
11985 static const ModeType
11986 DirectionCommands[] =
11988 HorizontalRotateCommand,
11989 VerticalRotateCommand
11993 RotateColorCommand,
11994 RotateDirectionCommand,
11996 RotateDismissCommand
11999 static unsigned int
12003 command[MaxTextExtent],
12004 text[MaxTextExtent];
12015 normalized_degrees;
12025 if (degrees == 0.0)
12040 Map Command widget.
12042 (void) CloneString(&windows->command.name,"Rotate");
12043 windows->command.data=2;
12044 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12045 (void) XMapRaised(display,windows->command.id);
12046 XClientMessage(display,windows->image.id,windows->im_protocols,
12047 windows->im_update_widget,CurrentTime);
12049 Wait for first button press.
12051 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12052 XQueryPosition(display,windows->image.id,&x,&y);
12057 state=DefaultState;
12060 XHighlightLine(display,windows->image.id,
12061 windows->image.highlight_context,&rotate_info);
12063 Wait for next event.
12065 XScreenEvent(display,windows,&event);
12066 XHighlightLine(display,windows->image.id,
12067 windows->image.highlight_context,&rotate_info);
12068 if (event.xany.window == windows->command.id)
12071 Select a command from the Command widget.
12073 id=XCommandWidget(display,windows,RotateMenu,&event);
12076 (void) XSetFunction(display,windows->image.highlight_context,
12078 switch (RotateCommands[id])
12080 case RotateColorCommand:
12083 *ColorMenu[MaxNumberPens];
12092 Initialize menu selections.
12094 for (i=0; i < (int) (MaxNumberPens-2); i++)
12095 ColorMenu[i]=resource_info->pen_colors[i];
12096 ColorMenu[MaxNumberPens-2]="Browser...";
12097 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12099 Select a pen color from the pop-up menu.
12101 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12102 (const char **) ColorMenu,command);
12103 if (pen_number < 0)
12105 if (pen_number == (MaxNumberPens-2))
12108 color_name[MaxTextExtent] = "gray";
12111 Select a pen color from a dialog.
12113 resource_info->pen_colors[pen_number]=color_name;
12114 XColorBrowserWidget(display,windows,"Select",color_name);
12115 if (*color_name == '\0')
12121 (void) XParseColor(display,windows->map_info->colormap,
12122 resource_info->pen_colors[pen_number],&color);
12123 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12124 (unsigned int) MaxColors,&color);
12125 windows->pixel_info->pen_colors[pen_number]=color;
12126 pen_id=(unsigned int) pen_number;
12129 case RotateDirectionCommand:
12140 Select a command from the pop-up menu.
12142 id=XMenuWidget(display,windows,RotateMenu[id],
12143 Directions,command);
12145 direction=DirectionCommands[id];
12148 case RotateHelpCommand:
12150 XTextViewWidget(display,resource_info,windows,MagickFalse,
12151 "Help Viewer - Image Rotation",ImageRotateHelp);
12154 case RotateDismissCommand:
12159 state|=EscapeState;
12166 (void) XSetFunction(display,windows->image.highlight_context,
12170 switch (event.type)
12174 if (event.xbutton.button != Button1)
12176 if (event.xbutton.window != windows->image.id)
12181 (void) XSetFunction(display,windows->image.highlight_context,
12183 rotate_info.x1=event.xbutton.x;
12184 rotate_info.y1=event.xbutton.y;
12188 case ButtonRelease:
12195 command[MaxTextExtent];
12200 if (event.xkey.window != windows->image.id)
12203 Respond to a user key press.
12205 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12206 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12207 switch ((int) key_symbol)
12215 state|=EscapeState;
12222 (void) XSetFunction(display,windows->image.highlight_context,
12224 XTextViewWidget(display,resource_info,windows,MagickFalse,
12225 "Help Viewer - Image Rotation",ImageRotateHelp);
12226 (void) XSetFunction(display,windows->image.highlight_context,
12232 (void) XBell(display,0);
12240 rotate_info.x1=event.xmotion.x;
12241 rotate_info.y1=event.xmotion.y;
12244 rotate_info.x2=rotate_info.x1;
12245 rotate_info.y2=rotate_info.y1;
12246 if (direction == HorizontalRotateCommand)
12247 rotate_info.x2+=32;
12249 rotate_info.y2-=32;
12250 } while ((state & ExitState) == 0);
12251 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12252 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12253 if ((state & EscapeState) != 0)
12254 return(MagickTrue);
12256 Draw line as pointer moves until the mouse button is released.
12259 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12260 state=DefaultState;
12266 Display info and draw rotation line.
12268 if (windows->info.mapped == MagickFalse)
12269 (void) XMapWindow(display,windows->info.id);
12270 (void) FormatLocaleString(text,MaxTextExtent," %g",
12271 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12272 XInfoWidget(display,windows,text);
12273 XHighlightLine(display,windows->image.id,
12274 windows->image.highlight_context,&rotate_info);
12277 if (windows->info.mapped != MagickFalse)
12278 (void) XWithdrawWindow(display,windows->info.id,
12279 windows->info.screen);
12281 Wait for next event.
12283 XScreenEvent(display,windows,&event);
12285 XHighlightLine(display,windows->image.id,
12286 windows->image.highlight_context,&rotate_info);
12287 switch (event.type)
12291 case ButtonRelease:
12294 User has committed to rotation line.
12296 rotate_info.x2=event.xbutton.x;
12297 rotate_info.y2=event.xbutton.y;
12305 rotate_info.x2=event.xmotion.x;
12306 rotate_info.y2=event.xmotion.y;
12312 Check boundary conditions.
12314 if (rotate_info.x2 < 0)
12317 if (rotate_info.x2 > (int) windows->image.width)
12318 rotate_info.x2=(short) windows->image.width;
12319 if (rotate_info.y2 < 0)
12322 if (rotate_info.y2 > (int) windows->image.height)
12323 rotate_info.y2=(short) windows->image.height;
12325 Compute rotation angle from the slope of the line.
12328 distance=(unsigned int)
12329 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12330 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12332 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12333 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12334 } while ((state & ExitState) == 0);
12335 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12336 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12338 return(MagickTrue);
12340 if (direction == VerticalRotateCommand)
12342 if (degrees == 0.0)
12343 return(MagickTrue);
12347 normalized_degrees=degrees;
12348 while (normalized_degrees < -45.0)
12349 normalized_degrees+=360.0;
12350 for (rotations=0; normalized_degrees > 45.0; rotations++)
12351 normalized_degrees-=90.0;
12352 if (normalized_degrees != 0.0)
12353 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12355 XSetCursorState(display,windows,MagickTrue);
12356 XCheckRefreshWindows(display,windows);
12357 (*image)->background_color.red=ScaleShortToQuantum(
12358 windows->pixel_info->pen_colors[pen_id].red);
12359 (*image)->background_color.green=ScaleShortToQuantum(
12360 windows->pixel_info->pen_colors[pen_id].green);
12361 (*image)->background_color.blue=ScaleShortToQuantum(
12362 windows->pixel_info->pen_colors[pen_id].blue);
12363 rotate_image=RotateImage(*image,degrees,exception);
12364 XSetCursorState(display,windows,MagickFalse);
12365 if (rotate_image == (Image *) NULL)
12366 return(MagickFalse);
12367 *image=DestroyImage(*image);
12368 *image=rotate_image;
12369 if (windows->image.crop_geometry != (char *) NULL)
12372 Rotate crop geometry.
12374 width=(unsigned int) (*image)->columns;
12375 height=(unsigned int) (*image)->rows;
12376 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12377 switch (rotations % 4)
12387 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12388 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12395 Rotate 180 degrees.
12397 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12398 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12404 Rotate 270 degrees.
12406 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12407 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12412 if (windows->image.orphan != MagickFalse)
12413 return(MagickTrue);
12414 if (normalized_degrees != 0.0)
12417 Update image colormap.
12419 windows->image.window_changes.width=(int) (*image)->columns;
12420 windows->image.window_changes.height=(int) (*image)->rows;
12421 if (windows->image.crop_geometry != (char *) NULL)
12424 Obtain dimensions of image from crop geometry.
12426 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12428 windows->image.window_changes.width=(int) width;
12429 windows->image.window_changes.height=(int) height;
12431 XConfigureImageColormap(display,resource_info,windows,*image);
12434 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12436 windows->image.window_changes.width=windows->image.ximage->height;
12437 windows->image.window_changes.height=windows->image.ximage->width;
12440 Update image configuration.
12442 (void) XConfigureImage(display,resource_info,windows,*image,exception);
12443 return(MagickTrue);
12447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12451 + X S a v e I m a g e %
12455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12457 % XSaveImage() saves an image to a file.
12459 % The format of the XSaveImage method is:
12461 % MagickBooleanType XSaveImage(Display *display,
12462 % XResourceInfo *resource_info,XWindows *windows,Image *image,
12463 % ExceptionInfo *exception)
12465 % A description of each parameter follows:
12467 % o display: Specifies a connection to an X server; returned from
12470 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12472 % o windows: Specifies a pointer to a XWindows structure.
12474 % o image: the image.
12476 % o exception: return any errors or warnings in this structure.
12479 static MagickBooleanType XSaveImage(Display *display,
12480 XResourceInfo *resource_info,XWindows *windows,Image *image,
12481 ExceptionInfo *exception)
12484 filename[MaxTextExtent],
12485 geometry[MaxTextExtent];
12497 Request file name from user.
12499 if (resource_info->write_filename != (char *) NULL)
12500 (void) CopyMagickString(filename,resource_info->write_filename,
12505 path[MaxTextExtent];
12510 GetPathComponent(image->filename,HeadPath,path);
12511 GetPathComponent(image->filename,TailPath,filename);
12514 status=chdir(path);
12516 (void) ThrowMagickException(exception,GetMagickModule(),
12517 FileOpenError,"UnableToOpenFile","%s",path);
12520 XFileBrowserWidget(display,windows,"Save",filename);
12521 if (*filename == '\0')
12522 return(MagickTrue);
12523 if (IsPathAccessible(filename) != MagickFalse)
12529 File exists-- seek user's permission before overwriting.
12531 status=XConfirmWidget(display,windows,"Overwrite",filename);
12533 return(MagickTrue);
12535 image_info=CloneImageInfo(resource_info->image_info);
12536 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12537 (void) SetImageInfo(image_info,1,exception);
12538 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12539 (LocaleCompare(image_info->magick,"JPG") == 0))
12542 quality[MaxTextExtent];
12548 Request JPEG quality from user.
12550 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
12552 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12554 if (*quality == '\0')
12555 return(MagickTrue);
12556 image->quality=StringToUnsignedLong(quality);
12557 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12559 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12560 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12561 (LocaleCompare(image_info->magick,"PS") == 0) ||
12562 (LocaleCompare(image_info->magick,"PS2") == 0))
12565 geometry[MaxTextExtent];
12568 Request page geometry from user.
12570 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12571 if (LocaleCompare(image_info->magick,"PDF") == 0)
12572 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12573 if (image_info->page != (char *) NULL)
12574 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12575 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12576 "Select page geometry:",geometry);
12577 if (*geometry != '\0')
12578 image_info->page=GetPageGeometry(geometry);
12581 Apply image transforms.
12583 XSetCursorState(display,windows,MagickTrue);
12584 XCheckRefreshWindows(display,windows);
12585 save_image=CloneImage(image,0,0,MagickTrue,exception);
12586 if (save_image == (Image *) NULL)
12587 return(MagickFalse);
12588 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
12589 windows->image.ximage->width,windows->image.ximage->height);
12590 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12594 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12595 status=WriteImage(image_info,save_image,exception);
12596 if (status != MagickFalse)
12597 image->taint=MagickFalse;
12598 save_image=DestroyImage(save_image);
12599 image_info=DestroyImageInfo(image_info);
12600 XSetCursorState(display,windows,MagickFalse);
12601 return(status != 0 ? MagickTrue : MagickFalse);
12605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12609 + X S c r e e n E v e n t %
12613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12615 % XScreenEvent() handles global events associated with the Pan and Magnify
12618 % The format of the XScreenEvent function is:
12620 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12622 % A description of each parameter follows:
12624 % o display: Specifies a pointer to the Display structure; returned from
12627 % o windows: Specifies a pointer to a XWindows structure.
12629 % o event: Specifies a pointer to a X11 XEvent structure.
12634 #if defined(__cplusplus) || defined(c_plusplus)
12638 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12643 windows=(XWindows *) data;
12644 if ((event->type == ClientMessage) &&
12645 (event->xclient.window == windows->image.id))
12646 return(MagickFalse);
12647 return(MagickTrue);
12650 #if defined(__cplusplus) || defined(c_plusplus)
12654 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12660 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12661 if (event->xany.window == windows->command.id)
12663 switch (event->type)
12666 case ButtonRelease:
12668 if ((event->xbutton.button == Button3) &&
12669 (event->xbutton.state & Mod1Mask))
12672 Convert Alt-Button3 to Button2.
12674 event->xbutton.button=Button2;
12675 event->xbutton.state&=(~Mod1Mask);
12677 if (event->xbutton.window == windows->backdrop.id)
12679 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12680 event->xbutton.time);
12683 if (event->xbutton.window == windows->pan.id)
12685 XPanImage(display,windows,event);
12688 if (event->xbutton.window == windows->image.id)
12689 if (event->xbutton.button == Button2)
12692 Update magnified image.
12694 x=event->xbutton.x;
12695 y=event->xbutton.y;
12699 if (x >= (int) windows->image.width)
12700 x=(int) (windows->image.width-1);
12701 windows->magnify.x=(int) windows->image.x+x;
12705 if (y >= (int) windows->image.height)
12706 y=(int) (windows->image.height-1);
12707 windows->magnify.y=windows->image.y+y;
12708 if (windows->magnify.mapped == MagickFalse)
12709 (void) XMapRaised(display,windows->magnify.id);
12710 XMakeMagnifyImage(display,windows);
12711 if (event->type == ButtonRelease)
12712 (void) XWithdrawWindow(display,windows->info.id,
12713 windows->info.screen);
12718 case ClientMessage:
12721 If client window delete message, exit.
12723 if (event->xclient.message_type != windows->wm_protocols)
12725 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12727 if (event->xclient.window == windows->magnify.id)
12729 (void) XWithdrawWindow(display,windows->magnify.id,
12730 windows->magnify.screen);
12735 case ConfigureNotify:
12737 if (event->xconfigure.window == windows->magnify.id)
12743 Magnify window has a new configuration.
12745 windows->magnify.width=(unsigned int) event->xconfigure.width;
12746 windows->magnify.height=(unsigned int) event->xconfigure.height;
12747 if (windows->magnify.mapped == MagickFalse)
12750 while ((int) magnify <= event->xconfigure.width)
12752 while ((int) magnify <= event->xconfigure.height)
12755 if (((int) magnify != event->xconfigure.width) ||
12756 ((int) magnify != event->xconfigure.height))
12761 window_changes.width=(int) magnify;
12762 window_changes.height=(int) magnify;
12763 (void) XReconfigureWMWindow(display,windows->magnify.id,
12764 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12768 XMakeMagnifyImage(display,windows);
12775 if (event->xexpose.window == windows->image.id)
12777 XRefreshWindow(display,&windows->image,event);
12780 if (event->xexpose.window == windows->pan.id)
12781 if (event->xexpose.count == 0)
12783 XDrawPanRectangle(display,windows);
12786 if (event->xexpose.window == windows->magnify.id)
12787 if (event->xexpose.count == 0)
12789 XMakeMagnifyImage(display,windows);
12797 command[MaxTextExtent];
12802 if (event->xkey.window != windows->magnify.id)
12805 Respond to a user key press.
12807 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12808 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12809 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12814 if (event->xmap.window == windows->magnify.id)
12816 windows->magnify.mapped=MagickTrue;
12817 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12820 if (event->xmap.window == windows->info.id)
12822 windows->info.mapped=MagickTrue;
12829 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12830 if (event->xmotion.window == windows->image.id)
12831 if (windows->magnify.mapped != MagickFalse)
12834 Update magnified image.
12836 x=event->xmotion.x;
12837 y=event->xmotion.y;
12841 if (x >= (int) windows->image.width)
12842 x=(int) (windows->image.width-1);
12843 windows->magnify.x=(int) windows->image.x+x;
12847 if (y >= (int) windows->image.height)
12848 y=(int) (windows->image.height-1);
12849 windows->magnify.y=windows->image.y+y;
12850 XMakeMagnifyImage(display,windows);
12856 if (event->xunmap.window == windows->magnify.id)
12858 windows->magnify.mapped=MagickFalse;
12861 if (event->xunmap.window == windows->info.id)
12863 windows->info.mapped=MagickFalse;
12874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12878 + X S e t C r o p G e o m e t r y %
12882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12884 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12885 % and translates it to a cropping geometry relative to the image.
12887 % The format of the XSetCropGeometry method is:
12889 % void XSetCropGeometry(Display *display,XWindows *windows,
12890 % RectangleInfo *crop_info,Image *image)
12892 % A description of each parameter follows:
12894 % o display: Specifies a connection to an X server; returned from
12897 % o windows: Specifies a pointer to a XWindows structure.
12899 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12900 % Image window to crop.
12902 % o image: the image.
12905 static void XSetCropGeometry(Display *display,XWindows *windows,
12906 RectangleInfo *crop_info,Image *image)
12909 text[MaxTextExtent];
12922 if (windows->info.mapped != MagickFalse)
12925 Display info on cropping rectangle.
12927 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12928 (double) crop_info->width,(double) crop_info->height,(double)
12929 crop_info->x,(double) crop_info->y);
12930 XInfoWidget(display,windows,text);
12933 Cropping geometry is relative to any previous crop geometry.
12937 width=(unsigned int) image->columns;
12938 height=(unsigned int) image->rows;
12939 if (windows->image.crop_geometry != (char *) NULL)
12940 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12942 windows->image.crop_geometry=AcquireString((char *) NULL);
12944 Define the crop geometry string from the cropping rectangle.
12946 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12947 if (crop_info->x > 0)
12948 x+=(int) (scale_factor*crop_info->x+0.5);
12949 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12952 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12953 if (crop_info->y > 0)
12954 y+=(int) (scale_factor*crop_info->y+0.5);
12955 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12958 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12959 "%ux%u%+d%+d",width,height,x,y);
12963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12967 + X T i l e I m a g e %
12971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12973 % XTileImage() loads or deletes a selected tile from a visual image directory.
12974 % The load or delete command is chosen from a menu.
12976 % The format of the XTileImage method is:
12978 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
12979 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
12981 % A description of each parameter follows:
12983 % o tile_image: XTileImage reads or deletes the tile image
12984 % and returns it. A null image is returned if an error occurs.
12986 % o display: Specifies a connection to an X server; returned from
12989 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12991 % o windows: Specifies a pointer to a XWindows structure.
12993 % o image: the image; returned from ReadImage.
12995 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
12996 % the entire image is refreshed.
12998 % o exception: return any errors or warnings in this structure.
13001 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
13002 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13015 static const ModeType
13026 command[MaxTextExtent],
13027 filename[MaxTextExtent];
13054 Tile image is relative to montage image configuration.
13058 width=(unsigned int) image->columns;
13059 height=(unsigned int) image->rows;
13060 if (windows->image.crop_geometry != (char *) NULL)
13061 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13062 scale_factor=(MagickRealType) width/windows->image.ximage->width;
13063 event->xbutton.x+=windows->image.x;
13064 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13065 scale_factor=(MagickRealType) height/windows->image.ximage->height;
13066 event->xbutton.y+=windows->image.y;
13067 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13069 Determine size and location of each tile in the visual image directory.
13071 width=(unsigned int) image->columns;
13072 height=(unsigned int) image->rows;
13075 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13076 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13077 (event->xbutton.x-x)/width;
13081 Button press is outside any tile.
13083 (void) XBell(display,0);
13084 return((Image *) NULL);
13087 Determine file name from the tile directory.
13089 p=image->directory;
13090 for (i=tile; (i != 0) && (*p != '\0'); )
13099 Button press is outside any tile.
13101 (void) XBell(display,0);
13102 return((Image *) NULL);
13105 Select a command from the pop-up menu.
13107 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13109 return((Image *) NULL);
13111 while ((*q != '\n') && (*q != '\0'))
13113 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13115 Perform command for the selected tile.
13117 XSetCursorState(display,windows,MagickTrue);
13118 XCheckRefreshWindows(display,windows);
13119 tile_image=NewImageList();
13120 switch (TileCommands[id])
13122 case TileLoadCommand:
13127 XCheckRefreshWindows(display,windows);
13128 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13130 (void) CopyMagickString(resource_info->image_info->filename,filename,
13132 tile_image=ReadImage(resource_info->image_info,exception);
13133 CatchException(exception);
13134 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13137 case TileNextCommand:
13140 Display next image.
13142 XClientMessage(display,windows->image.id,windows->im_protocols,
13143 windows->im_next_image,CurrentTime);
13146 case TileFormerCommand:
13149 Display former image.
13151 XClientMessage(display,windows->image.id,windows->im_protocols,
13152 windows->im_former_image,CurrentTime);
13155 case TileDeleteCommand:
13160 if (IsPathAccessible(filename) == MagickFalse)
13162 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13165 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13168 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13169 if (status != MagickFalse)
13171 XNoticeWidget(display,windows,"Unable to delete image file:",
13176 case TileUpdateCommand:
13192 Ensure all the images exist.
13195 for (p=image->directory; *p != '\0'; p++)
13201 while ((*q != '\n') && (*q != '\0'))
13203 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13205 if (IsPathAccessible(filename) != MagickFalse)
13211 Overwrite tile with background color.
13213 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13214 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13215 image_view=AcquireCacheView(image);
13216 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13217 for (i=0; i < (int) height; i++)
13219 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13220 y_offset+i,width,1,exception);
13221 if (s == (Quantum *) NULL)
13223 for (j=0; j < (int) width; j++)
13225 SetPixelPacket(image,&pixel,s);
13226 s+=GetPixelChannels(image);
13228 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13231 image_view=DestroyCacheView(image_view);
13234 windows->image.window_changes.width=(int) image->columns;
13235 windows->image.window_changes.height=(int) image->rows;
13236 XConfigureImageColormap(display,resource_info,windows,image);
13237 (void) XConfigureImage(display,resource_info,windows,image,exception);
13243 XSetCursorState(display,windows,MagickFalse);
13244 return(tile_image);
13248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13252 + X T r a n s l a t e I m a g e %
13256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13258 % XTranslateImage() translates the image within an Image window by one pixel
13259 % as specified by the key symbol. If the image has a `montage string the
13260 % translation is respect to the width and height contained within the string.
13262 % The format of the XTranslateImage method is:
13264 % void XTranslateImage(Display *display,XWindows *windows,
13265 % Image *image,const KeySym key_symbol)
13267 % A description of each parameter follows:
13269 % o display: Specifies a connection to an X server; returned from
13272 % o windows: Specifies a pointer to a XWindows structure.
13274 % o image: the image.
13276 % o key_symbol: Specifies a KeySym which indicates which side of the image
13280 static void XTranslateImage(Display *display,XWindows *windows,
13281 Image *image,const KeySym key_symbol)
13284 text[MaxTextExtent];
13295 User specified a pan position offset.
13297 x_offset=windows->image.width;
13298 y_offset=windows->image.height;
13299 if (image->montage != (char *) NULL)
13300 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13301 switch ((int) key_symbol)
13306 windows->image.x=(int) windows->image.width/2;
13307 windows->image.y=(int) windows->image.height/2;
13313 windows->image.x-=x_offset;
13320 windows->image.y-=y_offset;
13326 windows->image.x+=x_offset;
13333 windows->image.y+=y_offset;
13340 Check boundary conditions.
13342 if (windows->image.x < 0)
13343 windows->image.x=0;
13345 if ((int) (windows->image.x+windows->image.width) >
13346 windows->image.ximage->width)
13347 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13348 if (windows->image.y < 0)
13349 windows->image.y=0;
13351 if ((int) (windows->image.y+windows->image.height) >
13352 windows->image.ximage->height)
13353 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13355 Refresh Image window.
13357 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
13358 windows->image.width,windows->image.height,windows->image.x,
13360 XInfoWidget(display,windows,text);
13361 XCheckRefreshWindows(display,windows);
13362 XDrawPanRectangle(display,windows);
13363 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13364 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13372 + X T r i m I m a g e %
13376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13378 % XTrimImage() trims the edges from the Image window.
13380 % The format of the XTrimImage method is:
13382 % MagickBooleanType XTrimImage(Display *display,
13383 % XResourceInfo *resource_info,XWindows *windows,Image *image,
13384 % ExceptionInfo *exception)
13386 % A description of each parameter follows:
13388 % o display: Specifies a connection to an X server; returned from
13391 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13393 % o windows: Specifies a pointer to a XWindows structure.
13395 % o image: the image.
13397 % o exception: return any errors or warnings in this structure.
13400 static MagickBooleanType XTrimImage(Display *display,
13401 XResourceInfo *resource_info,XWindows *windows,Image *image,
13402 ExceptionInfo *exception)
13416 Trim edges from image.
13418 XSetCursorState(display,windows,MagickTrue);
13419 XCheckRefreshWindows(display,windows);
13421 Crop the left edge.
13423 background=XGetPixel(windows->image.ximage,0,0);
13424 trim_info.width=(size_t) windows->image.ximage->width;
13425 for (x=0; x < windows->image.ximage->width; x++)
13427 for (y=0; y < windows->image.ximage->height; y++)
13429 pixel=XGetPixel(windows->image.ximage,x,y);
13430 if (pixel != background)
13433 if (y < windows->image.ximage->height)
13436 trim_info.x=(ssize_t) x;
13437 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13439 XSetCursorState(display,windows,MagickFalse);
13440 return(MagickFalse);
13443 Crop the right edge.
13445 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13446 for (x=windows->image.ximage->width-1; x != 0; x--)
13448 for (y=0; y < windows->image.ximage->height; y++)
13450 pixel=XGetPixel(windows->image.ximage,x,y);
13451 if (pixel != background)
13454 if (y < windows->image.ximage->height)
13457 trim_info.width=(size_t) (x-trim_info.x+1);
13461 background=XGetPixel(windows->image.ximage,0,0);
13462 trim_info.height=(size_t) windows->image.ximage->height;
13463 for (y=0; y < windows->image.ximage->height; y++)
13465 for (x=0; x < windows->image.ximage->width; x++)
13467 pixel=XGetPixel(windows->image.ximage,x,y);
13468 if (pixel != background)
13471 if (x < windows->image.ximage->width)
13474 trim_info.y=(ssize_t) y;
13476 Crop the bottom edge.
13478 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13479 for (y=windows->image.ximage->height-1; y != 0; y--)
13481 for (x=0; x < windows->image.ximage->width; x++)
13483 pixel=XGetPixel(windows->image.ximage,x,y);
13484 if (pixel != background)
13487 if (x < windows->image.ximage->width)
13490 trim_info.height=(size_t) y-trim_info.y+1;
13491 if (((unsigned int) trim_info.width != windows->image.width) ||
13492 ((unsigned int) trim_info.height != windows->image.height))
13495 Reconfigure Image window as defined by the trimming rectangle.
13497 XSetCropGeometry(display,windows,&trim_info,image);
13498 windows->image.window_changes.width=(int) trim_info.width;
13499 windows->image.window_changes.height=(int) trim_info.height;
13500 (void) XConfigureImage(display,resource_info,windows,image,exception);
13502 XSetCursorState(display,windows,MagickFalse);
13503 return(MagickTrue);
13507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13511 + X V i s u a l D i r e c t o r y I m a g e %
13515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13517 % XVisualDirectoryImage() creates a Visual Image Directory.
13519 % The format of the XVisualDirectoryImage method is:
13521 % Image *XVisualDirectoryImage(Display *display,
13522 % XResourceInfo *resource_info,XWindows *windows,
13523 % ExceptionInfo *exception)
13525 % A description of each parameter follows:
13527 % o display: Specifies a connection to an X server; returned from
13530 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13532 % o windows: Specifies a pointer to a XWindows structure.
13534 % o exception: return any errors or warnings in this structure.
13537 static Image *XVisualDirectoryImage(Display *display,
13538 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
13540 #define TileImageTag "Scale/Image"
13541 #define XClientName "montage"
13574 filename[MaxTextExtent] = "\0",
13575 filenames[MaxTextExtent] = "*";
13578 background_resources;
13581 Request file name from user.
13583 XFileBrowserWidget(display,windows,"Directory",filenames);
13584 if (*filenames == '\0')
13585 return((Image *) NULL);
13587 Expand the filenames.
13589 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13590 if (filelist == (char **) NULL)
13592 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13594 return((Image *) NULL);
13597 filelist[0]=filenames;
13598 status=ExpandFilenames(&number_files,&filelist);
13599 if ((status == MagickFalse) || (number_files == 0))
13601 if (number_files == 0)
13602 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13604 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13606 return((Image *) NULL);
13609 Set image background resources.
13611 background_resources=(*resource_info);
13612 background_resources.window_id=AcquireString("");
13613 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
13614 "0x%lx",windows->image.id);
13615 background_resources.backdrop=MagickTrue;
13617 Read each image and convert them to a tile.
13619 backdrop=(windows->visual_info->klass == TrueColor) ||
13620 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13621 read_info=CloneImageInfo(resource_info->image_info);
13622 (void) SetImageOption(read_info,"jpeg:size","120x120");
13623 (void) CloneString(&read_info->size,DefaultTileGeometry);
13624 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13626 images=NewImageList();
13627 XSetCursorState(display,windows,MagickTrue);
13628 XCheckRefreshWindows(display,windows);
13629 for (i=0; i < (int) number_files; i++)
13631 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13632 filelist[i]=DestroyString(filelist[i]);
13633 *read_info->magick='\0';
13634 next_image=ReadImage(read_info,exception);
13635 CatchException(exception);
13636 if (next_image != (Image *) NULL)
13638 (void) DeleteImageProperty(next_image,"label");
13639 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13640 read_info,next_image,DefaultTileLabel));
13641 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13643 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13644 geometry.height,exception);
13645 if (thumbnail_image != (Image *) NULL)
13647 next_image=DestroyImage(next_image);
13648 next_image=thumbnail_image;
13652 (void) XDisplayBackgroundImage(display,&background_resources,
13653 next_image,exception);
13654 XSetCursorState(display,windows,MagickTrue);
13656 AppendImageToList(&images,next_image);
13657 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13662 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13663 (MagickSizeType) number_files);
13664 if (proceed == MagickFalse)
13669 filelist=(char **) RelinquishMagickMemory(filelist);
13670 if (images == (Image *) NULL)
13672 read_info=DestroyImageInfo(read_info);
13673 XSetCursorState(display,windows,MagickFalse);
13674 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13675 return((Image *) NULL);
13678 Create the Visual Image Directory.
13680 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13681 montage_info->pointsize=10;
13682 if (resource_info->font != (char *) NULL)
13683 (void) CloneString(&montage_info->font,resource_info->font);
13684 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13685 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13686 images),exception);
13687 images=DestroyImageList(images);
13688 montage_info=DestroyMontageInfo(montage_info);
13689 read_info=DestroyImageInfo(read_info);
13690 XSetCursorState(display,windows,MagickFalse);
13691 if (montage_image == (Image *) NULL)
13692 return(montage_image);
13693 XClientMessage(display,windows->image.id,windows->im_protocols,
13694 windows->im_next_image,CurrentTime);
13695 return(montage_image);
13699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13703 % X D i s p l a y B a c k g r o u n d I m a g e %
13707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13709 % XDisplayBackgroundImage() displays an image in the background of a window.
13711 % The format of the XDisplayBackgroundImage method is:
13713 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13714 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13716 % A description of each parameter follows:
13718 % o display: Specifies a connection to an X server; returned from
13721 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13723 % o image: the image.
13725 % o exception: return any errors or warnings in this structure.
13728 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13729 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13732 geometry[MaxTextExtent],
13733 visual_type[MaxTextExtent];
13746 static XStandardColormap
13750 *visual_info = (XVisualInfo *) NULL;
13771 Determine target window.
13773 assert(image != (Image *) NULL);
13774 assert(image->signature == MagickSignature);
13775 if (image->debug != MagickFalse)
13776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13777 resources=(*resource_info);
13778 window_info.id=(Window) NULL;
13779 root_window=XRootWindow(display,XDefaultScreen(display));
13780 if (LocaleCompare(resources.window_id,"root") == 0)
13781 window_info.id=root_window;
13784 if (isdigit((unsigned char) *resources.window_id) != 0)
13785 window_info.id=XWindowByID(display,root_window,
13786 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13787 if (window_info.id == (Window) NULL)
13788 window_info.id=XWindowByName(display,root_window,resources.window_id);
13790 if (window_info.id == (Window) NULL)
13792 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13793 resources.window_id);
13794 return(MagickFalse);
13797 Determine window visual id.
13799 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13800 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13801 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13802 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13804 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
13805 XVisualIDFromVisual(window_attributes.visual));
13806 if (visual_info == (XVisualInfo *) NULL)
13809 Allocate standard colormap.
13811 map_info=XAllocStandardColormap();
13812 if (map_info == (XStandardColormap *) NULL)
13813 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13815 map_info->colormap=(Colormap) NULL;
13816 pixel.pixels=(unsigned long *) NULL;
13818 Initialize visual info.
13820 resources.map_type=(char *) NULL;
13821 resources.visual_type=visual_type;
13822 visual_info=XBestVisualInfo(display,map_info,&resources);
13823 if (visual_info == (XVisualInfo *) NULL)
13824 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13825 resources.visual_type);
13827 Initialize window info.
13829 window_info.ximage=(XImage *) NULL;
13830 window_info.matte_image=(XImage *) NULL;
13831 window_info.pixmap=(Pixmap) NULL;
13832 window_info.matte_pixmap=(Pixmap) NULL;
13835 Free previous root colors.
13837 if (window_info.id == root_window)
13838 (void) XDestroyWindowColors(display,root_window);
13840 Initialize Standard Colormap.
13842 resources.colormap=SharedColormap;
13843 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13845 Graphic context superclass.
13847 context_values.background=pixel.background_color.pixel;
13848 context_values.foreground=pixel.foreground_color.pixel;
13849 pixel.annotate_context=XCreateGC(display,window_info.id,
13850 (size_t) (GCBackground | GCForeground),&context_values);
13851 if (pixel.annotate_context == (GC) NULL)
13852 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13855 Initialize Image window attributes.
13857 window_info.name=AcquireString("\0");
13858 window_info.icon_name=AcquireString("\0");
13859 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13860 &resources,&window_info);
13862 Create the X image.
13864 window_info.width=(unsigned int) image->columns;
13865 window_info.height=(unsigned int) image->rows;
13866 if ((image->columns != window_info.width) ||
13867 (image->rows != window_info.height))
13868 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13870 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
13871 window_attributes.width,window_attributes.height);
13872 geometry_info.width=window_info.width;
13873 geometry_info.height=window_info.height;
13874 geometry_info.x=(ssize_t) window_info.x;
13875 geometry_info.y=(ssize_t) window_info.y;
13876 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13877 &geometry_info.width,&geometry_info.height);
13878 window_info.width=(unsigned int) geometry_info.width;
13879 window_info.height=(unsigned int) geometry_info.height;
13880 window_info.x=(int) geometry_info.x;
13881 window_info.y=(int) geometry_info.y;
13882 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13883 window_info.height,exception);
13884 if (status == MagickFalse)
13885 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13889 if (image->debug != MagickFalse)
13891 (void) LogMagickEvent(X11Event,GetMagickModule(),
13892 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13893 (double) image->columns,(double) image->rows);
13894 if (image->colors != 0)
13895 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13897 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13900 Adjust image dimensions as specified by backdrop or geometry options.
13902 width=(int) window_info.width;
13903 height=(int) window_info.height;
13904 if (resources.backdrop != MagickFalse)
13907 Center image on window.
13909 window_info.x=(window_attributes.width/2)-
13910 (window_info.ximage->width/2);
13911 window_info.y=(window_attributes.height/2)-
13912 (window_info.ximage->height/2);
13913 width=window_attributes.width;
13914 height=window_attributes.height;
13916 if ((resources.image_geometry != (char *) NULL) &&
13917 (*resources.image_geometry != '\0'))
13920 default_geometry[MaxTextExtent];
13930 User specified geometry.
13932 size_hints=XAllocSizeHints();
13933 if (size_hints == (XSizeHints *) NULL)
13934 ThrowXWindowFatalException(ResourceLimitFatalError,
13935 "MemoryAllocationFailed",image->filename);
13936 size_hints->flags=0L;
13937 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
13939 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13940 default_geometry,window_info.border_width,size_hints,&window_info.x,
13941 &window_info.y,&width,&height,&gravity);
13942 if (flags & (XValue | YValue))
13944 width=window_attributes.width;
13945 height=window_attributes.height;
13947 (void) XFree((void *) size_hints);
13950 Create the X pixmap.
13952 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13953 (unsigned int) height,window_info.depth);
13954 if (window_info.pixmap == (Pixmap) NULL)
13955 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13958 Display pixmap on the window.
13960 if (((unsigned int) width > window_info.width) ||
13961 ((unsigned int) height > window_info.height))
13962 (void) XFillRectangle(display,window_info.pixmap,
13963 window_info.annotate_context,0,0,(unsigned int) width,
13964 (unsigned int) height);
13965 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13966 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13967 window_info.width,(unsigned int) window_info.height);
13968 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13969 (void) XClearWindow(display,window_info.id);
13970 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13971 XDelay(display,delay == 0UL ? 10UL : delay);
13972 (void) XSync(display,MagickFalse);
13973 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13981 + X D i s p l a y I m a g e %
13985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13987 % XDisplayImage() displays an image via X11. A new image is created and
13988 % returned if the user interactively transforms the displayed image.
13990 % The format of the XDisplayImage method is:
13992 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13993 % char **argv,int argc,Image **image,size_t *state,
13994 % ExceptionInfo *exception)
13996 % A description of each parameter follows:
13998 % o nexus: Method XDisplayImage returns an image when the
13999 % user chooses 'Open Image' from the command menu or picks a tile
14000 % from the image directory. Otherwise a null image is returned.
14002 % o display: Specifies a connection to an X server; returned from
14005 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14007 % o argv: Specifies the application's argument list.
14009 % o argc: Specifies the number of arguments.
14011 % o image: Specifies an address to an address of an Image structure;
14013 % o exception: return any errors or warnings in this structure.
14016 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14017 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
14019 #define MagnifySize 256 /* must be a power of 2 */
14020 #define MagickMenus 10
14021 #define MagickTitle "Commands"
14048 "Visual Directory...",
14094 "Contrast Stretch...",
14095 "Sigmoidal Contrast...",
14129 "Charcoal Draw...",
14143 "Region of Interest...",
14146 *MiscellanyMenu[] =
14161 "Browse Documentation",
14188 **Menus[MagickMenus] =
14226 VisualDirectoryCommand,
14240 OriginalSizeCommand,
14247 TransformCommands[] =
14253 RotateRightCommand,
14260 EnhanceCommands[] =
14268 ContrastStretchCommand,
14269 SigmoidalContrastCommand,
14277 EffectsCommands[] =
14281 ReduceNoiseCommand,
14301 CharcoalDrawCommand
14303 ImageEditCommands[] =
14314 RegionofInterestCommand
14316 MiscellanyCommands[] =
14320 ShowPreviewCommand,
14321 ShowHistogramCommand,
14330 BrowseDocumentationCommand,
14333 ShortCutsCommands[] =
14345 VirtualCommands[] =
14354 *Commands[MagickMenus] =
14364 MiscellanyCommands,
14369 command[MaxTextExtent],
14371 geometry[MaxTextExtent],
14372 resource_name[MaxTextExtent];
14399 working_directory[MaxTextExtent];
14405 *magick_windows[MaxXWindows];
14407 static unsigned int
14467 assert(image != (Image **) NULL);
14468 assert((*image)->signature == MagickSignature);
14469 if ((*image)->debug != MagickFalse)
14470 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14471 display_image=(*image);
14472 warning_handler=(WarningHandler) NULL;
14473 windows=XSetWindows((XWindows *) ~0);
14474 if (windows != (XWindows *) NULL)
14479 status=chdir(working_directory);
14481 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14482 "UnableToOpenFile","%s",working_directory);
14483 warning_handler=resource_info->display_warnings ?
14484 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14485 warning_handler=resource_info->display_warnings ?
14486 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14491 Allocate windows structure.
14493 resource_info->colors=display_image->colors;
14494 windows=XSetWindows(XInitializeWindows(display,resource_info));
14495 if (windows == (XWindows *) NULL)
14496 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14497 (*image)->filename);
14499 Initialize window id's.
14502 magick_windows[number_windows++]=(&windows->icon);
14503 magick_windows[number_windows++]=(&windows->backdrop);
14504 magick_windows[number_windows++]=(&windows->image);
14505 magick_windows[number_windows++]=(&windows->info);
14506 magick_windows[number_windows++]=(&windows->command);
14507 magick_windows[number_windows++]=(&windows->widget);
14508 magick_windows[number_windows++]=(&windows->popup);
14509 magick_windows[number_windows++]=(&windows->magnify);
14510 magick_windows[number_windows++]=(&windows->pan);
14511 for (i=0; i < (int) number_windows; i++)
14512 magick_windows[i]->id=(Window) NULL;
14517 Initialize font info.
14519 if (windows->font_info != (XFontStruct *) NULL)
14520 (void) XFreeFont(display,windows->font_info);
14521 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14522 if (windows->font_info == (XFontStruct *) NULL)
14523 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14524 resource_info->font);
14526 Initialize Standard Colormap.
14528 map_info=windows->map_info;
14529 icon_map=windows->icon_map;
14530 visual_info=windows->visual_info;
14531 icon_visual=windows->icon_visual;
14532 pixel=windows->pixel_info;
14533 icon_pixel=windows->icon_pixel;
14534 font_info=windows->font_info;
14535 icon_resources=windows->icon_resources;
14536 class_hints=windows->class_hints;
14537 manager_hints=windows->manager_hints;
14538 root_window=XRootWindow(display,visual_info->screen);
14539 nexus=NewImageList();
14540 if (display_image->debug != MagickFalse)
14542 (void) LogMagickEvent(X11Event,GetMagickModule(),
14543 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14544 (double) display_image->scene,(double) display_image->columns,
14545 (double) display_image->rows);
14546 if (display_image->colors != 0)
14547 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14548 display_image->colors);
14549 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14550 display_image->magick);
14552 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14554 display_image->taint=MagickFalse;
14556 Initialize graphic context.
14558 windows->context.id=(Window) NULL;
14559 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14560 resource_info,&windows->context);
14561 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14562 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14563 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14564 manager_hints->flags=InputHint | StateHint;
14565 manager_hints->input=MagickFalse;
14566 manager_hints->initial_state=WithdrawnState;
14567 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14568 &windows->context);
14569 if (display_image->debug != MagickFalse)
14570 (void) LogMagickEvent(X11Event,GetMagickModule(),
14571 "Window id: 0x%lx (context)",windows->context.id);
14572 context_values.background=pixel->background_color.pixel;
14573 context_values.font=font_info->fid;
14574 context_values.foreground=pixel->foreground_color.pixel;
14575 context_values.graphics_exposures=MagickFalse;
14576 context_mask=(MagickStatusType)
14577 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14578 if (pixel->annotate_context != (GC) NULL)
14579 (void) XFreeGC(display,pixel->annotate_context);
14580 pixel->annotate_context=XCreateGC(display,windows->context.id,
14581 context_mask,&context_values);
14582 if (pixel->annotate_context == (GC) NULL)
14583 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14584 display_image->filename);
14585 context_values.background=pixel->depth_color.pixel;
14586 if (pixel->widget_context != (GC) NULL)
14587 (void) XFreeGC(display,pixel->widget_context);
14588 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14590 if (pixel->widget_context == (GC) NULL)
14591 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14592 display_image->filename);
14593 context_values.background=pixel->foreground_color.pixel;
14594 context_values.foreground=pixel->background_color.pixel;
14595 context_values.plane_mask=context_values.background ^
14596 context_values.foreground;
14597 if (pixel->highlight_context != (GC) NULL)
14598 (void) XFreeGC(display,pixel->highlight_context);
14599 pixel->highlight_context=XCreateGC(display,windows->context.id,
14600 (size_t) (context_mask | GCPlaneMask),&context_values);
14601 if (pixel->highlight_context == (GC) NULL)
14602 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14603 display_image->filename);
14604 (void) XDestroyWindow(display,windows->context.id);
14606 Initialize icon window.
14608 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14609 icon_resources,&windows->icon);
14610 windows->icon.geometry=resource_info->icon_geometry;
14611 XBestIconSize(display,&windows->icon,display_image);
14612 windows->icon.attributes.colormap=XDefaultColormap(display,
14613 icon_visual->screen);
14614 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14615 manager_hints->flags=InputHint | StateHint;
14616 manager_hints->input=MagickFalse;
14617 manager_hints->initial_state=IconicState;
14618 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14620 if (display_image->debug != MagickFalse)
14621 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14624 Initialize graphic context for icon window.
14626 if (icon_pixel->annotate_context != (GC) NULL)
14627 (void) XFreeGC(display,icon_pixel->annotate_context);
14628 context_values.background=icon_pixel->background_color.pixel;
14629 context_values.foreground=icon_pixel->foreground_color.pixel;
14630 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14631 (size_t) (GCBackground | GCForeground),&context_values);
14632 if (icon_pixel->annotate_context == (GC) NULL)
14633 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14634 display_image->filename);
14635 windows->icon.annotate_context=icon_pixel->annotate_context;
14637 Initialize Image window.
14639 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14641 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14642 if (resource_info->use_shared_memory == MagickFalse)
14643 windows->image.shared_memory=MagickFalse;
14644 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14649 title=InterpretImageProperties(resource_info->image_info,display_image,
14650 resource_info->title);
14651 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14652 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14653 title=DestroyString(title);
14658 filename[MaxTextExtent];
14661 Window name is the base of the filename.
14663 GetPathComponent(display_image->magick_filename,TailPath,filename);
14664 if (GetImageListLength(display_image) == 1)
14665 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14666 "%s: %s",MagickPackageName,filename);
14668 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14669 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14670 (double) display_image->scene,(double) GetImageListLength(
14672 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14674 if (resource_info->immutable)
14675 windows->image.immutable=MagickTrue;
14676 windows->image.use_pixmap=resource_info->use_pixmap;
14677 windows->image.geometry=resource_info->image_geometry;
14678 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14679 XDisplayWidth(display,visual_info->screen),
14680 XDisplayHeight(display,visual_info->screen));
14681 geometry_info.width=display_image->columns;
14682 geometry_info.height=display_image->rows;
14685 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14686 &geometry_info.width,&geometry_info.height);
14687 windows->image.width=(unsigned int) geometry_info.width;
14688 windows->image.height=(unsigned int) geometry_info.height;
14689 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14690 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14691 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14692 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14693 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14694 resource_info,&windows->backdrop);
14695 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14698 Initialize backdrop window.
14700 windows->backdrop.x=0;
14701 windows->backdrop.y=0;
14702 (void) CloneString(&windows->backdrop.name,"Backdrop");
14703 windows->backdrop.flags=(size_t) (USSize | USPosition);
14704 windows->backdrop.width=(unsigned int)
14705 XDisplayWidth(display,visual_info->screen);
14706 windows->backdrop.height=(unsigned int)
14707 XDisplayHeight(display,visual_info->screen);
14708 windows->backdrop.border_width=0;
14709 windows->backdrop.immutable=MagickTrue;
14710 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14712 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14713 StructureNotifyMask;
14714 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14715 manager_hints->icon_window=windows->icon.id;
14716 manager_hints->input=MagickTrue;
14717 manager_hints->initial_state=resource_info->iconic ? IconicState :
14719 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14720 &windows->backdrop);
14721 if (display_image->debug != MagickFalse)
14722 (void) LogMagickEvent(X11Event,GetMagickModule(),
14723 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14724 (void) XMapWindow(display,windows->backdrop.id);
14725 (void) XClearWindow(display,windows->backdrop.id);
14726 if (windows->image.id != (Window) NULL)
14728 (void) XDestroyWindow(display,windows->image.id);
14729 windows->image.id=(Window) NULL;
14732 Position image in the center the backdrop.
14734 windows->image.flags|=USPosition;
14735 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14736 (windows->image.width/2);
14737 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14738 (windows->image.height/2);
14740 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14741 manager_hints->icon_window=windows->icon.id;
14742 manager_hints->input=MagickTrue;
14743 manager_hints->initial_state=resource_info->iconic ? IconicState :
14745 if (windows->group_leader.id != (Window) NULL)
14750 manager_hints->flags|=WindowGroupHint;
14751 manager_hints->window_group=windows->group_leader.id;
14752 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14753 if (display_image->debug != MagickFalse)
14754 (void) LogMagickEvent(X11Event,GetMagickModule(),
14755 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14757 XMakeWindow(display,
14758 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14759 argv,argc,class_hints,manager_hints,&windows->image);
14760 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14761 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14762 if (windows->group_leader.id != (Window) NULL)
14763 (void) XSetTransientForHint(display,windows->image.id,
14764 windows->group_leader.id);
14765 if (display_image->debug != MagickFalse)
14766 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14767 windows->image.id);
14769 Initialize Info widget.
14771 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14773 (void) CloneString(&windows->info.name,"Info");
14774 (void) CloneString(&windows->info.icon_name,"Info");
14775 windows->info.border_width=1;
14778 windows->info.flags|=PPosition;
14779 windows->info.attributes.win_gravity=UnmapGravity;
14780 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14781 StructureNotifyMask;
14782 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14783 manager_hints->input=MagickFalse;
14784 manager_hints->initial_state=NormalState;
14785 manager_hints->window_group=windows->image.id;
14786 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14788 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14789 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14790 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14791 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14792 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14793 if (windows->image.mapped != MagickFalse)
14794 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14795 if (display_image->debug != MagickFalse)
14796 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14799 Initialize Command widget.
14801 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14802 resource_info,&windows->command);
14803 windows->command.data=MagickMenus;
14804 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14805 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
14806 resource_info->client_name);
14807 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14808 resource_name,"geometry",(char *) NULL);
14809 (void) CloneString(&windows->command.name,MagickTitle);
14810 windows->command.border_width=0;
14811 windows->command.flags|=PPosition;
14812 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14813 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14814 OwnerGrabButtonMask | StructureNotifyMask;
14815 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14816 manager_hints->input=MagickTrue;
14817 manager_hints->initial_state=NormalState;
14818 manager_hints->window_group=windows->image.id;
14819 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14820 &windows->command);
14821 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14822 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14824 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14825 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14826 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14827 if (windows->command.mapped != MagickFalse)
14828 (void) XMapRaised(display,windows->command.id);
14829 if (display_image->debug != MagickFalse)
14830 (void) LogMagickEvent(X11Event,GetMagickModule(),
14831 "Window id: 0x%lx (command)",windows->command.id);
14833 Initialize Widget window.
14835 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14836 resource_info,&windows->widget);
14837 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
14838 resource_info->client_name);
14839 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14840 resource_name,"geometry",(char *) NULL);
14841 windows->widget.border_width=0;
14842 windows->widget.flags|=PPosition;
14843 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14844 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14845 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14846 StructureNotifyMask;
14847 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14848 manager_hints->input=MagickTrue;
14849 manager_hints->initial_state=NormalState;
14850 manager_hints->window_group=windows->image.id;
14851 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14853 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14854 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14855 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14856 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14857 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14858 if (display_image->debug != MagickFalse)
14859 (void) LogMagickEvent(X11Event,GetMagickModule(),
14860 "Window id: 0x%lx (widget)",windows->widget.id);
14862 Initialize popup window.
14864 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14865 resource_info,&windows->popup);
14866 windows->popup.border_width=0;
14867 windows->popup.flags|=PPosition;
14868 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14869 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14870 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14871 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14872 manager_hints->input=MagickTrue;
14873 manager_hints->initial_state=NormalState;
14874 manager_hints->window_group=windows->image.id;
14875 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14877 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14878 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14879 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14880 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14881 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14882 if (display_image->debug != MagickFalse)
14883 (void) LogMagickEvent(X11Event,GetMagickModule(),
14884 "Window id: 0x%lx (pop up)",windows->popup.id);
14886 Initialize Magnify window and cursor.
14888 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14889 resource_info,&windows->magnify);
14890 if (resource_info->use_shared_memory == MagickFalse)
14891 windows->magnify.shared_memory=MagickFalse;
14892 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
14893 resource_info->client_name);
14894 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14895 resource_name,"geometry",(char *) NULL);
14896 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14897 resource_info->magnify);
14898 if (windows->magnify.cursor != (Cursor) NULL)
14899 (void) XFreeCursor(display,windows->magnify.cursor);
14900 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14901 map_info->colormap,resource_info->background_color,
14902 resource_info->foreground_color);
14903 if (windows->magnify.cursor == (Cursor) NULL)
14904 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14905 display_image->filename);
14906 windows->magnify.width=MagnifySize;
14907 windows->magnify.height=MagnifySize;
14908 windows->magnify.flags|=PPosition;
14909 windows->magnify.min_width=MagnifySize;
14910 windows->magnify.min_height=MagnifySize;
14911 windows->magnify.width_inc=MagnifySize;
14912 windows->magnify.height_inc=MagnifySize;
14913 windows->magnify.data=resource_info->magnify;
14914 windows->magnify.attributes.cursor=windows->magnify.cursor;
14915 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14916 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14917 StructureNotifyMask;
14918 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14919 manager_hints->input=MagickTrue;
14920 manager_hints->initial_state=NormalState;
14921 manager_hints->window_group=windows->image.id;
14922 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14923 &windows->magnify);
14924 if (display_image->debug != MagickFalse)
14925 (void) LogMagickEvent(X11Event,GetMagickModule(),
14926 "Window id: 0x%lx (magnify)",windows->magnify.id);
14927 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14929 Initialize panning window.
14931 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14932 resource_info,&windows->pan);
14933 (void) CloneString(&windows->pan.name,"Pan Icon");
14934 windows->pan.width=windows->icon.width;
14935 windows->pan.height=windows->icon.height;
14936 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
14937 resource_info->client_name);
14938 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14939 resource_name,"geometry",(char *) NULL);
14940 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14941 &windows->pan.width,&windows->pan.height);
14942 windows->pan.flags|=PPosition;
14943 windows->pan.immutable=MagickTrue;
14944 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14945 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14946 StructureNotifyMask;
14947 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14948 manager_hints->input=MagickFalse;
14949 manager_hints->initial_state=NormalState;
14950 manager_hints->window_group=windows->image.id;
14951 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14953 if (display_image->debug != MagickFalse)
14954 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14956 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14957 if (windows->info.mapped != MagickFalse)
14958 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14959 if ((windows->image.mapped == MagickFalse) ||
14960 (windows->backdrop.id != (Window) NULL))
14961 (void) XMapWindow(display,windows->image.id);
14963 Set our progress monitor and warning handlers.
14965 if (warning_handler == (WarningHandler) NULL)
14967 warning_handler=resource_info->display_warnings ?
14968 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14969 warning_handler=resource_info->display_warnings ?
14970 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14973 Initialize Image and Magnify X images.
14975 windows->image.x=0;
14976 windows->image.y=0;
14977 windows->magnify.shape=MagickFalse;
14978 width=(unsigned int) display_image->columns;
14979 height=(unsigned int) display_image->rows;
14980 if ((display_image->columns != width) || (display_image->rows != height))
14981 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14982 display_image->filename);
14983 status=XMakeImage(display,resource_info,&windows->image,display_image,
14984 width,height,exception);
14985 if (status == MagickFalse)
14986 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14987 display_image->filename);
14988 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14989 windows->magnify.width,windows->magnify.height,exception);
14990 if (status == MagickFalse)
14991 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14992 display_image->filename);
14993 if (windows->magnify.mapped != MagickFalse)
14994 (void) XMapRaised(display,windows->magnify.id);
14995 if (windows->pan.mapped != MagickFalse)
14996 (void) XMapRaised(display,windows->pan.id);
14997 windows->image.window_changes.width=(int) display_image->columns;
14998 windows->image.window_changes.height=(int) display_image->rows;
14999 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
15000 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15001 (void) XSync(display,MagickFalse);
15005 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15006 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15008 if (resource_info->update != MagickFalse)
15014 Determine when file data was last modified.
15016 status=GetPathAttributes(display_image->filename,&attributes);
15017 if (status != MagickFalse)
15018 update_time=attributes.st_mtime;
15020 *state&=(~FormerImageState);
15021 *state&=(~MontageImageState);
15022 *state&=(~NextImageState);
15026 Handle a window event.
15028 if (windows->image.mapped != MagickFalse)
15029 if ((display_image->delay != 0) || (resource_info->update != 0))
15031 if (timer < time((time_t *) NULL))
15033 if (resource_info->update == MagickFalse)
15034 *state|=NextImageState | ExitState;
15041 Determine if image file was modified.
15043 status=GetPathAttributes(display_image->filename,&attributes);
15044 if (status != MagickFalse)
15045 if (update_time != attributes.st_mtime)
15050 (void) FormatLocaleString(
15051 resource_info->image_info->filename,MaxTextExtent,
15052 "%s:%s",display_image->magick,
15053 display_image->filename);
15054 nexus=ReadImage(resource_info->image_info,
15055 &display_image->exception);
15056 if (nexus != (Image *) NULL)
15058 nexus=DestroyImage(nexus);
15059 *state|=NextImageState | ExitState;
15062 delay=display_image->delay/MagickMax(
15063 display_image->ticks_per_second,1L);
15064 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15067 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15070 Do not block if delay > 0.
15072 XDelay(display,SuspendTime << 2);
15076 timestamp=time((time_t *) NULL);
15077 (void) XNextEvent(display,&event);
15078 if (windows->image.stasis == MagickFalse)
15079 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15080 MagickTrue : MagickFalse;
15081 if (windows->magnify.stasis == MagickFalse)
15082 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15083 MagickTrue : MagickFalse;
15084 if (event.xany.window == windows->command.id)
15087 Select a command from the Command widget.
15089 id=XCommandWidget(display,windows,CommandMenu,&event);
15092 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15093 command_type=CommandMenus[id];
15094 if (id < MagickMenus)
15097 Select a command from a pop-up menu.
15099 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15103 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15104 command_type=Commands[id][entry];
15106 if (command_type != NullCommand)
15107 nexus=XMagickCommand(display,resource_info,windows,command_type,
15108 &display_image,exception);
15111 switch (event.type)
15115 if (display_image->debug != MagickFalse)
15116 (void) LogMagickEvent(X11Event,GetMagickModule(),
15117 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15118 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15119 if ((event.xbutton.button == Button3) &&
15120 (event.xbutton.state & Mod1Mask))
15123 Convert Alt-Button3 to Button2.
15125 event.xbutton.button=Button2;
15126 event.xbutton.state&=(~Mod1Mask);
15128 if (event.xbutton.window == windows->backdrop.id)
15130 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15131 event.xbutton.time);
15134 if (event.xbutton.window == windows->image.id)
15136 switch (event.xbutton.button)
15140 if (resource_info->immutable)
15143 Select a command from the Virtual menu.
15145 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15148 nexus=XMagickCommand(display,resource_info,windows,
15149 VirtualCommands[entry],&display_image,exception);
15153 Map/unmap Command widget.
15155 if (windows->command.mapped != MagickFalse)
15156 (void) XWithdrawWindow(display,windows->command.id,
15157 windows->command.screen);
15160 (void) XCommandWidget(display,windows,CommandMenu,
15162 (void) XMapRaised(display,windows->command.id);
15169 User pressed the image magnify button.
15171 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15172 &display_image,exception);
15173 XMagnifyImage(display,windows,&event);
15178 if (resource_info->immutable)
15181 Select a command from the Virtual menu.
15183 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15186 nexus=XMagickCommand(display,resource_info,windows,
15187 VirtualCommands[entry],&display_image,exception);
15190 if (display_image->montage != (char *) NULL)
15193 Open or delete a tile from a visual image directory.
15195 nexus=XTileImage(display,resource_info,windows,
15196 display_image,&event,exception);
15197 if (nexus != (Image *) NULL)
15198 *state|=MontageImageState | NextImageState | ExitState;
15199 vid_info.x=(short int) windows->image.x;
15200 vid_info.y=(short int) windows->image.y;
15204 Select a command from the Short Cuts menu.
15206 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15209 nexus=XMagickCommand(display,resource_info,windows,
15210 ShortCutsCommands[entry],&display_image,exception);
15218 XTranslateImage(display,windows,*image,XK_Up);
15226 XTranslateImage(display,windows,*image,XK_Down);
15234 if (event.xbutton.window == windows->magnify.id)
15254 MagnifyCommands[] =
15267 Select a magnify factor from the pop-up menu.
15269 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15271 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15274 if (event.xbutton.window == windows->pan.id)
15276 switch (event.xbutton.button)
15283 XTranslateImage(display,windows,*image,XK_Up);
15291 XTranslateImage(display,windows,*image,XK_Down);
15296 XPanImage(display,windows,&event);
15302 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15304 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15307 case ButtonRelease:
15309 if (display_image->debug != MagickFalse)
15310 (void) LogMagickEvent(X11Event,GetMagickModule(),
15311 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15312 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15315 case ClientMessage:
15317 if (display_image->debug != MagickFalse)
15318 (void) LogMagickEvent(X11Event,GetMagickModule(),
15319 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15320 event.xclient.message_type,event.xclient.format,(unsigned long)
15321 event.xclient.data.l[0]);
15322 if (event.xclient.message_type == windows->im_protocols)
15324 if (*event.xclient.data.l == (long) windows->im_update_widget)
15326 (void) CloneString(&windows->command.name,MagickTitle);
15327 windows->command.data=MagickMenus;
15328 (void) XCommandWidget(display,windows,CommandMenu,
15332 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15335 Update graphic context and window colormap.
15337 for (i=0; i < (int) number_windows; i++)
15339 if (magick_windows[i]->id == windows->icon.id)
15341 context_values.background=pixel->background_color.pixel;
15342 context_values.foreground=pixel->foreground_color.pixel;
15343 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15344 context_mask,&context_values);
15345 (void) XChangeGC(display,magick_windows[i]->widget_context,
15346 context_mask,&context_values);
15347 context_values.background=pixel->foreground_color.pixel;
15348 context_values.foreground=pixel->background_color.pixel;
15349 context_values.plane_mask=context_values.background ^
15350 context_values.foreground;
15351 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15352 (size_t) (context_mask | GCPlaneMask),
15354 magick_windows[i]->attributes.background_pixel=
15355 pixel->background_color.pixel;
15356 magick_windows[i]->attributes.border_pixel=
15357 pixel->border_color.pixel;
15358 magick_windows[i]->attributes.colormap=map_info->colormap;
15359 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15360 (unsigned long) magick_windows[i]->mask,
15361 &magick_windows[i]->attributes);
15363 if (windows->pan.mapped != MagickFalse)
15365 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15366 windows->pan.pixmap);
15367 (void) XClearWindow(display,windows->pan.id);
15368 XDrawPanRectangle(display,windows);
15370 if (windows->backdrop.id != (Window) NULL)
15371 (void) XInstallColormap(display,map_info->colormap);
15374 if (*event.xclient.data.l == (long) windows->im_former_image)
15376 *state|=FormerImageState | ExitState;
15379 if (*event.xclient.data.l == (long) windows->im_next_image)
15381 *state|=NextImageState | ExitState;
15384 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15386 *state|=RetainColorsState;
15389 if (*event.xclient.data.l == (long) windows->im_exit)
15396 if (event.xclient.message_type == windows->dnd_protocols)
15414 Display image named by the Drag-and-Drop selection.
15416 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15418 selection=XInternAtom(display,"DndSelection",MagickFalse);
15419 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15420 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15421 &length,&after,&data);
15422 if ((status != Success) || (length == 0))
15424 if (*event.xclient.data.l == 2)
15429 (void) CopyMagickString(resource_info->image_info->filename,
15430 (char *) data,MaxTextExtent);
15437 if (strncmp((char *) data, "file:", 5) != 0)
15439 (void) XFree((void *) data);
15442 (void) CopyMagickString(resource_info->image_info->filename,
15443 ((char *) data)+5,MaxTextExtent);
15445 nexus=ReadImage(resource_info->image_info,
15446 &display_image->exception);
15447 CatchException(&display_image->exception);
15448 if (nexus != (Image *) NULL)
15449 *state|=NextImageState | ExitState;
15450 (void) XFree((void *) data);
15454 If client window delete message, exit.
15456 if (event.xclient.message_type != windows->wm_protocols)
15458 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15460 (void) XWithdrawWindow(display,event.xclient.window,
15461 visual_info->screen);
15462 if (event.xclient.window == windows->image.id)
15467 if (event.xclient.window == windows->pan.id)
15470 Restore original image size when pan window is deleted.
15472 windows->image.window_changes.width=windows->image.ximage->width;
15473 windows->image.window_changes.height=windows->image.ximage->height;
15474 (void) XConfigureImage(display,resource_info,windows,
15475 display_image,exception);
15479 case ConfigureNotify:
15481 if (display_image->debug != MagickFalse)
15482 (void) LogMagickEvent(X11Event,GetMagickModule(),
15483 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15484 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15485 event.xconfigure.y,event.xconfigure.send_event);
15486 if (event.xconfigure.window == windows->image.id)
15489 Image window has a new configuration.
15491 if (event.xconfigure.send_event != 0)
15497 Position the transient windows relative of the Image window.
15499 if (windows->command.geometry == (char *) NULL)
15500 if (windows->command.mapped == MagickFalse)
15502 windows->command.x=event.xconfigure.x-
15503 windows->command.width-25;
15504 windows->command.y=event.xconfigure.y;
15505 XConstrainWindowPosition(display,&windows->command);
15506 window_changes.x=windows->command.x;
15507 window_changes.y=windows->command.y;
15508 (void) XReconfigureWMWindow(display,windows->command.id,
15509 windows->command.screen,(unsigned int) (CWX | CWY),
15512 if (windows->widget.geometry == (char *) NULL)
15513 if (windows->widget.mapped == MagickFalse)
15515 windows->widget.x=event.xconfigure.x+
15516 event.xconfigure.width/10;
15517 windows->widget.y=event.xconfigure.y+
15518 event.xconfigure.height/10;
15519 XConstrainWindowPosition(display,&windows->widget);
15520 window_changes.x=windows->widget.x;
15521 window_changes.y=windows->widget.y;
15522 (void) XReconfigureWMWindow(display,windows->widget.id,
15523 windows->widget.screen,(unsigned int) (CWX | CWY),
15526 if (windows->magnify.geometry == (char *) NULL)
15527 if (windows->magnify.mapped == MagickFalse)
15529 windows->magnify.x=event.xconfigure.x+
15530 event.xconfigure.width+25;
15531 windows->magnify.y=event.xconfigure.y;
15532 XConstrainWindowPosition(display,&windows->magnify);
15533 window_changes.x=windows->magnify.x;
15534 window_changes.y=windows->magnify.y;
15535 (void) XReconfigureWMWindow(display,windows->magnify.id,
15536 windows->magnify.screen,(unsigned int) (CWX | CWY),
15539 if (windows->pan.geometry == (char *) NULL)
15540 if (windows->pan.mapped == MagickFalse)
15542 windows->pan.x=event.xconfigure.x+
15543 event.xconfigure.width+25;
15544 windows->pan.y=event.xconfigure.y+
15545 windows->magnify.height+50;
15546 XConstrainWindowPosition(display,&windows->pan);
15547 window_changes.x=windows->pan.x;
15548 window_changes.y=windows->pan.y;
15549 (void) XReconfigureWMWindow(display,windows->pan.id,
15550 windows->pan.screen,(unsigned int) (CWX | CWY),
15554 if ((event.xconfigure.width == (int) windows->image.width) &&
15555 (event.xconfigure.height == (int) windows->image.height))
15557 windows->image.width=(unsigned int) event.xconfigure.width;
15558 windows->image.height=(unsigned int) event.xconfigure.height;
15559 windows->image.x=0;
15560 windows->image.y=0;
15561 if (display_image->montage != (char *) NULL)
15563 windows->image.x=vid_info.x;
15564 windows->image.y=vid_info.y;
15566 if ((windows->image.mapped != MagickFalse) &&
15567 (windows->image.stasis != MagickFalse))
15570 Update image window configuration.
15572 windows->image.window_changes.width=event.xconfigure.width;
15573 windows->image.window_changes.height=event.xconfigure.height;
15574 (void) XConfigureImage(display,resource_info,windows,
15575 display_image,exception);
15578 Update pan window configuration.
15580 if ((event.xconfigure.width < windows->image.ximage->width) ||
15581 (event.xconfigure.height < windows->image.ximage->height))
15583 (void) XMapRaised(display,windows->pan.id);
15584 XDrawPanRectangle(display,windows);
15587 if (windows->pan.mapped != MagickFalse)
15588 (void) XWithdrawWindow(display,windows->pan.id,
15589 windows->pan.screen);
15592 if (event.xconfigure.window == windows->magnify.id)
15598 Magnify window has a new configuration.
15600 windows->magnify.width=(unsigned int) event.xconfigure.width;
15601 windows->magnify.height=(unsigned int) event.xconfigure.height;
15602 if (windows->magnify.mapped == MagickFalse)
15605 while ((int) magnify <= event.xconfigure.width)
15607 while ((int) magnify <= event.xconfigure.height)
15610 if (((int) magnify != event.xconfigure.width) ||
15611 ((int) magnify != event.xconfigure.height))
15613 window_changes.width=(int) magnify;
15614 window_changes.height=(int) magnify;
15615 (void) XReconfigureWMWindow(display,windows->magnify.id,
15616 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15620 if ((windows->magnify.mapped != MagickFalse) &&
15621 (windows->magnify.stasis != MagickFalse))
15623 status=XMakeImage(display,resource_info,&windows->magnify,
15624 display_image,windows->magnify.width,windows->magnify.height,
15626 XMakeMagnifyImage(display,windows);
15630 if ((windows->magnify.mapped != MagickFalse) &&
15631 (event.xconfigure.window == windows->pan.id))
15634 Pan icon window has a new configuration.
15636 if (event.xconfigure.send_event != 0)
15638 windows->pan.x=event.xconfigure.x;
15639 windows->pan.y=event.xconfigure.y;
15641 windows->pan.width=(unsigned int) event.xconfigure.width;
15642 windows->pan.height=(unsigned int) event.xconfigure.height;
15645 if (event.xconfigure.window == windows->icon.id)
15648 Icon window has a new configuration.
15650 windows->icon.width=(unsigned int) event.xconfigure.width;
15651 windows->icon.height=(unsigned int) event.xconfigure.height;
15656 case DestroyNotify:
15659 Group leader has exited.
15661 if (display_image->debug != MagickFalse)
15662 (void) LogMagickEvent(X11Event,GetMagickModule(),
15663 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15664 if (event.xdestroywindow.window == windows->group_leader.id)
15674 Selectively install colormap.
15676 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15677 if (event.xcrossing.mode != NotifyUngrab)
15678 XInstallColormap(display,map_info->colormap);
15683 if (display_image->debug != MagickFalse)
15684 (void) LogMagickEvent(X11Event,GetMagickModule(),
15685 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15686 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15689 Refresh windows that are now exposed.
15691 if ((event.xexpose.window == windows->image.id) &&
15692 (windows->image.mapped != MagickFalse))
15694 XRefreshWindow(display,&windows->image,&event);
15695 delay=display_image->delay/MagickMax(
15696 display_image->ticks_per_second,1L);
15697 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15700 if ((event.xexpose.window == windows->magnify.id) &&
15701 (windows->magnify.mapped != MagickFalse))
15703 XMakeMagnifyImage(display,windows);
15706 if (event.xexpose.window == windows->pan.id)
15708 XDrawPanRectangle(display,windows);
15711 if (event.xexpose.window == windows->icon.id)
15713 XRefreshWindow(display,&windows->icon,&event);
15724 Respond to a user key press.
15726 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15727 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15728 *(command+length)='\0';
15729 if (display_image->debug != MagickFalse)
15730 (void) LogMagickEvent(X11Event,GetMagickModule(),
15731 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15732 key_symbol,command);
15733 if (event.xkey.window == windows->image.id)
15735 command_type=XImageWindowCommand(display,resource_info,windows,
15736 event.xkey.state,key_symbol,&display_image,exception);
15737 if (command_type != NullCommand)
15738 nexus=XMagickCommand(display,resource_info,windows,command_type,
15739 &display_image,exception);
15741 if (event.xkey.window == windows->magnify.id)
15742 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15743 if (event.xkey.window == windows->pan.id)
15745 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15746 (void) XWithdrawWindow(display,windows->pan.id,
15747 windows->pan.screen);
15749 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15750 XTextViewWidget(display,resource_info,windows,MagickFalse,
15751 "Help Viewer - Image Pan",ImagePanHelp);
15753 XTranslateImage(display,windows,*image,key_symbol);
15755 delay=display_image->delay/MagickMax(
15756 display_image->ticks_per_second,1L);
15757 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15763 Respond to a user key release.
15765 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15766 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15767 if (display_image->debug != MagickFalse)
15768 (void) LogMagickEvent(X11Event,GetMagickModule(),
15769 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15775 Selectively uninstall colormap.
15777 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15778 if (event.xcrossing.mode != NotifyUngrab)
15779 XUninstallColormap(display,map_info->colormap);
15784 if (display_image->debug != MagickFalse)
15785 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15786 event.xmap.window);
15787 if (event.xmap.window == windows->backdrop.id)
15789 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15791 windows->backdrop.mapped=MagickTrue;
15794 if (event.xmap.window == windows->image.id)
15796 if (windows->backdrop.id != (Window) NULL)
15797 (void) XInstallColormap(display,map_info->colormap);
15798 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15800 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15801 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15803 if (((int) windows->image.width < windows->image.ximage->width) ||
15804 ((int) windows->image.height < windows->image.ximage->height))
15805 (void) XMapRaised(display,windows->pan.id);
15806 windows->image.mapped=MagickTrue;
15809 if (event.xmap.window == windows->magnify.id)
15811 XMakeMagnifyImage(display,windows);
15812 windows->magnify.mapped=MagickTrue;
15813 (void) XWithdrawWindow(display,windows->info.id,
15814 windows->info.screen);
15817 if (event.xmap.window == windows->pan.id)
15819 XMakePanImage(display,resource_info,windows,display_image,
15821 windows->pan.mapped=MagickTrue;
15824 if (event.xmap.window == windows->info.id)
15826 windows->info.mapped=MagickTrue;
15829 if (event.xmap.window == windows->icon.id)
15835 Create an icon image.
15837 taint=display_image->taint;
15838 XMakeStandardColormap(display,icon_visual,icon_resources,
15839 display_image,icon_map,icon_pixel);
15840 (void) XMakeImage(display,icon_resources,&windows->icon,
15841 display_image,windows->icon.width,windows->icon.height,
15843 display_image->taint=taint;
15844 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15845 windows->icon.pixmap);
15846 (void) XClearWindow(display,windows->icon.id);
15847 (void) XWithdrawWindow(display,windows->info.id,
15848 windows->info.screen);
15849 windows->icon.mapped=MagickTrue;
15852 if (event.xmap.window == windows->command.id)
15854 windows->command.mapped=MagickTrue;
15857 if (event.xmap.window == windows->popup.id)
15859 windows->popup.mapped=MagickTrue;
15862 if (event.xmap.window == windows->widget.id)
15864 windows->widget.mapped=MagickTrue;
15869 case MappingNotify:
15871 (void) XRefreshKeyboardMapping(&event.xmapping);
15876 case PropertyNotify:
15892 if (display_image->debug != MagickFalse)
15893 (void) LogMagickEvent(X11Event,GetMagickModule(),
15894 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15895 event.xproperty.atom,event.xproperty.state);
15896 if (event.xproperty.atom != windows->im_remote_command)
15899 Display image named by the remote command protocol.
15901 status=XGetWindowProperty(display,event.xproperty.window,
15902 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15903 AnyPropertyType,&type,&format,&length,&after,&data);
15904 if ((status != Success) || (length == 0))
15906 if (LocaleCompare((char *) data,"-quit") == 0)
15908 XClientMessage(display,windows->image.id,windows->im_protocols,
15909 windows->im_exit,CurrentTime);
15910 (void) XFree((void *) data);
15913 (void) CopyMagickString(resource_info->image_info->filename,
15914 (char *) data,MaxTextExtent);
15915 (void) XFree((void *) data);
15916 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15917 CatchException(&display_image->exception);
15918 if (nexus != (Image *) NULL)
15919 *state|=NextImageState | ExitState;
15922 case ReparentNotify:
15924 if (display_image->debug != MagickFalse)
15925 (void) LogMagickEvent(X11Event,GetMagickModule(),
15926 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15927 event.xreparent.window);
15932 if (display_image->debug != MagickFalse)
15933 (void) LogMagickEvent(X11Event,GetMagickModule(),
15934 "Unmap Notify: 0x%lx",event.xunmap.window);
15935 if (event.xunmap.window == windows->backdrop.id)
15937 windows->backdrop.mapped=MagickFalse;
15940 if (event.xunmap.window == windows->image.id)
15942 windows->image.mapped=MagickFalse;
15945 if (event.xunmap.window == windows->magnify.id)
15947 windows->magnify.mapped=MagickFalse;
15950 if (event.xunmap.window == windows->pan.id)
15952 windows->pan.mapped=MagickFalse;
15955 if (event.xunmap.window == windows->info.id)
15957 windows->info.mapped=MagickFalse;
15960 if (event.xunmap.window == windows->icon.id)
15962 if (map_info->colormap == icon_map->colormap)
15963 XConfigureImageColormap(display,resource_info,windows,
15965 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15967 windows->icon.mapped=MagickFalse;
15970 if (event.xunmap.window == windows->command.id)
15972 windows->command.mapped=MagickFalse;
15975 if (event.xunmap.window == windows->popup.id)
15977 if (windows->backdrop.id != (Window) NULL)
15978 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15980 windows->popup.mapped=MagickFalse;
15983 if (event.xunmap.window == windows->widget.id)
15985 if (windows->backdrop.id != (Window) NULL)
15986 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15988 windows->widget.mapped=MagickFalse;
15995 if (display_image->debug != MagickFalse)
15996 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16001 } while (!(*state & ExitState));
16002 if ((*state & ExitState) == 0)
16003 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
16004 &display_image,exception);
16006 if (resource_info->confirm_edit != MagickFalse)
16009 Query user if image has changed.
16011 if ((resource_info->immutable == MagickFalse) &&
16012 (display_image->taint != MagickFalse))
16017 status=XConfirmWidget(display,windows,"Your image changed.",
16018 "Do you want to save it");
16020 *state&=(~ExitState);
16023 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
16024 &display_image,exception);
16027 if ((windows->visual_info->klass == GrayScale) ||
16028 (windows->visual_info->klass == PseudoColor) ||
16029 (windows->visual_info->klass == DirectColor))
16032 Withdraw pan and Magnify window.
16034 if (windows->info.mapped != MagickFalse)
16035 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16036 if (windows->magnify.mapped != MagickFalse)
16037 (void) XWithdrawWindow(display,windows->magnify.id,
16038 windows->magnify.screen);
16039 if (windows->command.mapped != MagickFalse)
16040 (void) XWithdrawWindow(display,windows->command.id,
16041 windows->command.screen);
16043 if (windows->pan.mapped != MagickFalse)
16044 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16045 if (resource_info->backdrop == MagickFalse)
16046 if (windows->backdrop.mapped)
16048 (void) XWithdrawWindow(display,windows->backdrop.id,
16049 windows->backdrop.screen);
16050 (void) XDestroyWindow(display,windows->backdrop.id);
16051 windows->backdrop.id=(Window) NULL;
16052 (void) XWithdrawWindow(display,windows->image.id,
16053 windows->image.screen);
16054 (void) XDestroyWindow(display,windows->image.id);
16055 windows->image.id=(Window) NULL;
16057 XSetCursorState(display,windows,MagickTrue);
16058 XCheckRefreshWindows(display,windows);
16059 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16060 *state&=(~ExitState);
16061 if (*state & ExitState)
16064 Free Standard Colormap.
16066 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16067 if (resource_info->map_type == (char *) NULL)
16068 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16072 if (resource_info->copy_image != (Image *) NULL)
16074 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16075 resource_info->copy_image=NewImageList();
16077 DestroyXResources();
16079 (void) XSync(display,MagickFalse);
16081 Restore our progress monitor and warning handlers.
16083 (void) SetErrorHandler(warning_handler);
16084 (void) SetWarningHandler(warning_handler);
16086 Change to home directory.
16088 directory=getcwd(working_directory,MaxTextExtent);
16094 status=chdir(resource_info->home_directory);
16096 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
16097 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
16099 *image=display_image;
16105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16109 + D i s p l a y I m a g e s %
16113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16115 % DisplayImages() displays an image sequence to any X window screen. It
16116 % returns a value other than 0 if successful. Check the exception member
16117 % of image to determine the reason for any failure.
16119 % The format of the DisplayImages method is:
16121 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16122 % Image *images,ExceptionInfo *exception)
16124 % A description of each parameter follows:
16126 % o image_info: the image info.
16128 % o image: the image.
16130 % o exception: return any errors or warnings in this structure.
16133 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16134 Image *image,ExceptionInfo *exception)
16136 assert(image_info != (const ImageInfo *) NULL);
16137 assert(image_info->signature == MagickSignature);
16138 assert(image != (Image *) NULL);
16139 assert(image->signature == MagickSignature);
16140 if (image->debug != MagickFalse)
16141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16142 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16143 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename);
16144 return(MagickFalse);
16148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16152 + R e m o t e D i s p l a y C o m m a n d %
16156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16158 % RemoteDisplayCommand() encourages a remote display program to display the
16159 % specified image filename.
16161 % The format of the RemoteDisplayCommand method is:
16163 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16164 % const char *window,const char *filename,ExceptionInfo *exception)
16166 % A description of each parameter follows:
16168 % o image_info: the image info.
16170 % o window: Specifies the name or id of an X window.
16172 % o filename: the name of the image filename to display.
16174 % o exception: return any errors or warnings in this structure.
16177 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16178 const char *window,const char *filename,ExceptionInfo *exception)
16180 assert(image_info != (const ImageInfo *) NULL);
16181 assert(image_info->signature == MagickSignature);
16182 assert(filename != (char *) NULL);
16184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16185 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16186 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16187 return(MagickFalse);