blob: 6b8c9d8ba787706b4059c45ec1cdee76a8a843de [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% DDDD IIIII SSSSS PPPP L AAA Y Y %
7% D D I SS P P L A A Y Y %
8% D D I SSS PPPP L AAAAA Y %
9% D D I SS P L A A Y %
10% DDDD IIIII SSSSS P LLLLL A A Y %
11% %
12% %
13% MagickCore Methods to Interactively Display and Edit an Image %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/artifact.h"
44#include "magick/blob.h"
45#include "magick/cache.h"
46#include "magick/client.h"
47#include "magick/color.h"
48#include "magick/colorspace.h"
49#include "magick/composite.h"
50#include "magick/constitute.h"
51#include "magick/decorate.h"
52#include "magick/delegate.h"
53#include "magick/display.h"
54#include "magick/display-private.h"
55#include "magick/draw.h"
56#include "magick/effect.h"
57#include "magick/enhance.h"
58#include "magick/exception.h"
59#include "magick/exception-private.h"
60#include "magick/fx.h"
61#include "magick/geometry.h"
62#include "magick/image.h"
63#include "magick/image-private.h"
64#include "magick/list.h"
65#include "magick/log.h"
66#include "magick/magick.h"
67#include "magick/memory_.h"
68#include "magick/monitor.h"
69#include "magick/monitor-private.h"
70#include "magick/montage.h"
71#include "magick/option.h"
72#include "magick/paint.h"
73#include "magick/pixel.h"
74#include "magick/pixel-private.h"
75#include "magick/PreRvIcccm.h"
76#include "magick/property.h"
77#include "magick/quantum.h"
78#include "magick/resize.h"
79#include "magick/resource_.h"
80#include "magick/shear.h"
81#include "magick/segment.h"
82#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000083#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000084#include "magick/transform.h"
85#include "magick/threshold.h"
86#include "magick/utility.h"
87#include "magick/version.h"
88#include "magick/widget.h"
89#include "magick/xwindow-private.h"
90
91#if defined(MAGICKCORE_X11_DELEGATE)
92/*
93 Define declarations.
94*/
95#define MaxColors MagickMin(windows->visual_info->colormap_size,256L)
96
97/*
98 Constant declarations.
99*/
100static const unsigned char
101 HighlightBitmap[8] =
102 {
103 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
104 },
105 ShadowBitmap[8] =
106 {
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
108 };
109
110static const char
111 *PageSizes[] =
112 {
113 "Letter",
114 "Tabloid",
115 "Ledger",
116 "Legal",
117 "Statement",
118 "Executive",
119 "A3",
120 "A4",
121 "A5",
122 "B4",
123 "B5",
124 "Folio",
125 "Quarto",
126 "10x14",
127 (char *) NULL
128 };
129
130/*
131 Help widget declarations.
132*/
133static const char
134 *ImageAnnotateHelp[] =
135 {
136 "In annotate mode, the Command widget has these options:",
137 "",
138 " Font Name",
139 " fixed",
140 " variable",
141 " 5x8",
142 " 6x10",
143 " 7x13bold",
144 " 8x13bold",
145 " 9x15bold",
146 " 10x20",
147 " 12x24",
148 " Browser...",
149 " Font Color",
150 " black",
151 " blue",
152 " cyan",
153 " green",
154 " gray",
155 " red",
156 " magenta",
157 " yellow",
158 " white",
159 " transparent",
160 " Browser...",
161 " Font Color",
162 " black",
163 " blue",
164 " cyan",
165 " green",
166 " gray",
167 " red",
168 " magenta",
169 " yellow",
170 " white",
171 " transparent",
172 " Browser...",
173 " Rotate Text",
174 " -90",
175 " -45",
176 " -30",
177 " 0",
178 " 30",
179 " 45",
180 " 90",
181 " 180",
182 " Dialog...",
183 " Help",
184 " Dismiss",
185 "",
186 "Choose a font name from the Font Name sub-menu. Additional",
187 "font names can be specified with the font browser. You can",
188 "change the menu names by setting the X resources font1",
189 "through font9.",
190 "",
191 "Choose a font color from the Font Color sub-menu.",
192 "Additional font colors can be specified with the color",
193 "browser. You can change the menu colors by setting the X",
194 "resources pen1 through pen9.",
195 "",
196 "If you select the color browser and press Grab, you can",
197 "choose the font color by moving the pointer to the desired",
198 "color on the screen and press any button.",
199 "",
200 "If you choose to rotate the text, choose Rotate Text from the",
201 "menu and select an angle. Typically you will only want to",
202 "rotate one line of text at a time. Depending on the angle you",
203 "choose, subsequent lines may end up overwriting each other.",
204 "",
205 "Choosing a font and its color is optional. The default font",
206 "is fixed and the default color is black. However, you must",
207 "choose a location to begin entering text and press button 1.",
208 "An underscore character will appear at the location of the",
209 "pointer. The cursor changes to a pencil to indicate you are",
210 "in text mode. To exit immediately, press Dismiss.",
211 "",
212 "In text mode, any key presses will display the character at",
213 "the location of the underscore and advance the underscore",
214 "cursor. Enter your text and once completed press Apply to",
215 "finish your image annotation. To correct errors press BACK",
216 "SPACE. To delete an entire line of text, press DELETE. Any",
217 "text that exceeds the boundaries of the image window is",
218 "automagically continued onto the next line.",
219 "",
220 "The actual color you request for the font is saved in the",
221 "image. However, the color that appears in your image window",
222 "may be different. For example, on a monochrome screen the",
223 "text will appear black or white even if you choose the color",
224 "red as the font color. However, the image saved to a file",
225 "with -write is written with red lettering. To assure the",
226 "correct color text in the final image, any PseudoClass image",
227 "is promoted to DirectClass (see miff(5)). To force a",
228 "PseudoClass image to remain PseudoClass, use -colors.",
229 (char *) NULL,
230 },
231 *ImageChopHelp[] =
232 {
233 "In chop mode, the Command widget has these options:",
234 "",
235 " Direction",
236 " horizontal",
237 " vertical",
238 " Help",
239 " Dismiss",
240 "",
241 "If the you choose the horizontal direction (this the",
242 "default), the area of the image between the two horizontal",
243 "endpoints of the chop line is removed. Otherwise, the area",
244 "of the image between the two vertical endpoints of the chop",
245 "line is removed.",
246 "",
247 "Select a location within the image window to begin your chop,",
248 "press and hold any button. Next, move the pointer to",
249 "another location in the image. As you move a line will",
250 "connect the initial location and the pointer. When you",
251 "release the button, the area within the image to chop is",
252 "determined by which direction you choose from the Command",
253 "widget.",
254 "",
255 "To cancel the image chopping, move the pointer back to the",
256 "starting point of the line and release the button.",
257 (char *) NULL,
258 },
259 *ImageColorEditHelp[] =
260 {
261 "In color edit mode, the Command widget has these options:",
262 "",
263 " Method",
264 " point",
265 " replace",
266 " floodfill",
267 " filltoborder",
268 " reset",
269 " Pixel Color",
270 " black",
271 " blue",
272 " cyan",
273 " green",
274 " gray",
275 " red",
276 " magenta",
277 " yellow",
278 " white",
279 " Browser...",
280 " Border Color",
281 " black",
282 " blue",
283 " cyan",
284 " green",
285 " gray",
286 " red",
287 " magenta",
288 " yellow",
289 " white",
290 " Browser...",
291 " Fuzz",
292 " 0%",
293 " 2%",
294 " 5%",
295 " 10%",
296 " 15%",
297 " Dialog...",
298 " Undo",
299 " Help",
300 " Dismiss",
301 "",
302 "Choose a color editing method from the Method sub-menu",
303 "of the Command widget. The point method recolors any pixel",
304 "selected with the pointer until the button is released. The",
305 "replace method recolors any pixel that matches the color of",
306 "the pixel you select with a button press. Floodfill recolors",
307 "any pixel that matches the color of the pixel you select with",
308 "a button press and is a neighbor. Whereas filltoborder recolors",
309 "any neighbor pixel that is not the border color. Finally reset",
310 "changes the entire image to the designated color.",
311 "",
312 "Next, choose a pixel color from the Pixel Color sub-menu.",
313 "Additional pixel colors can be specified with the color",
314 "browser. You can change the menu colors by setting the X",
315 "resources pen1 through pen9.",
316 "",
317 "Now press button 1 to select a pixel within the image window",
318 "to change its color. Additional pixels may be recolored as",
319 "prescribed by the method you choose.",
320 "",
321 "If the Magnify widget is mapped, it can be helpful in positioning",
322 "your pointer within the image (refer to button 2).",
323 "",
324 "The actual color you request for the pixels is saved in the",
325 "image. However, the color that appears in your image window",
326 "may be different. For example, on a monochrome screen the",
327 "pixel will appear black or white even if you choose the",
328 "color red as the pixel color. However, the image saved to a",
329 "file with -write is written with red pixels. To assure the",
330 "correct color text in the final image, any PseudoClass image",
331 "is promoted to DirectClass (see miff(5)). To force a",
332 "PseudoClass image to remain PseudoClass, use -colors.",
333 (char *) NULL,
334 },
335 *ImageCompositeHelp[] =
336 {
337 "First a widget window is displayed requesting you to enter an",
338 "image name. Press Composite, Grab or type a file name.",
339 "Press Cancel if you choose not to create a composite image.",
340 "When you choose Grab, move the pointer to the desired window",
341 "and press any button.",
342 "",
343 "If the Composite image does not have any matte information,",
344 "you are informed and the file browser is displayed again.",
345 "Enter the name of a mask image. The image is typically",
346 "grayscale and the same size as the composite image. If the",
347 "image is not grayscale, it is converted to grayscale and the",
348 "resulting intensities are used as matte information.",
349 "",
350 "A small window appears showing the location of the cursor in",
351 "the image window. You are now in composite mode. To exit",
352 "immediately, press Dismiss. In composite mode, the Command",
353 "widget has these options:",
354 "",
355 " Operators",
356 " Over",
357 " In",
358 " Out",
359 " Atop",
360 " Xor",
361 " Plus",
362 " Minus",
363 " Add",
364 " Subtract",
365 " Difference",
366 " Multiply",
367 " Bumpmap",
368 " Copy",
369 " CopyRed",
370 " CopyGreen",
371 " CopyBlue",
372 " CopyOpacity",
373 " Clear",
374 " Dissolve",
375 " Displace",
376 " Help",
377 " Dismiss",
378 "",
379 "Choose a composite operation from the Operators sub-menu of",
380 "the Command widget. How each operator behaves is described",
381 "below. Image window is the image currently displayed on",
382 "your X server and image is the image obtained with the File",
383 "Browser widget.",
384 "",
385 "Over The result is the union of the two image shapes,",
386 " with image obscuring image window in the region of",
387 " overlap.",
388 "",
389 "In The result is simply image cut by the shape of",
390 " image window. None of the image data of image",
391 " window is in the result.",
392 "",
393 "Out The resulting image is image with the shape of",
394 " image window cut out.",
395 "",
396 "Atop The result is the same shape as image image window,",
397 " with image obscuring image window where the image",
398 " shapes overlap. Note this differs from over",
399 " because the portion of image outside image window's",
400 " shape does not appear in the result.",
401 "",
402 "Xor The result is the image data from both image and",
403 " image window that is outside the overlap region.",
404 " The overlap region is blank.",
405 "",
406 "Plus The result is just the sum of the image data.",
407 " Output values are cropped to QuantumRange (no overflow).",
408 "",
409 "Minus The result of image - image window, with underflow",
410 " cropped to zero.",
411 "",
412 "Add The result of image + image window, with overflow",
413 " wrapping around (mod 256).",
414 "",
415 "Subtract The result of image - image window, with underflow",
416 " wrapping around (mod 256). The add and subtract",
417 " operators can be used to perform reversible",
418 " transformations.",
419 "",
420 "Difference",
421 " The result of abs(image - image window). This",
422 " useful for comparing two very similar images.",
423 "",
424 "Multiply",
425 " The result of image * image window. This",
426 " useful for the creation of drop-shadows.",
427 "",
428 "Bumpmap The result of surface normals from image * image",
429 " window.",
430 "",
431 "Copy The resulting image is image window replaced with",
432 " image. Here the matte information is ignored.",
433 "",
434 "CopyRed The red layer of the image window is replace with",
435 " the red layer of the image. The other layers are",
436 " untouched.",
437 "",
438 "CopyGreen",
439 " The green layer of the image window is replace with",
440 " the green layer of the image. The other layers are",
441 " untouched.",
442 "",
443 "CopyBlue The blue layer of the image window is replace with",
444 " the blue layer of the image. The other layers are",
445 " untouched.",
446 "",
447 "CopyOpacity",
448 " The matte layer of the image window is replace with",
449 " the matte layer of the image. The other layers are",
450 " untouched.",
451 "",
452 "The image compositor requires a matte, or alpha channel in",
453 "the image for some operations. This extra channel usually",
454 "defines a mask which represents a sort of a cookie-cutter",
455 "for the image. This the case when matte is opaque (full",
456 "coverage) for pixels inside the shape, zero outside, and",
457 "between 0 and QuantumRange on the boundary. If image does not",
458 "have a matte channel, it is initialized with 0 for any pixel",
459 "matching in color to pixel location (0,0), otherwise QuantumRange.",
460 "",
461 "If you choose Dissolve, the composite operator becomes Over. The",
462 "image matte channel percent transparency is initialized to factor.",
463 "The image window is initialized to (100-factor). Where factor is the",
464 "value you specify in the Dialog widget.",
465 "",
466 "Displace shifts the image pixels as defined by a displacement",
467 "map. With this option, image is used as a displacement map.",
468 "Black, within the displacement map, is a maximum positive",
469 "displacement. White is a maximum negative displacement and",
470 "middle gray is neutral. The displacement is scaled to determine",
471 "the pixel shift. By default, the displacement applies in both the",
472 "horizontal and vertical directions. However, if you specify a mask,",
473 "image is the horizontal X displacement and mask the vertical Y",
474 "displacement.",
475 "",
476 "Note that matte information for image window is not retained",
477 "for colormapped X server visuals (e.g. StaticColor,",
478 "StaticColor, GrayScale, PseudoColor). Correct compositing",
479 "behavior may require a TrueColor or DirectColor visual or a",
480 "Standard Colormap.",
481 "",
482 "Choosing a composite operator is optional. The default",
483 "operator is replace. However, you must choose a location to",
484 "composite your image and press button 1. Press and hold the",
485 "button before releasing and an outline of the image will",
486 "appear to help you identify your location.",
487 "",
488 "The actual colors of the composite image is saved. However,",
489 "the color that appears in image window may be different.",
490 "For example, on a monochrome screen image window will appear",
491 "black or white even though your composited image may have",
492 "many colors. If the image is saved to a file it is written",
493 "with the correct colors. To assure the correct colors are",
494 "saved in the final image, any PseudoClass image is promoted",
495 "to DirectClass (see miff(5)). To force a PseudoClass image",
496 "to remain PseudoClass, use -colors.",
497 (char *) NULL,
498 },
499 *ImageCutHelp[] =
500 {
501 "In cut mode, the Command widget has these options:",
502 "",
503 " Help",
504 " Dismiss",
505 "",
506 "To define a cut region, press button 1 and drag. The",
507 "cut region is defined by a highlighted rectangle that",
508 "expands or contracts as it follows the pointer. Once you",
509 "are satisfied with the cut region, release the button.",
510 "You are now in rectify mode. In rectify mode, the Command",
511 "widget has these options:",
512 "",
513 " Cut",
514 " Help",
515 " Dismiss",
516 "",
517 "You can make adjustments by moving the pointer to one of the",
518 "cut rectangle corners, pressing a button, and dragging.",
519 "Finally, press Cut to commit your copy region. To",
520 "exit without cutting the image, press Dismiss.",
521 (char *) NULL,
522 },
523 *ImageCopyHelp[] =
524 {
525 "In copy mode, the Command widget has these options:",
526 "",
527 " Help",
528 " Dismiss",
529 "",
530 "To define a copy region, press button 1 and drag. The",
531 "copy region is defined by a highlighted rectangle that",
532 "expands or contracts as it follows the pointer. Once you",
533 "are satisfied with the copy region, release the button.",
534 "You are now in rectify mode. In rectify mode, the Command",
535 "widget has these options:",
536 "",
537 " Copy",
538 " Help",
539 " Dismiss",
540 "",
541 "You can make adjustments by moving the pointer to one of the",
542 "copy rectangle corners, pressing a button, and dragging.",
543 "Finally, press Copy to commit your copy region. To",
544 "exit without copying the image, press Dismiss.",
545 (char *) NULL,
546 },
547 *ImageCropHelp[] =
548 {
549 "In crop mode, the Command widget has these options:",
550 "",
551 " Help",
552 " Dismiss",
553 "",
554 "To define a cropping region, press button 1 and drag. The",
555 "cropping region is defined by a highlighted rectangle that",
556 "expands or contracts as it follows the pointer. Once you",
557 "are satisfied with the cropping region, release the button.",
558 "You are now in rectify mode. In rectify mode, the Command",
559 "widget has these options:",
560 "",
561 " Crop",
562 " Help",
563 " Dismiss",
564 "",
565 "You can make adjustments by moving the pointer to one of the",
566 "cropping rectangle corners, pressing a button, and dragging.",
567 "Finally, press Crop to commit your cropping region. To",
568 "exit without cropping the image, press Dismiss.",
569 (char *) NULL,
570 },
571 *ImageDrawHelp[] =
572 {
573 "The cursor changes to a crosshair to indicate you are in",
574 "draw mode. To exit immediately, press Dismiss. In draw mode,",
575 "the Command widget has these options:",
576 "",
577 " Element",
578 " point",
579 " line",
580 " rectangle",
581 " fill rectangle",
582 " circle",
583 " fill circle",
584 " ellipse",
585 " fill ellipse",
586 " polygon",
587 " fill polygon",
588 " Color",
589 " black",
590 " blue",
591 " cyan",
592 " green",
593 " gray",
594 " red",
595 " magenta",
596 " yellow",
597 " white",
598 " transparent",
599 " Browser...",
600 " Stipple",
601 " Brick",
602 " Diagonal",
603 " Scales",
604 " Vertical",
605 " Wavy",
606 " Translucent",
607 " Opaque",
608 " Open...",
609 " Width",
610 " 1",
611 " 2",
612 " 4",
613 " 8",
614 " 16",
615 " Dialog...",
616 " Undo",
617 " Help",
618 " Dismiss",
619 "",
620 "Choose a drawing primitive from the Element sub-menu.",
621 "",
622 "Choose a color from the Color sub-menu. Additional",
623 "colors can be specified with the color browser.",
624 "",
625 "If you choose the color browser and press Grab, you can",
626 "select the color by moving the pointer to the desired",
627 "color on the screen and press any button. The transparent",
628 "color updates the image matte channel and is useful for",
629 "image compositing.",
630 "",
631 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
632 "Additional stipples can be specified with the file browser.",
633 "Stipples obtained from the file browser must be on disk in the",
634 "X11 bitmap format.",
635 "",
636 "Choose a width, if appropriate, from the Width sub-menu. To",
637 "choose a specific width select the Dialog widget.",
638 "",
639 "Choose a point in the Image window and press button 1 and",
640 "hold. Next, move the pointer to another location in the",
641 "image. As you move, a line connects the initial location and",
642 "the pointer. When you release the button, the image is",
643 "updated with the primitive you just drew. For polygons, the",
644 "image is updated when you press and release the button without",
645 "moving the pointer.",
646 "",
647 "To cancel image drawing, move the pointer back to the",
648 "starting point of the line and release the button.",
649 (char *) NULL,
650 },
651 *DisplayHelp[] =
652 {
653 "BUTTONS",
654 " The effects of each button press is described below. Three",
655 " buttons are required. If you have a two button mouse,",
656 " button 1 and 3 are returned. Press ALT and button 3 to",
657 " simulate button 2.",
658 "",
659 " 1 Press this button to map or unmap the Command widget.",
660 "",
661 " 2 Press and drag to define a region of the image to",
662 " magnify.",
663 "",
664 " 3 Press and drag to choose from a select set of commands.",
665 " This button behaves differently if the image being",
666 " displayed is a visual image directory. Here, choose a",
667 " particular tile of the directory and press this button and",
668 " drag to select a command from a pop-up menu. Choose from",
669 " these menu items:",
670 "",
671 " Open",
672 " Next",
673 " Former",
674 " Delete",
675 " Update",
676 "",
677 " If you choose Open, the image represented by the tile is",
678 " displayed. To return to the visual image directory, choose",
679 " Next from the Command widget. Next and Former moves to the",
680 " next or former image respectively. Choose Delete to delete",
681 " a particular image tile. Finally, choose Update to",
682 " synchronize all the image tiles with their respective",
683 " images.",
684 "",
685 "COMMAND WIDGET",
686 " The Command widget lists a number of sub-menus and commands.",
687 " They are",
688 "",
689 " File",
690 " Open...",
691 " Next",
692 " Former",
693 " Select...",
694 " Save...",
695 " Print...",
696 " Delete...",
697 " New...",
698 " Visual Directory...",
699 " Quit",
700 " Edit",
701 " Undo",
702 " Redo",
703 " Cut",
704 " Copy",
705 " Paste",
706 " View",
707 " Half Size",
708 " Original Size",
709 " Double Size",
710 " Resize...",
711 " Apply",
712 " Refresh",
713 " Restore",
714 " Transform",
715 " Crop",
716 " Chop",
717 " Flop",
718 " Flip",
719 " Rotate Right",
720 " Rotate Left",
721 " Rotate...",
722 " Shear...",
723 " Roll...",
724 " Trim Edges",
725 " Enhance",
726 " Brightness...",
727 " Saturation...",
728 " Hue...",
729 " Gamma...",
730 " Sharpen...",
731 " Dull",
732 " Contrast Stretch...",
733 " Sigmoidal Contrast...",
734 " Normalize",
735 " Equalize",
736 " Negate",
737 " Grayscale",
738 " Map...",
739 " Quantize...",
740 " Effects",
741 " Despeckle",
742 " Emboss",
743 " Reduce Noise",
744 " Add Noise",
745 " Sharpen...",
746 " Blur...",
747 " Threshold...",
748 " Edge Detect...",
749 " Spread...",
750 " Shade...",
751 " Painting...",
752 " Segment...",
753 " F/X",
754 " Solarize...",
755 " Sepia Tone...",
756 " Swirl...",
757 " Implode...",
758 " Vignette...",
759 " Wave...",
760 " Oil Painting...",
761 " Charcoal Drawing...",
762 " Image Edit",
763 " Annotate...",
764 " Draw...",
765 " Color...",
766 " Matte...",
767 " Composite...",
768 " Add Border...",
769 " Add Frame...",
770 " Comment...",
771 " Launch...",
772 " Region of Interest...",
773 " Miscellany",
774 " Image Info",
775 " Zoom Image",
776 " Show Preview...",
777 " Show Histogram",
778 " Show Matte",
779 " Background...",
780 " Slide Show",
781 " Preferences...",
782 " Help",
783 " Overview",
784 " Browse Documentation",
785 " About Display",
786 "",
787 " Menu items with a indented triangle have a sub-menu. They",
788 " are represented above as the indented items. To access a",
789 " sub-menu item, move the pointer to the appropriate menu and",
790 " press a button and drag. When you find the desired sub-menu",
791 " item, release the button and the command is executed. Move",
792 " the pointer away from the sub-menu if you decide not to",
793 " execute a particular command.",
794 "",
795 "KEYBOARD ACCELERATORS",
796 " Accelerators are one or two key presses that effect a",
797 " particular command. The keyboard accelerators that",
798 " display(1) understands is:",
799 "",
800 " Ctl+O Press to open an image from a file.",
801 "",
802 " space Press to display the next image.",
803 "",
804 " If the image is a multi-paged document such as a Postscript",
805 " document, you can skip ahead several pages by preceding",
806 " this command with a number. For example to display the",
807 " third page beyond the current page, press 3<space>.",
808 "",
809 " backspace Press to display the former image.",
810 "",
811 " If the image is a multi-paged document such as a Postscript",
812 " document, you can skip behind several pages by preceding",
813 " this command with a number. For example to display the",
814 " third page preceding the current page, press 3<backspace>.",
815 "",
816 " Ctl+S Press to write the image to a file.",
817 "",
818 " Ctl+P Press to print the image to a Postscript printer.",
819 "",
820 " Ctl+D Press to delete an image file.",
821 "",
822 " Ctl+N Press to create a blank canvas.",
823 "",
824 " Ctl+Q Press to discard all images and exit program.",
825 "",
826 " Ctl+Z Press to undo last image transformation.",
827 "",
828 " Ctl+R Press to redo last image transformation.",
829 "",
830 " Ctl+X Press to cut a region of the image.",
831 "",
832 " Ctl+C Press to copy a region of the image.",
833 "",
834 " Ctl+V Press to paste a region to the image.",
835 "",
836 " < Press to half the image size.",
837 "",
838 " - Press to return to the original image size.",
839 "",
840 " > Press to double the image size.",
841 "",
842 " % Press to resize the image to a width and height you",
843 " specify.",
844 "",
845 "Cmd-A Press to make any image transformations permanent."
846 "",
847 " By default, any image size transformations are applied",
848 " to the original image to create the image displayed on",
849 " the X server. However, the transformations are not",
850 " permanent (i.e. the original image does not change",
851 " size only the X image does). For example, if you",
852 " press > the X image will appear to double in size,",
853 " but the original image will in fact remain the same size.",
854 " To force the original image to double in size, press >",
855 " followed by Cmd-A.",
856 "",
857 " @ Press to refresh the image window.",
858 "",
859 " C Press to cut out a rectangular region of the image.",
860 "",
861 " [ Press to chop the image.",
862 "",
863 " H Press to flop image in the horizontal direction.",
864 "",
865 " V Press to flip image in the vertical direction.",
866 "",
867 " / Press to rotate the image 90 degrees clockwise.",
868 "",
869 " \\ Press to rotate the image 90 degrees counter-clockwise.",
870 "",
871 " * Press to rotate the image the number of degrees you",
872 " specify.",
873 "",
874 " S Press to shear the image the number of degrees you",
875 " specify.",
876 "",
877 " R Press to roll the image.",
878 "",
879 " T Press to trim the image edges.",
880 "",
881 " Shft-H Press to vary the image hue.",
882 "",
883 " Shft-S Press to vary the color saturation.",
884 "",
885 " Shft-L Press to vary the color brightness.",
886 "",
887 " Shft-G Press to gamma correct the image.",
888 "",
889 " Shft-C Press to sharpen the image contrast.",
890 "",
891 " Shft-Z Press to dull the image contrast.",
892 "",
893 " = Press to perform histogram equalization on the image.",
894 "",
895 " Shft-N Press to perform histogram normalization on the image.",
896 "",
897 " Shft-~ Press to negate the colors of the image.",
898 "",
899 " . Press to convert the image colors to gray.",
900 "",
901 " Shft-# Press to set the maximum number of unique colors in the",
902 " image.",
903 "",
904 " F2 Press to reduce the speckles in an image.",
905 "",
906 " F3 Press to eliminate peak noise from an image.",
907 "",
908 " F4 Press to add noise to an image.",
909 "",
910 " F5 Press to sharpen an image.",
911 "",
912 " F6 Press to delete an image file.",
913 "",
914 " F7 Press to threshold the image.",
915 "",
916 " F8 Press to detect edges within an image.",
917 "",
918 " F9 Press to emboss an image.",
919 "",
920 " F10 Press to displace pixels by a random amount.",
921 "",
922 " F11 Press to negate all pixels above the threshold level.",
923 "",
924 " F12 Press to shade the image using a distant light source.",
925 "",
926 " F13 Press to lighten or darken image edges to create a 3-D effect.",
927 "",
928 " F14 Press to segment the image by color.",
929 "",
930 " Meta-S Press to swirl image pixels about the center.",
931 "",
932 " Meta-I Press to implode image pixels about the center.",
933 "",
934 " Meta-W Press to alter an image along a sine wave.",
935 "",
936 " Meta-P Press to simulate an oil painting.",
937 "",
938 " Meta-C Press to simulate a charcoal drawing.",
939 "",
940 " Alt-A Press to annotate the image with text.",
941 "",
942 " Alt-D Press to draw on an image.",
943 "",
944 " Alt-P Press to edit an image pixel color.",
945 "",
946 " Alt-M Press to edit the image matte information.",
947 "",
948 " Alt-V Press to composite the image with another.",
949 "",
950 " Alt-B Press to add a border to the image.",
951 "",
952 " Alt-F Press to add an ornamental border to the image.",
953 "",
954 " Alt-Shft-!",
955 " Press to add an image comment.",
956 "",
957 " Ctl-A Press to apply image processing techniques to a region",
958 " of interest.",
959 "",
960 " Shft-? Press to display information about the image.",
961 "",
962 " Shft-+ Press to map the zoom image window.",
963 "",
964 " Shft-P Press to preview an image enhancement, effect, or f/x.",
965 "",
966 " F1 Press to display helpful information about display(1).",
967 "",
968 " Find Press to browse documentation about ImageMagick.",
969 "",
970 " 1-9 Press to change the level of magnification.",
971 "",
972 " Use the arrow keys to move the image one pixel up, down,",
973 " left, or right within the magnify window. Be sure to first",
974 " map the magnify window by pressing button 2.",
975 "",
976 " Press ALT and one of the arrow keys to trim off one pixel",
977 " from any side of the image.",
978 (char *) NULL,
979 },
980 *ImageMatteEditHelp[] =
981 {
982 "Matte information within an image is useful for some",
983 "operations such as image compositing (See IMAGE",
984 "COMPOSITING). This extra channel usually defines a mask",
985 "which represents a sort of a cookie-cutter for the image.",
986 "This the case when matte is opaque (full coverage) for",
987 "pixels inside the shape, zero outside, and between 0 and",
988 "QuantumRange on the boundary.",
989 "",
990 "A small window appears showing the location of the cursor in",
991 "the image window. You are now in matte edit mode. To exit",
992 "immediately, press Dismiss. In matte edit mode, the Command",
993 "widget has these options:",
994 "",
995 " Method",
996 " point",
997 " replace",
998 " floodfill",
999 " filltoborder",
1000 " reset",
1001 " Border Color",
1002 " black",
1003 " blue",
1004 " cyan",
1005 " green",
1006 " gray",
1007 " red",
1008 " magenta",
1009 " yellow",
1010 " white",
1011 " Browser...",
1012 " Fuzz",
1013 " 0%",
1014 " 2%",
1015 " 5%",
1016 " 10%",
1017 " 15%",
1018 " Dialog...",
1019 " Matte",
1020 " Opaque",
1021 " Transparent",
1022 " Dialog...",
1023 " Undo",
1024 " Help",
1025 " Dismiss",
1026 "",
1027 "Choose a matte editing method from the Method sub-menu of",
1028 "the Command widget. The point method changes the matte value",
1029 "of any pixel selected with the pointer until the button is",
1030 "is released. The replace method changes the matte value of",
1031 "any pixel that matches the color of the pixel you select with",
1032 "a button press. Floodfill changes the matte value of any pixel",
1033 "that matches the color of the pixel you select with a button",
1034 "press and is a neighbor. Whereas filltoborder changes the matte",
1035 "value any neighbor pixel that is not the border color. Finally",
1036 "reset changes the entire image to the designated matte value.",
1037 "",
1038 "Choose Matte Value and pick Opaque or Transarent. For other values",
1039 "select the Dialog entry. Here a dialog appears requesting a matte",
1040 "value. The value you select is assigned as the opacity value of the",
1041 "selected pixel or pixels.",
1042 "",
1043 "Now, press any button to select a pixel within the image",
1044 "window to change its matte value.",
1045 "",
1046 "If the Magnify widget is mapped, it can be helpful in positioning",
1047 "your pointer within the image (refer to button 2).",
1048 "",
1049 "Matte information is only valid in a DirectClass image.",
1050 "Therefore, any PseudoClass image is promoted to DirectClass",
1051 "(see miff(5)). Note that matte information for PseudoClass",
1052 "is not retained for colormapped X server visuals (e.g.",
1053 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1054 "immediately save your image to a file (refer to Write).",
1055 "Correct matte editing behavior may require a TrueColor or",
1056 "DirectColor visual or a Standard Colormap.",
1057 (char *) NULL,
1058 },
1059 *ImagePanHelp[] =
1060 {
1061 "When an image exceeds the width or height of the X server",
1062 "screen, display maps a small panning icon. The rectangle",
1063 "within the panning icon shows the area that is currently",
1064 "displayed in the image window. To pan about the image,",
1065 "press any button and drag the pointer within the panning",
1066 "icon. The pan rectangle moves with the pointer and the",
1067 "image window is updated to reflect the location of the",
1068 "rectangle within the panning icon. When you have selected",
1069 "the area of the image you wish to view, release the button.",
1070 "",
1071 "Use the arrow keys to pan the image one pixel up, down,",
1072 "left, or right within the image window.",
1073 "",
1074 "The panning icon is withdrawn if the image becomes smaller",
1075 "than the dimensions of the X server screen.",
1076 (char *) NULL,
1077 },
1078 *ImagePasteHelp[] =
1079 {
1080 "A small window appears showing the location of the cursor in",
1081 "the image window. You are now in paste mode. To exit",
1082 "immediately, press Dismiss. In paste mode, the Command",
1083 "widget has these options:",
1084 "",
1085 " Operators",
1086 " over",
1087 " in",
1088 " out",
1089 " atop",
1090 " xor",
1091 " plus",
1092 " minus",
1093 " add",
1094 " subtract",
1095 " difference",
1096 " replace",
1097 " Help",
1098 " Dismiss",
1099 "",
1100 "Choose a composite operation from the Operators sub-menu of",
1101 "the Command widget. How each operator behaves is described",
1102 "below. Image window is the image currently displayed on",
1103 "your X server and image is the image obtained with the File",
1104 "Browser widget.",
1105 "",
1106 "Over The result is the union of the two image shapes,",
1107 " with image obscuring image window in the region of",
1108 " overlap.",
1109 "",
1110 "In The result is simply image cut by the shape of",
1111 " image window. None of the image data of image",
1112 " window is in the result.",
1113 "",
1114 "Out The resulting image is image with the shape of",
1115 " image window cut out.",
1116 "",
1117 "Atop The result is the same shape as image image window,",
1118 " with image obscuring image window where the image",
1119 " shapes overlap. Note this differs from over",
1120 " because the portion of image outside image window's",
1121 " shape does not appear in the result.",
1122 "",
1123 "Xor The result is the image data from both image and",
1124 " image window that is outside the overlap region.",
1125 " The overlap region is blank.",
1126 "",
1127 "Plus The result is just the sum of the image data.",
1128 " Output values are cropped to QuantumRange (no overflow).",
1129 " This operation is independent of the matte",
1130 " channels.",
1131 "",
1132 "Minus The result of image - image window, with underflow",
1133 " cropped to zero.",
1134 "",
1135 "Add The result of image + image window, with overflow",
1136 " wrapping around (mod 256).",
1137 "",
1138 "Subtract The result of image - image window, with underflow",
1139 " wrapping around (mod 256). The add and subtract",
1140 " operators can be used to perform reversible",
1141 " transformations.",
1142 "",
1143 "Difference",
1144 " The result of abs(image - image window). This",
1145 " useful for comparing two very similar images.",
1146 "",
1147 "Copy The resulting image is image window replaced with",
1148 " image. Here the matte information is ignored.",
1149 "",
1150 "CopyRed The red layer of the image window is replace with",
1151 " the red layer of the image. The other layers are",
1152 " untouched.",
1153 "",
1154 "CopyGreen",
1155 " The green layer of the image window is replace with",
1156 " the green layer of the image. The other layers are",
1157 " untouched.",
1158 "",
1159 "CopyBlue The blue layer of the image window is replace with",
1160 " the blue layer of the image. The other layers are",
1161 " untouched.",
1162 "",
1163 "CopyOpacity",
1164 " The matte layer of the image window is replace with",
1165 " the matte layer of the image. The other layers are",
1166 " untouched.",
1167 "",
1168 "The image compositor requires a matte, or alpha channel in",
1169 "the image for some operations. This extra channel usually",
1170 "defines a mask which represents a sort of a cookie-cutter",
1171 "for the image. This the case when matte is opaque (full",
1172 "coverage) for pixels inside the shape, zero outside, and",
1173 "between 0 and QuantumRange on the boundary. If image does not",
1174 "have a matte channel, it is initialized with 0 for any pixel",
1175 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1176 "",
1177 "Note that matte information for image window is not retained",
1178 "for colormapped X server visuals (e.g. StaticColor,",
1179 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1180 "behavior may require a TrueColor or DirectColor visual or a",
1181 "Standard Colormap.",
1182 "",
1183 "Choosing a composite operator is optional. The default",
1184 "operator is replace. However, you must choose a location to",
1185 "paste your image and press button 1. Press and hold the",
1186 "button before releasing and an outline of the image will",
1187 "appear to help you identify your location.",
1188 "",
1189 "The actual colors of the pasted image is saved. However,",
1190 "the color that appears in image window may be different.",
1191 "For example, on a monochrome screen image window will appear",
1192 "black or white even though your pasted image may have",
1193 "many colors. If the image is saved to a file it is written",
1194 "with the correct colors. To assure the correct colors are",
1195 "saved in the final image, any PseudoClass image is promoted",
1196 "to DirectClass (see miff(5)). To force a PseudoClass image",
1197 "to remain PseudoClass, use -colors.",
1198 (char *) NULL,
1199 },
1200 *ImageROIHelp[] =
1201 {
1202 "In region of interest mode, the Command widget has these",
1203 "options:",
1204 "",
1205 " Help",
1206 " Dismiss",
1207 "",
1208 "To define a region of interest, press button 1 and drag.",
1209 "The region of interest is defined by a highlighted rectangle",
1210 "that expands or contracts as it follows the pointer. Once",
1211 "you are satisfied with the region of interest, release the",
1212 "button. You are now in apply mode. In apply mode the",
1213 "Command widget has these options:",
1214 "",
1215 " File",
1216 " Save...",
1217 " Print...",
1218 " Edit",
1219 " Undo",
1220 " Redo",
1221 " Transform",
1222 " Flop",
1223 " Flip",
1224 " Rotate Right",
1225 " Rotate Left",
1226 " Enhance",
1227 " Hue...",
1228 " Saturation...",
1229 " Brightness...",
1230 " Gamma...",
1231 " Spiff",
1232 " Dull",
1233 " Contrast Stretch",
1234 " Sigmoidal Contrast...",
1235 " Normalize",
1236 " Equalize",
1237 " Negate",
1238 " Grayscale",
1239 " Map...",
1240 " Quantize...",
1241 " Effects",
1242 " Despeckle",
1243 " Emboss",
1244 " Reduce Noise",
1245 " Sharpen...",
1246 " Blur...",
1247 " Threshold...",
1248 " Edge Detect...",
1249 " Spread...",
1250 " Shade...",
1251 " Raise...",
1252 " Segment...",
1253 " F/X",
1254 " Solarize...",
1255 " Sepia Tone...",
1256 " Swirl...",
1257 " Implode...",
1258 " Vignette...",
1259 " Wave...",
1260 " Oil Painting...",
1261 " Charcoal Drawing...",
1262 " Miscellany",
1263 " Image Info",
1264 " Zoom Image",
1265 " Show Preview...",
1266 " Show Histogram",
1267 " Show Matte",
1268 " Help",
1269 " Dismiss",
1270 "",
1271 "You can make adjustments to the region of interest by moving",
1272 "the pointer to one of the rectangle corners, pressing a",
1273 "button, and dragging. Finally, choose an image processing",
1274 "technique from the Command widget. You can choose more than",
1275 "one image processing technique to apply to an area.",
1276 "Alternatively, you can move the region of interest before",
1277 "applying another image processing technique. To exit, press",
1278 "Dismiss.",
1279 (char *) NULL,
1280 },
1281 *ImageRotateHelp[] =
1282 {
1283 "In rotate mode, the Command widget has these options:",
1284 "",
1285 " Pixel Color",
1286 " black",
1287 " blue",
1288 " cyan",
1289 " green",
1290 " gray",
1291 " red",
1292 " magenta",
1293 " yellow",
1294 " white",
1295 " Browser...",
1296 " Direction",
1297 " horizontal",
1298 " vertical",
1299 " Help",
1300 " Dismiss",
1301 "",
1302 "Choose a background color from the Pixel Color sub-menu.",
1303 "Additional background colors can be specified with the color",
1304 "browser. You can change the menu colors by setting the X",
1305 "resources pen1 through pen9.",
1306 "",
1307 "If you choose the color browser and press Grab, you can",
1308 "select the background color by moving the pointer to the",
1309 "desired color on the screen and press any button.",
1310 "",
1311 "Choose a point in the image window and press this button and",
1312 "hold. Next, move the pointer to another location in the",
1313 "image. As you move a line connects the initial location and",
1314 "the pointer. When you release the button, the degree of",
1315 "image rotation is determined by the slope of the line you",
1316 "just drew. The slope is relative to the direction you",
1317 "choose from the Direction sub-menu of the Command widget.",
1318 "",
1319 "To cancel the image rotation, move the pointer back to the",
1320 "starting point of the line and release the button.",
1321 (char *) NULL,
1322 };
1323
1324/*
1325 Enumeration declarations.
1326*/
1327typedef enum
1328{
1329 CopyMode,
1330 CropMode,
1331 CutMode
1332} ClipboardMode;
1333
1334typedef enum
1335{
1336 OpenCommand,
1337 NextCommand,
1338 FormerCommand,
1339 SelectCommand,
1340 SaveCommand,
1341 PrintCommand,
1342 DeleteCommand,
1343 NewCommand,
1344 VisualDirectoryCommand,
1345 QuitCommand,
1346 UndoCommand,
1347 RedoCommand,
1348 CutCommand,
1349 CopyCommand,
1350 PasteCommand,
1351 HalfSizeCommand,
1352 OriginalSizeCommand,
1353 DoubleSizeCommand,
1354 ResizeCommand,
1355 ApplyCommand,
1356 RefreshCommand,
1357 RestoreCommand,
1358 CropCommand,
1359 ChopCommand,
1360 FlopCommand,
1361 FlipCommand,
1362 RotateRightCommand,
1363 RotateLeftCommand,
1364 RotateCommand,
1365 ShearCommand,
1366 RollCommand,
1367 TrimCommand,
1368 HueCommand,
1369 SaturationCommand,
1370 BrightnessCommand,
1371 GammaCommand,
1372 SpiffCommand,
1373 DullCommand,
1374 ContrastStretchCommand,
1375 SigmoidalContrastCommand,
1376 NormalizeCommand,
1377 EqualizeCommand,
1378 NegateCommand,
1379 GrayscaleCommand,
1380 MapCommand,
1381 QuantizeCommand,
1382 DespeckleCommand,
1383 EmbossCommand,
1384 ReduceNoiseCommand,
1385 AddNoiseCommand,
1386 SharpenCommand,
1387 BlurCommand,
1388 ThresholdCommand,
1389 EdgeDetectCommand,
1390 SpreadCommand,
1391 ShadeCommand,
1392 RaiseCommand,
1393 SegmentCommand,
1394 SolarizeCommand,
1395 SepiaToneCommand,
1396 SwirlCommand,
1397 ImplodeCommand,
1398 VignetteCommand,
1399 WaveCommand,
1400 OilPaintCommand,
1401 CharcoalDrawCommand,
1402 AnnotateCommand,
1403 DrawCommand,
1404 ColorCommand,
1405 MatteCommand,
1406 CompositeCommand,
1407 AddBorderCommand,
1408 AddFrameCommand,
1409 CommentCommand,
1410 LaunchCommand,
1411 RegionofInterestCommand,
1412 ROIHelpCommand,
1413 ROIDismissCommand,
1414 InfoCommand,
1415 ZoomCommand,
1416 ShowPreviewCommand,
1417 ShowHistogramCommand,
1418 ShowMatteCommand,
1419 BackgroundCommand,
1420 SlideShowCommand,
1421 PreferencesCommand,
1422 HelpCommand,
1423 BrowseDocumentationCommand,
1424 VersionCommand,
1425 SaveToUndoBufferCommand,
1426 FreeBuffersCommand,
1427 NullCommand
1428} CommandType;
1429
1430typedef enum
1431{
1432 AnnotateNameCommand,
1433 AnnotateFontColorCommand,
1434 AnnotateBackgroundColorCommand,
1435 AnnotateRotateCommand,
1436 AnnotateHelpCommand,
1437 AnnotateDismissCommand,
1438 TextHelpCommand,
1439 TextApplyCommand,
1440 ChopDirectionCommand,
1441 ChopHelpCommand,
1442 ChopDismissCommand,
1443 HorizontalChopCommand,
1444 VerticalChopCommand,
1445 ColorEditMethodCommand,
1446 ColorEditColorCommand,
1447 ColorEditBorderCommand,
1448 ColorEditFuzzCommand,
1449 ColorEditUndoCommand,
1450 ColorEditHelpCommand,
1451 ColorEditDismissCommand,
1452 CompositeOperatorsCommand,
1453 CompositeDissolveCommand,
1454 CompositeDisplaceCommand,
1455 CompositeHelpCommand,
1456 CompositeDismissCommand,
1457 CropHelpCommand,
1458 CropDismissCommand,
1459 RectifyCopyCommand,
1460 RectifyHelpCommand,
1461 RectifyDismissCommand,
1462 DrawElementCommand,
1463 DrawColorCommand,
1464 DrawStippleCommand,
1465 DrawWidthCommand,
1466 DrawUndoCommand,
1467 DrawHelpCommand,
1468 DrawDismissCommand,
1469 MatteEditMethod,
1470 MatteEditBorderCommand,
1471 MatteEditFuzzCommand,
1472 MatteEditValueCommand,
1473 MatteEditUndoCommand,
1474 MatteEditHelpCommand,
1475 MatteEditDismissCommand,
1476 PasteOperatorsCommand,
1477 PasteHelpCommand,
1478 PasteDismissCommand,
1479 RotateColorCommand,
1480 RotateDirectionCommand,
1481 RotateCropCommand,
1482 RotateSharpenCommand,
1483 RotateHelpCommand,
1484 RotateDismissCommand,
1485 HorizontalRotateCommand,
1486 VerticalRotateCommand,
1487 TileLoadCommand,
1488 TileNextCommand,
1489 TileFormerCommand,
1490 TileDeleteCommand,
1491 TileUpdateCommand
1492} ModeType;
1493
1494/*
1495 Stipples.
1496*/
1497#define BricksWidth 20
1498#define BricksHeight 20
1499#define DiagonalWidth 16
1500#define DiagonalHeight 16
1501#define HighlightWidth 8
1502#define HighlightHeight 8
1503#define ScalesWidth 16
1504#define ScalesHeight 16
1505#define ShadowWidth 8
1506#define ShadowHeight 8
1507#define VerticalWidth 16
1508#define VerticalHeight 16
1509#define WavyWidth 16
1510#define WavyHeight 16
1511
1512/*
1513 Constant declaration.
1514*/
1515static const int
1516 RoiDelta = 8;
1517
1518static const unsigned char
1519 BricksBitmap[] =
1520 {
1521 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1522 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1523 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1524 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1525 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1526 },
1527 DiagonalBitmap[] =
1528 {
1529 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1530 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1531 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1532 },
1533 ScalesBitmap[] =
1534 {
1535 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1536 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1537 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1538 },
1539 VerticalBitmap[] =
1540 {
1541 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1542 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1543 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1544 },
1545 WavyBitmap[] =
1546 {
1547 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1548 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1549 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1550 };
1551
1552/*
1553 Function prototypes.
1554*/
1555static CommandType
1556 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1557 const MagickStatusType,KeySym,Image **);
1558
1559static Image
1560 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1561 Image **),
1562 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1563 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1564 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1565
1566static MagickBooleanType
1567 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1568 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1569 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1570 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1571 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1572 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1573 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1574 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1575 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1576 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1577 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1578 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1579 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1580 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1581 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1582
1583static void
1584 XDrawPanRectangle(Display *,XWindows *),
1585 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
1586 XMagnifyImage(Display *,XWindows *,XEvent *),
1587 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1588 XPanImage(Display *,XWindows *,XEvent *),
1589 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1590 const KeySym),
1591 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1592 XScreenEvent(Display *,XWindows *,XEvent *),
1593 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1594
1595/*
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597% %
1598% %
1599% %
1600% D i s p l a y I m a g e s %
1601% %
1602% %
1603% %
1604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605%
1606% DisplayImages() displays an image sequence to any X window screen. It
1607% returns a value other than 0 if successful. Check the exception member
1608% of image to determine the reason for any failure.
1609%
1610% The format of the DisplayImages method is:
1611%
1612% MagickBooleanType DisplayImages(const ImageInfo *image_info,
1613% Image *images)
1614%
1615% A description of each parameter follows:
1616%
1617% o image_info: the image info.
1618%
1619% o image: the image.
1620%
1621*/
1622MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1623 Image *images)
1624{
1625 char
1626 *argv[1];
1627
1628 Display
1629 *display;
1630
1631 Image
1632 *image;
1633
1634 register long
1635 i;
1636
1637 unsigned long
1638 state;
1639
1640 XrmDatabase
1641 resource_database;
1642
1643 XResourceInfo
1644 resource_info;
1645
1646 assert(image_info != (const ImageInfo *) NULL);
1647 assert(image_info->signature == MagickSignature);
1648 assert(images != (Image *) NULL);
1649 assert(images->signature == MagickSignature);
1650 if (images->debug != MagickFalse)
1651 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1652 display=XOpenDisplay(image_info->server_name);
1653 if (display == (Display *) NULL)
1654 {
1655 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1656 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1657 image_info->server_name));
1658 return(MagickFalse);
1659 }
1660 if (images->exception.severity != UndefinedException)
1661 CatchException(&images->exception);
1662 (void) XSetErrorHandler(XError);
1663 resource_database=XGetResourceDatabase(display,GetClientName());
1664 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1665 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1666 if (image_info->page != (char *) NULL)
1667 resource_info.image_geometry=AcquireString(image_info->page);
1668 resource_info.immutable=MagickTrue;
1669 argv[0]=AcquireString(GetClientName());
1670 state=DefaultState;
1671 for (i=0; (state & ExitState) == 0; i++)
1672 {
1673 if ((images->iterations != 0) && (i >= (long) images->iterations))
1674 break;
1675 image=GetImageFromList(images,i % GetImageListLength(images));
1676 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1677 }
1678 argv[0]=DestroyString(argv[0]);
1679 (void) XCloseDisplay(display);
1680 XDestroyResourceInfo(&resource_info);
1681 if (images->exception.severity != UndefinedException)
1682 return(MagickFalse);
1683 return(MagickTrue);
1684}
1685
1686/*
1687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688% %
1689% %
1690% %
1691% R e m o t e D i s p l a y C o m m a n d %
1692% %
1693% %
1694% %
1695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696%
1697% RemoteDisplayCommand() encourages a remote display program to display the
1698% specified image filename.
1699%
1700% The format of the RemoteDisplayCommand method is:
1701%
1702% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1703% const char *window,const char *filename,ExceptionInfo *exception)
1704%
1705% A description of each parameter follows:
1706%
1707% o image_info: the image info.
1708%
1709% o window: Specifies the name or id of an X window.
1710%
1711% o filename: the name of the image filename to display.
1712%
1713% o exception: return any errors or warnings in this structure.
1714%
1715*/
1716MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1717 const char *window,const char *filename,ExceptionInfo *exception)
1718{
1719 Display
1720 *display;
1721
1722 MagickStatusType
1723 status;
1724
1725 assert(image_info != (const ImageInfo *) NULL);
1726 assert(image_info->signature == MagickSignature);
1727 assert(filename != (char *) NULL);
1728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1729 display=XOpenDisplay(image_info->server_name);
1730 if (display == (Display *) NULL)
1731 {
1732 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1733 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1734 return(MagickFalse);
1735 }
1736 (void) XSetErrorHandler(XError);
1737 status=XRemoteCommand(display,window,filename);
1738 (void) XCloseDisplay(display);
1739 return(status != 0 ? MagickTrue : MagickFalse);
1740}
1741
1742/*
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744% %
1745% %
1746% %
1747+ X A n n o t a t e E d i t I m a g e %
1748% %
1749% %
1750% %
1751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752%
1753% XAnnotateEditImage() annotates the image with text.
1754%
1755% The format of the XAnnotateEditImage method is:
1756%
1757% MagickBooleanType XAnnotateEditImage(Display *display,
1758% XResourceInfo *resource_info,XWindows *windows,Image *image)
1759%
1760% A description of each parameter follows:
1761%
1762% o display: Specifies a connection to an X server; returned from
1763% XOpenDisplay.
1764%
1765% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1766%
1767% o windows: Specifies a pointer to a XWindows structure.
1768%
1769% o image: the image; returned from ReadImage.
1770%
1771*/
1772
1773static inline long MagickMax(const long x,const long y)
1774{
1775 if (x > y)
1776 return(x);
1777 return(y);
1778}
1779
1780static inline long MagickMin(const long x,const long y)
1781{
1782 if (x < y)
1783 return(x);
1784 return(y);
1785}
1786
1787static MagickBooleanType XAnnotateEditImage(Display *display,
1788 XResourceInfo *resource_info,XWindows *windows,Image *image)
1789{
1790 static const char
1791 *AnnotateMenu[] =
1792 {
1793 "Font Name",
1794 "Font Color",
1795 "Box Color",
1796 "Rotate Text",
1797 "Help",
1798 "Dismiss",
1799 (char *) NULL
1800 },
1801 *TextMenu[] =
1802 {
1803 "Help",
1804 "Apply",
1805 (char *) NULL
1806 };
1807
1808 static const ModeType
1809 AnnotateCommands[] =
1810 {
1811 AnnotateNameCommand,
1812 AnnotateFontColorCommand,
1813 AnnotateBackgroundColorCommand,
1814 AnnotateRotateCommand,
1815 AnnotateHelpCommand,
1816 AnnotateDismissCommand
1817 },
1818 TextCommands[] =
1819 {
1820 TextHelpCommand,
1821 TextApplyCommand
1822 };
1823
1824 static MagickBooleanType
1825 transparent_box = MagickTrue,
1826 transparent_pen = MagickFalse;
1827
1828 static MagickRealType
1829 degrees = 0.0;
1830
1831 static unsigned int
1832 box_id = MaxNumberPens-2,
1833 font_id = 0,
1834 pen_id = 0;
1835
1836 char
1837 command[MaxTextExtent],
1838 text[MaxTextExtent];
1839
1840 const char
1841 *ColorMenu[MaxNumberPens+1];
1842
1843 Cursor
1844 cursor;
1845
1846 GC
1847 annotate_context;
1848
1849 int
1850 id,
1851 pen_number,
1852 status,
1853 x,
1854 y;
1855
1856 KeySym
1857 key_symbol;
1858
1859 register char
1860 *p;
1861
1862 register long
1863 i;
1864
1865 unsigned int
1866 height,
1867 width;
1868
1869 unsigned long
1870 state;
1871
1872 XAnnotateInfo
1873 *annotate_info,
1874 *previous_info;
1875
1876 XColor
1877 color;
1878
1879 XFontStruct
1880 *font_info;
1881
1882 XEvent
1883 event,
1884 text_event;
1885
1886 /*
1887 Map Command widget.
1888 */
1889 (void) CloneString(&windows->command.name,"Annotate");
1890 windows->command.data=4;
1891 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1892 (void) XMapRaised(display,windows->command.id);
1893 XClientMessage(display,windows->image.id,windows->im_protocols,
1894 windows->im_update_widget,CurrentTime);
1895 /*
1896 Track pointer until button 1 is pressed.
1897 */
1898 XQueryPosition(display,windows->image.id,&x,&y);
1899 (void) XSelectInput(display,windows->image.id,
1900 windows->image.attributes.event_mask | PointerMotionMask);
1901 cursor=XCreateFontCursor(display,XC_left_side);
1902 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1903 state=DefaultState;
1904 do
1905 {
1906 if (windows->info.mapped != MagickFalse)
1907 {
1908 /*
1909 Display pointer position.
1910 */
1911 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
1912 x+windows->image.x,y+windows->image.y);
1913 XInfoWidget(display,windows,text);
1914 }
1915 /*
1916 Wait for next event.
1917 */
1918 XScreenEvent(display,windows,&event);
1919 if (event.xany.window == windows->command.id)
1920 {
1921 /*
1922 Select a command from the Command widget.
1923 */
1924 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1925 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1926 if (id < 0)
1927 continue;
1928 switch (AnnotateCommands[id])
1929 {
1930 case AnnotateNameCommand:
1931 {
1932 const char
1933 *FontMenu[MaxNumberFonts];
1934
1935 int
1936 font_number;
1937
1938 /*
1939 Initialize menu selections.
1940 */
1941 for (i=0; i < MaxNumberFonts; i++)
1942 FontMenu[i]=resource_info->font_name[i];
1943 FontMenu[MaxNumberFonts-2]="Browser...";
1944 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1945 /*
1946 Select a font name from the pop-up menu.
1947 */
1948 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1949 (const char **) FontMenu,command);
1950 if (font_number < 0)
1951 break;
1952 if (font_number == (MaxNumberFonts-2))
1953 {
1954 static char
1955 font_name[MaxTextExtent] = "fixed";
1956
1957 /*
1958 Select a font name from a browser.
1959 */
1960 resource_info->font_name[font_number]=font_name;
1961 XFontBrowserWidget(display,windows,"Select",font_name);
1962 if (*font_name == '\0')
1963 break;
1964 }
1965 /*
1966 Initialize font info.
1967 */
1968 font_info=XLoadQueryFont(display,resource_info->font_name[
1969 font_number]);
1970 if (font_info == (XFontStruct *) NULL)
1971 {
1972 XNoticeWidget(display,windows,"Unable to load font:",
1973 resource_info->font_name[font_number]);
1974 break;
1975 }
1976 font_id=(unsigned int) font_number;
1977 (void) XFreeFont(display,font_info);
1978 break;
1979 }
1980 case AnnotateFontColorCommand:
1981 {
1982 /*
1983 Initialize menu selections.
1984 */
1985 for (i=0; i < (int) (MaxNumberPens-2); i++)
1986 ColorMenu[i]=resource_info->pen_colors[i];
1987 ColorMenu[MaxNumberPens-2]="transparent";
1988 ColorMenu[MaxNumberPens-1]="Browser...";
1989 ColorMenu[MaxNumberPens]=(const char *) NULL;
1990 /*
1991 Select a pen color from the pop-up menu.
1992 */
1993 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
1994 (const char **) ColorMenu,command);
1995 if (pen_number < 0)
1996 break;
1997 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
1998 MagickFalse;
1999 if (transparent_pen != MagickFalse)
2000 break;
2001 if (pen_number == (MaxNumberPens-1))
2002 {
2003 static char
2004 color_name[MaxTextExtent] = "gray";
2005
2006 /*
2007 Select a pen color from a dialog.
2008 */
2009 resource_info->pen_colors[pen_number]=color_name;
2010 XColorBrowserWidget(display,windows,"Select",color_name);
2011 if (*color_name == '\0')
2012 break;
2013 }
2014 /*
2015 Set pen color.
2016 */
2017 (void) XParseColor(display,windows->map_info->colormap,
2018 resource_info->pen_colors[pen_number],&color);
2019 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2020 (unsigned int) MaxColors,&color);
2021 windows->pixel_info->pen_colors[pen_number]=color;
2022 pen_id=(unsigned int) pen_number;
2023 break;
2024 }
2025 case AnnotateBackgroundColorCommand:
2026 {
2027 /*
2028 Initialize menu selections.
2029 */
2030 for (i=0; i < (int) (MaxNumberPens-2); i++)
2031 ColorMenu[i]=resource_info->pen_colors[i];
2032 ColorMenu[MaxNumberPens-2]="transparent";
2033 ColorMenu[MaxNumberPens-1]="Browser...";
2034 ColorMenu[MaxNumberPens]=(const char *) NULL;
2035 /*
2036 Select a pen color from the pop-up menu.
2037 */
2038 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2039 (const char **) ColorMenu,command);
2040 if (pen_number < 0)
2041 break;
2042 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2043 MagickFalse;
2044 if (transparent_box != MagickFalse)
2045 break;
2046 if (pen_number == (MaxNumberPens-1))
2047 {
2048 static char
2049 color_name[MaxTextExtent] = "gray";
2050
2051 /*
2052 Select a pen color from a dialog.
2053 */
2054 resource_info->pen_colors[pen_number]=color_name;
2055 XColorBrowserWidget(display,windows,"Select",color_name);
2056 if (*color_name == '\0')
2057 break;
2058 }
2059 /*
2060 Set pen color.
2061 */
2062 (void) XParseColor(display,windows->map_info->colormap,
2063 resource_info->pen_colors[pen_number],&color);
2064 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2065 (unsigned int) MaxColors,&color);
2066 windows->pixel_info->pen_colors[pen_number]=color;
2067 box_id=(unsigned int) pen_number;
2068 break;
2069 }
2070 case AnnotateRotateCommand:
2071 {
2072 int
2073 entry;
2074
2075 static char
2076 angle[MaxTextExtent] = "30.0";
2077
2078 static const char
2079 *RotateMenu[] =
2080 {
2081 "-90",
2082 "-45",
2083 "-30",
2084 "0",
2085 "30",
2086 "45",
2087 "90",
2088 "180",
2089 "Dialog...",
2090 (char *) NULL,
2091 };
2092
2093 /*
2094 Select a command from the pop-up menu.
2095 */
2096 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2097 command);
2098 if (entry < 0)
2099 break;
2100 if (entry != 8)
2101 {
cristyf2f27272009-12-17 14:48:46 +00002102 degrees=StringToDouble(RotateMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00002103 break;
2104 }
2105 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2106 angle);
2107 if (*angle == '\0')
2108 break;
cristyf2f27272009-12-17 14:48:46 +00002109 degrees=StringToDouble(angle);
cristy3ed852e2009-09-05 21:47:34 +00002110 break;
2111 }
2112 case AnnotateHelpCommand:
2113 {
2114 XTextViewWidget(display,resource_info,windows,MagickFalse,
2115 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2116 break;
2117 }
2118 case AnnotateDismissCommand:
2119 {
2120 /*
2121 Prematurely exit.
2122 */
2123 state|=EscapeState;
2124 state|=ExitState;
2125 break;
2126 }
2127 default:
2128 break;
2129 }
2130 continue;
2131 }
2132 switch (event.type)
2133 {
2134 case ButtonPress:
2135 {
2136 if (event.xbutton.button != Button1)
2137 break;
2138 if (event.xbutton.window != windows->image.id)
2139 break;
2140 /*
2141 Change to text entering mode.
2142 */
2143 x=event.xbutton.x;
2144 y=event.xbutton.y;
2145 state|=ExitState;
2146 break;
2147 }
2148 case ButtonRelease:
2149 break;
2150 case Expose:
2151 break;
2152 case KeyPress:
2153 {
2154 if (event.xkey.window != windows->image.id)
2155 break;
2156 /*
2157 Respond to a user key press.
2158 */
2159 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2160 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2161 switch ((int) key_symbol)
2162 {
2163 case XK_Escape:
2164 case XK_F20:
2165 {
2166 /*
2167 Prematurely exit.
2168 */
2169 state|=EscapeState;
2170 state|=ExitState;
2171 break;
2172 }
2173 case XK_F1:
2174 case XK_Help:
2175 {
2176 XTextViewWidget(display,resource_info,windows,MagickFalse,
2177 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2178 break;
2179 }
2180 default:
2181 {
2182 (void) XBell(display,0);
2183 break;
2184 }
2185 }
2186 break;
2187 }
2188 case MotionNotify:
2189 {
2190 /*
2191 Map and unmap Info widget as cursor crosses its boundaries.
2192 */
2193 x=event.xmotion.x;
2194 y=event.xmotion.y;
2195 if (windows->info.mapped != MagickFalse)
2196 {
2197 if ((x < (int) (windows->info.x+windows->info.width)) &&
2198 (y < (int) (windows->info.y+windows->info.height)))
2199 (void) XWithdrawWindow(display,windows->info.id,
2200 windows->info.screen);
2201 }
2202 else
2203 if ((x > (int) (windows->info.x+windows->info.width)) ||
2204 (y > (int) (windows->info.y+windows->info.height)))
2205 (void) XMapWindow(display,windows->info.id);
2206 break;
2207 }
2208 default:
2209 break;
2210 }
2211 } while ((state & ExitState) == 0);
2212 (void) XSelectInput(display,windows->image.id,
2213 windows->image.attributes.event_mask);
2214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2215 if ((state & EscapeState) != 0)
2216 return(MagickTrue);
2217 /*
2218 Set font info and check boundary conditions.
2219 */
2220 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2221 if (font_info == (XFontStruct *) NULL)
2222 {
2223 XNoticeWidget(display,windows,"Unable to load font:",
2224 resource_info->font_name[font_id]);
2225 font_info=windows->font_info;
2226 }
2227 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2228 x=(int) windows->image.width-font_info->max_bounds.width;
2229 if (y < (int) (font_info->ascent+font_info->descent))
2230 y=(int) font_info->ascent+font_info->descent;
2231 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2232 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2233 return(MagickFalse);
2234 /*
2235 Initialize annotate structure.
2236 */
cristy90823212009-12-12 20:48:33 +00002237 annotate_info=(XAnnotateInfo *) AcquireAlignedMemory(1,sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002238 if (annotate_info == (XAnnotateInfo *) NULL)
2239 return(MagickFalse);
2240 XGetAnnotateInfo(annotate_info);
2241 annotate_info->x=x;
2242 annotate_info->y=y;
2243 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2244 annotate_info->stencil=OpaqueStencil;
2245 else
2246 if (transparent_box == MagickFalse)
2247 annotate_info->stencil=BackgroundStencil;
2248 else
2249 annotate_info->stencil=ForegroundStencil;
2250 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2251 annotate_info->degrees=degrees;
2252 annotate_info->font_info=font_info;
2253 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2254 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2255 sizeof(*annotate_info->text));
2256 if (annotate_info->text == (char *) NULL)
2257 return(MagickFalse);
2258 /*
2259 Create cursor and set graphic context.
2260 */
2261 cursor=XCreateFontCursor(display,XC_pencil);
2262 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2263 annotate_context=windows->image.annotate_context;
2264 (void) XSetFont(display,annotate_context,font_info->fid);
2265 (void) XSetBackground(display,annotate_context,
2266 windows->pixel_info->pen_colors[box_id].pixel);
2267 (void) XSetForeground(display,annotate_context,
2268 windows->pixel_info->pen_colors[pen_id].pixel);
2269 /*
2270 Begin annotating the image with text.
2271 */
2272 (void) CloneString(&windows->command.name,"Text");
2273 windows->command.data=0;
2274 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2275 state=DefaultState;
2276 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2277 text_event.xexpose.width=(int) font_info->max_bounds.width;
2278 text_event.xexpose.height=font_info->max_bounds.ascent+
2279 font_info->max_bounds.descent;
2280 p=annotate_info->text;
2281 do
2282 {
2283 /*
2284 Display text cursor.
2285 */
2286 *p='\0';
2287 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2288 /*
2289 Wait for next event.
2290 */
2291 XScreenEvent(display,windows,&event);
2292 if (event.xany.window == windows->command.id)
2293 {
2294 /*
2295 Select a command from the Command widget.
2296 */
2297 (void) XSetBackground(display,annotate_context,
2298 windows->pixel_info->background_color.pixel);
2299 (void) XSetForeground(display,annotate_context,
2300 windows->pixel_info->foreground_color.pixel);
2301 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2302 (void) XSetBackground(display,annotate_context,
2303 windows->pixel_info->pen_colors[box_id].pixel);
2304 (void) XSetForeground(display,annotate_context,
2305 windows->pixel_info->pen_colors[pen_id].pixel);
2306 if (id < 0)
2307 continue;
2308 switch (TextCommands[id])
2309 {
2310 case TextHelpCommand:
2311 {
2312 XTextViewWidget(display,resource_info,windows,MagickFalse,
2313 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2314 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2315 break;
2316 }
2317 case TextApplyCommand:
2318 {
2319 /*
2320 Finished annotating.
2321 */
2322 annotate_info->width=(unsigned int) XTextWidth(font_info,
2323 annotate_info->text,(int) strlen(annotate_info->text));
2324 XRefreshWindow(display,&windows->image,&text_event);
2325 state|=ExitState;
2326 break;
2327 }
2328 default:
2329 break;
2330 }
2331 continue;
2332 }
2333 /*
2334 Erase text cursor.
2335 */
2336 text_event.xexpose.x=x;
2337 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2338 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2339 (unsigned int) text_event.xexpose.width,(unsigned int)
2340 text_event.xexpose.height,MagickFalse);
2341 XRefreshWindow(display,&windows->image,&text_event);
2342 switch (event.type)
2343 {
2344 case ButtonPress:
2345 {
2346 if (event.xbutton.window != windows->image.id)
2347 break;
2348 if (event.xbutton.button == Button2)
2349 {
2350 /*
2351 Request primary selection.
2352 */
2353 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2354 windows->image.id,CurrentTime);
2355 break;
2356 }
2357 break;
2358 }
2359 case Expose:
2360 {
2361 if (event.xexpose.count == 0)
2362 {
2363 XAnnotateInfo
2364 *text_info;
2365
2366 /*
2367 Refresh Image window.
2368 */
2369 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2370 text_info=annotate_info;
2371 while (text_info != (XAnnotateInfo *) NULL)
2372 {
2373 if (annotate_info->stencil == ForegroundStencil)
2374 (void) XDrawString(display,windows->image.id,annotate_context,
2375 text_info->x,text_info->y,text_info->text,
2376 (int) strlen(text_info->text));
2377 else
2378 (void) XDrawImageString(display,windows->image.id,
2379 annotate_context,text_info->x,text_info->y,text_info->text,
2380 (int) strlen(text_info->text));
2381 text_info=text_info->previous;
2382 }
2383 (void) XDrawString(display,windows->image.id,annotate_context,
2384 x,y,"_",1);
2385 }
2386 break;
2387 }
2388 case KeyPress:
2389 {
2390 int
2391 length;
2392
2393 if (event.xkey.window != windows->image.id)
2394 break;
2395 /*
2396 Respond to a user key press.
2397 */
2398 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2399 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2400 *(command+length)='\0';
2401 if (((event.xkey.state & ControlMask) != 0) ||
2402 ((event.xkey.state & Mod1Mask) != 0))
2403 state|=ModifierState;
2404 if ((state & ModifierState) != 0)
2405 switch ((int) key_symbol)
2406 {
2407 case XK_u:
2408 case XK_U:
2409 {
2410 key_symbol=DeleteCommand;
2411 break;
2412 }
2413 default:
2414 break;
2415 }
2416 switch ((int) key_symbol)
2417 {
2418 case XK_BackSpace:
2419 {
2420 /*
2421 Erase one character.
2422 */
2423 if (p == annotate_info->text)
2424 {
2425 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2426 break;
2427 else
2428 {
2429 /*
2430 Go to end of the previous line of text.
2431 */
2432 annotate_info=annotate_info->previous;
2433 p=annotate_info->text;
2434 x=annotate_info->x+annotate_info->width;
2435 y=annotate_info->y;
2436 if (annotate_info->width != 0)
2437 p+=strlen(annotate_info->text);
2438 break;
2439 }
2440 }
2441 p--;
2442 x-=XTextWidth(font_info,p,1);
2443 text_event.xexpose.x=x;
2444 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2445 XRefreshWindow(display,&windows->image,&text_event);
2446 break;
2447 }
2448 case XK_bracketleft:
2449 {
2450 key_symbol=XK_Escape;
2451 break;
2452 }
2453 case DeleteCommand:
2454 {
2455 /*
2456 Erase the entire line of text.
2457 */
2458 while (p != annotate_info->text)
2459 {
2460 p--;
2461 x-=XTextWidth(font_info,p,1);
2462 text_event.xexpose.x=x;
2463 XRefreshWindow(display,&windows->image,&text_event);
2464 }
2465 break;
2466 }
2467 case XK_Escape:
2468 case XK_F20:
2469 {
2470 /*
2471 Finished annotating.
2472 */
2473 annotate_info->width=(unsigned int) XTextWidth(font_info,
2474 annotate_info->text,(int) strlen(annotate_info->text));
2475 XRefreshWindow(display,&windows->image,&text_event);
2476 state|=ExitState;
2477 break;
2478 }
2479 default:
2480 {
2481 /*
2482 Draw a single character on the Image window.
2483 */
2484 if ((state & ModifierState) != 0)
2485 break;
2486 if (*command == '\0')
2487 break;
2488 *p=(*command);
2489 if (annotate_info->stencil == ForegroundStencil)
2490 (void) XDrawString(display,windows->image.id,annotate_context,
2491 x,y,p,1);
2492 else
2493 (void) XDrawImageString(display,windows->image.id,
2494 annotate_context,x,y,p,1);
2495 x+=XTextWidth(font_info,p,1);
2496 p++;
2497 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2498 break;
2499 }
2500 case XK_Return:
2501 case XK_KP_Enter:
2502 {
2503 /*
2504 Advance to the next line of text.
2505 */
2506 *p='\0';
2507 annotate_info->width=(unsigned int) XTextWidth(font_info,
2508 annotate_info->text,(int) strlen(annotate_info->text));
2509 if (annotate_info->next != (XAnnotateInfo *) NULL)
2510 {
2511 /*
2512 Line of text already exists.
2513 */
2514 annotate_info=annotate_info->next;
2515 x=annotate_info->x;
2516 y=annotate_info->y;
2517 p=annotate_info->text;
2518 break;
2519 }
2520 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2521 sizeof(*annotate_info->next));
2522 if (annotate_info->next == (XAnnotateInfo *) NULL)
2523 return(MagickFalse);
2524 *annotate_info->next=(*annotate_info);
2525 annotate_info->next->previous=annotate_info;
2526 annotate_info=annotate_info->next;
2527 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2528 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2529 sizeof(*annotate_info->text));
2530 if (annotate_info->text == (char *) NULL)
2531 return(MagickFalse);
2532 annotate_info->y+=annotate_info->height;
2533 if (annotate_info->y > (int) windows->image.height)
2534 annotate_info->y=(int) annotate_info->height;
2535 annotate_info->next=(XAnnotateInfo *) NULL;
2536 x=annotate_info->x;
2537 y=annotate_info->y;
2538 p=annotate_info->text;
2539 break;
2540 }
2541 }
2542 break;
2543 }
2544 case KeyRelease:
2545 {
2546 /*
2547 Respond to a user key release.
2548 */
2549 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2550 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2551 state&=(~ModifierState);
2552 break;
2553 }
2554 case SelectionNotify:
2555 {
2556 Atom
2557 type;
2558
2559 int
2560 format;
2561
2562 unsigned char
2563 *data;
2564
2565 unsigned long
2566 after,
2567 length;
2568
2569 /*
2570 Obtain response from primary selection.
2571 */
2572 if (event.xselection.property == (Atom) None)
2573 break;
2574 status=XGetWindowProperty(display,event.xselection.requestor,
2575 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2576 &type,&format,&length,&after,&data);
2577 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2578 (length == 0))
2579 break;
2580 /*
2581 Annotate Image window with primary selection.
2582 */
2583 for (i=0; i < (long) length; i++)
2584 {
2585 if ((char) data[i] != '\n')
2586 {
2587 /*
2588 Draw a single character on the Image window.
2589 */
2590 *p=(char) data[i];
2591 (void) XDrawString(display,windows->image.id,annotate_context,
2592 x,y,p,1);
2593 x+=XTextWidth(font_info,p,1);
2594 p++;
2595 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2596 continue;
2597 }
2598 /*
2599 Advance to the next line of text.
2600 */
2601 *p='\0';
2602 annotate_info->width=(unsigned int) XTextWidth(font_info,
2603 annotate_info->text,(int) strlen(annotate_info->text));
2604 if (annotate_info->next != (XAnnotateInfo *) NULL)
2605 {
2606 /*
2607 Line of text already exists.
2608 */
2609 annotate_info=annotate_info->next;
2610 x=annotate_info->x;
2611 y=annotate_info->y;
2612 p=annotate_info->text;
2613 continue;
2614 }
2615 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2616 sizeof(*annotate_info->next));
2617 if (annotate_info->next == (XAnnotateInfo *) NULL)
2618 return(MagickFalse);
2619 *annotate_info->next=(*annotate_info);
2620 annotate_info->next->previous=annotate_info;
2621 annotate_info=annotate_info->next;
2622 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2623 windows->image.width/MagickMax(font_info->min_bounds.width,1)+2UL,
2624 sizeof(*annotate_info->text));
2625 if (annotate_info->text == (char *) NULL)
2626 return(MagickFalse);
2627 annotate_info->y+=annotate_info->height;
2628 if (annotate_info->y > (int) windows->image.height)
2629 annotate_info->y=(int) annotate_info->height;
2630 annotate_info->next=(XAnnotateInfo *) NULL;
2631 x=annotate_info->x;
2632 y=annotate_info->y;
2633 p=annotate_info->text;
2634 }
2635 (void) XFree((void *) data);
2636 break;
2637 }
2638 default:
2639 break;
2640 }
2641 } while ((state & ExitState) == 0);
2642 (void) XFreeCursor(display,cursor);
2643 /*
2644 Annotation is relative to image configuration.
2645 */
2646 width=(unsigned int) image->columns;
2647 height=(unsigned int) image->rows;
2648 x=0;
2649 y=0;
2650 if (windows->image.crop_geometry != (char *) NULL)
2651 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2652 /*
2653 Initialize annotated image.
2654 */
2655 XSetCursorState(display,windows,MagickTrue);
2656 XCheckRefreshWindows(display,windows);
2657 while (annotate_info != (XAnnotateInfo *) NULL)
2658 {
2659 if (annotate_info->width == 0)
2660 {
2661 /*
2662 No text on this line-- go to the next line of text.
2663 */
2664 previous_info=annotate_info->previous;
2665 annotate_info->text=(char *)
2666 RelinquishMagickMemory(annotate_info->text);
2667 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2668 annotate_info=previous_info;
2669 continue;
2670 }
2671 /*
2672 Determine pixel index for box and pen color.
2673 */
2674 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2675 if (windows->pixel_info->colors != 0)
2676 for (i=0; i < (long) windows->pixel_info->colors; i++)
2677 if (windows->pixel_info->pixels[i] ==
2678 windows->pixel_info->pen_colors[box_id].pixel)
2679 {
2680 windows->pixel_info->box_index=(unsigned short) i;
2681 break;
2682 }
2683 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2684 if (windows->pixel_info->colors != 0)
2685 for (i=0; i < (long) windows->pixel_info->colors; i++)
2686 if (windows->pixel_info->pixels[i] ==
2687 windows->pixel_info->pen_colors[pen_id].pixel)
2688 {
2689 windows->pixel_info->pen_index=(unsigned short) i;
2690 break;
2691 }
2692 /*
2693 Define the annotate geometry string.
2694 */
2695 annotate_info->x=(int)
2696 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2697 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2698 windows->image.y)/windows->image.ximage->height;
2699 (void) FormatMagickString(annotate_info->geometry,MaxTextExtent,
2700 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2701 height*annotate_info->height/windows->image.ximage->height,
2702 annotate_info->x+x,annotate_info->y+y);
2703 /*
2704 Annotate image with text.
2705 */
2706 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2707 if (status == 0)
2708 return(MagickFalse);
2709 /*
2710 Free up memory.
2711 */
2712 previous_info=annotate_info->previous;
2713 annotate_info->text=DestroyString(annotate_info->text);
2714 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2715 annotate_info=previous_info;
2716 }
2717 (void) XSetForeground(display,annotate_context,
2718 windows->pixel_info->foreground_color.pixel);
2719 (void) XSetBackground(display,annotate_context,
2720 windows->pixel_info->background_color.pixel);
2721 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2722 XSetCursorState(display,windows,MagickFalse);
2723 (void) XFreeFont(display,font_info);
2724 /*
2725 Update image configuration.
2726 */
2727 XConfigureImageColormap(display,resource_info,windows,image);
2728 (void) XConfigureImage(display,resource_info,windows,image);
2729 return(MagickTrue);
2730}
2731
2732/*
2733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2734% %
2735% %
2736% %
2737+ X B a c k g r o u n d I m a g e %
2738% %
2739% %
2740% %
2741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2742%
2743% XBackgroundImage() displays the image in the background of a window.
2744%
2745% The format of the XBackgroundImage method is:
2746%
2747% MagickBooleanType XBackgroundImage(Display *display,
2748% XResourceInfo *resource_info,XWindows *windows,Image **image)
2749%
2750% A description of each parameter follows:
2751%
2752% o display: Specifies a connection to an X server; returned from
2753% XOpenDisplay.
2754%
2755% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2756%
2757% o windows: Specifies a pointer to a XWindows structure.
2758%
2759% o image: the image.
2760%
2761*/
2762static MagickBooleanType XBackgroundImage(Display *display,
2763 XResourceInfo *resource_info,XWindows *windows,Image **image)
2764{
2765#define BackgroundImageTag "Background/Image"
2766
2767 int
2768 status;
2769
2770 static char
2771 window_id[MaxTextExtent] = "root";
2772
2773 XResourceInfo
2774 background_resources;
2775
2776 /*
2777 Put image in background.
2778 */
2779 status=XDialogWidget(display,windows,"Background",
2780 "Enter window id (id 0x00 selects window with pointer):",window_id);
2781 if (*window_id == '\0')
2782 return(MagickFalse);
2783 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2784 XInfoWidget(display,windows,BackgroundImageTag);
2785 XSetCursorState(display,windows,MagickTrue);
2786 XCheckRefreshWindows(display,windows);
2787 background_resources=(*resource_info);
2788 background_resources.window_id=window_id;
2789 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2790 status=XDisplayBackgroundImage(display,&background_resources,*image);
2791 if (status != MagickFalse)
2792 XClientMessage(display,windows->image.id,windows->im_protocols,
2793 windows->im_retain_colors,CurrentTime);
2794 XSetCursorState(display,windows,MagickFalse);
2795 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2796 return(MagickTrue);
2797}
2798
2799/*
2800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801% %
2802% %
2803% %
2804+ X C h o p I m a g e %
2805% %
2806% %
2807% %
2808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809%
2810% XChopImage() chops the X image.
2811%
2812% The format of the XChopImage method is:
2813%
2814% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2815% XWindows *windows,Image **image)
2816%
2817% A description of each parameter follows:
2818%
2819% o display: Specifies a connection to an X server; returned from
2820% XOpenDisplay.
2821%
2822% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2823%
2824% o windows: Specifies a pointer to a XWindows structure.
2825%
2826% o image: the image.
2827%
2828*/
2829static MagickBooleanType XChopImage(Display *display,
2830 XResourceInfo *resource_info,XWindows *windows,Image **image)
2831{
2832 static const char
2833 *ChopMenu[] =
2834 {
2835 "Direction",
2836 "Help",
2837 "Dismiss",
2838 (char *) NULL
2839 };
2840
2841 static ModeType
2842 direction = HorizontalChopCommand;
2843
2844 static const ModeType
2845 ChopCommands[] =
2846 {
2847 ChopDirectionCommand,
2848 ChopHelpCommand,
2849 ChopDismissCommand
2850 },
2851 DirectionCommands[] =
2852 {
2853 HorizontalChopCommand,
2854 VerticalChopCommand
2855 };
2856
2857 char
2858 text[MaxTextExtent];
2859
2860 Image
2861 *chop_image;
2862
2863 int
2864 id,
2865 x,
2866 y;
2867
2868 MagickRealType
2869 scale_factor;
2870
2871 RectangleInfo
2872 chop_info;
2873
2874 unsigned int
2875 distance,
2876 height,
2877 width;
2878
2879 unsigned long
2880 state;
2881
2882 XEvent
2883 event;
2884
2885 XSegment
2886 segment_info;
2887
2888 /*
2889 Map Command widget.
2890 */
2891 (void) CloneString(&windows->command.name,"Chop");
2892 windows->command.data=1;
2893 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2894 (void) XMapRaised(display,windows->command.id);
2895 XClientMessage(display,windows->image.id,windows->im_protocols,
2896 windows->im_update_widget,CurrentTime);
2897 /*
2898 Track pointer until button 1 is pressed.
2899 */
2900 XQueryPosition(display,windows->image.id,&x,&y);
2901 (void) XSelectInput(display,windows->image.id,
2902 windows->image.attributes.event_mask | PointerMotionMask);
2903 state=DefaultState;
2904 do
2905 {
2906 if (windows->info.mapped != MagickFalse)
2907 {
2908 /*
2909 Display pointer position.
2910 */
2911 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
2912 x+windows->image.x,y+windows->image.y);
2913 XInfoWidget(display,windows,text);
2914 }
2915 /*
2916 Wait for next event.
2917 */
2918 XScreenEvent(display,windows,&event);
2919 if (event.xany.window == windows->command.id)
2920 {
2921 /*
2922 Select a command from the Command widget.
2923 */
2924 id=XCommandWidget(display,windows,ChopMenu,&event);
2925 if (id < 0)
2926 continue;
2927 switch (ChopCommands[id])
2928 {
2929 case ChopDirectionCommand:
2930 {
2931 char
2932 command[MaxTextExtent];
2933
2934 static const char
2935 *Directions[] =
2936 {
2937 "horizontal",
2938 "vertical",
2939 (char *) NULL,
2940 };
2941
2942 /*
2943 Select a command from the pop-up menu.
2944 */
2945 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2946 if (id >= 0)
2947 direction=DirectionCommands[id];
2948 break;
2949 }
2950 case ChopHelpCommand:
2951 {
2952 XTextViewWidget(display,resource_info,windows,MagickFalse,
2953 "Help Viewer - Image Chop",ImageChopHelp);
2954 break;
2955 }
2956 case ChopDismissCommand:
2957 {
2958 /*
2959 Prematurely exit.
2960 */
2961 state|=EscapeState;
2962 state|=ExitState;
2963 break;
2964 }
2965 default:
2966 break;
2967 }
2968 continue;
2969 }
2970 switch (event.type)
2971 {
2972 case ButtonPress:
2973 {
2974 if (event.xbutton.button != Button1)
2975 break;
2976 if (event.xbutton.window != windows->image.id)
2977 break;
2978 /*
2979 User has committed to start point of chopping line.
2980 */
2981 segment_info.x1=(short int) event.xbutton.x;
2982 segment_info.x2=(short int) event.xbutton.x;
2983 segment_info.y1=(short int) event.xbutton.y;
2984 segment_info.y2=(short int) event.xbutton.y;
2985 state|=ExitState;
2986 break;
2987 }
2988 case ButtonRelease:
2989 break;
2990 case Expose:
2991 break;
2992 case KeyPress:
2993 {
2994 char
2995 command[MaxTextExtent];
2996
2997 KeySym
2998 key_symbol;
2999
3000 if (event.xkey.window != windows->image.id)
3001 break;
3002 /*
3003 Respond to a user key press.
3004 */
3005 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3006 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3007 switch ((int) key_symbol)
3008 {
3009 case XK_Escape:
3010 case XK_F20:
3011 {
3012 /*
3013 Prematurely exit.
3014 */
3015 state|=EscapeState;
3016 state|=ExitState;
3017 break;
3018 }
3019 case XK_F1:
3020 case XK_Help:
3021 {
3022 (void) XSetFunction(display,windows->image.highlight_context,
3023 GXcopy);
3024 XTextViewWidget(display,resource_info,windows,MagickFalse,
3025 "Help Viewer - Image Chop",ImageChopHelp);
3026 (void) XSetFunction(display,windows->image.highlight_context,
3027 GXinvert);
3028 break;
3029 }
3030 default:
3031 {
3032 (void) XBell(display,0);
3033 break;
3034 }
3035 }
3036 break;
3037 }
3038 case MotionNotify:
3039 {
3040 /*
3041 Map and unmap Info widget as text cursor crosses its boundaries.
3042 */
3043 x=event.xmotion.x;
3044 y=event.xmotion.y;
3045 if (windows->info.mapped != MagickFalse)
3046 {
3047 if ((x < (int) (windows->info.x+windows->info.width)) &&
3048 (y < (int) (windows->info.y+windows->info.height)))
3049 (void) XWithdrawWindow(display,windows->info.id,
3050 windows->info.screen);
3051 }
3052 else
3053 if ((x > (int) (windows->info.x+windows->info.width)) ||
3054 (y > (int) (windows->info.y+windows->info.height)))
3055 (void) XMapWindow(display,windows->info.id);
3056 }
3057 }
3058 } while ((state & ExitState) == 0);
3059 (void) XSelectInput(display,windows->image.id,
3060 windows->image.attributes.event_mask);
3061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3062 if ((state & EscapeState) != 0)
3063 return(MagickTrue);
3064 /*
3065 Draw line as pointer moves until the mouse button is released.
3066 */
3067 chop_info.width=0;
3068 chop_info.height=0;
3069 chop_info.x=0;
3070 chop_info.y=0;
3071 distance=0;
3072 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3073 state=DefaultState;
3074 do
3075 {
3076 if (distance > 9)
3077 {
3078 /*
3079 Display info and draw chopping line.
3080 */
3081 if (windows->info.mapped == MagickFalse)
3082 (void) XMapWindow(display,windows->info.id);
3083 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
3084 chop_info.width,chop_info.height,chop_info.x,chop_info.y);
3085 XInfoWidget(display,windows,text);
3086 XHighlightLine(display,windows->image.id,
3087 windows->image.highlight_context,&segment_info);
3088 }
3089 else
3090 if (windows->info.mapped != MagickFalse)
3091 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3092 /*
3093 Wait for next event.
3094 */
3095 XScreenEvent(display,windows,&event);
3096 if (distance > 9)
3097 XHighlightLine(display,windows->image.id,
3098 windows->image.highlight_context,&segment_info);
3099 switch (event.type)
3100 {
3101 case ButtonPress:
3102 {
3103 segment_info.x2=(short int) event.xmotion.x;
3104 segment_info.y2=(short int) event.xmotion.y;
3105 break;
3106 }
3107 case ButtonRelease:
3108 {
3109 /*
3110 User has committed to chopping line.
3111 */
3112 segment_info.x2=(short int) event.xbutton.x;
3113 segment_info.y2=(short int) event.xbutton.y;
3114 state|=ExitState;
3115 break;
3116 }
3117 case Expose:
3118 break;
3119 case MotionNotify:
3120 {
3121 segment_info.x2=(short int) event.xmotion.x;
3122 segment_info.y2=(short int) event.xmotion.y;
3123 }
3124 default:
3125 break;
3126 }
3127 /*
3128 Check boundary conditions.
3129 */
3130 if (segment_info.x2 < 0)
3131 segment_info.x2=0;
3132 else
3133 if (segment_info.x2 > windows->image.ximage->width)
3134 segment_info.x2=windows->image.ximage->width;
3135 if (segment_info.y2 < 0)
3136 segment_info.y2=0;
3137 else
3138 if (segment_info.y2 > windows->image.ximage->height)
3139 segment_info.y2=windows->image.ximage->height;
3140 distance=(unsigned int)
3141 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3142 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3143 /*
3144 Compute chopping geometry.
3145 */
3146 if (direction == HorizontalChopCommand)
3147 {
3148 chop_info.width=(unsigned long) (segment_info.x2-segment_info.x1+1);
3149 chop_info.x=windows->image.x+segment_info.x1;
3150 chop_info.height=0;
3151 chop_info.y=0;
3152 if (segment_info.x1 > (int) segment_info.x2)
3153 {
3154 chop_info.width=(unsigned long) (segment_info.x1-segment_info.x2+1);
3155 chop_info.x=windows->image.x+segment_info.x2;
3156 }
3157 }
3158 else
3159 {
3160 chop_info.width=0;
3161 chop_info.height=(unsigned long) (segment_info.y2-segment_info.y1+1);
3162 chop_info.x=0;
3163 chop_info.y=windows->image.y+segment_info.y1;
3164 if (segment_info.y1 > segment_info.y2)
3165 {
3166 chop_info.height=(unsigned long)
3167 (segment_info.y1-segment_info.y2+1);
3168 chop_info.y=windows->image.y+segment_info.y2;
3169 }
3170 }
3171 } while ((state & ExitState) == 0);
3172 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3173 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3174 if (distance <= 9)
3175 return(MagickTrue);
3176 /*
3177 Image chopping is relative to image configuration.
3178 */
3179 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3180 XSetCursorState(display,windows,MagickTrue);
3181 XCheckRefreshWindows(display,windows);
3182 windows->image.window_changes.width=windows->image.ximage->width-
3183 (unsigned int) chop_info.width;
3184 windows->image.window_changes.height=windows->image.ximage->height-
3185 (unsigned int) chop_info.height;
3186 width=(unsigned int) (*image)->columns;
3187 height=(unsigned int) (*image)->rows;
3188 x=0;
3189 y=0;
3190 if (windows->image.crop_geometry != (char *) NULL)
3191 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3192 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3193 chop_info.x+=x;
3194 chop_info.x=(int) (scale_factor*chop_info.x+0.5);
3195 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3196 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3197 chop_info.y+=y;
3198 chop_info.y=(int) (scale_factor*chop_info.y+0.5);
3199 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3200 /*
3201 Chop image.
3202 */
3203 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3204 XSetCursorState(display,windows,MagickFalse);
3205 if (chop_image == (Image *) NULL)
3206 return(MagickFalse);
3207 *image=DestroyImage(*image);
3208 *image=chop_image;
3209 /*
3210 Update image configuration.
3211 */
3212 XConfigureImageColormap(display,resource_info,windows,*image);
3213 (void) XConfigureImage(display,resource_info,windows,*image);
3214 return(MagickTrue);
3215}
3216
3217/*
3218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3219% %
3220% %
3221% %
3222+ X C o l o r E d i t I m a g e %
3223% %
3224% %
3225% %
3226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3227%
3228% XColorEditImage() allows the user to interactively change the color of one
3229% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3230%
3231% The format of the XColorEditImage method is:
3232%
3233% MagickBooleanType XColorEditImage(Display *display,
3234% XResourceInfo *resource_info,XWindows *windows,Image **image)
3235%
3236% A description of each parameter follows:
3237%
3238% o display: Specifies a connection to an X server; returned from
3239% XOpenDisplay.
3240%
3241% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3242%
3243% o windows: Specifies a pointer to a XWindows structure.
3244%
3245% o image: the image; returned from ReadImage.
3246%
3247*/
3248
3249
3250static MagickBooleanType XColorEditImage(Display *display,
3251 XResourceInfo *resource_info,XWindows *windows,Image **image)
3252{
3253 static const char
3254 *ColorEditMenu[] =
3255 {
3256 "Method",
3257 "Pixel Color",
3258 "Border Color",
3259 "Fuzz",
3260 "Undo",
3261 "Help",
3262 "Dismiss",
3263 (char *) NULL
3264 };
3265
3266 static const ModeType
3267 ColorEditCommands[] =
3268 {
3269 ColorEditMethodCommand,
3270 ColorEditColorCommand,
3271 ColorEditBorderCommand,
3272 ColorEditFuzzCommand,
3273 ColorEditUndoCommand,
3274 ColorEditHelpCommand,
3275 ColorEditDismissCommand
3276 };
3277
3278 static PaintMethod
3279 method = PointMethod;
3280
3281 static unsigned int
3282 pen_id = 0;
3283
3284 static XColor
3285 border_color = { 0, 0, 0, 0, 0, 0 };
3286
3287 char
3288 command[MaxTextExtent],
3289 text[MaxTextExtent];
3290
3291 Cursor
3292 cursor;
3293
3294 ExceptionInfo
3295 *exception;
3296
3297 int
3298 entry,
3299 id,
3300 x,
3301 x_offset,
3302 y,
3303 y_offset;
3304
3305 register PixelPacket
3306 *q;
3307
3308 register long
3309 i;
3310
3311 unsigned int
3312 height,
3313 width;
3314
3315 unsigned long
3316 state;
3317
3318 XColor
3319 color;
3320
3321 XEvent
3322 event;
3323
3324 /*
3325 Map Command widget.
3326 */
3327 (void) CloneString(&windows->command.name,"Color Edit");
3328 windows->command.data=4;
3329 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3330 (void) XMapRaised(display,windows->command.id);
3331 XClientMessage(display,windows->image.id,windows->im_protocols,
3332 windows->im_update_widget,CurrentTime);
3333 /*
3334 Make cursor.
3335 */
3336 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3337 resource_info->background_color,resource_info->foreground_color);
3338 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3339 /*
3340 Track pointer until button 1 is pressed.
3341 */
3342 XQueryPosition(display,windows->image.id,&x,&y);
3343 (void) XSelectInput(display,windows->image.id,
3344 windows->image.attributes.event_mask | PointerMotionMask);
3345 state=DefaultState;
3346 do
3347 {
3348 if (windows->info.mapped != MagickFalse)
3349 {
3350 /*
3351 Display pointer position.
3352 */
3353 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
3354 x+windows->image.x,y+windows->image.y);
3355 XInfoWidget(display,windows,text);
3356 }
3357 /*
3358 Wait for next event.
3359 */
3360 XScreenEvent(display,windows,&event);
3361 if (event.xany.window == windows->command.id)
3362 {
3363 /*
3364 Select a command from the Command widget.
3365 */
3366 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3367 if (id < 0)
3368 {
3369 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3370 continue;
3371 }
3372 switch (ColorEditCommands[id])
3373 {
3374 case ColorEditMethodCommand:
3375 {
3376 char
3377 **methods;
3378
3379 /*
3380 Select a method from the pop-up menu.
3381 */
3382 methods=(char **) GetMagickOptions(MagickMethodOptions);
3383 if (methods == (char **) NULL)
3384 break;
3385 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3386 (const char **) methods,command);
3387 if (entry >= 0)
3388 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
3389 MagickFalse,methods[entry]);
3390 methods=DestroyStringList(methods);
3391 break;
3392 }
3393 case ColorEditColorCommand:
3394 {
3395 const char
3396 *ColorMenu[MaxNumberPens];
3397
3398 int
3399 pen_number;
3400
3401 /*
3402 Initialize menu selections.
3403 */
3404 for (i=0; i < (int) (MaxNumberPens-2); i++)
3405 ColorMenu[i]=resource_info->pen_colors[i];
3406 ColorMenu[MaxNumberPens-2]="Browser...";
3407 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3408 /*
3409 Select a pen color from the pop-up menu.
3410 */
3411 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3412 (const char **) ColorMenu,command);
3413 if (pen_number < 0)
3414 break;
3415 if (pen_number == (MaxNumberPens-2))
3416 {
3417 static char
3418 color_name[MaxTextExtent] = "gray";
3419
3420 /*
3421 Select a pen color from a dialog.
3422 */
3423 resource_info->pen_colors[pen_number]=color_name;
3424 XColorBrowserWidget(display,windows,"Select",color_name);
3425 if (*color_name == '\0')
3426 break;
3427 }
3428 /*
3429 Set pen color.
3430 */
3431 (void) XParseColor(display,windows->map_info->colormap,
3432 resource_info->pen_colors[pen_number],&color);
3433 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3434 (unsigned int) MaxColors,&color);
3435 windows->pixel_info->pen_colors[pen_number]=color;
3436 pen_id=(unsigned int) pen_number;
3437 break;
3438 }
3439 case ColorEditBorderCommand:
3440 {
3441 const char
3442 *ColorMenu[MaxNumberPens];
3443
3444 int
3445 pen_number;
3446
3447 /*
3448 Initialize menu selections.
3449 */
3450 for (i=0; i < (int) (MaxNumberPens-2); i++)
3451 ColorMenu[i]=resource_info->pen_colors[i];
3452 ColorMenu[MaxNumberPens-2]="Browser...";
3453 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3454 /*
3455 Select a pen color from the pop-up menu.
3456 */
3457 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3458 (const char **) ColorMenu,command);
3459 if (pen_number < 0)
3460 break;
3461 if (pen_number == (MaxNumberPens-2))
3462 {
3463 static char
3464 color_name[MaxTextExtent] = "gray";
3465
3466 /*
3467 Select a pen color from a dialog.
3468 */
3469 resource_info->pen_colors[pen_number]=color_name;
3470 XColorBrowserWidget(display,windows,"Select",color_name);
3471 if (*color_name == '\0')
3472 break;
3473 }
3474 /*
3475 Set border color.
3476 */
3477 (void) XParseColor(display,windows->map_info->colormap,
3478 resource_info->pen_colors[pen_number],&border_color);
3479 break;
3480 }
3481 case ColorEditFuzzCommand:
3482 {
3483 static char
3484 fuzz[MaxTextExtent];
3485
3486 static const char
3487 *FuzzMenu[] =
3488 {
3489 "0%",
3490 "2%",
3491 "5%",
3492 "10%",
3493 "15%",
3494 "Dialog...",
3495 (char *) NULL,
3496 };
3497
3498 /*
3499 Select a command from the pop-up menu.
3500 */
3501 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3502 command);
3503 if (entry < 0)
3504 break;
3505 if (entry != 5)
3506 {
cristyf2f27272009-12-17 14:48:46 +00003507 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*QuantumRange+
cristy3ed852e2009-09-05 21:47:34 +00003508 1.0);
3509 break;
3510 }
3511 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3512 (void) XDialogWidget(display,windows,"Ok",
3513 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3514 if (*fuzz == '\0')
3515 break;
3516 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00003517 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003518 break;
3519 }
3520 case ColorEditUndoCommand:
3521 {
3522 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3523 image);
3524 break;
3525 }
3526 case ColorEditHelpCommand:
3527 default:
3528 {
3529 XTextViewWidget(display,resource_info,windows,MagickFalse,
3530 "Help Viewer - Image Annotation",ImageColorEditHelp);
3531 break;
3532 }
3533 case ColorEditDismissCommand:
3534 {
3535 /*
3536 Prematurely exit.
3537 */
3538 state|=EscapeState;
3539 state|=ExitState;
3540 break;
3541 }
3542 }
3543 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3544 continue;
3545 }
3546 switch (event.type)
3547 {
3548 case ButtonPress:
3549 {
3550 if (event.xbutton.button != Button1)
3551 break;
3552 if ((event.xbutton.window != windows->image.id) &&
3553 (event.xbutton.window != windows->magnify.id))
3554 break;
3555 /*
3556 exit loop.
3557 */
3558 x=event.xbutton.x;
3559 y=event.xbutton.y;
3560 (void) XMagickCommand(display,resource_info,windows,
3561 SaveToUndoBufferCommand,image);
3562 state|=UpdateConfigurationState;
3563 break;
3564 }
3565 case ButtonRelease:
3566 {
3567 if (event.xbutton.button != Button1)
3568 break;
3569 if ((event.xbutton.window != windows->image.id) &&
3570 (event.xbutton.window != windows->magnify.id))
3571 break;
3572 /*
3573 Update colormap information.
3574 */
3575 x=event.xbutton.x;
3576 y=event.xbutton.y;
3577 XConfigureImageColormap(display,resource_info,windows,*image);
3578 (void) XConfigureImage(display,resource_info,windows,*image);
3579 XInfoWidget(display,windows,text);
3580 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3581 state&=(~UpdateConfigurationState);
3582 break;
3583 }
3584 case Expose:
3585 break;
3586 case KeyPress:
3587 {
3588 KeySym
3589 key_symbol;
3590
3591 if (event.xkey.window == windows->magnify.id)
3592 {
3593 Window
3594 window;
3595
3596 window=windows->magnify.id;
3597 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3598 }
3599 if (event.xkey.window != windows->image.id)
3600 break;
3601 /*
3602 Respond to a user key press.
3603 */
3604 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3605 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3606 switch ((int) key_symbol)
3607 {
3608 case XK_Escape:
3609 case XK_F20:
3610 {
3611 /*
3612 Prematurely exit.
3613 */
3614 state|=ExitState;
3615 break;
3616 }
3617 case XK_F1:
3618 case XK_Help:
3619 {
3620 XTextViewWidget(display,resource_info,windows,MagickFalse,
3621 "Help Viewer - Image Annotation",ImageColorEditHelp);
3622 break;
3623 }
3624 default:
3625 {
3626 (void) XBell(display,0);
3627 break;
3628 }
3629 }
3630 break;
3631 }
3632 case MotionNotify:
3633 {
3634 /*
3635 Map and unmap Info widget as cursor crosses its boundaries.
3636 */
3637 x=event.xmotion.x;
3638 y=event.xmotion.y;
3639 if (windows->info.mapped != MagickFalse)
3640 {
3641 if ((x < (int) (windows->info.x+windows->info.width)) &&
3642 (y < (int) (windows->info.y+windows->info.height)))
3643 (void) XWithdrawWindow(display,windows->info.id,
3644 windows->info.screen);
3645 }
3646 else
3647 if ((x > (int) (windows->info.x+windows->info.width)) ||
3648 (y > (int) (windows->info.y+windows->info.height)))
3649 (void) XMapWindow(display,windows->info.id);
3650 break;
3651 }
3652 default:
3653 break;
3654 }
3655 if (event.xany.window == windows->magnify.id)
3656 {
3657 x=windows->magnify.x-windows->image.x;
3658 y=windows->magnify.y-windows->image.y;
3659 }
3660 x_offset=x;
3661 y_offset=y;
3662 if ((state & UpdateConfigurationState) != 0)
3663 {
3664 int
3665 x,
3666 y;
3667
3668 /*
3669 Pixel edit is relative to image configuration.
3670 */
3671 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3672 MagickTrue);
3673 color=windows->pixel_info->pen_colors[pen_id];
3674 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3675 width=(unsigned int) (*image)->columns;
3676 height=(unsigned int) (*image)->rows;
3677 x=0;
3678 y=0;
3679 if (windows->image.crop_geometry != (char *) NULL)
3680 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3681 &width,&height);
3682 x_offset=(int)
3683 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3684 y_offset=(int)
3685 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3686 if ((x_offset < 0) || (y_offset < 0))
3687 continue;
3688 if ((x_offset >= (long) (*image)->columns) ||
3689 (y_offset >= (long) (*image)->rows))
3690 continue;
3691 exception=(&(*image)->exception);
3692 switch (method)
3693 {
3694 case PointMethod:
3695 default:
3696 {
3697 /*
3698 Update color information using point algorithm.
3699 */
3700 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3701 return(MagickFalse);
3702 q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
3703 if (q == (PixelPacket *) NULL)
3704 break;
3705 q->red=ScaleShortToQuantum(color.red);
3706 q->green=ScaleShortToQuantum(color.green);
3707 q->blue=ScaleShortToQuantum(color.blue);
3708 (void) SyncAuthenticPixels(*image,&(*image)->exception);
3709 break;
3710 }
3711 case ReplaceMethod:
3712 {
3713 PixelPacket
3714 target;
3715
3716 /*
3717 Update color information using replace algorithm.
3718 */
3719 (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
3720 &(*image)->exception);
3721 if ((*image)->storage_class == DirectClass)
3722 {
3723 for (y=0; y < (long) (*image)->rows; y++)
3724 {
cristyf154a4e2009-12-19 02:44:50 +00003725 q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,
3726 exception);
cristy3ed852e2009-09-05 21:47:34 +00003727 if (q == (PixelPacket *) NULL)
3728 break;
3729 for (x=0; x < (int) (*image)->columns; x++)
3730 {
3731 if (IsColorSimilar(*image,q,&target))
3732 {
3733 q->red=ScaleShortToQuantum(color.red);
3734 q->green=ScaleShortToQuantum(color.green);
3735 q->blue=ScaleShortToQuantum(color.blue);
3736 }
3737 q++;
3738 }
3739 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
3740 break;
3741 }
3742 }
3743 else
3744 {
3745 for (i=0; i < (int) (*image)->colors; i++)
3746 if (IsColorSimilar(*image,(*image)->colormap+i,&target))
3747 {
3748 (*image)->colormap[i].red=ScaleShortToQuantum(color.red);
3749 (*image)->colormap[i].green=ScaleShortToQuantum(
3750 color.green);
3751 (*image)->colormap[i].blue=ScaleShortToQuantum(
3752 color.blue);
3753 }
3754 (void) SyncImage(*image);
3755 }
3756 break;
3757 }
3758 case FloodfillMethod:
3759 case FillToBorderMethod:
3760 {
3761 DrawInfo
3762 *draw_info;
3763
3764 MagickPixelPacket
3765 target;
3766
3767 /*
3768 Update color information using floodfill algorithm.
3769 */
3770 (void) GetOneVirtualMagickPixel(*image,x_offset,y_offset,&target,
3771 exception);
3772 if (method == FillToBorderMethod)
3773 {
3774 target.red=(MagickRealType)
3775 ScaleShortToQuantum(border_color.red);
3776 target.green=(MagickRealType)
3777 ScaleShortToQuantum(border_color.green);
3778 target.blue=(MagickRealType)
3779 ScaleShortToQuantum(border_color.blue);
3780 }
3781 draw_info=CloneDrawInfo(resource_info->image_info,
3782 (DrawInfo *) NULL);
3783 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3784 &draw_info->fill,exception);
3785 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
3786 x_offset,y_offset,method == FloodfillMethod ? MagickFalse :
3787 MagickTrue);
3788 draw_info=DestroyDrawInfo(draw_info);
3789 break;
3790 }
3791 case ResetMethod:
3792 {
3793 /*
3794 Update color information using reset algorithm.
3795 */
3796 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3797 return(MagickFalse);
3798 for (y=0; y < (long) (*image)->rows; y++)
3799 {
3800 q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
3801 if (q == (PixelPacket *) NULL)
3802 break;
3803 for (x=0; x < (int) (*image)->columns; x++)
3804 {
3805 q->red=ScaleShortToQuantum(color.red);
3806 q->green=ScaleShortToQuantum(color.green);
3807 q->blue=ScaleShortToQuantum(color.blue);
3808 q++;
3809 }
3810 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
3811 break;
3812 }
3813 break;
3814 }
3815 }
3816 state&=(~UpdateConfigurationState);
3817 }
3818 } while ((state & ExitState) == 0);
3819 (void) XSelectInput(display,windows->image.id,
3820 windows->image.attributes.event_mask);
3821 XSetCursorState(display,windows,MagickFalse);
3822 (void) XFreeCursor(display,cursor);
3823 return(MagickTrue);
3824}
3825
3826/*
3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828% %
3829% %
3830% %
3831+ X C o m p o s i t e I m a g e %
3832% %
3833% %
3834% %
3835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3836%
3837% XCompositeImage() requests an image name from the user, reads the image and
3838% composites it with the X window image at a location the user chooses with
3839% the pointer.
3840%
3841% The format of the XCompositeImage method is:
3842%
3843% MagickBooleanType XCompositeImage(Display *display,
3844% XResourceInfo *resource_info,XWindows *windows,Image *image)
3845%
3846% A description of each parameter follows:
3847%
3848% o display: Specifies a connection to an X server; returned from
3849% XOpenDisplay.
3850%
3851% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3852%
3853% o windows: Specifies a pointer to a XWindows structure.
3854%
3855% o image: the image; returned from ReadImage.
3856%
3857*/
3858static MagickBooleanType XCompositeImage(Display *display,
3859 XResourceInfo *resource_info,XWindows *windows,Image *image)
3860{
3861 static char
3862 displacement_geometry[MaxTextExtent] = "30x30",
3863 filename[MaxTextExtent] = "\0";
3864
3865 static const char
3866 *CompositeMenu[] =
3867 {
3868 "Operators",
3869 "Dissolve",
3870 "Displace",
3871 "Help",
3872 "Dismiss",
3873 (char *) NULL
3874 };
3875
3876 static CompositeOperator
3877 compose = CopyCompositeOp;
3878
3879 static const ModeType
3880 CompositeCommands[] =
3881 {
3882 CompositeOperatorsCommand,
3883 CompositeDissolveCommand,
3884 CompositeDisplaceCommand,
3885 CompositeHelpCommand,
3886 CompositeDismissCommand
3887 };
3888
3889 char
3890 text[MaxTextExtent];
3891
3892 Cursor
3893 cursor;
3894
3895 Image
3896 *composite_image;
3897
3898 int
3899 entry,
3900 id,
3901 x,
3902 y;
3903
3904 MagickRealType
3905 blend,
3906 scale_factor;
3907
3908 RectangleInfo
3909 highlight_info,
3910 composite_info;
3911
3912 unsigned int
3913 height,
3914 width;
3915
3916 unsigned long
3917 state;
3918
3919 XEvent
3920 event;
3921
3922 /*
3923 Request image file name from user.
3924 */
3925 XFileBrowserWidget(display,windows,"Composite",filename);
3926 if (*filename == '\0')
3927 return(MagickTrue);
3928 /*
3929 Read image.
3930 */
3931 XSetCursorState(display,windows,MagickTrue);
3932 XCheckRefreshWindows(display,windows);
3933 (void) CopyMagickString(resource_info->image_info->filename,filename,
3934 MaxTextExtent);
3935 composite_image=ReadImage(resource_info->image_info,&image->exception);
3936 CatchException(&image->exception);
3937 XSetCursorState(display,windows,MagickFalse);
3938 if (composite_image == (Image *) NULL)
3939 return(MagickFalse);
3940 /*
3941 Map Command widget.
3942 */
3943 (void) CloneString(&windows->command.name,"Composite");
3944 windows->command.data=1;
3945 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3946 (void) XMapRaised(display,windows->command.id);
3947 XClientMessage(display,windows->image.id,windows->im_protocols,
3948 windows->im_update_widget,CurrentTime);
3949 /*
3950 Track pointer until button 1 is pressed.
3951 */
3952 XQueryPosition(display,windows->image.id,&x,&y);
3953 (void) XSelectInput(display,windows->image.id,
3954 windows->image.attributes.event_mask | PointerMotionMask);
3955 composite_info.x=windows->image.x+x;
3956 composite_info.y=windows->image.y+y;
3957 composite_info.width=0;
3958 composite_info.height=0;
3959 cursor=XCreateFontCursor(display,XC_ul_angle);
3960 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3961 blend=0.0;
3962 state=DefaultState;
3963 do
3964 {
3965 if (windows->info.mapped != MagickFalse)
3966 {
3967 /*
3968 Display pointer position.
3969 */
3970 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
3971 composite_info.x,composite_info.y);
3972 XInfoWidget(display,windows,text);
3973 }
3974 highlight_info=composite_info;
3975 highlight_info.x=composite_info.x-windows->image.x;
3976 highlight_info.y=composite_info.y-windows->image.y;
3977 XHighlightRectangle(display,windows->image.id,
3978 windows->image.highlight_context,&highlight_info);
3979 /*
3980 Wait for next event.
3981 */
3982 XScreenEvent(display,windows,&event);
3983 XHighlightRectangle(display,windows->image.id,
3984 windows->image.highlight_context,&highlight_info);
3985 if (event.xany.window == windows->command.id)
3986 {
3987 /*
3988 Select a command from the Command widget.
3989 */
3990 id=XCommandWidget(display,windows,CompositeMenu,&event);
3991 if (id < 0)
3992 continue;
3993 switch (CompositeCommands[id])
3994 {
3995 case CompositeOperatorsCommand:
3996 {
3997 char
3998 command[MaxTextExtent],
3999 **operators;
4000
4001 /*
4002 Select a command from the pop-up menu.
4003 */
4004 operators=GetMagickOptions(MagickComposeOptions);
4005 if (operators == (char **) NULL)
4006 break;
4007 entry=XMenuWidget(display,windows,CompositeMenu[id],
4008 (const char **) operators,command);
4009 if (entry >= 0)
4010 compose=(CompositeOperator) ParseMagickOption(
4011 MagickComposeOptions,MagickFalse,operators[entry]);
4012 operators=DestroyStringList(operators);
4013 break;
4014 }
4015 case CompositeDissolveCommand:
4016 {
4017 static char
4018 factor[MaxTextExtent] = "20.0";
4019
4020 /*
4021 Dissolve the two images a given percent.
4022 */
4023 (void) XSetFunction(display,windows->image.highlight_context,
4024 GXcopy);
4025 (void) XDialogWidget(display,windows,"Dissolve",
4026 "Enter the blend factor (0.0 - 99.9%):",factor);
4027 (void) XSetFunction(display,windows->image.highlight_context,
4028 GXinvert);
4029 if (*factor == '\0')
4030 break;
cristyf2f27272009-12-17 14:48:46 +00004031 blend=StringToDouble(factor);
cristy3ed852e2009-09-05 21:47:34 +00004032 compose=DissolveCompositeOp;
4033 break;
4034 }
4035 case CompositeDisplaceCommand:
4036 {
4037 /*
4038 Get horizontal and vertical scale displacement geometry.
4039 */
4040 (void) XSetFunction(display,windows->image.highlight_context,
4041 GXcopy);
4042 (void) XDialogWidget(display,windows,"Displace",
4043 "Enter the horizontal and vertical scale:",displacement_geometry);
4044 (void) XSetFunction(display,windows->image.highlight_context,
4045 GXinvert);
4046 if (*displacement_geometry == '\0')
4047 break;
4048 compose=DisplaceCompositeOp;
4049 break;
4050 }
4051 case CompositeHelpCommand:
4052 {
4053 (void) XSetFunction(display,windows->image.highlight_context,
4054 GXcopy);
4055 XTextViewWidget(display,resource_info,windows,MagickFalse,
4056 "Help Viewer - Image Composite",ImageCompositeHelp);
4057 (void) XSetFunction(display,windows->image.highlight_context,
4058 GXinvert);
4059 break;
4060 }
4061 case CompositeDismissCommand:
4062 {
4063 /*
4064 Prematurely exit.
4065 */
4066 state|=EscapeState;
4067 state|=ExitState;
4068 break;
4069 }
4070 default:
4071 break;
4072 }
4073 continue;
4074 }
4075 switch (event.type)
4076 {
4077 case ButtonPress:
4078 {
4079 if (image->debug != MagickFalse)
4080 (void) LogMagickEvent(X11Event,GetMagickModule(),
4081 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4082 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4083 if (event.xbutton.button != Button1)
4084 break;
4085 if (event.xbutton.window != windows->image.id)
4086 break;
4087 /*
4088 Change cursor.
4089 */
4090 composite_info.width=composite_image->columns;
4091 composite_info.height=composite_image->rows;
4092 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4093 composite_info.x=windows->image.x+event.xbutton.x;
4094 composite_info.y=windows->image.y+event.xbutton.y;
4095 break;
4096 }
4097 case ButtonRelease:
4098 {
4099 if (image->debug != MagickFalse)
4100 (void) LogMagickEvent(X11Event,GetMagickModule(),
4101 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4102 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4103 if (event.xbutton.button != Button1)
4104 break;
4105 if (event.xbutton.window != windows->image.id)
4106 break;
4107 if ((composite_info.width != 0) && (composite_info.height != 0))
4108 {
4109 /*
4110 User has selected the location of the composite image.
4111 */
4112 composite_info.x=windows->image.x+event.xbutton.x;
4113 composite_info.y=windows->image.y+event.xbutton.y;
4114 state|=ExitState;
4115 }
4116 break;
4117 }
4118 case Expose:
4119 break;
4120 case KeyPress:
4121 {
4122 char
4123 command[MaxTextExtent];
4124
4125 KeySym
4126 key_symbol;
4127
4128 int
4129 length;
4130
4131 if (event.xkey.window != windows->image.id)
4132 break;
4133 /*
4134 Respond to a user key press.
4135 */
4136 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4137 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4138 *(command+length)='\0';
4139 if (image->debug != MagickFalse)
4140 (void) LogMagickEvent(X11Event,GetMagickModule(),
4141 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4142 switch ((int) key_symbol)
4143 {
4144 case XK_Escape:
4145 case XK_F20:
4146 {
4147 /*
4148 Prematurely exit.
4149 */
4150 composite_image=DestroyImage(composite_image);
4151 state|=EscapeState;
4152 state|=ExitState;
4153 break;
4154 }
4155 case XK_F1:
4156 case XK_Help:
4157 {
4158 (void) XSetFunction(display,windows->image.highlight_context,
4159 GXcopy);
4160 XTextViewWidget(display,resource_info,windows,MagickFalse,
4161 "Help Viewer - Image Composite",ImageCompositeHelp);
4162 (void) XSetFunction(display,windows->image.highlight_context,
4163 GXinvert);
4164 break;
4165 }
4166 default:
4167 {
4168 (void) XBell(display,0);
4169 break;
4170 }
4171 }
4172 break;
4173 }
4174 case MotionNotify:
4175 {
4176 /*
4177 Map and unmap Info widget as text cursor crosses its boundaries.
4178 */
4179 x=event.xmotion.x;
4180 y=event.xmotion.y;
4181 if (windows->info.mapped != MagickFalse)
4182 {
4183 if ((x < (int) (windows->info.x+windows->info.width)) &&
4184 (y < (int) (windows->info.y+windows->info.height)))
4185 (void) XWithdrawWindow(display,windows->info.id,
4186 windows->info.screen);
4187 }
4188 else
4189 if ((x > (int) (windows->info.x+windows->info.width)) ||
4190 (y > (int) (windows->info.y+windows->info.height)))
4191 (void) XMapWindow(display,windows->info.id);
4192 composite_info.x=windows->image.x+x;
4193 composite_info.y=windows->image.y+y;
4194 break;
4195 }
4196 default:
4197 {
4198 if (image->debug != MagickFalse)
4199 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4200 event.type);
4201 break;
4202 }
4203 }
4204 } while ((state & ExitState) == 0);
4205 (void) XSelectInput(display,windows->image.id,
4206 windows->image.attributes.event_mask);
4207 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4208 XSetCursorState(display,windows,MagickFalse);
4209 (void) XFreeCursor(display,cursor);
4210 if ((state & EscapeState) != 0)
4211 return(MagickTrue);
4212 /*
4213 Image compositing is relative to image configuration.
4214 */
4215 XSetCursorState(display,windows,MagickTrue);
4216 XCheckRefreshWindows(display,windows);
4217 width=(unsigned int) image->columns;
4218 height=(unsigned int) image->rows;
4219 x=0;
4220 y=0;
4221 if (windows->image.crop_geometry != (char *) NULL)
4222 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4223 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4224 composite_info.x+=x;
4225 composite_info.x=(int) (scale_factor*composite_info.x+0.5);
4226 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4227 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4228 composite_info.y+=y;
4229 composite_info.y=(int) (scale_factor*composite_info.y+0.5);
4230 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4231 if ((composite_info.width != composite_image->columns) ||
4232 (composite_info.height != composite_image->rows))
4233 {
4234 Image
4235 *resize_image;
4236
4237 /*
4238 Scale composite image.
4239 */
4240 resize_image=ZoomImage(composite_image,composite_info.width,
4241 composite_info.height,&image->exception);
4242 composite_image=DestroyImage(composite_image);
4243 if (resize_image == (Image *) NULL)
4244 {
4245 XSetCursorState(display,windows,MagickFalse);
4246 return(MagickFalse);
4247 }
4248 composite_image=resize_image;
4249 }
4250 if (compose == DisplaceCompositeOp)
4251 (void) SetImageArtifact(composite_image,"compose:args",
4252 displacement_geometry);
4253 if (blend != 0.0)
4254 {
4255 ExceptionInfo
4256 *exception;
4257
4258 int
4259 y;
4260
4261 Quantum
4262 opacity;
4263
4264 register int
4265 x;
4266
4267 register PixelPacket
4268 *q;
4269
4270 /*
4271 Create mattes for blending.
4272 */
4273 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
4274 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
4275 ((long) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
4276 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4277 return(MagickFalse);
4278 image->matte=MagickTrue;
4279 exception=(&image->exception);
4280 for (y=0; y < (long) image->rows; y++)
4281 {
4282 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4283 if (q == (PixelPacket *) NULL)
4284 break;
4285 for (x=0; x < (int) image->columns; x++)
4286 {
4287 q->opacity=opacity;
4288 q++;
4289 }
4290 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4291 break;
4292 }
4293 }
4294 /*
4295 Composite image with X Image window.
4296 */
4297 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4298 composite_info.y);
4299 composite_image=DestroyImage(composite_image);
4300 XSetCursorState(display,windows,MagickFalse);
4301 /*
4302 Update image configuration.
4303 */
4304 XConfigureImageColormap(display,resource_info,windows,image);
4305 (void) XConfigureImage(display,resource_info,windows,image);
4306 return(MagickTrue);
4307}
4308
4309/*
4310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311% %
4312% %
4313% %
4314+ X C o n f i g u r e I m a g e %
4315% %
4316% %
4317% %
4318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4319%
4320% XConfigureImage() creates a new X image. It also notifies the window
4321% manager of the new image size and configures the transient widows.
4322%
4323% The format of the XConfigureImage method is:
4324%
4325% MagickBooleanType XConfigureImage(Display *display,
4326% XResourceInfo *resource_info,XWindows *windows,Image *image)
4327%
4328% A description of each parameter follows:
4329%
4330% o display: Specifies a connection to an X server; returned from
4331% XOpenDisplay.
4332%
4333% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4334%
4335% o windows: Specifies a pointer to a XWindows structure.
4336%
4337% o image: the image.
4338%
4339%
4340*/
4341static MagickBooleanType XConfigureImage(Display *display,
4342 XResourceInfo *resource_info,XWindows *windows,Image *image)
4343{
4344 char
4345 geometry[MaxTextExtent];
4346
4347 long
4348 x,
4349 y;
4350
4351 MagickStatusType
4352 status;
4353
4354 unsigned long
4355 mask,
4356 height,
4357 width;
4358
4359 XSizeHints
4360 *size_hints;
4361
4362 XWindowChanges
4363 window_changes;
4364
4365 /*
4366 Dismiss if window dimensions are zero.
4367 */
4368 width=(unsigned int) windows->image.window_changes.width;
4369 height=(unsigned int) windows->image.window_changes.height;
4370 if (image->debug != MagickFalse)
4371 (void) LogMagickEvent(X11Event,GetMagickModule(),
4372 "Configure Image: %dx%d=>%lux%lu",windows->image.ximage->width,
4373 windows->image.ximage->height,width,height);
4374 if ((width*height) == 0)
4375 return(MagickTrue);
4376 x=0;
4377 y=0;
4378 /*
4379 Resize image to fit Image window dimensions.
4380 */
4381 XSetCursorState(display,windows,MagickTrue);
4382 (void) XFlush(display);
4383 if (((int) width != windows->image.ximage->width) ||
4384 ((int) height != windows->image.ximage->height))
4385 image->taint=MagickTrue;
4386 windows->magnify.x=(int)
4387 width*windows->magnify.x/windows->image.ximage->width;
4388 windows->magnify.y=(int)
4389 height*windows->magnify.y/windows->image.ximage->height;
4390 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4391 windows->image.y=(int)
4392 (height*windows->image.y/windows->image.ximage->height);
4393 status=XMakeImage(display,resource_info,&windows->image,image,
4394 (unsigned int) width,(unsigned int) height);
4395 if (status == MagickFalse)
4396 XNoticeWidget(display,windows,"Unable to configure X image:",
4397 windows->image.name);
4398 /*
4399 Notify window manager of the new configuration.
4400 */
4401 if (resource_info->image_geometry != (char *) NULL)
4402 (void) FormatMagickString(geometry,MaxTextExtent,"%s>!",
4403 resource_info->image_geometry);
4404 else
4405 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4406 XDisplayWidth(display,windows->image.screen),
4407 XDisplayHeight(display,windows->image.screen));
4408 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4409 window_changes.width=(int) width;
4410 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4411 window_changes.width=XDisplayWidth(display,windows->image.screen);
4412 window_changes.height=(int) height;
4413 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4414 window_changes.height=XDisplayHeight(display,windows->image.screen);
4415 mask=(unsigned long) (CWWidth | CWHeight);
4416 if (resource_info->backdrop)
4417 {
4418 mask|=CWX | CWY;
4419 window_changes.x=(int)
4420 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4421 window_changes.y=(int)
4422 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4423 }
4424 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4425 (unsigned int) mask,&window_changes);
4426 (void) XClearWindow(display,windows->image.id);
4427 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4428 /*
4429 Update Magnify window configuration.
4430 */
4431 if (windows->magnify.mapped != MagickFalse)
4432 XMakeMagnifyImage(display,windows);
4433 windows->pan.crop_geometry=windows->image.crop_geometry;
4434 XBestIconSize(display,&windows->pan,image);
4435 while (((windows->pan.width << 1) < MaxIconSize) &&
4436 ((windows->pan.height << 1) < MaxIconSize))
4437 {
4438 windows->pan.width<<=1;
4439 windows->pan.height<<=1;
4440 }
4441 if (windows->pan.geometry != (char *) NULL)
4442 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4443 &windows->pan.width,&windows->pan.height);
4444 window_changes.width=(int) windows->pan.width;
4445 window_changes.height=(int) windows->pan.height;
4446 size_hints=XAllocSizeHints();
4447 if (size_hints != (XSizeHints *) NULL)
4448 {
4449 /*
4450 Set new size hints.
4451 */
4452 size_hints->flags=PSize | PMinSize | PMaxSize;
4453 size_hints->width=window_changes.width;
4454 size_hints->height=window_changes.height;
4455 size_hints->min_width=size_hints->width;
4456 size_hints->min_height=size_hints->height;
4457 size_hints->max_width=size_hints->width;
4458 size_hints->max_height=size_hints->height;
4459 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4460 (void) XFree((void *) size_hints);
4461 }
4462 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4463 (unsigned int) (CWWidth | CWHeight),&window_changes);
4464 /*
4465 Update icon window configuration.
4466 */
4467 windows->icon.crop_geometry=windows->image.crop_geometry;
4468 XBestIconSize(display,&windows->icon,image);
4469 window_changes.width=(int) windows->icon.width;
4470 window_changes.height=(int) windows->icon.height;
4471 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4472 (unsigned int) (CWWidth | CWHeight),&window_changes);
4473 XSetCursorState(display,windows,MagickFalse);
4474 return(status != 0 ? MagickTrue : MagickFalse);
4475}
4476
4477/*
4478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4479% %
4480% %
4481% %
4482+ X C r o p I m a g e %
4483% %
4484% %
4485% %
4486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487%
4488% XCropImage() allows the user to select a region of the image and crop, copy,
4489% or cut it. For copy or cut, the image can subsequently be composited onto
4490% the image with XPasteImage.
4491%
4492% The format of the XCropImage method is:
4493%
4494% MagickBooleanType XCropImage(Display *display,
4495% XResourceInfo *resource_info,XWindows *windows,Image *image,
4496% const ClipboardMode mode)
4497%
4498% A description of each parameter follows:
4499%
4500% o display: Specifies a connection to an X server; returned from
4501% XOpenDisplay.
4502%
4503% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4504%
4505% o windows: Specifies a pointer to a XWindows structure.
4506%
4507% o image: the image; returned from ReadImage.
4508%
4509% o mode: This unsigned value specified whether the image should be
4510% cropped, copied, or cut.
4511%
4512*/
4513static MagickBooleanType XCropImage(Display *display,
4514 XResourceInfo *resource_info,XWindows *windows,Image *image,
4515 const ClipboardMode mode)
4516{
4517 static const char
4518 *CropModeMenu[] =
4519 {
4520 "Help",
4521 "Dismiss",
4522 (char *) NULL
4523 },
4524 *RectifyModeMenu[] =
4525 {
4526 "Crop",
4527 "Help",
4528 "Dismiss",
4529 (char *) NULL
4530 };
4531
4532 static const ModeType
4533 CropCommands[] =
4534 {
4535 CropHelpCommand,
4536 CropDismissCommand
4537 },
4538 RectifyCommands[] =
4539 {
4540 RectifyCopyCommand,
4541 RectifyHelpCommand,
4542 RectifyDismissCommand
4543 };
4544
4545 char
4546 command[MaxTextExtent],
4547 text[MaxTextExtent];
4548
4549 Cursor
4550 cursor;
4551
4552 ExceptionInfo
4553 *exception;
4554
4555 int
4556 id,
4557 x,
4558 y;
4559
4560 KeySym
4561 key_symbol;
4562
4563 Image
4564 *crop_image;
4565
4566 MagickRealType
4567 scale_factor;
4568
4569 RectangleInfo
4570 crop_info,
4571 highlight_info;
4572
4573 register PixelPacket
4574 *q;
4575
4576 unsigned int
4577 height,
4578 width;
4579
4580 unsigned long
4581 state;
4582
4583 XEvent
4584 event;
4585
4586 /*
4587 Map Command widget.
4588 */
4589 switch (mode)
4590 {
4591 case CopyMode:
4592 {
4593 (void) CloneString(&windows->command.name,"Copy");
4594 break;
4595 }
4596 case CropMode:
4597 {
4598 (void) CloneString(&windows->command.name,"Crop");
4599 break;
4600 }
4601 case CutMode:
4602 {
4603 (void) CloneString(&windows->command.name,"Cut");
4604 break;
4605 }
4606 }
4607 RectifyModeMenu[0]=windows->command.name;
4608 windows->command.data=0;
4609 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4610 (void) XMapRaised(display,windows->command.id);
4611 XClientMessage(display,windows->image.id,windows->im_protocols,
4612 windows->im_update_widget,CurrentTime);
4613 /*
4614 Track pointer until button 1 is pressed.
4615 */
4616 XQueryPosition(display,windows->image.id,&x,&y);
4617 (void) XSelectInput(display,windows->image.id,
4618 windows->image.attributes.event_mask | PointerMotionMask);
4619 crop_info.x=windows->image.x+x;
4620 crop_info.y=windows->image.y+y;
4621 crop_info.width=0;
4622 crop_info.height=0;
4623 cursor=XCreateFontCursor(display,XC_fleur);
4624 state=DefaultState;
4625 do
4626 {
4627 if (windows->info.mapped != MagickFalse)
4628 {
4629 /*
4630 Display pointer position.
4631 */
4632 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
4633 crop_info.x,crop_info.y);
4634 XInfoWidget(display,windows,text);
4635 }
4636 /*
4637 Wait for next event.
4638 */
4639 XScreenEvent(display,windows,&event);
4640 if (event.xany.window == windows->command.id)
4641 {
4642 /*
4643 Select a command from the Command widget.
4644 */
4645 id=XCommandWidget(display,windows,CropModeMenu,&event);
4646 if (id < 0)
4647 continue;
4648 switch (CropCommands[id])
4649 {
4650 case CropHelpCommand:
4651 {
4652 switch (mode)
4653 {
4654 case CopyMode:
4655 {
4656 XTextViewWidget(display,resource_info,windows,MagickFalse,
4657 "Help Viewer - Image Copy",ImageCopyHelp);
4658 break;
4659 }
4660 case CropMode:
4661 {
4662 XTextViewWidget(display,resource_info,windows,MagickFalse,
4663 "Help Viewer - Image Crop",ImageCropHelp);
4664 break;
4665 }
4666 case CutMode:
4667 {
4668 XTextViewWidget(display,resource_info,windows,MagickFalse,
4669 "Help Viewer - Image Cut",ImageCutHelp);
4670 break;
4671 }
4672 }
4673 break;
4674 }
4675 case CropDismissCommand:
4676 {
4677 /*
4678 Prematurely exit.
4679 */
4680 state|=EscapeState;
4681 state|=ExitState;
4682 break;
4683 }
4684 default:
4685 break;
4686 }
4687 continue;
4688 }
4689 switch (event.type)
4690 {
4691 case ButtonPress:
4692 {
4693 if (event.xbutton.button != Button1)
4694 break;
4695 if (event.xbutton.window != windows->image.id)
4696 break;
4697 /*
4698 Note first corner of cropping rectangle-- exit loop.
4699 */
4700 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4701 crop_info.x=windows->image.x+event.xbutton.x;
4702 crop_info.y=windows->image.y+event.xbutton.y;
4703 state|=ExitState;
4704 break;
4705 }
4706 case ButtonRelease:
4707 break;
4708 case Expose:
4709 break;
4710 case KeyPress:
4711 {
4712 if (event.xkey.window != windows->image.id)
4713 break;
4714 /*
4715 Respond to a user key press.
4716 */
4717 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4718 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4719 switch ((int) key_symbol)
4720 {
4721 case XK_Escape:
4722 case XK_F20:
4723 {
4724 /*
4725 Prematurely exit.
4726 */
4727 state|=EscapeState;
4728 state|=ExitState;
4729 break;
4730 }
4731 case XK_F1:
4732 case XK_Help:
4733 {
4734 switch (mode)
4735 {
4736 case CopyMode:
4737 {
4738 XTextViewWidget(display,resource_info,windows,MagickFalse,
4739 "Help Viewer - Image Copy",ImageCopyHelp);
4740 break;
4741 }
4742 case CropMode:
4743 {
4744 XTextViewWidget(display,resource_info,windows,MagickFalse,
4745 "Help Viewer - Image Crop",ImageCropHelp);
4746 break;
4747 }
4748 case CutMode:
4749 {
4750 XTextViewWidget(display,resource_info,windows,MagickFalse,
4751 "Help Viewer - Image Cut",ImageCutHelp);
4752 break;
4753 }
4754 }
4755 break;
4756 }
4757 default:
4758 {
4759 (void) XBell(display,0);
4760 break;
4761 }
4762 }
4763 break;
4764 }
4765 case MotionNotify:
4766 {
4767 if (event.xmotion.window != windows->image.id)
4768 break;
4769 /*
4770 Map and unmap Info widget as text cursor crosses its boundaries.
4771 */
4772 x=event.xmotion.x;
4773 y=event.xmotion.y;
4774 if (windows->info.mapped != MagickFalse)
4775 {
4776 if ((x < (int) (windows->info.x+windows->info.width)) &&
4777 (y < (int) (windows->info.y+windows->info.height)))
4778 (void) XWithdrawWindow(display,windows->info.id,
4779 windows->info.screen);
4780 }
4781 else
4782 if ((x > (int) (windows->info.x+windows->info.width)) ||
4783 (y > (int) (windows->info.y+windows->info.height)))
4784 (void) XMapWindow(display,windows->info.id);
4785 crop_info.x=windows->image.x+x;
4786 crop_info.y=windows->image.y+y;
4787 break;
4788 }
4789 default:
4790 break;
4791 }
4792 } while ((state & ExitState) == 0);
4793 (void) XSelectInput(display,windows->image.id,
4794 windows->image.attributes.event_mask);
4795 if ((state & EscapeState) != 0)
4796 {
4797 /*
4798 User want to exit without cropping.
4799 */
4800 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4801 (void) XFreeCursor(display,cursor);
4802 return(MagickTrue);
4803 }
4804 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4805 do
4806 {
4807 /*
4808 Size rectangle as pointer moves until the mouse button is released.
4809 */
4810 x=(int) crop_info.x;
4811 y=(int) crop_info.y;
4812 crop_info.width=0;
4813 crop_info.height=0;
4814 state=DefaultState;
4815 do
4816 {
4817 highlight_info=crop_info;
4818 highlight_info.x=crop_info.x-windows->image.x;
4819 highlight_info.y=crop_info.y-windows->image.y;
4820 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4821 {
4822 /*
4823 Display info and draw cropping rectangle.
4824 */
4825 if (windows->info.mapped == MagickFalse)
4826 (void) XMapWindow(display,windows->info.id);
4827 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
4828 crop_info.width,crop_info.height,crop_info.x,crop_info.y);
4829 XInfoWidget(display,windows,text);
4830 XHighlightRectangle(display,windows->image.id,
4831 windows->image.highlight_context,&highlight_info);
4832 }
4833 else
4834 if (windows->info.mapped != MagickFalse)
4835 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4836 /*
4837 Wait for next event.
4838 */
4839 XScreenEvent(display,windows,&event);
4840 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4841 XHighlightRectangle(display,windows->image.id,
4842 windows->image.highlight_context,&highlight_info);
4843 switch (event.type)
4844 {
4845 case ButtonPress:
4846 {
4847 crop_info.x=windows->image.x+event.xbutton.x;
4848 crop_info.y=windows->image.y+event.xbutton.y;
4849 break;
4850 }
4851 case ButtonRelease:
4852 {
4853 /*
4854 User has committed to cropping rectangle.
4855 */
4856 crop_info.x=windows->image.x+event.xbutton.x;
4857 crop_info.y=windows->image.y+event.xbutton.y;
4858 XSetCursorState(display,windows,MagickFalse);
4859 state|=ExitState;
4860 windows->command.data=0;
4861 (void) XCommandWidget(display,windows,RectifyModeMenu,
4862 (XEvent *) NULL);
4863 break;
4864 }
4865 case Expose:
4866 break;
4867 case MotionNotify:
4868 {
4869 crop_info.x=windows->image.x+event.xmotion.x;
4870 crop_info.y=windows->image.y+event.xmotion.y;
4871 }
4872 default:
4873 break;
4874 }
4875 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4876 ((state & ExitState) != 0))
4877 {
4878 /*
4879 Check boundary conditions.
4880 */
4881 if (crop_info.x < 0)
4882 crop_info.x=0;
4883 else
4884 if (crop_info.x > (int) windows->image.ximage->width)
4885 crop_info.x=windows->image.ximage->width;
4886 if ((int) crop_info.x < x)
4887 crop_info.width=(unsigned int) (x-crop_info.x);
4888 else
4889 {
4890 crop_info.width=(unsigned int) (crop_info.x-x);
4891 crop_info.x=x;
4892 }
4893 if (crop_info.y < 0)
4894 crop_info.y=0;
4895 else
4896 if (crop_info.y > (int) windows->image.ximage->height)
4897 crop_info.y=windows->image.ximage->height;
4898 if ((int) crop_info.y < y)
4899 crop_info.height=(unsigned int) (y-crop_info.y);
4900 else
4901 {
4902 crop_info.height=(unsigned int) (crop_info.y-y);
4903 crop_info.y=y;
4904 }
4905 }
4906 } while ((state & ExitState) == 0);
4907 /*
4908 Wait for user to grab a corner of the rectangle or press return.
4909 */
4910 state=DefaultState;
4911 (void) XMapWindow(display,windows->info.id);
4912 do
4913 {
4914 if (windows->info.mapped != MagickFalse)
4915 {
4916 /*
4917 Display pointer position.
4918 */
4919 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
4920 crop_info.width,crop_info.height,crop_info.x,crop_info.y);
4921 XInfoWidget(display,windows,text);
4922 }
4923 highlight_info=crop_info;
4924 highlight_info.x=crop_info.x-windows->image.x;
4925 highlight_info.y=crop_info.y-windows->image.y;
4926 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4927 {
4928 state|=EscapeState;
4929 state|=ExitState;
4930 break;
4931 }
4932 XHighlightRectangle(display,windows->image.id,
4933 windows->image.highlight_context,&highlight_info);
4934 XScreenEvent(display,windows,&event);
4935 if (event.xany.window == windows->command.id)
4936 {
4937 /*
4938 Select a command from the Command widget.
4939 */
4940 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4941 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4942 (void) XSetFunction(display,windows->image.highlight_context,
4943 GXinvert);
4944 XHighlightRectangle(display,windows->image.id,
4945 windows->image.highlight_context,&highlight_info);
4946 if (id >= 0)
4947 switch (RectifyCommands[id])
4948 {
4949 case RectifyCopyCommand:
4950 {
4951 state|=ExitState;
4952 break;
4953 }
4954 case RectifyHelpCommand:
4955 {
4956 (void) XSetFunction(display,windows->image.highlight_context,
4957 GXcopy);
4958 switch (mode)
4959 {
4960 case CopyMode:
4961 {
4962 XTextViewWidget(display,resource_info,windows,MagickFalse,
4963 "Help Viewer - Image Copy",ImageCopyHelp);
4964 break;
4965 }
4966 case CropMode:
4967 {
4968 XTextViewWidget(display,resource_info,windows,MagickFalse,
4969 "Help Viewer - Image Crop",ImageCropHelp);
4970 break;
4971 }
4972 case CutMode:
4973 {
4974 XTextViewWidget(display,resource_info,windows,MagickFalse,
4975 "Help Viewer - Image Cut",ImageCutHelp);
4976 break;
4977 }
4978 }
4979 (void) XSetFunction(display,windows->image.highlight_context,
4980 GXinvert);
4981 break;
4982 }
4983 case RectifyDismissCommand:
4984 {
4985 /*
4986 Prematurely exit.
4987 */
4988 state|=EscapeState;
4989 state|=ExitState;
4990 break;
4991 }
4992 default:
4993 break;
4994 }
4995 continue;
4996 }
4997 XHighlightRectangle(display,windows->image.id,
4998 windows->image.highlight_context,&highlight_info);
4999 switch (event.type)
5000 {
5001 case ButtonPress:
5002 {
5003 if (event.xbutton.button != Button1)
5004 break;
5005 if (event.xbutton.window != windows->image.id)
5006 break;
5007 x=windows->image.x+event.xbutton.x;
5008 y=windows->image.y+event.xbutton.y;
5009 if ((x < (int) (crop_info.x+RoiDelta)) &&
5010 (x > (int) (crop_info.x-RoiDelta)) &&
5011 (y < (int) (crop_info.y+RoiDelta)) &&
5012 (y > (int) (crop_info.y-RoiDelta)))
5013 {
5014 crop_info.x=(long) (crop_info.x+crop_info.width);
5015 crop_info.y=(long) (crop_info.y+crop_info.height);
5016 state|=UpdateConfigurationState;
5017 break;
5018 }
5019 if ((x < (int) (crop_info.x+RoiDelta)) &&
5020 (x > (int) (crop_info.x-RoiDelta)) &&
5021 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5022 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5023 {
5024 crop_info.x=(long) (crop_info.x+crop_info.width);
5025 state|=UpdateConfigurationState;
5026 break;
5027 }
5028 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5029 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5030 (y < (int) (crop_info.y+RoiDelta)) &&
5031 (y > (int) (crop_info.y-RoiDelta)))
5032 {
5033 crop_info.y=(long) (crop_info.y+crop_info.height);
5034 state|=UpdateConfigurationState;
5035 break;
5036 }
5037 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5038 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5039 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5040 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5041 {
5042 state|=UpdateConfigurationState;
5043 break;
5044 }
5045 }
5046 case ButtonRelease:
5047 {
5048 if (event.xbutton.window == windows->pan.id)
5049 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5050 (highlight_info.y != crop_info.y-windows->image.y))
5051 XHighlightRectangle(display,windows->image.id,
5052 windows->image.highlight_context,&highlight_info);
5053 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5054 event.xbutton.time);
5055 break;
5056 }
5057 case Expose:
5058 {
5059 if (event.xexpose.window == windows->image.id)
5060 if (event.xexpose.count == 0)
5061 {
5062 event.xexpose.x=(int) highlight_info.x;
5063 event.xexpose.y=(int) highlight_info.y;
5064 event.xexpose.width=(int) highlight_info.width;
5065 event.xexpose.height=(int) highlight_info.height;
5066 XRefreshWindow(display,&windows->image,&event);
5067 }
5068 if (event.xexpose.window == windows->info.id)
5069 if (event.xexpose.count == 0)
5070 XInfoWidget(display,windows,text);
5071 break;
5072 }
5073 case KeyPress:
5074 {
5075 if (event.xkey.window != windows->image.id)
5076 break;
5077 /*
5078 Respond to a user key press.
5079 */
5080 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5081 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5082 switch ((int) key_symbol)
5083 {
5084 case XK_Escape:
5085 case XK_F20:
5086 state|=EscapeState;
5087 case XK_Return:
5088 {
5089 state|=ExitState;
5090 break;
5091 }
5092 case XK_Home:
5093 case XK_KP_Home:
5094 {
5095 crop_info.x=(long) (windows->image.width/2L-crop_info.width/2L);
5096 crop_info.y=(long) (windows->image.height/2L-crop_info.height/2L);
5097 break;
5098 }
5099 case XK_Left:
5100 case XK_KP_Left:
5101 {
5102 crop_info.x--;
5103 break;
5104 }
5105 case XK_Up:
5106 case XK_KP_Up:
5107 case XK_Next:
5108 {
5109 crop_info.y--;
5110 break;
5111 }
5112 case XK_Right:
5113 case XK_KP_Right:
5114 {
5115 crop_info.x++;
5116 break;
5117 }
5118 case XK_Prior:
5119 case XK_Down:
5120 case XK_KP_Down:
5121 {
5122 crop_info.y++;
5123 break;
5124 }
5125 case XK_F1:
5126 case XK_Help:
5127 {
5128 (void) XSetFunction(display,windows->image.highlight_context,
5129 GXcopy);
5130 switch (mode)
5131 {
5132 case CopyMode:
5133 {
5134 XTextViewWidget(display,resource_info,windows,MagickFalse,
5135 "Help Viewer - Image Copy",ImageCopyHelp);
5136 break;
5137 }
5138 case CropMode:
5139 {
5140 XTextViewWidget(display,resource_info,windows,MagickFalse,
5141 "Help Viewer - Image Cropg",ImageCropHelp);
5142 break;
5143 }
5144 case CutMode:
5145 {
5146 XTextViewWidget(display,resource_info,windows,MagickFalse,
5147 "Help Viewer - Image Cutg",ImageCutHelp);
5148 break;
5149 }
5150 }
5151 (void) XSetFunction(display,windows->image.highlight_context,
5152 GXinvert);
5153 break;
5154 }
5155 default:
5156 {
5157 (void) XBell(display,0);
5158 break;
5159 }
5160 }
5161 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5162 event.xkey.time);
5163 break;
5164 }
5165 case KeyRelease:
5166 break;
5167 case MotionNotify:
5168 {
5169 if (event.xmotion.window != windows->image.id)
5170 break;
5171 /*
5172 Map and unmap Info widget as text cursor crosses its boundaries.
5173 */
5174 x=event.xmotion.x;
5175 y=event.xmotion.y;
5176 if (windows->info.mapped != MagickFalse)
5177 {
5178 if ((x < (int) (windows->info.x+windows->info.width)) &&
5179 (y < (int) (windows->info.y+windows->info.height)))
5180 (void) XWithdrawWindow(display,windows->info.id,
5181 windows->info.screen);
5182 }
5183 else
5184 if ((x > (int) (windows->info.x+windows->info.width)) ||
5185 (y > (int) (windows->info.y+windows->info.height)))
5186 (void) XMapWindow(display,windows->info.id);
5187 crop_info.x=windows->image.x+event.xmotion.x;
5188 crop_info.y=windows->image.y+event.xmotion.y;
5189 break;
5190 }
5191 case SelectionRequest:
5192 {
5193 XSelectionEvent
5194 notify;
5195
5196 XSelectionRequestEvent
5197 *request;
5198
5199 /*
5200 Set primary selection.
5201 */
5202 (void) FormatMagickString(text,MaxTextExtent,"%lux%lu%+ld%+ld",
5203 crop_info.width,crop_info.height,crop_info.x,crop_info.y);
5204 request=(&(event.xselectionrequest));
5205 (void) XChangeProperty(request->display,request->requestor,
5206 request->property,request->target,8,PropModeReplace,
5207 (unsigned char *) text,(int) strlen(text));
5208 notify.type=SelectionNotify;
5209 notify.display=request->display;
5210 notify.requestor=request->requestor;
5211 notify.selection=request->selection;
5212 notify.target=request->target;
5213 notify.time=request->time;
5214 if (request->property == None)
5215 notify.property=request->target;
5216 else
5217 notify.property=request->property;
5218 (void) XSendEvent(request->display,request->requestor,False,0,
5219 (XEvent *) &notify);
5220 }
5221 default:
5222 break;
5223 }
5224 if ((state & UpdateConfigurationState) != 0)
5225 {
5226 (void) XPutBackEvent(display,&event);
5227 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5228 break;
5229 }
5230 } while ((state & ExitState) == 0);
5231 } while ((state & ExitState) == 0);
5232 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5233 XSetCursorState(display,windows,MagickFalse);
5234 if ((state & EscapeState) != 0)
5235 return(MagickTrue);
5236 if (mode == CropMode)
5237 if (((int) crop_info.width != windows->image.ximage->width) ||
5238 ((int) crop_info.height != windows->image.ximage->height))
5239 {
5240 /*
5241 Reconfigure Image window as defined by cropping rectangle.
5242 */
5243 XSetCropGeometry(display,windows,&crop_info,image);
5244 windows->image.window_changes.width=(int) crop_info.width;
5245 windows->image.window_changes.height=(int) crop_info.height;
5246 (void) XConfigureImage(display,resource_info,windows,image);
5247 return(MagickTrue);
5248 }
5249 /*
5250 Copy image before applying image transforms.
5251 */
5252 XSetCursorState(display,windows,MagickTrue);
5253 XCheckRefreshWindows(display,windows);
5254 width=(unsigned int) image->columns;
5255 height=(unsigned int) image->rows;
5256 x=0;
5257 y=0;
5258 if (windows->image.crop_geometry != (char *) NULL)
5259 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5260 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5261 crop_info.x+=x;
5262 crop_info.x=(int) (scale_factor*crop_info.x+0.5);
5263 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5264 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5265 crop_info.y+=y;
5266 crop_info.y=(int) (scale_factor*crop_info.y+0.5);
5267 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5268 crop_image=CropImage(image,&crop_info,&image->exception);
5269 XSetCursorState(display,windows,MagickFalse);
5270 if (crop_image == (Image *) NULL)
5271 return(MagickFalse);
5272 if (resource_info->copy_image != (Image *) NULL)
5273 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5274 resource_info->copy_image=crop_image;
5275 if (mode == CopyMode)
5276 {
5277 (void) XConfigureImage(display,resource_info,windows,image);
5278 return(MagickTrue);
5279 }
5280 /*
5281 Cut image.
5282 */
5283 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
5284 return(MagickFalse);
5285 image->matte=MagickTrue;
5286 exception=(&image->exception);
5287 for (y=0; y < (long) crop_info.height; y++)
5288 {
5289 q=GetAuthenticPixels(image,crop_info.x,y+crop_info.y,crop_info.width,1,
5290 exception);
5291 if (q == (PixelPacket *) NULL)
5292 break;
5293 for (x=0; x < (int) crop_info.width; x++)
5294 {
5295 q->opacity=(Quantum) TransparentOpacity;
5296 q++;
5297 }
5298 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5299 break;
5300 }
5301 /*
5302 Update image configuration.
5303 */
5304 XConfigureImageColormap(display,resource_info,windows,image);
5305 (void) XConfigureImage(display,resource_info,windows,image);
5306 return(MagickTrue);
5307}
5308
5309/*
5310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5311% %
5312% %
5313% %
5314+ X D r a w I m a g e %
5315% %
5316% %
5317% %
5318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5319%
5320% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5321% the image.
5322%
5323% The format of the XDrawEditImage method is:
5324%
5325% MagickBooleanType XDrawEditImage(Display *display,
5326% XResourceInfo *resource_info,XWindows *windows,Image **image)
5327%
5328% A description of each parameter follows:
5329%
5330% o display: Specifies a connection to an X server; returned from
5331% XOpenDisplay.
5332%
5333% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5334%
5335% o windows: Specifies a pointer to a XWindows structure.
5336%
5337% o image: the image.
5338%
5339*/
5340static MagickBooleanType XDrawEditImage(Display *display,
5341 XResourceInfo *resource_info,XWindows *windows,Image **image)
5342{
5343 static const char
5344 *DrawMenu[] =
5345 {
5346 "Element",
5347 "Color",
5348 "Stipple",
5349 "Width",
5350 "Undo",
5351 "Help",
5352 "Dismiss",
5353 (char *) NULL
5354 };
5355
5356 static ElementType
5357 element = PointElement;
5358
5359 static const ModeType
5360 DrawCommands[] =
5361 {
5362 DrawElementCommand,
5363 DrawColorCommand,
5364 DrawStippleCommand,
5365 DrawWidthCommand,
5366 DrawUndoCommand,
5367 DrawHelpCommand,
5368 DrawDismissCommand
5369 };
5370
5371 static Pixmap
5372 stipple = (Pixmap) NULL;
5373
5374 static unsigned int
5375 pen_id = 0,
5376 line_width = 1;
5377
5378 char
5379 command[MaxTextExtent],
5380 text[MaxTextExtent];
5381
5382 Cursor
5383 cursor;
5384
5385 int
5386 entry,
5387 id,
5388 number_coordinates,
5389 x,
5390 y;
5391
5392 MagickRealType
5393 degrees;
5394
5395 MagickStatusType
5396 status;
5397
5398 RectangleInfo
5399 rectangle_info;
5400
5401 register int
5402 i;
5403
5404 unsigned int
5405 distance,
5406 height,
5407 max_coordinates,
5408 width;
5409
5410 unsigned long
5411 state;
5412
5413 Window
5414 root_window;
5415
5416 XDrawInfo
5417 draw_info;
5418
5419 XEvent
5420 event;
5421
5422 XPoint
5423 *coordinate_info;
5424
5425 XSegment
5426 line_info;
5427
5428 /*
5429 Allocate polygon info.
5430 */
5431 max_coordinates=2048;
5432 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5433 sizeof(*coordinate_info));
5434 if (coordinate_info == (XPoint *) NULL)
5435 {
5436 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5437 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5438 return(MagickFalse);
5439 }
5440 /*
5441 Map Command widget.
5442 */
5443 (void) CloneString(&windows->command.name,"Draw");
5444 windows->command.data=4;
5445 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5446 (void) XMapRaised(display,windows->command.id);
5447 XClientMessage(display,windows->image.id,windows->im_protocols,
5448 windows->im_update_widget,CurrentTime);
5449 /*
5450 Wait for first button press.
5451 */
5452 root_window=XRootWindow(display,XDefaultScreen(display));
5453 draw_info.stencil=OpaqueStencil;
5454 status=MagickTrue;
5455 cursor=XCreateFontCursor(display,XC_tcross);
5456 for ( ; ; )
5457 {
5458 XQueryPosition(display,windows->image.id,&x,&y);
5459 (void) XSelectInput(display,windows->image.id,
5460 windows->image.attributes.event_mask | PointerMotionMask);
5461 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5462 state=DefaultState;
5463 do
5464 {
5465 if (windows->info.mapped != MagickFalse)
5466 {
5467 /*
5468 Display pointer position.
5469 */
5470 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
5471 x+windows->image.x,y+windows->image.y);
5472 XInfoWidget(display,windows,text);
5473 }
5474 /*
5475 Wait for next event.
5476 */
5477 XScreenEvent(display,windows,&event);
5478 if (event.xany.window == windows->command.id)
5479 {
5480 /*
5481 Select a command from the Command widget.
5482 */
5483 id=XCommandWidget(display,windows,DrawMenu,&event);
5484 if (id < 0)
5485 continue;
5486 switch (DrawCommands[id])
5487 {
5488 case DrawElementCommand:
5489 {
5490 static const char
5491 *Elements[] =
5492 {
5493 "point",
5494 "line",
5495 "rectangle",
5496 "fill rectangle",
5497 "circle",
5498 "fill circle",
5499 "ellipse",
5500 "fill ellipse",
5501 "polygon",
5502 "fill polygon",
5503 (char *) NULL,
5504 };
5505
5506 /*
5507 Select a command from the pop-up menu.
5508 */
5509 element=(ElementType) (XMenuWidget(display,windows,
5510 DrawMenu[id],Elements,command)+1);
5511 break;
5512 }
5513 case DrawColorCommand:
5514 {
5515 const char
5516 *ColorMenu[MaxNumberPens+1];
5517
5518 int
5519 pen_number;
5520
5521 MagickBooleanType
5522 transparent;
5523
5524 XColor
5525 color;
5526
5527 /*
5528 Initialize menu selections.
5529 */
5530 for (i=0; i < (int) (MaxNumberPens-2); i++)
5531 ColorMenu[i]=resource_info->pen_colors[i];
5532 ColorMenu[MaxNumberPens-2]="transparent";
5533 ColorMenu[MaxNumberPens-1]="Browser...";
5534 ColorMenu[MaxNumberPens]=(char *) NULL;
5535 /*
5536 Select a pen color from the pop-up menu.
5537 */
5538 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5539 (const char **) ColorMenu,command);
5540 if (pen_number < 0)
5541 break;
5542 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5543 MagickFalse;
5544 if (transparent != MagickFalse)
5545 {
5546 draw_info.stencil=TransparentStencil;
5547 break;
5548 }
5549 if (pen_number == (MaxNumberPens-1))
5550 {
5551 static char
5552 color_name[MaxTextExtent] = "gray";
5553
5554 /*
5555 Select a pen color from a dialog.
5556 */
5557 resource_info->pen_colors[pen_number]=color_name;
5558 XColorBrowserWidget(display,windows,"Select",color_name);
5559 if (*color_name == '\0')
5560 break;
5561 }
5562 /*
5563 Set pen color.
5564 */
5565 (void) XParseColor(display,windows->map_info->colormap,
5566 resource_info->pen_colors[pen_number],&color);
5567 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5568 (unsigned int) MaxColors,&color);
5569 windows->pixel_info->pen_colors[pen_number]=color;
5570 pen_id=(unsigned int) pen_number;
5571 draw_info.stencil=OpaqueStencil;
5572 break;
5573 }
5574 case DrawStippleCommand:
5575 {
5576 Image
5577 *stipple_image;
5578
5579 ImageInfo
5580 *image_info;
5581
5582 int
5583 status;
5584
5585 static char
5586 filename[MaxTextExtent] = "\0";
5587
5588 static const char
5589 *StipplesMenu[] =
5590 {
5591 "Brick",
5592 "Diagonal",
5593 "Scales",
5594 "Vertical",
5595 "Wavy",
5596 "Translucent",
5597 "Opaque",
5598 (char *) NULL,
5599 (char *) NULL,
5600 };
5601
5602 /*
5603 Select a command from the pop-up menu.
5604 */
5605 StipplesMenu[7]="Open...";
5606 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5607 command);
5608 if (entry < 0)
5609 break;
5610 if (stipple != (Pixmap) NULL)
5611 (void) XFreePixmap(display,stipple);
5612 stipple=(Pixmap) NULL;
5613 if (entry == 6)
5614 break;
5615 if (entry != 7)
5616 {
5617 switch (entry)
5618 {
5619 case 0:
5620 {
5621 stipple=XCreateBitmapFromData(display,root_window,
5622 (char *) BricksBitmap,BricksWidth,BricksHeight);
5623 break;
5624 }
5625 case 1:
5626 {
5627 stipple=XCreateBitmapFromData(display,root_window,
5628 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5629 break;
5630 }
5631 case 2:
5632 {
5633 stipple=XCreateBitmapFromData(display,root_window,
5634 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5635 break;
5636 }
5637 case 3:
5638 {
5639 stipple=XCreateBitmapFromData(display,root_window,
5640 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5641 break;
5642 }
5643 case 4:
5644 {
5645 stipple=XCreateBitmapFromData(display,root_window,
5646 (char *) WavyBitmap,WavyWidth,WavyHeight);
5647 break;
5648 }
5649 case 5:
5650 default:
5651 {
5652 stipple=XCreateBitmapFromData(display,root_window,
5653 (char *) HighlightBitmap,HighlightWidth,
5654 HighlightHeight);
5655 break;
5656 }
5657 }
5658 break;
5659 }
5660 XFileBrowserWidget(display,windows,"Stipple",filename);
5661 if (*filename == '\0')
5662 break;
5663 /*
5664 Read image.
5665 */
5666 XSetCursorState(display,windows,MagickTrue);
5667 XCheckRefreshWindows(display,windows);
5668 image_info=AcquireImageInfo();
5669 (void) CopyMagickString(image_info->filename,filename,
5670 MaxTextExtent);
5671 stipple_image=ReadImage(image_info,&(*image)->exception);
5672 CatchException(&(*image)->exception);
5673 XSetCursorState(display,windows,MagickFalse);
5674 if (stipple_image == (Image *) NULL)
5675 break;
5676 (void) AcquireUniqueFileResource(filename);
5677 (void) FormatMagickString(stipple_image->filename,MaxTextExtent,
5678 "xbm:%s",filename);
5679 (void) WriteImage(image_info,stipple_image);
5680 stipple_image=DestroyImage(stipple_image);
5681 image_info=DestroyImageInfo(image_info);
5682 status=XReadBitmapFile(display,root_window,filename,&width,
5683 &height,&stipple,&x,&y);
5684 (void) RelinquishUniqueFileResource(filename);
5685 if ((status != BitmapSuccess) != 0)
5686 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5687 filename);
5688 break;
5689 }
5690 case DrawWidthCommand:
5691 {
5692 static char
5693 width[MaxTextExtent] = "0";
5694
5695 static const char
5696 *WidthsMenu[] =
5697 {
5698 "1",
5699 "2",
5700 "4",
5701 "8",
5702 "16",
5703 "Dialog...",
5704 (char *) NULL,
5705 };
5706
5707 /*
5708 Select a command from the pop-up menu.
5709 */
5710 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5711 command);
5712 if (entry < 0)
5713 break;
5714 if (entry != 5)
5715 {
cristye27293e2009-12-18 02:53:20 +00005716 line_width=(unsigned int) StringToUnsignedLong(WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005717 break;
5718 }
5719 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5720 width);
5721 if (*width == '\0')
5722 break;
cristye27293e2009-12-18 02:53:20 +00005723 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005724 break;
5725 }
5726 case DrawUndoCommand:
5727 {
5728 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5729 image);
5730 break;
5731 }
5732 case DrawHelpCommand:
5733 {
5734 XTextViewWidget(display,resource_info,windows,MagickFalse,
5735 "Help Viewer - Image Rotation",ImageDrawHelp);
5736 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5737 break;
5738 }
5739 case DrawDismissCommand:
5740 {
5741 /*
5742 Prematurely exit.
5743 */
5744 state|=EscapeState;
5745 state|=ExitState;
5746 break;
5747 }
5748 default:
5749 break;
5750 }
5751 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5752 continue;
5753 }
5754 switch (event.type)
5755 {
5756 case ButtonPress:
5757 {
5758 if (event.xbutton.button != Button1)
5759 break;
5760 if (event.xbutton.window != windows->image.id)
5761 break;
5762 /*
5763 exit loop.
5764 */
5765 x=event.xbutton.x;
5766 y=event.xbutton.y;
5767 state|=ExitState;
5768 break;
5769 }
5770 case ButtonRelease:
5771 break;
5772 case Expose:
5773 break;
5774 case KeyPress:
5775 {
5776 KeySym
5777 key_symbol;
5778
5779 if (event.xkey.window != windows->image.id)
5780 break;
5781 /*
5782 Respond to a user key press.
5783 */
5784 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5785 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5786 switch ((int) key_symbol)
5787 {
5788 case XK_Escape:
5789 case XK_F20:
5790 {
5791 /*
5792 Prematurely exit.
5793 */
5794 state|=EscapeState;
5795 state|=ExitState;
5796 break;
5797 }
5798 case XK_F1:
5799 case XK_Help:
5800 {
5801 XTextViewWidget(display,resource_info,windows,MagickFalse,
5802 "Help Viewer - Image Rotation",ImageDrawHelp);
5803 break;
5804 }
5805 default:
5806 {
5807 (void) XBell(display,0);
5808 break;
5809 }
5810 }
5811 break;
5812 }
5813 case MotionNotify:
5814 {
5815 /*
5816 Map and unmap Info widget as text cursor crosses its boundaries.
5817 */
5818 x=event.xmotion.x;
5819 y=event.xmotion.y;
5820 if (windows->info.mapped != MagickFalse)
5821 {
5822 if ((x < (int) (windows->info.x+windows->info.width)) &&
5823 (y < (int) (windows->info.y+windows->info.height)))
5824 (void) XWithdrawWindow(display,windows->info.id,
5825 windows->info.screen);
5826 }
5827 else
5828 if ((x > (int) (windows->info.x+windows->info.width)) ||
5829 (y > (int) (windows->info.y+windows->info.height)))
5830 (void) XMapWindow(display,windows->info.id);
5831 break;
5832 }
5833 }
5834 } while ((state & ExitState) == 0);
5835 (void) XSelectInput(display,windows->image.id,
5836 windows->image.attributes.event_mask);
5837 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5838 if ((state & EscapeState) != 0)
5839 break;
5840 /*
5841 Draw element as pointer moves until the button is released.
5842 */
5843 distance=0;
5844 degrees=0.0;
5845 line_info.x1=x;
5846 line_info.y1=y;
5847 line_info.x2=x;
5848 line_info.y2=y;
5849 rectangle_info.x=x;
5850 rectangle_info.y=y;
5851 rectangle_info.width=0;
5852 rectangle_info.height=0;
5853 number_coordinates=1;
5854 coordinate_info->x=x;
5855 coordinate_info->y=y;
5856 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5857 state=DefaultState;
5858 do
5859 {
5860 switch (element)
5861 {
5862 case PointElement:
5863 default:
5864 {
5865 if (number_coordinates > 1)
5866 {
5867 (void) XDrawLines(display,windows->image.id,
5868 windows->image.highlight_context,coordinate_info,
5869 number_coordinates,CoordModeOrigin);
5870 (void) FormatMagickString(text,MaxTextExtent," %+d%+d",
5871 coordinate_info[number_coordinates-1].x,
5872 coordinate_info[number_coordinates-1].y);
5873 XInfoWidget(display,windows,text);
5874 }
5875 break;
5876 }
5877 case LineElement:
5878 {
5879 if (distance > 9)
5880 {
5881 /*
5882 Display angle of the line.
5883 */
5884 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5885 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristye7f51092010-01-17 00:39:37 +00005886 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005887 (double) degrees);
5888 XInfoWidget(display,windows,text);
5889 XHighlightLine(display,windows->image.id,
5890 windows->image.highlight_context,&line_info);
5891 }
5892 else
5893 if (windows->info.mapped != MagickFalse)
5894 (void) XWithdrawWindow(display,windows->info.id,
5895 windows->info.screen);
5896 break;
5897 }
5898 case RectangleElement:
5899 case FillRectangleElement:
5900 {
5901 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5902 {
5903 /*
5904 Display info and draw drawing rectangle.
5905 */
5906 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
5907 rectangle_info.width,rectangle_info.height,rectangle_info.x,
5908 rectangle_info.y);
5909 XInfoWidget(display,windows,text);
5910 XHighlightRectangle(display,windows->image.id,
5911 windows->image.highlight_context,&rectangle_info);
5912 }
5913 else
5914 if (windows->info.mapped != MagickFalse)
5915 (void) XWithdrawWindow(display,windows->info.id,
5916 windows->info.screen);
5917 break;
5918 }
5919 case CircleElement:
5920 case FillCircleElement:
5921 case EllipseElement:
5922 case FillEllipseElement:
5923 {
5924 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5925 {
5926 /*
5927 Display info and draw drawing rectangle.
5928 */
5929 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
5930 rectangle_info.width,rectangle_info.height,rectangle_info.x,
5931 rectangle_info.y);
5932 XInfoWidget(display,windows,text);
5933 XHighlightEllipse(display,windows->image.id,
5934 windows->image.highlight_context,&rectangle_info);
5935 }
5936 else
5937 if (windows->info.mapped != MagickFalse)
5938 (void) XWithdrawWindow(display,windows->info.id,
5939 windows->info.screen);
5940 break;
5941 }
5942 case PolygonElement:
5943 case FillPolygonElement:
5944 {
5945 if (number_coordinates > 1)
5946 (void) XDrawLines(display,windows->image.id,
5947 windows->image.highlight_context,coordinate_info,
5948 number_coordinates,CoordModeOrigin);
5949 if (distance > 9)
5950 {
5951 /*
5952 Display angle of the line.
5953 */
5954 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5955 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristye7f51092010-01-17 00:39:37 +00005956 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005957 (double) degrees);
5958 XInfoWidget(display,windows,text);
5959 XHighlightLine(display,windows->image.id,
5960 windows->image.highlight_context,&line_info);
5961 }
5962 else
5963 if (windows->info.mapped != MagickFalse)
5964 (void) XWithdrawWindow(display,windows->info.id,
5965 windows->info.screen);
5966 break;
5967 }
5968 }
5969 /*
5970 Wait for next event.
5971 */
5972 XScreenEvent(display,windows,&event);
5973 switch (element)
5974 {
5975 case PointElement:
5976 default:
5977 {
5978 if (number_coordinates > 1)
5979 (void) XDrawLines(display,windows->image.id,
5980 windows->image.highlight_context,coordinate_info,
5981 number_coordinates,CoordModeOrigin);
5982 break;
5983 }
5984 case LineElement:
5985 {
5986 if (distance > 9)
5987 XHighlightLine(display,windows->image.id,
5988 windows->image.highlight_context,&line_info);
5989 break;
5990 }
5991 case RectangleElement:
5992 case FillRectangleElement:
5993 {
5994 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5995 XHighlightRectangle(display,windows->image.id,
5996 windows->image.highlight_context,&rectangle_info);
5997 break;
5998 }
5999 case CircleElement:
6000 case FillCircleElement:
6001 case EllipseElement:
6002 case FillEllipseElement:
6003 {
6004 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6005 XHighlightEllipse(display,windows->image.id,
6006 windows->image.highlight_context,&rectangle_info);
6007 break;
6008 }
6009 case PolygonElement:
6010 case FillPolygonElement:
6011 {
6012 if (number_coordinates > 1)
6013 (void) XDrawLines(display,windows->image.id,
6014 windows->image.highlight_context,coordinate_info,
6015 number_coordinates,CoordModeOrigin);
6016 if (distance > 9)
6017 XHighlightLine(display,windows->image.id,
6018 windows->image.highlight_context,&line_info);
6019 break;
6020 }
6021 }
6022 switch (event.type)
6023 {
6024 case ButtonPress:
6025 break;
6026 case ButtonRelease:
6027 {
6028 /*
6029 User has committed to element.
6030 */
6031 line_info.x2=event.xbutton.x;
6032 line_info.y2=event.xbutton.y;
6033 rectangle_info.x=event.xbutton.x;
6034 rectangle_info.y=event.xbutton.y;
6035 coordinate_info[number_coordinates].x=event.xbutton.x;
6036 coordinate_info[number_coordinates].y=event.xbutton.y;
6037 if (((element != PolygonElement) &&
6038 (element != FillPolygonElement)) || (distance <= 9))
6039 {
6040 state|=ExitState;
6041 break;
6042 }
6043 number_coordinates++;
6044 if (number_coordinates < (int) max_coordinates)
6045 {
6046 line_info.x1=event.xbutton.x;
6047 line_info.y1=event.xbutton.y;
6048 break;
6049 }
6050 max_coordinates<<=1;
6051 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6052 max_coordinates,sizeof(*coordinate_info));
6053 if (coordinate_info == (XPoint *) NULL)
6054 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6055 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6056 break;
6057 }
6058 case Expose:
6059 break;
6060 case MotionNotify:
6061 {
6062 if (event.xmotion.window != windows->image.id)
6063 break;
6064 if (element != PointElement)
6065 {
6066 line_info.x2=event.xmotion.x;
6067 line_info.y2=event.xmotion.y;
6068 rectangle_info.x=event.xmotion.x;
6069 rectangle_info.y=event.xmotion.y;
6070 break;
6071 }
6072 coordinate_info[number_coordinates].x=event.xbutton.x;
6073 coordinate_info[number_coordinates].y=event.xbutton.y;
6074 number_coordinates++;
6075 if (number_coordinates < (int) max_coordinates)
6076 break;
6077 max_coordinates<<=1;
6078 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6079 max_coordinates,sizeof(*coordinate_info));
6080 if (coordinate_info == (XPoint *) NULL)
6081 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6082 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6083 break;
6084 }
6085 default:
6086 break;
6087 }
6088 /*
6089 Check boundary conditions.
6090 */
6091 if (line_info.x2 < 0)
6092 line_info.x2=0;
6093 else
6094 if (line_info.x2 > (int) windows->image.width)
6095 line_info.x2=(short) windows->image.width;
6096 if (line_info.y2 < 0)
6097 line_info.y2=0;
6098 else
6099 if (line_info.y2 > (int) windows->image.height)
6100 line_info.y2=(short) windows->image.height;
6101 distance=(unsigned int)
6102 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6103 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6104 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6105 ((state & ExitState) != 0))
6106 {
6107 if (rectangle_info.x < 0)
6108 rectangle_info.x=0;
6109 else
6110 if (rectangle_info.x > (int) windows->image.width)
6111 rectangle_info.x=(long) windows->image.width;
6112 if ((int) rectangle_info.x < x)
6113 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6114 else
6115 {
6116 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6117 rectangle_info.x=x;
6118 }
6119 if (rectangle_info.y < 0)
6120 rectangle_info.y=0;
6121 else
6122 if (rectangle_info.y > (int) windows->image.height)
6123 rectangle_info.y=(long) windows->image.height;
6124 if ((int) rectangle_info.y < y)
6125 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6126 else
6127 {
6128 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6129 rectangle_info.y=y;
6130 }
6131 }
6132 } while ((state & ExitState) == 0);
6133 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6134 if ((element == PointElement) || (element == PolygonElement) ||
6135 (element == FillPolygonElement))
6136 {
6137 /*
6138 Determine polygon bounding box.
6139 */
6140 rectangle_info.x=coordinate_info->x;
6141 rectangle_info.y=coordinate_info->y;
6142 x=coordinate_info->x;
6143 y=coordinate_info->y;
6144 for (i=1; i < number_coordinates; i++)
6145 {
6146 if (coordinate_info[i].x > x)
6147 x=coordinate_info[i].x;
6148 if (coordinate_info[i].y > y)
6149 y=coordinate_info[i].y;
6150 if (coordinate_info[i].x < rectangle_info.x)
6151 rectangle_info.x=MagickMax(coordinate_info[i].x,0);
6152 if (coordinate_info[i].y < rectangle_info.y)
6153 rectangle_info.y=MagickMax(coordinate_info[i].y,0);
6154 }
6155 rectangle_info.width=(unsigned long) (x-rectangle_info.x);
6156 rectangle_info.height=(unsigned long) (y-rectangle_info.y);
6157 for (i=0; i < number_coordinates; i++)
6158 {
6159 coordinate_info[i].x-=rectangle_info.x;
6160 coordinate_info[i].y-=rectangle_info.y;
6161 }
6162 }
6163 else
6164 if (distance <= 9)
6165 continue;
6166 else
6167 if ((element == RectangleElement) ||
6168 (element == CircleElement) || (element == EllipseElement))
6169 {
6170 rectangle_info.width--;
6171 rectangle_info.height--;
6172 }
6173 /*
6174 Drawing is relative to image configuration.
6175 */
6176 draw_info.x=(int) rectangle_info.x;
6177 draw_info.y=(int) rectangle_info.y;
6178 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6179 image);
6180 width=(unsigned int) (*image)->columns;
6181 height=(unsigned int) (*image)->rows;
6182 x=0;
6183 y=0;
6184 if (windows->image.crop_geometry != (char *) NULL)
6185 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6186 draw_info.x+=windows->image.x-(line_width/2);
6187 if (draw_info.x < 0)
6188 draw_info.x=0;
6189 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6190 draw_info.y+=windows->image.y-(line_width/2);
6191 if (draw_info.y < 0)
6192 draw_info.y=0;
6193 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6194 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6195 if (draw_info.width > (unsigned int) (*image)->columns)
6196 draw_info.width=(unsigned int) (*image)->columns;
6197 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6198 if (draw_info.height > (unsigned int) (*image)->rows)
6199 draw_info.height=(unsigned int) (*image)->rows;
6200 (void) FormatMagickString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6201 width*draw_info.width/windows->image.ximage->width,
6202 height*draw_info.height/windows->image.ximage->height,
6203 draw_info.x+x,draw_info.y+y);
6204 /*
6205 Initialize drawing attributes.
6206 */
6207 draw_info.degrees=0.0;
6208 draw_info.element=element;
6209 draw_info.stipple=stipple;
6210 draw_info.line_width=line_width;
6211 draw_info.line_info=line_info;
6212 if (line_info.x1 > (int) (line_width/2))
6213 draw_info.line_info.x1=(short) line_width/2;
6214 if (line_info.y1 > (int) (line_width/2))
6215 draw_info.line_info.y1=(short) line_width/2;
6216 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6217 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6218 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6219 {
6220 draw_info.line_info.x2=(-draw_info.line_info.x2);
6221 draw_info.line_info.y2=(-draw_info.line_info.y2);
6222 }
6223 if (draw_info.line_info.x2 < 0)
6224 {
6225 draw_info.line_info.x2=(-draw_info.line_info.x2);
6226 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6227 }
6228 if (draw_info.line_info.y2 < 0)
6229 {
6230 draw_info.line_info.y2=(-draw_info.line_info.y2);
6231 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6232 }
6233 draw_info.rectangle_info=rectangle_info;
6234 if (draw_info.rectangle_info.x > (int) (line_width/2))
6235 draw_info.rectangle_info.x=(long) line_width/2;
6236 if (draw_info.rectangle_info.y > (int) (line_width/2))
6237 draw_info.rectangle_info.y=(long) line_width/2;
6238 draw_info.number_coordinates=(unsigned int) number_coordinates;
6239 draw_info.coordinate_info=coordinate_info;
6240 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6241 /*
6242 Draw element on image.
6243 */
6244 XSetCursorState(display,windows,MagickTrue);
6245 XCheckRefreshWindows(display,windows);
6246 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6247 XSetCursorState(display,windows,MagickFalse);
6248 /*
6249 Update image colormap and return to image drawing.
6250 */
6251 XConfigureImageColormap(display,resource_info,windows,*image);
6252 (void) XConfigureImage(display,resource_info,windows,*image);
6253 }
6254 XSetCursorState(display,windows,MagickFalse);
6255 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6256 return(status != 0 ? MagickTrue : MagickFalse);
6257}
6258
6259/*
6260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6261% %
6262% %
6263% %
6264+ X D r a w P a n R e c t a n g l e %
6265% %
6266% %
6267% %
6268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6269%
6270% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6271% displays a zoom image and the rectangle shows which portion of the image is
6272% displayed in the Image window.
6273%
6274% The format of the XDrawPanRectangle method is:
6275%
6276% XDrawPanRectangle(Display *display,XWindows *windows)
6277%
6278% A description of each parameter follows:
6279%
6280% o display: Specifies a connection to an X server; returned from
6281% XOpenDisplay.
6282%
6283% o windows: Specifies a pointer to a XWindows structure.
6284%
6285*/
6286static void XDrawPanRectangle(Display *display,XWindows *windows)
6287{
6288 MagickRealType
6289 scale_factor;
6290
6291 RectangleInfo
6292 highlight_info;
6293
6294 /*
6295 Determine dimensions of the panning rectangle.
6296 */
6297 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6298 highlight_info.x=(int) (scale_factor*windows->image.x+0.5);
6299 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6300 scale_factor=(MagickRealType)
6301 windows->pan.height/windows->image.ximage->height;
6302 highlight_info.y=(int) (scale_factor*windows->image.y+0.5);
6303 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6304 /*
6305 Display the panning rectangle.
6306 */
6307 (void) XClearWindow(display,windows->pan.id);
6308 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6309 &highlight_info);
6310}
6311
6312/*
6313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6314% %
6315% %
6316% %
6317+ X I m a g e C a c h e %
6318% %
6319% %
6320% %
6321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6322%
6323% XImageCache() handles the creation, manipulation, and destruction of the
6324% image cache (undo and redo buffers).
6325%
6326% The format of the XImageCache method is:
6327%
6328% void XImageCache(Display *display,XResourceInfo *resource_info,
6329% XWindows *windows,const CommandType command,Image **image)
6330%
6331% A description of each parameter follows:
6332%
6333% o display: Specifies a connection to an X server; returned from
6334% XOpenDisplay.
6335%
6336% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6337%
6338% o windows: Specifies a pointer to a XWindows structure.
6339%
6340% o command: Specifies a command to perform.
6341%
6342% o image: the image; XImageCache
6343% may transform the image and return a new image pointer.
6344%
6345*/
6346static void XImageCache(Display *display,XResourceInfo *resource_info,
6347 XWindows *windows,const CommandType command,Image **image)
6348{
6349 Image
6350 *cache_image;
6351
6352 static Image
6353 *redo_image = (Image *) NULL,
6354 *undo_image = (Image *) NULL;
6355
6356 switch (command)
6357 {
6358 case FreeBuffersCommand:
6359 {
6360 /*
6361 Free memory from the undo and redo cache.
6362 */
6363 while (undo_image != (Image *) NULL)
6364 {
6365 cache_image=undo_image;
6366 undo_image=GetPreviousImageInList(undo_image);
6367 cache_image->list=DestroyImage(cache_image->list);
6368 cache_image=DestroyImage(cache_image);
6369 }
6370 undo_image=NewImageList();
6371 if (redo_image != (Image *) NULL)
6372 redo_image=DestroyImage(redo_image);
6373 redo_image=NewImageList();
6374 return;
6375 }
6376 case UndoCommand:
6377 {
6378 /*
6379 Undo the last image transformation.
6380 */
6381 if (undo_image == (Image *) NULL)
6382 {
6383 (void) XBell(display,0);
6384 return;
6385 }
6386 cache_image=undo_image;
6387 undo_image=GetPreviousImageInList(undo_image);
6388 windows->image.window_changes.width=(int) cache_image->columns;
6389 windows->image.window_changes.height=(int) cache_image->rows;
6390 if (windows->image.crop_geometry != (char *) NULL)
6391 windows->image.crop_geometry=(char *)
6392 RelinquishMagickMemory(windows->image.crop_geometry);
6393 windows->image.crop_geometry=cache_image->geometry;
6394 if (redo_image != (Image *) NULL)
6395 redo_image=DestroyImage(redo_image);
6396 redo_image=(*image);
6397 *image=cache_image->list;
6398 cache_image=DestroyImage(cache_image);
6399 if (windows->image.orphan != MagickFalse)
6400 return;
6401 XConfigureImageColormap(display,resource_info,windows,*image);
6402 (void) XConfigureImage(display,resource_info,windows,*image);
6403 return;
6404 }
6405 case CutCommand:
6406 case PasteCommand:
6407 case ApplyCommand:
6408 case HalfSizeCommand:
6409 case OriginalSizeCommand:
6410 case DoubleSizeCommand:
6411 case ResizeCommand:
6412 case TrimCommand:
6413 case CropCommand:
6414 case ChopCommand:
6415 case FlipCommand:
6416 case FlopCommand:
6417 case RotateRightCommand:
6418 case RotateLeftCommand:
6419 case RotateCommand:
6420 case ShearCommand:
6421 case RollCommand:
6422 case NegateCommand:
6423 case ContrastStretchCommand:
6424 case SigmoidalContrastCommand:
6425 case NormalizeCommand:
6426 case EqualizeCommand:
6427 case HueCommand:
6428 case SaturationCommand:
6429 case BrightnessCommand:
6430 case GammaCommand:
6431 case SpiffCommand:
6432 case DullCommand:
6433 case GrayscaleCommand:
6434 case MapCommand:
6435 case QuantizeCommand:
6436 case DespeckleCommand:
6437 case EmbossCommand:
6438 case ReduceNoiseCommand:
6439 case AddNoiseCommand:
6440 case SharpenCommand:
6441 case BlurCommand:
6442 case ThresholdCommand:
6443 case EdgeDetectCommand:
6444 case SpreadCommand:
6445 case ShadeCommand:
6446 case RaiseCommand:
6447 case SegmentCommand:
6448 case SolarizeCommand:
6449 case SepiaToneCommand:
6450 case SwirlCommand:
6451 case ImplodeCommand:
6452 case VignetteCommand:
6453 case WaveCommand:
6454 case OilPaintCommand:
6455 case CharcoalDrawCommand:
6456 case AnnotateCommand:
6457 case AddBorderCommand:
6458 case AddFrameCommand:
6459 case CompositeCommand:
6460 case CommentCommand:
6461 case LaunchCommand:
6462 case RegionofInterestCommand:
6463 case SaveToUndoBufferCommand:
6464 case RedoCommand:
6465 {
6466 Image
6467 *previous_image;
6468
6469 long
6470 bytes;
6471
6472 bytes=(long) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6473 if (undo_image != (Image *) NULL)
6474 {
6475 /*
6476 Ensure the undo stash.has enough memory available.
6477 */
6478 previous_image=undo_image;
6479 while (previous_image != (Image *) NULL)
6480 {
6481 bytes+=previous_image->list->columns*previous_image->list->rows*
6482 sizeof(PixelPacket);
6483 if (bytes <= (long) (resource_info->undo_cache << 20))
6484 {
6485 previous_image=GetPreviousImageInList(previous_image);
6486 continue;
6487 }
6488 bytes-=previous_image->list->columns*previous_image->list->rows*
6489 sizeof(PixelPacket);
6490 if (previous_image == undo_image)
6491 undo_image=NewImageList();
6492 else
6493 previous_image->next->previous=NewImageList();
6494 break;
6495 }
6496 while (previous_image != (Image *) NULL)
6497 {
6498 /*
6499 Delete any excess memory from undo cache.
6500 */
6501 cache_image=previous_image;
6502 previous_image=GetPreviousImageInList(previous_image);
6503 cache_image->list=DestroyImage(cache_image->list);
6504 cache_image=DestroyImage(cache_image);
6505 }
6506 }
6507 if (bytes > (long) (resource_info->undo_cache << 20))
6508 break;
6509 /*
6510 Save image before transformations are applied.
6511 */
6512 cache_image=AcquireImage((ImageInfo *) NULL);
6513 if (cache_image == (Image *) NULL)
6514 break;
6515 XSetCursorState(display,windows,MagickTrue);
6516 XCheckRefreshWindows(display,windows);
6517 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6518 XSetCursorState(display,windows,MagickFalse);
6519 if (cache_image->list == (Image *) NULL)
6520 {
6521 cache_image=DestroyImage(cache_image);
6522 break;
6523 }
6524 cache_image->columns=(unsigned long) windows->image.ximage->width;
6525 cache_image->rows=(unsigned long) windows->image.ximage->height;
6526 cache_image->geometry=windows->image.crop_geometry;
6527 if (windows->image.crop_geometry != (char *) NULL)
6528 {
6529 cache_image->geometry=AcquireString((char *) NULL);
6530 (void) CopyMagickString(cache_image->geometry,
6531 windows->image.crop_geometry,MaxTextExtent);
6532 }
6533 if (undo_image == (Image *) NULL)
6534 {
6535 undo_image=cache_image;
6536 break;
6537 }
6538 undo_image->next=cache_image;
6539 undo_image->next->previous=undo_image;
6540 undo_image=undo_image->next;
6541 break;
6542 }
6543 default:
6544 break;
6545 }
6546 if (command == RedoCommand)
6547 {
6548 /*
6549 Redo the last image transformation.
6550 */
6551 if (redo_image == (Image *) NULL)
6552 {
6553 (void) XBell(display,0);
6554 return;
6555 }
6556 windows->image.window_changes.width=(int) redo_image->columns;
6557 windows->image.window_changes.height=(int) redo_image->rows;
6558 if (windows->image.crop_geometry != (char *) NULL)
6559 windows->image.crop_geometry=(char *)
6560 RelinquishMagickMemory(windows->image.crop_geometry);
6561 windows->image.crop_geometry=redo_image->geometry;
6562 *image=DestroyImage(*image);
6563 *image=redo_image;
6564 redo_image=NewImageList();
6565 if (windows->image.orphan != MagickFalse)
6566 return;
6567 XConfigureImageColormap(display,resource_info,windows,*image);
6568 (void) XConfigureImage(display,resource_info,windows,*image);
6569 return;
6570 }
6571 if (command != InfoCommand)
6572 return;
6573 /*
6574 Display image info.
6575 */
6576 XSetCursorState(display,windows,MagickTrue);
6577 XCheckRefreshWindows(display,windows);
6578 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6579 XSetCursorState(display,windows,MagickFalse);
6580}
6581
6582/*
6583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6584% %
6585% %
6586% %
6587+ X I m a g e W i n d o w C o m m a n d %
6588% %
6589% %
6590% %
6591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6592%
6593% XImageWindowCommand() makes a transform to the image or Image window as
6594% specified by a user menu button or keyboard command.
6595%
6596% The format of the XMagickCommand method is:
6597%
6598% CommandType XImageWindowCommand(Display *display,
6599% XResourceInfo *resource_info,XWindows *windows,
6600% const MagickStatusType state,KeySym key_symbol,Image **image)
6601%
6602% A description of each parameter follows:
6603%
6604% o nexus: Method XImageWindowCommand returns an image when the
6605% user chooses 'Open Image' from the command menu. Otherwise a null
6606% image is returned.
6607%
6608% o display: Specifies a connection to an X server; returned from
6609% XOpenDisplay.
6610%
6611% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6612%
6613% o windows: Specifies a pointer to a XWindows structure.
6614%
6615% o state: key mask.
6616%
6617% o key_symbol: Specifies a command to perform.
6618%
6619% o image: the image; XImageWIndowCommand
6620% may transform the image and return a new image pointer.
6621%
6622*/
6623static CommandType XImageWindowCommand(Display *display,
6624 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6625 KeySym key_symbol,Image **image)
6626{
6627 static char
6628 delta[MaxTextExtent] = "";
6629
6630 static const char
6631 Digits[] = "01234567890";
6632
6633 static KeySym
6634 last_symbol = XK_0;
6635
6636 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6637 {
6638 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6639 {
6640 *delta='\0';
6641 resource_info->quantum=1;
6642 }
6643 last_symbol=key_symbol;
6644 delta[strlen(delta)+1]='\0';
6645 delta[strlen(delta)]=Digits[key_symbol-XK_0];
cristyf2f27272009-12-17 14:48:46 +00006646 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006647 return(NullCommand);
6648 }
6649 last_symbol=key_symbol;
6650 if (resource_info->immutable)
6651 {
6652 /*
6653 Virtual image window has a restricted command set.
6654 */
6655 switch (key_symbol)
6656 {
6657 case XK_question:
6658 return(InfoCommand);
6659 case XK_p:
6660 case XK_Print:
6661 return(PrintCommand);
6662 case XK_space:
6663 return(NextCommand);
6664 case XK_q:
6665 case XK_Escape:
6666 return(QuitCommand);
6667 default:
6668 break;
6669 }
6670 return(NullCommand);
6671 }
6672 switch ((int) key_symbol)
6673 {
6674 case XK_o:
6675 {
6676 if ((state & ControlMask) == 0)
6677 break;
6678 return(OpenCommand);
6679 }
6680 case XK_space:
6681 return(NextCommand);
6682 case XK_BackSpace:
6683 return(FormerCommand);
6684 case XK_s:
6685 {
6686 if ((state & Mod1Mask) != 0)
6687 return(SwirlCommand);
6688 if ((state & ControlMask) == 0)
6689 return(ShearCommand);
6690 return(SaveCommand);
6691 }
6692 case XK_p:
6693 case XK_Print:
6694 {
6695 if ((state & Mod1Mask) != 0)
6696 return(OilPaintCommand);
6697 if ((state & Mod4Mask) != 0)
6698 return(ColorCommand);
6699 if ((state & ControlMask) == 0)
6700 return(NullCommand);
6701 return(PrintCommand);
6702 }
6703 case XK_d:
6704 {
6705 if ((state & Mod4Mask) != 0)
6706 return(DrawCommand);
6707 if ((state & ControlMask) == 0)
6708 return(NullCommand);
6709 return(DeleteCommand);
6710 }
6711 case XK_Select:
6712 {
6713 if ((state & ControlMask) == 0)
6714 return(NullCommand);
6715 return(SelectCommand);
6716 }
6717 case XK_n:
6718 {
6719 if ((state & ControlMask) == 0)
6720 return(NullCommand);
6721 return(NewCommand);
6722 }
6723 case XK_q:
6724 case XK_Escape:
6725 return(QuitCommand);
6726 case XK_z:
6727 case XK_Undo:
6728 {
6729 if ((state & ControlMask) == 0)
6730 return(NullCommand);
6731 return(UndoCommand);
6732 }
6733 case XK_r:
6734 case XK_Redo:
6735 {
6736 if ((state & ControlMask) == 0)
6737 return(RollCommand);
6738 return(RedoCommand);
6739 }
6740 case XK_x:
6741 {
6742 if ((state & ControlMask) == 0)
6743 return(NullCommand);
6744 return(CutCommand);
6745 }
6746 case XK_c:
6747 {
6748 if ((state & Mod1Mask) != 0)
6749 return(CharcoalDrawCommand);
6750 if ((state & ControlMask) == 0)
6751 return(CropCommand);
6752 return(CopyCommand);
6753 }
6754 case XK_v:
6755 case XK_Insert:
6756 {
6757 if ((state & Mod4Mask) != 0)
6758 return(CompositeCommand);
6759 if ((state & ControlMask) == 0)
6760 return(FlipCommand);
6761 return(PasteCommand);
6762 }
6763 case XK_less:
6764 return(HalfSizeCommand);
6765 case XK_minus:
6766 return(OriginalSizeCommand);
6767 case XK_greater:
6768 return(DoubleSizeCommand);
6769 case XK_percent:
6770 return(ResizeCommand);
6771 case XK_at:
6772 return(RefreshCommand);
6773 case XK_bracketleft:
6774 return(ChopCommand);
6775 case XK_h:
6776 return(FlopCommand);
6777 case XK_slash:
6778 return(RotateRightCommand);
6779 case XK_backslash:
6780 return(RotateLeftCommand);
6781 case XK_asterisk:
6782 return(RotateCommand);
6783 case XK_t:
6784 return(TrimCommand);
6785 case XK_H:
6786 return(HueCommand);
6787 case XK_S:
6788 return(SaturationCommand);
6789 case XK_L:
6790 return(BrightnessCommand);
6791 case XK_G:
6792 return(GammaCommand);
6793 case XK_C:
6794 return(SpiffCommand);
6795 case XK_Z:
6796 return(DullCommand);
6797 case XK_N:
6798 return(NormalizeCommand);
6799 case XK_equal:
6800 return(EqualizeCommand);
6801 case XK_asciitilde:
6802 return(NegateCommand);
6803 case XK_period:
6804 return(GrayscaleCommand);
6805 case XK_numbersign:
6806 return(QuantizeCommand);
6807 case XK_F2:
6808 return(DespeckleCommand);
6809 case XK_F3:
6810 return(EmbossCommand);
6811 case XK_F4:
6812 return(ReduceNoiseCommand);
6813 case XK_F5:
6814 return(AddNoiseCommand);
6815 case XK_F6:
6816 return(SharpenCommand);
6817 case XK_F7:
6818 return(BlurCommand);
6819 case XK_F8:
6820 return(ThresholdCommand);
6821 case XK_F9:
6822 return(EdgeDetectCommand);
6823 case XK_F10:
6824 return(SpreadCommand);
6825 case XK_F11:
6826 return(ShadeCommand);
6827 case XK_F12:
6828 return(RaiseCommand);
6829 case XK_F13:
6830 return(SegmentCommand);
6831 case XK_i:
6832 {
6833 if ((state & Mod1Mask) == 0)
6834 return(NullCommand);
6835 return(ImplodeCommand);
6836 }
6837 case XK_w:
6838 {
6839 if ((state & Mod1Mask) == 0)
6840 return(NullCommand);
6841 return(WaveCommand);
6842 }
6843 case XK_m:
6844 {
6845 if ((state & Mod4Mask) == 0)
6846 return(NullCommand);
6847 return(MatteCommand);
6848 }
6849 case XK_b:
6850 {
6851 if ((state & Mod4Mask) == 0)
6852 return(NullCommand);
6853 return(AddBorderCommand);
6854 }
6855 case XK_f:
6856 {
6857 if ((state & Mod4Mask) == 0)
6858 return(NullCommand);
6859 return(AddFrameCommand);
6860 }
6861 case XK_exclam:
6862 {
6863 if ((state & Mod4Mask) == 0)
6864 return(NullCommand);
6865 return(CommentCommand);
6866 }
6867 case XK_a:
6868 {
6869 if ((state & Mod1Mask) != 0)
6870 return(ApplyCommand);
6871 if ((state & Mod4Mask) != 0)
6872 return(AnnotateCommand);
6873 if ((state & ControlMask) == 0)
6874 return(NullCommand);
6875 return(RegionofInterestCommand);
6876 }
6877 case XK_question:
6878 return(InfoCommand);
6879 case XK_plus:
6880 return(ZoomCommand);
6881 case XK_P:
6882 {
6883 if ((state & ShiftMask) == 0)
6884 return(NullCommand);
6885 return(ShowPreviewCommand);
6886 }
6887 case XK_Execute:
6888 return(LaunchCommand);
6889 case XK_F1:
6890 return(HelpCommand);
6891 case XK_Find:
6892 return(BrowseDocumentationCommand);
6893 case XK_Menu:
6894 {
6895 (void) XMapRaised(display,windows->command.id);
6896 return(NullCommand);
6897 }
6898 case XK_Next:
6899 case XK_Prior:
6900 case XK_Home:
6901 case XK_KP_Home:
6902 {
6903 XTranslateImage(display,windows,*image,key_symbol);
6904 return(NullCommand);
6905 }
6906 case XK_Up:
6907 case XK_KP_Up:
6908 case XK_Down:
6909 case XK_KP_Down:
6910 case XK_Left:
6911 case XK_KP_Left:
6912 case XK_Right:
6913 case XK_KP_Right:
6914 {
6915 if ((state & Mod1Mask) != 0)
6916 {
6917 RectangleInfo
6918 crop_info;
6919
6920 /*
6921 Trim one pixel from edge of image.
6922 */
6923 crop_info.x=0;
6924 crop_info.y=0;
6925 crop_info.width=(unsigned long) windows->image.ximage->width;
6926 crop_info.height=(unsigned long) windows->image.ximage->height;
6927 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6928 {
6929 if (resource_info->quantum >= (int) crop_info.height)
6930 resource_info->quantum=(int) crop_info.height-1;
6931 crop_info.height-=resource_info->quantum;
6932 }
6933 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6934 {
6935 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6936 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6937 crop_info.y+=resource_info->quantum;
6938 crop_info.height-=resource_info->quantum;
6939 }
6940 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6941 {
6942 if (resource_info->quantum >= (int) crop_info.width)
6943 resource_info->quantum=(int) crop_info.width-1;
6944 crop_info.width-=resource_info->quantum;
6945 }
6946 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6947 {
6948 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6949 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6950 crop_info.x+=resource_info->quantum;
6951 crop_info.width-=resource_info->quantum;
6952 }
6953 if ((int) (windows->image.x+windows->image.width) >
6954 (int) crop_info.width)
6955 windows->image.x=(int) (crop_info.width-windows->image.width);
6956 if ((int) (windows->image.y+windows->image.height) >
6957 (int) crop_info.height)
6958 windows->image.y=(int) (crop_info.height-windows->image.height);
6959 XSetCropGeometry(display,windows,&crop_info,*image);
6960 windows->image.window_changes.width=(int) crop_info.width;
6961 windows->image.window_changes.height=(int) crop_info.height;
6962 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
6963 (void) XConfigureImage(display,resource_info,windows,*image);
6964 return(NullCommand);
6965 }
6966 XTranslateImage(display,windows,*image,key_symbol);
6967 return(NullCommand);
6968 }
6969 default:
6970 return(NullCommand);
6971 }
6972 return(NullCommand);
6973}
6974
6975/*
6976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6977% %
6978% %
6979% %
6980+ X M a g i c k C o m m a n d %
6981% %
6982% %
6983% %
6984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6985%
6986% XMagickCommand() makes a transform to the image or Image window as
6987% specified by a user menu button or keyboard command.
6988%
6989% The format of the XMagickCommand method is:
6990%
6991% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
6992% XWindows *windows,const CommandType command,Image **image)
6993%
6994% A description of each parameter follows:
6995%
6996% o nexus: Method XMagickCommand returns an image when the
6997% user chooses 'Load Image' from the command menu. Otherwise a null
6998% image is returned.
6999%
7000% o display: Specifies a connection to an X server; returned from
7001% XOpenDisplay.
7002%
7003% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7004%
7005% o windows: Specifies a pointer to a XWindows structure.
7006%
7007% o command: Specifies a command to perform.
7008%
7009% o image: the image; XMagickCommand
7010% may transform the image and return a new image pointer.
7011%
7012*/
7013static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7014 XWindows *windows,const CommandType command,Image **image)
7015{
7016 char
7017 filename[MaxTextExtent],
7018 geometry[MaxTextExtent],
7019 modulate_factors[MaxTextExtent];
7020
7021 GeometryInfo
7022 geometry_info;
7023
7024 Image
7025 *nexus;
7026
7027 ImageInfo
7028 *image_info;
7029
7030 int
7031 x,
7032 y;
7033
7034 MagickStatusType
7035 flags,
7036 status;
7037
7038 QuantizeInfo
7039 quantize_info;
7040
7041 RectangleInfo
7042 page_geometry;
7043
7044 register int
7045 i;
7046
7047 static char
7048 color[MaxTextExtent] = "gray";
7049
7050 unsigned int
7051 height,
7052 width;
7053
7054 /*
7055 Process user command.
7056 */
7057 XCheckRefreshWindows(display,windows);
7058 XImageCache(display,resource_info,windows,command,image);
7059 nexus=NewImageList();
7060 windows->image.window_changes.width=windows->image.ximage->width;
7061 windows->image.window_changes.height=windows->image.ximage->height;
7062 image_info=CloneImageInfo(resource_info->image_info);
7063 SetGeometryInfo(&geometry_info);
7064 GetQuantizeInfo(&quantize_info);
7065 switch (command)
7066 {
7067 case OpenCommand:
7068 {
7069 /*
7070 Load image.
7071 */
7072 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7073 break;
7074 }
7075 case NextCommand:
7076 {
7077 /*
7078 Display next image.
7079 */
7080 for (i=0; i < resource_info->quantum; i++)
7081 XClientMessage(display,windows->image.id,windows->im_protocols,
7082 windows->im_next_image,CurrentTime);
7083 break;
7084 }
7085 case FormerCommand:
7086 {
7087 /*
7088 Display former image.
7089 */
7090 for (i=0; i < resource_info->quantum; i++)
7091 XClientMessage(display,windows->image.id,windows->im_protocols,
7092 windows->im_former_image,CurrentTime);
7093 break;
7094 }
7095 case SelectCommand:
7096 {
7097 int
7098 status;
7099
7100 /*
7101 Select image.
7102 */
7103 status=chdir(resource_info->home_directory);
7104 if (status == -1)
7105 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7106 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7107 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7108 break;
7109 }
7110 case SaveCommand:
7111 {
7112 /*
7113 Save image.
7114 */
7115 status=XSaveImage(display,resource_info,windows,*image);
7116 if (status == MagickFalse)
7117 {
7118 XNoticeWidget(display,windows,"Unable to write X image:",
7119 (*image)->filename);
7120 break;
7121 }
7122 break;
7123 }
7124 case PrintCommand:
7125 {
7126 /*
7127 Print image.
7128 */
7129 status=XPrintImage(display,resource_info,windows,*image);
7130 if (status == MagickFalse)
7131 {
7132 XNoticeWidget(display,windows,"Unable to print X image:",
7133 (*image)->filename);
7134 break;
7135 }
7136 break;
7137 }
7138 case DeleteCommand:
7139 {
7140 static char
7141 filename[MaxTextExtent] = "\0";
7142
7143 /*
7144 Delete image file.
7145 */
7146 XFileBrowserWidget(display,windows,"Delete",filename);
7147 if (*filename == '\0')
7148 break;
7149 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
7150 if (status != MagickFalse)
7151 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7152 break;
7153 }
7154 case NewCommand:
7155 {
7156 int
7157 status;
7158
7159 static char
7160 color[MaxTextExtent] = "gray",
7161 geometry[MaxTextExtent] = "640x480";
7162
7163 static const char
7164 *format = "gradient";
7165
7166 /*
7167 Query user for canvas geometry.
7168 */
7169 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7170 geometry);
7171 if (*geometry == '\0')
7172 break;
7173 if (status == 0)
7174 format="xc";
7175 XColorBrowserWidget(display,windows,"Select",color);
7176 if (*color == '\0')
7177 break;
7178 /*
7179 Create canvas.
7180 */
7181 (void) FormatMagickString(image_info->filename,MaxTextExtent,
7182 "%s:%s",format,color);
7183 (void) CloneString(&image_info->size,geometry);
7184 nexus=ReadImage(image_info,&(*image)->exception);
7185 CatchException(&(*image)->exception);
7186 XClientMessage(display,windows->image.id,windows->im_protocols,
7187 windows->im_next_image,CurrentTime);
7188 break;
7189 }
7190 case VisualDirectoryCommand:
7191 {
7192 /*
7193 Visual Image directory.
7194 */
7195 nexus=XVisualDirectoryImage(display,resource_info,windows);
7196 break;
7197 }
7198 case QuitCommand:
7199 {
7200 /*
7201 exit program.
7202 */
7203 if (resource_info->confirm_exit == MagickFalse)
7204 XClientMessage(display,windows->image.id,windows->im_protocols,
7205 windows->im_exit,CurrentTime);
7206 else
7207 {
7208 int
7209 status;
7210
7211 /*
7212 Confirm program exit.
7213 */
7214 status=XConfirmWidget(display,windows,"Do you really want to exit",
7215 resource_info->client_name);
7216 if (status > 0)
7217 XClientMessage(display,windows->image.id,windows->im_protocols,
7218 windows->im_exit,CurrentTime);
7219 }
7220 break;
7221 }
7222 case CutCommand:
7223 {
7224 /*
7225 Cut image.
7226 */
7227 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7228 break;
7229 }
7230 case CopyCommand:
7231 {
7232 /*
7233 Copy image.
7234 */
7235 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7236 break;
7237 }
7238 case PasteCommand:
7239 {
7240 /*
7241 Paste image.
7242 */
7243 status=XPasteImage(display,resource_info,windows,*image);
7244 if (status == MagickFalse)
7245 {
7246 XNoticeWidget(display,windows,"Unable to paste X image",
7247 (*image)->filename);
7248 break;
7249 }
7250 break;
7251 }
7252 case HalfSizeCommand:
7253 {
7254 /*
7255 Half image size.
7256 */
7257 windows->image.window_changes.width=windows->image.ximage->width/2;
7258 windows->image.window_changes.height=windows->image.ximage->height/2;
7259 (void) XConfigureImage(display,resource_info,windows,*image);
7260 break;
7261 }
7262 case OriginalSizeCommand:
7263 {
7264 /*
7265 Original image size.
7266 */
7267 windows->image.window_changes.width=(int) (*image)->columns;
7268 windows->image.window_changes.height=(int) (*image)->rows;
7269 (void) XConfigureImage(display,resource_info,windows,*image);
7270 break;
7271 }
7272 case DoubleSizeCommand:
7273 {
7274 /*
7275 Double the image size.
7276 */
7277 windows->image.window_changes.width=windows->image.ximage->width << 1;
7278 windows->image.window_changes.height=windows->image.ximage->height << 1;
7279 (void) XConfigureImage(display,resource_info,windows,*image);
7280 break;
7281 }
7282 case ResizeCommand:
7283 {
7284 int
7285 status;
7286
7287 long
7288 x,
7289 y;
7290
7291 unsigned long
7292 height,
7293 width;
7294
7295 /*
7296 Resize image.
7297 */
7298 width=(unsigned long) windows->image.ximage->width;
7299 height=(unsigned long) windows->image.ximage->height;
7300 x=0;
7301 y=0;
7302 (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu+0+0",
7303 width,height);
7304 status=XDialogWidget(display,windows,"Resize",
7305 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7306 if (*geometry == '\0')
7307 break;
7308 if (status == 0)
7309 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7310 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7311 windows->image.window_changes.width=(int) width;
7312 windows->image.window_changes.height=(int) height;
7313 (void) XConfigureImage(display,resource_info,windows,*image);
7314 break;
7315 }
7316 case ApplyCommand:
7317 {
7318 char
7319 image_geometry[MaxTextExtent];
7320
7321 if ((windows->image.crop_geometry == (char *) NULL) &&
7322 ((int) (*image)->columns == windows->image.ximage->width) &&
7323 ((int) (*image)->rows == windows->image.ximage->height))
7324 break;
7325 /*
7326 Apply size transforms to image.
7327 */
7328 XSetCursorState(display,windows,MagickTrue);
7329 XCheckRefreshWindows(display,windows);
7330 /*
7331 Crop and/or scale displayed image.
7332 */
7333 (void) FormatMagickString(image_geometry,MaxTextExtent,"%dx%d!",
7334 windows->image.ximage->width,windows->image.ximage->height);
7335 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7336 if (windows->image.crop_geometry != (char *) NULL)
7337 windows->image.crop_geometry=(char *)
7338 RelinquishMagickMemory(windows->image.crop_geometry);
7339 windows->image.x=0;
7340 windows->image.y=0;
7341 XConfigureImageColormap(display,resource_info,windows,*image);
7342 (void) XConfigureImage(display,resource_info,windows,*image);
7343 break;
7344 }
7345 case RefreshCommand:
7346 {
7347 (void) XConfigureImage(display,resource_info,windows,*image);
7348 break;
7349 }
7350 case RestoreCommand:
7351 {
7352 /*
7353 Restore Image window to its original size.
7354 */
7355 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7356 (windows->image.height == (unsigned int) (*image)->rows) &&
7357 (windows->image.crop_geometry == (char *) NULL))
7358 {
7359 (void) XBell(display,0);
7360 break;
7361 }
7362 windows->image.window_changes.width=(int) (*image)->columns;
7363 windows->image.window_changes.height=(int) (*image)->rows;
7364 if (windows->image.crop_geometry != (char *) NULL)
7365 {
7366 windows->image.crop_geometry=(char *)
7367 RelinquishMagickMemory(windows->image.crop_geometry);
7368 windows->image.crop_geometry=(char *) NULL;
7369 windows->image.x=0;
7370 windows->image.y=0;
7371 }
7372 XConfigureImageColormap(display,resource_info,windows,*image);
7373 (void) XConfigureImage(display,resource_info,windows,*image);
7374 break;
7375 }
7376 case CropCommand:
7377 {
7378 /*
7379 Crop image.
7380 */
7381 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7382 break;
7383 }
7384 case ChopCommand:
7385 {
7386 /*
7387 Chop image.
7388 */
7389 status=XChopImage(display,resource_info,windows,image);
7390 if (status == MagickFalse)
7391 {
7392 XNoticeWidget(display,windows,"Unable to cut X image",
7393 (*image)->filename);
7394 break;
7395 }
7396 break;
7397 }
7398 case FlopCommand:
7399 {
7400 Image
7401 *flop_image;
7402
7403 /*
7404 Flop image scanlines.
7405 */
7406 XSetCursorState(display,windows,MagickTrue);
7407 XCheckRefreshWindows(display,windows);
7408 flop_image=FlopImage(*image,&(*image)->exception);
7409 if (flop_image != (Image *) NULL)
7410 {
7411 *image=DestroyImage(*image);
7412 *image=flop_image;
7413 }
7414 CatchException(&(*image)->exception);
7415 XSetCursorState(display,windows,MagickFalse);
7416 if (windows->image.crop_geometry != (char *) NULL)
7417 {
7418 /*
7419 Flop crop geometry.
7420 */
7421 width=(unsigned int) (*image)->columns;
7422 height=(unsigned int) (*image)->rows;
7423 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7424 &width,&height);
7425 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7426 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7427 }
7428 if (windows->image.orphan != MagickFalse)
7429 break;
7430 (void) XConfigureImage(display,resource_info,windows,*image);
7431 break;
7432 }
7433 case FlipCommand:
7434 {
7435 Image
7436 *flip_image;
7437
7438 /*
7439 Flip image scanlines.
7440 */
7441 XSetCursorState(display,windows,MagickTrue);
7442 XCheckRefreshWindows(display,windows);
7443 flip_image=FlipImage(*image,&(*image)->exception);
7444 if (flip_image != (Image *) NULL)
7445 {
7446 *image=DestroyImage(*image);
7447 *image=flip_image;
7448 }
7449 CatchException(&(*image)->exception);
7450 XSetCursorState(display,windows,MagickFalse);
7451 if (windows->image.crop_geometry != (char *) NULL)
7452 {
7453 /*
7454 Flip crop geometry.
7455 */
7456 width=(unsigned int) (*image)->columns;
7457 height=(unsigned int) (*image)->rows;
7458 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7459 &width,&height);
7460 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
7461 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7462 }
7463 if (windows->image.orphan != MagickFalse)
7464 break;
7465 (void) XConfigureImage(display,resource_info,windows,*image);
7466 break;
7467 }
7468 case RotateRightCommand:
7469 {
7470 /*
7471 Rotate image 90 degrees clockwise.
7472 */
7473 status=XRotateImage(display,resource_info,windows,90.0,image);
7474 if (status == MagickFalse)
7475 {
7476 XNoticeWidget(display,windows,"Unable to rotate X image",
7477 (*image)->filename);
7478 break;
7479 }
7480 break;
7481 }
7482 case RotateLeftCommand:
7483 {
7484 /*
7485 Rotate image 90 degrees counter-clockwise.
7486 */
7487 status=XRotateImage(display,resource_info,windows,-90.0,image);
7488 if (status == MagickFalse)
7489 {
7490 XNoticeWidget(display,windows,"Unable to rotate X image",
7491 (*image)->filename);
7492 break;
7493 }
7494 break;
7495 }
7496 case RotateCommand:
7497 {
7498 /*
7499 Rotate image.
7500 */
7501 status=XRotateImage(display,resource_info,windows,0.0,image);
7502 if (status == MagickFalse)
7503 {
7504 XNoticeWidget(display,windows,"Unable to rotate X image",
7505 (*image)->filename);
7506 break;
7507 }
7508 break;
7509 }
7510 case ShearCommand:
7511 {
7512 Image
7513 *shear_image;
7514
7515 static char
7516 geometry[MaxTextExtent] = "45.0x45.0";
7517
7518 /*
7519 Query user for shear color and geometry.
7520 */
7521 XColorBrowserWidget(display,windows,"Select",color);
7522 if (*color == '\0')
7523 break;
7524 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7525 geometry);
7526 if (*geometry == '\0')
7527 break;
7528 /*
7529 Shear image.
7530 */
7531 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7532 XSetCursorState(display,windows,MagickTrue);
7533 XCheckRefreshWindows(display,windows);
7534 (void) QueryColorDatabase(color,&(*image)->background_color,
7535 &(*image)->exception);
7536 flags=ParseGeometry(geometry,&geometry_info);
7537 if ((flags & SigmaValue) == 0)
7538 geometry_info.sigma=geometry_info.rho;
7539 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7540 &(*image)->exception);
7541 if (shear_image != (Image *) NULL)
7542 {
7543 *image=DestroyImage(*image);
7544 *image=shear_image;
7545 }
7546 CatchException(&(*image)->exception);
7547 XSetCursorState(display,windows,MagickFalse);
7548 if (windows->image.orphan != MagickFalse)
7549 break;
7550 windows->image.window_changes.width=(int) (*image)->columns;
7551 windows->image.window_changes.height=(int) (*image)->rows;
7552 XConfigureImageColormap(display,resource_info,windows,*image);
7553 (void) XConfigureImage(display,resource_info,windows,*image);
7554 break;
7555 }
7556 case RollCommand:
7557 {
7558 Image
7559 *roll_image;
7560
7561 static char
7562 geometry[MaxTextExtent] = "+2+2";
7563
7564 /*
7565 Query user for the roll geometry.
7566 */
7567 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7568 geometry);
7569 if (*geometry == '\0')
7570 break;
7571 /*
7572 Roll image.
7573 */
7574 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7575 XSetCursorState(display,windows,MagickTrue);
7576 XCheckRefreshWindows(display,windows);
7577 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7578 &(*image)->exception);
7579 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7580 &(*image)->exception);
7581 if (roll_image != (Image *) NULL)
7582 {
7583 *image=DestroyImage(*image);
7584 *image=roll_image;
7585 }
7586 CatchException(&(*image)->exception);
7587 XSetCursorState(display,windows,MagickFalse);
7588 if (windows->image.orphan != MagickFalse)
7589 break;
7590 windows->image.window_changes.width=(int) (*image)->columns;
7591 windows->image.window_changes.height=(int) (*image)->rows;
7592 XConfigureImageColormap(display,resource_info,windows,*image);
7593 (void) XConfigureImage(display,resource_info,windows,*image);
7594 break;
7595 }
7596 case TrimCommand:
7597 {
7598 static char
7599 fuzz[MaxTextExtent];
7600
7601 /*
7602 Query user for the fuzz factor.
7603 */
cristye7f51092010-01-17 00:39:37 +00007604 (void) FormatMagickString(fuzz,MaxTextExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007605 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007606 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7607 if (*fuzz == '\0')
7608 break;
cristyf2f27272009-12-17 14:48:46 +00007609 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007610 /*
7611 Trim image.
7612 */
7613 status=XTrimImage(display,resource_info,windows,*image);
7614 if (status == MagickFalse)
7615 {
7616 XNoticeWidget(display,windows,"Unable to trim X image",
7617 (*image)->filename);
7618 break;
7619 }
7620 break;
7621 }
7622 case HueCommand:
7623 {
7624 static char
7625 hue_percent[MaxTextExtent] = "110";
7626
7627 /*
7628 Query user for percent hue change.
7629 */
7630 (void) XDialogWidget(display,windows,"Apply",
7631 "Enter percent change in image hue (0-200):",hue_percent);
7632 if (*hue_percent == '\0')
7633 break;
7634 /*
7635 Vary the image hue.
7636 */
7637 XSetCursorState(display,windows,MagickTrue);
7638 XCheckRefreshWindows(display,windows);
7639 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7640 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7641 MaxTextExtent);
7642 (void) ModulateImage(*image,modulate_factors);
7643 XSetCursorState(display,windows,MagickFalse);
7644 if (windows->image.orphan != MagickFalse)
7645 break;
7646 XConfigureImageColormap(display,resource_info,windows,*image);
7647 (void) XConfigureImage(display,resource_info,windows,*image);
7648 break;
7649 }
7650 case SaturationCommand:
7651 {
7652 static char
7653 saturation_percent[MaxTextExtent] = "110";
7654
7655 /*
7656 Query user for percent saturation change.
7657 */
7658 (void) XDialogWidget(display,windows,"Apply",
7659 "Enter percent change in color saturation (0-200):",saturation_percent);
7660 if (*saturation_percent == '\0')
7661 break;
7662 /*
7663 Vary color saturation.
7664 */
7665 XSetCursorState(display,windows,MagickTrue);
7666 XCheckRefreshWindows(display,windows);
7667 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7668 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7669 MaxTextExtent);
7670 (void) ModulateImage(*image,modulate_factors);
7671 XSetCursorState(display,windows,MagickFalse);
7672 if (windows->image.orphan != MagickFalse)
7673 break;
7674 XConfigureImageColormap(display,resource_info,windows,*image);
7675 (void) XConfigureImage(display,resource_info,windows,*image);
7676 break;
7677 }
7678 case BrightnessCommand:
7679 {
7680 static char
7681 brightness_percent[MaxTextExtent] = "110";
7682
7683 /*
7684 Query user for percent brightness change.
7685 */
7686 (void) XDialogWidget(display,windows,"Apply",
7687 "Enter percent change in color brightness (0-200):",brightness_percent);
7688 if (*brightness_percent == '\0')
7689 break;
7690 /*
7691 Vary the color brightness.
7692 */
7693 XSetCursorState(display,windows,MagickTrue);
7694 XCheckRefreshWindows(display,windows);
7695 (void) CopyMagickString(modulate_factors,brightness_percent,
7696 MaxTextExtent);
7697 (void) ModulateImage(*image,modulate_factors);
7698 XSetCursorState(display,windows,MagickFalse);
7699 if (windows->image.orphan != MagickFalse)
7700 break;
7701 XConfigureImageColormap(display,resource_info,windows,*image);
7702 (void) XConfigureImage(display,resource_info,windows,*image);
7703 break;
7704 }
7705 case GammaCommand:
7706 {
7707 static char
7708 factor[MaxTextExtent] = "1.6";
7709
7710 /*
7711 Query user for gamma value.
7712 */
7713 (void) XDialogWidget(display,windows,"Gamma",
7714 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7715 if (*factor == '\0')
7716 break;
7717 /*
7718 Gamma correct image.
7719 */
7720 XSetCursorState(display,windows,MagickTrue);
7721 XCheckRefreshWindows(display,windows);
7722 (void) GammaImage(*image,factor);
7723 XSetCursorState(display,windows,MagickFalse);
7724 if (windows->image.orphan != MagickFalse)
7725 break;
7726 XConfigureImageColormap(display,resource_info,windows,*image);
7727 (void) XConfigureImage(display,resource_info,windows,*image);
7728 break;
7729 }
7730 case SpiffCommand:
7731 {
7732 /*
7733 Sharpen the image contrast.
7734 */
7735 XSetCursorState(display,windows,MagickTrue);
7736 XCheckRefreshWindows(display,windows);
7737 (void) ContrastImage(*image,MagickTrue);
7738 XSetCursorState(display,windows,MagickFalse);
7739 if (windows->image.orphan != MagickFalse)
7740 break;
7741 XConfigureImageColormap(display,resource_info,windows,*image);
7742 (void) XConfigureImage(display,resource_info,windows,*image);
7743 break;
7744 }
7745 case DullCommand:
7746 {
7747 /*
7748 Dull the image contrast.
7749 */
7750 XSetCursorState(display,windows,MagickTrue);
7751 XCheckRefreshWindows(display,windows);
7752 (void) ContrastImage(*image,MagickFalse);
7753 XSetCursorState(display,windows,MagickFalse);
7754 if (windows->image.orphan != MagickFalse)
7755 break;
7756 XConfigureImageColormap(display,resource_info,windows,*image);
7757 (void) XConfigureImage(display,resource_info,windows,*image);
7758 break;
7759 }
7760 case ContrastStretchCommand:
7761 {
7762 double
7763 black_point,
7764 white_point;
7765
7766 static char
7767 levels[MaxTextExtent] = "1%";
7768
7769 /*
7770 Query user for gamma value.
7771 */
7772 (void) XDialogWidget(display,windows,"Contrast Stretch",
7773 "Enter black and white points:",levels);
7774 if (*levels == '\0')
7775 break;
7776 /*
7777 Contrast stretch image.
7778 */
7779 XSetCursorState(display,windows,MagickTrue);
7780 XCheckRefreshWindows(display,windows);
7781 flags=ParseGeometry(levels,&geometry_info);
7782 black_point=geometry_info.rho;
7783 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7784 if ((flags & PercentValue) != 0)
7785 {
7786 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7787 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7788 }
7789 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7790 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7791 white_point);
7792 XSetCursorState(display,windows,MagickFalse);
7793 if (windows->image.orphan != MagickFalse)
7794 break;
7795 XConfigureImageColormap(display,resource_info,windows,*image);
7796 (void) XConfigureImage(display,resource_info,windows,*image);
7797 break;
7798 }
7799 case SigmoidalContrastCommand:
7800 {
7801 static char
7802 levels[MaxTextExtent] = "3x50%";
7803
7804 /*
7805 Query user for gamma value.
7806 */
7807 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7808 "Enter contrast and midpoint:",levels);
7809 if (*levels == '\0')
7810 break;
7811 /*
7812 Contrast stretch image.
7813 */
7814 XSetCursorState(display,windows,MagickTrue);
7815 XCheckRefreshWindows(display,windows);
7816 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
7817 XSetCursorState(display,windows,MagickFalse);
7818 if (windows->image.orphan != MagickFalse)
7819 break;
7820 XConfigureImageColormap(display,resource_info,windows,*image);
7821 (void) XConfigureImage(display,resource_info,windows,*image);
7822 break;
7823 }
7824 case NormalizeCommand:
7825 {
7826 /*
7827 Perform histogram normalization on the image.
7828 */
7829 XSetCursorState(display,windows,MagickTrue);
7830 XCheckRefreshWindows(display,windows);
7831 (void) NormalizeImage(*image);
7832 XSetCursorState(display,windows,MagickFalse);
7833 if (windows->image.orphan != MagickFalse)
7834 break;
7835 XConfigureImageColormap(display,resource_info,windows,*image);
7836 (void) XConfigureImage(display,resource_info,windows,*image);
7837 break;
7838 }
7839 case EqualizeCommand:
7840 {
7841 /*
7842 Perform histogram equalization on the image.
7843 */
7844 XSetCursorState(display,windows,MagickTrue);
7845 XCheckRefreshWindows(display,windows);
7846 (void) EqualizeImage(*image);
7847 XSetCursorState(display,windows,MagickFalse);
7848 if (windows->image.orphan != MagickFalse)
7849 break;
7850 XConfigureImageColormap(display,resource_info,windows,*image);
7851 (void) XConfigureImage(display,resource_info,windows,*image);
7852 break;
7853 }
7854 case NegateCommand:
7855 {
7856 /*
7857 Negate colors in image.
7858 */
7859 XSetCursorState(display,windows,MagickTrue);
7860 XCheckRefreshWindows(display,windows);
7861 (void) NegateImage(*image,MagickFalse);
7862 XSetCursorState(display,windows,MagickFalse);
7863 if (windows->image.orphan != MagickFalse)
7864 break;
7865 XConfigureImageColormap(display,resource_info,windows,*image);
7866 (void) XConfigureImage(display,resource_info,windows,*image);
7867 break;
7868 }
7869 case GrayscaleCommand:
7870 {
7871 /*
7872 Convert image to grayscale.
7873 */
7874 XSetCursorState(display,windows,MagickTrue);
7875 XCheckRefreshWindows(display,windows);
7876 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7877 GrayscaleType : GrayscaleMatteType);
7878 XSetCursorState(display,windows,MagickFalse);
7879 if (windows->image.orphan != MagickFalse)
7880 break;
7881 XConfigureImageColormap(display,resource_info,windows,*image);
7882 (void) XConfigureImage(display,resource_info,windows,*image);
7883 break;
7884 }
7885 case MapCommand:
7886 {
7887 Image
7888 *affinity_image;
7889
7890 static char
7891 filename[MaxTextExtent] = "\0";
7892
7893 /*
7894 Request image file name from user.
7895 */
7896 XFileBrowserWidget(display,windows,"Map",filename);
7897 if (*filename == '\0')
7898 break;
7899 /*
7900 Map image.
7901 */
7902 XSetCursorState(display,windows,MagickTrue);
7903 XCheckRefreshWindows(display,windows);
7904 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7905 affinity_image=ReadImage(image_info,&(*image)->exception);
7906 if (affinity_image != (Image *) NULL)
7907 {
7908 (void) RemapImage(&quantize_info,*image,affinity_image);
7909 affinity_image=DestroyImage(affinity_image);
7910 }
7911 CatchException(&(*image)->exception);
7912 XSetCursorState(display,windows,MagickFalse);
7913 if (windows->image.orphan != MagickFalse)
7914 break;
7915 XConfigureImageColormap(display,resource_info,windows,*image);
7916 (void) XConfigureImage(display,resource_info,windows,*image);
7917 break;
7918 }
7919 case QuantizeCommand:
7920 {
7921 int
7922 status;
7923
7924 static char
7925 colors[MaxTextExtent] = "256";
7926
7927 /*
7928 Query user for maximum number of colors.
7929 */
7930 status=XDialogWidget(display,windows,"Quantize",
7931 "Maximum number of colors:",colors);
7932 if (*colors == '\0')
7933 break;
7934 /*
7935 Color reduce the image.
7936 */
7937 XSetCursorState(display,windows,MagickTrue);
7938 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00007939 quantize_info.number_colors=StringToUnsignedLong(colors);
cristy3ed852e2009-09-05 21:47:34 +00007940 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7941 (void) QuantizeImage(&quantize_info,*image);
7942 XSetCursorState(display,windows,MagickFalse);
7943 if (windows->image.orphan != MagickFalse)
7944 break;
7945 XConfigureImageColormap(display,resource_info,windows,*image);
7946 (void) XConfigureImage(display,resource_info,windows,*image);
7947 break;
7948 }
7949 case DespeckleCommand:
7950 {
7951 Image
7952 *despeckle_image;
7953
7954 /*
7955 Despeckle image.
7956 */
7957 XSetCursorState(display,windows,MagickTrue);
7958 XCheckRefreshWindows(display,windows);
7959 despeckle_image=DespeckleImage(*image,&(*image)->exception);
7960 if (despeckle_image != (Image *) NULL)
7961 {
7962 *image=DestroyImage(*image);
7963 *image=despeckle_image;
7964 }
7965 CatchException(&(*image)->exception);
7966 XSetCursorState(display,windows,MagickFalse);
7967 if (windows->image.orphan != MagickFalse)
7968 break;
7969 XConfigureImageColormap(display,resource_info,windows,*image);
7970 (void) XConfigureImage(display,resource_info,windows,*image);
7971 break;
7972 }
7973 case EmbossCommand:
7974 {
7975 Image
7976 *emboss_image;
7977
7978 static char
7979 radius[MaxTextExtent] = "0.0x1.0";
7980
7981 /*
7982 Query user for emboss radius.
7983 */
7984 (void) XDialogWidget(display,windows,"Emboss",
7985 "Enter the emboss radius and standard deviation:",radius);
7986 if (*radius == '\0')
7987 break;
7988 /*
7989 Reduce noise in the image.
7990 */
7991 XSetCursorState(display,windows,MagickTrue);
7992 XCheckRefreshWindows(display,windows);
7993 flags=ParseGeometry(radius,&geometry_info);
7994 if ((flags & SigmaValue) == 0)
7995 geometry_info.sigma=1.0;
7996 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
7997 &(*image)->exception);
7998 if (emboss_image != (Image *) NULL)
7999 {
8000 *image=DestroyImage(*image);
8001 *image=emboss_image;
8002 }
8003 CatchException(&(*image)->exception);
8004 XSetCursorState(display,windows,MagickFalse);
8005 if (windows->image.orphan != MagickFalse)
8006 break;
8007 XConfigureImageColormap(display,resource_info,windows,*image);
8008 (void) XConfigureImage(display,resource_info,windows,*image);
8009 break;
8010 }
8011 case ReduceNoiseCommand:
8012 {
8013 Image
8014 *noise_image;
8015
8016 static char
8017 radius[MaxTextExtent] = "0";
8018
8019 /*
8020 Query user for noise radius.
8021 */
8022 (void) XDialogWidget(display,windows,"Reduce Noise",
8023 "Enter the noise radius:",radius);
8024 if (*radius == '\0')
8025 break;
8026 /*
8027 Reduce noise in the image.
8028 */
8029 XSetCursorState(display,windows,MagickTrue);
8030 XCheckRefreshWindows(display,windows);
8031 flags=ParseGeometry(radius,&geometry_info);
8032 noise_image=ReduceNoiseImage(*image,geometry_info.rho,
8033 &(*image)->exception);
8034 if (noise_image != (Image *) NULL)
8035 {
8036 *image=DestroyImage(*image);
8037 *image=noise_image;
8038 }
8039 CatchException(&(*image)->exception);
8040 XSetCursorState(display,windows,MagickFalse);
8041 if (windows->image.orphan != MagickFalse)
8042 break;
8043 XConfigureImageColormap(display,resource_info,windows,*image);
8044 (void) XConfigureImage(display,resource_info,windows,*image);
8045 break;
8046 }
8047 case AddNoiseCommand:
8048 {
8049 char
8050 **noises;
8051
8052 Image
8053 *noise_image;
8054
8055 static char
8056 noise_type[MaxTextExtent] = "Gaussian";
8057
8058 /*
8059 Add noise to the image.
8060 */
8061 noises=GetMagickOptions(MagickNoiseOptions);
8062 if (noises == (char **) NULL)
8063 break;
8064 XListBrowserWidget(display,windows,&windows->widget,
8065 (const char **) noises,"Add Noise",
8066 "Select a type of noise to add to your image:",noise_type);
8067 noises=DestroyStringList(noises);
8068 if (*noise_type == '\0')
8069 break;
8070 XSetCursorState(display,windows,MagickTrue);
8071 XCheckRefreshWindows(display,windows);
8072 noise_image=AddNoiseImage(*image,(NoiseType) ParseMagickOption(
8073 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8074 if (noise_image != (Image *) NULL)
8075 {
8076 *image=DestroyImage(*image);
8077 *image=noise_image;
8078 }
8079 CatchException(&(*image)->exception);
8080 XSetCursorState(display,windows,MagickFalse);
8081 if (windows->image.orphan != MagickFalse)
8082 break;
8083 XConfigureImageColormap(display,resource_info,windows,*image);
8084 (void) XConfigureImage(display,resource_info,windows,*image);
8085 break;
8086 }
8087 case SharpenCommand:
8088 {
8089 Image
8090 *sharp_image;
8091
8092 static char
8093 radius[MaxTextExtent] = "0.0x1.0";
8094
8095 /*
8096 Query user for sharpen radius.
8097 */
8098 (void) XDialogWidget(display,windows,"Sharpen",
8099 "Enter the sharpen radius and standard deviation:",radius);
8100 if (*radius == '\0')
8101 break;
8102 /*
8103 Sharpen image scanlines.
8104 */
8105 XSetCursorState(display,windows,MagickTrue);
8106 XCheckRefreshWindows(display,windows);
8107 flags=ParseGeometry(radius,&geometry_info);
8108 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8109 &(*image)->exception);
8110 if (sharp_image != (Image *) NULL)
8111 {
8112 *image=DestroyImage(*image);
8113 *image=sharp_image;
8114 }
8115 CatchException(&(*image)->exception);
8116 XSetCursorState(display,windows,MagickFalse);
8117 if (windows->image.orphan != MagickFalse)
8118 break;
8119 XConfigureImageColormap(display,resource_info,windows,*image);
8120 (void) XConfigureImage(display,resource_info,windows,*image);
8121 break;
8122 }
8123 case BlurCommand:
8124 {
8125 Image
8126 *blur_image;
8127
8128 static char
8129 radius[MaxTextExtent] = "0.0x1.0";
8130
8131 /*
8132 Query user for blur radius.
8133 */
8134 (void) XDialogWidget(display,windows,"Blur",
8135 "Enter the blur radius and standard deviation:",radius);
8136 if (*radius == '\0')
8137 break;
8138 /*
8139 Blur an image.
8140 */
8141 XSetCursorState(display,windows,MagickTrue);
8142 XCheckRefreshWindows(display,windows);
8143 flags=ParseGeometry(radius,&geometry_info);
8144 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8145 &(*image)->exception);
8146 if (blur_image != (Image *) NULL)
8147 {
8148 *image=DestroyImage(*image);
8149 *image=blur_image;
8150 }
8151 CatchException(&(*image)->exception);
8152 XSetCursorState(display,windows,MagickFalse);
8153 if (windows->image.orphan != MagickFalse)
8154 break;
8155 XConfigureImageColormap(display,resource_info,windows,*image);
8156 (void) XConfigureImage(display,resource_info,windows,*image);
8157 break;
8158 }
8159 case ThresholdCommand:
8160 {
8161 double
8162 threshold;
8163
8164 static char
8165 factor[MaxTextExtent] = "128";
8166
8167 /*
8168 Query user for threshold value.
8169 */
8170 (void) XDialogWidget(display,windows,"Threshold",
8171 "Enter threshold value:",factor);
8172 if (*factor == '\0')
8173 break;
8174 /*
8175 Gamma correct image.
8176 */
8177 XSetCursorState(display,windows,MagickTrue);
8178 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008179 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008180 (void) BilevelImage(*image,threshold);
8181 XSetCursorState(display,windows,MagickFalse);
8182 if (windows->image.orphan != MagickFalse)
8183 break;
8184 XConfigureImageColormap(display,resource_info,windows,*image);
8185 (void) XConfigureImage(display,resource_info,windows,*image);
8186 break;
8187 }
8188 case EdgeDetectCommand:
8189 {
8190 Image
8191 *edge_image;
8192
8193 static char
8194 radius[MaxTextExtent] = "0";
8195
8196 /*
8197 Query user for edge factor.
8198 */
8199 (void) XDialogWidget(display,windows,"Detect Edges",
8200 "Enter the edge detect radius:",radius);
8201 if (*radius == '\0')
8202 break;
8203 /*
8204 Detect edge in image.
8205 */
8206 XSetCursorState(display,windows,MagickTrue);
8207 XCheckRefreshWindows(display,windows);
8208 flags=ParseGeometry(radius,&geometry_info);
8209 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8210 if (edge_image != (Image *) NULL)
8211 {
8212 *image=DestroyImage(*image);
8213 *image=edge_image;
8214 }
8215 CatchException(&(*image)->exception);
8216 XSetCursorState(display,windows,MagickFalse);
8217 if (windows->image.orphan != MagickFalse)
8218 break;
8219 XConfigureImageColormap(display,resource_info,windows,*image);
8220 (void) XConfigureImage(display,resource_info,windows,*image);
8221 break;
8222 }
8223 case SpreadCommand:
8224 {
8225 Image
8226 *spread_image;
8227
8228 static char
8229 amount[MaxTextExtent] = "2";
8230
8231 /*
8232 Query user for spread amount.
8233 */
8234 (void) XDialogWidget(display,windows,"Spread",
8235 "Enter the displacement amount:",amount);
8236 if (*amount == '\0')
8237 break;
8238 /*
8239 Displace image pixels by a random amount.
8240 */
8241 XSetCursorState(display,windows,MagickTrue);
8242 XCheckRefreshWindows(display,windows);
8243 flags=ParseGeometry(amount,&geometry_info);
8244 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8245 if (spread_image != (Image *) NULL)
8246 {
8247 *image=DestroyImage(*image);
8248 *image=spread_image;
8249 }
8250 CatchException(&(*image)->exception);
8251 XSetCursorState(display,windows,MagickFalse);
8252 if (windows->image.orphan != MagickFalse)
8253 break;
8254 XConfigureImageColormap(display,resource_info,windows,*image);
8255 (void) XConfigureImage(display,resource_info,windows,*image);
8256 break;
8257 }
8258 case ShadeCommand:
8259 {
8260 Image
8261 *shade_image;
8262
8263 int
8264 status;
8265
8266 static char
8267 geometry[MaxTextExtent] = "30x30";
8268
8269 /*
8270 Query user for the shade geometry.
8271 */
8272 status=XDialogWidget(display,windows,"Shade",
8273 "Enter the azimuth and elevation of the light source:",geometry);
8274 if (*geometry == '\0')
8275 break;
8276 /*
8277 Shade image pixels.
8278 */
8279 XSetCursorState(display,windows,MagickTrue);
8280 XCheckRefreshWindows(display,windows);
8281 flags=ParseGeometry(geometry,&geometry_info);
8282 if ((flags & SigmaValue) == 0)
8283 geometry_info.sigma=1.0;
8284 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8285 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8286 if (shade_image != (Image *) NULL)
8287 {
8288 *image=DestroyImage(*image);
8289 *image=shade_image;
8290 }
8291 CatchException(&(*image)->exception);
8292 XSetCursorState(display,windows,MagickFalse);
8293 if (windows->image.orphan != MagickFalse)
8294 break;
8295 XConfigureImageColormap(display,resource_info,windows,*image);
8296 (void) XConfigureImage(display,resource_info,windows,*image);
8297 break;
8298 }
8299 case RaiseCommand:
8300 {
8301 static char
8302 bevel_width[MaxTextExtent] = "10";
8303
8304 /*
8305 Query user for bevel width.
8306 */
8307 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8308 if (*bevel_width == '\0')
8309 break;
8310 /*
8311 Raise an image.
8312 */
8313 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8314 XSetCursorState(display,windows,MagickTrue);
8315 XCheckRefreshWindows(display,windows);
8316 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8317 &(*image)->exception);
8318 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8319 XSetCursorState(display,windows,MagickFalse);
8320 if (windows->image.orphan != MagickFalse)
8321 break;
8322 XConfigureImageColormap(display,resource_info,windows,*image);
8323 (void) XConfigureImage(display,resource_info,windows,*image);
8324 break;
8325 }
8326 case SegmentCommand:
8327 {
8328 static char
8329 threshold[MaxTextExtent] = "1.0x1.5";
8330
8331 /*
8332 Query user for smoothing threshold.
8333 */
8334 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8335 threshold);
8336 if (*threshold == '\0')
8337 break;
8338 /*
8339 Segment an image.
8340 */
8341 XSetCursorState(display,windows,MagickTrue);
8342 XCheckRefreshWindows(display,windows);
8343 flags=ParseGeometry(threshold,&geometry_info);
8344 if ((flags & SigmaValue) == 0)
8345 geometry_info.sigma=1.0;
8346 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
8347 geometry_info.sigma);
8348 XSetCursorState(display,windows,MagickFalse);
8349 if (windows->image.orphan != MagickFalse)
8350 break;
8351 XConfigureImageColormap(display,resource_info,windows,*image);
8352 (void) XConfigureImage(display,resource_info,windows,*image);
8353 break;
8354 }
8355 case SepiaToneCommand:
8356 {
8357 double
8358 threshold;
8359
8360 Image
8361 *sepia_image;
8362
8363 static char
8364 factor[MaxTextExtent] = "80%";
8365
8366 /*
8367 Query user for sepia-tone factor.
8368 */
8369 (void) XDialogWidget(display,windows,"Sepia Tone",
8370 "Enter the sepia tone factor (0 - 99.9%):",factor);
8371 if (*factor == '\0')
8372 break;
8373 /*
8374 Sepia tone image pixels.
8375 */
8376 XSetCursorState(display,windows,MagickTrue);
8377 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008378 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008379 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8380 if (sepia_image != (Image *) NULL)
8381 {
8382 *image=DestroyImage(*image);
8383 *image=sepia_image;
8384 }
8385 CatchException(&(*image)->exception);
8386 XSetCursorState(display,windows,MagickFalse);
8387 if (windows->image.orphan != MagickFalse)
8388 break;
8389 XConfigureImageColormap(display,resource_info,windows,*image);
8390 (void) XConfigureImage(display,resource_info,windows,*image);
8391 break;
8392 }
8393 case SolarizeCommand:
8394 {
8395 double
8396 threshold;
8397
8398 static char
8399 factor[MaxTextExtent] = "60%";
8400
8401 /*
8402 Query user for solarize factor.
8403 */
8404 (void) XDialogWidget(display,windows,"Solarize",
8405 "Enter the solarize factor (0 - 99.9%):",factor);
8406 if (*factor == '\0')
8407 break;
8408 /*
8409 Solarize image pixels.
8410 */
8411 XSetCursorState(display,windows,MagickTrue);
8412 XCheckRefreshWindows(display,windows);
cristyf2f27272009-12-17 14:48:46 +00008413 threshold=SiPrefixToDouble(factor,QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00008414 (void) SolarizeImage(*image,threshold);
8415 XSetCursorState(display,windows,MagickFalse);
8416 if (windows->image.orphan != MagickFalse)
8417 break;
8418 XConfigureImageColormap(display,resource_info,windows,*image);
8419 (void) XConfigureImage(display,resource_info,windows,*image);
8420 break;
8421 }
8422 case SwirlCommand:
8423 {
8424 Image
8425 *swirl_image;
8426
8427 static char
8428 degrees[MaxTextExtent] = "60";
8429
8430 /*
8431 Query user for swirl angle.
8432 */
8433 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8434 degrees);
8435 if (*degrees == '\0')
8436 break;
8437 /*
8438 Swirl image pixels about the center.
8439 */
8440 XSetCursorState(display,windows,MagickTrue);
8441 XCheckRefreshWindows(display,windows);
8442 flags=ParseGeometry(degrees,&geometry_info);
8443 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8444 if (swirl_image != (Image *) NULL)
8445 {
8446 *image=DestroyImage(*image);
8447 *image=swirl_image;
8448 }
8449 CatchException(&(*image)->exception);
8450 XSetCursorState(display,windows,MagickFalse);
8451 if (windows->image.orphan != MagickFalse)
8452 break;
8453 XConfigureImageColormap(display,resource_info,windows,*image);
8454 (void) XConfigureImage(display,resource_info,windows,*image);
8455 break;
8456 }
8457 case ImplodeCommand:
8458 {
8459 Image
8460 *implode_image;
8461
8462 static char
8463 factor[MaxTextExtent] = "0.3";
8464
8465 /*
8466 Query user for implode factor.
8467 */
8468 (void) XDialogWidget(display,windows,"Implode",
8469 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8470 if (*factor == '\0')
8471 break;
8472 /*
8473 Implode image pixels about the center.
8474 */
8475 XSetCursorState(display,windows,MagickTrue);
8476 XCheckRefreshWindows(display,windows);
8477 flags=ParseGeometry(factor,&geometry_info);
8478 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8479 if (implode_image != (Image *) NULL)
8480 {
8481 *image=DestroyImage(*image);
8482 *image=implode_image;
8483 }
8484 CatchException(&(*image)->exception);
8485 XSetCursorState(display,windows,MagickFalse);
8486 if (windows->image.orphan != MagickFalse)
8487 break;
8488 XConfigureImageColormap(display,resource_info,windows,*image);
8489 (void) XConfigureImage(display,resource_info,windows,*image);
8490 break;
8491 }
8492 case VignetteCommand:
8493 {
8494 Image
8495 *vignette_image;
8496
8497 static char
8498 geometry[MaxTextExtent] = "0x20";
8499
8500 /*
8501 Query user for the vignette geometry.
8502 */
8503 (void) XDialogWidget(display,windows,"Vignette",
8504 "Enter the radius, sigma, and x and y offsets:",geometry);
8505 if (*geometry == '\0')
8506 break;
8507 /*
8508 Soften the edges of the image in vignette style
8509 */
8510 XSetCursorState(display,windows,MagickTrue);
8511 XCheckRefreshWindows(display,windows);
8512 flags=ParseGeometry(geometry,&geometry_info);
8513 if ((flags & SigmaValue) == 0)
8514 geometry_info.sigma=1.0;
8515 if ((flags & XiValue) == 0)
8516 geometry_info.xi=0.1*(*image)->columns;
8517 if ((flags & PsiValue) == 0)
8518 geometry_info.psi=0.1*(*image)->rows;
8519 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8520 (long) (geometry_info.xi+0.5),(long) (geometry_info.psi+0.5),
8521 &(*image)->exception);
8522 if (vignette_image != (Image *) NULL)
8523 {
8524 *image=DestroyImage(*image);
8525 *image=vignette_image;
8526 }
8527 CatchException(&(*image)->exception);
8528 XSetCursorState(display,windows,MagickFalse);
8529 if (windows->image.orphan != MagickFalse)
8530 break;
8531 XConfigureImageColormap(display,resource_info,windows,*image);
8532 (void) XConfigureImage(display,resource_info,windows,*image);
8533 break;
8534 }
8535 case WaveCommand:
8536 {
8537 Image
8538 *wave_image;
8539
8540 static char
8541 geometry[MaxTextExtent] = "25x150";
8542
8543 /*
8544 Query user for the wave geometry.
8545 */
8546 (void) XDialogWidget(display,windows,"Wave",
8547 "Enter the amplitude and length of the wave:",geometry);
8548 if (*geometry == '\0')
8549 break;
8550 /*
8551 Alter an image along a sine wave.
8552 */
8553 XSetCursorState(display,windows,MagickTrue);
8554 XCheckRefreshWindows(display,windows);
8555 flags=ParseGeometry(geometry,&geometry_info);
8556 if ((flags & SigmaValue) == 0)
8557 geometry_info.sigma=1.0;
8558 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8559 &(*image)->exception);
8560 if (wave_image != (Image *) NULL)
8561 {
8562 *image=DestroyImage(*image);
8563 *image=wave_image;
8564 }
8565 CatchException(&(*image)->exception);
8566 XSetCursorState(display,windows,MagickFalse);
8567 if (windows->image.orphan != MagickFalse)
8568 break;
8569 XConfigureImageColormap(display,resource_info,windows,*image);
8570 (void) XConfigureImage(display,resource_info,windows,*image);
8571 break;
8572 }
8573 case OilPaintCommand:
8574 {
8575 Image
8576 *paint_image;
8577
8578 static char
8579 radius[MaxTextExtent] = "0";
8580
8581 /*
8582 Query user for circular neighborhood radius.
8583 */
8584 (void) XDialogWidget(display,windows,"Oil Paint",
8585 "Enter the mask radius:",radius);
8586 if (*radius == '\0')
8587 break;
8588 /*
8589 OilPaint image scanlines.
8590 */
8591 XSetCursorState(display,windows,MagickTrue);
8592 XCheckRefreshWindows(display,windows);
8593 flags=ParseGeometry(radius,&geometry_info);
8594 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8595 if (paint_image != (Image *) NULL)
8596 {
8597 *image=DestroyImage(*image);
8598 *image=paint_image;
8599 }
8600 CatchException(&(*image)->exception);
8601 XSetCursorState(display,windows,MagickFalse);
8602 if (windows->image.orphan != MagickFalse)
8603 break;
8604 XConfigureImageColormap(display,resource_info,windows,*image);
8605 (void) XConfigureImage(display,resource_info,windows,*image);
8606 break;
8607 }
8608 case CharcoalDrawCommand:
8609 {
8610 Image
8611 *charcoal_image;
8612
8613 static char
8614 radius[MaxTextExtent] = "0x1";
8615
8616 /*
8617 Query user for charcoal radius.
8618 */
8619 (void) XDialogWidget(display,windows,"Charcoal Draw",
8620 "Enter the charcoal radius and sigma:",radius);
8621 if (*radius == '\0')
8622 break;
8623 /*
8624 Charcoal the image.
8625 */
8626 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8627 XSetCursorState(display,windows,MagickTrue);
8628 XCheckRefreshWindows(display,windows);
8629 flags=ParseGeometry(radius,&geometry_info);
8630 if ((flags & SigmaValue) == 0)
8631 geometry_info.sigma=geometry_info.rho;
8632 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8633 &(*image)->exception);
8634 if (charcoal_image != (Image *) NULL)
8635 {
8636 *image=DestroyImage(*image);
8637 *image=charcoal_image;
8638 }
8639 CatchException(&(*image)->exception);
8640 XSetCursorState(display,windows,MagickFalse);
8641 if (windows->image.orphan != MagickFalse)
8642 break;
8643 XConfigureImageColormap(display,resource_info,windows,*image);
8644 (void) XConfigureImage(display,resource_info,windows,*image);
8645 break;
8646 }
8647 case AnnotateCommand:
8648 {
8649 /*
8650 Annotate the image with text.
8651 */
8652 status=XAnnotateEditImage(display,resource_info,windows,*image);
8653 if (status == MagickFalse)
8654 {
8655 XNoticeWidget(display,windows,"Unable to annotate X image",
8656 (*image)->filename);
8657 break;
8658 }
8659 break;
8660 }
8661 case DrawCommand:
8662 {
8663 /*
8664 Draw image.
8665 */
8666 status=XDrawEditImage(display,resource_info,windows,image);
8667 if (status == MagickFalse)
8668 {
8669 XNoticeWidget(display,windows,"Unable to draw on the X image",
8670 (*image)->filename);
8671 break;
8672 }
8673 break;
8674 }
8675 case ColorCommand:
8676 {
8677 /*
8678 Color edit.
8679 */
8680 status=XColorEditImage(display,resource_info,windows,image);
8681 if (status == MagickFalse)
8682 {
8683 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8684 (*image)->filename);
8685 break;
8686 }
8687 break;
8688 }
8689 case MatteCommand:
8690 {
8691 /*
8692 Matte edit.
8693 */
8694 status=XMatteEditImage(display,resource_info,windows,image);
8695 if (status == MagickFalse)
8696 {
8697 XNoticeWidget(display,windows,"Unable to matte edit X image",
8698 (*image)->filename);
8699 break;
8700 }
8701 break;
8702 }
8703 case CompositeCommand:
8704 {
8705 /*
8706 Composite image.
8707 */
8708 status=XCompositeImage(display,resource_info,windows,*image);
8709 if (status == MagickFalse)
8710 {
8711 XNoticeWidget(display,windows,"Unable to composite X image",
8712 (*image)->filename);
8713 break;
8714 }
8715 break;
8716 }
8717 case AddBorderCommand:
8718 {
8719 Image
8720 *border_image;
8721
8722 static char
8723 geometry[MaxTextExtent] = "6x6";
8724
8725 /*
8726 Query user for border color and geometry.
8727 */
8728 XColorBrowserWidget(display,windows,"Select",color);
8729 if (*color == '\0')
8730 break;
8731 (void) XDialogWidget(display,windows,"Add Border",
8732 "Enter border geometry:",geometry);
8733 if (*geometry == '\0')
8734 break;
8735 /*
8736 Add a border to the image.
8737 */
8738 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8739 XSetCursorState(display,windows,MagickTrue);
8740 XCheckRefreshWindows(display,windows);
8741 (void) QueryColorDatabase(color,&(*image)->border_color,
8742 &(*image)->exception);
8743 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8744 &(*image)->exception);
8745 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8746 if (border_image != (Image *) NULL)
8747 {
8748 *image=DestroyImage(*image);
8749 *image=border_image;
8750 }
8751 CatchException(&(*image)->exception);
8752 XSetCursorState(display,windows,MagickFalse);
8753 if (windows->image.orphan != MagickFalse)
8754 break;
8755 windows->image.window_changes.width=(int) (*image)->columns;
8756 windows->image.window_changes.height=(int) (*image)->rows;
8757 XConfigureImageColormap(display,resource_info,windows,*image);
8758 (void) XConfigureImage(display,resource_info,windows,*image);
8759 break;
8760 }
8761 case AddFrameCommand:
8762 {
8763 FrameInfo
8764 frame_info;
8765
8766 Image
8767 *frame_image;
8768
8769 static char
8770 geometry[MaxTextExtent] = "6x6";
8771
8772 /*
8773 Query user for frame color and geometry.
8774 */
8775 XColorBrowserWidget(display,windows,"Select",color);
8776 if (*color == '\0')
8777 break;
8778 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8779 geometry);
8780 if (*geometry == '\0')
8781 break;
8782 /*
8783 Surround image with an ornamental border.
8784 */
8785 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8786 XSetCursorState(display,windows,MagickTrue);
8787 XCheckRefreshWindows(display,windows);
8788 (void) QueryColorDatabase(color,&(*image)->matte_color,
8789 &(*image)->exception);
8790 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8791 &(*image)->exception);
8792 frame_info.width=page_geometry.width;
8793 frame_info.height=page_geometry.height;
8794 frame_info.outer_bevel=page_geometry.x;
8795 frame_info.inner_bevel=page_geometry.y;
8796 frame_info.x=(long) frame_info.width;
8797 frame_info.y=(long) frame_info.height;
8798 frame_info.width=(*image)->columns+2*frame_info.width;
8799 frame_info.height=(*image)->rows+2*frame_info.height;
8800 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8801 if (frame_image != (Image *) NULL)
8802 {
8803 *image=DestroyImage(*image);
8804 *image=frame_image;
8805 }
8806 CatchException(&(*image)->exception);
8807 XSetCursorState(display,windows,MagickFalse);
8808 if (windows->image.orphan != MagickFalse)
8809 break;
8810 windows->image.window_changes.width=(int) (*image)->columns;
8811 windows->image.window_changes.height=(int) (*image)->rows;
8812 XConfigureImageColormap(display,resource_info,windows,*image);
8813 (void) XConfigureImage(display,resource_info,windows,*image);
8814 break;
8815 }
8816 case CommentCommand:
8817 {
8818 const char
8819 *value;
8820
8821 FILE
8822 *file;
8823
8824 int
8825 unique_file;
8826
8827 /*
8828 Edit image comment.
8829 */
8830 unique_file=AcquireUniqueFileResource(image_info->filename);
8831 if (unique_file == -1)
8832 XNoticeWidget(display,windows,"Unable to edit image comment",
8833 image_info->filename);
8834 value=GetImageProperty(*image,"comment");
8835 if (value == (char *) NULL)
8836 unique_file=close(unique_file)-1;
8837 else
8838 {
8839 register const char
8840 *p;
8841
8842 file=fdopen(unique_file,"w");
8843 if (file == (FILE *) NULL)
8844 {
8845 XNoticeWidget(display,windows,"Unable to edit image comment",
8846 image_info->filename);
8847 break;
8848 }
8849 for (p=value; *p != '\0'; p++)
8850 (void) fputc((int) *p,file);
8851 (void) fputc('\n',file);
8852 (void) fclose(file);
8853 }
8854 XSetCursorState(display,windows,MagickTrue);
8855 XCheckRefreshWindows(display,windows);
8856 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8857 &(*image)->exception);
8858 if (status == MagickFalse)
8859 XNoticeWidget(display,windows,"Unable to edit image comment",
8860 (char *) NULL);
8861 else
8862 {
8863 char
8864 *comment;
8865
8866 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8867 if (comment != (char *) NULL)
8868 {
8869 (void) SetImageProperty(*image,"comment",comment);
8870 (*image)->taint=MagickTrue;
8871 }
8872 }
8873 (void) RelinquishUniqueFileResource(image_info->filename);
8874 XSetCursorState(display,windows,MagickFalse);
8875 break;
8876 }
8877 case LaunchCommand:
8878 {
8879 /*
8880 Launch program.
8881 */
8882 XSetCursorState(display,windows,MagickTrue);
8883 XCheckRefreshWindows(display,windows);
8884 (void) AcquireUniqueFilename(filename);
8885 (void) FormatMagickString((*image)->filename,MaxTextExtent,"launch:%s",
8886 filename);
8887 status=WriteImage(image_info,*image);
8888 if (status == MagickFalse)
8889 XNoticeWidget(display,windows,"Unable to launch image editor",
8890 (char *) NULL);
8891 else
8892 {
8893 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8894 CatchException(&(*image)->exception);
8895 XClientMessage(display,windows->image.id,windows->im_protocols,
8896 windows->im_next_image,CurrentTime);
8897 }
8898 (void) RelinquishUniqueFileResource(filename);
8899 XSetCursorState(display,windows,MagickFalse);
8900 break;
8901 }
8902 case RegionofInterestCommand:
8903 {
8904 /*
8905 Apply an image processing technique to a region of interest.
8906 */
8907 (void) XROIImage(display,resource_info,windows,image);
8908 break;
8909 }
8910 case InfoCommand:
8911 break;
8912 case ZoomCommand:
8913 {
8914 /*
8915 Zoom image.
8916 */
8917 if (windows->magnify.mapped != MagickFalse)
8918 (void) XRaiseWindow(display,windows->magnify.id);
8919 else
8920 {
8921 /*
8922 Make magnify image.
8923 */
8924 XSetCursorState(display,windows,MagickTrue);
8925 (void) XMapRaised(display,windows->magnify.id);
8926 XSetCursorState(display,windows,MagickFalse);
8927 }
8928 break;
8929 }
8930 case ShowPreviewCommand:
8931 {
8932 char
8933 **previews;
8934
8935 Image
8936 *preview_image;
8937
8938 static char
8939 preview_type[MaxTextExtent] = "Gamma";
8940
8941 /*
8942 Select preview type from menu.
8943 */
8944 previews=GetMagickOptions(MagickPreviewOptions);
8945 if (previews == (char **) NULL)
8946 break;
8947 XListBrowserWidget(display,windows,&windows->widget,
8948 (const char **) previews,"Preview",
8949 "Select an enhancement, effect, or F/X:",preview_type);
8950 previews=DestroyStringList(previews);
8951 if (*preview_type == '\0')
8952 break;
8953 /*
8954 Show image preview.
8955 */
8956 XSetCursorState(display,windows,MagickTrue);
8957 XCheckRefreshWindows(display,windows);
8958 image_info->preview_type=(PreviewType)
8959 ParseMagickOption(MagickPreviewOptions,MagickFalse,preview_type);
8960 image_info->group=(long) windows->image.id;
8961 (void) DeleteImageProperty(*image,"label");
8962 (void) SetImageProperty(*image,"label","Preview");
8963 (void) AcquireUniqueFilename(filename);
8964 (void) FormatMagickString((*image)->filename,MaxTextExtent,"preview:%s",
8965 filename);
8966 status=WriteImage(image_info,*image);
8967 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
8968 preview_image=ReadImage(image_info,&(*image)->exception);
8969 (void) RelinquishUniqueFileResource(filename);
8970 if (preview_image == (Image *) NULL)
8971 break;
8972 (void) FormatMagickString(preview_image->filename,MaxTextExtent,"show:%s",
8973 filename);
8974 status=WriteImage(image_info,preview_image);
8975 preview_image=DestroyImage(preview_image);
8976 if (status == MagickFalse)
8977 XNoticeWidget(display,windows,"Unable to show image preview",
8978 (*image)->filename);
8979 XDelay(display,1500);
8980 XSetCursorState(display,windows,MagickFalse);
8981 break;
8982 }
8983 case ShowHistogramCommand:
8984 {
8985 Image
8986 *histogram_image;
8987
8988 /*
8989 Show image histogram.
8990 */
8991 XSetCursorState(display,windows,MagickTrue);
8992 XCheckRefreshWindows(display,windows);
8993 image_info->group=(long) windows->image.id;
8994 (void) DeleteImageProperty(*image,"label");
8995 (void) SetImageProperty(*image,"label","Histogram");
8996 (void) AcquireUniqueFilename(filename);
8997 (void) FormatMagickString((*image)->filename,MaxTextExtent,"histogram:%s",
8998 filename);
8999 status=WriteImage(image_info,*image);
9000 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9001 histogram_image=ReadImage(image_info,&(*image)->exception);
9002 (void) RelinquishUniqueFileResource(filename);
9003 if (histogram_image == (Image *) NULL)
9004 break;
9005 (void) FormatMagickString(histogram_image->filename,MaxTextExtent,
9006 "show:%s",filename);
9007 status=WriteImage(image_info,histogram_image);
9008 histogram_image=DestroyImage(histogram_image);
9009 if (status == MagickFalse)
9010 XNoticeWidget(display,windows,"Unable to show histogram",
9011 (*image)->filename);
9012 XDelay(display,1500);
9013 XSetCursorState(display,windows,MagickFalse);
9014 break;
9015 }
9016 case ShowMatteCommand:
9017 {
9018 Image
9019 *matte_image;
9020
9021 if ((*image)->matte == MagickFalse)
9022 {
9023 XNoticeWidget(display,windows,
9024 "Image does not have any matte information",(*image)->filename);
9025 break;
9026 }
9027 /*
9028 Show image matte.
9029 */
9030 XSetCursorState(display,windows,MagickTrue);
9031 XCheckRefreshWindows(display,windows);
9032 image_info->group=(long) windows->image.id;
9033 (void) DeleteImageProperty(*image,"label");
9034 (void) SetImageProperty(*image,"label","Matte");
9035 (void) AcquireUniqueFilename(filename);
9036 (void) FormatMagickString((*image)->filename,MaxTextExtent,"matte:%s",
9037 filename);
9038 status=WriteImage(image_info,*image);
9039 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9040 matte_image=ReadImage(image_info,&(*image)->exception);
9041 (void) RelinquishUniqueFileResource(filename);
9042 if (matte_image == (Image *) NULL)
9043 break;
9044 (void) FormatMagickString(matte_image->filename,MaxTextExtent,"show:%s",
9045 filename);
9046 status=WriteImage(image_info,matte_image);
9047 matte_image=DestroyImage(matte_image);
9048 if (status == MagickFalse)
9049 XNoticeWidget(display,windows,"Unable to show matte",
9050 (*image)->filename);
9051 XDelay(display,1500);
9052 XSetCursorState(display,windows,MagickFalse);
9053 break;
9054 }
9055 case BackgroundCommand:
9056 {
9057 /*
9058 Background image.
9059 */
9060 status=XBackgroundImage(display,resource_info,windows,image);
9061 if (status == MagickFalse)
9062 break;
9063 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9064 if (nexus != (Image *) NULL)
9065 XClientMessage(display,windows->image.id,windows->im_protocols,
9066 windows->im_next_image,CurrentTime);
9067 break;
9068 }
9069 case SlideShowCommand:
9070 {
9071 static char
9072 delay[MaxTextExtent] = "5";
9073
9074 /*
9075 Display next image after pausing.
9076 */
9077 (void) XDialogWidget(display,windows,"Slide Show",
9078 "Pause how many 1/100ths of a second between images:",delay);
9079 if (*delay == '\0')
9080 break;
cristye27293e2009-12-18 02:53:20 +00009081 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009082 XClientMessage(display,windows->image.id,windows->im_protocols,
9083 windows->im_next_image,CurrentTime);
9084 break;
9085 }
9086 case PreferencesCommand:
9087 {
9088 /*
9089 Set user preferences.
9090 */
9091 status=XPreferencesWidget(display,resource_info,windows);
9092 if (status == MagickFalse)
9093 break;
9094 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9095 if (nexus != (Image *) NULL)
9096 XClientMessage(display,windows->image.id,windows->im_protocols,
9097 windows->im_next_image,CurrentTime);
9098 break;
9099 }
9100 case HelpCommand:
9101 {
9102 /*
9103 User requested help.
9104 */
9105 XTextViewWidget(display,resource_info,windows,MagickFalse,
9106 "Help Viewer - Display",DisplayHelp);
9107 break;
9108 }
9109 case BrowseDocumentationCommand:
9110 {
9111 Atom
9112 mozilla_atom;
9113
9114 Window
9115 mozilla_window,
9116 root_window;
9117
9118 /*
9119 Browse the ImageMagick documentation.
9120 */
9121 root_window=XRootWindow(display,XDefaultScreen(display));
9122 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9123 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9124 if (mozilla_window != (Window) NULL)
9125 {
9126 char
9127 command[MaxTextExtent],
9128 *url;
9129
9130 /*
9131 Display documentation using Netscape remote control.
9132 */
9133 url=GetMagickHomeURL();
9134 (void) FormatMagickString(command,MaxTextExtent,
9135 "openurl(%s,new-tab)",url);
9136 url=DestroyString(url);
9137 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9138 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9139 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9140 XSetCursorState(display,windows,MagickFalse);
9141 break;
9142 }
9143 XSetCursorState(display,windows,MagickTrue);
9144 XCheckRefreshWindows(display,windows);
9145 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9146 &(*image)->exception);
9147 if (status == MagickFalse)
9148 XNoticeWidget(display,windows,"Unable to browse documentation",
9149 (char *) NULL);
9150 XDelay(display,1500);
9151 XSetCursorState(display,windows,MagickFalse);
9152 break;
9153 }
9154 case VersionCommand:
9155 {
9156 XNoticeWidget(display,windows,GetMagickVersion((unsigned long *) NULL),
9157 GetMagickCopyright());
9158 break;
9159 }
9160 case SaveToUndoBufferCommand:
9161 break;
9162 default:
9163 {
9164 (void) XBell(display,0);
9165 break;
9166 }
9167 }
9168 image_info=DestroyImageInfo(image_info);
9169 return(nexus);
9170}
9171
9172/*
9173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9174% %
9175% %
9176% %
9177+ X M a g n i f y I m a g e %
9178% %
9179% %
9180% %
9181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9182%
9183% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9184% The magnified portion is displayed in a separate window.
9185%
9186% The format of the XMagnifyImage method is:
9187%
9188% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9189%
9190% A description of each parameter follows:
9191%
9192% o display: Specifies a connection to an X server; returned from
9193% XOpenDisplay.
9194%
9195% o windows: Specifies a pointer to a XWindows structure.
9196%
9197% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9198% the entire image is refreshed.
9199%
9200*/
9201static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9202{
9203 char
9204 text[MaxTextExtent];
9205
9206 register int
9207 x,
9208 y;
9209
9210 unsigned long
9211 state;
9212
9213 /*
9214 Update magnified image until the mouse button is released.
9215 */
9216 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9217 state=DefaultState;
9218 x=event->xbutton.x;
9219 y=event->xbutton.y;
9220 windows->magnify.x=windows->image.x+x;
9221 windows->magnify.y=windows->image.y+y;
9222 do
9223 {
9224 /*
9225 Map and unmap Info widget as text cursor crosses its boundaries.
9226 */
9227 if (windows->info.mapped != MagickFalse)
9228 {
9229 if ((x < (int) (windows->info.x+windows->info.width)) &&
9230 (y < (int) (windows->info.y+windows->info.height)))
9231 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9232 }
9233 else
9234 if ((x > (int) (windows->info.x+windows->info.width)) ||
9235 (y > (int) (windows->info.y+windows->info.height)))
9236 (void) XMapWindow(display,windows->info.id);
9237 if (windows->info.mapped != MagickFalse)
9238 {
9239 /*
9240 Display pointer position.
9241 */
9242 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9243 windows->magnify.x,windows->magnify.y);
9244 XInfoWidget(display,windows,text);
9245 }
9246 /*
9247 Wait for next event.
9248 */
9249 XScreenEvent(display,windows,event);
9250 switch (event->type)
9251 {
9252 case ButtonPress:
9253 break;
9254 case ButtonRelease:
9255 {
9256 /*
9257 User has finished magnifying image.
9258 */
9259 x=event->xbutton.x;
9260 y=event->xbutton.y;
9261 state|=ExitState;
9262 break;
9263 }
9264 case Expose:
9265 break;
9266 case MotionNotify:
9267 {
9268 x=event->xmotion.x;
9269 y=event->xmotion.y;
9270 break;
9271 }
9272 default:
9273 break;
9274 }
9275 /*
9276 Check boundary conditions.
9277 */
9278 if (x < 0)
9279 x=0;
9280 else
9281 if (x >= (int) windows->image.width)
9282 x=(int) windows->image.width-1;
9283 if (y < 0)
9284 y=0;
9285 else
9286 if (y >= (int) windows->image.height)
9287 y=(int) windows->image.height-1;
9288 } while ((state & ExitState) == 0);
9289 /*
9290 Display magnified image.
9291 */
9292 XSetCursorState(display,windows,MagickFalse);
9293}
9294
9295/*
9296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9297% %
9298% %
9299% %
9300+ X M a g n i f y W i n d o w C o m m a n d %
9301% %
9302% %
9303% %
9304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9305%
9306% XMagnifyWindowCommand() moves the image within an Magnify window by one
9307% pixel as specified by the key symbol.
9308%
9309% The format of the XMagnifyWindowCommand method is:
9310%
9311% void XMagnifyWindowCommand(Display *display,XWindows *windows,
9312% const MagickStatusType state,const KeySym key_symbol)
9313%
9314% A description of each parameter follows:
9315%
9316% o display: Specifies a connection to an X server; returned from
9317% XOpenDisplay.
9318%
9319% o windows: Specifies a pointer to a XWindows structure.
9320%
9321% o state: key mask.
9322%
9323% o key_symbol: Specifies a KeySym which indicates which side of the image
9324% to trim.
9325%
9326*/
9327static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9328 const MagickStatusType state,const KeySym key_symbol)
9329{
9330 unsigned int
9331 quantum;
9332
9333 /*
9334 User specified a magnify factor or position.
9335 */
9336 quantum=1;
9337 if ((state & Mod1Mask) != 0)
9338 quantum=10;
9339 switch ((int) key_symbol)
9340 {
9341 case QuitCommand:
9342 {
9343 (void) XWithdrawWindow(display,windows->magnify.id,
9344 windows->magnify.screen);
9345 break;
9346 }
9347 case XK_Home:
9348 case XK_KP_Home:
9349 {
9350 windows->magnify.x=(int) windows->image.width/2;
9351 windows->magnify.y=(int) windows->image.height/2;
9352 break;
9353 }
9354 case XK_Left:
9355 case XK_KP_Left:
9356 {
9357 if (windows->magnify.x > 0)
9358 windows->magnify.x-=quantum;
9359 break;
9360 }
9361 case XK_Up:
9362 case XK_KP_Up:
9363 {
9364 if (windows->magnify.y > 0)
9365 windows->magnify.y-=quantum;
9366 break;
9367 }
9368 case XK_Right:
9369 case XK_KP_Right:
9370 {
9371 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9372 windows->magnify.x+=quantum;
9373 break;
9374 }
9375 case XK_Down:
9376 case XK_KP_Down:
9377 {
9378 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9379 windows->magnify.y+=quantum;
9380 break;
9381 }
9382 case XK_0:
9383 case XK_1:
9384 case XK_2:
9385 case XK_3:
9386 case XK_4:
9387 case XK_5:
9388 case XK_6:
9389 case XK_7:
9390 case XK_8:
9391 case XK_9:
9392 {
9393 windows->magnify.data=(key_symbol-XK_0);
9394 break;
9395 }
9396 case XK_KP_0:
9397 case XK_KP_1:
9398 case XK_KP_2:
9399 case XK_KP_3:
9400 case XK_KP_4:
9401 case XK_KP_5:
9402 case XK_KP_6:
9403 case XK_KP_7:
9404 case XK_KP_8:
9405 case XK_KP_9:
9406 {
9407 windows->magnify.data=(key_symbol-XK_KP_0);
9408 break;
9409 }
9410 default:
9411 break;
9412 }
9413 XMakeMagnifyImage(display,windows);
9414}
9415
9416/*
9417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9418% %
9419% %
9420% %
9421+ X M a k e P a n I m a g e %
9422% %
9423% %
9424% %
9425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9426%
9427% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9428% icon window.
9429%
9430% The format of the XMakePanImage method is:
9431%
9432% void XMakePanImage(Display *display,XResourceInfo *resource_info,
9433% XWindows *windows,Image *image)
9434%
9435% A description of each parameter follows:
9436%
9437% o display: Specifies a connection to an X server; returned from
9438% XOpenDisplay.
9439%
9440% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9441%
9442% o windows: Specifies a pointer to a XWindows structure.
9443%
9444% o image: the image.
9445%
9446*/
9447static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9448 XWindows *windows,Image *image)
9449{
9450 MagickStatusType
9451 status;
9452
9453 /*
9454 Create and display image for panning icon.
9455 */
9456 XSetCursorState(display,windows,MagickTrue);
9457 XCheckRefreshWindows(display,windows);
9458 windows->pan.x=windows->image.x;
9459 windows->pan.y=windows->image.y;
9460 status=XMakeImage(display,resource_info,&windows->pan,image,
9461 windows->pan.width,windows->pan.height);
9462 if (status == MagickFalse)
9463 ThrowXWindowFatalException(XServerError,image->exception.reason,
9464 image->exception.description);
9465 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9466 windows->pan.pixmap);
9467 (void) XClearWindow(display,windows->pan.id);
9468 XDrawPanRectangle(display,windows);
9469 XSetCursorState(display,windows,MagickFalse);
9470}
9471
9472/*
9473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9474% %
9475% %
9476% %
9477+ X M a t t a E d i t I m a g e %
9478% %
9479% %
9480% %
9481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9482%
9483% XMatteEditImage() allows the user to interactively change the Matte channel
9484% of an image. If the image is PseudoClass it is promoted to DirectClass
9485% before the matte information is stored.
9486%
9487% The format of the XMatteEditImage method is:
9488%
9489% MagickBooleanType XMatteEditImage(Display *display,
9490% XResourceInfo *resource_info,XWindows *windows,Image **image)
9491%
9492% A description of each parameter follows:
9493%
9494% o display: Specifies a connection to an X server; returned from
9495% XOpenDisplay.
9496%
9497% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9498%
9499% o windows: Specifies a pointer to a XWindows structure.
9500%
9501% o image: the image; returned from ReadImage.
9502%
9503*/
9504static MagickBooleanType XMatteEditImage(Display *display,
9505 XResourceInfo *resource_info,XWindows *windows,Image **image)
9506{
9507 static char
9508 matte[MaxTextExtent] = "0";
9509
9510 static const char
9511 *MatteEditMenu[] =
9512 {
9513 "Method",
9514 "Border Color",
9515 "Fuzz",
9516 "Matte Value",
9517 "Undo",
9518 "Help",
9519 "Dismiss",
9520 (char *) NULL
9521 };
9522
9523 static const ModeType
9524 MatteEditCommands[] =
9525 {
9526 MatteEditMethod,
9527 MatteEditBorderCommand,
9528 MatteEditFuzzCommand,
9529 MatteEditValueCommand,
9530 MatteEditUndoCommand,
9531 MatteEditHelpCommand,
9532 MatteEditDismissCommand
9533 };
9534
9535 static PaintMethod
9536 method = PointMethod;
9537
9538 static XColor
9539 border_color = { 0, 0, 0, 0, 0, 0 };
9540
9541 char
9542 command[MaxTextExtent],
9543 text[MaxTextExtent];
9544
9545 Cursor
9546 cursor;
9547
9548 int
9549 entry,
9550 id,
9551 x,
9552 x_offset,
9553 y,
9554 y_offset;
9555
9556 register int
9557 i;
9558
9559 register PixelPacket
9560 *q;
9561
9562 unsigned int
9563 height,
9564 width;
9565
9566 unsigned long
9567 state;
9568
9569 XEvent
9570 event;
9571
9572 /*
9573 Map Command widget.
9574 */
9575 (void) CloneString(&windows->command.name,"Matte Edit");
9576 windows->command.data=4;
9577 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9578 (void) XMapRaised(display,windows->command.id);
9579 XClientMessage(display,windows->image.id,windows->im_protocols,
9580 windows->im_update_widget,CurrentTime);
9581 /*
9582 Make cursor.
9583 */
9584 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9585 resource_info->background_color,resource_info->foreground_color);
9586 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9587 /*
9588 Track pointer until button 1 is pressed.
9589 */
9590 XQueryPosition(display,windows->image.id,&x,&y);
9591 (void) XSelectInput(display,windows->image.id,
9592 windows->image.attributes.event_mask | PointerMotionMask);
9593 state=DefaultState;
9594 do
9595 {
9596 if (windows->info.mapped != MagickFalse)
9597 {
9598 /*
9599 Display pointer position.
9600 */
9601 (void) FormatMagickString(text,MaxTextExtent," %+d%+d ",
9602 x+windows->image.x,y+windows->image.y);
9603 XInfoWidget(display,windows,text);
9604 }
9605 /*
9606 Wait for next event.
9607 */
9608 XScreenEvent(display,windows,&event);
9609 if (event.xany.window == windows->command.id)
9610 {
9611 /*
9612 Select a command from the Command widget.
9613 */
9614 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9615 if (id < 0)
9616 {
9617 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9618 continue;
9619 }
9620 switch (MatteEditCommands[id])
9621 {
9622 case MatteEditMethod:
9623 {
9624 char
9625 **methods;
9626
9627 /*
9628 Select a method from the pop-up menu.
9629 */
9630 methods=GetMagickOptions(MagickMethodOptions);
9631 if (methods == (char **) NULL)
9632 break;
9633 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9634 (const char **) methods,command);
9635 if (entry >= 0)
9636 method=(PaintMethod) ParseMagickOption(MagickMethodOptions,
9637 MagickFalse,methods[entry]);
9638 methods=DestroyStringList(methods);
9639 break;
9640 }
9641 case MatteEditBorderCommand:
9642 {
9643 const char
9644 *ColorMenu[MaxNumberPens];
9645
9646 int
9647 pen_number;
9648
9649 /*
9650 Initialize menu selections.
9651 */
9652 for (i=0; i < (int) (MaxNumberPens-2); i++)
9653 ColorMenu[i]=resource_info->pen_colors[i];
9654 ColorMenu[MaxNumberPens-2]="Browser...";
9655 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9656 /*
9657 Select a pen color from the pop-up menu.
9658 */
9659 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9660 (const char **) ColorMenu,command);
9661 if (pen_number < 0)
9662 break;
9663 if (pen_number == (MaxNumberPens-2))
9664 {
9665 static char
9666 color_name[MaxTextExtent] = "gray";
9667
9668 /*
9669 Select a pen color from a dialog.
9670 */
9671 resource_info->pen_colors[pen_number]=color_name;
9672 XColorBrowserWidget(display,windows,"Select",color_name);
9673 if (*color_name == '\0')
9674 break;
9675 }
9676 /*
9677 Set border color.
9678 */
9679 (void) XParseColor(display,windows->map_info->colormap,
9680 resource_info->pen_colors[pen_number],&border_color);
9681 break;
9682 }
9683 case MatteEditFuzzCommand:
9684 {
9685 static char
9686 fuzz[MaxTextExtent];
9687
9688 static const char
9689 *FuzzMenu[] =
9690 {
9691 "0%",
9692 "2%",
9693 "5%",
9694 "10%",
9695 "15%",
9696 "Dialog...",
9697 (char *) NULL,
9698 };
9699
9700 /*
9701 Select a command from the pop-up menu.
9702 */
9703 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9704 command);
9705 if (entry < 0)
9706 break;
9707 if (entry != 5)
9708 {
cristyf2f27272009-12-17 14:48:46 +00009709 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*QuantumRange+
cristy3ed852e2009-09-05 21:47:34 +00009710 1.0);
9711 break;
9712 }
9713 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9714 (void) XDialogWidget(display,windows,"Ok",
9715 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9716 if (*fuzz == '\0')
9717 break;
9718 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristyf2f27272009-12-17 14:48:46 +00009719 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009720 break;
9721 }
9722 case MatteEditValueCommand:
9723 {
9724 static char
9725 message[MaxTextExtent];
9726
9727 static const char
9728 *MatteMenu[] =
9729 {
9730 "Opaque",
9731 "Transparent",
9732 "Dialog...",
9733 (char *) NULL,
9734 };
9735
9736 /*
9737 Select a command from the pop-up menu.
9738 */
9739 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9740 command);
9741 if (entry < 0)
9742 break;
9743 if (entry != 2)
9744 {
9745 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9746 OpaqueOpacity);
9747 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9748 (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
9749 (Quantum) TransparentOpacity);
9750 break;
9751 }
9752 (void) FormatMagickString(message,MaxTextExtent,
9753 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9754 QuantumRange);
9755 (void) XDialogWidget(display,windows,"Matte",message,matte);
9756 if (*matte == '\0')
9757 break;
9758 break;
9759 }
9760 case MatteEditUndoCommand:
9761 {
9762 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9763 image);
9764 break;
9765 }
9766 case MatteEditHelpCommand:
9767 {
9768 XTextViewWidget(display,resource_info,windows,MagickFalse,
9769 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9770 break;
9771 }
9772 case MatteEditDismissCommand:
9773 {
9774 /*
9775 Prematurely exit.
9776 */
9777 state|=EscapeState;
9778 state|=ExitState;
9779 break;
9780 }
9781 default:
9782 break;
9783 }
9784 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9785 continue;
9786 }
9787 switch (event.type)
9788 {
9789 case ButtonPress:
9790 {
9791 if (event.xbutton.button != Button1)
9792 break;
9793 if ((event.xbutton.window != windows->image.id) &&
9794 (event.xbutton.window != windows->magnify.id))
9795 break;
9796 /*
9797 Update matte data.
9798 */
9799 x=event.xbutton.x;
9800 y=event.xbutton.y;
9801 (void) XMagickCommand(display,resource_info,windows,
9802 SaveToUndoBufferCommand,image);
9803 state|=UpdateConfigurationState;
9804 break;
9805 }
9806 case ButtonRelease:
9807 {
9808 if (event.xbutton.button != Button1)
9809 break;
9810 if ((event.xbutton.window != windows->image.id) &&
9811 (event.xbutton.window != windows->magnify.id))
9812 break;
9813 /*
9814 Update colormap information.
9815 */
9816 x=event.xbutton.x;
9817 y=event.xbutton.y;
9818 XConfigureImageColormap(display,resource_info,windows,*image);
9819 (void) XConfigureImage(display,resource_info,windows,*image);
9820 XInfoWidget(display,windows,text);
9821 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9822 state&=(~UpdateConfigurationState);
9823 break;
9824 }
9825 case Expose:
9826 break;
9827 case KeyPress:
9828 {
9829 char
9830 command[MaxTextExtent];
9831
9832 KeySym
9833 key_symbol;
9834
9835 if (event.xkey.window == windows->magnify.id)
9836 {
9837 Window
9838 window;
9839
9840 window=windows->magnify.id;
9841 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9842 }
9843 if (event.xkey.window != windows->image.id)
9844 break;
9845 /*
9846 Respond to a user key press.
9847 */
9848 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9849 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9850 switch ((int) key_symbol)
9851 {
9852 case XK_Escape:
9853 case XK_F20:
9854 {
9855 /*
9856 Prematurely exit.
9857 */
9858 state|=ExitState;
9859 break;
9860 }
9861 case XK_F1:
9862 case XK_Help:
9863 {
9864 XTextViewWidget(display,resource_info,windows,MagickFalse,
9865 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9866 break;
9867 }
9868 default:
9869 {
9870 (void) XBell(display,0);
9871 break;
9872 }
9873 }
9874 break;
9875 }
9876 case MotionNotify:
9877 {
9878 /*
9879 Map and unmap Info widget as cursor crosses its boundaries.
9880 */
9881 x=event.xmotion.x;
9882 y=event.xmotion.y;
9883 if (windows->info.mapped != MagickFalse)
9884 {
9885 if ((x < (int) (windows->info.x+windows->info.width)) &&
9886 (y < (int) (windows->info.y+windows->info.height)))
9887 (void) XWithdrawWindow(display,windows->info.id,
9888 windows->info.screen);
9889 }
9890 else
9891 if ((x > (int) (windows->info.x+windows->info.width)) ||
9892 (y > (int) (windows->info.y+windows->info.height)))
9893 (void) XMapWindow(display,windows->info.id);
9894 break;
9895 }
9896 default:
9897 break;
9898 }
9899 if (event.xany.window == windows->magnify.id)
9900 {
9901 x=windows->magnify.x-windows->image.x;
9902 y=windows->magnify.y-windows->image.y;
9903 }
9904 x_offset=x;
9905 y_offset=y;
9906 if ((state & UpdateConfigurationState) != 0)
9907 {
9908 ExceptionInfo
9909 *exception;
9910
9911 int
9912 x,
9913 y;
9914
9915 /*
9916 Matte edit is relative to image configuration.
9917 */
9918 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9919 MagickTrue);
9920 XPutPixel(windows->image.ximage,x_offset,y_offset,
9921 windows->pixel_info->background_color.pixel);
9922 width=(unsigned int) (*image)->columns;
9923 height=(unsigned int) (*image)->rows;
9924 x=0;
9925 y=0;
9926 if (windows->image.crop_geometry != (char *) NULL)
9927 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9928 &width,&height);
9929 x_offset=(int)
9930 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9931 y_offset=(int)
9932 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9933 if ((x_offset < 0) || (y_offset < 0))
9934 continue;
9935 if ((x_offset >= (int) (*image)->columns) ||
9936 (y_offset >= (int) (*image)->rows))
9937 continue;
9938 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9939 return(MagickFalse);
9940 (*image)->matte=MagickTrue;
9941 exception=(&(*image)->exception);
9942 switch (method)
9943 {
9944 case PointMethod:
9945 default:
9946 {
9947 /*
9948 Update matte information using point algorithm.
9949 */
9950 q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
9951 if (q == (PixelPacket *) NULL)
9952 break;
cristyf2f27272009-12-17 14:48:46 +00009953 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +00009954 (void) SyncAuthenticPixels(*image,exception);
9955 break;
9956 }
9957 case ReplaceMethod:
9958 {
9959 PixelPacket
9960 target;
9961
9962 /*
9963 Update matte information using replace algorithm.
9964 */
9965 (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
9966 exception);
9967 for (y=0; y < (long) (*image)->rows; y++)
9968 {
9969 q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,
9970 &(*image)->exception);
9971 if (q == (PixelPacket *) NULL)
9972 break;
9973 for (x=0; x < (int) (*image)->columns; x++)
9974 {
9975 if (IsColorSimilar(*image,q,&target))
cristyf2f27272009-12-17 14:48:46 +00009976 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +00009977 q++;
9978 }
9979 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
9980 break;
9981 }
9982 break;
9983 }
9984 case FloodfillMethod:
9985 case FillToBorderMethod:
9986 {
9987 DrawInfo
9988 *draw_info;
9989
9990 MagickPixelPacket
9991 target;
9992
9993 /*
9994 Update matte information using floodfill algorithm.
9995 */
9996 (void) GetOneVirtualMagickPixel(*image,x_offset,y_offset,&target,
9997 exception);
9998 if (method == FillToBorderMethod)
9999 {
10000 target.red=(MagickRealType)
10001 ScaleShortToQuantum(border_color.red);
10002 target.green=(MagickRealType)
10003 ScaleShortToQuantum(border_color.green);
10004 target.blue=(MagickRealType)
10005 ScaleShortToQuantum(border_color.blue);
10006 }
10007 draw_info=CloneDrawInfo(resource_info->image_info,
10008 (DrawInfo *) NULL);
cristyce70c172010-01-07 17:15:30 +000010009 draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte));
cristy3ed852e2009-09-05 21:47:34 +000010010 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10011 x_offset,y_offset,method == FloodfillMethod ? MagickFalse :
10012 MagickTrue);
10013 draw_info=DestroyDrawInfo(draw_info);
10014 break;
10015 }
10016 case ResetMethod:
10017 {
10018 /*
10019 Update matte information using reset algorithm.
10020 */
10021 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10022 return(MagickFalse);
10023 for (y=0; y < (long) (*image)->rows; y++)
10024 {
10025 q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
10026 if (q == (PixelPacket *) NULL)
10027 break;
10028 for (x=0; x < (int) (*image)->columns; x++)
10029 {
cristyf2f27272009-12-17 14:48:46 +000010030 q->opacity=(Quantum) StringToLong(matte);
cristy3ed852e2009-09-05 21:47:34 +000010031 q++;
10032 }
10033 if (SyncAuthenticPixels(*image,exception) == MagickFalse)
10034 break;
10035 }
cristyf2f27272009-12-17 14:48:46 +000010036 if (StringToLong(matte) == OpaqueOpacity)
cristy3ed852e2009-09-05 21:47:34 +000010037 (*image)->matte=MagickFalse;
10038 break;
10039 }
10040 }
10041 state&=(~UpdateConfigurationState);
10042 }
10043 } while ((state & ExitState) == 0);
10044 (void) XSelectInput(display,windows->image.id,
10045 windows->image.attributes.event_mask);
10046 XSetCursorState(display,windows,MagickFalse);
10047 (void) XFreeCursor(display,cursor);
10048 return(MagickTrue);
10049}
10050
10051/*
10052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10053% %
10054% %
10055% %
10056+ X O p e n I m a g e %
10057% %
10058% %
10059% %
10060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10061%
10062% XOpenImage() loads an image from a file.
10063%
10064% The format of the XOpenImage method is:
10065%
10066% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10067% XWindows *windows,const unsigned int command)
10068%
10069% A description of each parameter follows:
10070%
10071% o display: Specifies a connection to an X server; returned from
10072% XOpenDisplay.
10073%
10074% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10075%
10076% o windows: Specifies a pointer to a XWindows structure.
10077%
10078% o command: A value other than zero indicates that the file is selected
10079% from the command line argument list.
10080%
10081*/
10082static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10083 XWindows *windows,const MagickBooleanType command)
10084{
10085 const MagickInfo
10086 *magick_info;
10087
10088 ExceptionInfo
10089 *exception;
10090
10091 Image
10092 *nexus;
10093
10094 ImageInfo
10095 *image_info;
10096
10097 static char
10098 filename[MaxTextExtent] = "\0";
10099
10100 /*
10101 Request file name from user.
10102 */
10103 if (command == MagickFalse)
10104 XFileBrowserWidget(display,windows,"Open",filename);
10105 else
10106 {
10107 char
10108 **filelist,
10109 **files;
10110
10111 int
10112 count,
10113 status;
10114
10115 register int
10116 i,
10117 j;
10118
10119 /*
10120 Select next image from the command line.
10121 */
10122 status=XGetCommand(display,windows->image.id,&files,&count);
10123 if (status == 0)
10124 {
10125 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10126 return((Image *) NULL);
10127 }
10128 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10129 if (filelist == (char **) NULL)
10130 {
10131 ThrowXWindowFatalException(ResourceLimitError,
10132 "MemoryAllocationFailed","...");
10133 (void) XFreeStringList(files);
10134 return((Image *) NULL);
10135 }
10136 j=0;
10137 for (i=1; i < count; i++)
10138 if (*files[i] != '-')
10139 filelist[j++]=files[i];
10140 filelist[j]=(char *) NULL;
10141 XListBrowserWidget(display,windows,&windows->widget,
10142 (const char **) filelist,"Load","Select Image to Load:",filename);
10143 filelist=(char **) RelinquishMagickMemory(filelist);
10144 (void) XFreeStringList(files);
10145 }
10146 if (*filename == '\0')
10147 return((Image *) NULL);
10148 image_info=CloneImageInfo(resource_info->image_info);
10149 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10150 (void *) NULL);
10151 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10152 exception=AcquireExceptionInfo();
10153 (void) SetImageInfo(image_info,MagickFalse,exception);
10154 if (LocaleCompare(image_info->magick,"X") == 0)
10155 {
10156 char
10157 seconds[MaxTextExtent];
10158
10159 /*
10160 User may want to delay the X server screen grab.
10161 */
10162 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10163 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10164 seconds);
10165 if (*seconds == '\0')
10166 return((Image *) NULL);
cristyf2f27272009-12-17 14:48:46 +000010167 XDelay(display,(unsigned long) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010168 }
10169 magick_info=GetMagickInfo(image_info->magick,exception);
10170 if ((magick_info != (const MagickInfo *) NULL) &&
10171 (magick_info->raw != MagickFalse))
10172 {
10173 char
10174 geometry[MaxTextExtent];
10175
10176 /*
10177 Request image size from the user.
10178 */
10179 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10180 if (image_info->size != (char *) NULL)
10181 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10182 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10183 geometry);
10184 (void) CloneString(&image_info->size,geometry);
10185 }
10186 /*
10187 Load the image.
10188 */
10189 XSetCursorState(display,windows,MagickTrue);
10190 XCheckRefreshWindows(display,windows);
10191 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10192 nexus=ReadImage(image_info,exception);
10193 CatchException(exception);
10194 XSetCursorState(display,windows,MagickFalse);
10195 if (nexus != (Image *) NULL)
10196 XClientMessage(display,windows->image.id,windows->im_protocols,
10197 windows->im_next_image,CurrentTime);
10198 else
10199 {
10200 char
10201 *text,
10202 **textlist;
10203
10204 /*
10205 Unknown image format.
10206 */
10207 text=FileToString(filename,~0,exception);
10208 if (text == (char *) NULL)
10209 return((Image *) NULL);
10210 textlist=StringToList(text);
10211 if (textlist != (char **) NULL)
10212 {
10213 char
10214 title[MaxTextExtent];
10215
10216 register int
10217 i;
10218
10219 (void) FormatMagickString(title,MaxTextExtent,
10220 "Unknown format: %s",filename);
10221 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10222 (const char **) textlist);
10223 for (i=0; textlist[i] != (char *) NULL; i++)
10224 textlist[i]=DestroyString(textlist[i]);
10225 textlist=(char **) RelinquishMagickMemory(textlist);
10226 }
10227 text=DestroyString(text);
10228 }
10229 exception=DestroyExceptionInfo(exception);
10230 image_info=DestroyImageInfo(image_info);
10231 return(nexus);
10232}
10233
10234/*
10235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10236% %
10237% %
10238% %
10239+ X P a n I m a g e %
10240% %
10241% %
10242% %
10243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10244%
10245% XPanImage() pans the image until the mouse button is released.
10246%
10247% The format of the XPanImage method is:
10248%
10249% void XPanImage(Display *display,XWindows *windows,XEvent *event)
10250%
10251% A description of each parameter follows:
10252%
10253% o display: Specifies a connection to an X server; returned from
10254% XOpenDisplay.
10255%
10256% o windows: Specifies a pointer to a XWindows structure.
10257%
10258% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10259% the entire image is refreshed.
10260%
10261*/
10262static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10263{
10264 char
10265 text[MaxTextExtent];
10266
10267 Cursor
10268 cursor;
10269
10270 MagickRealType
10271 x_factor,
10272 y_factor;
10273
10274 RectangleInfo
10275 pan_info;
10276
10277 unsigned long
10278 state;
10279
10280 /*
10281 Define cursor.
10282 */
10283 if ((windows->image.ximage->width > (int) windows->image.width) &&
10284 (windows->image.ximage->height > (int) windows->image.height))
10285 cursor=XCreateFontCursor(display,XC_fleur);
10286 else
10287 if (windows->image.ximage->width > (int) windows->image.width)
10288 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10289 else
10290 if (windows->image.ximage->height > (int) windows->image.height)
10291 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10292 else
10293 cursor=XCreateFontCursor(display,XC_arrow);
10294 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10295 /*
10296 Pan image as pointer moves until the mouse button is released.
10297 */
10298 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10299 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10300 pan_info.width=windows->pan.width*windows->image.width/
10301 windows->image.ximage->width;
10302 pan_info.height=windows->pan.height*windows->image.height/
10303 windows->image.ximage->height;
10304 pan_info.x=0;
10305 pan_info.y=0;
10306 state=UpdateConfigurationState;
10307 do
10308 {
10309 switch (event->type)
10310 {
10311 case ButtonPress:
10312 {
10313 /*
10314 User choose an initial pan location.
10315 */
10316 pan_info.x=event->xbutton.x;
10317 pan_info.y=event->xbutton.y;
10318 state|=UpdateConfigurationState;
10319 break;
10320 }
10321 case ButtonRelease:
10322 {
10323 /*
10324 User has finished panning the image.
10325 */
10326 pan_info.x=event->xbutton.x;
10327 pan_info.y=event->xbutton.y;
10328 state|=UpdateConfigurationState | ExitState;
10329 break;
10330 }
10331 case MotionNotify:
10332 {
10333 pan_info.x=event->xmotion.x;
10334 pan_info.y=event->xmotion.y;
10335 state|=UpdateConfigurationState;
10336 }
10337 default:
10338 break;
10339 }
10340 if ((state & UpdateConfigurationState) != 0)
10341 {
10342 /*
10343 Check boundary conditions.
10344 */
10345 if (pan_info.x < (int) (pan_info.width/2))
10346 pan_info.x=0;
10347 else
10348 pan_info.x=(int) (x_factor*(pan_info.x-(pan_info.width/2)));
10349 if (pan_info.x < 0)
10350 pan_info.x=0;
10351 else
10352 if ((int) (pan_info.x+windows->image.width) >
10353 windows->image.ximage->width)
10354 pan_info.x=(long)
10355 (windows->image.ximage->width-windows->image.width);
10356 if (pan_info.y < (long) (pan_info.height/2))
10357 pan_info.y=0;
10358 else
10359 pan_info.y=(long) (y_factor*(pan_info.y-(pan_info.height/2)));
10360 if (pan_info.y < 0)
10361 pan_info.y=0;
10362 else
10363 if ((int) (pan_info.y+windows->image.height) >
10364 windows->image.ximage->height)
10365 pan_info.y=(long)
10366 (windows->image.ximage->height-windows->image.height);
10367 if ((windows->image.x != (int) pan_info.x) ||
10368 (windows->image.y != (int) pan_info.y))
10369 {
10370 /*
10371 Display image pan offset.
10372 */
10373 windows->image.x=(int) pan_info.x;
10374 windows->image.y=(int) pan_info.y;
10375 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
10376 windows->image.width,windows->image.height,windows->image.x,
10377 windows->image.y);
10378 XInfoWidget(display,windows,text);
10379 /*
10380 Refresh Image window.
10381 */
10382 XDrawPanRectangle(display,windows);
10383 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10384 }
10385 state&=(~UpdateConfigurationState);
10386 }
10387 /*
10388 Wait for next event.
10389 */
10390 if ((state & ExitState) == 0)
10391 XScreenEvent(display,windows,event);
10392 } while ((state & ExitState) == 0);
10393 /*
10394 Restore cursor.
10395 */
10396 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10397 (void) XFreeCursor(display,cursor);
10398 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10399}
10400
10401/*
10402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10403% %
10404% %
10405% %
10406+ X P a s t e I m a g e %
10407% %
10408% %
10409% %
10410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10411%
10412% XPasteImage() pastes an image previously saved with XCropImage in the X
10413% window image at a location the user chooses with the pointer.
10414%
10415% The format of the XPasteImage method is:
10416%
10417% MagickBooleanType XPasteImage(Display *display,
10418% XResourceInfo *resource_info,XWindows *windows,Image *image)
10419%
10420% A description of each parameter follows:
10421%
10422% o display: Specifies a connection to an X server; returned from
10423% XOpenDisplay.
10424%
10425% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10426%
10427% o windows: Specifies a pointer to a XWindows structure.
10428%
10429% o image: the image; returned from ReadImage.
10430%
10431*/
10432static MagickBooleanType XPasteImage(Display *display,
10433 XResourceInfo *resource_info,XWindows *windows,Image *image)
10434{
10435 static const char
10436 *PasteMenu[] =
10437 {
10438 "Operator",
10439 "Help",
10440 "Dismiss",
10441 (char *) NULL
10442 };
10443
10444 static const ModeType
10445 PasteCommands[] =
10446 {
10447 PasteOperatorsCommand,
10448 PasteHelpCommand,
10449 PasteDismissCommand
10450 };
10451
10452 static CompositeOperator
10453 compose = CopyCompositeOp;
10454
10455 char
10456 text[MaxTextExtent];
10457
10458 Cursor
10459 cursor;
10460
10461 Image
10462 *paste_image;
10463
10464 int
10465 entry,
10466 id,
10467 x,
10468 y;
10469
10470 MagickRealType
10471 scale_factor;
10472
10473 RectangleInfo
10474 highlight_info,
10475 paste_info;
10476
10477 unsigned int
10478 height,
10479 width;
10480
10481 unsigned long
10482 state;
10483
10484 XEvent
10485 event;
10486
10487 /*
10488 Copy image.
10489 */
10490 if (resource_info->copy_image == (Image *) NULL)
10491 return(MagickFalse);
10492 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10493 &image->exception);
10494 /*
10495 Map Command widget.
10496 */
10497 (void) CloneString(&windows->command.name,"Paste");
10498 windows->command.data=1;
10499 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10500 (void) XMapRaised(display,windows->command.id);
10501 XClientMessage(display,windows->image.id,windows->im_protocols,
10502 windows->im_update_widget,CurrentTime);
10503 /*
10504 Track pointer until button 1 is pressed.
10505 */
10506 XSetCursorState(display,windows,MagickFalse);
10507 XQueryPosition(display,windows->image.id,&x,&y);
10508 (void) XSelectInput(display,windows->image.id,
10509 windows->image.attributes.event_mask | PointerMotionMask);
10510 paste_info.x=windows->image.x+x;
10511 paste_info.y=windows->image.y+y;
10512 paste_info.width=0;
10513 paste_info.height=0;
10514 cursor=XCreateFontCursor(display,XC_ul_angle);
10515 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10516 state=DefaultState;
10517 do
10518 {
10519 if (windows->info.mapped != MagickFalse)
10520 {
10521 /*
10522 Display pointer position.
10523 */
10524 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
10525 paste_info.x,paste_info.y);
10526 XInfoWidget(display,windows,text);
10527 }
10528 highlight_info=paste_info;
10529 highlight_info.x=paste_info.x-windows->image.x;
10530 highlight_info.y=paste_info.y-windows->image.y;
10531 XHighlightRectangle(display,windows->image.id,
10532 windows->image.highlight_context,&highlight_info);
10533 /*
10534 Wait for next event.
10535 */
10536 XScreenEvent(display,windows,&event);
10537 XHighlightRectangle(display,windows->image.id,
10538 windows->image.highlight_context,&highlight_info);
10539 if (event.xany.window == windows->command.id)
10540 {
10541 /*
10542 Select a command from the Command widget.
10543 */
10544 id=XCommandWidget(display,windows,PasteMenu,&event);
10545 if (id < 0)
10546 continue;
10547 switch (PasteCommands[id])
10548 {
10549 case PasteOperatorsCommand:
10550 {
10551 char
10552 command[MaxTextExtent],
10553 **operators;
10554
10555 /*
10556 Select a command from the pop-up menu.
10557 */
10558 operators=GetMagickOptions(MagickComposeOptions);
10559 if (operators == (char **) NULL)
10560 break;
10561 entry=XMenuWidget(display,windows,PasteMenu[id],
10562 (const char **) operators,command);
10563 if (entry >= 0)
10564 compose=(CompositeOperator) ParseMagickOption(
10565 MagickComposeOptions,MagickFalse,operators[entry]);
10566 operators=DestroyStringList(operators);
10567 break;
10568 }
10569 case PasteHelpCommand:
10570 {
10571 XTextViewWidget(display,resource_info,windows,MagickFalse,
10572 "Help Viewer - Image Composite",ImagePasteHelp);
10573 break;
10574 }
10575 case PasteDismissCommand:
10576 {
10577 /*
10578 Prematurely exit.
10579 */
10580 state|=EscapeState;
10581 state|=ExitState;
10582 break;
10583 }
10584 default:
10585 break;
10586 }
10587 continue;
10588 }
10589 switch (event.type)
10590 {
10591 case ButtonPress:
10592 {
10593 if (image->debug != MagickFalse)
10594 (void) LogMagickEvent(X11Event,GetMagickModule(),
10595 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10596 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10597 if (event.xbutton.button != Button1)
10598 break;
10599 if (event.xbutton.window != windows->image.id)
10600 break;
10601 /*
10602 Paste rectangle is relative to image configuration.
10603 */
10604 width=(unsigned int) image->columns;
10605 height=(unsigned int) image->rows;
10606 x=0;
10607 y=0;
10608 if (windows->image.crop_geometry != (char *) NULL)
10609 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10610 &width,&height);
10611 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10612 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10613 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10614 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10615 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10616 paste_info.x=windows->image.x+event.xbutton.x;
10617 paste_info.y=windows->image.y+event.xbutton.y;
10618 break;
10619 }
10620 case ButtonRelease:
10621 {
10622 if (image->debug != MagickFalse)
10623 (void) LogMagickEvent(X11Event,GetMagickModule(),
10624 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10625 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10626 if (event.xbutton.button != Button1)
10627 break;
10628 if (event.xbutton.window != windows->image.id)
10629 break;
10630 if ((paste_info.width != 0) && (paste_info.height != 0))
10631 {
10632 /*
10633 User has selected the location of the paste image.
10634 */
10635 paste_info.x=windows->image.x+event.xbutton.x;
10636 paste_info.y=windows->image.y+event.xbutton.y;
10637 state|=ExitState;
10638 }
10639 break;
10640 }
10641 case Expose:
10642 break;
10643 case KeyPress:
10644 {
10645 char
10646 command[MaxTextExtent];
10647
10648 KeySym
10649 key_symbol;
10650
10651 int
10652 length;
10653
10654 if (event.xkey.window != windows->image.id)
10655 break;
10656 /*
10657 Respond to a user key press.
10658 */
10659 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10660 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10661 *(command+length)='\0';
10662 if (image->debug != MagickFalse)
10663 (void) LogMagickEvent(X11Event,GetMagickModule(),
10664 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10665 switch ((int) key_symbol)
10666 {
10667 case XK_Escape:
10668 case XK_F20:
10669 {
10670 /*
10671 Prematurely exit.
10672 */
10673 paste_image=DestroyImage(paste_image);
10674 state|=EscapeState;
10675 state|=ExitState;
10676 break;
10677 }
10678 case XK_F1:
10679 case XK_Help:
10680 {
10681 (void) XSetFunction(display,windows->image.highlight_context,
10682 GXcopy);
10683 XTextViewWidget(display,resource_info,windows,MagickFalse,
10684 "Help Viewer - Image Composite",ImagePasteHelp);
10685 (void) XSetFunction(display,windows->image.highlight_context,
10686 GXinvert);
10687 break;
10688 }
10689 default:
10690 {
10691 (void) XBell(display,0);
10692 break;
10693 }
10694 }
10695 break;
10696 }
10697 case MotionNotify:
10698 {
10699 /*
10700 Map and unmap Info widget as text cursor crosses its boundaries.
10701 */
10702 x=event.xmotion.x;
10703 y=event.xmotion.y;
10704 if (windows->info.mapped != MagickFalse)
10705 {
10706 if ((x < (int) (windows->info.x+windows->info.width)) &&
10707 (y < (int) (windows->info.y+windows->info.height)))
10708 (void) XWithdrawWindow(display,windows->info.id,
10709 windows->info.screen);
10710 }
10711 else
10712 if ((x > (int) (windows->info.x+windows->info.width)) ||
10713 (y > (int) (windows->info.y+windows->info.height)))
10714 (void) XMapWindow(display,windows->info.id);
10715 paste_info.x=windows->image.x+x;
10716 paste_info.y=windows->image.y+y;
10717 break;
10718 }
10719 default:
10720 {
10721 if (image->debug != MagickFalse)
10722 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10723 event.type);
10724 break;
10725 }
10726 }
10727 } while ((state & ExitState) == 0);
10728 (void) XSelectInput(display,windows->image.id,
10729 windows->image.attributes.event_mask);
10730 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10731 XSetCursorState(display,windows,MagickFalse);
10732 (void) XFreeCursor(display,cursor);
10733 if ((state & EscapeState) != 0)
10734 return(MagickTrue);
10735 /*
10736 Image pasting is relative to image configuration.
10737 */
10738 XSetCursorState(display,windows,MagickTrue);
10739 XCheckRefreshWindows(display,windows);
10740 width=(unsigned int) image->columns;
10741 height=(unsigned int) image->rows;
10742 x=0;
10743 y=0;
10744 if (windows->image.crop_geometry != (char *) NULL)
10745 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10746 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10747 paste_info.x+=x;
10748 paste_info.x=(int) (scale_factor*paste_info.x+0.5);
10749 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10750 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10751 paste_info.y+=y;
10752 paste_info.y=(int) (scale_factor*paste_info.y*scale_factor+0.5);
10753 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10754 /*
10755 Paste image with X Image window.
10756 */
10757 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10758 paste_image=DestroyImage(paste_image);
10759 XSetCursorState(display,windows,MagickFalse);
10760 /*
10761 Update image colormap.
10762 */
10763 XConfigureImageColormap(display,resource_info,windows,image);
10764 (void) XConfigureImage(display,resource_info,windows,image);
10765 return(MagickTrue);
10766}
10767
10768/*
10769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10770% %
10771% %
10772% %
10773+ X P r i n t I m a g e %
10774% %
10775% %
10776% %
10777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10778%
10779% XPrintImage() prints an image to a Postscript printer.
10780%
10781% The format of the XPrintImage method is:
10782%
10783% MagickBooleanType XPrintImage(Display *display,
10784% XResourceInfo *resource_info,XWindows *windows,Image *image)
10785%
10786% A description of each parameter follows:
10787%
10788% o display: Specifies a connection to an X server; returned from
10789% XOpenDisplay.
10790%
10791% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10792%
10793% o windows: Specifies a pointer to a XWindows structure.
10794%
10795% o image: the image.
10796%
10797*/
10798static MagickBooleanType XPrintImage(Display *display,
10799 XResourceInfo *resource_info,XWindows *windows,Image *image)
10800{
10801 char
10802 filename[MaxTextExtent],
10803 geometry[MaxTextExtent];
10804
10805 Image
10806 *print_image;
10807
10808 ImageInfo
10809 *image_info;
10810
10811 MagickStatusType
10812 status;
10813
10814 /*
10815 Request Postscript page geometry from user.
10816 */
10817 image_info=CloneImageInfo(resource_info->image_info);
10818 (void) FormatMagickString(geometry,MaxTextExtent,"Letter");
10819 if (image_info->page != (char *) NULL)
10820 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10821 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10822 "Select Postscript Page Geometry:",geometry);
10823 if (*geometry == '\0')
10824 return(MagickTrue);
10825 image_info->page=GetPageGeometry(geometry);
10826 /*
10827 Apply image transforms.
10828 */
10829 XSetCursorState(display,windows,MagickTrue);
10830 XCheckRefreshWindows(display,windows);
10831 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10832 if (print_image == (Image *) NULL)
10833 return(MagickFalse);
10834 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
10835 windows->image.ximage->width,windows->image.ximage->height);
10836 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10837 /*
10838 Print image.
10839 */
10840 (void) AcquireUniqueFilename(filename);
10841 (void) FormatMagickString(print_image->filename,MaxTextExtent,"print:%s",
10842 filename);
10843 status=WriteImage(image_info,print_image);
10844 (void) RelinquishUniqueFileResource(filename);
10845 print_image=DestroyImage(print_image);
10846 image_info=DestroyImageInfo(image_info);
10847 XSetCursorState(display,windows,MagickFalse);
10848 return(status != 0 ? MagickTrue : MagickFalse);
10849}
10850
10851/*
10852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10853% %
10854% %
10855% %
10856+ X R O I I m a g e %
10857% %
10858% %
10859% %
10860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10861%
10862% XROIImage() applies an image processing technique to a region of interest.
10863%
10864% The format of the XROIImage method is:
10865%
10866% MagickBooleanType XROIImage(Display *display,
10867% XResourceInfo *resource_info,XWindows *windows,Image **image)
10868%
10869% A description of each parameter follows:
10870%
10871% o display: Specifies a connection to an X server; returned from
10872% XOpenDisplay.
10873%
10874% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10875%
10876% o windows: Specifies a pointer to a XWindows structure.
10877%
10878% o image: the image; returned from ReadImage.
10879%
10880*/
10881static MagickBooleanType XROIImage(Display *display,
10882 XResourceInfo *resource_info,XWindows *windows,Image **image)
10883{
10884#define ApplyMenus 7
10885
10886 static const char
10887 *ROIMenu[] =
10888 {
10889 "Help",
10890 "Dismiss",
10891 (char *) NULL
10892 },
10893 *ApplyMenu[] =
10894 {
10895 "File",
10896 "Edit",
10897 "Transform",
10898 "Enhance",
10899 "Effects",
10900 "F/X",
10901 "Miscellany",
10902 "Help",
10903 "Dismiss",
10904 (char *) NULL
10905 },
10906 *FileMenu[] =
10907 {
10908 "Save...",
10909 "Print...",
10910 (char *) NULL
10911 },
10912 *EditMenu[] =
10913 {
10914 "Undo",
10915 "Redo",
10916 (char *) NULL
10917 },
10918 *TransformMenu[] =
10919 {
10920 "Flop",
10921 "Flip",
10922 "Rotate Right",
10923 "Rotate Left",
10924 (char *) NULL
10925 },
10926 *EnhanceMenu[] =
10927 {
10928 "Hue...",
10929 "Saturation...",
10930 "Brightness...",
10931 "Gamma...",
10932 "Spiff",
10933 "Dull",
10934 "Contrast Stretch...",
10935 "Sigmoidal Contrast...",
10936 "Normalize",
10937 "Equalize",
10938 "Negate",
10939 "Grayscale",
10940 "Map...",
10941 "Quantize...",
10942 (char *) NULL
10943 },
10944 *EffectsMenu[] =
10945 {
10946 "Despeckle",
10947 "Emboss",
10948 "Reduce Noise",
10949 "Add Noise",
10950 "Sharpen...",
10951 "Blur...",
10952 "Threshold...",
10953 "Edge Detect...",
10954 "Spread...",
10955 "Shade...",
10956 "Raise...",
10957 "Segment...",
10958 (char *) NULL
10959 },
10960 *FXMenu[] =
10961 {
10962 "Solarize...",
10963 "Sepia Tone...",
10964 "Swirl...",
10965 "Implode...",
10966 "Vignette...",
10967 "Wave...",
10968 "Oil Paint...",
10969 "Charcoal Draw...",
10970 (char *) NULL
10971 },
10972 *MiscellanyMenu[] =
10973 {
10974 "Image Info",
10975 "Zoom Image",
10976 "Show Preview...",
10977 "Show Histogram",
10978 "Show Matte",
10979 (char *) NULL
10980 };
10981
10982 static const char
10983 **Menus[ApplyMenus] =
10984 {
10985 FileMenu,
10986 EditMenu,
10987 TransformMenu,
10988 EnhanceMenu,
10989 EffectsMenu,
10990 FXMenu,
10991 MiscellanyMenu
10992 };
10993
10994 static const CommandType
10995 ApplyCommands[] =
10996 {
10997 NullCommand,
10998 NullCommand,
10999 NullCommand,
11000 NullCommand,
11001 NullCommand,
11002 NullCommand,
11003 NullCommand,
11004 HelpCommand,
11005 QuitCommand
11006 },
11007 FileCommands[] =
11008 {
11009 SaveCommand,
11010 PrintCommand
11011 },
11012 EditCommands[] =
11013 {
11014 UndoCommand,
11015 RedoCommand
11016 },
11017 TransformCommands[] =
11018 {
11019 FlopCommand,
11020 FlipCommand,
11021 RotateRightCommand,
11022 RotateLeftCommand
11023 },
11024 EnhanceCommands[] =
11025 {
11026 HueCommand,
11027 SaturationCommand,
11028 BrightnessCommand,
11029 GammaCommand,
11030 SpiffCommand,
11031 DullCommand,
11032 ContrastStretchCommand,
11033 SigmoidalContrastCommand,
11034 NormalizeCommand,
11035 EqualizeCommand,
11036 NegateCommand,
11037 GrayscaleCommand,
11038 MapCommand,
11039 QuantizeCommand
11040 },
11041 EffectsCommands[] =
11042 {
11043 DespeckleCommand,
11044 EmbossCommand,
11045 ReduceNoiseCommand,
11046 AddNoiseCommand,
11047 SharpenCommand,
11048 BlurCommand,
11049 EdgeDetectCommand,
11050 SpreadCommand,
11051 ShadeCommand,
11052 RaiseCommand,
11053 SegmentCommand
11054 },
11055 FXCommands[] =
11056 {
11057 SolarizeCommand,
11058 SepiaToneCommand,
11059 SwirlCommand,
11060 ImplodeCommand,
11061 VignetteCommand,
11062 WaveCommand,
11063 OilPaintCommand,
11064 CharcoalDrawCommand
11065 },
11066 MiscellanyCommands[] =
11067 {
11068 InfoCommand,
11069 ZoomCommand,
11070 ShowPreviewCommand,
11071 ShowHistogramCommand,
11072 ShowMatteCommand
11073 },
11074 ROICommands[] =
11075 {
11076 ROIHelpCommand,
11077 ROIDismissCommand
11078 };
11079
11080 static const CommandType
11081 *Commands[ApplyMenus] =
11082 {
11083 FileCommands,
11084 EditCommands,
11085 TransformCommands,
11086 EnhanceCommands,
11087 EffectsCommands,
11088 FXCommands,
11089 MiscellanyCommands
11090 };
11091
11092 char
11093 command[MaxTextExtent],
11094 text[MaxTextExtent];
11095
11096 CommandType
11097 command_type;
11098
11099 Cursor
11100 cursor;
11101
11102 Image
11103 *roi_image;
11104
11105 int
11106 entry,
11107 id,
11108 x,
11109 y;
11110
11111 MagickRealType
11112 scale_factor;
11113
11114 MagickProgressMonitor
11115 progress_monitor;
11116
11117 RectangleInfo
11118 crop_info,
11119 highlight_info,
11120 roi_info;
11121
11122 unsigned int
11123 height,
11124 width;
11125
11126 unsigned long
11127 state;
11128
11129 XEvent
11130 event;
11131
11132 /*
11133 Map Command widget.
11134 */
11135 (void) CloneString(&windows->command.name,"ROI");
11136 windows->command.data=0;
11137 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11138 (void) XMapRaised(display,windows->command.id);
11139 XClientMessage(display,windows->image.id,windows->im_protocols,
11140 windows->im_update_widget,CurrentTime);
11141 /*
11142 Track pointer until button 1 is pressed.
11143 */
11144 XQueryPosition(display,windows->image.id,&x,&y);
11145 (void) XSelectInput(display,windows->image.id,
11146 windows->image.attributes.event_mask | PointerMotionMask);
11147 roi_info.x=windows->image.x+x;
11148 roi_info.y=windows->image.y+y;
11149 roi_info.width=0;
11150 roi_info.height=0;
11151 cursor=XCreateFontCursor(display,XC_fleur);
11152 state=DefaultState;
11153 do
11154 {
11155 if (windows->info.mapped != MagickFalse)
11156 {
11157 /*
11158 Display pointer position.
11159 */
11160 (void) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
11161 roi_info.x,roi_info.y);
11162 XInfoWidget(display,windows,text);
11163 }
11164 /*
11165 Wait for next event.
11166 */
11167 XScreenEvent(display,windows,&event);
11168 if (event.xany.window == windows->command.id)
11169 {
11170 /*
11171 Select a command from the Command widget.
11172 */
11173 id=XCommandWidget(display,windows,ROIMenu,&event);
11174 if (id < 0)
11175 continue;
11176 switch (ROICommands[id])
11177 {
11178 case ROIHelpCommand:
11179 {
11180 XTextViewWidget(display,resource_info,windows,MagickFalse,
11181 "Help Viewer - Region of Interest",ImageROIHelp);
11182 break;
11183 }
11184 case ROIDismissCommand:
11185 {
11186 /*
11187 Prematurely exit.
11188 */
11189 state|=EscapeState;
11190 state|=ExitState;
11191 break;
11192 }
11193 default:
11194 break;
11195 }
11196 continue;
11197 }
11198 switch (event.type)
11199 {
11200 case ButtonPress:
11201 {
11202 if (event.xbutton.button != Button1)
11203 break;
11204 if (event.xbutton.window != windows->image.id)
11205 break;
11206 /*
11207 Note first corner of region of interest rectangle-- exit loop.
11208 */
11209 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11210 roi_info.x=windows->image.x+event.xbutton.x;
11211 roi_info.y=windows->image.y+event.xbutton.y;
11212 state|=ExitState;
11213 break;
11214 }
11215 case ButtonRelease:
11216 break;
11217 case Expose:
11218 break;
11219 case KeyPress:
11220 {
11221 KeySym
11222 key_symbol;
11223
11224 if (event.xkey.window != windows->image.id)
11225 break;
11226 /*
11227 Respond to a user key press.
11228 */
11229 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11230 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11231 switch ((int) key_symbol)
11232 {
11233 case XK_Escape:
11234 case XK_F20:
11235 {
11236 /*
11237 Prematurely exit.
11238 */
11239 state|=EscapeState;
11240 state|=ExitState;
11241 break;
11242 }
11243 case XK_F1:
11244 case XK_Help:
11245 {
11246 XTextViewWidget(display,resource_info,windows,MagickFalse,
11247 "Help Viewer - Region of Interest",ImageROIHelp);
11248 break;
11249 }
11250 default:
11251 {
11252 (void) XBell(display,0);
11253 break;
11254 }
11255 }
11256 break;
11257 }
11258 case MotionNotify:
11259 {
11260 /*
11261 Map and unmap Info widget as text cursor crosses its boundaries.
11262 */
11263 x=event.xmotion.x;
11264 y=event.xmotion.y;
11265 if (windows->info.mapped != MagickFalse)
11266 {
11267 if ((x < (int) (windows->info.x+windows->info.width)) &&
11268 (y < (int) (windows->info.y+windows->info.height)))
11269 (void) XWithdrawWindow(display,windows->info.id,
11270 windows->info.screen);
11271 }
11272 else
11273 if ((x > (int) (windows->info.x+windows->info.width)) ||
11274 (y > (int) (windows->info.y+windows->info.height)))
11275 (void) XMapWindow(display,windows->info.id);
11276 roi_info.x=windows->image.x+x;
11277 roi_info.y=windows->image.y+y;
11278 break;
11279 }
11280 default:
11281 break;
11282 }
11283 } while ((state & ExitState) == 0);
11284 (void) XSelectInput(display,windows->image.id,
11285 windows->image.attributes.event_mask);
11286 if ((state & EscapeState) != 0)
11287 {
11288 /*
11289 User want to exit without region of interest.
11290 */
11291 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11292 (void) XFreeCursor(display,cursor);
11293 return(MagickTrue);
11294 }
11295 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11296 do
11297 {
11298 /*
11299 Size rectangle as pointer moves until the mouse button is released.
11300 */
11301 x=(int) roi_info.x;
11302 y=(int) roi_info.y;
11303 roi_info.width=0;
11304 roi_info.height=0;
11305 state=DefaultState;
11306 do
11307 {
11308 highlight_info=roi_info;
11309 highlight_info.x=roi_info.x-windows->image.x;
11310 highlight_info.y=roi_info.y-windows->image.y;
11311 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11312 {
11313 /*
11314 Display info and draw region of interest rectangle.
11315 */
11316 if (windows->info.mapped == MagickFalse)
11317 (void) XMapWindow(display,windows->info.id);
11318 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
11319 roi_info.width,roi_info.height,roi_info.x,roi_info.y);
11320 XInfoWidget(display,windows,text);
11321 XHighlightRectangle(display,windows->image.id,
11322 windows->image.highlight_context,&highlight_info);
11323 }
11324 else
11325 if (windows->info.mapped != MagickFalse)
11326 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11327 /*
11328 Wait for next event.
11329 */
11330 XScreenEvent(display,windows,&event);
11331 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11332 XHighlightRectangle(display,windows->image.id,
11333 windows->image.highlight_context,&highlight_info);
11334 switch (event.type)
11335 {
11336 case ButtonPress:
11337 {
11338 roi_info.x=windows->image.x+event.xbutton.x;
11339 roi_info.y=windows->image.y+event.xbutton.y;
11340 break;
11341 }
11342 case ButtonRelease:
11343 {
11344 /*
11345 User has committed to region of interest rectangle.
11346 */
11347 roi_info.x=windows->image.x+event.xbutton.x;
11348 roi_info.y=windows->image.y+event.xbutton.y;
11349 XSetCursorState(display,windows,MagickFalse);
11350 state|=ExitState;
11351 if (LocaleCompare(windows->command.name,"Apply") == 0)
11352 break;
11353 (void) CloneString(&windows->command.name,"Apply");
11354 windows->command.data=ApplyMenus;
11355 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11356 break;
11357 }
11358 case Expose:
11359 break;
11360 case MotionNotify:
11361 {
11362 roi_info.x=windows->image.x+event.xmotion.x;
11363 roi_info.y=windows->image.y+event.xmotion.y;
11364 }
11365 default:
11366 break;
11367 }
11368 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11369 ((state & ExitState) != 0))
11370 {
11371 /*
11372 Check boundary conditions.
11373 */
11374 if (roi_info.x < 0)
11375 roi_info.x=0;
11376 else
11377 if (roi_info.x > (int) windows->image.ximage->width)
11378 roi_info.x=windows->image.ximage->width;
11379 if ((int) roi_info.x < x)
11380 roi_info.width=(unsigned int) (x-roi_info.x);
11381 else
11382 {
11383 roi_info.width=(unsigned int) (roi_info.x-x);
11384 roi_info.x=x;
11385 }
11386 if (roi_info.y < 0)
11387 roi_info.y=0;
11388 else
11389 if (roi_info.y > (int) windows->image.ximage->height)
11390 roi_info.y=windows->image.ximage->height;
11391 if ((int) roi_info.y < y)
11392 roi_info.height=(unsigned int) (y-roi_info.y);
11393 else
11394 {
11395 roi_info.height=(unsigned int) (roi_info.y-y);
11396 roi_info.y=y;
11397 }
11398 }
11399 } while ((state & ExitState) == 0);
11400 /*
11401 Wait for user to grab a corner of the rectangle or press return.
11402 */
11403 state=DefaultState;
11404 command_type=NullCommand;
11405 (void) XMapWindow(display,windows->info.id);
11406 do
11407 {
11408 if (windows->info.mapped != MagickFalse)
11409 {
11410 /*
11411 Display pointer position.
11412 */
11413 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
11414 roi_info.width,roi_info.height,roi_info.x,roi_info.y);
11415 XInfoWidget(display,windows,text);
11416 }
11417 highlight_info=roi_info;
11418 highlight_info.x=roi_info.x-windows->image.x;
11419 highlight_info.y=roi_info.y-windows->image.y;
11420 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11421 {
11422 state|=EscapeState;
11423 state|=ExitState;
11424 break;
11425 }
11426 if ((state & UpdateRegionState) != 0)
11427 {
11428 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11429 switch (command_type)
11430 {
11431 case UndoCommand:
11432 case RedoCommand:
11433 {
11434 (void) XMagickCommand(display,resource_info,windows,command_type,
11435 image);
11436 break;
11437 }
11438 default:
11439 {
11440 /*
11441 Region of interest is relative to image configuration.
11442 */
11443 progress_monitor=SetImageProgressMonitor(*image,
11444 (MagickProgressMonitor) NULL,(*image)->client_data);
11445 crop_info=roi_info;
11446 width=(unsigned int) (*image)->columns;
11447 height=(unsigned int) (*image)->rows;
11448 x=0;
11449 y=0;
11450 if (windows->image.crop_geometry != (char *) NULL)
11451 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11452 &width,&height);
11453 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11454 crop_info.x+=x;
11455 crop_info.x=(int) (scale_factor*crop_info.x+0.5);
11456 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11457 scale_factor=(MagickRealType)
11458 height/windows->image.ximage->height;
11459 crop_info.y+=y;
11460 crop_info.y=(int) (scale_factor*crop_info.y+0.5);
11461 crop_info.height=(unsigned int)
11462 (scale_factor*crop_info.height+0.5);
11463 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11464 (void) SetImageProgressMonitor(*image,progress_monitor,
11465 (*image)->client_data);
11466 if (roi_image == (Image *) NULL)
11467 continue;
11468 /*
11469 Apply image processing technique to the region of interest.
11470 */
11471 windows->image.orphan=MagickTrue;
11472 (void) XMagickCommand(display,resource_info,windows,command_type,
11473 &roi_image);
11474 progress_monitor=SetImageProgressMonitor(*image,
11475 (MagickProgressMonitor) NULL,(*image)->client_data);
11476 (void) XMagickCommand(display,resource_info,windows,
11477 SaveToUndoBufferCommand,image);
11478 windows->image.orphan=MagickFalse;
11479 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11480 crop_info.x,crop_info.y);
11481 roi_image=DestroyImage(roi_image);
11482 (void) SetImageProgressMonitor(*image,progress_monitor,
11483 (*image)->client_data);
11484 break;
11485 }
11486 }
11487 if (command_type != InfoCommand)
11488 {
11489 XConfigureImageColormap(display,resource_info,windows,*image);
11490 (void) XConfigureImage(display,resource_info,windows,*image);
11491 }
11492 XCheckRefreshWindows(display,windows);
11493 XInfoWidget(display,windows,text);
11494 (void) XSetFunction(display,windows->image.highlight_context,
11495 GXinvert);
11496 state&=(~UpdateRegionState);
11497 }
11498 XHighlightRectangle(display,windows->image.id,
11499 windows->image.highlight_context,&highlight_info);
11500 XScreenEvent(display,windows,&event);
11501 if (event.xany.window == windows->command.id)
11502 {
11503 /*
11504 Select a command from the Command widget.
11505 */
11506 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11507 command_type=NullCommand;
11508 id=XCommandWidget(display,windows,ApplyMenu,&event);
11509 if (id >= 0)
11510 {
11511 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11512 command_type=ApplyCommands[id];
11513 if (id < ApplyMenus)
11514 {
11515 /*
11516 Select a command from a pop-up menu.
11517 */
11518 entry=XMenuWidget(display,windows,ApplyMenu[id],
11519 (const char **) Menus[id],command);
11520 if (entry >= 0)
11521 {
11522 (void) CopyMagickString(command,Menus[id][entry],
11523 MaxTextExtent);
11524 command_type=Commands[id][entry];
11525 }
11526 }
11527 }
11528 (void) XSetFunction(display,windows->image.highlight_context,
11529 GXinvert);
11530 XHighlightRectangle(display,windows->image.id,
11531 windows->image.highlight_context,&highlight_info);
11532 if (command_type == HelpCommand)
11533 {
11534 (void) XSetFunction(display,windows->image.highlight_context,
11535 GXcopy);
11536 XTextViewWidget(display,resource_info,windows,MagickFalse,
11537 "Help Viewer - Region of Interest",ImageROIHelp);
11538 (void) XSetFunction(display,windows->image.highlight_context,
11539 GXinvert);
11540 continue;
11541 }
11542 if (command_type == QuitCommand)
11543 {
11544 /*
11545 exit.
11546 */
11547 state|=EscapeState;
11548 state|=ExitState;
11549 continue;
11550 }
11551 if (command_type != NullCommand)
11552 state|=UpdateRegionState;
11553 continue;
11554 }
11555 XHighlightRectangle(display,windows->image.id,
11556 windows->image.highlight_context,&highlight_info);
11557 switch (event.type)
11558 {
11559 case ButtonPress:
11560 {
11561 x=windows->image.x;
11562 y=windows->image.y;
11563 if (event.xbutton.button != Button1)
11564 break;
11565 if (event.xbutton.window != windows->image.id)
11566 break;
11567 x=windows->image.x+event.xbutton.x;
11568 y=windows->image.y+event.xbutton.y;
11569 if ((x < (int) (roi_info.x+RoiDelta)) &&
11570 (x > (int) (roi_info.x-RoiDelta)) &&
11571 (y < (int) (roi_info.y+RoiDelta)) &&
11572 (y > (int) (roi_info.y-RoiDelta)))
11573 {
11574 roi_info.x=(long) (roi_info.x+roi_info.width);
11575 roi_info.y=(long) (roi_info.y+roi_info.height);
11576 state|=UpdateConfigurationState;
11577 break;
11578 }
11579 if ((x < (int) (roi_info.x+RoiDelta)) &&
11580 (x > (int) (roi_info.x-RoiDelta)) &&
11581 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11582 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11583 {
11584 roi_info.x=(long) (roi_info.x+roi_info.width);
11585 state|=UpdateConfigurationState;
11586 break;
11587 }
11588 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11589 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11590 (y < (int) (roi_info.y+RoiDelta)) &&
11591 (y > (int) (roi_info.y-RoiDelta)))
11592 {
11593 roi_info.y=(long) (roi_info.y+roi_info.height);
11594 state|=UpdateConfigurationState;
11595 break;
11596 }
11597 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11598 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11599 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11600 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11601 {
11602 state|=UpdateConfigurationState;
11603 break;
11604 }
11605 }
11606 case ButtonRelease:
11607 {
11608 if (event.xbutton.window == windows->pan.id)
11609 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11610 (highlight_info.y != crop_info.y-windows->image.y))
11611 XHighlightRectangle(display,windows->image.id,
11612 windows->image.highlight_context,&highlight_info);
11613 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11614 event.xbutton.time);
11615 break;
11616 }
11617 case Expose:
11618 {
11619 if (event.xexpose.window == windows->image.id)
11620 if (event.xexpose.count == 0)
11621 {
11622 event.xexpose.x=(int) highlight_info.x;
11623 event.xexpose.y=(int) highlight_info.y;
11624 event.xexpose.width=(int) highlight_info.width;
11625 event.xexpose.height=(int) highlight_info.height;
11626 XRefreshWindow(display,&windows->image,&event);
11627 }
11628 if (event.xexpose.window == windows->info.id)
11629 if (event.xexpose.count == 0)
11630 XInfoWidget(display,windows,text);
11631 break;
11632 }
11633 case KeyPress:
11634 {
11635 KeySym
11636 key_symbol;
11637
11638 if (event.xkey.window != windows->image.id)
11639 break;
11640 /*
11641 Respond to a user key press.
11642 */
11643 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11644 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11645 switch ((int) key_symbol)
11646 {
11647 case XK_Shift_L:
11648 case XK_Shift_R:
11649 break;
11650 case XK_Escape:
11651 case XK_F20:
11652 state|=EscapeState;
11653 case XK_Return:
11654 {
11655 state|=ExitState;
11656 break;
11657 }
11658 case XK_Home:
11659 case XK_KP_Home:
11660 {
11661 roi_info.x=(long) (windows->image.width/2L-roi_info.width/2L);
11662 roi_info.y=(long) (windows->image.height/2L-roi_info.height/2L);
11663 break;
11664 }
11665 case XK_Left:
11666 case XK_KP_Left:
11667 {
11668 roi_info.x--;
11669 break;
11670 }
11671 case XK_Up:
11672 case XK_KP_Up:
11673 case XK_Next:
11674 {
11675 roi_info.y--;
11676 break;
11677 }
11678 case XK_Right:
11679 case XK_KP_Right:
11680 {
11681 roi_info.x++;
11682 break;
11683 }
11684 case XK_Prior:
11685 case XK_Down:
11686 case XK_KP_Down:
11687 {
11688 roi_info.y++;
11689 break;
11690 }
11691 case XK_F1:
11692 case XK_Help:
11693 {
11694 (void) XSetFunction(display,windows->image.highlight_context,
11695 GXcopy);
11696 XTextViewWidget(display,resource_info,windows,MagickFalse,
11697 "Help Viewer - Region of Interest",ImageROIHelp);
11698 (void) XSetFunction(display,windows->image.highlight_context,
11699 GXinvert);
11700 break;
11701 }
11702 default:
11703 {
11704 command_type=XImageWindowCommand(display,resource_info,windows,
11705 event.xkey.state,key_symbol,image);
11706 if (command_type != NullCommand)
11707 state|=UpdateRegionState;
11708 break;
11709 }
11710 }
11711 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11712 event.xkey.time);
11713 break;
11714 }
11715 case KeyRelease:
11716 break;
11717 case MotionNotify:
11718 {
11719 if (event.xbutton.window != windows->image.id)
11720 break;
11721 /*
11722 Map and unmap Info widget as text cursor crosses its boundaries.
11723 */
11724 x=event.xmotion.x;
11725 y=event.xmotion.y;
11726 if (windows->info.mapped != MagickFalse)
11727 {
11728 if ((x < (int) (windows->info.x+windows->info.width)) &&
11729 (y < (int) (windows->info.y+windows->info.height)))
11730 (void) XWithdrawWindow(display,windows->info.id,
11731 windows->info.screen);
11732 }
11733 else
11734 if ((x > (int) (windows->info.x+windows->info.width)) ||
11735 (y > (int) (windows->info.y+windows->info.height)))
11736 (void) XMapWindow(display,windows->info.id);
11737 roi_info.x=windows->image.x+event.xmotion.x;
11738 roi_info.y=windows->image.y+event.xmotion.y;
11739 break;
11740 }
11741 case SelectionRequest:
11742 {
11743 XSelectionEvent
11744 notify;
11745
11746 XSelectionRequestEvent
11747 *request;
11748
11749 /*
11750 Set primary selection.
11751 */
11752 (void) FormatMagickString(text,MaxTextExtent,"%lux%lu%+ld%+ld",
11753 roi_info.width,roi_info.height,roi_info.x,roi_info.y);
11754 request=(&(event.xselectionrequest));
11755 (void) XChangeProperty(request->display,request->requestor,
11756 request->property,request->target,8,PropModeReplace,
11757 (unsigned char *) text,(int) strlen(text));
11758 notify.type=SelectionNotify;
11759 notify.display=request->display;
11760 notify.requestor=request->requestor;
11761 notify.selection=request->selection;
11762 notify.target=request->target;
11763 notify.time=request->time;
11764 if (request->property == None)
11765 notify.property=request->target;
11766 else
11767 notify.property=request->property;
11768 (void) XSendEvent(request->display,request->requestor,False,0,
11769 (XEvent *) &notify);
11770 }
11771 default:
11772 break;
11773 }
11774 if ((state & UpdateConfigurationState) != 0)
11775 {
11776 (void) XPutBackEvent(display,&event);
11777 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11778 break;
11779 }
11780 } while ((state & ExitState) == 0);
11781 } while ((state & ExitState) == 0);
11782 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11783 XSetCursorState(display,windows,MagickFalse);
11784 if ((state & EscapeState) != 0)
11785 return(MagickTrue);
11786 return(MagickTrue);
11787}
11788
11789/*
11790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11791% %
11792% %
11793% %
11794+ X R o t a t e I m a g e %
11795% %
11796% %
11797% %
11798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11799%
11800% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11801% rotation angle is computed from the slope of a line drawn by the user.
11802%
11803% The format of the XRotateImage method is:
11804%
11805% MagickBooleanType XRotateImage(Display *display,
11806% XResourceInfo *resource_info,XWindows *windows,double degrees,
11807% Image **image)
11808%
11809% A description of each parameter follows:
11810%
11811% o display: Specifies a connection to an X server; returned from
11812% XOpenDisplay.
11813%
11814% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11815%
11816% o windows: Specifies a pointer to a XWindows structure.
11817%
11818% o degrees: Specifies the number of degrees to rotate the image.
11819%
11820% o image: the image.
11821%
11822*/
11823static MagickBooleanType XRotateImage(Display *display,
11824 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11825{
11826 static const char
11827 *RotateMenu[] =
11828 {
11829 "Pixel Color",
11830 "Direction",
11831 "Help",
11832 "Dismiss",
11833 (char *) NULL
11834 };
11835
11836 static ModeType
11837 direction = HorizontalRotateCommand;
11838
11839 static const ModeType
11840 DirectionCommands[] =
11841 {
11842 HorizontalRotateCommand,
11843 VerticalRotateCommand
11844 },
11845 RotateCommands[] =
11846 {
11847 RotateColorCommand,
11848 RotateDirectionCommand,
11849 RotateHelpCommand,
11850 RotateDismissCommand
11851 };
11852
11853 static unsigned int
11854 pen_id = 0;
11855
11856 char
11857 command[MaxTextExtent],
11858 text[MaxTextExtent];
11859
11860 Image
11861 *rotate_image;
11862
11863 int
11864 id,
11865 x,
11866 y;
11867
11868 MagickRealType
11869 normalized_degrees;
11870
11871 register int
11872 i;
11873
11874 unsigned int
11875 height,
11876 rotations,
11877 width;
11878
11879 if (degrees == 0.0)
11880 {
11881 unsigned int
11882 distance;
11883
11884 unsigned long
11885 state;
11886
11887 XEvent
11888 event;
11889
11890 XSegment
11891 rotate_info;
11892
11893 /*
11894 Map Command widget.
11895 */
11896 (void) CloneString(&windows->command.name,"Rotate");
11897 windows->command.data=2;
11898 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11899 (void) XMapRaised(display,windows->command.id);
11900 XClientMessage(display,windows->image.id,windows->im_protocols,
11901 windows->im_update_widget,CurrentTime);
11902 /*
11903 Wait for first button press.
11904 */
11905 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11906 XQueryPosition(display,windows->image.id,&x,&y);
11907 rotate_info.x1=x;
11908 rotate_info.y1=y;
11909 rotate_info.x2=x;
11910 rotate_info.y2=y;
11911 state=DefaultState;
11912 do
11913 {
11914 XHighlightLine(display,windows->image.id,
11915 windows->image.highlight_context,&rotate_info);
11916 /*
11917 Wait for next event.
11918 */
11919 XScreenEvent(display,windows,&event);
11920 XHighlightLine(display,windows->image.id,
11921 windows->image.highlight_context,&rotate_info);
11922 if (event.xany.window == windows->command.id)
11923 {
11924 /*
11925 Select a command from the Command widget.
11926 */
11927 id=XCommandWidget(display,windows,RotateMenu,&event);
11928 if (id < 0)
11929 continue;
11930 (void) XSetFunction(display,windows->image.highlight_context,
11931 GXcopy);
11932 switch (RotateCommands[id])
11933 {
11934 case RotateColorCommand:
11935 {
11936 const char
11937 *ColorMenu[MaxNumberPens];
11938
11939 int
11940 pen_number;
11941
11942 XColor
11943 color;
11944
11945 /*
11946 Initialize menu selections.
11947 */
11948 for (i=0; i < (int) (MaxNumberPens-2); i++)
11949 ColorMenu[i]=resource_info->pen_colors[i];
11950 ColorMenu[MaxNumberPens-2]="Browser...";
11951 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
11952 /*
11953 Select a pen color from the pop-up menu.
11954 */
11955 pen_number=XMenuWidget(display,windows,RotateMenu[id],
11956 (const char **) ColorMenu,command);
11957 if (pen_number < 0)
11958 break;
11959 if (pen_number == (MaxNumberPens-2))
11960 {
11961 static char
11962 color_name[MaxTextExtent] = "gray";
11963
11964 /*
11965 Select a pen color from a dialog.
11966 */
11967 resource_info->pen_colors[pen_number]=color_name;
11968 XColorBrowserWidget(display,windows,"Select",color_name);
11969 if (*color_name == '\0')
11970 break;
11971 }
11972 /*
11973 Set pen color.
11974 */
11975 (void) XParseColor(display,windows->map_info->colormap,
11976 resource_info->pen_colors[pen_number],&color);
11977 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
11978 (unsigned int) MaxColors,&color);
11979 windows->pixel_info->pen_colors[pen_number]=color;
11980 pen_id=(unsigned int) pen_number;
11981 break;
11982 }
11983 case RotateDirectionCommand:
11984 {
11985 static const char
11986 *Directions[] =
11987 {
11988 "horizontal",
11989 "vertical",
11990 (char *) NULL,
11991 };
11992
11993 /*
11994 Select a command from the pop-up menu.
11995 */
11996 id=XMenuWidget(display,windows,RotateMenu[id],
11997 Directions,command);
11998 if (id >= 0)
11999 direction=DirectionCommands[id];
12000 break;
12001 }
12002 case RotateHelpCommand:
12003 {
12004 XTextViewWidget(display,resource_info,windows,MagickFalse,
12005 "Help Viewer - Image Rotation",ImageRotateHelp);
12006 break;
12007 }
12008 case RotateDismissCommand:
12009 {
12010 /*
12011 Prematurely exit.
12012 */
12013 state|=EscapeState;
12014 state|=ExitState;
12015 break;
12016 }
12017 default:
12018 break;
12019 }
12020 (void) XSetFunction(display,windows->image.highlight_context,
12021 GXinvert);
12022 continue;
12023 }
12024 switch (event.type)
12025 {
12026 case ButtonPress:
12027 {
12028 if (event.xbutton.button != Button1)
12029 break;
12030 if (event.xbutton.window != windows->image.id)
12031 break;
12032 /*
12033 exit loop.
12034 */
12035 (void) XSetFunction(display,windows->image.highlight_context,
12036 GXcopy);
12037 rotate_info.x1=event.xbutton.x;
12038 rotate_info.y1=event.xbutton.y;
12039 state|=ExitState;
12040 break;
12041 }
12042 case ButtonRelease:
12043 break;
12044 case Expose:
12045 break;
12046 case KeyPress:
12047 {
12048 char
12049 command[MaxTextExtent];
12050
12051 KeySym
12052 key_symbol;
12053
12054 if (event.xkey.window != windows->image.id)
12055 break;
12056 /*
12057 Respond to a user key press.
12058 */
12059 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12060 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12061 switch ((int) key_symbol)
12062 {
12063 case XK_Escape:
12064 case XK_F20:
12065 {
12066 /*
12067 Prematurely exit.
12068 */
12069 state|=EscapeState;
12070 state|=ExitState;
12071 break;
12072 }
12073 case XK_F1:
12074 case XK_Help:
12075 {
12076 (void) XSetFunction(display,windows->image.highlight_context,
12077 GXcopy);
12078 XTextViewWidget(display,resource_info,windows,MagickFalse,
12079 "Help Viewer - Image Rotation",ImageRotateHelp);
12080 (void) XSetFunction(display,windows->image.highlight_context,
12081 GXinvert);
12082 break;
12083 }
12084 default:
12085 {
12086 (void) XBell(display,0);
12087 break;
12088 }
12089 }
12090 break;
12091 }
12092 case MotionNotify:
12093 {
12094 rotate_info.x1=event.xmotion.x;
12095 rotate_info.y1=event.xmotion.y;
12096 }
12097 }
12098 rotate_info.x2=rotate_info.x1;
12099 rotate_info.y2=rotate_info.y1;
12100 if (direction == HorizontalRotateCommand)
12101 rotate_info.x2+=32;
12102 else
12103 rotate_info.y2-=32;
12104 } while ((state & ExitState) == 0);
12105 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12106 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12107 if ((state & EscapeState) != 0)
12108 return(MagickTrue);
12109 /*
12110 Draw line as pointer moves until the mouse button is released.
12111 */
12112 distance=0;
12113 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12114 state=DefaultState;
12115 do
12116 {
12117 if (distance > 9)
12118 {
12119 /*
12120 Display info and draw rotation line.
12121 */
12122 if (windows->info.mapped == MagickFalse)
12123 (void) XMapWindow(display,windows->info.id);
cristye7f51092010-01-17 00:39:37 +000012124 (void) FormatMagickString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012125 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12126 XInfoWidget(display,windows,text);
12127 XHighlightLine(display,windows->image.id,
12128 windows->image.highlight_context,&rotate_info);
12129 }
12130 else
12131 if (windows->info.mapped != MagickFalse)
12132 (void) XWithdrawWindow(display,windows->info.id,
12133 windows->info.screen);
12134 /*
12135 Wait for next event.
12136 */
12137 XScreenEvent(display,windows,&event);
12138 if (distance > 9)
12139 XHighlightLine(display,windows->image.id,
12140 windows->image.highlight_context,&rotate_info);
12141 switch (event.type)
12142 {
12143 case ButtonPress:
12144 break;
12145 case ButtonRelease:
12146 {
12147 /*
12148 User has committed to rotation line.
12149 */
12150 rotate_info.x2=event.xbutton.x;
12151 rotate_info.y2=event.xbutton.y;
12152 state|=ExitState;
12153 break;
12154 }
12155 case Expose:
12156 break;
12157 case MotionNotify:
12158 {
12159 rotate_info.x2=event.xmotion.x;
12160 rotate_info.y2=event.xmotion.y;
12161 }
12162 default:
12163 break;
12164 }
12165 /*
12166 Check boundary conditions.
12167 */
12168 if (rotate_info.x2 < 0)
12169 rotate_info.x2=0;
12170 else
12171 if (rotate_info.x2 > (int) windows->image.width)
12172 rotate_info.x2=(short) windows->image.width;
12173 if (rotate_info.y2 < 0)
12174 rotate_info.y2=0;
12175 else
12176 if (rotate_info.y2 > (int) windows->image.height)
12177 rotate_info.y2=(short) windows->image.height;
12178 /*
12179 Compute rotation angle from the slope of the line.
12180 */
12181 degrees=0.0;
12182 distance=(unsigned int)
12183 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12184 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12185 if (distance > 9)
12186 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12187 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12188 } while ((state & ExitState) == 0);
12189 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12190 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12191 if (distance <= 9)
12192 return(MagickTrue);
12193 }
12194 if (direction == VerticalRotateCommand)
12195 degrees-=90.0;
12196 if (degrees == 0.0)
12197 return(MagickTrue);
12198 /*
12199 Rotate image.
12200 */
12201 normalized_degrees=degrees;
12202 while (normalized_degrees < -45.0)
12203 normalized_degrees+=360.0;
12204 for (rotations=0; normalized_degrees > 45.0; rotations++)
12205 normalized_degrees-=90.0;
12206 if (normalized_degrees != 0.0)
12207 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12208 XSetCursorState(display,windows,MagickTrue);
12209 XCheckRefreshWindows(display,windows);
12210 (*image)->background_color.red=ScaleShortToQuantum(
12211 windows->pixel_info->pen_colors[pen_id].red);
12212 (*image)->background_color.green=ScaleShortToQuantum(
12213 windows->pixel_info->pen_colors[pen_id].green);
12214 (*image)->background_color.blue=ScaleShortToQuantum(
12215 windows->pixel_info->pen_colors[pen_id].blue);
12216 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12217 XSetCursorState(display,windows,MagickFalse);
12218 if (rotate_image == (Image *) NULL)
12219 return(MagickFalse);
12220 *image=DestroyImage(*image);
12221 *image=rotate_image;
12222 if (windows->image.crop_geometry != (char *) NULL)
12223 {
12224 /*
12225 Rotate crop geometry.
12226 */
12227 width=(unsigned int) (*image)->columns;
12228 height=(unsigned int) (*image)->rows;
12229 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12230 switch (rotations % 4)
12231 {
12232 default:
12233 case 0:
12234 break;
12235 case 1:
12236 {
12237 /*
12238 Rotate 90 degrees.
12239 */
12240 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12241 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12242 (int) height-y,x);
12243 break;
12244 }
12245 case 2:
12246 {
12247 /*
12248 Rotate 180 degrees.
12249 */
12250 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12251 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12252 break;
12253 }
12254 case 3:
12255 {
12256 /*
12257 Rotate 270 degrees.
12258 */
12259 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12260 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12261 break;
12262 }
12263 }
12264 }
12265 if (windows->image.orphan != MagickFalse)
12266 return(MagickTrue);
12267 if (normalized_degrees != 0.0)
12268 {
12269 /*
12270 Update image colormap.
12271 */
12272 windows->image.window_changes.width=(int) (*image)->columns;
12273 windows->image.window_changes.height=(int) (*image)->rows;
12274 if (windows->image.crop_geometry != (char *) NULL)
12275 {
12276 /*
12277 Obtain dimensions of image from crop geometry.
12278 */
12279 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12280 &width,&height);
12281 windows->image.window_changes.width=(int) width;
12282 windows->image.window_changes.height=(int) height;
12283 }
12284 XConfigureImageColormap(display,resource_info,windows,*image);
12285 }
12286 else
12287 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12288 {
12289 windows->image.window_changes.width=windows->image.ximage->height;
12290 windows->image.window_changes.height=windows->image.ximage->width;
12291 }
12292 /*
12293 Update image configuration.
12294 */
12295 (void) XConfigureImage(display,resource_info,windows,*image);
12296 return(MagickTrue);
12297}
12298
12299/*
12300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12301% %
12302% %
12303% %
12304+ X S a v e I m a g e %
12305% %
12306% %
12307% %
12308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12309%
12310% XSaveImage() saves an image to a file.
12311%
12312% The format of the XSaveImage method is:
12313%
12314% MagickBooleanType XSaveImage(Display *display,
12315% XResourceInfo *resource_info,XWindows *windows,Image *image)
12316%
12317% A description of each parameter follows:
12318%
12319% o display: Specifies a connection to an X server; returned from
12320% XOpenDisplay.
12321%
12322% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12323%
12324% o windows: Specifies a pointer to a XWindows structure.
12325%
12326% o image: the image.
12327%
12328*/
12329static MagickBooleanType XSaveImage(Display *display,
12330 XResourceInfo *resource_info,XWindows *windows,Image *image)
12331{
12332 char
12333 filename[MaxTextExtent],
12334 geometry[MaxTextExtent];
12335
12336 Image
12337 *save_image;
12338
12339 ImageInfo
12340 *image_info;
12341
12342 MagickStatusType
12343 status;
12344
12345 /*
12346 Request file name from user.
12347 */
12348 if (resource_info->write_filename != (char *) NULL)
12349 (void) CopyMagickString(filename,resource_info->write_filename,
12350 MaxTextExtent);
12351 else
12352 {
12353 char
12354 path[MaxTextExtent];
12355
12356 int
12357 status;
12358
12359 GetPathComponent(image->filename,HeadPath,path);
12360 GetPathComponent(image->filename,TailPath,filename);
12361 status=chdir(path);
12362 if (status == -1)
12363 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12364 FileOpenError,"UnableToOpenFile","%s",path);
12365 }
12366 XFileBrowserWidget(display,windows,"Save",filename);
12367 if (*filename == '\0')
12368 return(MagickTrue);
12369 if (IsPathAccessible(filename) != MagickFalse)
12370 {
12371 int
12372 status;
12373
12374 /*
12375 File exists-- seek user's permission before overwriting.
12376 */
12377 status=XConfirmWidget(display,windows,"Overwrite",filename);
12378 if (status <= 0)
12379 return(MagickTrue);
12380 }
12381 image_info=CloneImageInfo(resource_info->image_info);
12382 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12383 (void) SetImageInfo(image_info,MagickFalse,&image->exception);
12384 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12385 (LocaleCompare(image_info->magick,"JPG") == 0))
12386 {
12387 char
12388 quality[MaxTextExtent];
12389
12390 int
12391 status;
12392
12393 /*
12394 Request JPEG quality from user.
12395 */
12396 (void) FormatMagickString(quality,MaxTextExtent,"%lu",image->quality);
12397 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12398 quality);
12399 if (*quality == '\0')
12400 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012401 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012402 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12403 }
12404 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12405 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12406 (LocaleCompare(image_info->magick,"PS") == 0) ||
12407 (LocaleCompare(image_info->magick,"PS2") == 0))
12408 {
12409 char
12410 geometry[MaxTextExtent];
12411
12412 /*
12413 Request page geometry from user.
12414 */
cristyb93d9e72009-09-12 20:02:21 +000012415 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012416 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristyb93d9e72009-09-12 20:02:21 +000012417 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012418 if (image_info->page != (char *) NULL)
12419 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12420 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12421 "Select page geometry:",geometry);
12422 if (*geometry != '\0')
12423 image_info->page=GetPageGeometry(geometry);
12424 }
12425 /*
12426 Apply image transforms.
12427 */
12428 XSetCursorState(display,windows,MagickTrue);
12429 XCheckRefreshWindows(display,windows);
12430 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12431 if (save_image == (Image *) NULL)
12432 return(MagickFalse);
12433 (void) FormatMagickString(geometry,MaxTextExtent,"%dx%d!",
12434 windows->image.ximage->width,windows->image.ximage->height);
12435 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12436 /*
12437 Write image.
12438 */
12439 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12440 status=WriteImage(image_info,save_image);
12441 if (status != MagickFalse)
12442 image->taint=MagickFalse;
12443 save_image=DestroyImage(save_image);
12444 image_info=DestroyImageInfo(image_info);
12445 XSetCursorState(display,windows,MagickFalse);
12446 return(status != 0 ? MagickTrue : MagickFalse);
12447}
12448
12449/*
12450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12451% %
12452% %
12453% %
12454+ X S c r e e n E v e n t %
12455% %
12456% %
12457% %
12458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12459%
12460% XScreenEvent() handles global events associated with the Pan and Magnify
12461% windows.
12462%
12463% The format of the XScreenEvent function is:
12464%
12465% void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12466%
12467% A description of each parameter follows:
12468%
12469% o display: Specifies a pointer to the Display structure; returned from
12470% XOpenDisplay.
12471%
12472% o windows: Specifies a pointer to a XWindows structure.
12473%
12474% o event: Specifies a pointer to a X11 XEvent structure.
12475%
12476%
12477*/
12478
12479#if defined(__cplusplus) || defined(c_plusplus)
12480extern "C" {
12481#endif
12482
12483static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12484{
12485 register XWindows
12486 *windows;
12487
12488 windows=(XWindows *) data;
12489 if ((event->type == ClientMessage) &&
12490 (event->xclient.window == windows->image.id))
12491 return(MagickFalse);
12492 return(MagickTrue);
12493}
12494
12495#if defined(__cplusplus) || defined(c_plusplus)
12496}
12497#endif
12498
12499static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12500{
12501 register int
12502 x,
12503 y;
12504
12505 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12506 if (event->xany.window == windows->command.id)
12507 return;
12508 switch (event->type)
12509 {
12510 case ButtonPress:
12511 case ButtonRelease:
12512 {
12513 if ((event->xbutton.button == Button3) &&
12514 (event->xbutton.state & Mod1Mask))
12515 {
12516 /*
12517 Convert Alt-Button3 to Button2.
12518 */
12519 event->xbutton.button=Button2;
12520 event->xbutton.state&=(~Mod1Mask);
12521 }
12522 if (event->xbutton.window == windows->backdrop.id)
12523 {
12524 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12525 event->xbutton.time);
12526 break;
12527 }
12528 if (event->xbutton.window == windows->pan.id)
12529 {
12530 XPanImage(display,windows,event);
12531 break;
12532 }
12533 if (event->xbutton.window == windows->image.id)
12534 if (event->xbutton.button == Button2)
12535 {
12536 /*
12537 Update magnified image.
12538 */
12539 x=event->xbutton.x;
12540 y=event->xbutton.y;
12541 if (x < 0)
12542 x=0;
12543 else
12544 if (x >= (int) windows->image.width)
12545 x=(int) (windows->image.width-1);
12546 windows->magnify.x=windows->image.x+x;
12547 if (y < 0)
12548 y=0;
12549 else
12550 if (y >= (int) windows->image.height)
12551 y=(int) (windows->image.height-1);
12552 windows->magnify.y=windows->image.y+y;
12553 if (windows->magnify.mapped == MagickFalse)
12554 (void) XMapRaised(display,windows->magnify.id);
12555 XMakeMagnifyImage(display,windows);
12556 if (event->type == ButtonRelease)
12557 (void) XWithdrawWindow(display,windows->info.id,
12558 windows->info.screen);
12559 break;
12560 }
12561 break;
12562 }
12563 case ClientMessage:
12564 {
12565 /*
12566 If client window delete message, exit.
12567 */
12568 if (event->xclient.message_type != windows->wm_protocols)
12569 break;
12570 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12571 break;
12572 if (event->xclient.window == windows->magnify.id)
12573 {
12574 (void) XWithdrawWindow(display,windows->magnify.id,
12575 windows->magnify.screen);
12576 break;
12577 }
12578 break;
12579 }
12580 case ConfigureNotify:
12581 {
12582 if (event->xconfigure.window == windows->magnify.id)
12583 {
12584 unsigned int
12585 magnify;
12586
12587 /*
12588 Magnify window has a new configuration.
12589 */
12590 windows->magnify.width=(unsigned int) event->xconfigure.width;
12591 windows->magnify.height=(unsigned int) event->xconfigure.height;
12592 if (windows->magnify.mapped == MagickFalse)
12593 break;
12594 magnify=1;
12595 while ((int) magnify <= event->xconfigure.width)
12596 magnify<<=1;
12597 while ((int) magnify <= event->xconfigure.height)
12598 magnify<<=1;
12599 magnify>>=1;
12600 if (((int) magnify != event->xconfigure.width) ||
12601 ((int) magnify != event->xconfigure.height))
12602 {
12603 XWindowChanges
12604 window_changes;
12605
12606 window_changes.width=(int) magnify;
12607 window_changes.height=(int) magnify;
12608 (void) XReconfigureWMWindow(display,windows->magnify.id,
12609 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12610 &window_changes);
12611 break;
12612 }
12613 XMakeMagnifyImage(display,windows);
12614 break;
12615 }
12616 break;
12617 }
12618 case Expose:
12619 {
12620 if (event->xexpose.window == windows->image.id)
12621 {
12622 XRefreshWindow(display,&windows->image,event);
12623 break;
12624 }
12625 if (event->xexpose.window == windows->pan.id)
12626 if (event->xexpose.count == 0)
12627 {
12628 XDrawPanRectangle(display,windows);
12629 break;
12630 }
12631 if (event->xexpose.window == windows->magnify.id)
12632 if (event->xexpose.count == 0)
12633 {
12634 XMakeMagnifyImage(display,windows);
12635 break;
12636 }
12637 break;
12638 }
12639 case KeyPress:
12640 {
12641 char
12642 command[MaxTextExtent];
12643
12644 KeySym
12645 key_symbol;
12646
12647 if (event->xkey.window != windows->magnify.id)
12648 break;
12649 /*
12650 Respond to a user key press.
12651 */
12652 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12653 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12654 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12655 break;
12656 }
12657 case MapNotify:
12658 {
12659 if (event->xmap.window == windows->magnify.id)
12660 {
12661 windows->magnify.mapped=MagickTrue;
12662 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12663 break;
12664 }
12665 if (event->xmap.window == windows->info.id)
12666 {
12667 windows->info.mapped=MagickTrue;
12668 break;
12669 }
12670 break;
12671 }
12672 case MotionNotify:
12673 {
12674 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12675 if (event->xmotion.window == windows->image.id)
12676 if (windows->magnify.mapped != MagickFalse)
12677 {
12678 /*
12679 Update magnified image.
12680 */
12681 x=event->xmotion.x;
12682 y=event->xmotion.y;
12683 if (x < 0)
12684 x=0;
12685 else
12686 if (x >= (int) windows->image.width)
12687 x=(int) (windows->image.width-1);
12688 windows->magnify.x=windows->image.x+x;
12689 if (y < 0)
12690 y=0;
12691 else
12692 if (y >= (int) windows->image.height)
12693 y=(int) (windows->image.height-1);
12694 windows->magnify.y=windows->image.y+y;
12695 XMakeMagnifyImage(display,windows);
12696 }
12697 break;
12698 }
12699 case UnmapNotify:
12700 {
12701 if (event->xunmap.window == windows->magnify.id)
12702 {
12703 windows->magnify.mapped=MagickFalse;
12704 break;
12705 }
12706 if (event->xunmap.window == windows->info.id)
12707 {
12708 windows->info.mapped=MagickFalse;
12709 break;
12710 }
12711 break;
12712 }
12713 default:
12714 break;
12715 }
12716}
12717
12718/*
12719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12720% %
12721% %
12722% %
12723+ X S e t C r o p G e o m e t r y %
12724% %
12725% %
12726% %
12727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12728%
12729% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12730% and translates it to a cropping geometry relative to the image.
12731%
12732% The format of the XSetCropGeometry method is:
12733%
12734% void XSetCropGeometry(Display *display,XWindows *windows,
12735% RectangleInfo *crop_info,Image *image)
12736%
12737% A description of each parameter follows:
12738%
12739% o display: Specifies a connection to an X server; returned from
12740% XOpenDisplay.
12741%
12742% o windows: Specifies a pointer to a XWindows structure.
12743%
12744% o crop_info: A pointer to a RectangleInfo that defines a region of the
12745% Image window to crop.
12746%
12747% o image: the image.
12748%
12749*/
12750static void XSetCropGeometry(Display *display,XWindows *windows,
12751 RectangleInfo *crop_info,Image *image)
12752{
12753 char
12754 text[MaxTextExtent];
12755
12756 int
12757 x,
12758 y;
12759
12760 MagickRealType
12761 scale_factor;
12762
12763 unsigned int
12764 height,
12765 width;
12766
12767 if (windows->info.mapped != MagickFalse)
12768 {
12769 /*
12770 Display info on cropping rectangle.
12771 */
12772 (void) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
12773 crop_info->width,crop_info->height,crop_info->x,crop_info->y);
12774 XInfoWidget(display,windows,text);
12775 }
12776 /*
12777 Cropping geometry is relative to any previous crop geometry.
12778 */
12779 x=0;
12780 y=0;
12781 width=(unsigned int) image->columns;
12782 height=(unsigned int) image->rows;
12783 if (windows->image.crop_geometry != (char *) NULL)
12784 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12785 else
12786 windows->image.crop_geometry=AcquireString((char *) NULL);
12787 /*
12788 Define the crop geometry string from the cropping rectangle.
12789 */
12790 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12791 if (crop_info->x > 0)
12792 x+=(int) (scale_factor*crop_info->x+0.5);
12793 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12794 if (width == 0)
12795 width=1;
12796 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12797 if (crop_info->y > 0)
12798 y+=(int) (scale_factor*crop_info->y+0.5);
12799 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12800 if (height == 0)
12801 height=1;
12802 (void) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
12803 "%ux%u%+d%+d",width,height,x,y);
12804}
12805
12806/*
12807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12808% %
12809% %
12810% %
12811+ X T i l e I m a g e %
12812% %
12813% %
12814% %
12815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12816%
12817% XTileImage() loads or deletes a selected tile from a visual image directory.
12818% The load or delete command is chosen from a menu.
12819%
12820% The format of the XTileImage method is:
12821%
12822% Image *XTileImage(Display *display,XResourceInfo *resource_info,
12823% XWindows *windows,Image *image,XEvent *event)
12824%
12825% A description of each parameter follows:
12826%
12827% o tile_image: XTileImage reads or deletes the tile image
12828% and returns it. A null image is returned if an error occurs.
12829%
12830% o display: Specifies a connection to an X server; returned from
12831% XOpenDisplay.
12832%
12833% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12834%
12835% o windows: Specifies a pointer to a XWindows structure.
12836%
12837% o image: the image; returned from ReadImage.
12838%
12839% o event: Specifies a pointer to a XEvent structure. If it is NULL,
12840% the entire image is refreshed.
12841%
12842*/
12843static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12844 XWindows *windows,Image *image,XEvent *event)
12845{
12846 static const char
12847 *VerbMenu[] =
12848 {
12849 "Load",
12850 "Next",
12851 "Former",
12852 "Delete",
12853 "Update",
12854 (char *) NULL,
12855 };
12856
12857 static const ModeType
12858 TileCommands[] =
12859 {
12860 TileLoadCommand,
12861 TileNextCommand,
12862 TileFormerCommand,
12863 TileDeleteCommand,
12864 TileUpdateCommand
12865 };
12866
12867 char
12868 command[MaxTextExtent],
12869 filename[MaxTextExtent];
12870
12871 Image
12872 *tile_image;
12873
12874 int
12875 id,
12876 status,
12877 tile,
12878 x,
12879 y;
12880
12881 MagickRealType
12882 scale_factor;
12883
12884 register char
12885 *p,
12886 *q;
12887
12888 register int
12889 i;
12890
12891 unsigned int
12892 height,
12893 width;
12894
12895 /*
12896 Tile image is relative to montage image configuration.
12897 */
12898 x=0;
12899 y=0;
12900 width=(unsigned int) image->columns;
12901 height=(unsigned int) image->rows;
12902 if (windows->image.crop_geometry != (char *) NULL)
12903 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12904 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12905 event->xbutton.x+=windows->image.x;
12906 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12907 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12908 event->xbutton.y+=windows->image.y;
12909 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12910 /*
12911 Determine size and location of each tile in the visual image directory.
12912 */
12913 width=(unsigned int) image->columns;
12914 height=(unsigned int) image->rows;
12915 x=0;
12916 y=0;
12917 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
12918 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
12919 (event->xbutton.x-x)/width;
12920 if (tile < 0)
12921 {
12922 /*
12923 Button press is outside any tile.
12924 */
12925 (void) XBell(display,0);
12926 return((Image *) NULL);
12927 }
12928 /*
12929 Determine file name from the tile directory.
12930 */
12931 p=image->directory;
12932 for (i=tile; (i != 0) && (*p != '\0'); )
12933 {
12934 if (*p == '\n')
12935 i--;
12936 p++;
12937 }
12938 if (*p == '\0')
12939 {
12940 /*
12941 Button press is outside any tile.
12942 */
12943 (void) XBell(display,0);
12944 return((Image *) NULL);
12945 }
12946 /*
12947 Select a command from the pop-up menu.
12948 */
12949 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
12950 if (id < 0)
12951 return((Image *) NULL);
12952 q=p;
12953 while ((*q != '\n') && (*q != '\0'))
12954 q++;
12955 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
12956 /*
12957 Perform command for the selected tile.
12958 */
12959 XSetCursorState(display,windows,MagickTrue);
12960 XCheckRefreshWindows(display,windows);
12961 tile_image=NewImageList();
12962 switch (TileCommands[id])
12963 {
12964 case TileLoadCommand:
12965 {
12966 /*
12967 Load tile image.
12968 */
12969 XCheckRefreshWindows(display,windows);
12970 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
12971 MaxTextExtent);
12972 (void) CopyMagickString(resource_info->image_info->filename,filename,
12973 MaxTextExtent);
12974 tile_image=ReadImage(resource_info->image_info,&image->exception);
12975 CatchException(&image->exception);
12976 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12977 break;
12978 }
12979 case TileNextCommand:
12980 {
12981 /*
12982 Display next image.
12983 */
12984 XClientMessage(display,windows->image.id,windows->im_protocols,
12985 windows->im_next_image,CurrentTime);
12986 break;
12987 }
12988 case TileFormerCommand:
12989 {
12990 /*
12991 Display former image.
12992 */
12993 XClientMessage(display,windows->image.id,windows->im_protocols,
12994 windows->im_former_image,CurrentTime);
12995 break;
12996 }
12997 case TileDeleteCommand:
12998 {
12999 /*
13000 Delete tile image.
13001 */
13002 if (IsPathAccessible(filename) == MagickFalse)
13003 {
13004 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13005 break;
13006 }
13007 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13008 if (status <= 0)
13009 break;
13010 status=remove(filename) != 0 ? MagickTrue : MagickFalse;
13011 if (status != MagickFalse)
13012 {
13013 XNoticeWidget(display,windows,"Unable to delete image file:",
13014 filename);
13015 break;
13016 }
13017 }
13018 case TileUpdateCommand:
13019 {
13020 ExceptionInfo
13021 *exception;
13022
13023 int
13024 x_offset,
13025 y_offset;
13026
13027 PixelPacket
13028 pixel;
13029
13030 register int
13031 j;
13032
13033 register PixelPacket
13034 *s;
13035
13036 /*
13037 Ensure all the images exist.
13038 */
13039 tile=0;
13040 for (p=image->directory; *p != '\0'; p++)
13041 {
13042 q=p;
13043 while ((*q != '\n') && (*q != '\0'))
13044 q++;
13045 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13046 p=q;
13047 if (IsPathAccessible(filename) != MagickFalse)
13048 {
13049 tile++;
13050 continue;
13051 }
13052 /*
13053 Overwrite tile with background color.
13054 */
13055 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13056 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13057 exception=(&image->exception);
13058 (void) GetOneVirtualPixel(image,0,0,&pixel,exception);
13059 for (i=0; i < (int) height; i++)
13060 {
13061 s=GetAuthenticPixels(image,x_offset,y_offset+i,width,1,exception);
13062 if (s == (PixelPacket *) NULL)
13063 break;
13064 for (j=0; j < (int) width; j++)
13065 *s++=pixel;
13066 if (SyncAuthenticPixels(image,exception) == MagickFalse)
13067 break;
13068 }
13069 tile++;
13070 }
13071 windows->image.window_changes.width=(int) image->columns;
13072 windows->image.window_changes.height=(int) image->rows;
13073 XConfigureImageColormap(display,resource_info,windows,image);
13074 (void) XConfigureImage(display,resource_info,windows,image);
13075 break;
13076 }
13077 default:
13078 break;
13079 }
13080 XSetCursorState(display,windows,MagickFalse);
13081 return(tile_image);
13082}
13083
13084/*
13085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13086% %
13087% %
13088% %
13089+ X T r a n s l a t e I m a g e %
13090% %
13091% %
13092% %
13093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13094%
13095% XTranslateImage() translates the image within an Image window by one pixel
13096% as specified by the key symbol. If the image has a `montage string the
13097% translation is respect to the width and height contained within the string.
13098%
13099% The format of the XTranslateImage method is:
13100%
13101% void XTranslateImage(Display *display,XWindows *windows,
13102% Image *image,const KeySym key_symbol)
13103%
13104% A description of each parameter follows:
13105%
13106% o display: Specifies a connection to an X server; returned from
13107% XOpenDisplay.
13108%
13109% o windows: Specifies a pointer to a XWindows structure.
13110%
13111% o image: the image.
13112%
13113% o key_symbol: Specifies a KeySym which indicates which side of the image
13114% to trim.
13115%
13116*/
13117static void XTranslateImage(Display *display,XWindows *windows,
13118 Image *image,const KeySym key_symbol)
13119{
13120 char
13121 text[MaxTextExtent];
13122
13123 int
13124 x,
13125 y;
13126
13127 unsigned int
13128 x_offset,
13129 y_offset;
13130
13131 /*
13132 User specified a pan position offset.
13133 */
13134 x_offset=windows->image.width;
13135 y_offset=windows->image.height;
13136 if (image->montage != (char *) NULL)
13137 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13138 switch ((int) key_symbol)
13139 {
13140 case XK_Home:
13141 case XK_KP_Home:
13142 {
13143 windows->image.x=(int) windows->image.width/2;
13144 windows->image.y=(int) windows->image.height/2;
13145 break;
13146 }
13147 case XK_Left:
13148 case XK_KP_Left:
13149 {
13150 windows->image.x-=x_offset;
13151 break;
13152 }
13153 case XK_Next:
13154 case XK_Up:
13155 case XK_KP_Up:
13156 {
13157 windows->image.y-=y_offset;
13158 break;
13159 }
13160 case XK_Right:
13161 case XK_KP_Right:
13162 {
13163 windows->image.x+=x_offset;
13164 break;
13165 }
13166 case XK_Prior:
13167 case XK_Down:
13168 case XK_KP_Down:
13169 {
13170 windows->image.y+=y_offset;
13171 break;
13172 }
13173 default:
13174 return;
13175 }
13176 /*
13177 Check boundary conditions.
13178 */
13179 if (windows->image.x < 0)
13180 windows->image.x=0;
13181 else
13182 if ((int) (windows->image.x+windows->image.width) >
13183 windows->image.ximage->width)
13184 windows->image.x=windows->image.ximage->width-windows->image.width;
13185 if (windows->image.y < 0)
13186 windows->image.y=0;
13187 else
13188 if ((int) (windows->image.y+windows->image.height) >
13189 windows->image.ximage->height)
13190 windows->image.y=windows->image.ximage->height-windows->image.height;
13191 /*
13192 Refresh Image window.
13193 */
13194 (void) FormatMagickString(text,MaxTextExtent," %ux%u%+d%+d ",
13195 windows->image.width,windows->image.height,windows->image.x,
13196 windows->image.y);
13197 XInfoWidget(display,windows,text);
13198 XCheckRefreshWindows(display,windows);
13199 XDrawPanRectangle(display,windows);
13200 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13201 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13202}
13203
13204/*
13205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13206% %
13207% %
13208% %
13209+ X T r i m I m a g e %
13210% %
13211% %
13212% %
13213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13214%
13215% XTrimImage() trims the edges from the Image window.
13216%
13217% The format of the XTrimImage method is:
13218%
13219% MagickBooleanType XTrimImage(Display *display,
13220% XResourceInfo *resource_info,XWindows *windows,Image *image)
13221%
13222% A description of each parameter follows:
13223%
13224% o display: Specifies a connection to an X server; returned from
13225% XOpenDisplay.
13226%
13227% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13228%
13229% o windows: Specifies a pointer to a XWindows structure.
13230%
13231% o image: the image.
13232%
13233*/
13234static MagickBooleanType XTrimImage(Display *display,
13235 XResourceInfo *resource_info,XWindows *windows,Image *image)
13236{
13237 RectangleInfo
13238 trim_info;
13239
13240 register int
13241 x,
13242 y;
13243
13244 unsigned long
13245 background,
13246 pixel;
13247
13248 /*
13249 Trim edges from image.
13250 */
13251 XSetCursorState(display,windows,MagickTrue);
13252 XCheckRefreshWindows(display,windows);
13253 /*
13254 Crop the left edge.
13255 */
13256 background=XGetPixel(windows->image.ximage,0,0);
13257 trim_info.width=(unsigned long) windows->image.ximage->width;
13258 for (x=0; x < windows->image.ximage->width; x++)
13259 {
13260 for (y=0; y < windows->image.ximage->height; y++)
13261 {
13262 pixel=XGetPixel(windows->image.ximage,x,y);
13263 if (pixel != background)
13264 break;
13265 }
13266 if (y < windows->image.ximage->height)
13267 break;
13268 }
13269 trim_info.x=x;
13270 if (trim_info.x == (int) windows->image.ximage->width)
13271 {
13272 XSetCursorState(display,windows,MagickFalse);
13273 return(MagickFalse);
13274 }
13275 /*
13276 Crop the right edge.
13277 */
13278 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13279 for (x=windows->image.ximage->width-1; x != 0; x--)
13280 {
13281 for (y=0; y < windows->image.ximage->height; y++)
13282 {
13283 pixel=XGetPixel(windows->image.ximage,x,y);
13284 if (pixel != background)
13285 break;
13286 }
13287 if (y < windows->image.ximage->height)
13288 break;
13289 }
13290 trim_info.width=(unsigned long) (x-trim_info.x+1);
13291 /*
13292 Crop the top edge.
13293 */
13294 background=XGetPixel(windows->image.ximage,0,0);
13295 trim_info.height=(unsigned long) windows->image.ximage->height;
13296 for (y=0; y < windows->image.ximage->height; y++)
13297 {
13298 for (x=0; x < windows->image.ximage->width; x++)
13299 {
13300 pixel=XGetPixel(windows->image.ximage,x,y);
13301 if (pixel != background)
13302 break;
13303 }
13304 if (x < windows->image.ximage->width)
13305 break;
13306 }
13307 trim_info.y=y;
13308 /*
13309 Crop the bottom edge.
13310 */
13311 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13312 for (y=windows->image.ximage->height-1; y != 0; y--)
13313 {
13314 for (x=0; x < windows->image.ximage->width; x++)
13315 {
13316 pixel=XGetPixel(windows->image.ximage,x,y);
13317 if (pixel != background)
13318 break;
13319 }
13320 if (x < windows->image.ximage->width)
13321 break;
13322 }
13323 trim_info.height=(unsigned long) y-trim_info.y+1;
13324 if (((unsigned int) trim_info.width != windows->image.width) ||
13325 ((unsigned int) trim_info.height != windows->image.height))
13326 {
13327 /*
13328 Reconfigure Image window as defined by the trimming rectangle.
13329 */
13330 XSetCropGeometry(display,windows,&trim_info,image);
13331 windows->image.window_changes.width=(int) trim_info.width;
13332 windows->image.window_changes.height=(int) trim_info.height;
13333 (void) XConfigureImage(display,resource_info,windows,image);
13334 }
13335 XSetCursorState(display,windows,MagickFalse);
13336 return(MagickTrue);
13337}
13338
13339/*
13340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13341% %
13342% %
13343% %
13344+ X V i s u a l D i r e c t o r y I m a g e %
13345% %
13346% %
13347% %
13348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13349%
13350% XVisualDirectoryImage() creates a Visual Image Directory.
13351%
13352% The format of the XVisualDirectoryImage method is:
13353%
13354% Image *XVisualDirectoryImage(Display *display,
13355% XResourceInfo *resource_info,XWindows *windows)
13356%
13357% A description of each parameter follows:
13358%
13359% o nexus: Method XVisualDirectoryImage returns a visual image
13360% directory if it can be created successfully. Otherwise a null image
13361% is returned.
13362%
13363% o display: Specifies a connection to an X server; returned from
13364% XOpenDisplay.
13365%
13366% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13367%
13368% o windows: Specifies a pointer to a XWindows structure.
13369%
13370*/
13371static Image *XVisualDirectoryImage(Display *display,
13372 XResourceInfo *resource_info,XWindows *windows)
13373{
13374#define TileImageTag "Scale/Image"
13375#define XClientName "montage"
13376
13377 char
13378 **filelist;
13379
13380 ExceptionInfo
13381 *exception;
13382
13383 Image
13384 *images,
13385 *montage_image,
13386 *next_image,
13387 *thumbnail_image;
13388
13389 ImageInfo
13390 *read_info;
13391
13392 int
13393 number_files;
13394
13395 MagickBooleanType
13396 backdrop;
13397
13398 MagickStatusType
13399 status;
13400
13401 MontageInfo
13402 *montage_info;
13403
13404 RectangleInfo
13405 geometry;
13406
13407 register int
13408 i;
13409
13410 static char
13411 filename[MaxTextExtent] = "\0",
13412 filenames[MaxTextExtent] = "*";
13413
13414 XResourceInfo
13415 background_resources;
13416
13417 /*
13418 Request file name from user.
13419 */
13420 XFileBrowserWidget(display,windows,"Directory",filenames);
13421 if (*filenames == '\0')
13422 return((Image *) NULL);
13423 /*
13424 Expand the filenames.
13425 */
cristy90823212009-12-12 20:48:33 +000013426 filelist=(char **) AcquireAlignedMemory(1,sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013427 if (filelist == (char **) NULL)
13428 {
13429 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13430 filenames);
13431 return((Image *) NULL);
13432 }
13433 number_files=1;
13434 filelist[0]=filenames;
13435 status=ExpandFilenames(&number_files,&filelist);
13436 if ((status == MagickFalse) || (number_files == 0))
13437 {
13438 if (number_files == 0)
13439 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13440 else
13441 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13442 filenames);
13443 return((Image *) NULL);
13444 }
13445 /*
13446 Set image background resources.
13447 */
13448 background_resources=(*resource_info);
13449 background_resources.window_id=AcquireString("");
13450 (void) FormatMagickString(background_resources.window_id,MaxTextExtent,
13451 "0x%lx",windows->image.id);
13452 background_resources.backdrop=MagickTrue;
13453 /*
13454 Read each image and convert them to a tile.
13455 */
13456 backdrop=(windows->visual_info->klass == TrueColor) ||
13457 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13458 read_info=CloneImageInfo(resource_info->image_info);
13459 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13460 (void *) NULL);
13461 images=NewImageList();
13462 exception=AcquireExceptionInfo();
13463 XSetCursorState(display,windows,MagickTrue);
13464 XCheckRefreshWindows(display,windows);
13465 for (i=0; i < (long) number_files; i++)
13466 {
13467 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13468 filelist[i]=DestroyString(filelist[i]);
13469 *read_info->magick='\0';
13470 (void) CloneString(&read_info->size,DefaultTileGeometry);
13471 next_image=ReadImage(read_info,exception);
13472 CatchException(exception);
13473 if (next_image != (Image *) NULL)
13474 {
13475 (void) DeleteImageProperty(next_image,"label");
13476 (void) SetImageProperty(next_image,"label",DefaultTileLabel);
13477 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13478 exception);
13479 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13480 geometry.height,exception);
13481 if (thumbnail_image != (Image *) NULL)
13482 {
13483 next_image=DestroyImage(next_image);
13484 next_image=thumbnail_image;
13485 }
13486 if (backdrop)
13487 {
13488 (void) XDisplayBackgroundImage(display,&background_resources,
13489 next_image);
13490 XSetCursorState(display,windows,MagickTrue);
13491 }
13492 AppendImageToList(&images,next_image);
13493 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13494 {
13495 MagickBooleanType
13496 proceed;
13497
13498 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13499 (MagickSizeType) number_files);
13500 if (proceed == MagickFalse)
13501 break;
13502 }
13503 }
13504 }
13505 exception=DestroyExceptionInfo(exception);
13506 filelist=(char **) RelinquishMagickMemory(filelist);
13507 read_info=DestroyImageInfo(read_info);
13508 if (images == (Image *) NULL)
13509 {
13510 XSetCursorState(display,windows,MagickFalse);
13511 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13512 return((Image *) NULL);
13513 }
13514 /*
13515 Create the Visual Image Directory.
13516 */
13517 montage_info=CloneMontageInfo(resource_info->image_info,(MontageInfo *) NULL);
13518 if (resource_info->font != (char *) NULL)
13519 (void) CloneString(&montage_info->font,resource_info->font);
13520 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13521 montage_image=MontageImageList(resource_info->image_info,montage_info,
13522 GetFirstImageInList(images),&images->exception);
13523 montage_info=DestroyMontageInfo(montage_info);
13524 images=DestroyImageList(images);
13525 XSetCursorState(display,windows,MagickFalse);
13526 if (montage_image == (Image *) NULL)
13527 return(montage_image);
13528 XClientMessage(display,windows->image.id,windows->im_protocols,
13529 windows->im_next_image,CurrentTime);
13530 return(montage_image);
13531}
13532
13533/*
13534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13535% %
13536% %
13537% %
13538% X D i s p l a y B a c k g r o u n d I m a g e %
13539% %
13540% %
13541% %
13542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13543%
13544% XDisplayBackgroundImage() displays an image in the background of a window.
13545%
13546% The format of the XDisplayBackgroundImage method is:
13547%
13548% MagickBooleanType XDisplayBackgroundImage(Display *display,
13549% XResourceInfo *resource_info,Image *image)
13550%
13551% A description of each parameter follows:
13552%
13553% o display: Specifies a connection to an X server; returned from
13554% XOpenDisplay.
13555%
13556% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13557%
13558% o image: the image.
13559%
13560*/
13561MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13562 XResourceInfo *resource_info,Image *image)
13563{
13564 char
13565 geometry[MaxTextExtent],
13566 visual_type[MaxTextExtent];
13567
13568 int
13569 height,
13570 status,
13571 width;
13572
13573 RectangleInfo
13574 geometry_info;
13575
13576 static XPixelInfo
13577 pixel;
13578
13579 static XStandardColormap
13580 *map_info;
13581
13582 static XVisualInfo
13583 *visual_info = (XVisualInfo *) NULL;
13584
13585 static XWindowInfo
13586 window_info;
13587
13588 unsigned long
13589 delay;
13590
13591 Window
13592 root_window;
13593
13594 XGCValues
13595 context_values;
13596
13597 XResourceInfo
13598 resources;
13599
13600 XWindowAttributes
13601 window_attributes;
13602
13603 /*
13604 Determine target window.
13605 */
13606 assert(image != (Image *) NULL);
13607 assert(image->signature == MagickSignature);
13608 if (image->debug != MagickFalse)
13609 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13610 resources=(*resource_info);
13611 window_info.id=(Window) NULL;
13612 root_window=XRootWindow(display,XDefaultScreen(display));
13613 if (LocaleCompare(resources.window_id,"root") == 0)
13614 window_info.id=root_window;
13615 else
13616 {
13617 if (isdigit((unsigned char) *resources.window_id) != 0)
13618 window_info.id=XWindowByID(display,root_window,
13619 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13620 if (window_info.id == (Window) NULL)
13621 window_info.id=XWindowByName(display,root_window,resources.window_id);
13622 }
13623 if (window_info.id == (Window) NULL)
13624 {
13625 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13626 resources.window_id);
13627 return(MagickFalse);
13628 }
13629 /*
13630 Determine window visual id.
13631 */
13632 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13633 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13634 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13635 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13636 if (status != 0)
13637 (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
13638 XVisualIDFromVisual(window_attributes.visual));
13639 if (visual_info == (XVisualInfo *) NULL)
13640 {
13641 /*
13642 Allocate standard colormap.
13643 */
13644 map_info=XAllocStandardColormap();
13645 if (map_info == (XStandardColormap *) NULL)
13646 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13647 image->filename);
13648 map_info->colormap=(Colormap) NULL;
13649 pixel.pixels=(unsigned long *) NULL;
13650 /*
13651 Initialize visual info.
13652 */
13653 resources.map_type=(char *) NULL;
13654 resources.visual_type=visual_type;
13655 visual_info=XBestVisualInfo(display,map_info,&resources);
13656 if (visual_info == (XVisualInfo *) NULL)
13657 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13658 resources.visual_type);
13659 /*
13660 Initialize window info.
13661 */
13662 window_info.ximage=(XImage *) NULL;
13663 window_info.matte_image=(XImage *) NULL;
13664 window_info.pixmap=(Pixmap) NULL;
13665 window_info.matte_pixmap=(Pixmap) NULL;
13666 }
13667 /*
13668 Free previous root colors.
13669 */
13670 if (window_info.id == root_window)
13671 (void) XDestroyWindowColors(display,root_window);
13672 /*
13673 Initialize Standard Colormap.
13674 */
13675 resources.colormap=SharedColormap;
13676 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13677 /*
13678 Graphic context superclass.
13679 */
13680 context_values.background=pixel.background_color.pixel;
13681 context_values.foreground=pixel.foreground_color.pixel;
13682 pixel.annotate_context=XCreateGC(display,window_info.id,
13683 (unsigned long) (GCBackground | GCForeground),&context_values);
13684 if (pixel.annotate_context == (GC) NULL)
13685 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13686 image->filename);
13687 /*
13688 Initialize Image window attributes.
13689 */
13690 window_info.name=AcquireString("\0");
13691 window_info.icon_name=AcquireString("\0");
13692 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13693 &resources,&window_info);
13694 /*
13695 Create the X image.
13696 */
13697 window_info.width=(unsigned int) image->columns;
13698 window_info.height=(unsigned int) image->rows;
13699 if ((image->columns != window_info.width) ||
13700 (image->rows != window_info.height))
13701 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13702 image->filename);
13703 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
13704 window_attributes.width,window_attributes.height);
13705 geometry_info.width=window_info.width;
13706 geometry_info.height=window_info.height;
13707 geometry_info.x=window_info.x;
13708 geometry_info.y=window_info.y;
13709 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13710 &geometry_info.width,&geometry_info.height);
13711 window_info.width=(unsigned int) geometry_info.width;
13712 window_info.height=(unsigned int) geometry_info.height;
13713 window_info.x=(int) geometry_info.x;
13714 window_info.y=(int) geometry_info.y;
13715 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13716 window_info.height);
13717 if (status == MagickFalse)
13718 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13719 image->filename);
13720 window_info.x=0;
13721 window_info.y=0;
13722 if (image->debug != MagickFalse)
13723 {
13724 (void) LogMagickEvent(X11Event,GetMagickModule(),
13725 "Image: %s[%lu] %lux%lu ",image->filename,image->scene,
13726 image->columns,image->rows);
13727 if (image->colors != 0)
13728 (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",image->colors);
13729 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13730 }
13731 /*
13732 Adjust image dimensions as specified by backdrop or geometry options.
13733 */
13734 width=(int) window_info.width;
13735 height=(int) window_info.height;
13736 if (resources.backdrop != MagickFalse)
13737 {
13738 /*
13739 Center image on window.
13740 */
13741 window_info.x=(window_attributes.width/2)-
13742 (window_info.ximage->width/2);
13743 window_info.y=(window_attributes.height/2)-
13744 (window_info.ximage->height/2);
13745 width=window_attributes.width;
13746 height=window_attributes.height;
13747 }
13748 if ((resources.image_geometry != (char *) NULL) &&
13749 (*resources.image_geometry != '\0'))
13750 {
13751 char
13752 default_geometry[MaxTextExtent];
13753
13754 int
13755 flags,
13756 gravity;
13757
13758 XSizeHints
13759 *size_hints;
13760
13761 /*
13762 User specified geometry.
13763 */
13764 size_hints=XAllocSizeHints();
13765 if (size_hints == (XSizeHints *) NULL)
13766 ThrowXWindowFatalException(ResourceLimitFatalError,
13767 "MemoryAllocationFailed",image->filename);
13768 size_hints->flags=0L;
13769 (void) FormatMagickString(default_geometry,MaxTextExtent,"%dx%d",
13770 width,height);
13771 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13772 default_geometry,window_info.border_width,size_hints,&window_info.x,
13773 &window_info.y,&width,&height,&gravity);
13774 if (flags & (XValue | YValue))
13775 {
13776 width=window_attributes.width;
13777 height=window_attributes.height;
13778 }
13779 (void) XFree((void *) size_hints);
13780 }
13781 /*
13782 Create the X pixmap.
13783 */
13784 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13785 (unsigned int) height,window_info.depth);
13786 if (window_info.pixmap == (Pixmap) NULL)
13787 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13788 image->filename);
13789 /*
13790 Display pixmap on the window.
13791 */
13792 if (((unsigned int) width > window_info.width) ||
13793 ((unsigned int) height > window_info.height))
13794 (void) XFillRectangle(display,window_info.pixmap,
13795 window_info.annotate_context,0,0,(unsigned int) width,
13796 (unsigned int) height);
13797 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13798 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13799 window_info.width,(unsigned int) window_info.height);
13800 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13801 (void) XClearWindow(display,window_info.id);
13802 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13803 XDelay(display,delay == 0UL ? 10UL : delay);
13804 (void) XSync(display,MagickFalse);
13805 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13806}
13807
13808/*
13809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13810% %
13811% %
13812% %
13813+ X D i s p l a y I m a g e %
13814% %
13815% %
13816% %
13817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13818%
13819% XDisplayImage() displays an image via X11. A new image is created and
13820% returned if the user interactively transforms the displayed image.
13821%
13822% The format of the XDisplayImage method is:
13823%
13824% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13825% char **argv,int argc,Image **image,unsigned long *state)
13826%
13827% A description of each parameter follows:
13828%
13829% o nexus: Method XDisplayImage returns an image when the
13830% user chooses 'Open Image' from the command menu or picks a tile
13831% from the image directory. Otherwise a null image is returned.
13832%
13833% o display: Specifies a connection to an X server; returned from
13834% XOpenDisplay.
13835%
13836% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13837%
13838% o argv: Specifies the application's argument list.
13839%
13840% o argc: Specifies the number of arguments.
13841%
13842% o image: Specifies an address to an address of an Image structure;
13843%
13844*/
13845MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13846 char **argv,int argc,Image **image,unsigned long *state)
13847{
13848#define MagnifySize 256 /* must be a power of 2 */
13849#define MagickMenus 10
13850#define MagickTitle "Commands"
13851
13852 static const char
13853 *CommandMenu[] =
13854 {
13855 "File",
13856 "Edit",
13857 "View",
13858 "Transform",
13859 "Enhance",
13860 "Effects",
13861 "F/X",
13862 "Image Edit",
13863 "Miscellany",
13864 "Help",
13865 (char *) NULL
13866 },
13867 *FileMenu[] =
13868 {
13869 "Open...",
13870 "Next",
13871 "Former",
13872 "Select...",
13873 "Save...",
13874 "Print...",
13875 "Delete...",
13876 "New...",
13877 "Visual Directory...",
13878 "Quit",
13879 (char *) NULL
13880 },
13881 *EditMenu[] =
13882 {
13883 "Undo",
13884 "Redo",
13885 "Cut",
13886 "Copy",
13887 "Paste",
13888 (char *) NULL
13889 },
13890 *ViewMenu[] =
13891 {
13892 "Half Size",
13893 "Original Size",
13894 "Double Size",
13895 "Resize...",
13896 "Apply",
13897 "Refresh",
13898 "Restore",
13899 (char *) NULL
13900 },
13901 *TransformMenu[] =
13902 {
13903 "Crop",
13904 "Chop",
13905 "Flop",
13906 "Flip",
13907 "Rotate Right",
13908 "Rotate Left",
13909 "Rotate...",
13910 "Shear...",
13911 "Roll...",
13912 "Trim Edges",
13913 (char *) NULL
13914 },
13915 *EnhanceMenu[] =
13916 {
13917 "Hue...",
13918 "Saturation...",
13919 "Brightness...",
13920 "Gamma...",
13921 "Spiff",
13922 "Dull",
13923 "Contrast Stretch...",
13924 "Sigmoidal Contrast...",
13925 "Normalize",
13926 "Equalize",
13927 "Negate",
13928 "Grayscale",
13929 "Map...",
13930 "Quantize...",
13931 (char *) NULL
13932 },
13933 *EffectsMenu[] =
13934 {
13935 "Despeckle",
13936 "Emboss",
13937 "Reduce Noise",
13938 "Add Noise...",
13939 "Sharpen...",
13940 "Blur...",
13941 "Threshold...",
13942 "Edge Detect...",
13943 "Spread...",
13944 "Shade...",
13945 "Raise...",
13946 "Segment...",
13947 (char *) NULL
13948 },
13949 *FXMenu[] =
13950 {
13951 "Solarize...",
13952 "Sepia Tone...",
13953 "Swirl...",
13954 "Implode...",
13955 "Vignette...",
13956 "Wave...",
13957 "Oil Paint...",
13958 "Charcoal Draw...",
13959 (char *) NULL
13960 },
13961 *ImageEditMenu[] =
13962 {
13963 "Annotate...",
13964 "Draw...",
13965 "Color...",
13966 "Matte...",
13967 "Composite...",
13968 "Add Border...",
13969 "Add Frame...",
13970 "Comment...",
13971 "Launch...",
13972 "Region of Interest...",
13973 (char *) NULL
13974 },
13975 *MiscellanyMenu[] =
13976 {
13977 "Image Info",
13978 "Zoom Image",
13979 "Show Preview...",
13980 "Show Histogram",
13981 "Show Matte",
13982 "Background...",
13983 "Slide Show...",
13984 "Preferences...",
13985 (char *) NULL
13986 },
13987 *HelpMenu[] =
13988 {
13989 "Overview",
13990 "Browse Documentation",
13991 "About Display",
13992 (char *) NULL
13993 },
13994 *ShortCutsMenu[] =
13995 {
13996 "Next",
13997 "Former",
13998 "Open...",
13999 "Save...",
14000 "Print...",
14001 "Undo",
14002 "Restore",
14003 "Image Info",
14004 "Quit",
14005 (char *) NULL
14006 },
14007 *VirtualMenu[] =
14008 {
14009 "Image Info",
14010 "Print",
14011 "Next",
14012 "Quit",
14013 (char *) NULL
14014 };
14015
14016 static const char
14017 **Menus[MagickMenus] =
14018 {
14019 FileMenu,
14020 EditMenu,
14021 ViewMenu,
14022 TransformMenu,
14023 EnhanceMenu,
14024 EffectsMenu,
14025 FXMenu,
14026 ImageEditMenu,
14027 MiscellanyMenu,
14028 HelpMenu
14029 };
14030
14031 static CommandType
14032 CommandMenus[] =
14033 {
14034 NullCommand,
14035 NullCommand,
14036 NullCommand,
14037 NullCommand,
14038 NullCommand,
14039 NullCommand,
14040 NullCommand,
14041 NullCommand,
14042 NullCommand,
14043 NullCommand,
14044 },
14045 FileCommands[] =
14046 {
14047 OpenCommand,
14048 NextCommand,
14049 FormerCommand,
14050 SelectCommand,
14051 SaveCommand,
14052 PrintCommand,
14053 DeleteCommand,
14054 NewCommand,
14055 VisualDirectoryCommand,
14056 QuitCommand
14057 },
14058 EditCommands[] =
14059 {
14060 UndoCommand,
14061 RedoCommand,
14062 CutCommand,
14063 CopyCommand,
14064 PasteCommand
14065 },
14066 ViewCommands[] =
14067 {
14068 HalfSizeCommand,
14069 OriginalSizeCommand,
14070 DoubleSizeCommand,
14071 ResizeCommand,
14072 ApplyCommand,
14073 RefreshCommand,
14074 RestoreCommand
14075 },
14076 TransformCommands[] =
14077 {
14078 CropCommand,
14079 ChopCommand,
14080 FlopCommand,
14081 FlipCommand,
14082 RotateRightCommand,
14083 RotateLeftCommand,
14084 RotateCommand,
14085 ShearCommand,
14086 RollCommand,
14087 TrimCommand
14088 },
14089 EnhanceCommands[] =
14090 {
14091 HueCommand,
14092 SaturationCommand,
14093 BrightnessCommand,
14094 GammaCommand,
14095 SpiffCommand,
14096 DullCommand,
14097 ContrastStretchCommand,
14098 SigmoidalContrastCommand,
14099 NormalizeCommand,
14100 EqualizeCommand,
14101 NegateCommand,
14102 GrayscaleCommand,
14103 MapCommand,
14104 QuantizeCommand
14105 },
14106 EffectsCommands[] =
14107 {
14108 DespeckleCommand,
14109 EmbossCommand,
14110 ReduceNoiseCommand,
14111 AddNoiseCommand,
14112 SharpenCommand,
14113 BlurCommand,
14114 ThresholdCommand,
14115 EdgeDetectCommand,
14116 SpreadCommand,
14117 ShadeCommand,
14118 RaiseCommand,
14119 SegmentCommand
14120 },
14121 FXCommands[] =
14122 {
14123 SolarizeCommand,
14124 SepiaToneCommand,
14125 SwirlCommand,
14126 ImplodeCommand,
14127 VignetteCommand,
14128 WaveCommand,
14129 OilPaintCommand,
14130 CharcoalDrawCommand
14131 },
14132 ImageEditCommands[] =
14133 {
14134 AnnotateCommand,
14135 DrawCommand,
14136 ColorCommand,
14137 MatteCommand,
14138 CompositeCommand,
14139 AddBorderCommand,
14140 AddFrameCommand,
14141 CommentCommand,
14142 LaunchCommand,
14143 RegionofInterestCommand
14144 },
14145 MiscellanyCommands[] =
14146 {
14147 InfoCommand,
14148 ZoomCommand,
14149 ShowPreviewCommand,
14150 ShowHistogramCommand,
14151 ShowMatteCommand,
14152 BackgroundCommand,
14153 SlideShowCommand,
14154 PreferencesCommand
14155 },
14156 HelpCommands[] =
14157 {
14158 HelpCommand,
14159 BrowseDocumentationCommand,
14160 VersionCommand
14161 },
14162 ShortCutsCommands[] =
14163 {
14164 NextCommand,
14165 FormerCommand,
14166 OpenCommand,
14167 SaveCommand,
14168 PrintCommand,
14169 UndoCommand,
14170 RestoreCommand,
14171 InfoCommand,
14172 QuitCommand
14173 },
14174 VirtualCommands[] =
14175 {
14176 InfoCommand,
14177 PrintCommand,
14178 NextCommand,
14179 QuitCommand
14180 };
14181
14182 static CommandType
14183 *Commands[MagickMenus] =
14184 {
14185 FileCommands,
14186 EditCommands,
14187 ViewCommands,
14188 TransformCommands,
14189 EnhanceCommands,
14190 EffectsCommands,
14191 FXCommands,
14192 ImageEditCommands,
14193 MiscellanyCommands,
14194 HelpCommands
14195 };
14196
14197 char
14198 command[MaxTextExtent],
14199 *cwd,
14200 geometry[MaxTextExtent],
14201 resource_name[MaxTextExtent];
14202
14203 CommandType
14204 command_type;
14205
14206 Image
14207 *display_image,
14208 *nexus;
14209
14210 int
14211 entry,
14212 id;
14213
14214 KeySym
14215 key_symbol;
14216
14217 MagickStatusType
14218 context_mask,
14219 status;
14220
14221 RectangleInfo
14222 geometry_info;
14223
14224 register int
14225 i;
14226
14227 static char
14228 working_directory[MaxTextExtent];
14229
14230 static XPoint
14231 vid_info;
14232
14233 static XWindowInfo
14234 *magick_windows[MaxXWindows];
14235
14236 static unsigned int
14237 number_windows;
14238
14239 struct stat
14240 attributes;
14241
14242 time_t
14243 timer,
14244 timestamp,
14245 update_time;
14246
14247 unsigned int
14248 height,
14249 width;
14250
14251 unsigned long
14252 delay;
14253
14254 WarningHandler
14255 warning_handler;
14256
14257 Window
14258 root_window;
14259
14260 XClassHint
14261 *class_hints;
14262
14263 XEvent
14264 event;
14265
14266 XFontStruct
14267 *font_info;
14268
14269 XGCValues
14270 context_values;
14271
14272 XPixelInfo
14273 *icon_pixel,
14274 *pixel;
14275
14276 XResourceInfo
14277 *icon_resources;
14278
14279 XStandardColormap
14280 *icon_map,
14281 *map_info;
14282
14283 XVisualInfo
14284 *icon_visual,
14285 *visual_info;
14286
14287 XWindowChanges
14288 window_changes;
14289
14290 XWindows
14291 *windows;
14292
14293 XWMHints
14294 *manager_hints;
14295
14296 assert(image != (Image **) NULL);
14297 assert((*image)->signature == MagickSignature);
14298 if ((*image)->debug != MagickFalse)
14299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14300 display_image=(*image);
14301 warning_handler=(WarningHandler) NULL;
14302 windows=XSetWindows((XWindows *) ~0);
14303 if (windows != (XWindows *) NULL)
14304 {
14305 int
14306 status;
14307
14308 status=chdir(working_directory);
14309 if (status == -1)
14310 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14311 FileOpenError,"UnableToOpenFile","%s",working_directory);
14312 warning_handler=resource_info->display_warnings ?
14313 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14314 warning_handler=resource_info->display_warnings ?
14315 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14316 }
14317 else
14318 {
14319 /*
14320 Allocate windows structure.
14321 */
14322 resource_info->colors=display_image->colors;
14323 windows=XSetWindows(XInitializeWindows(display,resource_info));
14324 if (windows == (XWindows *) NULL)
14325 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14326 (*image)->filename);
14327 /*
14328 Initialize window id's.
14329 */
14330 number_windows=0;
14331 magick_windows[number_windows++]=(&windows->icon);
14332 magick_windows[number_windows++]=(&windows->backdrop);
14333 magick_windows[number_windows++]=(&windows->image);
14334 magick_windows[number_windows++]=(&windows->info);
14335 magick_windows[number_windows++]=(&windows->command);
14336 magick_windows[number_windows++]=(&windows->widget);
14337 magick_windows[number_windows++]=(&windows->popup);
14338 magick_windows[number_windows++]=(&windows->magnify);
14339 magick_windows[number_windows++]=(&windows->pan);
14340 for (i=0; i < (int) number_windows; i++)
14341 magick_windows[i]->id=(Window) NULL;
14342 vid_info.x=0;
14343 vid_info.y=0;
14344 }
14345 /*
14346 Initialize font info.
14347 */
14348 if (windows->font_info != (XFontStruct *) NULL)
14349 (void) XFreeFont(display,windows->font_info);
14350 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14351 if (windows->font_info == (XFontStruct *) NULL)
14352 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14353 resource_info->font);
14354 /*
14355 Initialize Standard Colormap.
14356 */
14357 map_info=windows->map_info;
14358 icon_map=windows->icon_map;
14359 visual_info=windows->visual_info;
14360 icon_visual=windows->icon_visual;
14361 pixel=windows->pixel_info;
14362 icon_pixel=windows->icon_pixel;
14363 font_info=windows->font_info;
14364 icon_resources=windows->icon_resources;
14365 class_hints=windows->class_hints;
14366 manager_hints=windows->manager_hints;
14367 root_window=XRootWindow(display,visual_info->screen);
14368 nexus=NewImageList();
14369 if (display_image->debug != MagickFalse)
14370 {
14371 (void) LogMagickEvent(X11Event,GetMagickModule(),
14372 "Image: %s[%lu] %lux%lu ",display_image->filename,
14373 display_image->scene,display_image->columns,display_image->rows);
14374 if (display_image->colors != 0)
14375 (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
14376 display_image->colors);
14377 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14378 display_image->magick);
14379 }
14380 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14381 map_info,pixel);
14382 display_image->taint=MagickFalse;
14383 /*
14384 Initialize graphic context.
14385 */
14386 windows->context.id=(Window) NULL;
14387 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14388 resource_info,&windows->context);
14389 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14390 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14391 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14392 manager_hints->flags=InputHint | StateHint;
14393 manager_hints->input=MagickFalse;
14394 manager_hints->initial_state=WithdrawnState;
14395 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14396 &windows->context);
14397 if (display_image->debug != MagickFalse)
14398 (void) LogMagickEvent(X11Event,GetMagickModule(),
14399 "Window id: 0x%lx (context)",windows->context.id);
14400 context_values.background=pixel->background_color.pixel;
14401 context_values.font=font_info->fid;
14402 context_values.foreground=pixel->foreground_color.pixel;
14403 context_values.graphics_exposures=MagickFalse;
14404 context_mask=(MagickStatusType)
14405 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14406 if (pixel->annotate_context != (GC) NULL)
14407 (void) XFreeGC(display,pixel->annotate_context);
14408 pixel->annotate_context=XCreateGC(display,windows->context.id,
14409 context_mask,&context_values);
14410 if (pixel->annotate_context == (GC) NULL)
14411 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14412 display_image->filename);
14413 context_values.background=pixel->depth_color.pixel;
14414 if (pixel->widget_context != (GC) NULL)
14415 (void) XFreeGC(display,pixel->widget_context);
14416 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14417 &context_values);
14418 if (pixel->widget_context == (GC) NULL)
14419 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14420 display_image->filename);
14421 context_values.background=pixel->foreground_color.pixel;
14422 context_values.foreground=pixel->background_color.pixel;
14423 context_values.plane_mask=context_values.background ^
14424 context_values.foreground;
14425 if (pixel->highlight_context != (GC) NULL)
14426 (void) XFreeGC(display,pixel->highlight_context);
14427 pixel->highlight_context=XCreateGC(display,windows->context.id,
14428 (unsigned long) (context_mask | GCPlaneMask),&context_values);
14429 if (pixel->highlight_context == (GC) NULL)
14430 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14431 display_image->filename);
14432 (void) XDestroyWindow(display,windows->context.id);
14433 /*
14434 Initialize icon window.
14435 */
14436 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14437 icon_resources,&windows->icon);
14438 windows->icon.geometry=resource_info->icon_geometry;
14439 XBestIconSize(display,&windows->icon,display_image);
14440 windows->icon.attributes.colormap=XDefaultColormap(display,
14441 icon_visual->screen);
14442 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14443 manager_hints->flags=InputHint | StateHint;
14444 manager_hints->input=MagickFalse;
14445 manager_hints->initial_state=IconicState;
14446 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14447 &windows->icon);
14448 if (display_image->debug != MagickFalse)
14449 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14450 windows->icon.id);
14451 /*
14452 Initialize graphic context for icon window.
14453 */
14454 if (icon_pixel->annotate_context != (GC) NULL)
14455 (void) XFreeGC(display,icon_pixel->annotate_context);
14456 context_values.background=icon_pixel->background_color.pixel;
14457 context_values.foreground=icon_pixel->foreground_color.pixel;
14458 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14459 (unsigned long) (GCBackground | GCForeground),&context_values);
14460 if (icon_pixel->annotate_context == (GC) NULL)
14461 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14462 display_image->filename);
14463 windows->icon.annotate_context=icon_pixel->annotate_context;
14464 /*
14465 Initialize Image window.
14466 */
14467 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14468 &windows->image);
14469 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14470 if (resource_info->use_shared_memory == MagickFalse)
14471 windows->image.shared_memory=MagickFalse;
14472 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14473 {
14474 char
14475 *title;
14476
14477 title=InterpretImageProperties(resource_info->image_info,display_image,
14478 resource_info->title);
14479 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14480 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14481 title=DestroyString(title);
14482 }
14483 else
14484 {
14485 char
14486 filename[MaxTextExtent];
14487
14488 /*
14489 Window name is the base of the filename.
14490 */
14491 GetPathComponent(display_image->magick_filename,TailPath,filename);
14492 if (GetImageListLength(display_image) == 1)
14493 (void) FormatMagickString(windows->image.name,MaxTextExtent,
14494 "ImageMagick: %s",filename);
14495 else
14496 (void) FormatMagickString(windows->image.name,MaxTextExtent,
14497 "ImageMagick: %s[%lu of %lu]",filename,display_image->scene,
14498 GetImageListLength(display_image));
14499 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14500 }
14501 if (resource_info->immutable)
14502 windows->image.immutable=MagickTrue;
14503 windows->image.use_pixmap=resource_info->use_pixmap;
14504 windows->image.geometry=resource_info->image_geometry;
14505 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14506 XDisplayWidth(display,visual_info->screen),
14507 XDisplayHeight(display,visual_info->screen));
14508 geometry_info.width=display_image->columns;
14509 geometry_info.height=display_image->rows;
14510 geometry_info.x=0;
14511 geometry_info.y=0;
14512 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14513 &geometry_info.width,&geometry_info.height);
14514 windows->image.width=(unsigned int) geometry_info.width;
14515 windows->image.height=(unsigned int) geometry_info.height;
14516 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14517 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14518 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14519 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14520 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14521 resource_info,&windows->backdrop);
14522 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14523 {
14524 /*
14525 Initialize backdrop window.
14526 */
14527 windows->backdrop.x=0;
14528 windows->backdrop.y=0;
14529 (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
14530 windows->backdrop.flags=(unsigned long) (USSize | USPosition);
14531 windows->backdrop.width=(unsigned int)
14532 XDisplayWidth(display,visual_info->screen);
14533 windows->backdrop.height=(unsigned int)
14534 XDisplayHeight(display,visual_info->screen);
14535 windows->backdrop.border_width=0;
14536 windows->backdrop.immutable=MagickTrue;
14537 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14538 ButtonReleaseMask;
14539 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14540 StructureNotifyMask;
14541 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14542 manager_hints->icon_window=windows->icon.id;
14543 manager_hints->input=MagickTrue;
14544 manager_hints->initial_state=resource_info->iconic ? IconicState :
14545 NormalState;
14546 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14547 &windows->backdrop);
14548 if (display_image->debug != MagickFalse)
14549 (void) LogMagickEvent(X11Event,GetMagickModule(),
14550 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14551 (void) XMapWindow(display,windows->backdrop.id);
14552 (void) XClearWindow(display,windows->backdrop.id);
14553 if (windows->image.id != (Window) NULL)
14554 {
14555 (void) XDestroyWindow(display,windows->image.id);
14556 windows->image.id=(Window) NULL;
14557 }
14558 /*
14559 Position image in the center the backdrop.
14560 */
14561 windows->image.flags|=USPosition;
14562 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14563 (windows->image.width/2);
14564 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14565 (windows->image.height/2);
14566 }
14567 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14568 manager_hints->icon_window=windows->icon.id;
14569 manager_hints->input=MagickTrue;
14570 manager_hints->initial_state=resource_info->iconic ? IconicState :
14571 NormalState;
14572 if (windows->group_leader.id != (Window) NULL)
14573 {
14574 /*
14575 Follow the leader.
14576 */
14577 manager_hints->flags|=WindowGroupHint;
14578 manager_hints->window_group=windows->group_leader.id;
14579 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14580 if (display_image->debug != MagickFalse)
14581 (void) LogMagickEvent(X11Event,GetMagickModule(),
14582 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14583 }
14584 XMakeWindow(display,
14585 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14586 argv,argc,class_hints,manager_hints,&windows->image);
14587 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14588 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14589 if (windows->group_leader.id != (Window) NULL)
14590 (void) XSetTransientForHint(display,windows->image.id,
14591 windows->group_leader.id);
14592 if (display_image->debug != MagickFalse)
14593 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14594 windows->image.id);
14595 /*
14596 Initialize Info widget.
14597 */
14598 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14599 &windows->info);
14600 (void) CloneString(&windows->info.name,"Info");
14601 (void) CloneString(&windows->info.icon_name,"Info");
14602 windows->info.border_width=1;
14603 windows->info.x=2;
14604 windows->info.y=2;
14605 windows->info.flags|=PPosition;
14606 windows->info.attributes.win_gravity=UnmapGravity;
14607 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14608 StructureNotifyMask;
14609 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14610 manager_hints->input=MagickFalse;
14611 manager_hints->initial_state=NormalState;
14612 manager_hints->window_group=windows->image.id;
14613 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14614 &windows->info);
14615 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14616 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14617 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14618 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14619 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14620 if (windows->image.mapped != MagickFalse)
14621 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14622 if (display_image->debug != MagickFalse)
14623 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14624 windows->info.id);
14625 /*
14626 Initialize Command widget.
14627 */
14628 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14629 resource_info,&windows->command);
14630 windows->command.data=MagickMenus;
14631 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14632 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
14633 resource_info->client_name);
14634 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14635 resource_name,"geometry",(char *) NULL);
14636 (void) CloneString(&windows->command.name,MagickTitle);
14637 windows->command.border_width=0;
14638 windows->command.flags|=PPosition;
14639 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14640 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14641 OwnerGrabButtonMask | StructureNotifyMask;
14642 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14643 manager_hints->input=MagickTrue;
14644 manager_hints->initial_state=NormalState;
14645 manager_hints->window_group=windows->image.id;
14646 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14647 &windows->command);
14648 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14649 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14650 HighlightHeight);
14651 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14652 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14653 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14654 if (windows->command.mapped != MagickFalse)
14655 (void) XMapRaised(display,windows->command.id);
14656 if (display_image->debug != MagickFalse)
14657 (void) LogMagickEvent(X11Event,GetMagickModule(),
14658 "Window id: 0x%lx (command)",windows->command.id);
14659 /*
14660 Initialize Widget window.
14661 */
14662 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14663 resource_info,&windows->widget);
14664 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
14665 resource_info->client_name);
14666 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14667 resource_name,"geometry",(char *) NULL);
14668 windows->widget.border_width=0;
14669 windows->widget.flags|=PPosition;
14670 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14671 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14672 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14673 StructureNotifyMask;
14674 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14675 manager_hints->input=MagickTrue;
14676 manager_hints->initial_state=NormalState;
14677 manager_hints->window_group=windows->image.id;
14678 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14679 &windows->widget);
14680 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14681 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14682 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14683 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14684 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14685 if (display_image->debug != MagickFalse)
14686 (void) LogMagickEvent(X11Event,GetMagickModule(),
14687 "Window id: 0x%lx (widget)",windows->widget.id);
14688 /*
14689 Initialize popup window.
14690 */
14691 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14692 resource_info,&windows->popup);
14693 windows->popup.border_width=0;
14694 windows->popup.flags|=PPosition;
14695 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14696 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14697 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14698 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14699 manager_hints->input=MagickTrue;
14700 manager_hints->initial_state=NormalState;
14701 manager_hints->window_group=windows->image.id;
14702 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14703 &windows->popup);
14704 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14705 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14706 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14707 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14708 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14709 if (display_image->debug != MagickFalse)
14710 (void) LogMagickEvent(X11Event,GetMagickModule(),
14711 "Window id: 0x%lx (pop up)",windows->popup.id);
14712 /*
14713 Initialize Magnify window and cursor.
14714 */
14715 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14716 resource_info,&windows->magnify);
14717 if (resource_info->use_shared_memory == MagickFalse)
14718 windows->magnify.shared_memory=MagickFalse;
14719 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.magnify",
14720 resource_info->client_name);
14721 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14722 resource_name,"geometry",(char *) NULL);
14723 (void) FormatMagickString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14724 resource_info->magnify);
14725 if (windows->magnify.cursor != (Cursor) NULL)
14726 (void) XFreeCursor(display,windows->magnify.cursor);
14727 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14728 map_info->colormap,resource_info->background_color,
14729 resource_info->foreground_color);
14730 if (windows->magnify.cursor == (Cursor) NULL)
14731 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14732 display_image->filename);
14733 windows->magnify.width=MagnifySize;
14734 windows->magnify.height=MagnifySize;
14735 windows->magnify.flags|=PPosition;
14736 windows->magnify.min_width=MagnifySize;
14737 windows->magnify.min_height=MagnifySize;
14738 windows->magnify.width_inc=MagnifySize;
14739 windows->magnify.height_inc=MagnifySize;
14740 windows->magnify.data=resource_info->magnify;
14741 windows->magnify.attributes.cursor=windows->magnify.cursor;
14742 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14743 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14744 StructureNotifyMask;
14745 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14746 manager_hints->input=MagickTrue;
14747 manager_hints->initial_state=NormalState;
14748 manager_hints->window_group=windows->image.id;
14749 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14750 &windows->magnify);
14751 if (display_image->debug != MagickFalse)
14752 (void) LogMagickEvent(X11Event,GetMagickModule(),
14753 "Window id: 0x%lx (magnify)",windows->magnify.id);
14754 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14755 /*
14756 Initialize panning window.
14757 */
14758 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14759 resource_info,&windows->pan);
14760 (void) CloneString(&windows->pan.name,"Pan Icon");
14761 windows->pan.width=windows->icon.width;
14762 windows->pan.height=windows->icon.height;
14763 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.pan",
14764 resource_info->client_name);
14765 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14766 resource_name,"geometry",(char *) NULL);
14767 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14768 &windows->pan.width,&windows->pan.height);
14769 windows->pan.flags|=PPosition;
14770 windows->pan.immutable=MagickTrue;
14771 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14772 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14773 StructureNotifyMask;
14774 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14775 manager_hints->input=MagickFalse;
14776 manager_hints->initial_state=NormalState;
14777 manager_hints->window_group=windows->image.id;
14778 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14779 &windows->pan);
14780 if (display_image->debug != MagickFalse)
14781 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14782 windows->pan.id);
14783 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14784 if (windows->info.mapped != MagickFalse)
14785 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14786 if ((windows->image.mapped == MagickFalse) ||
14787 (windows->backdrop.id != (Window) NULL))
14788 (void) XMapWindow(display,windows->image.id);
14789 /*
14790 Set our progress monitor and warning handlers.
14791 */
14792 if (warning_handler == (WarningHandler) NULL)
14793 {
14794 warning_handler=resource_info->display_warnings ?
14795 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14796 warning_handler=resource_info->display_warnings ?
14797 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14798 }
14799 /*
14800 Initialize Image and Magnify X images.
14801 */
14802 windows->image.x=0;
14803 windows->image.y=0;
14804 windows->magnify.shape=MagickFalse;
14805 width=(unsigned int) display_image->columns;
14806 height=(unsigned int) display_image->rows;
14807 if ((display_image->columns != width) || (display_image->rows != height))
14808 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14809 display_image->filename);
14810 status=XMakeImage(display,resource_info,&windows->image,display_image,
14811 width,height);
14812 if (status == MagickFalse)
14813 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14814 display_image->filename);
14815 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14816 windows->magnify.width,windows->magnify.height);
14817 if (status == MagickFalse)
14818 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14819 display_image->filename);
14820 if (windows->magnify.mapped != MagickFalse)
14821 (void) XMapRaised(display,windows->magnify.id);
14822 if (windows->pan.mapped != MagickFalse)
14823 (void) XMapRaised(display,windows->pan.id);
14824 windows->image.window_changes.width=(int) display_image->columns;
14825 windows->image.window_changes.height=(int) display_image->rows;
14826 (void) XConfigureImage(display,resource_info,windows,display_image);
14827 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14828 (void) XSync(display,MagickFalse);
14829 /*
14830 Respond to events.
14831 */
14832 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14833 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14834 update_time=0;
14835 if (resource_info->update != MagickFalse)
14836 {
14837 MagickBooleanType
14838 status;
14839
14840 /*
14841 Determine when file data was last modified.
14842 */
14843 status=GetPathAttributes(display_image->filename,&attributes);
14844 if (status != MagickFalse)
14845 update_time=attributes.st_mtime;
14846 }
14847 *state&=(~FormerImageState);
14848 *state&=(~MontageImageState);
14849 *state&=(~NextImageState);
14850 do
14851 {
14852 /*
14853 Handle a window event.
14854 */
14855 if (windows->image.mapped != MagickFalse)
14856 if ((display_image->delay != 0) || (resource_info->update != 0))
14857 {
14858 if (timer < time((time_t *) NULL))
14859 {
14860 if (resource_info->update == MagickFalse)
14861 *state|=NextImageState | ExitState;
14862 else
14863 {
14864 MagickBooleanType
14865 status;
14866
14867 /*
14868 Determine if image file was modified.
14869 */
14870 status=GetPathAttributes(display_image->filename,&attributes);
14871 if (status != MagickFalse)
14872 if (update_time != attributes.st_mtime)
14873 {
14874 /*
14875 Redisplay image.
14876 */
14877 (void) FormatMagickString(
14878 resource_info->image_info->filename,MaxTextExtent,
14879 "%s:%s",display_image->magick,
14880 display_image->filename);
14881 nexus=ReadImage(resource_info->image_info,
14882 &display_image->exception);
14883 if (nexus != (Image *) NULL)
14884 {
14885 nexus=DestroyImage(nexus);
14886 *state|=NextImageState | ExitState;
14887 }
14888 }
14889 delay=display_image->delay/MagickMax(
14890 display_image->ticks_per_second,1L);
14891 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
14892 }
14893 }
14894 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14895 {
14896 /*
14897 Do not block if delay > 0.
14898 */
14899 XDelay(display,SuspendTime << 2);
14900 continue;
14901 }
14902 }
14903 timestamp=time((time_t *) NULL);
14904 (void) XNextEvent(display,&event);
14905 if (windows->image.stasis == MagickFalse)
14906 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14907 MagickTrue : MagickFalse;
14908 if (windows->magnify.stasis == MagickFalse)
14909 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
14910 MagickTrue : MagickFalse;
14911 if (event.xany.window == windows->command.id)
14912 {
14913 /*
14914 Select a command from the Command widget.
14915 */
14916 id=XCommandWidget(display,windows,CommandMenu,&event);
14917 if (id < 0)
14918 continue;
14919 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
14920 command_type=CommandMenus[id];
14921 if (id < MagickMenus)
14922 {
14923 /*
14924 Select a command from a pop-up menu.
14925 */
14926 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
14927 command);
14928 if (entry < 0)
14929 continue;
14930 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
14931 command_type=Commands[id][entry];
14932 }
14933 if (command_type != NullCommand)
14934 nexus=XMagickCommand(display,resource_info,windows,command_type,
14935 &display_image);
14936 continue;
14937 }
14938 switch (event.type)
14939 {
14940 case ButtonPress:
14941 {
14942 if (display_image->debug != MagickFalse)
14943 (void) LogMagickEvent(X11Event,GetMagickModule(),
14944 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
14945 event.xbutton.button,event.xbutton.x,event.xbutton.y);
14946 if ((event.xbutton.button == Button3) &&
14947 (event.xbutton.state & Mod1Mask))
14948 {
14949 /*
14950 Convert Alt-Button3 to Button2.
14951 */
14952 event.xbutton.button=Button2;
14953 event.xbutton.state&=(~Mod1Mask);
14954 }
14955 if (event.xbutton.window == windows->backdrop.id)
14956 {
14957 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
14958 event.xbutton.time);
14959 break;
14960 }
14961 if (event.xbutton.window == windows->image.id)
14962 {
14963 switch (event.xbutton.button)
14964 {
14965 case Button1:
14966 {
14967 if (resource_info->immutable)
14968 {
14969 /*
14970 Select a command from the Virtual menu.
14971 */
14972 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
14973 command);
14974 if (entry >= 0)
14975 nexus=XMagickCommand(display,resource_info,windows,
14976 VirtualCommands[entry],&display_image);
14977 break;
14978 }
14979 /*
14980 Map/unmap Command widget.
14981 */
14982 if (windows->command.mapped != MagickFalse)
14983 (void) XWithdrawWindow(display,windows->command.id,
14984 windows->command.screen);
14985 else
14986 {
14987 (void) XCommandWidget(display,windows,CommandMenu,
14988 (XEvent *) NULL);
14989 (void) XMapRaised(display,windows->command.id);
14990 }
14991 break;
14992 }
14993 case Button2:
14994 {
14995 /*
14996 User pressed the image magnify button.
14997 */
14998 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
14999 &display_image);
15000 XMagnifyImage(display,windows,&event);
15001 break;
15002 }
15003 case Button3:
15004 {
15005 if (resource_info->immutable)
15006 {
15007 /*
15008 Select a command from the Virtual menu.
15009 */
15010 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15011 command);
15012 if (entry >= 0)
15013 nexus=XMagickCommand(display,resource_info,windows,
15014 VirtualCommands[entry],&display_image);
15015 break;
15016 }
15017 if (display_image->montage != (char *) NULL)
15018 {
15019 /*
15020 Open or delete a tile from a visual image directory.
15021 */
15022 nexus=XTileImage(display,resource_info,windows,
15023 display_image,&event);
15024 if (nexus != (Image *) NULL)
15025 *state|=MontageImageState | NextImageState | ExitState;
15026 vid_info.x=windows->image.x;
15027 vid_info.y=windows->image.y;
15028 break;
15029 }
15030 /*
15031 Select a command from the Short Cuts menu.
15032 */
15033 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15034 command);
15035 if (entry >= 0)
15036 nexus=XMagickCommand(display,resource_info,windows,
15037 ShortCutsCommands[entry],&display_image);
15038 break;
15039 }
15040 case Button4:
15041 {
15042 /*
15043 Wheel up.
15044 */
15045 XTranslateImage(display,windows,*image,XK_Up);
15046 break;
15047 }
15048 case Button5:
15049 {
15050 /*
15051 Wheel down.
15052 */
15053 XTranslateImage(display,windows,*image,XK_Down);
15054 break;
15055 }
15056 default:
15057 break;
15058 }
15059 break;
15060 }
15061 if (event.xbutton.window == windows->magnify.id)
15062 {
15063 int
15064 factor;
15065
15066 static const char
15067 *MagnifyMenu[] =
15068 {
15069 "2",
15070 "4",
15071 "5",
15072 "6",
15073 "7",
15074 "8",
15075 "9",
15076 "3",
15077 (char *) NULL,
15078 };
15079
15080 static KeySym
15081 MagnifyCommands[] =
15082 {
15083 XK_2,
15084 XK_4,
15085 XK_5,
15086 XK_6,
15087 XK_7,
15088 XK_8,
15089 XK_9,
15090 XK_3
15091 };
15092
15093 /*
15094 Select a magnify factor from the pop-up menu.
15095 */
15096 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15097 if (factor >= 0)
15098 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15099 break;
15100 }
15101 if (event.xbutton.window == windows->pan.id)
15102 {
15103 switch (event.xbutton.button)
15104 {
15105 case Button4:
15106 {
15107 /*
15108 Wheel up.
15109 */
15110 XTranslateImage(display,windows,*image,XK_Up);
15111 break;
15112 }
15113 case Button5:
15114 {
15115 /*
15116 Wheel down.
15117 */
15118 XTranslateImage(display,windows,*image,XK_Down);
15119 break;
15120 }
15121 default:
15122 {
15123 XPanImage(display,windows,&event);
15124 break;
15125 }
15126 }
15127 break;
15128 }
15129 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15130 1L);
15131 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15132 break;
15133 }
15134 case ButtonRelease:
15135 {
15136 if (display_image->debug != MagickFalse)
15137 (void) LogMagickEvent(X11Event,GetMagickModule(),
15138 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15139 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15140 break;
15141 }
15142 case ClientMessage:
15143 {
15144 if (display_image->debug != MagickFalse)
15145 (void) LogMagickEvent(X11Event,GetMagickModule(),
15146 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15147 event.xclient.message_type,event.xclient.format,(unsigned long)
15148 event.xclient.data.l[0]);
15149 if (event.xclient.message_type == windows->im_protocols)
15150 {
15151 if (*event.xclient.data.l == (long) windows->im_update_widget)
15152 {
15153 (void) CloneString(&windows->command.name,MagickTitle);
15154 windows->command.data=MagickMenus;
15155 (void) XCommandWidget(display,windows,CommandMenu,
15156 (XEvent *) NULL);
15157 break;
15158 }
15159 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15160 {
15161 /*
15162 Update graphic context and window colormap.
15163 */
15164 for (i=0; i < (int) number_windows; i++)
15165 {
15166 if (magick_windows[i]->id == windows->icon.id)
15167 continue;
15168 context_values.background=pixel->background_color.pixel;
15169 context_values.foreground=pixel->foreground_color.pixel;
15170 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15171 context_mask,&context_values);
15172 (void) XChangeGC(display,magick_windows[i]->widget_context,
15173 context_mask,&context_values);
15174 context_values.background=pixel->foreground_color.pixel;
15175 context_values.foreground=pixel->background_color.pixel;
15176 context_values.plane_mask=context_values.background ^
15177 context_values.foreground;
15178 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15179 (unsigned long) (context_mask | GCPlaneMask),
15180 &context_values);
15181 magick_windows[i]->attributes.background_pixel=
15182 pixel->background_color.pixel;
15183 magick_windows[i]->attributes.border_pixel=
15184 pixel->border_color.pixel;
15185 magick_windows[i]->attributes.colormap=map_info->colormap;
15186 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15187 magick_windows[i]->mask,&magick_windows[i]->attributes);
15188 }
15189 if (windows->pan.mapped != MagickFalse)
15190 {
15191 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15192 windows->pan.pixmap);
15193 (void) XClearWindow(display,windows->pan.id);
15194 XDrawPanRectangle(display,windows);
15195 }
15196 if (windows->backdrop.id != (Window) NULL)
15197 (void) XInstallColormap(display,map_info->colormap);
15198 break;
15199 }
15200 if (*event.xclient.data.l == (long) windows->im_former_image)
15201 {
15202 *state|=FormerImageState | ExitState;
15203 break;
15204 }
15205 if (*event.xclient.data.l == (long) windows->im_next_image)
15206 {
15207 *state|=NextImageState | ExitState;
15208 break;
15209 }
15210 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15211 {
15212 *state|=RetainColorsState;
15213 break;
15214 }
15215 if (*event.xclient.data.l == (long) windows->im_exit)
15216 {
15217 *state|=ExitState;
15218 break;
15219 }
15220 break;
15221 }
15222 if (event.xclient.message_type == windows->dnd_protocols)
15223 {
15224 Atom
15225 selection,
15226 type;
15227
15228 int
15229 format,
15230 status;
15231
15232 unsigned char
15233 *data;
15234
15235 unsigned long
15236 after,
15237 length;
15238
15239 /*
15240 Display image named by the Drag-and-Drop selection.
15241 */
15242 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15243 break;
15244 selection=XInternAtom(display,"DndSelection",MagickFalse);
15245 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15246 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15247 &length,&after,&data);
15248 if ((status != Success) || (length == 0))
15249 break;
15250 if (*event.xclient.data.l == 2)
15251 {
15252 /*
15253 Offix DND.
15254 */
15255 (void) CopyMagickString(resource_info->image_info->filename,
15256 (char *) data,MaxTextExtent);
15257 }
15258 else
15259 {
15260 /*
15261 XDND.
15262 */
15263 if (strncmp((char *) data, "file:", 5) != 0)
15264 {
15265 (void) XFree((void *) data);
15266 break;
15267 }
15268 (void) CopyMagickString(resource_info->image_info->filename,
15269 ((char *) data)+5,MaxTextExtent);
15270 }
15271 nexus=ReadImage(resource_info->image_info,
15272 &display_image->exception);
15273 CatchException(&display_image->exception);
15274 if (nexus != (Image *) NULL)
15275 *state|=NextImageState | ExitState;
15276 (void) XFree((void *) data);
15277 break;
15278 }
15279 /*
15280 If client window delete message, exit.
15281 */
15282 if (event.xclient.message_type != windows->wm_protocols)
15283 break;
15284 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15285 break;
15286 (void) XWithdrawWindow(display,event.xclient.window,
15287 visual_info->screen);
15288 if (event.xclient.window == windows->image.id)
15289 {
15290 *state|=ExitState;
15291 break;
15292 }
15293 if (event.xclient.window == windows->pan.id)
15294 {
15295 /*
15296 Restore original image size when pan window is deleted.
15297 */
15298 windows->image.window_changes.width=windows->image.ximage->width;
15299 windows->image.window_changes.height=windows->image.ximage->height;
15300 (void) XConfigureImage(display,resource_info,windows,
15301 display_image);
15302 }
15303 break;
15304 }
15305 case ConfigureNotify:
15306 {
15307 if (display_image->debug != MagickFalse)
15308 (void) LogMagickEvent(X11Event,GetMagickModule(),
15309 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15310 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15311 event.xconfigure.y,event.xconfigure.send_event);
15312 if (event.xconfigure.window == windows->image.id)
15313 {
15314 /*
15315 Image window has a new configuration.
15316 */
15317 if (event.xconfigure.send_event != 0)
15318 {
15319 XWindowChanges
15320 window_changes;
15321
15322 /*
15323 Position the transient windows relative of the Image window.
15324 */
15325 if (windows->command.geometry == (char *) NULL)
15326 if (windows->command.mapped == MagickFalse)
15327 {
15328 windows->command.x=event.xconfigure.x-
15329 windows->command.width-25;
15330 windows->command.y=event.xconfigure.y;
15331 XConstrainWindowPosition(display,&windows->command);
15332 window_changes.x=windows->command.x;
15333 window_changes.y=windows->command.y;
15334 (void) XReconfigureWMWindow(display,windows->command.id,
15335 windows->command.screen,(unsigned int) (CWX | CWY),
15336 &window_changes);
15337 }
15338 if (windows->widget.geometry == (char *) NULL)
15339 if (windows->widget.mapped == MagickFalse)
15340 {
15341 windows->widget.x=event.xconfigure.x+
15342 event.xconfigure.width/10;
15343 windows->widget.y=event.xconfigure.y+
15344 event.xconfigure.height/10;
15345 XConstrainWindowPosition(display,&windows->widget);
15346 window_changes.x=windows->widget.x;
15347 window_changes.y=windows->widget.y;
15348 (void) XReconfigureWMWindow(display,windows->widget.id,
15349 windows->widget.screen,(unsigned int) (CWX | CWY),
15350 &window_changes);
15351 }
15352 if (windows->magnify.geometry == (char *) NULL)
15353 if (windows->magnify.mapped == MagickFalse)
15354 {
15355 windows->magnify.x=event.xconfigure.x+
15356 event.xconfigure.width+25;
15357 windows->magnify.y=event.xconfigure.y;
15358 XConstrainWindowPosition(display,&windows->magnify);
15359 window_changes.x=windows->magnify.x;
15360 window_changes.y=windows->magnify.y;
15361 (void) XReconfigureWMWindow(display,windows->magnify.id,
15362 windows->magnify.screen,(unsigned int) (CWX | CWY),
15363 &window_changes);
15364 }
15365 if (windows->pan.geometry == (char *) NULL)
15366 if (windows->pan.mapped == MagickFalse)
15367 {
15368 windows->pan.x=event.xconfigure.x+
15369 event.xconfigure.width+25;
15370 windows->pan.y=event.xconfigure.y+
15371 windows->magnify.height+50;
15372 XConstrainWindowPosition(display,&windows->pan);
15373 window_changes.x=windows->pan.x;
15374 window_changes.y=windows->pan.y;
15375 (void) XReconfigureWMWindow(display,windows->pan.id,
15376 windows->pan.screen,(unsigned int) (CWX | CWY),
15377 &window_changes);
15378 }
15379 }
15380 if ((event.xconfigure.width == (long) windows->image.width) &&
15381 (event.xconfigure.height == (long) windows->image.height))
15382 break;
15383 windows->image.width=(unsigned int) event.xconfigure.width;
15384 windows->image.height=(unsigned int) event.xconfigure.height;
15385 windows->image.x=0;
15386 windows->image.y=0;
15387 if (display_image->montage != (char *) NULL)
15388 {
15389 windows->image.x=vid_info.x;
15390 windows->image.y=vid_info.y;
15391 }
cristy34b9f452010-01-06 20:04:29 +000015392 if ((windows->image.mapped != MagickFalse) &&
15393 (windows->image.stasis != MagickFalse))
15394 {
15395 /*
15396 Update image window configuration.
15397 */
15398 windows->image.window_changes.width=event.xconfigure.width;
15399 windows->image.window_changes.height=event.xconfigure.height;
15400 (void) XConfigureImage(display,resource_info,windows,
15401 display_image);
15402 }
cristy3ed852e2009-09-05 21:47:34 +000015403 /*
15404 Update pan window configuration.
15405 */
15406 if ((event.xconfigure.width < windows->image.ximage->width) ||
15407 (event.xconfigure.height < windows->image.ximage->height))
15408 {
15409 (void) XMapRaised(display,windows->pan.id);
15410 XDrawPanRectangle(display,windows);
15411 }
15412 else
15413 if (windows->pan.mapped != MagickFalse)
15414 (void) XWithdrawWindow(display,windows->pan.id,
15415 windows->pan.screen);
15416 break;
15417 }
15418 if (event.xconfigure.window == windows->magnify.id)
15419 {
15420 unsigned int
15421 magnify;
15422
15423 /*
15424 Magnify window has a new configuration.
15425 */
15426 windows->magnify.width=(unsigned int) event.xconfigure.width;
15427 windows->magnify.height=(unsigned int) event.xconfigure.height;
15428 if (windows->magnify.mapped == MagickFalse)
15429 break;
15430 magnify=1;
15431 while ((int) magnify <= event.xconfigure.width)
15432 magnify<<=1;
15433 while ((int) magnify <= event.xconfigure.height)
15434 magnify<<=1;
15435 magnify>>=1;
15436 if (((int) magnify != event.xconfigure.width) ||
15437 ((int) magnify != event.xconfigure.height))
15438 {
15439 window_changes.width=(int) magnify;
15440 window_changes.height=(int) magnify;
15441 (void) XReconfigureWMWindow(display,windows->magnify.id,
15442 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15443 &window_changes);
15444 break;
15445 }
15446 if ((windows->magnify.mapped != MagickFalse) &&
15447 (windows->magnify.stasis != MagickFalse))
15448 {
15449 status=XMakeImage(display,resource_info,&windows->magnify,
15450 display_image,windows->magnify.width,windows->magnify.height);
15451 XMakeMagnifyImage(display,windows);
15452 }
15453 break;
15454 }
15455 if ((windows->magnify.mapped != MagickFalse) &&
15456 (event.xconfigure.window == windows->pan.id))
15457 {
15458 /*
15459 Pan icon window has a new configuration.
15460 */
15461 if (event.xconfigure.send_event != 0)
15462 {
15463 windows->pan.x=event.xconfigure.x;
15464 windows->pan.y=event.xconfigure.y;
15465 }
15466 windows->pan.width=(unsigned int) event.xconfigure.width;
15467 windows->pan.height=(unsigned int) event.xconfigure.height;
15468 break;
15469 }
15470 if (event.xconfigure.window == windows->icon.id)
15471 {
15472 /*
15473 Icon window has a new configuration.
15474 */
15475 windows->icon.width=(unsigned int) event.xconfigure.width;
15476 windows->icon.height=(unsigned int) event.xconfigure.height;
15477 break;
15478 }
15479 break;
15480 }
15481 case DestroyNotify:
15482 {
15483 /*
15484 Group leader has exited.
15485 */
15486 if (display_image->debug != MagickFalse)
15487 (void) LogMagickEvent(X11Event,GetMagickModule(),
15488 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15489 if (event.xdestroywindow.window == windows->group_leader.id)
15490 {
15491 *state|=ExitState;
15492 break;
15493 }
15494 break;
15495 }
15496 case EnterNotify:
15497 {
15498 /*
15499 Selectively install colormap.
15500 */
15501 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15502 if (event.xcrossing.mode != NotifyUngrab)
15503 XInstallColormap(display,map_info->colormap);
15504 break;
15505 }
15506 case Expose:
15507 {
15508 if (display_image->debug != MagickFalse)
15509 (void) LogMagickEvent(X11Event,GetMagickModule(),
15510 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15511 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15512 event.xexpose.y);
15513 /*
15514 Refresh windows that are now exposed.
15515 */
cristy6bee4042010-01-30 15:27:14 +000015516 if ((event.xexpose.window == windows->image.id) &&
15517 (windows->image.mapped != MagickFalse))
15518 {
15519 XRefreshWindow(display,&windows->image,&event);
15520 delay=display_image->delay/MagickMax(
15521 display_image->ticks_per_second,1L);
15522 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15523 break;
15524 }
15525 if ((event.xexpose.window == windows->magnify.id) &&
15526 (windows->magnify.mapped != MagickFalse))
15527 {
15528 XMakeMagnifyImage(display,windows);
15529 break;
15530 }
cristy3ed852e2009-09-05 21:47:34 +000015531 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015532 {
15533 XDrawPanRectangle(display,windows);
15534 break;
15535 }
cristy3ed852e2009-09-05 21:47:34 +000015536 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015537 {
15538 XRefreshWindow(display,&windows->icon,&event);
15539 break;
15540 }
cristy3ed852e2009-09-05 21:47:34 +000015541 break;
15542 }
15543 case KeyPress:
15544 {
15545 int
15546 length;
15547
15548 /*
15549 Respond to a user key press.
15550 */
15551 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15552 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15553 *(command+length)='\0';
15554 if (display_image->debug != MagickFalse)
15555 (void) LogMagickEvent(X11Event,GetMagickModule(),
15556 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15557 key_symbol,command);
15558 if (event.xkey.window == windows->image.id)
15559 {
15560 command_type=XImageWindowCommand(display,resource_info,windows,
15561 event.xkey.state,key_symbol,&display_image);
15562 if (command_type != NullCommand)
15563 nexus=XMagickCommand(display,resource_info,windows,command_type,
15564 &display_image);
15565 }
15566 if (event.xkey.window == windows->magnify.id)
15567 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15568 if (event.xkey.window == windows->pan.id)
15569 {
15570 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15571 (void) XWithdrawWindow(display,windows->pan.id,
15572 windows->pan.screen);
15573 else
15574 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15575 XTextViewWidget(display,resource_info,windows,MagickFalse,
15576 "Help Viewer - Image Pan",ImagePanHelp);
15577 else
15578 XTranslateImage(display,windows,*image,key_symbol);
15579 }
15580 delay=display_image->delay/MagickMax(
15581 display_image->ticks_per_second,1L);
15582 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15583 break;
15584 }
15585 case KeyRelease:
15586 {
15587 /*
15588 Respond to a user key release.
15589 */
15590 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15591 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15592 if (display_image->debug != MagickFalse)
15593 (void) LogMagickEvent(X11Event,GetMagickModule(),
15594 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15595 break;
15596 }
15597 case LeaveNotify:
15598 {
15599 /*
15600 Selectively uninstall colormap.
15601 */
15602 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15603 if (event.xcrossing.mode != NotifyUngrab)
15604 XUninstallColormap(display,map_info->colormap);
15605 break;
15606 }
15607 case MapNotify:
15608 {
15609 if (display_image->debug != MagickFalse)
15610 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15611 event.xmap.window);
15612 if (event.xmap.window == windows->backdrop.id)
15613 {
15614 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15615 CurrentTime);
15616 windows->backdrop.mapped=MagickTrue;
15617 break;
15618 }
15619 if (event.xmap.window == windows->image.id)
15620 {
15621 if (windows->backdrop.id != (Window) NULL)
15622 (void) XInstallColormap(display,map_info->colormap);
15623 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15624 {
15625 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15626 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15627 }
15628 if (((int) windows->image.width < windows->image.ximage->width) ||
15629 ((int) windows->image.height < windows->image.ximage->height))
15630 (void) XMapRaised(display,windows->pan.id);
15631 windows->image.mapped=MagickTrue;
15632 break;
15633 }
15634 if (event.xmap.window == windows->magnify.id)
15635 {
15636 XMakeMagnifyImage(display,windows);
15637 windows->magnify.mapped=MagickTrue;
15638 (void) XWithdrawWindow(display,windows->info.id,
15639 windows->info.screen);
15640 break;
15641 }
15642 if (event.xmap.window == windows->pan.id)
15643 {
15644 XMakePanImage(display,resource_info,windows,display_image);
15645 windows->pan.mapped=MagickTrue;
15646 break;
15647 }
15648 if (event.xmap.window == windows->info.id)
15649 {
15650 windows->info.mapped=MagickTrue;
15651 break;
15652 }
15653 if (event.xmap.window == windows->icon.id)
15654 {
15655 MagickBooleanType
15656 taint;
15657
15658 /*
15659 Create an icon image.
15660 */
15661 taint=display_image->taint;
15662 XMakeStandardColormap(display,icon_visual,icon_resources,
15663 display_image,icon_map,icon_pixel);
15664 (void) XMakeImage(display,icon_resources,&windows->icon,
15665 display_image,windows->icon.width,windows->icon.height);
15666 display_image->taint=taint;
15667 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15668 windows->icon.pixmap);
15669 (void) XClearWindow(display,windows->icon.id);
15670 (void) XWithdrawWindow(display,windows->info.id,
15671 windows->info.screen);
15672 windows->icon.mapped=MagickTrue;
15673 break;
15674 }
15675 if (event.xmap.window == windows->command.id)
15676 {
15677 windows->command.mapped=MagickTrue;
15678 break;
15679 }
15680 if (event.xmap.window == windows->popup.id)
15681 {
15682 windows->popup.mapped=MagickTrue;
15683 break;
15684 }
15685 if (event.xmap.window == windows->widget.id)
15686 {
15687 windows->widget.mapped=MagickTrue;
15688 break;
15689 }
15690 break;
15691 }
15692 case MappingNotify:
15693 {
15694 (void) XRefreshKeyboardMapping(&event.xmapping);
15695 break;
15696 }
15697 case NoExpose:
15698 break;
15699 case PropertyNotify:
15700 {
15701 Atom
15702 type;
15703
15704 int
15705 format,
15706 status;
15707
15708 unsigned char
15709 *data;
15710
15711 unsigned long
15712 after,
15713 length;
15714
15715 if (display_image->debug != MagickFalse)
15716 (void) LogMagickEvent(X11Event,GetMagickModule(),
15717 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15718 event.xproperty.atom,event.xproperty.state);
15719 if (event.xproperty.atom != windows->im_remote_command)
15720 break;
15721 /*
15722 Display image named by the remote command protocol.
15723 */
15724 status=XGetWindowProperty(display,event.xproperty.window,
15725 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15726 AnyPropertyType,&type,&format,&length,&after,&data);
15727 if ((status != Success) || (length == 0))
15728 break;
15729 if (LocaleCompare((char *) data,"-quit") == 0)
15730 {
15731 XClientMessage(display,windows->image.id,windows->im_protocols,
15732 windows->im_exit,CurrentTime);
15733 (void) XFree((void *) data);
15734 break;
15735 }
15736 (void) CopyMagickString(resource_info->image_info->filename,
15737 (char *) data,MaxTextExtent);
15738 (void) XFree((void *) data);
15739 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15740 CatchException(&display_image->exception);
15741 if (nexus != (Image *) NULL)
15742 *state|=NextImageState | ExitState;
15743 break;
15744 }
15745 case ReparentNotify:
15746 {
15747 if (display_image->debug != MagickFalse)
15748 (void) LogMagickEvent(X11Event,GetMagickModule(),
15749 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15750 event.xreparent.window);
15751 break;
15752 }
15753 case UnmapNotify:
15754 {
15755 if (display_image->debug != MagickFalse)
15756 (void) LogMagickEvent(X11Event,GetMagickModule(),
15757 "Unmap Notify: 0x%lx",event.xunmap.window);
15758 if (event.xunmap.window == windows->backdrop.id)
15759 {
15760 windows->backdrop.mapped=MagickFalse;
15761 break;
15762 }
15763 if (event.xunmap.window == windows->image.id)
15764 {
15765 windows->image.mapped=MagickFalse;
15766 break;
15767 }
15768 if (event.xunmap.window == windows->magnify.id)
15769 {
15770 windows->magnify.mapped=MagickFalse;
15771 break;
15772 }
15773 if (event.xunmap.window == windows->pan.id)
15774 {
15775 windows->pan.mapped=MagickFalse;
15776 break;
15777 }
15778 if (event.xunmap.window == windows->info.id)
15779 {
15780 windows->info.mapped=MagickFalse;
15781 break;
15782 }
15783 if (event.xunmap.window == windows->icon.id)
15784 {
15785 if (map_info->colormap == icon_map->colormap)
15786 XConfigureImageColormap(display,resource_info,windows,
15787 display_image);
15788 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15789 icon_pixel);
15790 windows->icon.mapped=MagickFalse;
15791 break;
15792 }
15793 if (event.xunmap.window == windows->command.id)
15794 {
15795 windows->command.mapped=MagickFalse;
15796 break;
15797 }
15798 if (event.xunmap.window == windows->popup.id)
15799 {
15800 if (windows->backdrop.id != (Window) NULL)
15801 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15802 CurrentTime);
15803 windows->popup.mapped=MagickFalse;
15804 break;
15805 }
15806 if (event.xunmap.window == windows->widget.id)
15807 {
15808 if (windows->backdrop.id != (Window) NULL)
15809 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15810 CurrentTime);
15811 windows->widget.mapped=MagickFalse;
15812 break;
15813 }
15814 break;
15815 }
15816 default:
15817 {
15818 if (display_image->debug != MagickFalse)
15819 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15820 event.type);
15821 break;
15822 }
15823 }
15824 } while (!(*state & ExitState));
15825 if ((*state & ExitState) == 0)
15826 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15827 &display_image);
15828 else
15829 if (resource_info->confirm_edit != MagickFalse)
15830 {
15831 /*
15832 Query user if image has changed.
15833 */
15834 if ((resource_info->immutable == MagickFalse) &&
15835 (display_image->taint != MagickFalse))
15836 {
15837 int
15838 status;
15839
15840 status=XConfirmWidget(display,windows,"Your image changed.",
15841 "Do you want to save it");
15842 if (status == 0)
15843 *state&=(~ExitState);
15844 else
15845 if (status > 0)
15846 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15847 &display_image);
15848 }
15849 }
15850 if ((windows->visual_info->klass == GrayScale) ||
15851 (windows->visual_info->klass == PseudoColor) ||
15852 (windows->visual_info->klass == DirectColor))
15853 {
15854 /*
15855 Withdraw pan and Magnify window.
15856 */
15857 if (windows->info.mapped != MagickFalse)
15858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15859 if (windows->magnify.mapped != MagickFalse)
15860 (void) XWithdrawWindow(display,windows->magnify.id,
15861 windows->magnify.screen);
15862 if (windows->command.mapped != MagickFalse)
15863 (void) XWithdrawWindow(display,windows->command.id,
15864 windows->command.screen);
15865 }
15866 if (windows->pan.mapped != MagickFalse)
15867 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15868 if (resource_info->backdrop == MagickFalse)
15869 if (windows->backdrop.mapped)
15870 {
15871 (void) XWithdrawWindow(display,windows->backdrop.id,
15872 windows->backdrop.screen);
15873 (void) XDestroyWindow(display,windows->backdrop.id);
15874 windows->backdrop.id=(Window) NULL;
15875 (void) XWithdrawWindow(display,windows->image.id,
15876 windows->image.screen);
15877 (void) XDestroyWindow(display,windows->image.id);
15878 windows->image.id=(Window) NULL;
15879 }
15880 XSetCursorState(display,windows,MagickTrue);
15881 XCheckRefreshWindows(display,windows);
15882 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15883 *state&=(~ExitState);
15884 if (*state & ExitState)
15885 {
15886 /*
15887 Free Standard Colormap.
15888 */
15889 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15890 if (resource_info->map_type == (char *) NULL)
15891 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15892 /*
15893 Free X resources.
15894 */
15895 if (resource_info->copy_image != (Image *) NULL)
15896 {
15897 resource_info->copy_image=DestroyImage(resource_info->copy_image);
15898 resource_info->copy_image=NewImageList();
15899 }
15900 DestroyXResources();
15901 }
15902 (void) XSync(display,MagickFalse);
15903 /*
15904 Restore our progress monitor and warning handlers.
15905 */
15906 (void) SetErrorHandler(warning_handler);
15907 (void) SetWarningHandler(warning_handler);
15908 /*
15909 Change to home directory.
15910 */
15911 cwd=getcwd(working_directory,MaxTextExtent);
15912 {
15913 int
15914 status;
15915
15916 status=chdir(resource_info->home_directory);
15917 if (status == -1)
15918 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
15919 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
15920 }
15921 *image=display_image;
15922 return(nexus);
15923}
15924#else
15925
15926/*
15927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15928% %
15929% %
15930% %
15931+ D i s p l a y I m a g e s %
15932% %
15933% %
15934% %
15935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15936%
15937% DisplayImages() displays an image sequence to any X window screen. It
15938% returns a value other than 0 if successful. Check the exception member
15939% of image to determine the reason for any failure.
15940%
15941% The format of the DisplayImages method is:
15942%
15943% MagickBooleanType DisplayImages(const ImageInfo *image_info,
15944% Image *images)
15945%
15946% A description of each parameter follows:
15947%
15948% o image_info: the image info.
15949%
15950% o image: the image.
15951%
15952*/
15953MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
15954 Image *image)
15955{
15956 assert(image_info != (const ImageInfo *) NULL);
15957 assert(image_info->signature == MagickSignature);
15958 assert(image != (Image *) NULL);
15959 assert(image->signature == MagickSignature);
15960 if (image->debug != MagickFalse)
15961 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
15962 (void) ThrowMagickException(&image->exception,GetMagickModule(),
15963 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
15964 image->filename);
15965 return(MagickFalse);
15966}
15967
15968/*
15969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15970% %
15971% %
15972% %
15973+ R e m o t e D i s p l a y C o m m a n d %
15974% %
15975% %
15976% %
15977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15978%
15979% RemoteDisplayCommand() encourages a remote display program to display the
15980% specified image filename.
15981%
15982% The format of the RemoteDisplayCommand method is:
15983%
15984% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
15985% const char *window,const char *filename,ExceptionInfo *exception)
15986%
15987% A description of each parameter follows:
15988%
15989% o image_info: the image info.
15990%
15991% o window: Specifies the name or id of an X window.
15992%
15993% o filename: the name of the image filename to display.
15994%
15995% o exception: return any errors or warnings in this structure.
15996%
15997*/
15998MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
15999 const char *window,const char *filename,ExceptionInfo *exception)
16000{
16001 assert(image_info != (const ImageInfo *) NULL);
16002 assert(image_info->signature == MagickSignature);
16003 assert(filename != (char *) NULL);
16004 (void) window;
16005 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16006 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16007 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16008 return(MagickFalse);
16009}
16010#endif