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 **);
1567 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1569 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1570 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1571 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1573 static MagickBooleanType
1574 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1575 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1576 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1577 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1578 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1579 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1580 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1581 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1582 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1583 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1584 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1585 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1586 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1587 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1588 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1591 XDrawPanRectangle(Display *,XWindows *),
1592 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
1593 XMagnifyImage(Display *,XWindows *,XEvent *),
1594 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1595 XPanImage(Display *,XWindows *,XEvent *),
1596 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1598 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1599 XScreenEvent(Display *,XWindows *,XEvent *),
1600 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607 % D i s p l a y I m a g e s %
1611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613 % DisplayImages() displays an image sequence to any X window screen. It
1614 % returns a value other than 0 if successful. Check the exception member
1615 % of image to determine the reason for any failure.
1617 % The format of the DisplayImages method is:
1619 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1622 % A description of each parameter follows:
1624 % o image_info: the image info.
1626 % o image: the image.
1629 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1653 assert(image_info != (const ImageInfo *) NULL);
1654 assert(image_info->signature == MagickSignature);
1655 assert(images != (Image *) NULL);
1656 assert(images->signature == MagickSignature);
1657 if (images->debug != MagickFalse)
1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1659 display=XOpenDisplay(image_info->server_name);
1660 if (display == (Display *) NULL)
1662 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1663 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1664 image_info->server_name));
1665 return(MagickFalse);
1667 if (images->exception.severity != UndefinedException)
1668 CatchException(&images->exception);
1669 (void) XSetErrorHandler(XError);
1670 resource_database=XGetResourceDatabase(display,GetClientName());
1671 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1672 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1673 if (image_info->page != (char *) NULL)
1674 resource_info.image_geometry=AcquireString(image_info->page);
1675 resource_info.immutable=MagickTrue;
1676 argv[0]=AcquireString(GetClientName());
1678 for (i=0; (state & ExitState) == 0; i++)
1680 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1682 image=GetImageFromList(images,i % GetImageListLength(images));
1683 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1685 argv[0]=DestroyString(argv[0]);
1686 (void) XCloseDisplay(display);
1687 XDestroyResourceInfo(&resource_info);
1688 if (images->exception.severity != UndefinedException)
1689 return(MagickFalse);
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698 % R e m o t e D i s p l a y C o m m a n d %
1702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704 % RemoteDisplayCommand() encourages a remote display program to display the
1705 % specified image filename.
1707 % The format of the RemoteDisplayCommand method is:
1709 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1710 % const char *window,const char *filename,ExceptionInfo *exception)
1712 % A description of each parameter follows:
1714 % o image_info: the image info.
1716 % o window: Specifies the name or id of an X window.
1718 % o filename: the name of the image filename to display.
1720 % o exception: return any errors or warnings in this structure.
1723 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1724 const char *window,const char *filename,ExceptionInfo *exception)
1732 assert(image_info != (const ImageInfo *) NULL);
1733 assert(image_info->signature == MagickSignature);
1734 assert(filename != (char *) NULL);
1735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1736 display=XOpenDisplay(image_info->server_name);
1737 if (display == (Display *) NULL)
1739 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1740 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1741 return(MagickFalse);
1743 (void) XSetErrorHandler(XError);
1744 status=XRemoteCommand(display,window,filename);
1745 (void) XCloseDisplay(display);
1746 return(status != 0 ? MagickTrue : MagickFalse);
1750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 + X A n n o t a t e E d i t I m a g e %
1758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760 % XAnnotateEditImage() annotates the image with text.
1762 % The format of the XAnnotateEditImage method is:
1764 % MagickBooleanType XAnnotateEditImage(Display *display,
1765 % XResourceInfo *resource_info,XWindows *windows,Image *image)
1767 % A description of each parameter follows:
1769 % o display: Specifies a connection to an X server; returned from
1772 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1774 % o windows: Specifies a pointer to a XWindows structure.
1776 % o image: the image; returned from ReadImage.
1780 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1787 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1794 static MagickBooleanType XAnnotateEditImage(Display *display,
1795 XResourceInfo *resource_info,XWindows *windows,Image *image)
1815 static const ModeType
1816 AnnotateCommands[] =
1818 AnnotateNameCommand,
1819 AnnotateFontColorCommand,
1820 AnnotateBackgroundColorCommand,
1821 AnnotateRotateCommand,
1822 AnnotateHelpCommand,
1823 AnnotateDismissCommand
1831 static MagickBooleanType
1832 transparent_box = MagickTrue,
1833 transparent_pen = MagickFalse;
1835 static MagickRealType
1839 box_id = MaxNumberPens-2,
1844 command[MaxTextExtent],
1845 text[MaxTextExtent];
1848 *ColorMenu[MaxNumberPens+1];
1896 (void) CloneString(&windows->command.name,"Annotate");
1897 windows->command.data=4;
1898 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1899 (void) XMapRaised(display,windows->command.id);
1900 XClientMessage(display,windows->image.id,windows->im_protocols,
1901 windows->im_update_widget,CurrentTime);
1903 Track pointer until button 1 is pressed.
1905 XQueryPosition(display,windows->image.id,&x,&y);
1906 (void) XSelectInput(display,windows->image.id,
1907 windows->image.attributes.event_mask | PointerMotionMask);
1908 cursor=XCreateFontCursor(display,XC_left_side);
1909 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1913 if (windows->info.mapped != MagickFalse)
1916 Display pointer position.
1918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
1919 x+windows->image.x,y+windows->image.y);
1920 XInfoWidget(display,windows,text);
1923 Wait for next event.
1925 XScreenEvent(display,windows,&event);
1926 if (event.xany.window == windows->command.id)
1929 Select a command from the Command widget.
1931 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1932 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1935 switch (AnnotateCommands[id])
1937 case AnnotateNameCommand:
1940 *FontMenu[MaxNumberFonts];
1946 Initialize menu selections.
1948 for (i=0; i < MaxNumberFonts; i++)
1949 FontMenu[i]=resource_info->font_name[i];
1950 FontMenu[MaxNumberFonts-2]="Browser...";
1951 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1953 Select a font name from the pop-up menu.
1955 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1956 (const char **) FontMenu,command);
1957 if (font_number < 0)
1959 if (font_number == (MaxNumberFonts-2))
1962 font_name[MaxTextExtent] = "fixed";
1965 Select a font name from a browser.
1967 resource_info->font_name[font_number]=font_name;
1968 XFontBrowserWidget(display,windows,"Select",font_name);
1969 if (*font_name == '\0')
1973 Initialize font info.
1975 font_info=XLoadQueryFont(display,resource_info->font_name[
1977 if (font_info == (XFontStruct *) NULL)
1979 XNoticeWidget(display,windows,"Unable to load font:",
1980 resource_info->font_name[font_number]);
1983 font_id=(unsigned int) font_number;
1984 (void) XFreeFont(display,font_info);
1987 case AnnotateFontColorCommand:
1990 Initialize menu selections.
1992 for (i=0; i < (int) (MaxNumberPens-2); i++)
1993 ColorMenu[i]=resource_info->pen_colors[i];
1994 ColorMenu[MaxNumberPens-2]="transparent";
1995 ColorMenu[MaxNumberPens-1]="Browser...";
1996 ColorMenu[MaxNumberPens]=(const char *) NULL;
1998 Select a pen color from the pop-up menu.
2000 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2001 (const char **) ColorMenu,command);
2004 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2006 if (transparent_pen != MagickFalse)
2008 if (pen_number == (MaxNumberPens-1))
2011 color_name[MaxTextExtent] = "gray";
2014 Select a pen color from a dialog.
2016 resource_info->pen_colors[pen_number]=color_name;
2017 XColorBrowserWidget(display,windows,"Select",color_name);
2018 if (*color_name == '\0')
2024 (void) XParseColor(display,windows->map_info->colormap,
2025 resource_info->pen_colors[pen_number],&color);
2026 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2027 (unsigned int) MaxColors,&color);
2028 windows->pixel_info->pen_colors[pen_number]=color;
2029 pen_id=(unsigned int) pen_number;
2032 case AnnotateBackgroundColorCommand:
2035 Initialize menu selections.
2037 for (i=0; i < (int) (MaxNumberPens-2); i++)
2038 ColorMenu[i]=resource_info->pen_colors[i];
2039 ColorMenu[MaxNumberPens-2]="transparent";
2040 ColorMenu[MaxNumberPens-1]="Browser...";
2041 ColorMenu[MaxNumberPens]=(const char *) NULL;
2043 Select a pen color from the pop-up menu.
2045 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2046 (const char **) ColorMenu,command);
2049 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2051 if (transparent_box != MagickFalse)
2053 if (pen_number == (MaxNumberPens-1))
2056 color_name[MaxTextExtent] = "gray";
2059 Select a pen color from a dialog.
2061 resource_info->pen_colors[pen_number]=color_name;
2062 XColorBrowserWidget(display,windows,"Select",color_name);
2063 if (*color_name == '\0')
2069 (void) XParseColor(display,windows->map_info->colormap,
2070 resource_info->pen_colors[pen_number],&color);
2071 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2072 (unsigned int) MaxColors,&color);
2073 windows->pixel_info->pen_colors[pen_number]=color;
2074 box_id=(unsigned int) pen_number;
2077 case AnnotateRotateCommand:
2083 angle[MaxTextExtent] = "30.0";
2101 Select a command from the pop-up menu.
2103 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2109 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL);
2112 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2116 degrees=InterpretLocaleValue(angle,(char **) NULL);
2119 case AnnotateHelpCommand:
2121 XTextViewWidget(display,resource_info,windows,MagickFalse,
2122 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2125 case AnnotateDismissCommand:
2143 if (event.xbutton.button != Button1)
2145 if (event.xbutton.window != windows->image.id)
2148 Change to text entering mode.
2161 if (event.xkey.window != windows->image.id)
2164 Respond to a user key press.
2166 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2167 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2168 switch ((int) key_symbol)
2183 XTextViewWidget(display,resource_info,windows,MagickFalse,
2184 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2189 (void) XBell(display,0);
2198 Map and unmap Info widget as cursor crosses its boundaries.
2202 if (windows->info.mapped != MagickFalse)
2204 if ((x < (int) (windows->info.x+windows->info.width)) &&
2205 (y < (int) (windows->info.y+windows->info.height)))
2206 (void) XWithdrawWindow(display,windows->info.id,
2207 windows->info.screen);
2210 if ((x > (int) (windows->info.x+windows->info.width)) ||
2211 (y > (int) (windows->info.y+windows->info.height)))
2212 (void) XMapWindow(display,windows->info.id);
2218 } while ((state & ExitState) == 0);
2219 (void) XSelectInput(display,windows->image.id,
2220 windows->image.attributes.event_mask);
2221 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2222 if ((state & EscapeState) != 0)
2225 Set font info and check boundary conditions.
2227 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2228 if (font_info == (XFontStruct *) NULL)
2230 XNoticeWidget(display,windows,"Unable to load font:",
2231 resource_info->font_name[font_id]);
2232 font_info=windows->font_info;
2234 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2235 x=(int) windows->image.width-font_info->max_bounds.width;
2236 if (y < (int) (font_info->ascent+font_info->descent))
2237 y=(int) font_info->ascent+font_info->descent;
2238 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2239 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2240 return(MagickFalse);
2242 Initialize annotate structure.
2244 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2245 if (annotate_info == (XAnnotateInfo *) NULL)
2246 return(MagickFalse);
2247 XGetAnnotateInfo(annotate_info);
2250 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2251 annotate_info->stencil=OpaqueStencil;
2253 if (transparent_box == MagickFalse)
2254 annotate_info->stencil=BackgroundStencil;
2256 annotate_info->stencil=ForegroundStencil;
2257 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2258 annotate_info->degrees=degrees;
2259 annotate_info->font_info=font_info;
2260 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2261 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2262 sizeof(*annotate_info->text));
2263 if (annotate_info->text == (char *) NULL)
2264 return(MagickFalse);
2266 Create cursor and set graphic context.
2268 cursor=XCreateFontCursor(display,XC_pencil);
2269 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2270 annotate_context=windows->image.annotate_context;
2271 (void) XSetFont(display,annotate_context,font_info->fid);
2272 (void) XSetBackground(display,annotate_context,
2273 windows->pixel_info->pen_colors[box_id].pixel);
2274 (void) XSetForeground(display,annotate_context,
2275 windows->pixel_info->pen_colors[pen_id].pixel);
2277 Begin annotating the image with text.
2279 (void) CloneString(&windows->command.name,"Text");
2280 windows->command.data=0;
2281 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2283 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2284 text_event.xexpose.width=(int) font_info->max_bounds.width;
2285 text_event.xexpose.height=font_info->max_bounds.ascent+
2286 font_info->max_bounds.descent;
2287 p=annotate_info->text;
2291 Display text cursor.
2294 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2296 Wait for next event.
2298 XScreenEvent(display,windows,&event);
2299 if (event.xany.window == windows->command.id)
2302 Select a command from the Command widget.
2304 (void) XSetBackground(display,annotate_context,
2305 windows->pixel_info->background_color.pixel);
2306 (void) XSetForeground(display,annotate_context,
2307 windows->pixel_info->foreground_color.pixel);
2308 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2309 (void) XSetBackground(display,annotate_context,
2310 windows->pixel_info->pen_colors[box_id].pixel);
2311 (void) XSetForeground(display,annotate_context,
2312 windows->pixel_info->pen_colors[pen_id].pixel);
2315 switch (TextCommands[id])
2317 case TextHelpCommand:
2319 XTextViewWidget(display,resource_info,windows,MagickFalse,
2320 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2321 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2324 case TextApplyCommand:
2327 Finished annotating.
2329 annotate_info->width=(unsigned int) XTextWidth(font_info,
2330 annotate_info->text,(int) strlen(annotate_info->text));
2331 XRefreshWindow(display,&windows->image,&text_event);
2343 text_event.xexpose.x=x;
2344 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2345 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2346 (unsigned int) text_event.xexpose.width,(unsigned int)
2347 text_event.xexpose.height,MagickFalse);
2348 XRefreshWindow(display,&windows->image,&text_event);
2353 if (event.xbutton.window != windows->image.id)
2355 if (event.xbutton.button == Button2)
2358 Request primary selection.
2360 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2361 windows->image.id,CurrentTime);
2368 if (event.xexpose.count == 0)
2374 Refresh Image window.
2376 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2377 text_info=annotate_info;
2378 while (text_info != (XAnnotateInfo *) NULL)
2380 if (annotate_info->stencil == ForegroundStencil)
2381 (void) XDrawString(display,windows->image.id,annotate_context,
2382 text_info->x,text_info->y,text_info->text,
2383 (int) strlen(text_info->text));
2385 (void) XDrawImageString(display,windows->image.id,
2386 annotate_context,text_info->x,text_info->y,text_info->text,
2387 (int) strlen(text_info->text));
2388 text_info=text_info->previous;
2390 (void) XDrawString(display,windows->image.id,annotate_context,
2400 if (event.xkey.window != windows->image.id)
2403 Respond to a user key press.
2405 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2406 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2407 *(command+length)='\0';
2408 if (((event.xkey.state & ControlMask) != 0) ||
2409 ((event.xkey.state & Mod1Mask) != 0))
2410 state|=ModifierState;
2411 if ((state & ModifierState) != 0)
2412 switch ((int) key_symbol)
2417 key_symbol=DeleteCommand;
2423 switch ((int) key_symbol)
2428 Erase one character.
2430 if (p == annotate_info->text)
2432 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2437 Go to end of the previous line of text.
2439 annotate_info=annotate_info->previous;
2440 p=annotate_info->text;
2441 x=annotate_info->x+annotate_info->width;
2443 if (annotate_info->width != 0)
2444 p+=strlen(annotate_info->text);
2449 x-=XTextWidth(font_info,p,1);
2450 text_event.xexpose.x=x;
2451 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2452 XRefreshWindow(display,&windows->image,&text_event);
2455 case XK_bracketleft:
2457 key_symbol=XK_Escape;
2463 Erase the entire line of text.
2465 while (p != annotate_info->text)
2468 x-=XTextWidth(font_info,p,1);
2469 text_event.xexpose.x=x;
2470 XRefreshWindow(display,&windows->image,&text_event);
2478 Finished annotating.
2480 annotate_info->width=(unsigned int) XTextWidth(font_info,
2481 annotate_info->text,(int) strlen(annotate_info->text));
2482 XRefreshWindow(display,&windows->image,&text_event);
2489 Draw a single character on the Image window.
2491 if ((state & ModifierState) != 0)
2493 if (*command == '\0')
2496 if (annotate_info->stencil == ForegroundStencil)
2497 (void) XDrawString(display,windows->image.id,annotate_context,
2500 (void) XDrawImageString(display,windows->image.id,
2501 annotate_context,x,y,p,1);
2502 x+=XTextWidth(font_info,p,1);
2504 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2511 Advance to the next line of text.
2514 annotate_info->width=(unsigned int) XTextWidth(font_info,
2515 annotate_info->text,(int) strlen(annotate_info->text));
2516 if (annotate_info->next != (XAnnotateInfo *) NULL)
2519 Line of text already exists.
2521 annotate_info=annotate_info->next;
2524 p=annotate_info->text;
2527 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2528 sizeof(*annotate_info->next));
2529 if (annotate_info->next == (XAnnotateInfo *) NULL)
2530 return(MagickFalse);
2531 *annotate_info->next=(*annotate_info);
2532 annotate_info->next->previous=annotate_info;
2533 annotate_info=annotate_info->next;
2534 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2535 windows->image.width/MagickMax((ssize_t)
2536 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2537 if (annotate_info->text == (char *) NULL)
2538 return(MagickFalse);
2539 annotate_info->y+=annotate_info->height;
2540 if (annotate_info->y > (int) windows->image.height)
2541 annotate_info->y=(int) annotate_info->height;
2542 annotate_info->next=(XAnnotateInfo *) NULL;
2545 p=annotate_info->text;
2554 Respond to a user key release.
2556 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2557 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2558 state&=(~ModifierState);
2561 case SelectionNotify:
2577 Obtain response from primary selection.
2579 if (event.xselection.property == (Atom) None)
2581 status=XGetWindowProperty(display,event.xselection.requestor,
2582 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2583 &type,&format,&length,&after,&data);
2584 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2588 Annotate Image window with primary selection.
2590 for (i=0; i < (ssize_t) length; i++)
2592 if ((char) data[i] != '\n')
2595 Draw a single character on the Image window.
2598 (void) XDrawString(display,windows->image.id,annotate_context,
2600 x+=XTextWidth(font_info,p,1);
2602 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2606 Advance to the next line of text.
2609 annotate_info->width=(unsigned int) XTextWidth(font_info,
2610 annotate_info->text,(int) strlen(annotate_info->text));
2611 if (annotate_info->next != (XAnnotateInfo *) NULL)
2614 Line of text already exists.
2616 annotate_info=annotate_info->next;
2619 p=annotate_info->text;
2622 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2623 sizeof(*annotate_info->next));
2624 if (annotate_info->next == (XAnnotateInfo *) NULL)
2625 return(MagickFalse);
2626 *annotate_info->next=(*annotate_info);
2627 annotate_info->next->previous=annotate_info;
2628 annotate_info=annotate_info->next;
2629 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2630 windows->image.width/MagickMax((ssize_t)
2631 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2632 if (annotate_info->text == (char *) NULL)
2633 return(MagickFalse);
2634 annotate_info->y+=annotate_info->height;
2635 if (annotate_info->y > (int) windows->image.height)
2636 annotate_info->y=(int) annotate_info->height;
2637 annotate_info->next=(XAnnotateInfo *) NULL;
2640 p=annotate_info->text;
2642 (void) XFree((void *) data);
2648 } while ((state & ExitState) == 0);
2649 (void) XFreeCursor(display,cursor);
2651 Annotation is relative to image configuration.
2653 width=(unsigned int) image->columns;
2654 height=(unsigned int) image->rows;
2657 if (windows->image.crop_geometry != (char *) NULL)
2658 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2660 Initialize annotated image.
2662 XSetCursorState(display,windows,MagickTrue);
2663 XCheckRefreshWindows(display,windows);
2664 while (annotate_info != (XAnnotateInfo *) NULL)
2666 if (annotate_info->width == 0)
2669 No text on this line-- go to the next line of text.
2671 previous_info=annotate_info->previous;
2672 annotate_info->text=(char *)
2673 RelinquishMagickMemory(annotate_info->text);
2674 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2675 annotate_info=previous_info;
2679 Determine pixel index for box and pen color.
2681 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2682 if (windows->pixel_info->colors != 0)
2683 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2684 if (windows->pixel_info->pixels[i] ==
2685 windows->pixel_info->pen_colors[box_id].pixel)
2687 windows->pixel_info->box_index=(unsigned short) i;
2690 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2691 if (windows->pixel_info->colors != 0)
2692 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2693 if (windows->pixel_info->pixels[i] ==
2694 windows->pixel_info->pen_colors[pen_id].pixel)
2696 windows->pixel_info->pen_index=(unsigned short) i;
2700 Define the annotate geometry string.
2702 annotate_info->x=(int)
2703 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2704 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2705 windows->image.y)/windows->image.ximage->height;
2706 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
2707 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2708 height*annotate_info->height/windows->image.ximage->height,
2709 annotate_info->x+x,annotate_info->y+y);
2711 Annotate image with text.
2713 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2715 return(MagickFalse);
2719 previous_info=annotate_info->previous;
2720 annotate_info->text=DestroyString(annotate_info->text);
2721 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2722 annotate_info=previous_info;
2724 (void) XSetForeground(display,annotate_context,
2725 windows->pixel_info->foreground_color.pixel);
2726 (void) XSetBackground(display,annotate_context,
2727 windows->pixel_info->background_color.pixel);
2728 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2729 XSetCursorState(display,windows,MagickFalse);
2730 (void) XFreeFont(display,font_info);
2732 Update image configuration.
2734 XConfigureImageColormap(display,resource_info,windows,image);
2735 (void) XConfigureImage(display,resource_info,windows,image);
2740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744 + X B a c k g r o u n d I m a g e %
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2750 % XBackgroundImage() displays the image in the background of a window.
2752 % The format of the XBackgroundImage method is:
2754 % MagickBooleanType XBackgroundImage(Display *display,
2755 % XResourceInfo *resource_info,XWindows *windows,Image **image)
2757 % A description of each parameter follows:
2759 % o display: Specifies a connection to an X server; returned from
2762 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2764 % o windows: Specifies a pointer to a XWindows structure.
2766 % o image: the image.
2769 static MagickBooleanType XBackgroundImage(Display *display,
2770 XResourceInfo *resource_info,XWindows *windows,Image **image)
2772 #define BackgroundImageTag "Background/Image"
2778 window_id[MaxTextExtent] = "root";
2781 background_resources;
2784 Put image in background.
2786 status=XDialogWidget(display,windows,"Background",
2787 "Enter window id (id 0x00 selects window with pointer):",window_id);
2788 if (*window_id == '\0')
2789 return(MagickFalse);
2790 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2791 XInfoWidget(display,windows,BackgroundImageTag);
2792 XSetCursorState(display,windows,MagickTrue);
2793 XCheckRefreshWindows(display,windows);
2794 background_resources=(*resource_info);
2795 background_resources.window_id=window_id;
2796 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2797 status=XDisplayBackgroundImage(display,&background_resources,*image);
2798 if (status != MagickFalse)
2799 XClientMessage(display,windows->image.id,windows->im_protocols,
2800 windows->im_retain_colors,CurrentTime);
2801 XSetCursorState(display,windows,MagickFalse);
2802 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2811 + X C h o p I m a g e %
2815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2817 % XChopImage() chops the X image.
2819 % The format of the XChopImage method is:
2821 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2822 % XWindows *windows,Image **image)
2824 % A description of each parameter follows:
2826 % o display: Specifies a connection to an X server; returned from
2829 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2831 % o windows: Specifies a pointer to a XWindows structure.
2833 % o image: the image.
2836 static MagickBooleanType XChopImage(Display *display,
2837 XResourceInfo *resource_info,XWindows *windows,Image **image)
2849 direction = HorizontalChopCommand;
2851 static const ModeType
2854 ChopDirectionCommand,
2858 DirectionCommands[] =
2860 HorizontalChopCommand,
2865 text[MaxTextExtent];
2898 (void) CloneString(&windows->command.name,"Chop");
2899 windows->command.data=1;
2900 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2901 (void) XMapRaised(display,windows->command.id);
2902 XClientMessage(display,windows->image.id,windows->im_protocols,
2903 windows->im_update_widget,CurrentTime);
2905 Track pointer until button 1 is pressed.
2907 XQueryPosition(display,windows->image.id,&x,&y);
2908 (void) XSelectInput(display,windows->image.id,
2909 windows->image.attributes.event_mask | PointerMotionMask);
2913 if (windows->info.mapped != MagickFalse)
2916 Display pointer position.
2918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
2919 x+windows->image.x,y+windows->image.y);
2920 XInfoWidget(display,windows,text);
2923 Wait for next event.
2925 XScreenEvent(display,windows,&event);
2926 if (event.xany.window == windows->command.id)
2929 Select a command from the Command widget.
2931 id=XCommandWidget(display,windows,ChopMenu,&event);
2934 switch (ChopCommands[id])
2936 case ChopDirectionCommand:
2939 command[MaxTextExtent];
2950 Select a command from the pop-up menu.
2952 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2954 direction=DirectionCommands[id];
2957 case ChopHelpCommand:
2959 XTextViewWidget(display,resource_info,windows,MagickFalse,
2960 "Help Viewer - Image Chop",ImageChopHelp);
2963 case ChopDismissCommand:
2981 if (event.xbutton.button != Button1)
2983 if (event.xbutton.window != windows->image.id)
2986 User has committed to start point of chopping line.
2988 segment_info.x1=(short int) event.xbutton.x;
2989 segment_info.x2=(short int) event.xbutton.x;
2990 segment_info.y1=(short int) event.xbutton.y;
2991 segment_info.y2=(short int) event.xbutton.y;
3002 command[MaxTextExtent];
3007 if (event.xkey.window != windows->image.id)
3010 Respond to a user key press.
3012 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3013 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3014 switch ((int) key_symbol)
3029 (void) XSetFunction(display,windows->image.highlight_context,
3031 XTextViewWidget(display,resource_info,windows,MagickFalse,
3032 "Help Viewer - Image Chop",ImageChopHelp);
3033 (void) XSetFunction(display,windows->image.highlight_context,
3039 (void) XBell(display,0);
3048 Map and unmap Info widget as text cursor crosses its boundaries.
3052 if (windows->info.mapped != MagickFalse)
3054 if ((x < (int) (windows->info.x+windows->info.width)) &&
3055 (y < (int) (windows->info.y+windows->info.height)))
3056 (void) XWithdrawWindow(display,windows->info.id,
3057 windows->info.screen);
3060 if ((x > (int) (windows->info.x+windows->info.width)) ||
3061 (y > (int) (windows->info.y+windows->info.height)))
3062 (void) XMapWindow(display,windows->info.id);
3065 } while ((state & ExitState) == 0);
3066 (void) XSelectInput(display,windows->image.id,
3067 windows->image.attributes.event_mask);
3068 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3069 if ((state & EscapeState) != 0)
3072 Draw line as pointer moves until the mouse button is released.
3079 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3086 Display info and draw chopping line.
3088 if (windows->info.mapped == MagickFalse)
3089 (void) XMapWindow(display,windows->info.id);
3090 (void) FormatLocaleString(text,MaxTextExtent,
3091 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3092 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3093 XInfoWidget(display,windows,text);
3094 XHighlightLine(display,windows->image.id,
3095 windows->image.highlight_context,&segment_info);
3098 if (windows->info.mapped != MagickFalse)
3099 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3101 Wait for next event.
3103 XScreenEvent(display,windows,&event);
3105 XHighlightLine(display,windows->image.id,
3106 windows->image.highlight_context,&segment_info);
3111 segment_info.x2=(short int) event.xmotion.x;
3112 segment_info.y2=(short int) event.xmotion.y;
3118 User has committed to chopping line.
3120 segment_info.x2=(short int) event.xbutton.x;
3121 segment_info.y2=(short int) event.xbutton.y;
3129 segment_info.x2=(short int) event.xmotion.x;
3130 segment_info.y2=(short int) event.xmotion.y;
3136 Check boundary conditions.
3138 if (segment_info.x2 < 0)
3141 if (segment_info.x2 > windows->image.ximage->width)
3142 segment_info.x2=windows->image.ximage->width;
3143 if (segment_info.y2 < 0)
3146 if (segment_info.y2 > windows->image.ximage->height)
3147 segment_info.y2=windows->image.ximage->height;
3148 distance=(unsigned int)
3149 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3150 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3152 Compute chopping geometry.
3154 if (direction == HorizontalChopCommand)
3156 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3157 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3160 if (segment_info.x1 > (int) segment_info.x2)
3162 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3163 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3169 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3171 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3172 if (segment_info.y1 > segment_info.y2)
3174 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3175 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3178 } while ((state & ExitState) == 0);
3179 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3180 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3184 Image chopping is relative to image configuration.
3186 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3187 XSetCursorState(display,windows,MagickTrue);
3188 XCheckRefreshWindows(display,windows);
3189 windows->image.window_changes.width=windows->image.ximage->width-
3190 (unsigned int) chop_info.width;
3191 windows->image.window_changes.height=windows->image.ximage->height-
3192 (unsigned int) chop_info.height;
3193 width=(unsigned int) (*image)->columns;
3194 height=(unsigned int) (*image)->rows;
3197 if (windows->image.crop_geometry != (char *) NULL)
3198 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3199 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3201 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3202 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3203 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3205 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3206 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3210 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3211 XSetCursorState(display,windows,MagickFalse);
3212 if (chop_image == (Image *) NULL)
3213 return(MagickFalse);
3214 *image=DestroyImage(*image);
3217 Update image configuration.
3219 XConfigureImageColormap(display,resource_info,windows,*image);
3220 (void) XConfigureImage(display,resource_info,windows,*image);
3225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3229 + X C o l o r E d i t I m a g e %
3233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3235 % XColorEditImage() allows the user to interactively change the color of one
3236 % pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3238 % The format of the XColorEditImage method is:
3240 % MagickBooleanType XColorEditImage(Display *display,
3241 % XResourceInfo *resource_info,XWindows *windows,Image **image)
3243 % A description of each parameter follows:
3245 % o display: Specifies a connection to an X server; returned from
3248 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3250 % o windows: Specifies a pointer to a XWindows structure.
3252 % o image: the image; returned from ReadImage.
3257 static MagickBooleanType XColorEditImage(Display *display,
3258 XResourceInfo *resource_info,XWindows *windows,Image **image)
3273 static const ModeType
3274 ColorEditCommands[] =
3276 ColorEditMethodCommand,
3277 ColorEditColorCommand,
3278 ColorEditBorderCommand,
3279 ColorEditFuzzCommand,
3280 ColorEditUndoCommand,
3281 ColorEditHelpCommand,
3282 ColorEditDismissCommand
3286 method = PointMethod;
3292 border_color = { 0, 0, 0, 0, 0, 0 };
3295 command[MaxTextExtent],
3296 text[MaxTextExtent];
3334 (void) CloneString(&windows->command.name,"Color Edit");
3335 windows->command.data=4;
3336 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3337 (void) XMapRaised(display,windows->command.id);
3338 XClientMessage(display,windows->image.id,windows->im_protocols,
3339 windows->im_update_widget,CurrentTime);
3343 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3344 resource_info->background_color,resource_info->foreground_color);
3345 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3347 Track pointer until button 1 is pressed.
3349 XQueryPosition(display,windows->image.id,&x,&y);
3350 (void) XSelectInput(display,windows->image.id,
3351 windows->image.attributes.event_mask | PointerMotionMask);
3355 if (windows->info.mapped != MagickFalse)
3358 Display pointer position.
3360 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
3361 x+windows->image.x,y+windows->image.y);
3362 XInfoWidget(display,windows,text);
3365 Wait for next event.
3367 XScreenEvent(display,windows,&event);
3368 if (event.xany.window == windows->command.id)
3371 Select a command from the Command widget.
3373 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3376 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3379 switch (ColorEditCommands[id])
3381 case ColorEditMethodCommand:
3387 Select a method from the pop-up menu.
3389 methods=(char **) GetCommandOptions(MagickMethodOptions);
3390 if (methods == (char **) NULL)
3392 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3393 (const char **) methods,command);
3395 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3396 MagickFalse,methods[entry]);
3397 methods=DestroyStringList(methods);
3400 case ColorEditColorCommand:
3403 *ColorMenu[MaxNumberPens];
3409 Initialize menu selections.
3411 for (i=0; i < (int) (MaxNumberPens-2); i++)
3412 ColorMenu[i]=resource_info->pen_colors[i];
3413 ColorMenu[MaxNumberPens-2]="Browser...";
3414 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3416 Select a pen color from the pop-up menu.
3418 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3419 (const char **) ColorMenu,command);
3422 if (pen_number == (MaxNumberPens-2))
3425 color_name[MaxTextExtent] = "gray";
3428 Select a pen color from a dialog.
3430 resource_info->pen_colors[pen_number]=color_name;
3431 XColorBrowserWidget(display,windows,"Select",color_name);
3432 if (*color_name == '\0')
3438 (void) XParseColor(display,windows->map_info->colormap,
3439 resource_info->pen_colors[pen_number],&color);
3440 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3441 (unsigned int) MaxColors,&color);
3442 windows->pixel_info->pen_colors[pen_number]=color;
3443 pen_id=(unsigned int) pen_number;
3446 case ColorEditBorderCommand:
3449 *ColorMenu[MaxNumberPens];
3455 Initialize menu selections.
3457 for (i=0; i < (int) (MaxNumberPens-2); i++)
3458 ColorMenu[i]=resource_info->pen_colors[i];
3459 ColorMenu[MaxNumberPens-2]="Browser...";
3460 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3462 Select a pen color from the pop-up menu.
3464 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3465 (const char **) ColorMenu,command);
3468 if (pen_number == (MaxNumberPens-2))
3471 color_name[MaxTextExtent] = "gray";
3474 Select a pen color from a dialog.
3476 resource_info->pen_colors[pen_number]=color_name;
3477 XColorBrowserWidget(display,windows,"Select",color_name);
3478 if (*color_name == '\0')
3484 (void) XParseColor(display,windows->map_info->colormap,
3485 resource_info->pen_colors[pen_number],&border_color);
3488 case ColorEditFuzzCommand:
3491 fuzz[MaxTextExtent];
3506 Select a command from the pop-up menu.
3508 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3514 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
3518 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3519 (void) XDialogWidget(display,windows,"Ok",
3520 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3523 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
3524 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
3527 case ColorEditUndoCommand:
3529 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3533 case ColorEditHelpCommand:
3536 XTextViewWidget(display,resource_info,windows,MagickFalse,
3537 "Help Viewer - Image Annotation",ImageColorEditHelp);
3540 case ColorEditDismissCommand:
3550 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3557 if (event.xbutton.button != Button1)
3559 if ((event.xbutton.window != windows->image.id) &&
3560 (event.xbutton.window != windows->magnify.id))
3567 (void) XMagickCommand(display,resource_info,windows,
3568 SaveToUndoBufferCommand,image);
3569 state|=UpdateConfigurationState;
3574 if (event.xbutton.button != Button1)
3576 if ((event.xbutton.window != windows->image.id) &&
3577 (event.xbutton.window != windows->magnify.id))
3580 Update colormap information.
3584 XConfigureImageColormap(display,resource_info,windows,*image);
3585 (void) XConfigureImage(display,resource_info,windows,*image);
3586 XInfoWidget(display,windows,text);
3587 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3588 state&=(~UpdateConfigurationState);
3598 if (event.xkey.window == windows->magnify.id)
3603 window=windows->magnify.id;
3604 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3606 if (event.xkey.window != windows->image.id)
3609 Respond to a user key press.
3611 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3612 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3613 switch ((int) key_symbol)
3627 XTextViewWidget(display,resource_info,windows,MagickFalse,
3628 "Help Viewer - Image Annotation",ImageColorEditHelp);
3633 (void) XBell(display,0);
3642 Map and unmap Info widget as cursor crosses its boundaries.
3646 if (windows->info.mapped != MagickFalse)
3648 if ((x < (int) (windows->info.x+windows->info.width)) &&
3649 (y < (int) (windows->info.y+windows->info.height)))
3650 (void) XWithdrawWindow(display,windows->info.id,
3651 windows->info.screen);
3654 if ((x > (int) (windows->info.x+windows->info.width)) ||
3655 (y > (int) (windows->info.y+windows->info.height)))
3656 (void) XMapWindow(display,windows->info.id);
3662 if (event.xany.window == windows->magnify.id)
3664 x=windows->magnify.x-windows->image.x;
3665 y=windows->magnify.y-windows->image.y;
3669 if ((state & UpdateConfigurationState) != 0)
3679 Pixel edit is relative to image configuration.
3681 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3683 color=windows->pixel_info->pen_colors[pen_id];
3684 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3685 width=(unsigned int) (*image)->columns;
3686 height=(unsigned int) (*image)->rows;
3689 if (windows->image.crop_geometry != (char *) NULL)
3690 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3693 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3695 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3696 if ((x_offset < 0) || (y_offset < 0))
3698 if ((x_offset >= (int) (*image)->columns) ||
3699 (y_offset >= (int) (*image)->rows))
3701 exception=(&(*image)->exception);
3702 image_view=AcquireCacheView(*image);
3709 Update color information using point algorithm.
3711 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3712 return(MagickFalse);
3713 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3714 (ssize_t) y_offset,1,1,exception);
3715 if (q == (Quantum *) NULL)
3717 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3718 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3719 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3720 (void) SyncCacheViewAuthenticPixels(image_view,
3721 &(*image)->exception);
3731 Update color information using replace algorithm.
3733 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
3734 (ssize_t) y_offset,&target,&(*image)->exception);
3735 if ((*image)->storage_class == DirectClass)
3737 for (y=0; y < (int) (*image)->rows; y++)
3739 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3740 (*image)->columns,1,exception);
3741 if (q == (Quantum *) NULL)
3743 for (x=0; x < (int) (*image)->columns; x++)
3745 GetPixelPacket(*image,q,&pixel);
3746 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
3748 SetPixelRed(*image,ScaleShortToQuantum(
3750 SetPixelGreen(*image,ScaleShortToQuantum(
3752 SetPixelBlue(*image,ScaleShortToQuantum(
3755 q+=GetPixelChannels(*image);
3757 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3763 for (i=0; i < (ssize_t) (*image)->colors; i++)
3764 if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target))
3766 (*image)->colormap[i].red=ScaleShortToQuantum(
3768 (*image)->colormap[i].green=ScaleShortToQuantum(
3770 (*image)->colormap[i].blue=ScaleShortToQuantum(
3773 (void) SyncImage(*image);
3777 case FloodfillMethod:
3778 case FillToBorderMethod:
3787 Update color information using floodfill algorithm.
3789 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3790 (ssize_t) y_offset,&target,exception);
3791 if (method == FillToBorderMethod)
3793 target.red=(MagickRealType)
3794 ScaleShortToQuantum(border_color.red);
3795 target.green=(MagickRealType)
3796 ScaleShortToQuantum(border_color.green);
3797 target.blue=(MagickRealType)
3798 ScaleShortToQuantum(border_color.blue);
3800 draw_info=CloneDrawInfo(resource_info->image_info,
3802 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3803 &draw_info->fill,exception);
3804 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
3805 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
3806 MagickFalse : MagickTrue,exception);
3807 draw_info=DestroyDrawInfo(draw_info);
3813 Update color information using reset algorithm.
3815 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3816 return(MagickFalse);
3817 for (y=0; y < (int) (*image)->rows; y++)
3819 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3820 (*image)->columns,1,exception);
3821 if (q == (Quantum *) NULL)
3823 for (x=0; x < (int) (*image)->columns; x++)
3825 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3826 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3827 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3828 q+=GetPixelChannels(*image);
3830 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3836 image_view=DestroyCacheView(image_view);
3837 state&=(~UpdateConfigurationState);
3839 } while ((state & ExitState) == 0);
3840 (void) XSelectInput(display,windows->image.id,
3841 windows->image.attributes.event_mask);
3842 XSetCursorState(display,windows,MagickFalse);
3843 (void) XFreeCursor(display,cursor);
3848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3852 + X C o m p o s i t e I m a g e %
3856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858 % XCompositeImage() requests an image name from the user, reads the image and
3859 % composites it with the X window image at a location the user chooses with
3862 % The format of the XCompositeImage method is:
3864 % MagickBooleanType XCompositeImage(Display *display,
3865 % XResourceInfo *resource_info,XWindows *windows,Image *image)
3867 % A description of each parameter follows:
3869 % o display: Specifies a connection to an X server; returned from
3872 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3874 % o windows: Specifies a pointer to a XWindows structure.
3876 % o image: the image; returned from ReadImage.
3879 static MagickBooleanType XCompositeImage(Display *display,
3880 XResourceInfo *resource_info,XWindows *windows,Image *image)
3883 displacement_geometry[MaxTextExtent] = "30x30",
3884 filename[MaxTextExtent] = "\0";
3897 static CompositeOperator
3898 compose = CopyCompositeOp;
3900 static const ModeType
3901 CompositeCommands[] =
3903 CompositeOperatorsCommand,
3904 CompositeDissolveCommand,
3905 CompositeDisplaceCommand,
3906 CompositeHelpCommand,
3907 CompositeDismissCommand
3911 text[MaxTextExtent];
3944 Request image file name from user.
3946 XFileBrowserWidget(display,windows,"Composite",filename);
3947 if (*filename == '\0')
3952 XSetCursorState(display,windows,MagickTrue);
3953 XCheckRefreshWindows(display,windows);
3954 (void) CopyMagickString(resource_info->image_info->filename,filename,
3956 composite_image=ReadImage(resource_info->image_info,&image->exception);
3957 CatchException(&image->exception);
3958 XSetCursorState(display,windows,MagickFalse);
3959 if (composite_image == (Image *) NULL)
3960 return(MagickFalse);
3964 (void) CloneString(&windows->command.name,"Composite");
3965 windows->command.data=1;
3966 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3967 (void) XMapRaised(display,windows->command.id);
3968 XClientMessage(display,windows->image.id,windows->im_protocols,
3969 windows->im_update_widget,CurrentTime);
3971 Track pointer until button 1 is pressed.
3973 XQueryPosition(display,windows->image.id,&x,&y);
3974 (void) XSelectInput(display,windows->image.id,
3975 windows->image.attributes.event_mask | PointerMotionMask);
3976 composite_info.x=(ssize_t) windows->image.x+x;
3977 composite_info.y=(ssize_t) windows->image.y+y;
3978 composite_info.width=0;
3979 composite_info.height=0;
3980 cursor=XCreateFontCursor(display,XC_ul_angle);
3981 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3986 if (windows->info.mapped != MagickFalse)
3989 Display pointer position.
3991 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
3992 (long) composite_info.x,(long) composite_info.y);
3993 XInfoWidget(display,windows,text);
3995 highlight_info=composite_info;
3996 highlight_info.x=composite_info.x-windows->image.x;
3997 highlight_info.y=composite_info.y-windows->image.y;
3998 XHighlightRectangle(display,windows->image.id,
3999 windows->image.highlight_context,&highlight_info);
4001 Wait for next event.
4003 XScreenEvent(display,windows,&event);
4004 XHighlightRectangle(display,windows->image.id,
4005 windows->image.highlight_context,&highlight_info);
4006 if (event.xany.window == windows->command.id)
4009 Select a command from the Command widget.
4011 id=XCommandWidget(display,windows,CompositeMenu,&event);
4014 switch (CompositeCommands[id])
4016 case CompositeOperatorsCommand:
4019 command[MaxTextExtent],
4023 Select a command from the pop-up menu.
4025 operators=GetCommandOptions(MagickComposeOptions);
4026 if (operators == (char **) NULL)
4028 entry=XMenuWidget(display,windows,CompositeMenu[id],
4029 (const char **) operators,command);
4031 compose=(CompositeOperator) ParseCommandOption(
4032 MagickComposeOptions,MagickFalse,operators[entry]);
4033 operators=DestroyStringList(operators);
4036 case CompositeDissolveCommand:
4039 factor[MaxTextExtent] = "20.0";
4042 Dissolve the two images a given percent.
4044 (void) XSetFunction(display,windows->image.highlight_context,
4046 (void) XDialogWidget(display,windows,"Dissolve",
4047 "Enter the blend factor (0.0 - 99.9%):",factor);
4048 (void) XSetFunction(display,windows->image.highlight_context,
4050 if (*factor == '\0')
4052 blend=InterpretLocaleValue(factor,(char **) NULL);
4053 compose=DissolveCompositeOp;
4056 case CompositeDisplaceCommand:
4059 Get horizontal and vertical scale displacement geometry.
4061 (void) XSetFunction(display,windows->image.highlight_context,
4063 (void) XDialogWidget(display,windows,"Displace",
4064 "Enter the horizontal and vertical scale:",displacement_geometry);
4065 (void) XSetFunction(display,windows->image.highlight_context,
4067 if (*displacement_geometry == '\0')
4069 compose=DisplaceCompositeOp;
4072 case CompositeHelpCommand:
4074 (void) XSetFunction(display,windows->image.highlight_context,
4076 XTextViewWidget(display,resource_info,windows,MagickFalse,
4077 "Help Viewer - Image Composite",ImageCompositeHelp);
4078 (void) XSetFunction(display,windows->image.highlight_context,
4082 case CompositeDismissCommand:
4100 if (image->debug != MagickFalse)
4101 (void) LogMagickEvent(X11Event,GetMagickModule(),
4102 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4103 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4104 if (event.xbutton.button != Button1)
4106 if (event.xbutton.window != windows->image.id)
4111 composite_info.width=composite_image->columns;
4112 composite_info.height=composite_image->rows;
4113 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4114 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4115 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4120 if (image->debug != MagickFalse)
4121 (void) LogMagickEvent(X11Event,GetMagickModule(),
4122 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4123 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4124 if (event.xbutton.button != Button1)
4126 if (event.xbutton.window != windows->image.id)
4128 if ((composite_info.width != 0) && (composite_info.height != 0))
4131 User has selected the location of the composite image.
4133 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4134 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4144 command[MaxTextExtent];
4152 if (event.xkey.window != windows->image.id)
4155 Respond to a user key press.
4157 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4158 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4159 *(command+length)='\0';
4160 if (image->debug != MagickFalse)
4161 (void) LogMagickEvent(X11Event,GetMagickModule(),
4162 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4163 switch ((int) key_symbol)
4171 composite_image=DestroyImage(composite_image);
4179 (void) XSetFunction(display,windows->image.highlight_context,
4181 XTextViewWidget(display,resource_info,windows,MagickFalse,
4182 "Help Viewer - Image Composite",ImageCompositeHelp);
4183 (void) XSetFunction(display,windows->image.highlight_context,
4189 (void) XBell(display,0);
4198 Map and unmap Info widget as text cursor crosses its boundaries.
4202 if (windows->info.mapped != MagickFalse)
4204 if ((x < (int) (windows->info.x+windows->info.width)) &&
4205 (y < (int) (windows->info.y+windows->info.height)))
4206 (void) XWithdrawWindow(display,windows->info.id,
4207 windows->info.screen);
4210 if ((x > (int) (windows->info.x+windows->info.width)) ||
4211 (y > (int) (windows->info.y+windows->info.height)))
4212 (void) XMapWindow(display,windows->info.id);
4213 composite_info.x=(ssize_t) windows->image.x+x;
4214 composite_info.y=(ssize_t) windows->image.y+y;
4219 if (image->debug != MagickFalse)
4220 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4225 } while ((state & ExitState) == 0);
4226 (void) XSelectInput(display,windows->image.id,
4227 windows->image.attributes.event_mask);
4228 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4229 XSetCursorState(display,windows,MagickFalse);
4230 (void) XFreeCursor(display,cursor);
4231 if ((state & EscapeState) != 0)
4234 Image compositing is relative to image configuration.
4236 XSetCursorState(display,windows,MagickTrue);
4237 XCheckRefreshWindows(display,windows);
4238 width=(unsigned int) image->columns;
4239 height=(unsigned int) image->rows;
4242 if (windows->image.crop_geometry != (char *) NULL)
4243 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4244 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4245 composite_info.x+=x;
4246 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4247 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4248 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4249 composite_info.y+=y;
4250 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4251 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4252 if ((composite_info.width != composite_image->columns) ||
4253 (composite_info.height != composite_image->rows))
4259 Scale composite image.
4261 resize_image=ResizeImage(composite_image,composite_info.width,
4262 composite_info.height,composite_image->filter,composite_image->blur,
4264 composite_image=DestroyImage(composite_image);
4265 if (resize_image == (Image *) NULL)
4267 XSetCursorState(display,windows,MagickFalse);
4268 return(MagickFalse);
4270 composite_image=resize_image;
4272 if (compose == DisplaceCompositeOp)
4273 (void) SetImageArtifact(composite_image,"compose:args",
4274 displacement_geometry);
4296 Create mattes for blending.
4298 exception=(&image->exception);
4299 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
4300 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
4301 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
4302 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4303 return(MagickFalse);
4304 image->matte=MagickTrue;
4305 image_view=AcquireCacheView(image);
4306 for (y=0; y < (int) image->rows; y++)
4308 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4310 if (q == (Quantum *) NULL)
4312 for (x=0; x < (int) image->columns; x++)
4314 SetPixelAlpha(image,opacity,q);
4315 q+=GetPixelChannels(image);
4317 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4320 image_view=DestroyCacheView(image_view);
4323 Composite image with X Image window.
4325 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4327 composite_image=DestroyImage(composite_image);
4328 XSetCursorState(display,windows,MagickFalse);
4330 Update image configuration.
4332 XConfigureImageColormap(display,resource_info,windows,image);
4333 (void) XConfigureImage(display,resource_info,windows,image);
4338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4342 + X C o n f i g u r e I m a g e %
4346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348 % XConfigureImage() creates a new X image. It also notifies the window
4349 % manager of the new image size and configures the transient widows.
4351 % The format of the XConfigureImage method is:
4353 % MagickBooleanType XConfigureImage(Display *display,
4354 % XResourceInfo *resource_info,XWindows *windows,Image *image)
4356 % A description of each parameter follows:
4358 % o display: Specifies a connection to an X server; returned from
4361 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4363 % o windows: Specifies a pointer to a XWindows structure.
4365 % o image: the image.
4369 static MagickBooleanType XConfigureImage(Display *display,
4370 XResourceInfo *resource_info,XWindows *windows,Image *image)
4373 geometry[MaxTextExtent];
4394 Dismiss if window dimensions are zero.
4396 width=(unsigned int) windows->image.window_changes.width;
4397 height=(unsigned int) windows->image.window_changes.height;
4398 if (image->debug != MagickFalse)
4399 (void) LogMagickEvent(X11Event,GetMagickModule(),
4400 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4401 windows->image.ximage->height,(double) width,(double) height);
4402 if ((width*height) == 0)
4407 Resize image to fit Image window dimensions.
4409 XSetCursorState(display,windows,MagickTrue);
4410 (void) XFlush(display);
4411 if (((int) width != windows->image.ximage->width) ||
4412 ((int) height != windows->image.ximage->height))
4413 image->taint=MagickTrue;
4414 windows->magnify.x=(int)
4415 width*windows->magnify.x/windows->image.ximage->width;
4416 windows->magnify.y=(int)
4417 height*windows->magnify.y/windows->image.ximage->height;
4418 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4419 windows->image.y=(int)
4420 (height*windows->image.y/windows->image.ximage->height);
4421 status=XMakeImage(display,resource_info,&windows->image,image,
4422 (unsigned int) width,(unsigned int) height);
4423 if (status == MagickFalse)
4424 XNoticeWidget(display,windows,"Unable to configure X image:",
4425 windows->image.name);
4427 Notify window manager of the new configuration.
4429 if (resource_info->image_geometry != (char *) NULL)
4430 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
4431 resource_info->image_geometry);
4433 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4434 XDisplayWidth(display,windows->image.screen),
4435 XDisplayHeight(display,windows->image.screen));
4436 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4437 window_changes.width=(int) width;
4438 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4439 window_changes.width=XDisplayWidth(display,windows->image.screen);
4440 window_changes.height=(int) height;
4441 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4442 window_changes.height=XDisplayHeight(display,windows->image.screen);
4443 mask=(size_t) (CWWidth | CWHeight);
4444 if (resource_info->backdrop)
4447 window_changes.x=(int)
4448 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4449 window_changes.y=(int)
4450 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4452 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4453 (unsigned int) mask,&window_changes);
4454 (void) XClearWindow(display,windows->image.id);
4455 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4457 Update Magnify window configuration.
4459 if (windows->magnify.mapped != MagickFalse)
4460 XMakeMagnifyImage(display,windows);
4461 windows->pan.crop_geometry=windows->image.crop_geometry;
4462 XBestIconSize(display,&windows->pan,image);
4463 while (((windows->pan.width << 1) < MaxIconSize) &&
4464 ((windows->pan.height << 1) < MaxIconSize))
4466 windows->pan.width<<=1;
4467 windows->pan.height<<=1;
4469 if (windows->pan.geometry != (char *) NULL)
4470 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4471 &windows->pan.width,&windows->pan.height);
4472 window_changes.width=(int) windows->pan.width;
4473 window_changes.height=(int) windows->pan.height;
4474 size_hints=XAllocSizeHints();
4475 if (size_hints != (XSizeHints *) NULL)
4480 size_hints->flags=PSize | PMinSize | PMaxSize;
4481 size_hints->width=window_changes.width;
4482 size_hints->height=window_changes.height;
4483 size_hints->min_width=size_hints->width;
4484 size_hints->min_height=size_hints->height;
4485 size_hints->max_width=size_hints->width;
4486 size_hints->max_height=size_hints->height;
4487 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4488 (void) XFree((void *) size_hints);
4490 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4491 (unsigned int) (CWWidth | CWHeight),&window_changes);
4493 Update icon window configuration.
4495 windows->icon.crop_geometry=windows->image.crop_geometry;
4496 XBestIconSize(display,&windows->icon,image);
4497 window_changes.width=(int) windows->icon.width;
4498 window_changes.height=(int) windows->icon.height;
4499 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4500 (unsigned int) (CWWidth | CWHeight),&window_changes);
4501 XSetCursorState(display,windows,MagickFalse);
4502 return(status != 0 ? MagickTrue : MagickFalse);
4506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4510 + X C r o p I m a g e %
4514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4516 % XCropImage() allows the user to select a region of the image and crop, copy,
4517 % or cut it. For copy or cut, the image can subsequently be composited onto
4518 % the image with XPasteImage.
4520 % The format of the XCropImage method is:
4522 % MagickBooleanType XCropImage(Display *display,
4523 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4524 % const ClipboardMode mode)
4526 % A description of each parameter follows:
4528 % o display: Specifies a connection to an X server; returned from
4531 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4533 % o windows: Specifies a pointer to a XWindows structure.
4535 % o image: the image; returned from ReadImage.
4537 % o mode: This unsigned value specified whether the image should be
4538 % cropped, copied, or cut.
4541 static MagickBooleanType XCropImage(Display *display,
4542 XResourceInfo *resource_info,XWindows *windows,Image *image,
4543 const ClipboardMode mode)
4552 *RectifyModeMenu[] =
4560 static const ModeType
4570 RectifyDismissCommand
4577 command[MaxTextExtent],
4578 text[MaxTextExtent];
4624 (void) CloneString(&windows->command.name,"Copy");
4629 (void) CloneString(&windows->command.name,"Crop");
4634 (void) CloneString(&windows->command.name,"Cut");
4638 RectifyModeMenu[0]=windows->command.name;
4639 windows->command.data=0;
4640 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4641 (void) XMapRaised(display,windows->command.id);
4642 XClientMessage(display,windows->image.id,windows->im_protocols,
4643 windows->im_update_widget,CurrentTime);
4645 Track pointer until button 1 is pressed.
4647 XQueryPosition(display,windows->image.id,&x,&y);
4648 (void) XSelectInput(display,windows->image.id,
4649 windows->image.attributes.event_mask | PointerMotionMask);
4650 crop_info.x=(ssize_t) windows->image.x+x;
4651 crop_info.y=(ssize_t) windows->image.y+y;
4654 cursor=XCreateFontCursor(display,XC_fleur);
4658 if (windows->info.mapped != MagickFalse)
4661 Display pointer position.
4663 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
4664 (long) crop_info.x,(long) crop_info.y);
4665 XInfoWidget(display,windows,text);
4668 Wait for next event.
4670 XScreenEvent(display,windows,&event);
4671 if (event.xany.window == windows->command.id)
4674 Select a command from the Command widget.
4676 id=XCommandWidget(display,windows,CropModeMenu,&event);
4679 switch (CropCommands[id])
4681 case CropHelpCommand:
4687 XTextViewWidget(display,resource_info,windows,MagickFalse,
4688 "Help Viewer - Image Copy",ImageCopyHelp);
4693 XTextViewWidget(display,resource_info,windows,MagickFalse,
4694 "Help Viewer - Image Crop",ImageCropHelp);
4699 XTextViewWidget(display,resource_info,windows,MagickFalse,
4700 "Help Viewer - Image Cut",ImageCutHelp);
4706 case CropDismissCommand:
4724 if (event.xbutton.button != Button1)
4726 if (event.xbutton.window != windows->image.id)
4729 Note first corner of cropping rectangle-- exit loop.
4731 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4732 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4733 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4743 if (event.xkey.window != windows->image.id)
4746 Respond to a user key press.
4748 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4749 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4750 switch ((int) key_symbol)
4769 XTextViewWidget(display,resource_info,windows,MagickFalse,
4770 "Help Viewer - Image Copy",ImageCopyHelp);
4775 XTextViewWidget(display,resource_info,windows,MagickFalse,
4776 "Help Viewer - Image Crop",ImageCropHelp);
4781 XTextViewWidget(display,resource_info,windows,MagickFalse,
4782 "Help Viewer - Image Cut",ImageCutHelp);
4790 (void) XBell(display,0);
4798 if (event.xmotion.window != windows->image.id)
4801 Map and unmap Info widget as text cursor crosses its boundaries.
4805 if (windows->info.mapped != MagickFalse)
4807 if ((x < (int) (windows->info.x+windows->info.width)) &&
4808 (y < (int) (windows->info.y+windows->info.height)))
4809 (void) XWithdrawWindow(display,windows->info.id,
4810 windows->info.screen);
4813 if ((x > (int) (windows->info.x+windows->info.width)) ||
4814 (y > (int) (windows->info.y+windows->info.height)))
4815 (void) XMapWindow(display,windows->info.id);
4816 crop_info.x=(ssize_t) windows->image.x+x;
4817 crop_info.y=(ssize_t) windows->image.y+y;
4823 } while ((state & ExitState) == 0);
4824 (void) XSelectInput(display,windows->image.id,
4825 windows->image.attributes.event_mask);
4826 if ((state & EscapeState) != 0)
4829 User want to exit without cropping.
4831 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4832 (void) XFreeCursor(display,cursor);
4835 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4839 Size rectangle as pointer moves until the mouse button is released.
4841 x=(int) crop_info.x;
4842 y=(int) crop_info.y;
4848 highlight_info=crop_info;
4849 highlight_info.x=crop_info.x-windows->image.x;
4850 highlight_info.y=crop_info.y-windows->image.y;
4851 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4854 Display info and draw cropping rectangle.
4856 if (windows->info.mapped == MagickFalse)
4857 (void) XMapWindow(display,windows->info.id);
4858 (void) FormatLocaleString(text,MaxTextExtent,
4859 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4860 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4861 XInfoWidget(display,windows,text);
4862 XHighlightRectangle(display,windows->image.id,
4863 windows->image.highlight_context,&highlight_info);
4866 if (windows->info.mapped != MagickFalse)
4867 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4869 Wait for next event.
4871 XScreenEvent(display,windows,&event);
4872 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4873 XHighlightRectangle(display,windows->image.id,
4874 windows->image.highlight_context,&highlight_info);
4879 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4880 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4886 User has committed to cropping rectangle.
4888 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4889 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4890 XSetCursorState(display,windows,MagickFalse);
4892 windows->command.data=0;
4893 (void) XCommandWidget(display,windows,RectifyModeMenu,
4901 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4902 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4907 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4908 ((state & ExitState) != 0))
4911 Check boundary conditions.
4913 if (crop_info.x < 0)
4916 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4917 crop_info.x=(ssize_t) windows->image.ximage->width;
4918 if ((int) crop_info.x < x)
4919 crop_info.width=(unsigned int) (x-crop_info.x);
4922 crop_info.width=(unsigned int) (crop_info.x-x);
4923 crop_info.x=(ssize_t) x;
4925 if (crop_info.y < 0)
4928 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4929 crop_info.y=(ssize_t) windows->image.ximage->height;
4930 if ((int) crop_info.y < y)
4931 crop_info.height=(unsigned int) (y-crop_info.y);
4934 crop_info.height=(unsigned int) (crop_info.y-y);
4935 crop_info.y=(ssize_t) y;
4938 } while ((state & ExitState) == 0);
4940 Wait for user to grab a corner of the rectangle or press return.
4943 (void) XMapWindow(display,windows->info.id);
4946 if (windows->info.mapped != MagickFalse)
4949 Display pointer position.
4951 (void) FormatLocaleString(text,MaxTextExtent,
4952 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4953 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4954 XInfoWidget(display,windows,text);
4956 highlight_info=crop_info;
4957 highlight_info.x=crop_info.x-windows->image.x;
4958 highlight_info.y=crop_info.y-windows->image.y;
4959 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4965 XHighlightRectangle(display,windows->image.id,
4966 windows->image.highlight_context,&highlight_info);
4967 XScreenEvent(display,windows,&event);
4968 if (event.xany.window == windows->command.id)
4971 Select a command from the Command widget.
4973 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4974 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4975 (void) XSetFunction(display,windows->image.highlight_context,
4977 XHighlightRectangle(display,windows->image.id,
4978 windows->image.highlight_context,&highlight_info);
4980 switch (RectifyCommands[id])
4982 case RectifyCopyCommand:
4987 case RectifyHelpCommand:
4989 (void) XSetFunction(display,windows->image.highlight_context,
4995 XTextViewWidget(display,resource_info,windows,MagickFalse,
4996 "Help Viewer - Image Copy",ImageCopyHelp);
5001 XTextViewWidget(display,resource_info,windows,MagickFalse,
5002 "Help Viewer - Image Crop",ImageCropHelp);
5007 XTextViewWidget(display,resource_info,windows,MagickFalse,
5008 "Help Viewer - Image Cut",ImageCutHelp);
5012 (void) XSetFunction(display,windows->image.highlight_context,
5016 case RectifyDismissCommand:
5030 XHighlightRectangle(display,windows->image.id,
5031 windows->image.highlight_context,&highlight_info);
5036 if (event.xbutton.button != Button1)
5038 if (event.xbutton.window != windows->image.id)
5040 x=windows->image.x+event.xbutton.x;
5041 y=windows->image.y+event.xbutton.y;
5042 if ((x < (int) (crop_info.x+RoiDelta)) &&
5043 (x > (int) (crop_info.x-RoiDelta)) &&
5044 (y < (int) (crop_info.y+RoiDelta)) &&
5045 (y > (int) (crop_info.y-RoiDelta)))
5047 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5048 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5049 state|=UpdateConfigurationState;
5052 if ((x < (int) (crop_info.x+RoiDelta)) &&
5053 (x > (int) (crop_info.x-RoiDelta)) &&
5054 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5055 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5057 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5058 state|=UpdateConfigurationState;
5061 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5062 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5063 (y < (int) (crop_info.y+RoiDelta)) &&
5064 (y > (int) (crop_info.y-RoiDelta)))
5066 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5067 state|=UpdateConfigurationState;
5070 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5071 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5072 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5073 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5075 state|=UpdateConfigurationState;
5081 if (event.xbutton.window == windows->pan.id)
5082 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5083 (highlight_info.y != crop_info.y-windows->image.y))
5084 XHighlightRectangle(display,windows->image.id,
5085 windows->image.highlight_context,&highlight_info);
5086 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5087 event.xbutton.time);
5092 if (event.xexpose.window == windows->image.id)
5093 if (event.xexpose.count == 0)
5095 event.xexpose.x=(int) highlight_info.x;
5096 event.xexpose.y=(int) highlight_info.y;
5097 event.xexpose.width=(int) highlight_info.width;
5098 event.xexpose.height=(int) highlight_info.height;
5099 XRefreshWindow(display,&windows->image,&event);
5101 if (event.xexpose.window == windows->info.id)
5102 if (event.xexpose.count == 0)
5103 XInfoWidget(display,windows,text);
5108 if (event.xkey.window != windows->image.id)
5111 Respond to a user key press.
5113 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5114 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5115 switch ((int) key_symbol)
5128 crop_info.x=(ssize_t) (windows->image.width/2L-
5129 crop_info.width/2L);
5130 crop_info.y=(ssize_t) (windows->image.height/2L-
5131 crop_info.height/2L);
5163 (void) XSetFunction(display,windows->image.highlight_context,
5169 XTextViewWidget(display,resource_info,windows,MagickFalse,
5170 "Help Viewer - Image Copy",ImageCopyHelp);
5175 XTextViewWidget(display,resource_info,windows,MagickFalse,
5176 "Help Viewer - Image Cropg",ImageCropHelp);
5181 XTextViewWidget(display,resource_info,windows,MagickFalse,
5182 "Help Viewer - Image Cutg",ImageCutHelp);
5186 (void) XSetFunction(display,windows->image.highlight_context,
5192 (void) XBell(display,0);
5196 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5204 if (event.xmotion.window != windows->image.id)
5207 Map and unmap Info widget as text cursor crosses its boundaries.
5211 if (windows->info.mapped != MagickFalse)
5213 if ((x < (int) (windows->info.x+windows->info.width)) &&
5214 (y < (int) (windows->info.y+windows->info.height)))
5215 (void) XWithdrawWindow(display,windows->info.id,
5216 windows->info.screen);
5219 if ((x > (int) (windows->info.x+windows->info.width)) ||
5220 (y > (int) (windows->info.y+windows->info.height)))
5221 (void) XMapWindow(display,windows->info.id);
5222 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5223 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5226 case SelectionRequest:
5231 XSelectionRequestEvent
5235 Set primary selection.
5237 (void) FormatLocaleString(text,MaxTextExtent,
5238 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5239 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5240 request=(&(event.xselectionrequest));
5241 (void) XChangeProperty(request->display,request->requestor,
5242 request->property,request->target,8,PropModeReplace,
5243 (unsigned char *) text,(int) strlen(text));
5244 notify.type=SelectionNotify;
5245 notify.display=request->display;
5246 notify.requestor=request->requestor;
5247 notify.selection=request->selection;
5248 notify.target=request->target;
5249 notify.time=request->time;
5250 if (request->property == None)
5251 notify.property=request->target;
5253 notify.property=request->property;
5254 (void) XSendEvent(request->display,request->requestor,False,0,
5255 (XEvent *) ¬ify);
5260 if ((state & UpdateConfigurationState) != 0)
5262 (void) XPutBackEvent(display,&event);
5263 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5266 } while ((state & ExitState) == 0);
5267 } while ((state & ExitState) == 0);
5268 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5269 XSetCursorState(display,windows,MagickFalse);
5270 if ((state & EscapeState) != 0)
5272 if (mode == CropMode)
5273 if (((int) crop_info.width != windows->image.ximage->width) ||
5274 ((int) crop_info.height != windows->image.ximage->height))
5277 Reconfigure Image window as defined by cropping rectangle.
5279 XSetCropGeometry(display,windows,&crop_info,image);
5280 windows->image.window_changes.width=(int) crop_info.width;
5281 windows->image.window_changes.height=(int) crop_info.height;
5282 (void) XConfigureImage(display,resource_info,windows,image);
5286 Copy image before applying image transforms.
5288 XSetCursorState(display,windows,MagickTrue);
5289 XCheckRefreshWindows(display,windows);
5290 width=(unsigned int) image->columns;
5291 height=(unsigned int) image->rows;
5294 if (windows->image.crop_geometry != (char *) NULL)
5295 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5296 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5298 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5299 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5300 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5302 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5303 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5304 crop_image=CropImage(image,&crop_info,&image->exception);
5305 XSetCursorState(display,windows,MagickFalse);
5306 if (crop_image == (Image *) NULL)
5307 return(MagickFalse);
5308 if (resource_info->copy_image != (Image *) NULL)
5309 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5310 resource_info->copy_image=crop_image;
5311 if (mode == CopyMode)
5313 (void) XConfigureImage(display,resource_info,windows,image);
5319 exception=(&image->exception);
5320 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
5321 return(MagickFalse);
5322 image->matte=MagickTrue;
5323 image_view=AcquireCacheView(image);
5324 for (y=0; y < (int) crop_info.height; y++)
5326 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5327 crop_info.width,1,exception);
5328 if (q == (Quantum *) NULL)
5330 for (x=0; x < (int) crop_info.width; x++)
5332 SetPixelAlpha(image,TransparentAlpha,q);
5333 q+=GetPixelChannels(image);
5335 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5338 image_view=DestroyCacheView(image_view);
5340 Update image configuration.
5342 XConfigureImageColormap(display,resource_info,windows,image);
5343 (void) XConfigureImage(display,resource_info,windows,image);
5348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5352 + X D r a w I m a g e %
5356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5361 % The format of the XDrawEditImage method is:
5363 % MagickBooleanType XDrawEditImage(Display *display,
5364 % XResourceInfo *resource_info,XWindows *windows,Image **image)
5366 % A description of each parameter follows:
5368 % o display: Specifies a connection to an X server; returned from
5371 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5373 % o windows: Specifies a pointer to a XWindows structure.
5375 % o image: the image.
5378 static MagickBooleanType XDrawEditImage(Display *display,
5379 XResourceInfo *resource_info,XWindows *windows,Image **image)
5395 element = PointElement;
5397 static const ModeType
5410 stipple = (Pixmap) NULL;
5417 command[MaxTextExtent],
5418 text[MaxTextExtent];
5467 Allocate polygon info.
5469 max_coordinates=2048;
5470 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5471 sizeof(*coordinate_info));
5472 if (coordinate_info == (XPoint *) NULL)
5474 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5475 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5476 return(MagickFalse);
5481 (void) CloneString(&windows->command.name,"Draw");
5482 windows->command.data=4;
5483 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5484 (void) XMapRaised(display,windows->command.id);
5485 XClientMessage(display,windows->image.id,windows->im_protocols,
5486 windows->im_update_widget,CurrentTime);
5488 Wait for first button press.
5490 root_window=XRootWindow(display,XDefaultScreen(display));
5491 draw_info.stencil=OpaqueStencil;
5493 cursor=XCreateFontCursor(display,XC_tcross);
5496 XQueryPosition(display,windows->image.id,&x,&y);
5497 (void) XSelectInput(display,windows->image.id,
5498 windows->image.attributes.event_mask | PointerMotionMask);
5499 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5503 if (windows->info.mapped != MagickFalse)
5506 Display pointer position.
5508 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
5509 x+windows->image.x,y+windows->image.y);
5510 XInfoWidget(display,windows,text);
5513 Wait for next event.
5515 XScreenEvent(display,windows,&event);
5516 if (event.xany.window == windows->command.id)
5519 Select a command from the Command widget.
5521 id=XCommandWidget(display,windows,DrawMenu,&event);
5524 switch (DrawCommands[id])
5526 case DrawElementCommand:
5545 Select a command from the pop-up menu.
5547 element=(ElementType) (XMenuWidget(display,windows,
5548 DrawMenu[id],Elements,command)+1);
5551 case DrawColorCommand:
5554 *ColorMenu[MaxNumberPens+1];
5566 Initialize menu selections.
5568 for (i=0; i < (int) (MaxNumberPens-2); i++)
5569 ColorMenu[i]=resource_info->pen_colors[i];
5570 ColorMenu[MaxNumberPens-2]="transparent";
5571 ColorMenu[MaxNumberPens-1]="Browser...";
5572 ColorMenu[MaxNumberPens]=(char *) NULL;
5574 Select a pen color from the pop-up menu.
5576 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5577 (const char **) ColorMenu,command);
5580 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5582 if (transparent != MagickFalse)
5584 draw_info.stencil=TransparentStencil;
5587 if (pen_number == (MaxNumberPens-1))
5590 color_name[MaxTextExtent] = "gray";
5593 Select a pen color from a dialog.
5595 resource_info->pen_colors[pen_number]=color_name;
5596 XColorBrowserWidget(display,windows,"Select",color_name);
5597 if (*color_name == '\0')
5603 (void) XParseColor(display,windows->map_info->colormap,
5604 resource_info->pen_colors[pen_number],&color);
5605 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5606 (unsigned int) MaxColors,&color);
5607 windows->pixel_info->pen_colors[pen_number]=color;
5608 pen_id=(unsigned int) pen_number;
5609 draw_info.stencil=OpaqueStencil;
5612 case DrawStippleCommand:
5624 filename[MaxTextExtent] = "\0";
5641 Select a command from the pop-up menu.
5643 StipplesMenu[7]="Open...";
5644 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5648 if (stipple != (Pixmap) NULL)
5649 (void) XFreePixmap(display,stipple);
5650 stipple=(Pixmap) NULL;
5657 stipple=XCreateBitmapFromData(display,root_window,
5658 (char *) BricksBitmap,BricksWidth,BricksHeight);
5663 stipple=XCreateBitmapFromData(display,root_window,
5664 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5669 stipple=XCreateBitmapFromData(display,root_window,
5670 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5675 stipple=XCreateBitmapFromData(display,root_window,
5676 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5681 stipple=XCreateBitmapFromData(display,root_window,
5682 (char *) WavyBitmap,WavyWidth,WavyHeight);
5687 stipple=XCreateBitmapFromData(display,root_window,
5688 (char *) HighlightBitmap,HighlightWidth,
5695 stipple=XCreateBitmapFromData(display,root_window,
5696 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5702 XFileBrowserWidget(display,windows,"Stipple",filename);
5703 if (*filename == '\0')
5708 XSetCursorState(display,windows,MagickTrue);
5709 XCheckRefreshWindows(display,windows);
5710 image_info=AcquireImageInfo();
5711 (void) CopyMagickString(image_info->filename,filename,
5713 stipple_image=ReadImage(image_info,&(*image)->exception);
5714 CatchException(&(*image)->exception);
5715 XSetCursorState(display,windows,MagickFalse);
5716 if (stipple_image == (Image *) NULL)
5718 (void) AcquireUniqueFileResource(filename);
5719 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
5721 (void) WriteImage(image_info,stipple_image,&(*image)->exception);
5722 stipple_image=DestroyImage(stipple_image);
5723 image_info=DestroyImageInfo(image_info);
5724 status=XReadBitmapFile(display,root_window,filename,&width,
5725 &height,&stipple,&x,&y);
5726 (void) RelinquishUniqueFileResource(filename);
5727 if ((status != BitmapSuccess) != 0)
5728 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5732 case DrawWidthCommand:
5735 width[MaxTextExtent] = "0";
5750 Select a command from the pop-up menu.
5752 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5758 line_width=(unsigned int) StringToUnsignedLong(
5762 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5766 line_width=(unsigned int) StringToUnsignedLong(width);
5769 case DrawUndoCommand:
5771 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5775 case DrawHelpCommand:
5777 XTextViewWidget(display,resource_info,windows,MagickFalse,
5778 "Help Viewer - Image Rotation",ImageDrawHelp);
5779 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5782 case DrawDismissCommand:
5794 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5801 if (event.xbutton.button != Button1)
5803 if (event.xbutton.window != windows->image.id)
5822 if (event.xkey.window != windows->image.id)
5825 Respond to a user key press.
5827 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5828 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5829 switch ((int) key_symbol)
5844 XTextViewWidget(display,resource_info,windows,MagickFalse,
5845 "Help Viewer - Image Rotation",ImageDrawHelp);
5850 (void) XBell(display,0);
5859 Map and unmap Info widget as text cursor crosses its boundaries.
5863 if (windows->info.mapped != MagickFalse)
5865 if ((x < (int) (windows->info.x+windows->info.width)) &&
5866 (y < (int) (windows->info.y+windows->info.height)))
5867 (void) XWithdrawWindow(display,windows->info.id,
5868 windows->info.screen);
5871 if ((x > (int) (windows->info.x+windows->info.width)) ||
5872 (y > (int) (windows->info.y+windows->info.height)))
5873 (void) XMapWindow(display,windows->info.id);
5877 } while ((state & ExitState) == 0);
5878 (void) XSelectInput(display,windows->image.id,
5879 windows->image.attributes.event_mask);
5880 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5881 if ((state & EscapeState) != 0)
5884 Draw element as pointer moves until the button is released.
5892 rectangle_info.x=(ssize_t) x;
5893 rectangle_info.y=(ssize_t) y;
5894 rectangle_info.width=0;
5895 rectangle_info.height=0;
5896 number_coordinates=1;
5897 coordinate_info->x=x;
5898 coordinate_info->y=y;
5899 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5908 if (number_coordinates > 1)
5910 (void) XDrawLines(display,windows->image.id,
5911 windows->image.highlight_context,coordinate_info,
5912 number_coordinates,CoordModeOrigin);
5913 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
5914 coordinate_info[number_coordinates-1].x,
5915 coordinate_info[number_coordinates-1].y);
5916 XInfoWidget(display,windows,text);
5925 Display angle of the line.
5927 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5928 line_info.y1),(double) (line_info.x2-line_info.x1)));
5929 (void) FormatLocaleString(text,MaxTextExtent," %g",
5931 XInfoWidget(display,windows,text);
5932 XHighlightLine(display,windows->image.id,
5933 windows->image.highlight_context,&line_info);
5936 if (windows->info.mapped != MagickFalse)
5937 (void) XWithdrawWindow(display,windows->info.id,
5938 windows->info.screen);
5941 case RectangleElement:
5942 case FillRectangleElement:
5944 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5947 Display info and draw drawing rectangle.
5949 (void) FormatLocaleString(text,MaxTextExtent,
5950 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5951 (double) rectangle_info.height,(double) rectangle_info.x,
5952 (double) rectangle_info.y);
5953 XInfoWidget(display,windows,text);
5954 XHighlightRectangle(display,windows->image.id,
5955 windows->image.highlight_context,&rectangle_info);
5958 if (windows->info.mapped != MagickFalse)
5959 (void) XWithdrawWindow(display,windows->info.id,
5960 windows->info.screen);
5964 case FillCircleElement:
5965 case EllipseElement:
5966 case FillEllipseElement:
5968 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5971 Display info and draw drawing rectangle.
5973 (void) FormatLocaleString(text,MaxTextExtent,
5974 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5975 (double) rectangle_info.height,(double) rectangle_info.x,
5976 (double) rectangle_info.y);
5977 XInfoWidget(display,windows,text);
5978 XHighlightEllipse(display,windows->image.id,
5979 windows->image.highlight_context,&rectangle_info);
5982 if (windows->info.mapped != MagickFalse)
5983 (void) XWithdrawWindow(display,windows->info.id,
5984 windows->info.screen);
5987 case PolygonElement:
5988 case FillPolygonElement:
5990 if (number_coordinates > 1)
5991 (void) XDrawLines(display,windows->image.id,
5992 windows->image.highlight_context,coordinate_info,
5993 number_coordinates,CoordModeOrigin);
5997 Display angle of the line.
5999 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6000 line_info.y1),(double) (line_info.x2-line_info.x1)));
6001 (void) FormatLocaleString(text,MaxTextExtent," %g",
6003 XInfoWidget(display,windows,text);
6004 XHighlightLine(display,windows->image.id,
6005 windows->image.highlight_context,&line_info);
6008 if (windows->info.mapped != MagickFalse)
6009 (void) XWithdrawWindow(display,windows->info.id,
6010 windows->info.screen);
6015 Wait for next event.
6017 XScreenEvent(display,windows,&event);
6023 if (number_coordinates > 1)
6024 (void) XDrawLines(display,windows->image.id,
6025 windows->image.highlight_context,coordinate_info,
6026 number_coordinates,CoordModeOrigin);
6032 XHighlightLine(display,windows->image.id,
6033 windows->image.highlight_context,&line_info);
6036 case RectangleElement:
6037 case FillRectangleElement:
6039 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6040 XHighlightRectangle(display,windows->image.id,
6041 windows->image.highlight_context,&rectangle_info);
6045 case FillCircleElement:
6046 case EllipseElement:
6047 case FillEllipseElement:
6049 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6050 XHighlightEllipse(display,windows->image.id,
6051 windows->image.highlight_context,&rectangle_info);
6054 case PolygonElement:
6055 case FillPolygonElement:
6057 if (number_coordinates > 1)
6058 (void) XDrawLines(display,windows->image.id,
6059 windows->image.highlight_context,coordinate_info,
6060 number_coordinates,CoordModeOrigin);
6062 XHighlightLine(display,windows->image.id,
6063 windows->image.highlight_context,&line_info);
6074 User has committed to element.
6076 line_info.x2=event.xbutton.x;
6077 line_info.y2=event.xbutton.y;
6078 rectangle_info.x=(ssize_t) event.xbutton.x;
6079 rectangle_info.y=(ssize_t) event.xbutton.y;
6080 coordinate_info[number_coordinates].x=event.xbutton.x;
6081 coordinate_info[number_coordinates].y=event.xbutton.y;
6082 if (((element != PolygonElement) &&
6083 (element != FillPolygonElement)) || (distance <= 9))
6088 number_coordinates++;
6089 if (number_coordinates < (int) max_coordinates)
6091 line_info.x1=event.xbutton.x;
6092 line_info.y1=event.xbutton.y;
6095 max_coordinates<<=1;
6096 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6097 max_coordinates,sizeof(*coordinate_info));
6098 if (coordinate_info == (XPoint *) NULL)
6099 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6100 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6107 if (event.xmotion.window != windows->image.id)
6109 if (element != PointElement)
6111 line_info.x2=event.xmotion.x;
6112 line_info.y2=event.xmotion.y;
6113 rectangle_info.x=(ssize_t) event.xmotion.x;
6114 rectangle_info.y=(ssize_t) event.xmotion.y;
6117 coordinate_info[number_coordinates].x=event.xbutton.x;
6118 coordinate_info[number_coordinates].y=event.xbutton.y;
6119 number_coordinates++;
6120 if (number_coordinates < (int) max_coordinates)
6122 max_coordinates<<=1;
6123 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6124 max_coordinates,sizeof(*coordinate_info));
6125 if (coordinate_info == (XPoint *) NULL)
6126 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6127 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6134 Check boundary conditions.
6136 if (line_info.x2 < 0)
6139 if (line_info.x2 > (int) windows->image.width)
6140 line_info.x2=(short) windows->image.width;
6141 if (line_info.y2 < 0)
6144 if (line_info.y2 > (int) windows->image.height)
6145 line_info.y2=(short) windows->image.height;
6146 distance=(unsigned int)
6147 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6148 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6149 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6150 ((state & ExitState) != 0))
6152 if (rectangle_info.x < 0)
6155 if (rectangle_info.x > (ssize_t) windows->image.width)
6156 rectangle_info.x=(ssize_t) windows->image.width;
6157 if ((int) rectangle_info.x < x)
6158 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6161 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6162 rectangle_info.x=(ssize_t) x;
6164 if (rectangle_info.y < 0)
6167 if (rectangle_info.y > (ssize_t) windows->image.height)
6168 rectangle_info.y=(ssize_t) windows->image.height;
6169 if ((int) rectangle_info.y < y)
6170 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6173 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6174 rectangle_info.y=(ssize_t) y;
6177 } while ((state & ExitState) == 0);
6178 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6179 if ((element == PointElement) || (element == PolygonElement) ||
6180 (element == FillPolygonElement))
6183 Determine polygon bounding box.
6185 rectangle_info.x=(ssize_t) coordinate_info->x;
6186 rectangle_info.y=(ssize_t) coordinate_info->y;
6187 x=coordinate_info->x;
6188 y=coordinate_info->y;
6189 for (i=1; i < number_coordinates; i++)
6191 if (coordinate_info[i].x > x)
6192 x=coordinate_info[i].x;
6193 if (coordinate_info[i].y > y)
6194 y=coordinate_info[i].y;
6195 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6196 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6197 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6198 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6200 rectangle_info.width=(size_t) (x-rectangle_info.x);
6201 rectangle_info.height=(size_t) (y-rectangle_info.y);
6202 for (i=0; i < number_coordinates; i++)
6204 coordinate_info[i].x-=rectangle_info.x;
6205 coordinate_info[i].y-=rectangle_info.y;
6212 if ((element == RectangleElement) ||
6213 (element == CircleElement) || (element == EllipseElement))
6215 rectangle_info.width--;
6216 rectangle_info.height--;
6219 Drawing is relative to image configuration.
6221 draw_info.x=(int) rectangle_info.x;
6222 draw_info.y=(int) rectangle_info.y;
6223 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6225 width=(unsigned int) (*image)->columns;
6226 height=(unsigned int) (*image)->rows;
6229 if (windows->image.crop_geometry != (char *) NULL)
6230 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6231 draw_info.x+=windows->image.x-(line_width/2);
6232 if (draw_info.x < 0)
6234 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6235 draw_info.y+=windows->image.y-(line_width/2);
6236 if (draw_info.y < 0)
6238 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6239 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6240 if (draw_info.width > (unsigned int) (*image)->columns)
6241 draw_info.width=(unsigned int) (*image)->columns;
6242 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6243 if (draw_info.height > (unsigned int) (*image)->rows)
6244 draw_info.height=(unsigned int) (*image)->rows;
6245 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6246 width*draw_info.width/windows->image.ximage->width,
6247 height*draw_info.height/windows->image.ximage->height,
6248 draw_info.x+x,draw_info.y+y);
6250 Initialize drawing attributes.
6252 draw_info.degrees=0.0;
6253 draw_info.element=element;
6254 draw_info.stipple=stipple;
6255 draw_info.line_width=line_width;
6256 draw_info.line_info=line_info;
6257 if (line_info.x1 > (int) (line_width/2))
6258 draw_info.line_info.x1=(short) line_width/2;
6259 if (line_info.y1 > (int) (line_width/2))
6260 draw_info.line_info.y1=(short) line_width/2;
6261 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6262 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6263 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6265 draw_info.line_info.x2=(-draw_info.line_info.x2);
6266 draw_info.line_info.y2=(-draw_info.line_info.y2);
6268 if (draw_info.line_info.x2 < 0)
6270 draw_info.line_info.x2=(-draw_info.line_info.x2);
6271 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6273 if (draw_info.line_info.y2 < 0)
6275 draw_info.line_info.y2=(-draw_info.line_info.y2);
6276 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6278 draw_info.rectangle_info=rectangle_info;
6279 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6280 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6281 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6282 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6283 draw_info.number_coordinates=(unsigned int) number_coordinates;
6284 draw_info.coordinate_info=coordinate_info;
6285 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6287 Draw element on image.
6289 XSetCursorState(display,windows,MagickTrue);
6290 XCheckRefreshWindows(display,windows);
6291 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6292 XSetCursorState(display,windows,MagickFalse);
6294 Update image colormap and return to image drawing.
6296 XConfigureImageColormap(display,resource_info,windows,*image);
6297 (void) XConfigureImage(display,resource_info,windows,*image);
6299 XSetCursorState(display,windows,MagickFalse);
6300 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6301 return(status != 0 ? MagickTrue : MagickFalse);
6305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6309 + X D r a w P a n R e c t a n g l e %
6313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6315 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6316 % displays a zoom image and the rectangle shows which portion of the image is
6317 % displayed in the Image window.
6319 % The format of the XDrawPanRectangle method is:
6321 % XDrawPanRectangle(Display *display,XWindows *windows)
6323 % A description of each parameter follows:
6325 % o display: Specifies a connection to an X server; returned from
6328 % o windows: Specifies a pointer to a XWindows structure.
6331 static void XDrawPanRectangle(Display *display,XWindows *windows)
6340 Determine dimensions of the panning rectangle.
6342 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6343 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6344 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6345 scale_factor=(MagickRealType)
6346 windows->pan.height/windows->image.ximage->height;
6347 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6348 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6350 Display the panning rectangle.
6352 (void) XClearWindow(display,windows->pan.id);
6353 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6362 + X I m a g e C a c h e %
6366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6368 % XImageCache() handles the creation, manipulation, and destruction of the
6369 % image cache (undo and redo buffers).
6371 % The format of the XImageCache method is:
6373 % void XImageCache(Display *display,XResourceInfo *resource_info,
6374 % XWindows *windows,const CommandType command,Image **image)
6376 % A description of each parameter follows:
6378 % o display: Specifies a connection to an X server; returned from
6381 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6383 % o windows: Specifies a pointer to a XWindows structure.
6385 % o command: Specifies a command to perform.
6387 % o image: the image; XImageCache may transform the image and return a new
6391 static void XImageCache(Display *display,XResourceInfo *resource_info,
6392 XWindows *windows,const CommandType command,Image **image)
6398 *redo_image = (Image *) NULL,
6399 *undo_image = (Image *) NULL;
6403 case FreeBuffersCommand:
6406 Free memory from the undo and redo cache.
6408 while (undo_image != (Image *) NULL)
6410 cache_image=undo_image;
6411 undo_image=GetPreviousImageInList(undo_image);
6412 cache_image->list=DestroyImage(cache_image->list);
6413 cache_image=DestroyImage(cache_image);
6415 undo_image=NewImageList();
6416 if (redo_image != (Image *) NULL)
6417 redo_image=DestroyImage(redo_image);
6418 redo_image=NewImageList();
6424 image_geometry[MaxTextExtent];
6427 Undo the last image transformation.
6429 if (undo_image == (Image *) NULL)
6431 (void) XBell(display,0);
6434 cache_image=undo_image;
6435 undo_image=GetPreviousImageInList(undo_image);
6436 windows->image.window_changes.width=(int) cache_image->columns;
6437 windows->image.window_changes.height=(int) cache_image->rows;
6438 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
6439 windows->image.ximage->width,windows->image.ximage->height);
6440 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
6441 if (windows->image.crop_geometry != (char *) NULL)
6442 windows->image.crop_geometry=(char *)
6443 RelinquishMagickMemory(windows->image.crop_geometry);
6444 windows->image.crop_geometry=cache_image->geometry;
6445 if (redo_image != (Image *) NULL)
6446 redo_image=DestroyImage(redo_image);
6447 redo_image=(*image);
6448 *image=cache_image->list;
6449 cache_image=DestroyImage(cache_image);
6450 if (windows->image.orphan != MagickFalse)
6452 XConfigureImageColormap(display,resource_info,windows,*image);
6453 (void) XConfigureImage(display,resource_info,windows,*image);
6459 case HalfSizeCommand:
6460 case OriginalSizeCommand:
6461 case DoubleSizeCommand:
6468 case RotateRightCommand:
6469 case RotateLeftCommand:
6474 case ContrastStretchCommand:
6475 case SigmoidalContrastCommand:
6476 case NormalizeCommand:
6477 case EqualizeCommand:
6479 case SaturationCommand:
6480 case BrightnessCommand:
6484 case GrayscaleCommand:
6486 case QuantizeCommand:
6487 case DespeckleCommand:
6489 case ReduceNoiseCommand:
6490 case AddNoiseCommand:
6491 case SharpenCommand:
6493 case ThresholdCommand:
6494 case EdgeDetectCommand:
6498 case SegmentCommand:
6499 case SolarizeCommand:
6500 case SepiaToneCommand:
6502 case ImplodeCommand:
6503 case VignetteCommand:
6505 case OilPaintCommand:
6506 case CharcoalDrawCommand:
6507 case AnnotateCommand:
6508 case AddBorderCommand:
6509 case AddFrameCommand:
6510 case CompositeCommand:
6511 case CommentCommand:
6513 case RegionofInterestCommand:
6514 case SaveToUndoBufferCommand:
6523 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6524 if (undo_image != (Image *) NULL)
6527 Ensure the undo cache has enough memory available.
6529 previous_image=undo_image;
6530 while (previous_image != (Image *) NULL)
6532 bytes+=previous_image->list->columns*previous_image->list->rows*
6533 sizeof(PixelPacket);
6534 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6536 previous_image=GetPreviousImageInList(previous_image);
6539 bytes-=previous_image->list->columns*previous_image->list->rows*
6540 sizeof(PixelPacket);
6541 if (previous_image == undo_image)
6542 undo_image=NewImageList();
6544 previous_image->next->previous=NewImageList();
6547 while (previous_image != (Image *) NULL)
6550 Delete any excess memory from undo cache.
6552 cache_image=previous_image;
6553 previous_image=GetPreviousImageInList(previous_image);
6554 cache_image->list=DestroyImage(cache_image->list);
6555 cache_image=DestroyImage(cache_image);
6558 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6561 Save image before transformations are applied.
6563 cache_image=AcquireImage((ImageInfo *) NULL);
6564 if (cache_image == (Image *) NULL)
6566 XSetCursorState(display,windows,MagickTrue);
6567 XCheckRefreshWindows(display,windows);
6568 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6569 XSetCursorState(display,windows,MagickFalse);
6570 if (cache_image->list == (Image *) NULL)
6572 cache_image=DestroyImage(cache_image);
6575 cache_image->columns=(size_t) windows->image.ximage->width;
6576 cache_image->rows=(size_t) windows->image.ximage->height;
6577 cache_image->geometry=windows->image.crop_geometry;
6578 if (windows->image.crop_geometry != (char *) NULL)
6580 cache_image->geometry=AcquireString((char *) NULL);
6581 (void) CopyMagickString(cache_image->geometry,
6582 windows->image.crop_geometry,MaxTextExtent);
6584 if (undo_image == (Image *) NULL)
6586 undo_image=cache_image;
6589 undo_image->next=cache_image;
6590 undo_image->next->previous=undo_image;
6591 undo_image=undo_image->next;
6597 if (command == RedoCommand)
6600 Redo the last image transformation.
6602 if (redo_image == (Image *) NULL)
6604 (void) XBell(display,0);
6607 windows->image.window_changes.width=(int) redo_image->columns;
6608 windows->image.window_changes.height=(int) redo_image->rows;
6609 if (windows->image.crop_geometry != (char *) NULL)
6610 windows->image.crop_geometry=(char *)
6611 RelinquishMagickMemory(windows->image.crop_geometry);
6612 windows->image.crop_geometry=redo_image->geometry;
6613 *image=DestroyImage(*image);
6615 redo_image=NewImageList();
6616 if (windows->image.orphan != MagickFalse)
6618 XConfigureImageColormap(display,resource_info,windows,*image);
6619 (void) XConfigureImage(display,resource_info,windows,*image);
6622 if (command != InfoCommand)
6627 XSetCursorState(display,windows,MagickTrue);
6628 XCheckRefreshWindows(display,windows);
6629 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6630 XSetCursorState(display,windows,MagickFalse);
6634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6638 + X I m a g e W i n d o w C o m m a n d %
6642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6644 % XImageWindowCommand() makes a transform to the image or Image window as
6645 % specified by a user menu button or keyboard command.
6647 % The format of the XMagickCommand method is:
6649 % CommandType XImageWindowCommand(Display *display,
6650 % XResourceInfo *resource_info,XWindows *windows,
6651 % const MagickStatusType state,KeySym key_symbol,Image **image)
6653 % A description of each parameter follows:
6655 % o nexus: Method XImageWindowCommand returns an image when the
6656 % user chooses 'Open Image' from the command menu. Otherwise a null
6657 % image is returned.
6659 % o display: Specifies a connection to an X server; returned from
6662 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6664 % o windows: Specifies a pointer to a XWindows structure.
6666 % o state: key mask.
6668 % o key_symbol: Specifies a command to perform.
6670 % o image: the image; XImageWIndowCommand
6671 % may transform the image and return a new image pointer.
6674 static CommandType XImageWindowCommand(Display *display,
6675 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6676 KeySym key_symbol,Image **image)
6679 delta[MaxTextExtent] = "";
6682 Digits[] = "01234567890";
6687 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6689 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6692 resource_info->quantum=1;
6694 last_symbol=key_symbol;
6695 delta[strlen(delta)+1]='\0';
6696 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6697 resource_info->quantum=StringToLong(delta);
6698 return(NullCommand);
6700 last_symbol=key_symbol;
6701 if (resource_info->immutable)
6704 Virtual image window has a restricted command set.
6709 return(InfoCommand);
6712 return(PrintCommand);
6714 return(NextCommand);
6717 return(QuitCommand);
6721 return(NullCommand);
6723 switch ((int) key_symbol)
6727 if ((state & ControlMask) == 0)
6729 return(OpenCommand);
6732 return(NextCommand);
6734 return(FormerCommand);
6737 if ((state & Mod1Mask) != 0)
6738 return(SwirlCommand);
6739 if ((state & ControlMask) == 0)
6740 return(ShearCommand);
6741 return(SaveCommand);
6746 if ((state & Mod1Mask) != 0)
6747 return(OilPaintCommand);
6748 if ((state & Mod4Mask) != 0)
6749 return(ColorCommand);
6750 if ((state & ControlMask) == 0)
6751 return(NullCommand);
6752 return(PrintCommand);
6756 if ((state & Mod4Mask) != 0)
6757 return(DrawCommand);
6758 if ((state & ControlMask) == 0)
6759 return(NullCommand);
6760 return(DeleteCommand);
6764 if ((state & ControlMask) == 0)
6765 return(NullCommand);
6766 return(SelectCommand);
6770 if ((state & ControlMask) == 0)
6771 return(NullCommand);
6776 return(QuitCommand);
6780 if ((state & ControlMask) == 0)
6781 return(NullCommand);
6782 return(UndoCommand);
6787 if ((state & ControlMask) == 0)
6788 return(RollCommand);
6789 return(RedoCommand);
6793 if ((state & ControlMask) == 0)
6794 return(NullCommand);
6799 if ((state & Mod1Mask) != 0)
6800 return(CharcoalDrawCommand);
6801 if ((state & ControlMask) == 0)
6802 return(CropCommand);
6803 return(CopyCommand);
6808 if ((state & Mod4Mask) != 0)
6809 return(CompositeCommand);
6810 if ((state & ControlMask) == 0)
6811 return(FlipCommand);
6812 return(PasteCommand);
6815 return(HalfSizeCommand);
6817 return(OriginalSizeCommand);
6819 return(DoubleSizeCommand);
6821 return(ResizeCommand);
6823 return(RefreshCommand);
6824 case XK_bracketleft:
6825 return(ChopCommand);
6827 return(FlopCommand);
6829 return(RotateRightCommand);
6831 return(RotateLeftCommand);
6833 return(RotateCommand);
6835 return(TrimCommand);
6839 return(SaturationCommand);
6841 return(BrightnessCommand);
6843 return(GammaCommand);
6845 return(SpiffCommand);
6847 return(DullCommand);
6849 return(NormalizeCommand);
6851 return(EqualizeCommand);
6853 return(NegateCommand);
6855 return(GrayscaleCommand);
6857 return(QuantizeCommand);
6859 return(DespeckleCommand);
6861 return(EmbossCommand);
6863 return(ReduceNoiseCommand);
6865 return(AddNoiseCommand);
6867 return(SharpenCommand);
6869 return(BlurCommand);
6871 return(ThresholdCommand);
6873 return(EdgeDetectCommand);
6875 return(SpreadCommand);
6877 return(ShadeCommand);
6879 return(RaiseCommand);
6881 return(SegmentCommand);
6884 if ((state & Mod1Mask) == 0)
6885 return(NullCommand);
6886 return(ImplodeCommand);
6890 if ((state & Mod1Mask) == 0)
6891 return(NullCommand);
6892 return(WaveCommand);
6896 if ((state & Mod4Mask) == 0)
6897 return(NullCommand);
6898 return(MatteCommand);
6902 if ((state & Mod4Mask) == 0)
6903 return(NullCommand);
6904 return(AddBorderCommand);
6908 if ((state & Mod4Mask) == 0)
6909 return(NullCommand);
6910 return(AddFrameCommand);
6914 if ((state & Mod4Mask) == 0)
6915 return(NullCommand);
6916 return(CommentCommand);
6920 if ((state & Mod1Mask) != 0)
6921 return(ApplyCommand);
6922 if ((state & Mod4Mask) != 0)
6923 return(AnnotateCommand);
6924 if ((state & ControlMask) == 0)
6925 return(NullCommand);
6926 return(RegionofInterestCommand);
6929 return(InfoCommand);
6931 return(ZoomCommand);
6934 if ((state & ShiftMask) == 0)
6935 return(NullCommand);
6936 return(ShowPreviewCommand);
6939 return(LaunchCommand);
6941 return(HelpCommand);
6943 return(BrowseDocumentationCommand);
6946 (void) XMapRaised(display,windows->command.id);
6947 return(NullCommand);
6954 XTranslateImage(display,windows,*image,key_symbol);
6955 return(NullCommand);
6966 if ((state & Mod1Mask) != 0)
6972 Trim one pixel from edge of image.
6976 crop_info.width=(size_t) windows->image.ximage->width;
6977 crop_info.height=(size_t) windows->image.ximage->height;
6978 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6980 if (resource_info->quantum >= (int) crop_info.height)
6981 resource_info->quantum=(int) crop_info.height-1;
6982 crop_info.height-=resource_info->quantum;
6984 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6986 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6987 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6988 crop_info.y+=resource_info->quantum;
6989 crop_info.height-=resource_info->quantum;
6991 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6993 if (resource_info->quantum >= (int) crop_info.width)
6994 resource_info->quantum=(int) crop_info.width-1;
6995 crop_info.width-=resource_info->quantum;
6997 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6999 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7000 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7001 crop_info.x+=resource_info->quantum;
7002 crop_info.width-=resource_info->quantum;
7004 if ((int) (windows->image.x+windows->image.width) >
7005 (int) crop_info.width)
7006 windows->image.x=(int) (crop_info.width-windows->image.width);
7007 if ((int) (windows->image.y+windows->image.height) >
7008 (int) crop_info.height)
7009 windows->image.y=(int) (crop_info.height-windows->image.height);
7010 XSetCropGeometry(display,windows,&crop_info,*image);
7011 windows->image.window_changes.width=(int) crop_info.width;
7012 windows->image.window_changes.height=(int) crop_info.height;
7013 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7014 (void) XConfigureImage(display,resource_info,windows,*image);
7015 return(NullCommand);
7017 XTranslateImage(display,windows,*image,key_symbol);
7018 return(NullCommand);
7021 return(NullCommand);
7023 return(NullCommand);
7027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7031 + X M a g i c k C o m m a n d %
7035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7037 % XMagickCommand() makes a transform to the image or Image window as
7038 % specified by a user menu button or keyboard command.
7040 % The format of the XMagickCommand method is:
7042 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7043 % XWindows *windows,const CommandType command,Image **image)
7045 % A description of each parameter follows:
7047 % o nexus: Method XMagickCommand returns an image when the
7048 % user chooses 'Load Image' from the command menu. Otherwise a null
7049 % image is returned.
7051 % o display: Specifies a connection to an X server; returned from
7054 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7056 % o windows: Specifies a pointer to a XWindows structure.
7058 % o command: Specifies a command to perform.
7060 % o image: the image; XMagickCommand
7061 % may transform the image and return a new image pointer.
7064 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7065 XWindows *windows,const CommandType command,Image **image)
7068 filename[MaxTextExtent],
7069 geometry[MaxTextExtent],
7070 modulate_factors[MaxTextExtent];
7099 color[MaxTextExtent] = "gray";
7106 Process user command.
7108 XCheckRefreshWindows(display,windows);
7109 XImageCache(display,resource_info,windows,command,image);
7110 nexus=NewImageList();
7111 windows->image.window_changes.width=windows->image.ximage->width;
7112 windows->image.window_changes.height=windows->image.ximage->height;
7113 image_info=CloneImageInfo(resource_info->image_info);
7114 SetGeometryInfo(&geometry_info);
7115 GetQuantizeInfo(&quantize_info);
7123 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7131 for (i=0; i < resource_info->quantum; i++)
7132 XClientMessage(display,windows->image.id,windows->im_protocols,
7133 windows->im_next_image,CurrentTime);
7139 Display former image.
7141 for (i=0; i < resource_info->quantum; i++)
7142 XClientMessage(display,windows->image.id,windows->im_protocols,
7143 windows->im_former_image,CurrentTime);
7154 status=chdir(resource_info->home_directory);
7156 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7157 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7158 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7166 status=XSaveImage(display,resource_info,windows,*image);
7167 if (status == MagickFalse)
7169 XNoticeWidget(display,windows,"Unable to write X image:",
7170 (*image)->filename);
7180 status=XPrintImage(display,resource_info,windows,*image);
7181 if (status == MagickFalse)
7183 XNoticeWidget(display,windows,"Unable to print X image:",
7184 (*image)->filename);
7192 filename[MaxTextExtent] = "\0";
7197 XFileBrowserWidget(display,windows,"Delete",filename);
7198 if (*filename == '\0')
7200 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7201 if (status != MagickFalse)
7202 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7211 color[MaxTextExtent] = "gray",
7212 geometry[MaxTextExtent] = "640x480";
7215 *format = "gradient";
7218 Query user for canvas geometry.
7220 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7222 if (*geometry == '\0')
7226 XColorBrowserWidget(display,windows,"Select",color);
7232 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
7233 "%s:%s",format,color);
7234 (void) CloneString(&image_info->size,geometry);
7235 nexus=ReadImage(image_info,&(*image)->exception);
7236 CatchException(&(*image)->exception);
7237 XClientMessage(display,windows->image.id,windows->im_protocols,
7238 windows->im_next_image,CurrentTime);
7241 case VisualDirectoryCommand:
7244 Visual Image directory.
7246 nexus=XVisualDirectoryImage(display,resource_info,windows);
7254 if (resource_info->confirm_exit == MagickFalse)
7255 XClientMessage(display,windows->image.id,windows->im_protocols,
7256 windows->im_exit,CurrentTime);
7263 Confirm program exit.
7265 status=XConfirmWidget(display,windows,"Do you really want to exit",
7266 resource_info->client_name);
7268 XClientMessage(display,windows->image.id,windows->im_protocols,
7269 windows->im_exit,CurrentTime);
7278 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7286 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7294 status=XPasteImage(display,resource_info,windows,*image);
7295 if (status == MagickFalse)
7297 XNoticeWidget(display,windows,"Unable to paste X image",
7298 (*image)->filename);
7303 case HalfSizeCommand:
7308 windows->image.window_changes.width=windows->image.ximage->width/2;
7309 windows->image.window_changes.height=windows->image.ximage->height/2;
7310 (void) XConfigureImage(display,resource_info,windows,*image);
7313 case OriginalSizeCommand:
7316 Original image size.
7318 windows->image.window_changes.width=(int) (*image)->columns;
7319 windows->image.window_changes.height=(int) (*image)->rows;
7320 (void) XConfigureImage(display,resource_info,windows,*image);
7323 case DoubleSizeCommand:
7326 Double the image size.
7328 windows->image.window_changes.width=windows->image.ximage->width << 1;
7329 windows->image.window_changes.height=windows->image.ximage->height << 1;
7330 (void) XConfigureImage(display,resource_info,windows,*image);
7349 width=(size_t) windows->image.ximage->width;
7350 height=(size_t) windows->image.ximage->height;
7353 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7354 (double) width,(double) height);
7355 status=XDialogWidget(display,windows,"Resize",
7356 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7357 if (*geometry == '\0')
7360 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7361 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7362 windows->image.window_changes.width=(int) width;
7363 windows->image.window_changes.height=(int) height;
7364 (void) XConfigureImage(display,resource_info,windows,*image);
7370 image_geometry[MaxTextExtent];
7372 if ((windows->image.crop_geometry == (char *) NULL) &&
7373 ((int) (*image)->columns == windows->image.ximage->width) &&
7374 ((int) (*image)->rows == windows->image.ximage->height))
7377 Apply size transforms to image.
7379 XSetCursorState(display,windows,MagickTrue);
7380 XCheckRefreshWindows(display,windows);
7382 Crop and/or scale displayed image.
7384 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
7385 windows->image.ximage->width,windows->image.ximage->height);
7386 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7387 if (windows->image.crop_geometry != (char *) NULL)
7388 windows->image.crop_geometry=(char *)
7389 RelinquishMagickMemory(windows->image.crop_geometry);
7392 XConfigureImageColormap(display,resource_info,windows,*image);
7393 (void) XConfigureImage(display,resource_info,windows,*image);
7396 case RefreshCommand:
7398 (void) XConfigureImage(display,resource_info,windows,*image);
7401 case RestoreCommand:
7404 Restore Image window to its original size.
7406 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7407 (windows->image.height == (unsigned int) (*image)->rows) &&
7408 (windows->image.crop_geometry == (char *) NULL))
7410 (void) XBell(display,0);
7413 windows->image.window_changes.width=(int) (*image)->columns;
7414 windows->image.window_changes.height=(int) (*image)->rows;
7415 if (windows->image.crop_geometry != (char *) NULL)
7417 windows->image.crop_geometry=(char *)
7418 RelinquishMagickMemory(windows->image.crop_geometry);
7419 windows->image.crop_geometry=(char *) NULL;
7423 XConfigureImageColormap(display,resource_info,windows,*image);
7424 (void) XConfigureImage(display,resource_info,windows,*image);
7432 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7440 status=XChopImage(display,resource_info,windows,image);
7441 if (status == MagickFalse)
7443 XNoticeWidget(display,windows,"Unable to cut X image",
7444 (*image)->filename);
7455 Flop image scanlines.
7457 XSetCursorState(display,windows,MagickTrue);
7458 XCheckRefreshWindows(display,windows);
7459 flop_image=FlopImage(*image,&(*image)->exception);
7460 if (flop_image != (Image *) NULL)
7462 *image=DestroyImage(*image);
7465 CatchException(&(*image)->exception);
7466 XSetCursorState(display,windows,MagickFalse);
7467 if (windows->image.crop_geometry != (char *) NULL)
7472 width=(unsigned int) (*image)->columns;
7473 height=(unsigned int) (*image)->rows;
7474 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7476 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7477 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7479 if (windows->image.orphan != MagickFalse)
7481 (void) XConfigureImage(display,resource_info,windows,*image);
7490 Flip image scanlines.
7492 XSetCursorState(display,windows,MagickTrue);
7493 XCheckRefreshWindows(display,windows);
7494 flip_image=FlipImage(*image,&(*image)->exception);
7495 if (flip_image != (Image *) NULL)
7497 *image=DestroyImage(*image);
7500 CatchException(&(*image)->exception);
7501 XSetCursorState(display,windows,MagickFalse);
7502 if (windows->image.crop_geometry != (char *) NULL)
7507 width=(unsigned int) (*image)->columns;
7508 height=(unsigned int) (*image)->rows;
7509 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7511 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7512 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7514 if (windows->image.orphan != MagickFalse)
7516 (void) XConfigureImage(display,resource_info,windows,*image);
7519 case RotateRightCommand:
7522 Rotate image 90 degrees clockwise.
7524 status=XRotateImage(display,resource_info,windows,90.0,image);
7525 if (status == MagickFalse)
7527 XNoticeWidget(display,windows,"Unable to rotate X image",
7528 (*image)->filename);
7533 case RotateLeftCommand:
7536 Rotate image 90 degrees counter-clockwise.
7538 status=XRotateImage(display,resource_info,windows,-90.0,image);
7539 if (status == MagickFalse)
7541 XNoticeWidget(display,windows,"Unable to rotate X image",
7542 (*image)->filename);
7552 status=XRotateImage(display,resource_info,windows,0.0,image);
7553 if (status == MagickFalse)
7555 XNoticeWidget(display,windows,"Unable to rotate X image",
7556 (*image)->filename);
7567 geometry[MaxTextExtent] = "45.0x45.0";
7570 Query user for shear color and geometry.
7572 XColorBrowserWidget(display,windows,"Select",color);
7575 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7577 if (*geometry == '\0')
7582 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7583 XSetCursorState(display,windows,MagickTrue);
7584 XCheckRefreshWindows(display,windows);
7585 (void) QueryColorDatabase(color,&(*image)->background_color,
7586 &(*image)->exception);
7587 flags=ParseGeometry(geometry,&geometry_info);
7588 if ((flags & SigmaValue) == 0)
7589 geometry_info.sigma=geometry_info.rho;
7590 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7591 &(*image)->exception);
7592 if (shear_image != (Image *) NULL)
7594 *image=DestroyImage(*image);
7597 CatchException(&(*image)->exception);
7598 XSetCursorState(display,windows,MagickFalse);
7599 if (windows->image.orphan != MagickFalse)
7601 windows->image.window_changes.width=(int) (*image)->columns;
7602 windows->image.window_changes.height=(int) (*image)->rows;
7603 XConfigureImageColormap(display,resource_info,windows,*image);
7604 (void) XConfigureImage(display,resource_info,windows,*image);
7613 geometry[MaxTextExtent] = "+2+2";
7616 Query user for the roll geometry.
7618 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7620 if (*geometry == '\0')
7625 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7626 XSetCursorState(display,windows,MagickTrue);
7627 XCheckRefreshWindows(display,windows);
7628 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7629 &(*image)->exception);
7630 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7631 &(*image)->exception);
7632 if (roll_image != (Image *) NULL)
7634 *image=DestroyImage(*image);
7637 CatchException(&(*image)->exception);
7638 XSetCursorState(display,windows,MagickFalse);
7639 if (windows->image.orphan != MagickFalse)
7641 windows->image.window_changes.width=(int) (*image)->columns;
7642 windows->image.window_changes.height=(int) (*image)->rows;
7643 XConfigureImageColormap(display,resource_info,windows,*image);
7644 (void) XConfigureImage(display,resource_info,windows,*image);
7650 fuzz[MaxTextExtent];
7653 Query user for the fuzz factor.
7655 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
7656 (*image)->fuzz/(QuantumRange+1.0));
7657 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7660 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
7664 status=XTrimImage(display,resource_info,windows,*image);
7665 if (status == MagickFalse)
7667 XNoticeWidget(display,windows,"Unable to trim X image",
7668 (*image)->filename);
7676 hue_percent[MaxTextExtent] = "110";
7679 Query user for percent hue change.
7681 (void) XDialogWidget(display,windows,"Apply",
7682 "Enter percent change in image hue (0-200):",hue_percent);
7683 if (*hue_percent == '\0')
7688 XSetCursorState(display,windows,MagickTrue);
7689 XCheckRefreshWindows(display,windows);
7690 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7691 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7693 (void) ModulateImage(*image,modulate_factors,&(*image)->exception);
7694 XSetCursorState(display,windows,MagickFalse);
7695 if (windows->image.orphan != MagickFalse)
7697 XConfigureImageColormap(display,resource_info,windows,*image);
7698 (void) XConfigureImage(display,resource_info,windows,*image);
7701 case SaturationCommand:
7704 saturation_percent[MaxTextExtent] = "110";
7707 Query user for percent saturation change.
7709 (void) XDialogWidget(display,windows,"Apply",
7710 "Enter percent change in color saturation (0-200):",saturation_percent);
7711 if (*saturation_percent == '\0')
7714 Vary color saturation.
7716 XSetCursorState(display,windows,MagickTrue);
7717 XCheckRefreshWindows(display,windows);
7718 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7719 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7721 (void) ModulateImage(*image,modulate_factors,&(*image)->exception);
7722 XSetCursorState(display,windows,MagickFalse);
7723 if (windows->image.orphan != MagickFalse)
7725 XConfigureImageColormap(display,resource_info,windows,*image);
7726 (void) XConfigureImage(display,resource_info,windows,*image);
7729 case BrightnessCommand:
7732 brightness_percent[MaxTextExtent] = "110";
7735 Query user for percent brightness change.
7737 (void) XDialogWidget(display,windows,"Apply",
7738 "Enter percent change in color brightness (0-200):",brightness_percent);
7739 if (*brightness_percent == '\0')
7742 Vary the color brightness.
7744 XSetCursorState(display,windows,MagickTrue);
7745 XCheckRefreshWindows(display,windows);
7746 (void) CopyMagickString(modulate_factors,brightness_percent,
7748 (void) ModulateImage(*image,modulate_factors,&(*image)->exception);
7749 XSetCursorState(display,windows,MagickFalse);
7750 if (windows->image.orphan != MagickFalse)
7752 XConfigureImageColormap(display,resource_info,windows,*image);
7753 (void) XConfigureImage(display,resource_info,windows,*image);
7759 factor[MaxTextExtent] = "1.6";
7762 Query user for gamma value.
7764 (void) XDialogWidget(display,windows,"Gamma",
7765 "Enter gamma value (e.g. 1.2):",factor);
7766 if (*factor == '\0')
7769 Gamma correct image.
7771 XSetCursorState(display,windows,MagickTrue);
7772 XCheckRefreshWindows(display,windows);
7773 (void) GammaImage(*image,atof(factor),&(*image)->exception);
7774 XSetCursorState(display,windows,MagickFalse);
7775 if (windows->image.orphan != MagickFalse)
7777 XConfigureImageColormap(display,resource_info,windows,*image);
7778 (void) XConfigureImage(display,resource_info,windows,*image);
7784 Sharpen the image contrast.
7786 XSetCursorState(display,windows,MagickTrue);
7787 XCheckRefreshWindows(display,windows);
7788 (void) ContrastImage(*image,MagickTrue,&(*image)->exception);
7789 XSetCursorState(display,windows,MagickFalse);
7790 if (windows->image.orphan != MagickFalse)
7792 XConfigureImageColormap(display,resource_info,windows,*image);
7793 (void) XConfigureImage(display,resource_info,windows,*image);
7799 Dull the image contrast.
7801 XSetCursorState(display,windows,MagickTrue);
7802 XCheckRefreshWindows(display,windows);
7803 (void) ContrastImage(*image,MagickFalse,&(*image)->exception);
7804 XSetCursorState(display,windows,MagickFalse);
7805 if (windows->image.orphan != MagickFalse)
7807 XConfigureImageColormap(display,resource_info,windows,*image);
7808 (void) XConfigureImage(display,resource_info,windows,*image);
7811 case ContrastStretchCommand:
7818 levels[MaxTextExtent] = "1%";
7821 Query user for gamma value.
7823 (void) XDialogWidget(display,windows,"Contrast Stretch",
7824 "Enter black and white points:",levels);
7825 if (*levels == '\0')
7828 Contrast stretch image.
7830 XSetCursorState(display,windows,MagickTrue);
7831 XCheckRefreshWindows(display,windows);
7832 flags=ParseGeometry(levels,&geometry_info);
7833 black_point=geometry_info.rho;
7834 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7835 if ((flags & PercentValue) != 0)
7837 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7838 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7840 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7841 (void) ContrastStretchImage(*image,black_point,white_point,
7842 &(*image)->exception);
7843 XSetCursorState(display,windows,MagickFalse);
7844 if (windows->image.orphan != MagickFalse)
7846 XConfigureImageColormap(display,resource_info,windows,*image);
7847 (void) XConfigureImage(display,resource_info,windows,*image);
7850 case SigmoidalContrastCommand:
7859 levels[MaxTextExtent] = "3x50%";
7862 Query user for gamma value.
7864 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7865 "Enter contrast and midpoint:",levels);
7866 if (*levels == '\0')
7869 Contrast stretch image.
7871 XSetCursorState(display,windows,MagickTrue);
7872 XCheckRefreshWindows(display,windows);
7873 flags=ParseGeometry(levels,&geometry_info);
7874 if ((flags & SigmaValue) == 0)
7875 geometry_info.sigma=1.0*QuantumRange/2.0;
7876 if ((flags & PercentValue) != 0)
7877 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7878 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7879 geometry_info.sigma,&(*image)->exception);
7880 XSetCursorState(display,windows,MagickFalse);
7881 if (windows->image.orphan != MagickFalse)
7883 XConfigureImageColormap(display,resource_info,windows,*image);
7884 (void) XConfigureImage(display,resource_info,windows,*image);
7887 case NormalizeCommand:
7890 Perform histogram normalization on the image.
7892 XSetCursorState(display,windows,MagickTrue);
7893 XCheckRefreshWindows(display,windows);
7894 (void) NormalizeImage(*image,&(*image)->exception);
7895 XSetCursorState(display,windows,MagickFalse);
7896 if (windows->image.orphan != MagickFalse)
7898 XConfigureImageColormap(display,resource_info,windows,*image);
7899 (void) XConfigureImage(display,resource_info,windows,*image);
7902 case EqualizeCommand:
7905 Perform histogram equalization on the image.
7907 XSetCursorState(display,windows,MagickTrue);
7908 XCheckRefreshWindows(display,windows);
7909 (void) EqualizeImage(*image,&(*image)->exception);
7910 XSetCursorState(display,windows,MagickFalse);
7911 if (windows->image.orphan != MagickFalse)
7913 XConfigureImageColormap(display,resource_info,windows,*image);
7914 (void) XConfigureImage(display,resource_info,windows,*image);
7920 Negate colors in image.
7922 XSetCursorState(display,windows,MagickTrue);
7923 XCheckRefreshWindows(display,windows);
7924 (void) NegateImage(*image,MagickFalse,&(*image)->exception);
7925 XSetCursorState(display,windows,MagickFalse);
7926 if (windows->image.orphan != MagickFalse)
7928 XConfigureImageColormap(display,resource_info,windows,*image);
7929 (void) XConfigureImage(display,resource_info,windows,*image);
7932 case GrayscaleCommand:
7935 Convert image to grayscale.
7937 XSetCursorState(display,windows,MagickTrue);
7938 XCheckRefreshWindows(display,windows);
7939 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7940 GrayscaleType : GrayscaleMatteType);
7941 XSetCursorState(display,windows,MagickFalse);
7942 if (windows->image.orphan != MagickFalse)
7944 XConfigureImageColormap(display,resource_info,windows,*image);
7945 (void) XConfigureImage(display,resource_info,windows,*image);
7954 filename[MaxTextExtent] = "\0";
7957 Request image file name from user.
7959 XFileBrowserWidget(display,windows,"Map",filename);
7960 if (*filename == '\0')
7965 XSetCursorState(display,windows,MagickTrue);
7966 XCheckRefreshWindows(display,windows);
7967 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7968 affinity_image=ReadImage(image_info,&(*image)->exception);
7969 if (affinity_image != (Image *) NULL)
7971 (void) RemapImage(&quantize_info,*image,affinity_image);
7972 affinity_image=DestroyImage(affinity_image);
7974 CatchException(&(*image)->exception);
7975 XSetCursorState(display,windows,MagickFalse);
7976 if (windows->image.orphan != MagickFalse)
7978 XConfigureImageColormap(display,resource_info,windows,*image);
7979 (void) XConfigureImage(display,resource_info,windows,*image);
7982 case QuantizeCommand:
7988 colors[MaxTextExtent] = "256";
7991 Query user for maximum number of colors.
7993 status=XDialogWidget(display,windows,"Quantize",
7994 "Maximum number of colors:",colors);
7995 if (*colors == '\0')
7998 Color reduce the image.
8000 XSetCursorState(display,windows,MagickTrue);
8001 XCheckRefreshWindows(display,windows);
8002 quantize_info.number_colors=StringToUnsignedLong(colors);
8003 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
8004 (void) QuantizeImage(&quantize_info,*image);
8005 XSetCursorState(display,windows,MagickFalse);
8006 if (windows->image.orphan != MagickFalse)
8008 XConfigureImageColormap(display,resource_info,windows,*image);
8009 (void) XConfigureImage(display,resource_info,windows,*image);
8012 case DespeckleCommand:
8020 XSetCursorState(display,windows,MagickTrue);
8021 XCheckRefreshWindows(display,windows);
8022 despeckle_image=DespeckleImage(*image,&(*image)->exception);
8023 if (despeckle_image != (Image *) NULL)
8025 *image=DestroyImage(*image);
8026 *image=despeckle_image;
8028 CatchException(&(*image)->exception);
8029 XSetCursorState(display,windows,MagickFalse);
8030 if (windows->image.orphan != MagickFalse)
8032 XConfigureImageColormap(display,resource_info,windows,*image);
8033 (void) XConfigureImage(display,resource_info,windows,*image);
8042 radius[MaxTextExtent] = "0.0x1.0";
8045 Query user for emboss radius.
8047 (void) XDialogWidget(display,windows,"Emboss",
8048 "Enter the emboss radius and standard deviation:",radius);
8049 if (*radius == '\0')
8052 Reduce noise in the image.
8054 XSetCursorState(display,windows,MagickTrue);
8055 XCheckRefreshWindows(display,windows);
8056 flags=ParseGeometry(radius,&geometry_info);
8057 if ((flags & SigmaValue) == 0)
8058 geometry_info.sigma=1.0;
8059 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8060 &(*image)->exception);
8061 if (emboss_image != (Image *) NULL)
8063 *image=DestroyImage(*image);
8064 *image=emboss_image;
8066 CatchException(&(*image)->exception);
8067 XSetCursorState(display,windows,MagickFalse);
8068 if (windows->image.orphan != MagickFalse)
8070 XConfigureImageColormap(display,resource_info,windows,*image);
8071 (void) XConfigureImage(display,resource_info,windows,*image);
8074 case ReduceNoiseCommand:
8080 radius[MaxTextExtent] = "0";
8083 Query user for noise radius.
8085 (void) XDialogWidget(display,windows,"Reduce Noise",
8086 "Enter the noise radius:",radius);
8087 if (*radius == '\0')
8090 Reduce noise in the image.
8092 XSetCursorState(display,windows,MagickTrue);
8093 XCheckRefreshWindows(display,windows);
8094 flags=ParseGeometry(radius,&geometry_info);
8095 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8096 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
8097 if (noise_image != (Image *) NULL)
8099 *image=DestroyImage(*image);
8102 CatchException(&(*image)->exception);
8103 XSetCursorState(display,windows,MagickFalse);
8104 if (windows->image.orphan != MagickFalse)
8106 XConfigureImageColormap(display,resource_info,windows,*image);
8107 (void) XConfigureImage(display,resource_info,windows,*image);
8110 case AddNoiseCommand:
8119 noise_type[MaxTextExtent] = "Gaussian";
8122 Add noise to the image.
8124 noises=GetCommandOptions(MagickNoiseOptions);
8125 if (noises == (char **) NULL)
8127 XListBrowserWidget(display,windows,&windows->widget,
8128 (const char **) noises,"Add Noise",
8129 "Select a type of noise to add to your image:",noise_type);
8130 noises=DestroyStringList(noises);
8131 if (*noise_type == '\0')
8133 XSetCursorState(display,windows,MagickTrue);
8134 XCheckRefreshWindows(display,windows);
8135 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8136 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8137 if (noise_image != (Image *) NULL)
8139 *image=DestroyImage(*image);
8142 CatchException(&(*image)->exception);
8143 XSetCursorState(display,windows,MagickFalse);
8144 if (windows->image.orphan != MagickFalse)
8146 XConfigureImageColormap(display,resource_info,windows,*image);
8147 (void) XConfigureImage(display,resource_info,windows,*image);
8150 case SharpenCommand:
8156 radius[MaxTextExtent] = "0.0x1.0";
8159 Query user for sharpen radius.
8161 (void) XDialogWidget(display,windows,"Sharpen",
8162 "Enter the sharpen radius and standard deviation:",radius);
8163 if (*radius == '\0')
8166 Sharpen image scanlines.
8168 XSetCursorState(display,windows,MagickTrue);
8169 XCheckRefreshWindows(display,windows);
8170 flags=ParseGeometry(radius,&geometry_info);
8171 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8172 &(*image)->exception);
8173 if (sharp_image != (Image *) NULL)
8175 *image=DestroyImage(*image);
8178 CatchException(&(*image)->exception);
8179 XSetCursorState(display,windows,MagickFalse);
8180 if (windows->image.orphan != MagickFalse)
8182 XConfigureImageColormap(display,resource_info,windows,*image);
8183 (void) XConfigureImage(display,resource_info,windows,*image);
8192 radius[MaxTextExtent] = "0.0x1.0";
8195 Query user for blur radius.
8197 (void) XDialogWidget(display,windows,"Blur",
8198 "Enter the blur radius and standard deviation:",radius);
8199 if (*radius == '\0')
8204 XSetCursorState(display,windows,MagickTrue);
8205 XCheckRefreshWindows(display,windows);
8206 flags=ParseGeometry(radius,&geometry_info);
8207 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8208 &(*image)->exception);
8209 if (blur_image != (Image *) NULL)
8211 *image=DestroyImage(*image);
8214 CatchException(&(*image)->exception);
8215 XSetCursorState(display,windows,MagickFalse);
8216 if (windows->image.orphan != MagickFalse)
8218 XConfigureImageColormap(display,resource_info,windows,*image);
8219 (void) XConfigureImage(display,resource_info,windows,*image);
8222 case ThresholdCommand:
8228 factor[MaxTextExtent] = "128";
8231 Query user for threshold value.
8233 (void) XDialogWidget(display,windows,"Threshold",
8234 "Enter threshold value:",factor);
8235 if (*factor == '\0')
8238 Gamma correct image.
8240 XSetCursorState(display,windows,MagickTrue);
8241 XCheckRefreshWindows(display,windows);
8242 threshold=SiPrefixToDouble(factor,QuantumRange);
8243 (void) BilevelImage(*image,threshold);
8244 XSetCursorState(display,windows,MagickFalse);
8245 if (windows->image.orphan != MagickFalse)
8247 XConfigureImageColormap(display,resource_info,windows,*image);
8248 (void) XConfigureImage(display,resource_info,windows,*image);
8251 case EdgeDetectCommand:
8257 radius[MaxTextExtent] = "0";
8260 Query user for edge factor.
8262 (void) XDialogWidget(display,windows,"Detect Edges",
8263 "Enter the edge detect radius:",radius);
8264 if (*radius == '\0')
8267 Detect edge in image.
8269 XSetCursorState(display,windows,MagickTrue);
8270 XCheckRefreshWindows(display,windows);
8271 flags=ParseGeometry(radius,&geometry_info);
8272 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8273 if (edge_image != (Image *) NULL)
8275 *image=DestroyImage(*image);
8278 CatchException(&(*image)->exception);
8279 XSetCursorState(display,windows,MagickFalse);
8280 if (windows->image.orphan != MagickFalse)
8282 XConfigureImageColormap(display,resource_info,windows,*image);
8283 (void) XConfigureImage(display,resource_info,windows,*image);
8292 amount[MaxTextExtent] = "2";
8295 Query user for spread amount.
8297 (void) XDialogWidget(display,windows,"Spread",
8298 "Enter the displacement amount:",amount);
8299 if (*amount == '\0')
8302 Displace image pixels by a random amount.
8304 XSetCursorState(display,windows,MagickTrue);
8305 XCheckRefreshWindows(display,windows);
8306 flags=ParseGeometry(amount,&geometry_info);
8307 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8308 if (spread_image != (Image *) NULL)
8310 *image=DestroyImage(*image);
8311 *image=spread_image;
8313 CatchException(&(*image)->exception);
8314 XSetCursorState(display,windows,MagickFalse);
8315 if (windows->image.orphan != MagickFalse)
8317 XConfigureImageColormap(display,resource_info,windows,*image);
8318 (void) XConfigureImage(display,resource_info,windows,*image);
8330 geometry[MaxTextExtent] = "30x30";
8333 Query user for the shade geometry.
8335 status=XDialogWidget(display,windows,"Shade",
8336 "Enter the azimuth and elevation of the light source:",geometry);
8337 if (*geometry == '\0')
8342 XSetCursorState(display,windows,MagickTrue);
8343 XCheckRefreshWindows(display,windows);
8344 flags=ParseGeometry(geometry,&geometry_info);
8345 if ((flags & SigmaValue) == 0)
8346 geometry_info.sigma=1.0;
8347 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8348 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8349 if (shade_image != (Image *) NULL)
8351 *image=DestroyImage(*image);
8354 CatchException(&(*image)->exception);
8355 XSetCursorState(display,windows,MagickFalse);
8356 if (windows->image.orphan != MagickFalse)
8358 XConfigureImageColormap(display,resource_info,windows,*image);
8359 (void) XConfigureImage(display,resource_info,windows,*image);
8365 bevel_width[MaxTextExtent] = "10";
8368 Query user for bevel width.
8370 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8371 if (*bevel_width == '\0')
8376 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8377 XSetCursorState(display,windows,MagickTrue);
8378 XCheckRefreshWindows(display,windows);
8379 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8380 &(*image)->exception);
8381 (void) RaiseImage(*image,&page_geometry,MagickTrue,&(*image)->exception);
8382 XSetCursorState(display,windows,MagickFalse);
8383 if (windows->image.orphan != MagickFalse)
8385 XConfigureImageColormap(display,resource_info,windows,*image);
8386 (void) XConfigureImage(display,resource_info,windows,*image);
8389 case SegmentCommand:
8392 threshold[MaxTextExtent] = "1.0x1.5";
8395 Query user for smoothing threshold.
8397 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8399 if (*threshold == '\0')
8404 XSetCursorState(display,windows,MagickTrue);
8405 XCheckRefreshWindows(display,windows);
8406 flags=ParseGeometry(threshold,&geometry_info);
8407 if ((flags & SigmaValue) == 0)
8408 geometry_info.sigma=1.0;
8409 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8410 geometry_info.sigma);
8411 XSetCursorState(display,windows,MagickFalse);
8412 if (windows->image.orphan != MagickFalse)
8414 XConfigureImageColormap(display,resource_info,windows,*image);
8415 (void) XConfigureImage(display,resource_info,windows,*image);
8418 case SepiaToneCommand:
8427 factor[MaxTextExtent] = "80%";
8430 Query user for sepia-tone factor.
8432 (void) XDialogWidget(display,windows,"Sepia Tone",
8433 "Enter the sepia tone factor (0 - 99.9%):",factor);
8434 if (*factor == '\0')
8437 Sepia tone image pixels.
8439 XSetCursorState(display,windows,MagickTrue);
8440 XCheckRefreshWindows(display,windows);
8441 threshold=SiPrefixToDouble(factor,QuantumRange);
8442 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8443 if (sepia_image != (Image *) NULL)
8445 *image=DestroyImage(*image);
8448 CatchException(&(*image)->exception);
8449 XSetCursorState(display,windows,MagickFalse);
8450 if (windows->image.orphan != MagickFalse)
8452 XConfigureImageColormap(display,resource_info,windows,*image);
8453 (void) XConfigureImage(display,resource_info,windows,*image);
8456 case SolarizeCommand:
8462 factor[MaxTextExtent] = "60%";
8465 Query user for solarize factor.
8467 (void) XDialogWidget(display,windows,"Solarize",
8468 "Enter the solarize factor (0 - 99.9%):",factor);
8469 if (*factor == '\0')
8472 Solarize image pixels.
8474 XSetCursorState(display,windows,MagickTrue);
8475 XCheckRefreshWindows(display,windows);
8476 threshold=SiPrefixToDouble(factor,QuantumRange);
8477 (void) SolarizeImage(*image,threshold);
8478 XSetCursorState(display,windows,MagickFalse);
8479 if (windows->image.orphan != MagickFalse)
8481 XConfigureImageColormap(display,resource_info,windows,*image);
8482 (void) XConfigureImage(display,resource_info,windows,*image);
8491 degrees[MaxTextExtent] = "60";
8494 Query user for swirl angle.
8496 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8498 if (*degrees == '\0')
8501 Swirl image pixels about the center.
8503 XSetCursorState(display,windows,MagickTrue);
8504 XCheckRefreshWindows(display,windows);
8505 flags=ParseGeometry(degrees,&geometry_info);
8506 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8507 if (swirl_image != (Image *) NULL)
8509 *image=DestroyImage(*image);
8512 CatchException(&(*image)->exception);
8513 XSetCursorState(display,windows,MagickFalse);
8514 if (windows->image.orphan != MagickFalse)
8516 XConfigureImageColormap(display,resource_info,windows,*image);
8517 (void) XConfigureImage(display,resource_info,windows,*image);
8520 case ImplodeCommand:
8526 factor[MaxTextExtent] = "0.3";
8529 Query user for implode factor.
8531 (void) XDialogWidget(display,windows,"Implode",
8532 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8533 if (*factor == '\0')
8536 Implode image pixels about the center.
8538 XSetCursorState(display,windows,MagickTrue);
8539 XCheckRefreshWindows(display,windows);
8540 flags=ParseGeometry(factor,&geometry_info);
8541 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8542 if (implode_image != (Image *) NULL)
8544 *image=DestroyImage(*image);
8545 *image=implode_image;
8547 CatchException(&(*image)->exception);
8548 XSetCursorState(display,windows,MagickFalse);
8549 if (windows->image.orphan != MagickFalse)
8551 XConfigureImageColormap(display,resource_info,windows,*image);
8552 (void) XConfigureImage(display,resource_info,windows,*image);
8555 case VignetteCommand:
8561 geometry[MaxTextExtent] = "0x20";
8564 Query user for the vignette geometry.
8566 (void) XDialogWidget(display,windows,"Vignette",
8567 "Enter the radius, sigma, and x and y offsets:",geometry);
8568 if (*geometry == '\0')
8571 Soften the edges of the image in vignette style
8573 XSetCursorState(display,windows,MagickTrue);
8574 XCheckRefreshWindows(display,windows);
8575 flags=ParseGeometry(geometry,&geometry_info);
8576 if ((flags & SigmaValue) == 0)
8577 geometry_info.sigma=1.0;
8578 if ((flags & XiValue) == 0)
8579 geometry_info.xi=0.1*(*image)->columns;
8580 if ((flags & PsiValue) == 0)
8581 geometry_info.psi=0.1*(*image)->rows;
8582 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8583 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8584 0.5),&(*image)->exception);
8585 if (vignette_image != (Image *) NULL)
8587 *image=DestroyImage(*image);
8588 *image=vignette_image;
8590 CatchException(&(*image)->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);
8604 geometry[MaxTextExtent] = "25x150";
8607 Query user for the wave geometry.
8609 (void) XDialogWidget(display,windows,"Wave",
8610 "Enter the amplitude and length of the wave:",geometry);
8611 if (*geometry == '\0')
8614 Alter an image along a sine wave.
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 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8622 &(*image)->exception);
8623 if (wave_image != (Image *) NULL)
8625 *image=DestroyImage(*image);
8628 CatchException(&(*image)->exception);
8629 XSetCursorState(display,windows,MagickFalse);
8630 if (windows->image.orphan != MagickFalse)
8632 XConfigureImageColormap(display,resource_info,windows,*image);
8633 (void) XConfigureImage(display,resource_info,windows,*image);
8636 case OilPaintCommand:
8642 radius[MaxTextExtent] = "0";
8645 Query user for circular neighborhood radius.
8647 (void) XDialogWidget(display,windows,"Oil Paint",
8648 "Enter the mask radius:",radius);
8649 if (*radius == '\0')
8652 OilPaint image scanlines.
8654 XSetCursorState(display,windows,MagickTrue);
8655 XCheckRefreshWindows(display,windows);
8656 flags=ParseGeometry(radius,&geometry_info);
8657 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8658 &(*image)->exception);
8659 if (paint_image != (Image *) NULL)
8661 *image=DestroyImage(*image);
8664 CatchException(&(*image)->exception);
8665 XSetCursorState(display,windows,MagickFalse);
8666 if (windows->image.orphan != MagickFalse)
8668 XConfigureImageColormap(display,resource_info,windows,*image);
8669 (void) XConfigureImage(display,resource_info,windows,*image);
8672 case CharcoalDrawCommand:
8678 radius[MaxTextExtent] = "0x1";
8681 Query user for charcoal radius.
8683 (void) XDialogWidget(display,windows,"Charcoal Draw",
8684 "Enter the charcoal radius and sigma:",radius);
8685 if (*radius == '\0')
8690 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8691 XSetCursorState(display,windows,MagickTrue);
8692 XCheckRefreshWindows(display,windows);
8693 flags=ParseGeometry(radius,&geometry_info);
8694 if ((flags & SigmaValue) == 0)
8695 geometry_info.sigma=geometry_info.rho;
8696 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8697 &(*image)->exception);
8698 if (charcoal_image != (Image *) NULL)
8700 *image=DestroyImage(*image);
8701 *image=charcoal_image;
8703 CatchException(&(*image)->exception);
8704 XSetCursorState(display,windows,MagickFalse);
8705 if (windows->image.orphan != MagickFalse)
8707 XConfigureImageColormap(display,resource_info,windows,*image);
8708 (void) XConfigureImage(display,resource_info,windows,*image);
8711 case AnnotateCommand:
8714 Annotate the image with text.
8716 status=XAnnotateEditImage(display,resource_info,windows,*image);
8717 if (status == MagickFalse)
8719 XNoticeWidget(display,windows,"Unable to annotate X image",
8720 (*image)->filename);
8730 status=XDrawEditImage(display,resource_info,windows,image);
8731 if (status == MagickFalse)
8733 XNoticeWidget(display,windows,"Unable to draw on the X image",
8734 (*image)->filename);
8744 status=XColorEditImage(display,resource_info,windows,image);
8745 if (status == MagickFalse)
8747 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8748 (*image)->filename);
8758 status=XMatteEditImage(display,resource_info,windows,image);
8759 if (status == MagickFalse)
8761 XNoticeWidget(display,windows,"Unable to matte edit X image",
8762 (*image)->filename);
8767 case CompositeCommand:
8772 status=XCompositeImage(display,resource_info,windows,*image);
8773 if (status == MagickFalse)
8775 XNoticeWidget(display,windows,"Unable to composite X image",
8776 (*image)->filename);
8781 case AddBorderCommand:
8787 geometry[MaxTextExtent] = "6x6";
8790 Query user for border color and geometry.
8792 XColorBrowserWidget(display,windows,"Select",color);
8795 (void) XDialogWidget(display,windows,"Add Border",
8796 "Enter border geometry:",geometry);
8797 if (*geometry == '\0')
8800 Add a border to the image.
8802 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8803 XSetCursorState(display,windows,MagickTrue);
8804 XCheckRefreshWindows(display,windows);
8805 (void) QueryColorDatabase(color,&(*image)->border_color,
8806 &(*image)->exception);
8807 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8808 &(*image)->exception);
8809 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8810 if (border_image != (Image *) NULL)
8812 *image=DestroyImage(*image);
8813 *image=border_image;
8815 CatchException(&(*image)->exception);
8816 XSetCursorState(display,windows,MagickFalse);
8817 if (windows->image.orphan != MagickFalse)
8819 windows->image.window_changes.width=(int) (*image)->columns;
8820 windows->image.window_changes.height=(int) (*image)->rows;
8821 XConfigureImageColormap(display,resource_info,windows,*image);
8822 (void) XConfigureImage(display,resource_info,windows,*image);
8825 case AddFrameCommand:
8834 geometry[MaxTextExtent] = "6x6";
8837 Query user for frame color and geometry.
8839 XColorBrowserWidget(display,windows,"Select",color);
8842 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8844 if (*geometry == '\0')
8847 Surround image with an ornamental border.
8849 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8850 XSetCursorState(display,windows,MagickTrue);
8851 XCheckRefreshWindows(display,windows);
8852 (void) QueryColorDatabase(color,&(*image)->matte_color,
8853 &(*image)->exception);
8854 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8855 &(*image)->exception);
8856 frame_info.width=page_geometry.width;
8857 frame_info.height=page_geometry.height;
8858 frame_info.outer_bevel=page_geometry.x;
8859 frame_info.inner_bevel=page_geometry.y;
8860 frame_info.x=(ssize_t) frame_info.width;
8861 frame_info.y=(ssize_t) frame_info.height;
8862 frame_info.width=(*image)->columns+2*frame_info.width;
8863 frame_info.height=(*image)->rows+2*frame_info.height;
8864 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8865 if (frame_image != (Image *) NULL)
8867 *image=DestroyImage(*image);
8870 CatchException(&(*image)->exception);
8871 XSetCursorState(display,windows,MagickFalse);
8872 if (windows->image.orphan != MagickFalse)
8874 windows->image.window_changes.width=(int) (*image)->columns;
8875 windows->image.window_changes.height=(int) (*image)->rows;
8876 XConfigureImageColormap(display,resource_info,windows,*image);
8877 (void) XConfigureImage(display,resource_info,windows,*image);
8880 case CommentCommand:
8894 unique_file=AcquireUniqueFileResource(image_info->filename);
8895 if (unique_file == -1)
8896 XNoticeWidget(display,windows,"Unable to edit image comment",
8897 image_info->filename);
8898 value=GetImageProperty(*image,"comment");
8899 if (value == (char *) NULL)
8900 unique_file=close(unique_file)-1;
8906 file=fdopen(unique_file,"w");
8907 if (file == (FILE *) NULL)
8909 XNoticeWidget(display,windows,"Unable to edit image comment",
8910 image_info->filename);
8913 for (p=value; *p != '\0'; p++)
8914 (void) fputc((int) *p,file);
8915 (void) fputc('\n',file);
8916 (void) fclose(file);
8918 XSetCursorState(display,windows,MagickTrue);
8919 XCheckRefreshWindows(display,windows);
8920 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8921 &(*image)->exception);
8922 if (status == MagickFalse)
8923 XNoticeWidget(display,windows,"Unable to edit image comment",
8930 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8931 if (comment != (char *) NULL)
8933 (void) SetImageProperty(*image,"comment",comment);
8934 (*image)->taint=MagickTrue;
8937 (void) RelinquishUniqueFileResource(image_info->filename);
8938 XSetCursorState(display,windows,MagickFalse);
8946 XSetCursorState(display,windows,MagickTrue);
8947 XCheckRefreshWindows(display,windows);
8948 (void) AcquireUniqueFilename(filename);
8949 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
8951 status=WriteImage(image_info,*image,&(*image)->exception);
8952 if (status == MagickFalse)
8953 XNoticeWidget(display,windows,"Unable to launch image editor",
8957 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8958 CatchException(&(*image)->exception);
8959 XClientMessage(display,windows->image.id,windows->im_protocols,
8960 windows->im_next_image,CurrentTime);
8962 (void) RelinquishUniqueFileResource(filename);
8963 XSetCursorState(display,windows,MagickFalse);
8966 case RegionofInterestCommand:
8969 Apply an image processing technique to a region of interest.
8971 (void) XROIImage(display,resource_info,windows,image);
8981 if (windows->magnify.mapped != MagickFalse)
8982 (void) XRaiseWindow(display,windows->magnify.id);
8988 XSetCursorState(display,windows,MagickTrue);
8989 (void) XMapRaised(display,windows->magnify.id);
8990 XSetCursorState(display,windows,MagickFalse);
8994 case ShowPreviewCommand:
9003 preview_type[MaxTextExtent] = "Gamma";
9006 Select preview type from menu.
9008 previews=GetCommandOptions(MagickPreviewOptions);
9009 if (previews == (char **) NULL)
9011 XListBrowserWidget(display,windows,&windows->widget,
9012 (const char **) previews,"Preview",
9013 "Select an enhancement, effect, or F/X:",preview_type);
9014 previews=DestroyStringList(previews);
9015 if (*preview_type == '\0')
9020 XSetCursorState(display,windows,MagickTrue);
9021 XCheckRefreshWindows(display,windows);
9022 image_info->preview_type=(PreviewType)
9023 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
9024 image_info->group=(ssize_t) windows->image.id;
9025 (void) DeleteImageProperty(*image,"label");
9026 (void) SetImageProperty(*image,"label","Preview");
9027 (void) AcquireUniqueFilename(filename);
9028 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
9030 status=WriteImage(image_info,*image,&(*image)->exception);
9031 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9032 preview_image=ReadImage(image_info,&(*image)->exception);
9033 (void) RelinquishUniqueFileResource(filename);
9034 if (preview_image == (Image *) NULL)
9036 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
9038 status=WriteImage(image_info,preview_image,&(*image)->exception);
9039 preview_image=DestroyImage(preview_image);
9040 if (status == MagickFalse)
9041 XNoticeWidget(display,windows,"Unable to show image preview",
9042 (*image)->filename);
9043 XDelay(display,1500);
9044 XSetCursorState(display,windows,MagickFalse);
9047 case ShowHistogramCommand:
9053 Show image histogram.
9055 XSetCursorState(display,windows,MagickTrue);
9056 XCheckRefreshWindows(display,windows);
9057 image_info->group=(ssize_t) windows->image.id;
9058 (void) DeleteImageProperty(*image,"label");
9059 (void) SetImageProperty(*image,"label","Histogram");
9060 (void) AcquireUniqueFilename(filename);
9061 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
9063 status=WriteImage(image_info,*image,&(*image)->exception);
9064 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9065 histogram_image=ReadImage(image_info,&(*image)->exception);
9066 (void) RelinquishUniqueFileResource(filename);
9067 if (histogram_image == (Image *) NULL)
9069 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
9070 "show:%s",filename);
9071 status=WriteImage(image_info,histogram_image,&(*image)->exception);
9072 histogram_image=DestroyImage(histogram_image);
9073 if (status == MagickFalse)
9074 XNoticeWidget(display,windows,"Unable to show histogram",
9075 (*image)->filename);
9076 XDelay(display,1500);
9077 XSetCursorState(display,windows,MagickFalse);
9080 case ShowMatteCommand:
9085 if ((*image)->matte == MagickFalse)
9087 XNoticeWidget(display,windows,
9088 "Image does not have any matte information",(*image)->filename);
9094 XSetCursorState(display,windows,MagickTrue);
9095 XCheckRefreshWindows(display,windows);
9096 image_info->group=(ssize_t) windows->image.id;
9097 (void) DeleteImageProperty(*image,"label");
9098 (void) SetImageProperty(*image,"label","Matte");
9099 (void) AcquireUniqueFilename(filename);
9100 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
9102 status=WriteImage(image_info,*image,&(*image)->exception);
9103 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9104 matte_image=ReadImage(image_info,&(*image)->exception);
9105 (void) RelinquishUniqueFileResource(filename);
9106 if (matte_image == (Image *) NULL)
9108 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
9110 status=WriteImage(image_info,matte_image,&(*image)->exception);
9111 matte_image=DestroyImage(matte_image);
9112 if (status == MagickFalse)
9113 XNoticeWidget(display,windows,"Unable to show matte",
9114 (*image)->filename);
9115 XDelay(display,1500);
9116 XSetCursorState(display,windows,MagickFalse);
9119 case BackgroundCommand:
9124 status=XBackgroundImage(display,resource_info,windows,image);
9125 if (status == MagickFalse)
9127 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9128 if (nexus != (Image *) NULL)
9129 XClientMessage(display,windows->image.id,windows->im_protocols,
9130 windows->im_next_image,CurrentTime);
9133 case SlideShowCommand:
9136 delay[MaxTextExtent] = "5";
9139 Display next image after pausing.
9141 (void) XDialogWidget(display,windows,"Slide Show",
9142 "Pause how many 1/100ths of a second between images:",delay);
9145 resource_info->delay=StringToUnsignedLong(delay);
9146 XClientMessage(display,windows->image.id,windows->im_protocols,
9147 windows->im_next_image,CurrentTime);
9150 case PreferencesCommand:
9153 Set user preferences.
9155 status=XPreferencesWidget(display,resource_info,windows);
9156 if (status == MagickFalse)
9158 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9159 if (nexus != (Image *) NULL)
9160 XClientMessage(display,windows->image.id,windows->im_protocols,
9161 windows->im_next_image,CurrentTime);
9167 User requested help.
9169 XTextViewWidget(display,resource_info,windows,MagickFalse,
9170 "Help Viewer - Display",DisplayHelp);
9173 case BrowseDocumentationCommand:
9183 Browse the ImageMagick documentation.
9185 root_window=XRootWindow(display,XDefaultScreen(display));
9186 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9187 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9188 if (mozilla_window != (Window) NULL)
9191 command[MaxTextExtent],
9195 Display documentation using Netscape remote control.
9197 url=GetMagickHomeURL();
9198 (void) FormatLocaleString(command,MaxTextExtent,
9199 "openurl(%s,new-tab)",url);
9200 url=DestroyString(url);
9201 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9202 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9203 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9204 XSetCursorState(display,windows,MagickFalse);
9207 XSetCursorState(display,windows,MagickTrue);
9208 XCheckRefreshWindows(display,windows);
9209 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9210 &(*image)->exception);
9211 if (status == MagickFalse)
9212 XNoticeWidget(display,windows,"Unable to browse documentation",
9214 XDelay(display,1500);
9215 XSetCursorState(display,windows,MagickFalse);
9218 case VersionCommand:
9220 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9221 GetMagickCopyright());
9224 case SaveToUndoBufferCommand:
9228 (void) XBell(display,0);
9232 image_info=DestroyImageInfo(image_info);
9237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9241 + X M a g n i f y I m a g e %
9245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9247 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9248 % The magnified portion is displayed in a separate window.
9250 % The format of the XMagnifyImage method is:
9252 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9254 % A description of each parameter follows:
9256 % o display: Specifies a connection to an X server; returned from
9259 % o windows: Specifies a pointer to a XWindows structure.
9261 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9262 % the entire image is refreshed.
9265 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9268 text[MaxTextExtent];
9278 Update magnified image until the mouse button is released.
9280 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9284 windows->magnify.x=(int) windows->image.x+x;
9285 windows->magnify.y=(int) windows->image.y+y;
9289 Map and unmap Info widget as text cursor crosses its boundaries.
9291 if (windows->info.mapped != MagickFalse)
9293 if ((x < (int) (windows->info.x+windows->info.width)) &&
9294 (y < (int) (windows->info.y+windows->info.height)))
9295 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9298 if ((x > (int) (windows->info.x+windows->info.width)) ||
9299 (y > (int) (windows->info.y+windows->info.height)))
9300 (void) XMapWindow(display,windows->info.id);
9301 if (windows->info.mapped != MagickFalse)
9304 Display pointer position.
9306 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9307 windows->magnify.x,windows->magnify.y);
9308 XInfoWidget(display,windows,text);
9311 Wait for next event.
9313 XScreenEvent(display,windows,event);
9314 switch (event->type)
9321 User has finished magnifying image.
9340 Check boundary conditions.
9345 if (x >= (int) windows->image.width)
9346 x=(int) windows->image.width-1;
9350 if (y >= (int) windows->image.height)
9351 y=(int) windows->image.height-1;
9352 } while ((state & ExitState) == 0);
9354 Display magnified image.
9356 XSetCursorState(display,windows,MagickFalse);
9360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9364 + X M a g n i f y W i n d o w C o m m a n d %
9368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9370 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9371 % pixel as specified by the key symbol.
9373 % The format of the XMagnifyWindowCommand method is:
9375 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9376 % const MagickStatusType state,const KeySym key_symbol)
9378 % A description of each parameter follows:
9380 % o display: Specifies a connection to an X server; returned from
9383 % o windows: Specifies a pointer to a XWindows structure.
9385 % o state: key mask.
9387 % o key_symbol: Specifies a KeySym which indicates which side of the image
9391 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9392 const MagickStatusType state,const KeySym key_symbol)
9398 User specified a magnify factor or position.
9401 if ((state & Mod1Mask) != 0)
9403 switch ((int) key_symbol)
9407 (void) XWithdrawWindow(display,windows->magnify.id,
9408 windows->magnify.screen);
9414 windows->magnify.x=(int) windows->image.width/2;
9415 windows->magnify.y=(int) windows->image.height/2;
9421 if (windows->magnify.x > 0)
9422 windows->magnify.x-=quantum;
9428 if (windows->magnify.y > 0)
9429 windows->magnify.y-=quantum;
9435 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9436 windows->magnify.x+=quantum;
9442 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9443 windows->magnify.y+=quantum;
9457 windows->magnify.data=(key_symbol-XK_0);
9471 windows->magnify.data=(key_symbol-XK_KP_0);
9477 XMakeMagnifyImage(display,windows);
9481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9485 + X M a k e P a n I m a g e %
9489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9491 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9494 % The format of the XMakePanImage method is:
9496 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9497 % XWindows *windows,Image *image)
9499 % A description of each parameter follows:
9501 % o display: Specifies a connection to an X server; returned from
9504 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9506 % o windows: Specifies a pointer to a XWindows structure.
9508 % o image: the image.
9511 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9512 XWindows *windows,Image *image)
9518 Create and display image for panning icon.
9520 XSetCursorState(display,windows,MagickTrue);
9521 XCheckRefreshWindows(display,windows);
9522 windows->pan.x=(int) windows->image.x;
9523 windows->pan.y=(int) windows->image.y;
9524 status=XMakeImage(display,resource_info,&windows->pan,image,
9525 windows->pan.width,windows->pan.height);
9526 if (status == MagickFalse)
9527 ThrowXWindowFatalException(XServerError,image->exception.reason,
9528 image->exception.description);
9529 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9530 windows->pan.pixmap);
9531 (void) XClearWindow(display,windows->pan.id);
9532 XDrawPanRectangle(display,windows);
9533 XSetCursorState(display,windows,MagickFalse);
9537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9541 + X M a t t a E d i t I m a g e %
9545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9547 % XMatteEditImage() allows the user to interactively change the Matte channel
9548 % of an image. If the image is PseudoClass it is promoted to DirectClass
9549 % before the matte information is stored.
9551 % The format of the XMatteEditImage method is:
9553 % MagickBooleanType XMatteEditImage(Display *display,
9554 % XResourceInfo *resource_info,XWindows *windows,Image **image)
9556 % A description of each parameter follows:
9558 % o display: Specifies a connection to an X server; returned from
9561 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9563 % o windows: Specifies a pointer to a XWindows structure.
9565 % o image: the image; returned from ReadImage.
9568 static MagickBooleanType XMatteEditImage(Display *display,
9569 XResourceInfo *resource_info,XWindows *windows,Image **image)
9572 matte[MaxTextExtent] = "0";
9587 static const ModeType
9588 MatteEditCommands[] =
9591 MatteEditBorderCommand,
9592 MatteEditFuzzCommand,
9593 MatteEditValueCommand,
9594 MatteEditUndoCommand,
9595 MatteEditHelpCommand,
9596 MatteEditDismissCommand
9600 method = PointMethod;
9603 border_color = { 0, 0, 0, 0, 0, 0 };
9606 command[MaxTextExtent],
9607 text[MaxTextExtent];
9639 (void) CloneString(&windows->command.name,"Matte Edit");
9640 windows->command.data=4;
9641 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9642 (void) XMapRaised(display,windows->command.id);
9643 XClientMessage(display,windows->image.id,windows->im_protocols,
9644 windows->im_update_widget,CurrentTime);
9648 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9649 resource_info->background_color,resource_info->foreground_color);
9650 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9652 Track pointer until button 1 is pressed.
9654 XQueryPosition(display,windows->image.id,&x,&y);
9655 (void) XSelectInput(display,windows->image.id,
9656 windows->image.attributes.event_mask | PointerMotionMask);
9660 if (windows->info.mapped != MagickFalse)
9663 Display pointer position.
9665 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9666 x+windows->image.x,y+windows->image.y);
9667 XInfoWidget(display,windows,text);
9670 Wait for next event.
9672 XScreenEvent(display,windows,&event);
9673 if (event.xany.window == windows->command.id)
9676 Select a command from the Command widget.
9678 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9681 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9684 switch (MatteEditCommands[id])
9686 case MatteEditMethod:
9692 Select a method from the pop-up menu.
9694 methods=GetCommandOptions(MagickMethodOptions);
9695 if (methods == (char **) NULL)
9697 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9698 (const char **) methods,command);
9700 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9701 MagickFalse,methods[entry]);
9702 methods=DestroyStringList(methods);
9705 case MatteEditBorderCommand:
9708 *ColorMenu[MaxNumberPens];
9714 Initialize menu selections.
9716 for (i=0; i < (int) (MaxNumberPens-2); i++)
9717 ColorMenu[i]=resource_info->pen_colors[i];
9718 ColorMenu[MaxNumberPens-2]="Browser...";
9719 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9721 Select a pen color from the pop-up menu.
9723 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9724 (const char **) ColorMenu,command);
9727 if (pen_number == (MaxNumberPens-2))
9730 color_name[MaxTextExtent] = "gray";
9733 Select a pen color from a dialog.
9735 resource_info->pen_colors[pen_number]=color_name;
9736 XColorBrowserWidget(display,windows,"Select",color_name);
9737 if (*color_name == '\0')
9743 (void) XParseColor(display,windows->map_info->colormap,
9744 resource_info->pen_colors[pen_number],&border_color);
9747 case MatteEditFuzzCommand:
9750 fuzz[MaxTextExtent];
9765 Select a command from the pop-up menu.
9767 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9773 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
9777 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9778 (void) XDialogWidget(display,windows,"Ok",
9779 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9782 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9783 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
9786 case MatteEditValueCommand:
9789 message[MaxTextExtent];
9801 Select a command from the pop-up menu.
9803 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9809 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9811 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9812 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9813 (Quantum) TransparentAlpha);
9816 (void) FormatLocaleString(message,MaxTextExtent,
9817 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9819 (void) XDialogWidget(display,windows,"Matte",message,matte);
9824 case MatteEditUndoCommand:
9826 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9830 case MatteEditHelpCommand:
9832 XTextViewWidget(display,resource_info,windows,MagickFalse,
9833 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9836 case MatteEditDismissCommand:
9848 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9855 if (event.xbutton.button != Button1)
9857 if ((event.xbutton.window != windows->image.id) &&
9858 (event.xbutton.window != windows->magnify.id))
9865 (void) XMagickCommand(display,resource_info,windows,
9866 SaveToUndoBufferCommand,image);
9867 state|=UpdateConfigurationState;
9872 if (event.xbutton.button != Button1)
9874 if ((event.xbutton.window != windows->image.id) &&
9875 (event.xbutton.window != windows->magnify.id))
9878 Update colormap information.
9882 XConfigureImageColormap(display,resource_info,windows,*image);
9883 (void) XConfigureImage(display,resource_info,windows,*image);
9884 XInfoWidget(display,windows,text);
9885 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9886 state&=(~UpdateConfigurationState);
9894 command[MaxTextExtent];
9899 if (event.xkey.window == windows->magnify.id)
9904 window=windows->magnify.id;
9905 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9907 if (event.xkey.window != windows->image.id)
9910 Respond to a user key press.
9912 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9913 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9914 switch ((int) key_symbol)
9928 XTextViewWidget(display,resource_info,windows,MagickFalse,
9929 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9934 (void) XBell(display,0);
9943 Map and unmap Info widget as cursor crosses its boundaries.
9947 if (windows->info.mapped != MagickFalse)
9949 if ((x < (int) (windows->info.x+windows->info.width)) &&
9950 (y < (int) (windows->info.y+windows->info.height)))
9951 (void) XWithdrawWindow(display,windows->info.id,
9952 windows->info.screen);
9955 if ((x > (int) (windows->info.x+windows->info.width)) ||
9956 (y > (int) (windows->info.y+windows->info.height)))
9957 (void) XMapWindow(display,windows->info.id);
9963 if (event.xany.window == windows->magnify.id)
9965 x=windows->magnify.x-windows->image.x;
9966 y=windows->magnify.y-windows->image.y;
9970 if ((state & UpdateConfigurationState) != 0)
9983 Matte edit is relative to image configuration.
9985 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9987 XPutPixel(windows->image.ximage,x_offset,y_offset,
9988 windows->pixel_info->background_color.pixel);
9989 width=(unsigned int) (*image)->columns;
9990 height=(unsigned int) (*image)->rows;
9993 if (windows->image.crop_geometry != (char *) NULL)
9994 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
9996 x_offset=(int) (width*(windows->image.x+x_offset)/
9997 windows->image.ximage->width+x);
9998 y_offset=(int) (height*(windows->image.y+y_offset)/
9999 windows->image.ximage->height+y);
10000 if ((x_offset < 0) || (y_offset < 0))
10002 if ((x_offset >= (int) (*image)->columns) ||
10003 (y_offset >= (int) (*image)->rows))
10005 exception=(&(*image)->exception);
10006 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10007 return(MagickFalse);
10008 (*image)->matte=MagickTrue;
10009 image_view=AcquireCacheView(*image);
10016 Update matte information using point algorithm.
10018 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10019 (ssize_t) y_offset,1,1,exception);
10020 if (q == (Quantum *) NULL)
10022 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10023 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10026 case ReplaceMethod:
10033 Update matte information using replace algorithm.
10035 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
10036 (ssize_t) y_offset,&target,exception);
10037 for (y=0; y < (int) (*image)->rows; y++)
10039 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10040 (*image)->columns,1,&(*image)->exception);
10041 if (q == (Quantum *) NULL)
10043 for (x=0; x < (int) (*image)->columns; x++)
10045 GetPixelPacket(*image,q,&pixel);
10046 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
10047 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10048 q+=GetPixelChannels(*image);
10050 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10055 case FloodfillMethod:
10056 case FillToBorderMethod:
10068 Update matte information using floodfill algorithm.
10070 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10071 (ssize_t) y_offset,&target,exception);
10072 if (method == FillToBorderMethod)
10074 target.red=(MagickRealType) ScaleShortToQuantum(
10076 target.green=(MagickRealType) ScaleShortToQuantum(
10077 border_color.green);
10078 target.blue=(MagickRealType) ScaleShortToQuantum(
10079 border_color.blue);
10081 draw_info=CloneDrawInfo(resource_info->image_info,
10082 (DrawInfo *) NULL);
10083 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte,
10085 channel_mask=SetPixelChannelMask(*image,AlphaChannel);
10086 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10087 x_offset,(ssize_t) y_offset,method == FloodfillMethod ?
10088 MagickFalse : MagickTrue,exception);
10089 (void) SetPixelChannelMap(*image,channel_mask);
10090 draw_info=DestroyDrawInfo(draw_info);
10096 Update matte information using reset algorithm.
10098 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10099 return(MagickFalse);
10100 for (y=0; y < (int) (*image)->rows; y++)
10102 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10103 (*image)->columns,1,exception);
10104 if (q == (Quantum *) NULL)
10106 for (x=0; x < (int) (*image)->columns; x++)
10108 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10109 q+=GetPixelChannels(*image);
10111 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10114 if (StringToLong(matte) == (long) OpaqueAlpha)
10115 (*image)->matte=MagickFalse;
10119 image_view=DestroyCacheView(image_view);
10120 state&=(~UpdateConfigurationState);
10122 } while ((state & ExitState) == 0);
10123 (void) XSelectInput(display,windows->image.id,
10124 windows->image.attributes.event_mask);
10125 XSetCursorState(display,windows,MagickFalse);
10126 (void) XFreeCursor(display,cursor);
10127 return(MagickTrue);
10131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10135 + X O p e n I m a g e %
10139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10141 % XOpenImage() loads an image from a file.
10143 % The format of the XOpenImage method is:
10145 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10146 % XWindows *windows,const unsigned int command)
10148 % A description of each parameter follows:
10150 % o display: Specifies a connection to an X server; returned from
10153 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10155 % o windows: Specifies a pointer to a XWindows structure.
10157 % o command: A value other than zero indicates that the file is selected
10158 % from the command line argument list.
10161 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10162 XWindows *windows,const MagickBooleanType command)
10177 filename[MaxTextExtent] = "\0";
10180 Request file name from user.
10182 if (command == MagickFalse)
10183 XFileBrowserWidget(display,windows,"Open",filename);
10199 Select next image from the command line.
10201 status=XGetCommand(display,windows->image.id,&files,&count);
10204 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10205 return((Image *) NULL);
10207 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10208 if (filelist == (char **) NULL)
10210 ThrowXWindowFatalException(ResourceLimitError,
10211 "MemoryAllocationFailed","...");
10212 (void) XFreeStringList(files);
10213 return((Image *) NULL);
10216 for (i=1; i < count; i++)
10217 if (*files[i] != '-')
10218 filelist[j++]=files[i];
10219 filelist[j]=(char *) NULL;
10220 XListBrowserWidget(display,windows,&windows->widget,
10221 (const char **) filelist,"Load","Select Image to Load:",filename);
10222 filelist=(char **) RelinquishMagickMemory(filelist);
10223 (void) XFreeStringList(files);
10225 if (*filename == '\0')
10226 return((Image *) NULL);
10227 image_info=CloneImageInfo(resource_info->image_info);
10228 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10230 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10231 exception=AcquireExceptionInfo();
10232 (void) SetImageInfo(image_info,0,exception);
10233 if (LocaleCompare(image_info->magick,"X") == 0)
10236 seconds[MaxTextExtent];
10239 User may want to delay the X server screen grab.
10241 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10242 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10244 if (*seconds == '\0')
10245 return((Image *) NULL);
10246 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10248 magick_info=GetMagickInfo(image_info->magick,exception);
10249 if ((magick_info != (const MagickInfo *) NULL) &&
10250 (magick_info->raw != MagickFalse))
10253 geometry[MaxTextExtent];
10256 Request image size from the user.
10258 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10259 if (image_info->size != (char *) NULL)
10260 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10261 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10263 (void) CloneString(&image_info->size,geometry);
10268 XSetCursorState(display,windows,MagickTrue);
10269 XCheckRefreshWindows(display,windows);
10270 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10271 nexus=ReadImage(image_info,exception);
10272 CatchException(exception);
10273 XSetCursorState(display,windows,MagickFalse);
10274 if (nexus != (Image *) NULL)
10275 XClientMessage(display,windows->image.id,windows->im_protocols,
10276 windows->im_next_image,CurrentTime);
10284 Unknown image format.
10286 text=FileToString(filename,~0,exception);
10287 if (text == (char *) NULL)
10288 return((Image *) NULL);
10289 textlist=StringToList(text);
10290 if (textlist != (char **) NULL)
10293 title[MaxTextExtent];
10298 (void) FormatLocaleString(title,MaxTextExtent,
10299 "Unknown format: %s",filename);
10300 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10301 (const char **) textlist);
10302 for (i=0; textlist[i] != (char *) NULL; i++)
10303 textlist[i]=DestroyString(textlist[i]);
10304 textlist=(char **) RelinquishMagickMemory(textlist);
10306 text=DestroyString(text);
10308 exception=DestroyExceptionInfo(exception);
10309 image_info=DestroyImageInfo(image_info);
10314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10318 + X P a n I m a g e %
10322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10324 % XPanImage() pans the image until the mouse button is released.
10326 % The format of the XPanImage method is:
10328 % void XPanImage(Display *display,XWindows *windows,XEvent *event)
10330 % A description of each parameter follows:
10332 % o display: Specifies a connection to an X server; returned from
10335 % o windows: Specifies a pointer to a XWindows structure.
10337 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10338 % the entire image is refreshed.
10341 static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10344 text[MaxTextExtent];
10362 if ((windows->image.ximage->width > (int) windows->image.width) &&
10363 (windows->image.ximage->height > (int) windows->image.height))
10364 cursor=XCreateFontCursor(display,XC_fleur);
10366 if (windows->image.ximage->width > (int) windows->image.width)
10367 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10369 if (windows->image.ximage->height > (int) windows->image.height)
10370 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10372 cursor=XCreateFontCursor(display,XC_arrow);
10373 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10375 Pan image as pointer moves until the mouse button is released.
10377 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10378 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10379 pan_info.width=windows->pan.width*windows->image.width/
10380 windows->image.ximage->width;
10381 pan_info.height=windows->pan.height*windows->image.height/
10382 windows->image.ximage->height;
10385 state=UpdateConfigurationState;
10388 switch (event->type)
10393 User choose an initial pan location.
10395 pan_info.x=(ssize_t) event->xbutton.x;
10396 pan_info.y=(ssize_t) event->xbutton.y;
10397 state|=UpdateConfigurationState;
10400 case ButtonRelease:
10403 User has finished panning the image.
10405 pan_info.x=(ssize_t) event->xbutton.x;
10406 pan_info.y=(ssize_t) event->xbutton.y;
10407 state|=UpdateConfigurationState | ExitState;
10412 pan_info.x=(ssize_t) event->xmotion.x;
10413 pan_info.y=(ssize_t) event->xmotion.y;
10414 state|=UpdateConfigurationState;
10419 if ((state & UpdateConfigurationState) != 0)
10422 Check boundary conditions.
10424 if (pan_info.x < (ssize_t) (pan_info.width/2))
10427 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10428 if (pan_info.x < 0)
10431 if ((int) (pan_info.x+windows->image.width) >
10432 windows->image.ximage->width)
10433 pan_info.x=(ssize_t)
10434 (windows->image.ximage->width-windows->image.width);
10435 if (pan_info.y < (ssize_t) (pan_info.height/2))
10438 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10439 if (pan_info.y < 0)
10442 if ((int) (pan_info.y+windows->image.height) >
10443 windows->image.ximage->height)
10444 pan_info.y=(ssize_t)
10445 (windows->image.ximage->height-windows->image.height);
10446 if ((windows->image.x != (int) pan_info.x) ||
10447 (windows->image.y != (int) pan_info.y))
10450 Display image pan offset.
10452 windows->image.x=(int) pan_info.x;
10453 windows->image.y=(int) pan_info.y;
10454 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
10455 windows->image.width,windows->image.height,windows->image.x,
10457 XInfoWidget(display,windows,text);
10459 Refresh Image window.
10461 XDrawPanRectangle(display,windows);
10462 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10464 state&=(~UpdateConfigurationState);
10467 Wait for next event.
10469 if ((state & ExitState) == 0)
10470 XScreenEvent(display,windows,event);
10471 } while ((state & ExitState) == 0);
10475 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10476 (void) XFreeCursor(display,cursor);
10477 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10485 + X P a s t e I m a g e %
10489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10491 % XPasteImage() pastes an image previously saved with XCropImage in the X
10492 % window image at a location the user chooses with the pointer.
10494 % The format of the XPasteImage method is:
10496 % MagickBooleanType XPasteImage(Display *display,
10497 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10499 % A description of each parameter follows:
10501 % o display: Specifies a connection to an X server; returned from
10504 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10506 % o windows: Specifies a pointer to a XWindows structure.
10508 % o image: the image; returned from ReadImage.
10511 static MagickBooleanType XPasteImage(Display *display,
10512 XResourceInfo *resource_info,XWindows *windows,Image *image)
10523 static const ModeType
10526 PasteOperatorsCommand,
10528 PasteDismissCommand
10531 static CompositeOperator
10532 compose = CopyCompositeOp;
10535 text[MaxTextExtent];
10569 if (resource_info->copy_image == (Image *) NULL)
10570 return(MagickFalse);
10571 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10572 &image->exception);
10574 Map Command widget.
10576 (void) CloneString(&windows->command.name,"Paste");
10577 windows->command.data=1;
10578 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10579 (void) XMapRaised(display,windows->command.id);
10580 XClientMessage(display,windows->image.id,windows->im_protocols,
10581 windows->im_update_widget,CurrentTime);
10583 Track pointer until button 1 is pressed.
10585 XSetCursorState(display,windows,MagickFalse);
10586 XQueryPosition(display,windows->image.id,&x,&y);
10587 (void) XSelectInput(display,windows->image.id,
10588 windows->image.attributes.event_mask | PointerMotionMask);
10589 paste_info.x=(ssize_t) windows->image.x+x;
10590 paste_info.y=(ssize_t) windows->image.y+y;
10591 paste_info.width=0;
10592 paste_info.height=0;
10593 cursor=XCreateFontCursor(display,XC_ul_angle);
10594 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10595 state=DefaultState;
10598 if (windows->info.mapped != MagickFalse)
10601 Display pointer position.
10603 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
10604 (long) paste_info.x,(long) paste_info.y);
10605 XInfoWidget(display,windows,text);
10607 highlight_info=paste_info;
10608 highlight_info.x=paste_info.x-windows->image.x;
10609 highlight_info.y=paste_info.y-windows->image.y;
10610 XHighlightRectangle(display,windows->image.id,
10611 windows->image.highlight_context,&highlight_info);
10613 Wait for next event.
10615 XScreenEvent(display,windows,&event);
10616 XHighlightRectangle(display,windows->image.id,
10617 windows->image.highlight_context,&highlight_info);
10618 if (event.xany.window == windows->command.id)
10621 Select a command from the Command widget.
10623 id=XCommandWidget(display,windows,PasteMenu,&event);
10626 switch (PasteCommands[id])
10628 case PasteOperatorsCommand:
10631 command[MaxTextExtent],
10635 Select a command from the pop-up menu.
10637 operators=GetCommandOptions(MagickComposeOptions);
10638 if (operators == (char **) NULL)
10640 entry=XMenuWidget(display,windows,PasteMenu[id],
10641 (const char **) operators,command);
10643 compose=(CompositeOperator) ParseCommandOption(
10644 MagickComposeOptions,MagickFalse,operators[entry]);
10645 operators=DestroyStringList(operators);
10648 case PasteHelpCommand:
10650 XTextViewWidget(display,resource_info,windows,MagickFalse,
10651 "Help Viewer - Image Composite",ImagePasteHelp);
10654 case PasteDismissCommand:
10659 state|=EscapeState;
10668 switch (event.type)
10672 if (image->debug != MagickFalse)
10673 (void) LogMagickEvent(X11Event,GetMagickModule(),
10674 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10675 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10676 if (event.xbutton.button != Button1)
10678 if (event.xbutton.window != windows->image.id)
10681 Paste rectangle is relative to image configuration.
10683 width=(unsigned int) image->columns;
10684 height=(unsigned int) image->rows;
10687 if (windows->image.crop_geometry != (char *) NULL)
10688 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10690 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10691 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10692 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10693 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10694 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10695 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10696 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10699 case ButtonRelease:
10701 if (image->debug != MagickFalse)
10702 (void) LogMagickEvent(X11Event,GetMagickModule(),
10703 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10704 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10705 if (event.xbutton.button != Button1)
10707 if (event.xbutton.window != windows->image.id)
10709 if ((paste_info.width != 0) && (paste_info.height != 0))
10712 User has selected the location of the paste image.
10714 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10715 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10725 command[MaxTextExtent];
10733 if (event.xkey.window != windows->image.id)
10736 Respond to a user key press.
10738 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10739 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10740 *(command+length)='\0';
10741 if (image->debug != MagickFalse)
10742 (void) LogMagickEvent(X11Event,GetMagickModule(),
10743 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10744 switch ((int) key_symbol)
10752 paste_image=DestroyImage(paste_image);
10753 state|=EscapeState;
10760 (void) XSetFunction(display,windows->image.highlight_context,
10762 XTextViewWidget(display,resource_info,windows,MagickFalse,
10763 "Help Viewer - Image Composite",ImagePasteHelp);
10764 (void) XSetFunction(display,windows->image.highlight_context,
10770 (void) XBell(display,0);
10779 Map and unmap Info widget as text cursor crosses its boundaries.
10783 if (windows->info.mapped != MagickFalse)
10785 if ((x < (int) (windows->info.x+windows->info.width)) &&
10786 (y < (int) (windows->info.y+windows->info.height)))
10787 (void) XWithdrawWindow(display,windows->info.id,
10788 windows->info.screen);
10791 if ((x > (int) (windows->info.x+windows->info.width)) ||
10792 (y > (int) (windows->info.y+windows->info.height)))
10793 (void) XMapWindow(display,windows->info.id);
10794 paste_info.x=(ssize_t) windows->image.x+x;
10795 paste_info.y=(ssize_t) windows->image.y+y;
10800 if (image->debug != MagickFalse)
10801 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10806 } while ((state & ExitState) == 0);
10807 (void) XSelectInput(display,windows->image.id,
10808 windows->image.attributes.event_mask);
10809 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10810 XSetCursorState(display,windows,MagickFalse);
10811 (void) XFreeCursor(display,cursor);
10812 if ((state & EscapeState) != 0)
10813 return(MagickTrue);
10815 Image pasting is relative to image configuration.
10817 XSetCursorState(display,windows,MagickTrue);
10818 XCheckRefreshWindows(display,windows);
10819 width=(unsigned int) image->columns;
10820 height=(unsigned int) image->rows;
10823 if (windows->image.crop_geometry != (char *) NULL)
10824 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10825 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10827 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10828 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10829 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10831 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10832 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10834 Paste image with X Image window.
10836 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10837 paste_image=DestroyImage(paste_image);
10838 XSetCursorState(display,windows,MagickFalse);
10840 Update image colormap.
10842 XConfigureImageColormap(display,resource_info,windows,image);
10843 (void) XConfigureImage(display,resource_info,windows,image);
10844 return(MagickTrue);
10848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10852 + X P r i n t I m a g e %
10856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10858 % XPrintImage() prints an image to a Postscript printer.
10860 % The format of the XPrintImage method is:
10862 % MagickBooleanType XPrintImage(Display *display,
10863 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10865 % A description of each parameter follows:
10867 % o display: Specifies a connection to an X server; returned from
10870 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10872 % o windows: Specifies a pointer to a XWindows structure.
10874 % o image: the image.
10877 static MagickBooleanType XPrintImage(Display *display,
10878 XResourceInfo *resource_info,XWindows *windows,Image *image)
10881 filename[MaxTextExtent],
10882 geometry[MaxTextExtent];
10894 Request Postscript page geometry from user.
10896 image_info=CloneImageInfo(resource_info->image_info);
10897 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
10898 if (image_info->page != (char *) NULL)
10899 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10900 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10901 "Select Postscript Page Geometry:",geometry);
10902 if (*geometry == '\0')
10903 return(MagickTrue);
10904 image_info->page=GetPageGeometry(geometry);
10906 Apply image transforms.
10908 XSetCursorState(display,windows,MagickTrue);
10909 XCheckRefreshWindows(display,windows);
10910 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10911 if (print_image == (Image *) NULL)
10912 return(MagickFalse);
10913 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
10914 windows->image.ximage->width,windows->image.ximage->height);
10915 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10919 (void) AcquireUniqueFilename(filename);
10920 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
10922 status=WriteImage(image_info,print_image,&image->exception);
10923 (void) RelinquishUniqueFileResource(filename);
10924 print_image=DestroyImage(print_image);
10925 image_info=DestroyImageInfo(image_info);
10926 XSetCursorState(display,windows,MagickFalse);
10927 return(status != 0 ? MagickTrue : MagickFalse);
10931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10935 + X R O I I m a g e %
10939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10941 % XROIImage() applies an image processing technique to a region of interest.
10943 % The format of the XROIImage method is:
10945 % MagickBooleanType XROIImage(Display *display,
10946 % XResourceInfo *resource_info,XWindows *windows,Image **image)
10948 % A description of each parameter follows:
10950 % o display: Specifies a connection to an X server; returned from
10953 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10955 % o windows: Specifies a pointer to a XWindows structure.
10957 % o image: the image; returned from ReadImage.
10960 static MagickBooleanType XROIImage(Display *display,
10961 XResourceInfo *resource_info,XWindows *windows,Image **image)
10963 #define ApplyMenus 7
11013 "Contrast Stretch...",
11014 "Sigmoidal Contrast...",
11048 "Charcoal Draw...",
11051 *MiscellanyMenu[] =
11062 **Menus[ApplyMenus] =
11073 static const CommandType
11096 TransformCommands[] =
11100 RotateRightCommand,
11103 EnhanceCommands[] =
11111 ContrastStretchCommand,
11112 SigmoidalContrastCommand,
11120 EffectsCommands[] =
11124 ReduceNoiseCommand,
11143 CharcoalDrawCommand
11145 MiscellanyCommands[] =
11149 ShowPreviewCommand,
11150 ShowHistogramCommand,
11159 static const CommandType
11160 *Commands[ApplyMenus] =
11172 command[MaxTextExtent],
11173 text[MaxTextExtent];
11193 MagickProgressMonitor
11212 Map Command widget.
11214 (void) CloneString(&windows->command.name,"ROI");
11215 windows->command.data=0;
11216 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11217 (void) XMapRaised(display,windows->command.id);
11218 XClientMessage(display,windows->image.id,windows->im_protocols,
11219 windows->im_update_widget,CurrentTime);
11221 Track pointer until button 1 is pressed.
11223 XQueryPosition(display,windows->image.id,&x,&y);
11224 (void) XSelectInput(display,windows->image.id,
11225 windows->image.attributes.event_mask | PointerMotionMask);
11226 roi_info.x=(ssize_t) windows->image.x+x;
11227 roi_info.y=(ssize_t) windows->image.y+y;
11230 cursor=XCreateFontCursor(display,XC_fleur);
11231 state=DefaultState;
11234 if (windows->info.mapped != MagickFalse)
11237 Display pointer position.
11239 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
11240 (long) roi_info.x,(long) roi_info.y);
11241 XInfoWidget(display,windows,text);
11244 Wait for next event.
11246 XScreenEvent(display,windows,&event);
11247 if (event.xany.window == windows->command.id)
11250 Select a command from the Command widget.
11252 id=XCommandWidget(display,windows,ROIMenu,&event);
11255 switch (ROICommands[id])
11257 case ROIHelpCommand:
11259 XTextViewWidget(display,resource_info,windows,MagickFalse,
11260 "Help Viewer - Region of Interest",ImageROIHelp);
11263 case ROIDismissCommand:
11268 state|=EscapeState;
11277 switch (event.type)
11281 if (event.xbutton.button != Button1)
11283 if (event.xbutton.window != windows->image.id)
11286 Note first corner of region of interest rectangle-- exit loop.
11288 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11289 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11290 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11294 case ButtonRelease:
11303 if (event.xkey.window != windows->image.id)
11306 Respond to a user key press.
11308 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11309 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11310 switch ((int) key_symbol)
11318 state|=EscapeState;
11325 XTextViewWidget(display,resource_info,windows,MagickFalse,
11326 "Help Viewer - Region of Interest",ImageROIHelp);
11331 (void) XBell(display,0);
11340 Map and unmap Info widget as text cursor crosses its boundaries.
11344 if (windows->info.mapped != MagickFalse)
11346 if ((x < (int) (windows->info.x+windows->info.width)) &&
11347 (y < (int) (windows->info.y+windows->info.height)))
11348 (void) XWithdrawWindow(display,windows->info.id,
11349 windows->info.screen);
11352 if ((x > (int) (windows->info.x+windows->info.width)) ||
11353 (y > (int) (windows->info.y+windows->info.height)))
11354 (void) XMapWindow(display,windows->info.id);
11355 roi_info.x=(ssize_t) windows->image.x+x;
11356 roi_info.y=(ssize_t) windows->image.y+y;
11362 } while ((state & ExitState) == 0);
11363 (void) XSelectInput(display,windows->image.id,
11364 windows->image.attributes.event_mask);
11365 if ((state & EscapeState) != 0)
11368 User want to exit without region of interest.
11370 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11371 (void) XFreeCursor(display,cursor);
11372 return(MagickTrue);
11374 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11378 Size rectangle as pointer moves until the mouse button is released.
11380 x=(int) roi_info.x;
11381 y=(int) roi_info.y;
11384 state=DefaultState;
11387 highlight_info=roi_info;
11388 highlight_info.x=roi_info.x-windows->image.x;
11389 highlight_info.y=roi_info.y-windows->image.y;
11390 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11393 Display info and draw region of interest rectangle.
11395 if (windows->info.mapped == MagickFalse)
11396 (void) XMapWindow(display,windows->info.id);
11397 (void) FormatLocaleString(text,MaxTextExtent,
11398 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11399 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11400 XInfoWidget(display,windows,text);
11401 XHighlightRectangle(display,windows->image.id,
11402 windows->image.highlight_context,&highlight_info);
11405 if (windows->info.mapped != MagickFalse)
11406 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11408 Wait for next event.
11410 XScreenEvent(display,windows,&event);
11411 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11412 XHighlightRectangle(display,windows->image.id,
11413 windows->image.highlight_context,&highlight_info);
11414 switch (event.type)
11418 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11419 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11422 case ButtonRelease:
11425 User has committed to region of interest rectangle.
11427 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11428 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11429 XSetCursorState(display,windows,MagickFalse);
11431 if (LocaleCompare(windows->command.name,"Apply") == 0)
11433 (void) CloneString(&windows->command.name,"Apply");
11434 windows->command.data=ApplyMenus;
11435 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11442 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11443 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11448 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11449 ((state & ExitState) != 0))
11452 Check boundary conditions.
11454 if (roi_info.x < 0)
11457 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11458 roi_info.x=(ssize_t) windows->image.ximage->width;
11459 if ((int) roi_info.x < x)
11460 roi_info.width=(unsigned int) (x-roi_info.x);
11463 roi_info.width=(unsigned int) (roi_info.x-x);
11464 roi_info.x=(ssize_t) x;
11466 if (roi_info.y < 0)
11469 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11470 roi_info.y=(ssize_t) windows->image.ximage->height;
11471 if ((int) roi_info.y < y)
11472 roi_info.height=(unsigned int) (y-roi_info.y);
11475 roi_info.height=(unsigned int) (roi_info.y-y);
11476 roi_info.y=(ssize_t) y;
11479 } while ((state & ExitState) == 0);
11481 Wait for user to grab a corner of the rectangle or press return.
11483 state=DefaultState;
11484 command_type=NullCommand;
11485 (void) XMapWindow(display,windows->info.id);
11488 if (windows->info.mapped != MagickFalse)
11491 Display pointer position.
11493 (void) FormatLocaleString(text,MaxTextExtent,
11494 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11495 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11496 XInfoWidget(display,windows,text);
11498 highlight_info=roi_info;
11499 highlight_info.x=roi_info.x-windows->image.x;
11500 highlight_info.y=roi_info.y-windows->image.y;
11501 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11503 state|=EscapeState;
11507 if ((state & UpdateRegionState) != 0)
11509 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11510 switch (command_type)
11515 (void) XMagickCommand(display,resource_info,windows,command_type,
11522 Region of interest is relative to image configuration.
11524 progress_monitor=SetImageProgressMonitor(*image,
11525 (MagickProgressMonitor) NULL,(*image)->client_data);
11526 crop_info=roi_info;
11527 width=(unsigned int) (*image)->columns;
11528 height=(unsigned int) (*image)->rows;
11531 if (windows->image.crop_geometry != (char *) NULL)
11532 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11534 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11536 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11537 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11538 scale_factor=(MagickRealType)
11539 height/windows->image.ximage->height;
11541 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11542 crop_info.height=(unsigned int)
11543 (scale_factor*crop_info.height+0.5);
11544 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11545 (void) SetImageProgressMonitor(*image,progress_monitor,
11546 (*image)->client_data);
11547 if (roi_image == (Image *) NULL)
11550 Apply image processing technique to the region of interest.
11552 windows->image.orphan=MagickTrue;
11553 (void) XMagickCommand(display,resource_info,windows,command_type,
11555 progress_monitor=SetImageProgressMonitor(*image,
11556 (MagickProgressMonitor) NULL,(*image)->client_data);
11557 (void) XMagickCommand(display,resource_info,windows,
11558 SaveToUndoBufferCommand,image);
11559 windows->image.orphan=MagickFalse;
11560 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11561 crop_info.x,crop_info.y);
11562 roi_image=DestroyImage(roi_image);
11563 (void) SetImageProgressMonitor(*image,progress_monitor,
11564 (*image)->client_data);
11568 if (command_type != InfoCommand)
11570 XConfigureImageColormap(display,resource_info,windows,*image);
11571 (void) XConfigureImage(display,resource_info,windows,*image);
11573 XCheckRefreshWindows(display,windows);
11574 XInfoWidget(display,windows,text);
11575 (void) XSetFunction(display,windows->image.highlight_context,
11577 state&=(~UpdateRegionState);
11579 XHighlightRectangle(display,windows->image.id,
11580 windows->image.highlight_context,&highlight_info);
11581 XScreenEvent(display,windows,&event);
11582 if (event.xany.window == windows->command.id)
11585 Select a command from the Command widget.
11587 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11588 command_type=NullCommand;
11589 id=XCommandWidget(display,windows,ApplyMenu,&event);
11592 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11593 command_type=ApplyCommands[id];
11594 if (id < ApplyMenus)
11597 Select a command from a pop-up menu.
11599 entry=XMenuWidget(display,windows,ApplyMenu[id],
11600 (const char **) Menus[id],command);
11603 (void) CopyMagickString(command,Menus[id][entry],
11605 command_type=Commands[id][entry];
11609 (void) XSetFunction(display,windows->image.highlight_context,
11611 XHighlightRectangle(display,windows->image.id,
11612 windows->image.highlight_context,&highlight_info);
11613 if (command_type == HelpCommand)
11615 (void) XSetFunction(display,windows->image.highlight_context,
11617 XTextViewWidget(display,resource_info,windows,MagickFalse,
11618 "Help Viewer - Region of Interest",ImageROIHelp);
11619 (void) XSetFunction(display,windows->image.highlight_context,
11623 if (command_type == QuitCommand)
11628 state|=EscapeState;
11632 if (command_type != NullCommand)
11633 state|=UpdateRegionState;
11636 XHighlightRectangle(display,windows->image.id,
11637 windows->image.highlight_context,&highlight_info);
11638 switch (event.type)
11642 x=windows->image.x;
11643 y=windows->image.y;
11644 if (event.xbutton.button != Button1)
11646 if (event.xbutton.window != windows->image.id)
11648 x=windows->image.x+event.xbutton.x;
11649 y=windows->image.y+event.xbutton.y;
11650 if ((x < (int) (roi_info.x+RoiDelta)) &&
11651 (x > (int) (roi_info.x-RoiDelta)) &&
11652 (y < (int) (roi_info.y+RoiDelta)) &&
11653 (y > (int) (roi_info.y-RoiDelta)))
11655 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11656 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11657 state|=UpdateConfigurationState;
11660 if ((x < (int) (roi_info.x+RoiDelta)) &&
11661 (x > (int) (roi_info.x-RoiDelta)) &&
11662 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11663 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11665 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11666 state|=UpdateConfigurationState;
11669 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11670 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11671 (y < (int) (roi_info.y+RoiDelta)) &&
11672 (y > (int) (roi_info.y-RoiDelta)))
11674 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11675 state|=UpdateConfigurationState;
11678 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11679 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11680 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11681 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11683 state|=UpdateConfigurationState;
11687 case ButtonRelease:
11689 if (event.xbutton.window == windows->pan.id)
11690 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11691 (highlight_info.y != crop_info.y-windows->image.y))
11692 XHighlightRectangle(display,windows->image.id,
11693 windows->image.highlight_context,&highlight_info);
11694 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11695 event.xbutton.time);
11700 if (event.xexpose.window == windows->image.id)
11701 if (event.xexpose.count == 0)
11703 event.xexpose.x=(int) highlight_info.x;
11704 event.xexpose.y=(int) highlight_info.y;
11705 event.xexpose.width=(int) highlight_info.width;
11706 event.xexpose.height=(int) highlight_info.height;
11707 XRefreshWindow(display,&windows->image,&event);
11709 if (event.xexpose.window == windows->info.id)
11710 if (event.xexpose.count == 0)
11711 XInfoWidget(display,windows,text);
11719 if (event.xkey.window != windows->image.id)
11722 Respond to a user key press.
11724 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11725 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11726 switch ((int) key_symbol)
11733 state|=EscapeState;
11742 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11743 roi_info.y=(ssize_t) (windows->image.height/2L-
11744 roi_info.height/2L);
11776 (void) XSetFunction(display,windows->image.highlight_context,
11778 XTextViewWidget(display,resource_info,windows,MagickFalse,
11779 "Help Viewer - Region of Interest",ImageROIHelp);
11780 (void) XSetFunction(display,windows->image.highlight_context,
11786 command_type=XImageWindowCommand(display,resource_info,windows,
11787 event.xkey.state,key_symbol,image);
11788 if (command_type != NullCommand)
11789 state|=UpdateRegionState;
11793 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11801 if (event.xbutton.window != windows->image.id)
11804 Map and unmap Info widget as text cursor crosses its boundaries.
11808 if (windows->info.mapped != MagickFalse)
11810 if ((x < (int) (windows->info.x+windows->info.width)) &&
11811 (y < (int) (windows->info.y+windows->info.height)))
11812 (void) XWithdrawWindow(display,windows->info.id,
11813 windows->info.screen);
11816 if ((x > (int) (windows->info.x+windows->info.width)) ||
11817 (y > (int) (windows->info.y+windows->info.height)))
11818 (void) XMapWindow(display,windows->info.id);
11819 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11820 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11823 case SelectionRequest:
11828 XSelectionRequestEvent
11832 Set primary selection.
11834 (void) FormatLocaleString(text,MaxTextExtent,
11835 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11836 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11837 request=(&(event.xselectionrequest));
11838 (void) XChangeProperty(request->display,request->requestor,
11839 request->property,request->target,8,PropModeReplace,
11840 (unsigned char *) text,(int) strlen(text));
11841 notify.type=SelectionNotify;
11842 notify.display=request->display;
11843 notify.requestor=request->requestor;
11844 notify.selection=request->selection;
11845 notify.target=request->target;
11846 notify.time=request->time;
11847 if (request->property == None)
11848 notify.property=request->target;
11850 notify.property=request->property;
11851 (void) XSendEvent(request->display,request->requestor,False,0,
11852 (XEvent *) ¬ify);
11857 if ((state & UpdateConfigurationState) != 0)
11859 (void) XPutBackEvent(display,&event);
11860 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11863 } while ((state & ExitState) == 0);
11864 } while ((state & ExitState) == 0);
11865 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11866 XSetCursorState(display,windows,MagickFalse);
11867 if ((state & EscapeState) != 0)
11868 return(MagickTrue);
11869 return(MagickTrue);
11873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11877 + X R o t a t e I m a g e %
11881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11883 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11884 % rotation angle is computed from the slope of a line drawn by the user.
11886 % The format of the XRotateImage method is:
11888 % MagickBooleanType XRotateImage(Display *display,
11889 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11892 % A description of each parameter follows:
11894 % o display: Specifies a connection to an X server; returned from
11897 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11899 % o windows: Specifies a pointer to a XWindows structure.
11901 % o degrees: Specifies the number of degrees to rotate the image.
11903 % o image: the image.
11906 static MagickBooleanType XRotateImage(Display *display,
11907 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11920 direction = HorizontalRotateCommand;
11922 static const ModeType
11923 DirectionCommands[] =
11925 HorizontalRotateCommand,
11926 VerticalRotateCommand
11930 RotateColorCommand,
11931 RotateDirectionCommand,
11933 RotateDismissCommand
11936 static unsigned int
11940 command[MaxTextExtent],
11941 text[MaxTextExtent];
11952 normalized_degrees;
11962 if (degrees == 0.0)
11977 Map Command widget.
11979 (void) CloneString(&windows->command.name,"Rotate");
11980 windows->command.data=2;
11981 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11982 (void) XMapRaised(display,windows->command.id);
11983 XClientMessage(display,windows->image.id,windows->im_protocols,
11984 windows->im_update_widget,CurrentTime);
11986 Wait for first button press.
11988 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11989 XQueryPosition(display,windows->image.id,&x,&y);
11994 state=DefaultState;
11997 XHighlightLine(display,windows->image.id,
11998 windows->image.highlight_context,&rotate_info);
12000 Wait for next event.
12002 XScreenEvent(display,windows,&event);
12003 XHighlightLine(display,windows->image.id,
12004 windows->image.highlight_context,&rotate_info);
12005 if (event.xany.window == windows->command.id)
12008 Select a command from the Command widget.
12010 id=XCommandWidget(display,windows,RotateMenu,&event);
12013 (void) XSetFunction(display,windows->image.highlight_context,
12015 switch (RotateCommands[id])
12017 case RotateColorCommand:
12020 *ColorMenu[MaxNumberPens];
12029 Initialize menu selections.
12031 for (i=0; i < (int) (MaxNumberPens-2); i++)
12032 ColorMenu[i]=resource_info->pen_colors[i];
12033 ColorMenu[MaxNumberPens-2]="Browser...";
12034 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12036 Select a pen color from the pop-up menu.
12038 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12039 (const char **) ColorMenu,command);
12040 if (pen_number < 0)
12042 if (pen_number == (MaxNumberPens-2))
12045 color_name[MaxTextExtent] = "gray";
12048 Select a pen color from a dialog.
12050 resource_info->pen_colors[pen_number]=color_name;
12051 XColorBrowserWidget(display,windows,"Select",color_name);
12052 if (*color_name == '\0')
12058 (void) XParseColor(display,windows->map_info->colormap,
12059 resource_info->pen_colors[pen_number],&color);
12060 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12061 (unsigned int) MaxColors,&color);
12062 windows->pixel_info->pen_colors[pen_number]=color;
12063 pen_id=(unsigned int) pen_number;
12066 case RotateDirectionCommand:
12077 Select a command from the pop-up menu.
12079 id=XMenuWidget(display,windows,RotateMenu[id],
12080 Directions,command);
12082 direction=DirectionCommands[id];
12085 case RotateHelpCommand:
12087 XTextViewWidget(display,resource_info,windows,MagickFalse,
12088 "Help Viewer - Image Rotation",ImageRotateHelp);
12091 case RotateDismissCommand:
12096 state|=EscapeState;
12103 (void) XSetFunction(display,windows->image.highlight_context,
12107 switch (event.type)
12111 if (event.xbutton.button != Button1)
12113 if (event.xbutton.window != windows->image.id)
12118 (void) XSetFunction(display,windows->image.highlight_context,
12120 rotate_info.x1=event.xbutton.x;
12121 rotate_info.y1=event.xbutton.y;
12125 case ButtonRelease:
12132 command[MaxTextExtent];
12137 if (event.xkey.window != windows->image.id)
12140 Respond to a user key press.
12142 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12143 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12144 switch ((int) key_symbol)
12152 state|=EscapeState;
12159 (void) XSetFunction(display,windows->image.highlight_context,
12161 XTextViewWidget(display,resource_info,windows,MagickFalse,
12162 "Help Viewer - Image Rotation",ImageRotateHelp);
12163 (void) XSetFunction(display,windows->image.highlight_context,
12169 (void) XBell(display,0);
12177 rotate_info.x1=event.xmotion.x;
12178 rotate_info.y1=event.xmotion.y;
12181 rotate_info.x2=rotate_info.x1;
12182 rotate_info.y2=rotate_info.y1;
12183 if (direction == HorizontalRotateCommand)
12184 rotate_info.x2+=32;
12186 rotate_info.y2-=32;
12187 } while ((state & ExitState) == 0);
12188 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12189 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12190 if ((state & EscapeState) != 0)
12191 return(MagickTrue);
12193 Draw line as pointer moves until the mouse button is released.
12196 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12197 state=DefaultState;
12203 Display info and draw rotation line.
12205 if (windows->info.mapped == MagickFalse)
12206 (void) XMapWindow(display,windows->info.id);
12207 (void) FormatLocaleString(text,MaxTextExtent," %g",
12208 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12209 XInfoWidget(display,windows,text);
12210 XHighlightLine(display,windows->image.id,
12211 windows->image.highlight_context,&rotate_info);
12214 if (windows->info.mapped != MagickFalse)
12215 (void) XWithdrawWindow(display,windows->info.id,
12216 windows->info.screen);
12218 Wait for next event.
12220 XScreenEvent(display,windows,&event);
12222 XHighlightLine(display,windows->image.id,
12223 windows->image.highlight_context,&rotate_info);
12224 switch (event.type)
12228 case ButtonRelease:
12231 User has committed to rotation line.
12233 rotate_info.x2=event.xbutton.x;
12234 rotate_info.y2=event.xbutton.y;
12242 rotate_info.x2=event.xmotion.x;
12243 rotate_info.y2=event.xmotion.y;
12249 Check boundary conditions.
12251 if (rotate_info.x2 < 0)
12254 if (rotate_info.x2 > (int) windows->image.width)
12255 rotate_info.x2=(short) windows->image.width;
12256 if (rotate_info.y2 < 0)
12259 if (rotate_info.y2 > (int) windows->image.height)
12260 rotate_info.y2=(short) windows->image.height;
12262 Compute rotation angle from the slope of the line.
12265 distance=(unsigned int)
12266 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12267 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12269 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12270 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12271 } while ((state & ExitState) == 0);
12272 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12273 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12275 return(MagickTrue);
12277 if (direction == VerticalRotateCommand)
12279 if (degrees == 0.0)
12280 return(MagickTrue);
12284 normalized_degrees=degrees;
12285 while (normalized_degrees < -45.0)
12286 normalized_degrees+=360.0;
12287 for (rotations=0; normalized_degrees > 45.0; rotations++)
12288 normalized_degrees-=90.0;
12289 if (normalized_degrees != 0.0)
12290 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12291 XSetCursorState(display,windows,MagickTrue);
12292 XCheckRefreshWindows(display,windows);
12293 (*image)->background_color.red=ScaleShortToQuantum(
12294 windows->pixel_info->pen_colors[pen_id].red);
12295 (*image)->background_color.green=ScaleShortToQuantum(
12296 windows->pixel_info->pen_colors[pen_id].green);
12297 (*image)->background_color.blue=ScaleShortToQuantum(
12298 windows->pixel_info->pen_colors[pen_id].blue);
12299 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12300 XSetCursorState(display,windows,MagickFalse);
12301 if (rotate_image == (Image *) NULL)
12302 return(MagickFalse);
12303 *image=DestroyImage(*image);
12304 *image=rotate_image;
12305 if (windows->image.crop_geometry != (char *) NULL)
12308 Rotate crop geometry.
12310 width=(unsigned int) (*image)->columns;
12311 height=(unsigned int) (*image)->rows;
12312 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12313 switch (rotations % 4)
12323 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12324 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12331 Rotate 180 degrees.
12333 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12334 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12340 Rotate 270 degrees.
12342 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12343 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12348 if (windows->image.orphan != MagickFalse)
12349 return(MagickTrue);
12350 if (normalized_degrees != 0.0)
12353 Update image colormap.
12355 windows->image.window_changes.width=(int) (*image)->columns;
12356 windows->image.window_changes.height=(int) (*image)->rows;
12357 if (windows->image.crop_geometry != (char *) NULL)
12360 Obtain dimensions of image from crop geometry.
12362 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12364 windows->image.window_changes.width=(int) width;
12365 windows->image.window_changes.height=(int) height;
12367 XConfigureImageColormap(display,resource_info,windows,*image);
12370 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12372 windows->image.window_changes.width=windows->image.ximage->height;
12373 windows->image.window_changes.height=windows->image.ximage->width;
12376 Update image configuration.
12378 (void) XConfigureImage(display,resource_info,windows,*image);
12379 return(MagickTrue);
12383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12387 + X S a v e I m a g e %
12391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12393 % XSaveImage() saves an image to a file.
12395 % The format of the XSaveImage method is:
12397 % MagickBooleanType XSaveImage(Display *display,
12398 % XResourceInfo *resource_info,XWindows *windows,Image *image)
12400 % A description of each parameter follows:
12402 % o display: Specifies a connection to an X server; returned from
12405 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12407 % o windows: Specifies a pointer to a XWindows structure.
12409 % o image: the image.
12412 static MagickBooleanType XSaveImage(Display *display,
12413 XResourceInfo *resource_info,XWindows *windows,Image *image)
12416 filename[MaxTextExtent],
12417 geometry[MaxTextExtent];
12429 Request file name from user.
12431 if (resource_info->write_filename != (char *) NULL)
12432 (void) CopyMagickString(filename,resource_info->write_filename,
12437 path[MaxTextExtent];
12442 GetPathComponent(image->filename,HeadPath,path);
12443 GetPathComponent(image->filename,TailPath,filename);
12444 status=chdir(path);
12446 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12447 FileOpenError,"UnableToOpenFile","%s",path);
12449 XFileBrowserWidget(display,windows,"Save",filename);
12450 if (*filename == '\0')
12451 return(MagickTrue);
12452 if (IsPathAccessible(filename) != MagickFalse)
12458 File exists-- seek user's permission before overwriting.
12460 status=XConfirmWidget(display,windows,"Overwrite",filename);
12462 return(MagickTrue);
12464 image_info=CloneImageInfo(resource_info->image_info);
12465 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12466 (void) SetImageInfo(image_info,1,&image->exception);
12467 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12468 (LocaleCompare(image_info->magick,"JPG") == 0))
12471 quality[MaxTextExtent];
12477 Request JPEG quality from user.
12479 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
12481 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12483 if (*quality == '\0')
12484 return(MagickTrue);
12485 image->quality=StringToUnsignedLong(quality);
12486 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12488 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12489 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12490 (LocaleCompare(image_info->magick,"PS") == 0) ||
12491 (LocaleCompare(image_info->magick,"PS2") == 0))
12494 geometry[MaxTextExtent];
12497 Request page geometry from user.
12499 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12500 if (LocaleCompare(image_info->magick,"PDF") == 0)
12501 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12502 if (image_info->page != (char *) NULL)
12503 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12504 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12505 "Select page geometry:",geometry);
12506 if (*geometry != '\0')
12507 image_info->page=GetPageGeometry(geometry);
12510 Apply image transforms.
12512 XSetCursorState(display,windows,MagickTrue);
12513 XCheckRefreshWindows(display,windows);
12514 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12515 if (save_image == (Image *) NULL)
12516 return(MagickFalse);
12517 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
12518 windows->image.ximage->width,windows->image.ximage->height);
12519 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12523 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12524 status=WriteImage(image_info,save_image,&image->exception);
12525 if (status != MagickFalse)
12526 image->taint=MagickFalse;
12527 save_image=DestroyImage(save_image);
12528 image_info=DestroyImageInfo(image_info);
12529 XSetCursorState(display,windows,MagickFalse);
12530 return(status != 0 ? MagickTrue : MagickFalse);
12534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12538 + X S c r e e n E v e n t %
12542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12544 % XScreenEvent() handles global events associated with the Pan and Magnify
12547 % The format of the XScreenEvent function is:
12549 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12551 % A description of each parameter follows:
12553 % o display: Specifies a pointer to the Display structure; returned from
12556 % o windows: Specifies a pointer to a XWindows structure.
12558 % o event: Specifies a pointer to a X11 XEvent structure.
12563 #if defined(__cplusplus) || defined(c_plusplus)
12567 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12572 windows=(XWindows *) data;
12573 if ((event->type == ClientMessage) &&
12574 (event->xclient.window == windows->image.id))
12575 return(MagickFalse);
12576 return(MagickTrue);
12579 #if defined(__cplusplus) || defined(c_plusplus)
12583 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12589 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12590 if (event->xany.window == windows->command.id)
12592 switch (event->type)
12595 case ButtonRelease:
12597 if ((event->xbutton.button == Button3) &&
12598 (event->xbutton.state & Mod1Mask))
12601 Convert Alt-Button3 to Button2.
12603 event->xbutton.button=Button2;
12604 event->xbutton.state&=(~Mod1Mask);
12606 if (event->xbutton.window == windows->backdrop.id)
12608 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12609 event->xbutton.time);
12612 if (event->xbutton.window == windows->pan.id)
12614 XPanImage(display,windows,event);
12617 if (event->xbutton.window == windows->image.id)
12618 if (event->xbutton.button == Button2)
12621 Update magnified image.
12623 x=event->xbutton.x;
12624 y=event->xbutton.y;
12628 if (x >= (int) windows->image.width)
12629 x=(int) (windows->image.width-1);
12630 windows->magnify.x=(int) windows->image.x+x;
12634 if (y >= (int) windows->image.height)
12635 y=(int) (windows->image.height-1);
12636 windows->magnify.y=windows->image.y+y;
12637 if (windows->magnify.mapped == MagickFalse)
12638 (void) XMapRaised(display,windows->magnify.id);
12639 XMakeMagnifyImage(display,windows);
12640 if (event->type == ButtonRelease)
12641 (void) XWithdrawWindow(display,windows->info.id,
12642 windows->info.screen);
12647 case ClientMessage:
12650 If client window delete message, exit.
12652 if (event->xclient.message_type != windows->wm_protocols)
12654 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12656 if (event->xclient.window == windows->magnify.id)
12658 (void) XWithdrawWindow(display,windows->magnify.id,
12659 windows->magnify.screen);
12664 case ConfigureNotify:
12666 if (event->xconfigure.window == windows->magnify.id)
12672 Magnify window has a new configuration.
12674 windows->magnify.width=(unsigned int) event->xconfigure.width;
12675 windows->magnify.height=(unsigned int) event->xconfigure.height;
12676 if (windows->magnify.mapped == MagickFalse)
12679 while ((int) magnify <= event->xconfigure.width)
12681 while ((int) magnify <= event->xconfigure.height)
12684 if (((int) magnify != event->xconfigure.width) ||
12685 ((int) magnify != event->xconfigure.height))
12690 window_changes.width=(int) magnify;
12691 window_changes.height=(int) magnify;
12692 (void) XReconfigureWMWindow(display,windows->magnify.id,
12693 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12697 XMakeMagnifyImage(display,windows);
12704 if (event->xexpose.window == windows->image.id)
12706 XRefreshWindow(display,&windows->image,event);
12709 if (event->xexpose.window == windows->pan.id)
12710 if (event->xexpose.count == 0)
12712 XDrawPanRectangle(display,windows);
12715 if (event->xexpose.window == windows->magnify.id)
12716 if (event->xexpose.count == 0)
12718 XMakeMagnifyImage(display,windows);
12726 command[MaxTextExtent];
12731 if (event->xkey.window != windows->magnify.id)
12734 Respond to a user key press.
12736 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12737 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12738 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12743 if (event->xmap.window == windows->magnify.id)
12745 windows->magnify.mapped=MagickTrue;
12746 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12749 if (event->xmap.window == windows->info.id)
12751 windows->info.mapped=MagickTrue;
12758 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12759 if (event->xmotion.window == windows->image.id)
12760 if (windows->magnify.mapped != MagickFalse)
12763 Update magnified image.
12765 x=event->xmotion.x;
12766 y=event->xmotion.y;
12770 if (x >= (int) windows->image.width)
12771 x=(int) (windows->image.width-1);
12772 windows->magnify.x=(int) windows->image.x+x;
12776 if (y >= (int) windows->image.height)
12777 y=(int) (windows->image.height-1);
12778 windows->magnify.y=windows->image.y+y;
12779 XMakeMagnifyImage(display,windows);
12785 if (event->xunmap.window == windows->magnify.id)
12787 windows->magnify.mapped=MagickFalse;
12790 if (event->xunmap.window == windows->info.id)
12792 windows->info.mapped=MagickFalse;
12803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12807 + X S e t C r o p G e o m e t r y %
12811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12813 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12814 % and translates it to a cropping geometry relative to the image.
12816 % The format of the XSetCropGeometry method is:
12818 % void XSetCropGeometry(Display *display,XWindows *windows,
12819 % RectangleInfo *crop_info,Image *image)
12821 % A description of each parameter follows:
12823 % o display: Specifies a connection to an X server; returned from
12826 % o windows: Specifies a pointer to a XWindows structure.
12828 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12829 % Image window to crop.
12831 % o image: the image.
12834 static void XSetCropGeometry(Display *display,XWindows *windows,
12835 RectangleInfo *crop_info,Image *image)
12838 text[MaxTextExtent];
12851 if (windows->info.mapped != MagickFalse)
12854 Display info on cropping rectangle.
12856 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12857 (double) crop_info->width,(double) crop_info->height,(double)
12858 crop_info->x,(double) crop_info->y);
12859 XInfoWidget(display,windows,text);
12862 Cropping geometry is relative to any previous crop geometry.
12866 width=(unsigned int) image->columns;
12867 height=(unsigned int) image->rows;
12868 if (windows->image.crop_geometry != (char *) NULL)
12869 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12871 windows->image.crop_geometry=AcquireString((char *) NULL);
12873 Define the crop geometry string from the cropping rectangle.
12875 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12876 if (crop_info->x > 0)
12877 x+=(int) (scale_factor*crop_info->x+0.5);
12878 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12881 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12882 if (crop_info->y > 0)
12883 y+=(int) (scale_factor*crop_info->y+0.5);
12884 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12887 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12888 "%ux%u%+d%+d",width,height,x,y);
12892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12896 + X T i l e I m a g e %
12900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12902 % XTileImage() loads or deletes a selected tile from a visual image directory.
12903 % The load or delete command is chosen from a menu.
12905 % The format of the XTileImage method is:
12907 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
12908 % XWindows *windows,Image *image,XEvent *event)
12910 % A description of each parameter follows:
12912 % o tile_image: XTileImage reads or deletes the tile image
12913 % and returns it. A null image is returned if an error occurs.
12915 % o display: Specifies a connection to an X server; returned from
12918 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12920 % o windows: Specifies a pointer to a XWindows structure.
12922 % o image: the image; returned from ReadImage.
12924 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
12925 % the entire image is refreshed.
12928 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12929 XWindows *windows,Image *image,XEvent *event)
12942 static const ModeType
12953 command[MaxTextExtent],
12954 filename[MaxTextExtent];
12981 Tile image is relative to montage image configuration.
12985 width=(unsigned int) image->columns;
12986 height=(unsigned int) image->rows;
12987 if (windows->image.crop_geometry != (char *) NULL)
12988 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12989 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12990 event->xbutton.x+=windows->image.x;
12991 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12992 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12993 event->xbutton.y+=windows->image.y;
12994 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12996 Determine size and location of each tile in the visual image directory.
12998 width=(unsigned int) image->columns;
12999 height=(unsigned int) image->rows;
13002 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13003 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13004 (event->xbutton.x-x)/width;
13008 Button press is outside any tile.
13010 (void) XBell(display,0);
13011 return((Image *) NULL);
13014 Determine file name from the tile directory.
13016 p=image->directory;
13017 for (i=tile; (i != 0) && (*p != '\0'); )
13026 Button press is outside any tile.
13028 (void) XBell(display,0);
13029 return((Image *) NULL);
13032 Select a command from the pop-up menu.
13034 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13036 return((Image *) NULL);
13038 while ((*q != '\n') && (*q != '\0'))
13040 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13042 Perform command for the selected tile.
13044 XSetCursorState(display,windows,MagickTrue);
13045 XCheckRefreshWindows(display,windows);
13046 tile_image=NewImageList();
13047 switch (TileCommands[id])
13049 case TileLoadCommand:
13054 XCheckRefreshWindows(display,windows);
13055 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13057 (void) CopyMagickString(resource_info->image_info->filename,filename,
13059 tile_image=ReadImage(resource_info->image_info,&image->exception);
13060 CatchException(&image->exception);
13061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13064 case TileNextCommand:
13067 Display next image.
13069 XClientMessage(display,windows->image.id,windows->im_protocols,
13070 windows->im_next_image,CurrentTime);
13073 case TileFormerCommand:
13076 Display former image.
13078 XClientMessage(display,windows->image.id,windows->im_protocols,
13079 windows->im_former_image,CurrentTime);
13082 case TileDeleteCommand:
13087 if (IsPathAccessible(filename) == MagickFalse)
13089 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13092 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13095 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13096 if (status != MagickFalse)
13098 XNoticeWidget(display,windows,"Unable to delete image file:",
13103 case TileUpdateCommand:
13122 Ensure all the images exist.
13125 for (p=image->directory; *p != '\0'; p++)
13131 while ((*q != '\n') && (*q != '\0'))
13133 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13135 if (IsPathAccessible(filename) != MagickFalse)
13141 Overwrite tile with background color.
13143 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13144 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13145 exception=(&image->exception);
13146 image_view=AcquireCacheView(image);
13147 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13148 for (i=0; i < (int) height; i++)
13150 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13151 y_offset+i,width,1,exception);
13152 if (s == (Quantum *) NULL)
13154 for (j=0; j < (int) width; j++)
13156 SetPixelPacket(image,&pixel,s);
13157 s+=GetPixelChannels(image);
13159 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13162 image_view=DestroyCacheView(image_view);
13165 windows->image.window_changes.width=(int) image->columns;
13166 windows->image.window_changes.height=(int) image->rows;
13167 XConfigureImageColormap(display,resource_info,windows,image);
13168 (void) XConfigureImage(display,resource_info,windows,image);
13174 XSetCursorState(display,windows,MagickFalse);
13175 return(tile_image);
13179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13183 + X T r a n s l a t e I m a g e %
13187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13189 % XTranslateImage() translates the image within an Image window by one pixel
13190 % as specified by the key symbol. If the image has a `montage string the
13191 % translation is respect to the width and height contained within the string.
13193 % The format of the XTranslateImage method is:
13195 % void XTranslateImage(Display *display,XWindows *windows,
13196 % Image *image,const KeySym key_symbol)
13198 % A description of each parameter follows:
13200 % o display: Specifies a connection to an X server; returned from
13203 % o windows: Specifies a pointer to a XWindows structure.
13205 % o image: the image.
13207 % o key_symbol: Specifies a KeySym which indicates which side of the image
13211 static void XTranslateImage(Display *display,XWindows *windows,
13212 Image *image,const KeySym key_symbol)
13215 text[MaxTextExtent];
13226 User specified a pan position offset.
13228 x_offset=windows->image.width;
13229 y_offset=windows->image.height;
13230 if (image->montage != (char *) NULL)
13231 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13232 switch ((int) key_symbol)
13237 windows->image.x=(int) windows->image.width/2;
13238 windows->image.y=(int) windows->image.height/2;
13244 windows->image.x-=x_offset;
13251 windows->image.y-=y_offset;
13257 windows->image.x+=x_offset;
13264 windows->image.y+=y_offset;
13271 Check boundary conditions.
13273 if (windows->image.x < 0)
13274 windows->image.x=0;
13276 if ((int) (windows->image.x+windows->image.width) >
13277 windows->image.ximage->width)
13278 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13279 if (windows->image.y < 0)
13280 windows->image.y=0;
13282 if ((int) (windows->image.y+windows->image.height) >
13283 windows->image.ximage->height)
13284 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13286 Refresh Image window.
13288 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
13289 windows->image.width,windows->image.height,windows->image.x,
13291 XInfoWidget(display,windows,text);
13292 XCheckRefreshWindows(display,windows);
13293 XDrawPanRectangle(display,windows);
13294 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13295 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13303 + X T r i m I m a g e %
13307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13309 % XTrimImage() trims the edges from the Image window.
13311 % The format of the XTrimImage method is:
13313 % MagickBooleanType XTrimImage(Display *display,
13314 % XResourceInfo *resource_info,XWindows *windows,Image *image)
13316 % A description of each parameter follows:
13318 % o display: Specifies a connection to an X server; returned from
13321 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13323 % o windows: Specifies a pointer to a XWindows structure.
13325 % o image: the image.
13328 static MagickBooleanType XTrimImage(Display *display,
13329 XResourceInfo *resource_info,XWindows *windows,Image *image)
13343 Trim edges from image.
13345 XSetCursorState(display,windows,MagickTrue);
13346 XCheckRefreshWindows(display,windows);
13348 Crop the left edge.
13350 background=XGetPixel(windows->image.ximage,0,0);
13351 trim_info.width=(size_t) windows->image.ximage->width;
13352 for (x=0; x < windows->image.ximage->width; x++)
13354 for (y=0; y < windows->image.ximage->height; y++)
13356 pixel=XGetPixel(windows->image.ximage,x,y);
13357 if (pixel != background)
13360 if (y < windows->image.ximage->height)
13363 trim_info.x=(ssize_t) x;
13364 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13366 XSetCursorState(display,windows,MagickFalse);
13367 return(MagickFalse);
13370 Crop the right edge.
13372 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13373 for (x=windows->image.ximage->width-1; x != 0; x--)
13375 for (y=0; y < windows->image.ximage->height; y++)
13377 pixel=XGetPixel(windows->image.ximage,x,y);
13378 if (pixel != background)
13381 if (y < windows->image.ximage->height)
13384 trim_info.width=(size_t) (x-trim_info.x+1);
13388 background=XGetPixel(windows->image.ximage,0,0);
13389 trim_info.height=(size_t) windows->image.ximage->height;
13390 for (y=0; y < windows->image.ximage->height; y++)
13392 for (x=0; x < windows->image.ximage->width; x++)
13394 pixel=XGetPixel(windows->image.ximage,x,y);
13395 if (pixel != background)
13398 if (x < windows->image.ximage->width)
13401 trim_info.y=(ssize_t) y;
13403 Crop the bottom edge.
13405 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13406 for (y=windows->image.ximage->height-1; y != 0; y--)
13408 for (x=0; x < windows->image.ximage->width; x++)
13410 pixel=XGetPixel(windows->image.ximage,x,y);
13411 if (pixel != background)
13414 if (x < windows->image.ximage->width)
13417 trim_info.height=(size_t) y-trim_info.y+1;
13418 if (((unsigned int) trim_info.width != windows->image.width) ||
13419 ((unsigned int) trim_info.height != windows->image.height))
13422 Reconfigure Image window as defined by the trimming rectangle.
13424 XSetCropGeometry(display,windows,&trim_info,image);
13425 windows->image.window_changes.width=(int) trim_info.width;
13426 windows->image.window_changes.height=(int) trim_info.height;
13427 (void) XConfigureImage(display,resource_info,windows,image);
13429 XSetCursorState(display,windows,MagickFalse);
13430 return(MagickTrue);
13434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13438 + X V i s u a l D i r e c t o r y I m a g e %
13442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13444 % XVisualDirectoryImage() creates a Visual Image Directory.
13446 % The format of the XVisualDirectoryImage method is:
13448 % Image *XVisualDirectoryImage(Display *display,
13449 % XResourceInfo *resource_info,XWindows *windows)
13451 % A description of each parameter follows:
13453 % o nexus: Method XVisualDirectoryImage returns a visual image
13454 % directory if it can be created successfully. Otherwise a null image
13457 % o display: Specifies a connection to an X server; returned from
13460 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13462 % o windows: Specifies a pointer to a XWindows structure.
13465 static Image *XVisualDirectoryImage(Display *display,
13466 XResourceInfo *resource_info,XWindows *windows)
13468 #define TileImageTag "Scale/Image"
13469 #define XClientName "montage"
13505 filename[MaxTextExtent] = "\0",
13506 filenames[MaxTextExtent] = "*";
13509 background_resources;
13512 Request file name from user.
13514 XFileBrowserWidget(display,windows,"Directory",filenames);
13515 if (*filenames == '\0')
13516 return((Image *) NULL);
13518 Expand the filenames.
13520 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13521 if (filelist == (char **) NULL)
13523 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13525 return((Image *) NULL);
13528 filelist[0]=filenames;
13529 status=ExpandFilenames(&number_files,&filelist);
13530 if ((status == MagickFalse) || (number_files == 0))
13532 if (number_files == 0)
13533 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13535 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13537 return((Image *) NULL);
13540 Set image background resources.
13542 background_resources=(*resource_info);
13543 background_resources.window_id=AcquireString("");
13544 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
13545 "0x%lx",windows->image.id);
13546 background_resources.backdrop=MagickTrue;
13548 Read each image and convert them to a tile.
13550 backdrop=(windows->visual_info->klass == TrueColor) ||
13551 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13552 read_info=CloneImageInfo(resource_info->image_info);
13553 (void) SetImageOption(read_info,"jpeg:size","120x120");
13554 (void) CloneString(&read_info->size,DefaultTileGeometry);
13555 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13557 images=NewImageList();
13558 exception=AcquireExceptionInfo();
13559 XSetCursorState(display,windows,MagickTrue);
13560 XCheckRefreshWindows(display,windows);
13561 for (i=0; i < (int) number_files; i++)
13563 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13564 filelist[i]=DestroyString(filelist[i]);
13565 *read_info->magick='\0';
13566 next_image=ReadImage(read_info,exception);
13567 CatchException(exception);
13568 if (next_image != (Image *) NULL)
13570 (void) DeleteImageProperty(next_image,"label");
13571 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13572 read_info,next_image,DefaultTileLabel));
13573 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13575 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13576 geometry.height,exception);
13577 if (thumbnail_image != (Image *) NULL)
13579 next_image=DestroyImage(next_image);
13580 next_image=thumbnail_image;
13584 (void) XDisplayBackgroundImage(display,&background_resources,
13586 XSetCursorState(display,windows,MagickTrue);
13588 AppendImageToList(&images,next_image);
13589 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13594 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13595 (MagickSizeType) number_files);
13596 if (proceed == MagickFalse)
13601 exception=DestroyExceptionInfo(exception);
13602 filelist=(char **) RelinquishMagickMemory(filelist);
13603 if (images == (Image *) NULL)
13605 read_info=DestroyImageInfo(read_info);
13606 XSetCursorState(display,windows,MagickFalse);
13607 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13608 return((Image *) NULL);
13611 Create the Visual Image Directory.
13613 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13614 montage_info->pointsize=10;
13615 if (resource_info->font != (char *) NULL)
13616 (void) CloneString(&montage_info->font,resource_info->font);
13617 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13618 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13619 images),&images->exception);
13620 images=DestroyImageList(images);
13621 montage_info=DestroyMontageInfo(montage_info);
13622 read_info=DestroyImageInfo(read_info);
13623 XSetCursorState(display,windows,MagickFalse);
13624 if (montage_image == (Image *) NULL)
13625 return(montage_image);
13626 XClientMessage(display,windows->image.id,windows->im_protocols,
13627 windows->im_next_image,CurrentTime);
13628 return(montage_image);
13632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13636 % X D i s p l a y B a c k g r o u n d I m a g e %
13640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13642 % XDisplayBackgroundImage() displays an image in the background of a window.
13644 % The format of the XDisplayBackgroundImage method is:
13646 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13647 % XResourceInfo *resource_info,Image *image)
13649 % A description of each parameter follows:
13651 % o display: Specifies a connection to an X server; returned from
13654 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13656 % o image: the image.
13659 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13660 XResourceInfo *resource_info,Image *image)
13663 geometry[MaxTextExtent],
13664 visual_type[MaxTextExtent];
13677 static XStandardColormap
13681 *visual_info = (XVisualInfo *) NULL;
13702 Determine target window.
13704 assert(image != (Image *) NULL);
13705 assert(image->signature == MagickSignature);
13706 if (image->debug != MagickFalse)
13707 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13708 resources=(*resource_info);
13709 window_info.id=(Window) NULL;
13710 root_window=XRootWindow(display,XDefaultScreen(display));
13711 if (LocaleCompare(resources.window_id,"root") == 0)
13712 window_info.id=root_window;
13715 if (isdigit((unsigned char) *resources.window_id) != 0)
13716 window_info.id=XWindowByID(display,root_window,
13717 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13718 if (window_info.id == (Window) NULL)
13719 window_info.id=XWindowByName(display,root_window,resources.window_id);
13721 if (window_info.id == (Window) NULL)
13723 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13724 resources.window_id);
13725 return(MagickFalse);
13728 Determine window visual id.
13730 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13731 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13732 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13733 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13735 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
13736 XVisualIDFromVisual(window_attributes.visual));
13737 if (visual_info == (XVisualInfo *) NULL)
13740 Allocate standard colormap.
13742 map_info=XAllocStandardColormap();
13743 if (map_info == (XStandardColormap *) NULL)
13744 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13746 map_info->colormap=(Colormap) NULL;
13747 pixel.pixels=(unsigned long *) NULL;
13749 Initialize visual info.
13751 resources.map_type=(char *) NULL;
13752 resources.visual_type=visual_type;
13753 visual_info=XBestVisualInfo(display,map_info,&resources);
13754 if (visual_info == (XVisualInfo *) NULL)
13755 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13756 resources.visual_type);
13758 Initialize window info.
13760 window_info.ximage=(XImage *) NULL;
13761 window_info.matte_image=(XImage *) NULL;
13762 window_info.pixmap=(Pixmap) NULL;
13763 window_info.matte_pixmap=(Pixmap) NULL;
13766 Free previous root colors.
13768 if (window_info.id == root_window)
13769 (void) XDestroyWindowColors(display,root_window);
13771 Initialize Standard Colormap.
13773 resources.colormap=SharedColormap;
13774 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13776 Graphic context superclass.
13778 context_values.background=pixel.background_color.pixel;
13779 context_values.foreground=pixel.foreground_color.pixel;
13780 pixel.annotate_context=XCreateGC(display,window_info.id,
13781 (size_t) (GCBackground | GCForeground),&context_values);
13782 if (pixel.annotate_context == (GC) NULL)
13783 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13786 Initialize Image window attributes.
13788 window_info.name=AcquireString("\0");
13789 window_info.icon_name=AcquireString("\0");
13790 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13791 &resources,&window_info);
13793 Create the X image.
13795 window_info.width=(unsigned int) image->columns;
13796 window_info.height=(unsigned int) image->rows;
13797 if ((image->columns != window_info.width) ||
13798 (image->rows != window_info.height))
13799 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13801 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
13802 window_attributes.width,window_attributes.height);
13803 geometry_info.width=window_info.width;
13804 geometry_info.height=window_info.height;
13805 geometry_info.x=(ssize_t) window_info.x;
13806 geometry_info.y=(ssize_t) window_info.y;
13807 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13808 &geometry_info.width,&geometry_info.height);
13809 window_info.width=(unsigned int) geometry_info.width;
13810 window_info.height=(unsigned int) geometry_info.height;
13811 window_info.x=(int) geometry_info.x;
13812 window_info.y=(int) geometry_info.y;
13813 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13814 window_info.height);
13815 if (status == MagickFalse)
13816 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13820 if (image->debug != MagickFalse)
13822 (void) LogMagickEvent(X11Event,GetMagickModule(),
13823 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13824 (double) image->columns,(double) image->rows);
13825 if (image->colors != 0)
13826 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13828 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13831 Adjust image dimensions as specified by backdrop or geometry options.
13833 width=(int) window_info.width;
13834 height=(int) window_info.height;
13835 if (resources.backdrop != MagickFalse)
13838 Center image on window.
13840 window_info.x=(window_attributes.width/2)-
13841 (window_info.ximage->width/2);
13842 window_info.y=(window_attributes.height/2)-
13843 (window_info.ximage->height/2);
13844 width=window_attributes.width;
13845 height=window_attributes.height;
13847 if ((resources.image_geometry != (char *) NULL) &&
13848 (*resources.image_geometry != '\0'))
13851 default_geometry[MaxTextExtent];
13861 User specified geometry.
13863 size_hints=XAllocSizeHints();
13864 if (size_hints == (XSizeHints *) NULL)
13865 ThrowXWindowFatalException(ResourceLimitFatalError,
13866 "MemoryAllocationFailed",image->filename);
13867 size_hints->flags=0L;
13868 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
13870 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13871 default_geometry,window_info.border_width,size_hints,&window_info.x,
13872 &window_info.y,&width,&height,&gravity);
13873 if (flags & (XValue | YValue))
13875 width=window_attributes.width;
13876 height=window_attributes.height;
13878 (void) XFree((void *) size_hints);
13881 Create the X pixmap.
13883 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13884 (unsigned int) height,window_info.depth);
13885 if (window_info.pixmap == (Pixmap) NULL)
13886 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13889 Display pixmap on the window.
13891 if (((unsigned int) width > window_info.width) ||
13892 ((unsigned int) height > window_info.height))
13893 (void) XFillRectangle(display,window_info.pixmap,
13894 window_info.annotate_context,0,0,(unsigned int) width,
13895 (unsigned int) height);
13896 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13897 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13898 window_info.width,(unsigned int) window_info.height);
13899 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13900 (void) XClearWindow(display,window_info.id);
13901 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13902 XDelay(display,delay == 0UL ? 10UL : delay);
13903 (void) XSync(display,MagickFalse);
13904 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13912 + X D i s p l a y I m a g e %
13916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13918 % XDisplayImage() displays an image via X11. A new image is created and
13919 % returned if the user interactively transforms the displayed image.
13921 % The format of the XDisplayImage method is:
13923 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13924 % char **argv,int argc,Image **image,size_t *state)
13926 % A description of each parameter follows:
13928 % o nexus: Method XDisplayImage returns an image when the
13929 % user chooses 'Open Image' from the command menu or picks a tile
13930 % from the image directory. Otherwise a null image is returned.
13932 % o display: Specifies a connection to an X server; returned from
13935 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13937 % o argv: Specifies the application's argument list.
13939 % o argc: Specifies the number of arguments.
13941 % o image: Specifies an address to an address of an Image structure;
13944 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13945 char **argv,int argc,Image **image,size_t *state)
13947 #define MagnifySize 256 /* must be a power of 2 */
13948 #define MagickMenus 10
13949 #define MagickTitle "Commands"
13976 "Visual Directory...",
14022 "Contrast Stretch...",
14023 "Sigmoidal Contrast...",
14057 "Charcoal Draw...",
14071 "Region of Interest...",
14074 *MiscellanyMenu[] =
14089 "Browse Documentation",
14116 **Menus[MagickMenus] =
14154 VisualDirectoryCommand,
14168 OriginalSizeCommand,
14175 TransformCommands[] =
14181 RotateRightCommand,
14188 EnhanceCommands[] =
14196 ContrastStretchCommand,
14197 SigmoidalContrastCommand,
14205 EffectsCommands[] =
14209 ReduceNoiseCommand,
14229 CharcoalDrawCommand
14231 ImageEditCommands[] =
14242 RegionofInterestCommand
14244 MiscellanyCommands[] =
14248 ShowPreviewCommand,
14249 ShowHistogramCommand,
14258 BrowseDocumentationCommand,
14261 ShortCutsCommands[] =
14273 VirtualCommands[] =
14282 *Commands[MagickMenus] =
14292 MiscellanyCommands,
14297 command[MaxTextExtent],
14299 geometry[MaxTextExtent],
14300 resource_name[MaxTextExtent];
14327 working_directory[MaxTextExtent];
14333 *magick_windows[MaxXWindows];
14335 static unsigned int
14395 assert(image != (Image **) NULL);
14396 assert((*image)->signature == MagickSignature);
14397 if ((*image)->debug != MagickFalse)
14398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14399 display_image=(*image);
14400 warning_handler=(WarningHandler) NULL;
14401 windows=XSetWindows((XWindows *) ~0);
14402 if (windows != (XWindows *) NULL)
14407 status=chdir(working_directory);
14409 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14410 FileOpenError,"UnableToOpenFile","%s",working_directory);
14411 warning_handler=resource_info->display_warnings ?
14412 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14413 warning_handler=resource_info->display_warnings ?
14414 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14419 Allocate windows structure.
14421 resource_info->colors=display_image->colors;
14422 windows=XSetWindows(XInitializeWindows(display,resource_info));
14423 if (windows == (XWindows *) NULL)
14424 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14425 (*image)->filename);
14427 Initialize window id's.
14430 magick_windows[number_windows++]=(&windows->icon);
14431 magick_windows[number_windows++]=(&windows->backdrop);
14432 magick_windows[number_windows++]=(&windows->image);
14433 magick_windows[number_windows++]=(&windows->info);
14434 magick_windows[number_windows++]=(&windows->command);
14435 magick_windows[number_windows++]=(&windows->widget);
14436 magick_windows[number_windows++]=(&windows->popup);
14437 magick_windows[number_windows++]=(&windows->magnify);
14438 magick_windows[number_windows++]=(&windows->pan);
14439 for (i=0; i < (int) number_windows; i++)
14440 magick_windows[i]->id=(Window) NULL;
14445 Initialize font info.
14447 if (windows->font_info != (XFontStruct *) NULL)
14448 (void) XFreeFont(display,windows->font_info);
14449 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14450 if (windows->font_info == (XFontStruct *) NULL)
14451 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14452 resource_info->font);
14454 Initialize Standard Colormap.
14456 map_info=windows->map_info;
14457 icon_map=windows->icon_map;
14458 visual_info=windows->visual_info;
14459 icon_visual=windows->icon_visual;
14460 pixel=windows->pixel_info;
14461 icon_pixel=windows->icon_pixel;
14462 font_info=windows->font_info;
14463 icon_resources=windows->icon_resources;
14464 class_hints=windows->class_hints;
14465 manager_hints=windows->manager_hints;
14466 root_window=XRootWindow(display,visual_info->screen);
14467 nexus=NewImageList();
14468 if (display_image->debug != MagickFalse)
14470 (void) LogMagickEvent(X11Event,GetMagickModule(),
14471 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14472 (double) display_image->scene,(double) display_image->columns,
14473 (double) display_image->rows);
14474 if (display_image->colors != 0)
14475 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14476 display_image->colors);
14477 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14478 display_image->magick);
14480 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14482 display_image->taint=MagickFalse;
14484 Initialize graphic context.
14486 windows->context.id=(Window) NULL;
14487 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14488 resource_info,&windows->context);
14489 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14490 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14491 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14492 manager_hints->flags=InputHint | StateHint;
14493 manager_hints->input=MagickFalse;
14494 manager_hints->initial_state=WithdrawnState;
14495 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14496 &windows->context);
14497 if (display_image->debug != MagickFalse)
14498 (void) LogMagickEvent(X11Event,GetMagickModule(),
14499 "Window id: 0x%lx (context)",windows->context.id);
14500 context_values.background=pixel->background_color.pixel;
14501 context_values.font=font_info->fid;
14502 context_values.foreground=pixel->foreground_color.pixel;
14503 context_values.graphics_exposures=MagickFalse;
14504 context_mask=(MagickStatusType)
14505 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14506 if (pixel->annotate_context != (GC) NULL)
14507 (void) XFreeGC(display,pixel->annotate_context);
14508 pixel->annotate_context=XCreateGC(display,windows->context.id,
14509 context_mask,&context_values);
14510 if (pixel->annotate_context == (GC) NULL)
14511 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14512 display_image->filename);
14513 context_values.background=pixel->depth_color.pixel;
14514 if (pixel->widget_context != (GC) NULL)
14515 (void) XFreeGC(display,pixel->widget_context);
14516 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14518 if (pixel->widget_context == (GC) NULL)
14519 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14520 display_image->filename);
14521 context_values.background=pixel->foreground_color.pixel;
14522 context_values.foreground=pixel->background_color.pixel;
14523 context_values.plane_mask=context_values.background ^
14524 context_values.foreground;
14525 if (pixel->highlight_context != (GC) NULL)
14526 (void) XFreeGC(display,pixel->highlight_context);
14527 pixel->highlight_context=XCreateGC(display,windows->context.id,
14528 (size_t) (context_mask | GCPlaneMask),&context_values);
14529 if (pixel->highlight_context == (GC) NULL)
14530 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14531 display_image->filename);
14532 (void) XDestroyWindow(display,windows->context.id);
14534 Initialize icon window.
14536 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14537 icon_resources,&windows->icon);
14538 windows->icon.geometry=resource_info->icon_geometry;
14539 XBestIconSize(display,&windows->icon,display_image);
14540 windows->icon.attributes.colormap=XDefaultColormap(display,
14541 icon_visual->screen);
14542 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14543 manager_hints->flags=InputHint | StateHint;
14544 manager_hints->input=MagickFalse;
14545 manager_hints->initial_state=IconicState;
14546 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14548 if (display_image->debug != MagickFalse)
14549 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14552 Initialize graphic context for icon window.
14554 if (icon_pixel->annotate_context != (GC) NULL)
14555 (void) XFreeGC(display,icon_pixel->annotate_context);
14556 context_values.background=icon_pixel->background_color.pixel;
14557 context_values.foreground=icon_pixel->foreground_color.pixel;
14558 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14559 (size_t) (GCBackground | GCForeground),&context_values);
14560 if (icon_pixel->annotate_context == (GC) NULL)
14561 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14562 display_image->filename);
14563 windows->icon.annotate_context=icon_pixel->annotate_context;
14565 Initialize Image window.
14567 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14569 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14570 if (resource_info->use_shared_memory == MagickFalse)
14571 windows->image.shared_memory=MagickFalse;
14572 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14577 title=InterpretImageProperties(resource_info->image_info,display_image,
14578 resource_info->title);
14579 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14580 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14581 title=DestroyString(title);
14586 filename[MaxTextExtent];
14589 Window name is the base of the filename.
14591 GetPathComponent(display_image->magick_filename,TailPath,filename);
14592 if (GetImageListLength(display_image) == 1)
14593 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14594 "%s: %s",MagickPackageName,filename);
14596 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
14597 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14598 (double) display_image->scene,(double) GetImageListLength(
14600 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14602 if (resource_info->immutable)
14603 windows->image.immutable=MagickTrue;
14604 windows->image.use_pixmap=resource_info->use_pixmap;
14605 windows->image.geometry=resource_info->image_geometry;
14606 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14607 XDisplayWidth(display,visual_info->screen),
14608 XDisplayHeight(display,visual_info->screen));
14609 geometry_info.width=display_image->columns;
14610 geometry_info.height=display_image->rows;
14613 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14614 &geometry_info.width,&geometry_info.height);
14615 windows->image.width=(unsigned int) geometry_info.width;
14616 windows->image.height=(unsigned int) geometry_info.height;
14617 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14618 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14619 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14620 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14621 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14622 resource_info,&windows->backdrop);
14623 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14626 Initialize backdrop window.
14628 windows->backdrop.x=0;
14629 windows->backdrop.y=0;
14630 (void) CloneString(&windows->backdrop.name,"Backdrop");
14631 windows->backdrop.flags=(size_t) (USSize | USPosition);
14632 windows->backdrop.width=(unsigned int)
14633 XDisplayWidth(display,visual_info->screen);
14634 windows->backdrop.height=(unsigned int)
14635 XDisplayHeight(display,visual_info->screen);
14636 windows->backdrop.border_width=0;
14637 windows->backdrop.immutable=MagickTrue;
14638 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14640 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14641 StructureNotifyMask;
14642 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14643 manager_hints->icon_window=windows->icon.id;
14644 manager_hints->input=MagickTrue;
14645 manager_hints->initial_state=resource_info->iconic ? IconicState :
14647 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14648 &windows->backdrop);
14649 if (display_image->debug != MagickFalse)
14650 (void) LogMagickEvent(X11Event,GetMagickModule(),
14651 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14652 (void) XMapWindow(display,windows->backdrop.id);
14653 (void) XClearWindow(display,windows->backdrop.id);
14654 if (windows->image.id != (Window) NULL)
14656 (void) XDestroyWindow(display,windows->image.id);
14657 windows->image.id=(Window) NULL;
14660 Position image in the center the backdrop.
14662 windows->image.flags|=USPosition;
14663 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14664 (windows->image.width/2);
14665 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14666 (windows->image.height/2);
14668 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14669 manager_hints->icon_window=windows->icon.id;
14670 manager_hints->input=MagickTrue;
14671 manager_hints->initial_state=resource_info->iconic ? IconicState :
14673 if (windows->group_leader.id != (Window) NULL)
14678 manager_hints->flags|=WindowGroupHint;
14679 manager_hints->window_group=windows->group_leader.id;
14680 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14681 if (display_image->debug != MagickFalse)
14682 (void) LogMagickEvent(X11Event,GetMagickModule(),
14683 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14685 XMakeWindow(display,
14686 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14687 argv,argc,class_hints,manager_hints,&windows->image);
14688 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14689 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14690 if (windows->group_leader.id != (Window) NULL)
14691 (void) XSetTransientForHint(display,windows->image.id,
14692 windows->group_leader.id);
14693 if (display_image->debug != MagickFalse)
14694 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14695 windows->image.id);
14697 Initialize Info widget.
14699 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14701 (void) CloneString(&windows->info.name,"Info");
14702 (void) CloneString(&windows->info.icon_name,"Info");
14703 windows->info.border_width=1;
14706 windows->info.flags|=PPosition;
14707 windows->info.attributes.win_gravity=UnmapGravity;
14708 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14709 StructureNotifyMask;
14710 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14711 manager_hints->input=MagickFalse;
14712 manager_hints->initial_state=NormalState;
14713 manager_hints->window_group=windows->image.id;
14714 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14716 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14717 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14718 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14719 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14720 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14721 if (windows->image.mapped != MagickFalse)
14722 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14723 if (display_image->debug != MagickFalse)
14724 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14727 Initialize Command widget.
14729 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14730 resource_info,&windows->command);
14731 windows->command.data=MagickMenus;
14732 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14733 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
14734 resource_info->client_name);
14735 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14736 resource_name,"geometry",(char *) NULL);
14737 (void) CloneString(&windows->command.name,MagickTitle);
14738 windows->command.border_width=0;
14739 windows->command.flags|=PPosition;
14740 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14741 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14742 OwnerGrabButtonMask | StructureNotifyMask;
14743 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14744 manager_hints->input=MagickTrue;
14745 manager_hints->initial_state=NormalState;
14746 manager_hints->window_group=windows->image.id;
14747 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14748 &windows->command);
14749 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14750 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14752 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14753 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14754 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14755 if (windows->command.mapped != MagickFalse)
14756 (void) XMapRaised(display,windows->command.id);
14757 if (display_image->debug != MagickFalse)
14758 (void) LogMagickEvent(X11Event,GetMagickModule(),
14759 "Window id: 0x%lx (command)",windows->command.id);
14761 Initialize Widget window.
14763 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14764 resource_info,&windows->widget);
14765 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
14766 resource_info->client_name);
14767 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14768 resource_name,"geometry",(char *) NULL);
14769 windows->widget.border_width=0;
14770 windows->widget.flags|=PPosition;
14771 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14772 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14773 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14774 StructureNotifyMask;
14775 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14776 manager_hints->input=MagickTrue;
14777 manager_hints->initial_state=NormalState;
14778 manager_hints->window_group=windows->image.id;
14779 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14781 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14782 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14783 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14784 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14785 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14786 if (display_image->debug != MagickFalse)
14787 (void) LogMagickEvent(X11Event,GetMagickModule(),
14788 "Window id: 0x%lx (widget)",windows->widget.id);
14790 Initialize popup window.
14792 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14793 resource_info,&windows->popup);
14794 windows->popup.border_width=0;
14795 windows->popup.flags|=PPosition;
14796 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14797 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14798 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14799 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14800 manager_hints->input=MagickTrue;
14801 manager_hints->initial_state=NormalState;
14802 manager_hints->window_group=windows->image.id;
14803 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14805 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14806 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14807 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14808 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14809 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14810 if (display_image->debug != MagickFalse)
14811 (void) LogMagickEvent(X11Event,GetMagickModule(),
14812 "Window id: 0x%lx (pop up)",windows->popup.id);
14814 Initialize Magnify window and cursor.
14816 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14817 resource_info,&windows->magnify);
14818 if (resource_info->use_shared_memory == MagickFalse)
14819 windows->magnify.shared_memory=MagickFalse;
14820 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
14821 resource_info->client_name);
14822 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14823 resource_name,"geometry",(char *) NULL);
14824 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14825 resource_info->magnify);
14826 if (windows->magnify.cursor != (Cursor) NULL)
14827 (void) XFreeCursor(display,windows->magnify.cursor);
14828 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14829 map_info->colormap,resource_info->background_color,
14830 resource_info->foreground_color);
14831 if (windows->magnify.cursor == (Cursor) NULL)
14832 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14833 display_image->filename);
14834 windows->magnify.width=MagnifySize;
14835 windows->magnify.height=MagnifySize;
14836 windows->magnify.flags|=PPosition;
14837 windows->magnify.min_width=MagnifySize;
14838 windows->magnify.min_height=MagnifySize;
14839 windows->magnify.width_inc=MagnifySize;
14840 windows->magnify.height_inc=MagnifySize;
14841 windows->magnify.data=resource_info->magnify;
14842 windows->magnify.attributes.cursor=windows->magnify.cursor;
14843 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14844 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14845 StructureNotifyMask;
14846 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14847 manager_hints->input=MagickTrue;
14848 manager_hints->initial_state=NormalState;
14849 manager_hints->window_group=windows->image.id;
14850 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14851 &windows->magnify);
14852 if (display_image->debug != MagickFalse)
14853 (void) LogMagickEvent(X11Event,GetMagickModule(),
14854 "Window id: 0x%lx (magnify)",windows->magnify.id);
14855 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14857 Initialize panning window.
14859 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14860 resource_info,&windows->pan);
14861 (void) CloneString(&windows->pan.name,"Pan Icon");
14862 windows->pan.width=windows->icon.width;
14863 windows->pan.height=windows->icon.height;
14864 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
14865 resource_info->client_name);
14866 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14867 resource_name,"geometry",(char *) NULL);
14868 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14869 &windows->pan.width,&windows->pan.height);
14870 windows->pan.flags|=PPosition;
14871 windows->pan.immutable=MagickTrue;
14872 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14873 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14874 StructureNotifyMask;
14875 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14876 manager_hints->input=MagickFalse;
14877 manager_hints->initial_state=NormalState;
14878 manager_hints->window_group=windows->image.id;
14879 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14881 if (display_image->debug != MagickFalse)
14882 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14884 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14885 if (windows->info.mapped != MagickFalse)
14886 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14887 if ((windows->image.mapped == MagickFalse) ||
14888 (windows->backdrop.id != (Window) NULL))
14889 (void) XMapWindow(display,windows->image.id);
14891 Set our progress monitor and warning handlers.
14893 if (warning_handler == (WarningHandler) NULL)
14895 warning_handler=resource_info->display_warnings ?
14896 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14897 warning_handler=resource_info->display_warnings ?
14898 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14901 Initialize Image and Magnify X images.
14903 windows->image.x=0;
14904 windows->image.y=0;
14905 windows->magnify.shape=MagickFalse;
14906 width=(unsigned int) display_image->columns;
14907 height=(unsigned int) display_image->rows;
14908 if ((display_image->columns != width) || (display_image->rows != height))
14909 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14910 display_image->filename);
14911 status=XMakeImage(display,resource_info,&windows->image,display_image,
14913 if (status == MagickFalse)
14914 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14915 display_image->filename);
14916 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14917 windows->magnify.width,windows->magnify.height);
14918 if (status == MagickFalse)
14919 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14920 display_image->filename);
14921 if (windows->magnify.mapped != MagickFalse)
14922 (void) XMapRaised(display,windows->magnify.id);
14923 if (windows->pan.mapped != MagickFalse)
14924 (void) XMapRaised(display,windows->pan.id);
14925 windows->image.window_changes.width=(int) display_image->columns;
14926 windows->image.window_changes.height=(int) display_image->rows;
14927 (void) XConfigureImage(display,resource_info,windows,display_image);
14928 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14929 (void) XSync(display,MagickFalse);
14933 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14934 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14936 if (resource_info->update != MagickFalse)
14942 Determine when file data was last modified.
14944 status=GetPathAttributes(display_image->filename,&attributes);
14945 if (status != MagickFalse)
14946 update_time=attributes.st_mtime;
14948 *state&=(~FormerImageState);
14949 *state&=(~MontageImageState);
14950 *state&=(~NextImageState);
14954 Handle a window event.
14956 if (windows->image.mapped != MagickFalse)
14957 if ((display_image->delay != 0) || (resource_info->update != 0))
14959 if (timer < time((time_t *) NULL))
14961 if (resource_info->update == MagickFalse)
14962 *state|=NextImageState | ExitState;
14969 Determine if image file was modified.
14971 status=GetPathAttributes(display_image->filename,&attributes);
14972 if (status != MagickFalse)
14973 if (update_time != attributes.st_mtime)
14978 (void) FormatLocaleString(
14979 resource_info->image_info->filename,MaxTextExtent,
14980 "%s:%s",display_image->magick,
14981 display_image->filename);
14982 nexus=ReadImage(resource_info->image_info,
14983 &display_image->exception);
14984 if (nexus != (Image *) NULL)
14986 nexus=DestroyImage(nexus);
14987 *state|=NextImageState | ExitState;
14990 delay=display_image->delay/MagickMax(
14991 display_image->ticks_per_second,1L);
14992 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14995 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14998 Do not block if delay > 0.
15000 XDelay(display,SuspendTime << 2);
15004 timestamp=time((time_t *) NULL);
15005 (void) XNextEvent(display,&event);
15006 if (windows->image.stasis == MagickFalse)
15007 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15008 MagickTrue : MagickFalse;
15009 if (windows->magnify.stasis == MagickFalse)
15010 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
15011 MagickTrue : MagickFalse;
15012 if (event.xany.window == windows->command.id)
15015 Select a command from the Command widget.
15017 id=XCommandWidget(display,windows,CommandMenu,&event);
15020 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15021 command_type=CommandMenus[id];
15022 if (id < MagickMenus)
15025 Select a command from a pop-up menu.
15027 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15031 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15032 command_type=Commands[id][entry];
15034 if (command_type != NullCommand)
15035 nexus=XMagickCommand(display,resource_info,windows,command_type,
15039 switch (event.type)
15043 if (display_image->debug != MagickFalse)
15044 (void) LogMagickEvent(X11Event,GetMagickModule(),
15045 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15046 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15047 if ((event.xbutton.button == Button3) &&
15048 (event.xbutton.state & Mod1Mask))
15051 Convert Alt-Button3 to Button2.
15053 event.xbutton.button=Button2;
15054 event.xbutton.state&=(~Mod1Mask);
15056 if (event.xbutton.window == windows->backdrop.id)
15058 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15059 event.xbutton.time);
15062 if (event.xbutton.window == windows->image.id)
15064 switch (event.xbutton.button)
15068 if (resource_info->immutable)
15071 Select a command from the Virtual menu.
15073 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15076 nexus=XMagickCommand(display,resource_info,windows,
15077 VirtualCommands[entry],&display_image);
15081 Map/unmap Command widget.
15083 if (windows->command.mapped != MagickFalse)
15084 (void) XWithdrawWindow(display,windows->command.id,
15085 windows->command.screen);
15088 (void) XCommandWidget(display,windows,CommandMenu,
15090 (void) XMapRaised(display,windows->command.id);
15097 User pressed the image magnify button.
15099 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15101 XMagnifyImage(display,windows,&event);
15106 if (resource_info->immutable)
15109 Select a command from the Virtual menu.
15111 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15114 nexus=XMagickCommand(display,resource_info,windows,
15115 VirtualCommands[entry],&display_image);
15118 if (display_image->montage != (char *) NULL)
15121 Open or delete a tile from a visual image directory.
15123 nexus=XTileImage(display,resource_info,windows,
15124 display_image,&event);
15125 if (nexus != (Image *) NULL)
15126 *state|=MontageImageState | NextImageState | ExitState;
15127 vid_info.x=(short int) windows->image.x;
15128 vid_info.y=(short int) windows->image.y;
15132 Select a command from the Short Cuts menu.
15134 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15137 nexus=XMagickCommand(display,resource_info,windows,
15138 ShortCutsCommands[entry],&display_image);
15146 XTranslateImage(display,windows,*image,XK_Up);
15154 XTranslateImage(display,windows,*image,XK_Down);
15162 if (event.xbutton.window == windows->magnify.id)
15182 MagnifyCommands[] =
15195 Select a magnify factor from the pop-up menu.
15197 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15199 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15202 if (event.xbutton.window == windows->pan.id)
15204 switch (event.xbutton.button)
15211 XTranslateImage(display,windows,*image,XK_Up);
15219 XTranslateImage(display,windows,*image,XK_Down);
15224 XPanImage(display,windows,&event);
15230 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15232 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15235 case ButtonRelease:
15237 if (display_image->debug != MagickFalse)
15238 (void) LogMagickEvent(X11Event,GetMagickModule(),
15239 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15240 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15243 case ClientMessage:
15245 if (display_image->debug != MagickFalse)
15246 (void) LogMagickEvent(X11Event,GetMagickModule(),
15247 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15248 event.xclient.message_type,event.xclient.format,(unsigned long)
15249 event.xclient.data.l[0]);
15250 if (event.xclient.message_type == windows->im_protocols)
15252 if (*event.xclient.data.l == (long) windows->im_update_widget)
15254 (void) CloneString(&windows->command.name,MagickTitle);
15255 windows->command.data=MagickMenus;
15256 (void) XCommandWidget(display,windows,CommandMenu,
15260 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15263 Update graphic context and window colormap.
15265 for (i=0; i < (int) number_windows; i++)
15267 if (magick_windows[i]->id == windows->icon.id)
15269 context_values.background=pixel->background_color.pixel;
15270 context_values.foreground=pixel->foreground_color.pixel;
15271 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15272 context_mask,&context_values);
15273 (void) XChangeGC(display,magick_windows[i]->widget_context,
15274 context_mask,&context_values);
15275 context_values.background=pixel->foreground_color.pixel;
15276 context_values.foreground=pixel->background_color.pixel;
15277 context_values.plane_mask=context_values.background ^
15278 context_values.foreground;
15279 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15280 (size_t) (context_mask | GCPlaneMask),
15282 magick_windows[i]->attributes.background_pixel=
15283 pixel->background_color.pixel;
15284 magick_windows[i]->attributes.border_pixel=
15285 pixel->border_color.pixel;
15286 magick_windows[i]->attributes.colormap=map_info->colormap;
15287 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15288 (unsigned long) magick_windows[i]->mask,
15289 &magick_windows[i]->attributes);
15291 if (windows->pan.mapped != MagickFalse)
15293 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15294 windows->pan.pixmap);
15295 (void) XClearWindow(display,windows->pan.id);
15296 XDrawPanRectangle(display,windows);
15298 if (windows->backdrop.id != (Window) NULL)
15299 (void) XInstallColormap(display,map_info->colormap);
15302 if (*event.xclient.data.l == (long) windows->im_former_image)
15304 *state|=FormerImageState | ExitState;
15307 if (*event.xclient.data.l == (long) windows->im_next_image)
15309 *state|=NextImageState | ExitState;
15312 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15314 *state|=RetainColorsState;
15317 if (*event.xclient.data.l == (long) windows->im_exit)
15324 if (event.xclient.message_type == windows->dnd_protocols)
15342 Display image named by the Drag-and-Drop selection.
15344 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15346 selection=XInternAtom(display,"DndSelection",MagickFalse);
15347 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15348 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15349 &length,&after,&data);
15350 if ((status != Success) || (length == 0))
15352 if (*event.xclient.data.l == 2)
15357 (void) CopyMagickString(resource_info->image_info->filename,
15358 (char *) data,MaxTextExtent);
15365 if (strncmp((char *) data, "file:", 5) != 0)
15367 (void) XFree((void *) data);
15370 (void) CopyMagickString(resource_info->image_info->filename,
15371 ((char *) data)+5,MaxTextExtent);
15373 nexus=ReadImage(resource_info->image_info,
15374 &display_image->exception);
15375 CatchException(&display_image->exception);
15376 if (nexus != (Image *) NULL)
15377 *state|=NextImageState | ExitState;
15378 (void) XFree((void *) data);
15382 If client window delete message, exit.
15384 if (event.xclient.message_type != windows->wm_protocols)
15386 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15388 (void) XWithdrawWindow(display,event.xclient.window,
15389 visual_info->screen);
15390 if (event.xclient.window == windows->image.id)
15395 if (event.xclient.window == windows->pan.id)
15398 Restore original image size when pan window is deleted.
15400 windows->image.window_changes.width=windows->image.ximage->width;
15401 windows->image.window_changes.height=windows->image.ximage->height;
15402 (void) XConfigureImage(display,resource_info,windows,
15407 case ConfigureNotify:
15409 if (display_image->debug != MagickFalse)
15410 (void) LogMagickEvent(X11Event,GetMagickModule(),
15411 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15412 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15413 event.xconfigure.y,event.xconfigure.send_event);
15414 if (event.xconfigure.window == windows->image.id)
15417 Image window has a new configuration.
15419 if (event.xconfigure.send_event != 0)
15425 Position the transient windows relative of the Image window.
15427 if (windows->command.geometry == (char *) NULL)
15428 if (windows->command.mapped == MagickFalse)
15430 windows->command.x=event.xconfigure.x-
15431 windows->command.width-25;
15432 windows->command.y=event.xconfigure.y;
15433 XConstrainWindowPosition(display,&windows->command);
15434 window_changes.x=windows->command.x;
15435 window_changes.y=windows->command.y;
15436 (void) XReconfigureWMWindow(display,windows->command.id,
15437 windows->command.screen,(unsigned int) (CWX | CWY),
15440 if (windows->widget.geometry == (char *) NULL)
15441 if (windows->widget.mapped == MagickFalse)
15443 windows->widget.x=event.xconfigure.x+
15444 event.xconfigure.width/10;
15445 windows->widget.y=event.xconfigure.y+
15446 event.xconfigure.height/10;
15447 XConstrainWindowPosition(display,&windows->widget);
15448 window_changes.x=windows->widget.x;
15449 window_changes.y=windows->widget.y;
15450 (void) XReconfigureWMWindow(display,windows->widget.id,
15451 windows->widget.screen,(unsigned int) (CWX | CWY),
15454 if (windows->magnify.geometry == (char *) NULL)
15455 if (windows->magnify.mapped == MagickFalse)
15457 windows->magnify.x=event.xconfigure.x+
15458 event.xconfigure.width+25;
15459 windows->magnify.y=event.xconfigure.y;
15460 XConstrainWindowPosition(display,&windows->magnify);
15461 window_changes.x=windows->magnify.x;
15462 window_changes.y=windows->magnify.y;
15463 (void) XReconfigureWMWindow(display,windows->magnify.id,
15464 windows->magnify.screen,(unsigned int) (CWX | CWY),
15467 if (windows->pan.geometry == (char *) NULL)
15468 if (windows->pan.mapped == MagickFalse)
15470 windows->pan.x=event.xconfigure.x+
15471 event.xconfigure.width+25;
15472 windows->pan.y=event.xconfigure.y+
15473 windows->magnify.height+50;
15474 XConstrainWindowPosition(display,&windows->pan);
15475 window_changes.x=windows->pan.x;
15476 window_changes.y=windows->pan.y;
15477 (void) XReconfigureWMWindow(display,windows->pan.id,
15478 windows->pan.screen,(unsigned int) (CWX | CWY),
15482 if ((event.xconfigure.width == (int) windows->image.width) &&
15483 (event.xconfigure.height == (int) windows->image.height))
15485 windows->image.width=(unsigned int) event.xconfigure.width;
15486 windows->image.height=(unsigned int) event.xconfigure.height;
15487 windows->image.x=0;
15488 windows->image.y=0;
15489 if (display_image->montage != (char *) NULL)
15491 windows->image.x=vid_info.x;
15492 windows->image.y=vid_info.y;
15494 if ((windows->image.mapped != MagickFalse) &&
15495 (windows->image.stasis != MagickFalse))
15498 Update image window configuration.
15500 windows->image.window_changes.width=event.xconfigure.width;
15501 windows->image.window_changes.height=event.xconfigure.height;
15502 (void) XConfigureImage(display,resource_info,windows,
15506 Update pan window configuration.
15508 if ((event.xconfigure.width < windows->image.ximage->width) ||
15509 (event.xconfigure.height < windows->image.ximage->height))
15511 (void) XMapRaised(display,windows->pan.id);
15512 XDrawPanRectangle(display,windows);
15515 if (windows->pan.mapped != MagickFalse)
15516 (void) XWithdrawWindow(display,windows->pan.id,
15517 windows->pan.screen);
15520 if (event.xconfigure.window == windows->magnify.id)
15526 Magnify window has a new configuration.
15528 windows->magnify.width=(unsigned int) event.xconfigure.width;
15529 windows->magnify.height=(unsigned int) event.xconfigure.height;
15530 if (windows->magnify.mapped == MagickFalse)
15533 while ((int) magnify <= event.xconfigure.width)
15535 while ((int) magnify <= event.xconfigure.height)
15538 if (((int) magnify != event.xconfigure.width) ||
15539 ((int) magnify != event.xconfigure.height))
15541 window_changes.width=(int) magnify;
15542 window_changes.height=(int) magnify;
15543 (void) XReconfigureWMWindow(display,windows->magnify.id,
15544 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15548 if ((windows->magnify.mapped != MagickFalse) &&
15549 (windows->magnify.stasis != MagickFalse))
15551 status=XMakeImage(display,resource_info,&windows->magnify,
15552 display_image,windows->magnify.width,windows->magnify.height);
15553 XMakeMagnifyImage(display,windows);
15557 if ((windows->magnify.mapped != MagickFalse) &&
15558 (event.xconfigure.window == windows->pan.id))
15561 Pan icon window has a new configuration.
15563 if (event.xconfigure.send_event != 0)
15565 windows->pan.x=event.xconfigure.x;
15566 windows->pan.y=event.xconfigure.y;
15568 windows->pan.width=(unsigned int) event.xconfigure.width;
15569 windows->pan.height=(unsigned int) event.xconfigure.height;
15572 if (event.xconfigure.window == windows->icon.id)
15575 Icon window has a new configuration.
15577 windows->icon.width=(unsigned int) event.xconfigure.width;
15578 windows->icon.height=(unsigned int) event.xconfigure.height;
15583 case DestroyNotify:
15586 Group leader has exited.
15588 if (display_image->debug != MagickFalse)
15589 (void) LogMagickEvent(X11Event,GetMagickModule(),
15590 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15591 if (event.xdestroywindow.window == windows->group_leader.id)
15601 Selectively install colormap.
15603 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15604 if (event.xcrossing.mode != NotifyUngrab)
15605 XInstallColormap(display,map_info->colormap);
15610 if (display_image->debug != MagickFalse)
15611 (void) LogMagickEvent(X11Event,GetMagickModule(),
15612 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15613 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15616 Refresh windows that are now exposed.
15618 if ((event.xexpose.window == windows->image.id) &&
15619 (windows->image.mapped != MagickFalse))
15621 XRefreshWindow(display,&windows->image,&event);
15622 delay=display_image->delay/MagickMax(
15623 display_image->ticks_per_second,1L);
15624 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15627 if ((event.xexpose.window == windows->magnify.id) &&
15628 (windows->magnify.mapped != MagickFalse))
15630 XMakeMagnifyImage(display,windows);
15633 if (event.xexpose.window == windows->pan.id)
15635 XDrawPanRectangle(display,windows);
15638 if (event.xexpose.window == windows->icon.id)
15640 XRefreshWindow(display,&windows->icon,&event);
15651 Respond to a user key press.
15653 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15654 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15655 *(command+length)='\0';
15656 if (display_image->debug != MagickFalse)
15657 (void) LogMagickEvent(X11Event,GetMagickModule(),
15658 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15659 key_symbol,command);
15660 if (event.xkey.window == windows->image.id)
15662 command_type=XImageWindowCommand(display,resource_info,windows,
15663 event.xkey.state,key_symbol,&display_image);
15664 if (command_type != NullCommand)
15665 nexus=XMagickCommand(display,resource_info,windows,command_type,
15668 if (event.xkey.window == windows->magnify.id)
15669 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15670 if (event.xkey.window == windows->pan.id)
15672 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15673 (void) XWithdrawWindow(display,windows->pan.id,
15674 windows->pan.screen);
15676 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15677 XTextViewWidget(display,resource_info,windows,MagickFalse,
15678 "Help Viewer - Image Pan",ImagePanHelp);
15680 XTranslateImage(display,windows,*image,key_symbol);
15682 delay=display_image->delay/MagickMax(
15683 display_image->ticks_per_second,1L);
15684 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15690 Respond to a user key release.
15692 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15693 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15694 if (display_image->debug != MagickFalse)
15695 (void) LogMagickEvent(X11Event,GetMagickModule(),
15696 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15702 Selectively uninstall colormap.
15704 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15705 if (event.xcrossing.mode != NotifyUngrab)
15706 XUninstallColormap(display,map_info->colormap);
15711 if (display_image->debug != MagickFalse)
15712 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15713 event.xmap.window);
15714 if (event.xmap.window == windows->backdrop.id)
15716 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15718 windows->backdrop.mapped=MagickTrue;
15721 if (event.xmap.window == windows->image.id)
15723 if (windows->backdrop.id != (Window) NULL)
15724 (void) XInstallColormap(display,map_info->colormap);
15725 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15727 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15728 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15730 if (((int) windows->image.width < windows->image.ximage->width) ||
15731 ((int) windows->image.height < windows->image.ximage->height))
15732 (void) XMapRaised(display,windows->pan.id);
15733 windows->image.mapped=MagickTrue;
15736 if (event.xmap.window == windows->magnify.id)
15738 XMakeMagnifyImage(display,windows);
15739 windows->magnify.mapped=MagickTrue;
15740 (void) XWithdrawWindow(display,windows->info.id,
15741 windows->info.screen);
15744 if (event.xmap.window == windows->pan.id)
15746 XMakePanImage(display,resource_info,windows,display_image);
15747 windows->pan.mapped=MagickTrue;
15750 if (event.xmap.window == windows->info.id)
15752 windows->info.mapped=MagickTrue;
15755 if (event.xmap.window == windows->icon.id)
15761 Create an icon image.
15763 taint=display_image->taint;
15764 XMakeStandardColormap(display,icon_visual,icon_resources,
15765 display_image,icon_map,icon_pixel);
15766 (void) XMakeImage(display,icon_resources,&windows->icon,
15767 display_image,windows->icon.width,windows->icon.height);
15768 display_image->taint=taint;
15769 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15770 windows->icon.pixmap);
15771 (void) XClearWindow(display,windows->icon.id);
15772 (void) XWithdrawWindow(display,windows->info.id,
15773 windows->info.screen);
15774 windows->icon.mapped=MagickTrue;
15777 if (event.xmap.window == windows->command.id)
15779 windows->command.mapped=MagickTrue;
15782 if (event.xmap.window == windows->popup.id)
15784 windows->popup.mapped=MagickTrue;
15787 if (event.xmap.window == windows->widget.id)
15789 windows->widget.mapped=MagickTrue;
15794 case MappingNotify:
15796 (void) XRefreshKeyboardMapping(&event.xmapping);
15801 case PropertyNotify:
15817 if (display_image->debug != MagickFalse)
15818 (void) LogMagickEvent(X11Event,GetMagickModule(),
15819 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15820 event.xproperty.atom,event.xproperty.state);
15821 if (event.xproperty.atom != windows->im_remote_command)
15824 Display image named by the remote command protocol.
15826 status=XGetWindowProperty(display,event.xproperty.window,
15827 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15828 AnyPropertyType,&type,&format,&length,&after,&data);
15829 if ((status != Success) || (length == 0))
15831 if (LocaleCompare((char *) data,"-quit") == 0)
15833 XClientMessage(display,windows->image.id,windows->im_protocols,
15834 windows->im_exit,CurrentTime);
15835 (void) XFree((void *) data);
15838 (void) CopyMagickString(resource_info->image_info->filename,
15839 (char *) data,MaxTextExtent);
15840 (void) XFree((void *) data);
15841 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15842 CatchException(&display_image->exception);
15843 if (nexus != (Image *) NULL)
15844 *state|=NextImageState | ExitState;
15847 case ReparentNotify:
15849 if (display_image->debug != MagickFalse)
15850 (void) LogMagickEvent(X11Event,GetMagickModule(),
15851 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15852 event.xreparent.window);
15857 if (display_image->debug != MagickFalse)
15858 (void) LogMagickEvent(X11Event,GetMagickModule(),
15859 "Unmap Notify: 0x%lx",event.xunmap.window);
15860 if (event.xunmap.window == windows->backdrop.id)
15862 windows->backdrop.mapped=MagickFalse;
15865 if (event.xunmap.window == windows->image.id)
15867 windows->image.mapped=MagickFalse;
15870 if (event.xunmap.window == windows->magnify.id)
15872 windows->magnify.mapped=MagickFalse;
15875 if (event.xunmap.window == windows->pan.id)
15877 windows->pan.mapped=MagickFalse;
15880 if (event.xunmap.window == windows->info.id)
15882 windows->info.mapped=MagickFalse;
15885 if (event.xunmap.window == windows->icon.id)
15887 if (map_info->colormap == icon_map->colormap)
15888 XConfigureImageColormap(display,resource_info,windows,
15890 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15892 windows->icon.mapped=MagickFalse;
15895 if (event.xunmap.window == windows->command.id)
15897 windows->command.mapped=MagickFalse;
15900 if (event.xunmap.window == windows->popup.id)
15902 if (windows->backdrop.id != (Window) NULL)
15903 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15905 windows->popup.mapped=MagickFalse;
15908 if (event.xunmap.window == windows->widget.id)
15910 if (windows->backdrop.id != (Window) NULL)
15911 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15913 windows->widget.mapped=MagickFalse;
15920 if (display_image->debug != MagickFalse)
15921 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15926 } while (!(*state & ExitState));
15927 if ((*state & ExitState) == 0)
15928 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15931 if (resource_info->confirm_edit != MagickFalse)
15934 Query user if image has changed.
15936 if ((resource_info->immutable == MagickFalse) &&
15937 (display_image->taint != MagickFalse))
15942 status=XConfirmWidget(display,windows,"Your image changed.",
15943 "Do you want to save it");
15945 *state&=(~ExitState);
15948 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15952 if ((windows->visual_info->klass == GrayScale) ||
15953 (windows->visual_info->klass == PseudoColor) ||
15954 (windows->visual_info->klass == DirectColor))
15957 Withdraw pan and Magnify window.
15959 if (windows->info.mapped != MagickFalse)
15960 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15961 if (windows->magnify.mapped != MagickFalse)
15962 (void) XWithdrawWindow(display,windows->magnify.id,
15963 windows->magnify.screen);
15964 if (windows->command.mapped != MagickFalse)
15965 (void) XWithdrawWindow(display,windows->command.id,
15966 windows->command.screen);
15968 if (windows->pan.mapped != MagickFalse)
15969 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15970 if (resource_info->backdrop == MagickFalse)
15971 if (windows->backdrop.mapped)
15973 (void) XWithdrawWindow(display,windows->backdrop.id,
15974 windows->backdrop.screen);
15975 (void) XDestroyWindow(display,windows->backdrop.id);
15976 windows->backdrop.id=(Window) NULL;
15977 (void) XWithdrawWindow(display,windows->image.id,
15978 windows->image.screen);
15979 (void) XDestroyWindow(display,windows->image.id);
15980 windows->image.id=(Window) NULL;
15982 XSetCursorState(display,windows,MagickTrue);
15983 XCheckRefreshWindows(display,windows);
15984 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15985 *state&=(~ExitState);
15986 if (*state & ExitState)
15989 Free Standard Colormap.
15991 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15992 if (resource_info->map_type == (char *) NULL)
15993 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15997 if (resource_info->copy_image != (Image *) NULL)
15999 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16000 resource_info->copy_image=NewImageList();
16002 DestroyXResources();
16004 (void) XSync(display,MagickFalse);
16006 Restore our progress monitor and warning handlers.
16008 (void) SetErrorHandler(warning_handler);
16009 (void) SetWarningHandler(warning_handler);
16011 Change to home directory.
16013 directory=getcwd(working_directory,MaxTextExtent);
16019 status=chdir(resource_info->home_directory);
16021 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
16022 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
16024 *image=display_image;
16030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16034 + D i s p l a y I m a g e s %
16038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16040 % DisplayImages() displays an image sequence to any X window screen. It
16041 % returns a value other than 0 if successful. Check the exception member
16042 % of image to determine the reason for any failure.
16044 % The format of the DisplayImages method is:
16046 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16049 % A description of each parameter follows:
16051 % o image_info: the image info.
16053 % o image: the image.
16056 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16059 assert(image_info != (const ImageInfo *) NULL);
16060 assert(image_info->signature == MagickSignature);
16061 assert(image != (Image *) NULL);
16062 assert(image->signature == MagickSignature);
16063 if (image->debug != MagickFalse)
16064 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16065 (void) ThrowMagickException(&image->exception,GetMagickModule(),
16066 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
16068 return(MagickFalse);
16072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16076 + R e m o t e D i s p l a y C o m m a n d %
16080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16082 % RemoteDisplayCommand() encourages a remote display program to display the
16083 % specified image filename.
16085 % The format of the RemoteDisplayCommand method is:
16087 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16088 % const char *window,const char *filename,ExceptionInfo *exception)
16090 % A description of each parameter follows:
16092 % o image_info: the image info.
16094 % o window: Specifies the name or id of an X window.
16096 % o filename: the name of the image filename to display.
16098 % o exception: return any errors or warnings in this structure.
16101 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16102 const char *window,const char *filename,ExceptionInfo *exception)
16104 assert(image_info != (const ImageInfo *) NULL);
16105 assert(image_info->signature == MagickSignature);
16106 assert(filename != (char *) NULL);
16108 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16109 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16110 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16111 return(MagickFalse);