1 /*
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 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % 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 % https://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 "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/composite.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/decorate.h"
55 #include "MagickCore/delegate.h"
56 #include "MagickCore/display.h"
57 #include "MagickCore/display-private.h"
58 #include "MagickCore/distort.h"
59 #include "MagickCore/draw.h"
60 #include "MagickCore/effect.h"
61 #include "MagickCore/enhance.h"
62 #include "MagickCore/exception.h"
63 #include "MagickCore/exception-private.h"
64 #include "MagickCore/fx.h"
65 #include "MagickCore/geometry.h"
66 #include "MagickCore/image.h"
67 #include "MagickCore/image-private.h"
68 #include "MagickCore/list.h"
69 #include "MagickCore/log.h"
70 #include "MagickCore/magick.h"
71 #include "MagickCore/memory_.h"
72 #include "MagickCore/monitor.h"
73 #include "MagickCore/monitor-private.h"
74 #include "MagickCore/montage.h"
75 #include "MagickCore/nt-base-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/paint.h"
78 #include "MagickCore/pixel.h"
79 #include "MagickCore/pixel-accessor.h"
80 #include "MagickCore/property.h"
81 #include "MagickCore/quantum.h"
82 #include "MagickCore/quantum-private.h"
83 #include "MagickCore/resize.h"
84 #include "MagickCore/resource_.h"
85 #include "MagickCore/shear.h"
86 #include "MagickCore/segment.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/string-private.h"
90 #include "MagickCore/timer-private.h"
91 #include "MagickCore/transform.h"
92 #include "MagickCore/transform-private.h"
93 #include "MagickCore/threshold.h"
94 #include "MagickCore/utility.h"
95 #include "MagickCore/utility-private.h"
96 #include "MagickCore/version.h"
97 #include "MagickCore/visual-effects.h"
98 #include "MagickCore/widget.h"
99 #include "MagickCore/widget-private.h"
100 #include "MagickCore/xwindow.h"
101 #include "MagickCore/xwindow-private.h"
102
103 #if defined(MAGICKCORE_X11_DELEGATE)
104 /*
105 Define declarations.
106 */
107 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
108
109 /*
110 Constant declarations.
111 */
112 static const unsigned char
113 HighlightBitmap[8] =
114 {
115 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
116 },
117 OpaqueBitmap[8] =
118 {
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
120 },
121 ShadowBitmap[8] =
122 {
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
124 };
125
126 /*
127 Help widget declarations.
128 */
129 static const char
130 ImageAnnotateHelp[] =
131 {
132 "In annotate mode, the Command widget has these options:\n"
133 "\n"
134 " Font Name\n"
135 " fixed\n"
136 " variable\n"
137 " 5x8\n"
138 " 6x10\n"
139 " 7x13bold\n"
140 " 8x13bold\n"
141 " 9x15bold\n"
142 " 10x20\n"
143 " 12x24\n"
144 " Browser...\n"
145 " Font Color\n"
146 " black\n"
147 " blue\n"
148 " cyan\n"
149 " green\n"
150 " gray\n"
151 " red\n"
152 " magenta\n"
153 " yellow\n"
154 " white\n"
155 " transparent\n"
156 " Browser...\n"
157 " Font Color\n"
158 " black\n"
159 " blue\n"
160 " cyan\n"
161 " green\n"
162 " gray\n"
163 " red\n"
164 " magenta\n"
165 " yellow\n"
166 " white\n"
167 " transparent\n"
168 " Browser...\n"
169 " Rotate Text\n"
170 " -90\n"
171 " -45\n"
172 " -30\n"
173 " 0\n"
174 " 30\n"
175 " 45\n"
176 " 90\n"
177 " 180\n"
178 " Dialog...\n"
179 " Help\n"
180 " Dismiss\n"
181 "\n"
182 "Choose a font name from the Font Name sub-menu. Additional\n"
183 "font names can be specified with the font browser. You can\n"
184 "change the menu names by setting the X resources font1\n"
185 "through font9.\n"
186 "\n"
187 "Choose a font color from the Font Color sub-menu.\n"
188 "Additional font colors can be specified with the color\n"
189 "browser. You can change the menu colors by setting the X\n"
190 "resources pen1 through pen9.\n"
191 "\n"
192 "If you select the color browser and press Grab, you can\n"
193 "choose the font color by moving the pointer to the desired\n"
194 "color on the screen and press any button.\n"
195 "\n"
196 "If you choose to rotate the text, choose Rotate Text from the\n"
197 "menu and select an angle. Typically you will only want to\n"
198 "rotate one line of text at a time. Depending on the angle you\n"
199 "choose, subsequent lines may end up overwriting each other.\n"
200 "\n"
201 "Choosing a font and its color is optional. The default font\n"
202 "is fixed and the default color is black. However, you must\n"
203 "choose a location to begin entering text and press button 1.\n"
204 "An underscore character will appear at the location of the\n"
205 "pointer. The cursor changes to a pencil to indicate you are\n"
206 "in text mode. To exit immediately, press Dismiss.\n"
207 "\n"
208 "In text mode, any key presses will display the character at\n"
209 "the location of the underscore and advance the underscore\n"
210 "cursor. Enter your text and once completed press Apply to\n"
211 "finish your image annotation. To correct errors press BACK\n"
212 "SPACE. To delete an entire line of text, press DELETE. Any\n"
213 "text that exceeds the boundaries of the image window is\n"
214 "automagically continued onto the next line.\n"
215 "\n"
216 "The actual color you request for the font is saved in the\n"
217 "image. However, the color that appears in your image window\n"
218 "may be different. For example, on a monochrome screen the\n"
219 "text will appear black or white even if you choose the color\n"
220 "red as the font color. However, the image saved to a file\n"
221 "with -write is written with red lettering. To assure the\n"
222 "correct color text in the final image, any PseudoClass image\n"
223 "is promoted to DirectClass (see miff(5)). To force a\n"
224 "PseudoClass image to remain PseudoClass, use -colors.\n"
225 },
226 ImageChopHelp[] =
227 {
228 "In chop mode, the Command widget has these options:\n"
229 "\n"
230 " Direction\n"
231 " horizontal\n"
232 " vertical\n"
233 " Help\n"
234 " Dismiss\n"
235 "\n"
236 "If the you choose the horizontal direction (this the\n"
237 "default), the area of the image between the two horizontal\n"
238 "endpoints of the chop line is removed. Otherwise, the area\n"
239 "of the image between the two vertical endpoints of the chop\n"
240 "line is removed.\n"
241 "\n"
242 "Select a location within the image window to begin your chop,\n"
243 "press and hold any button. Next, move the pointer to\n"
244 "another location in the image. As you move a line will\n"
245 "connect the initial location and the pointer. When you\n"
246 "release the button, the area within the image to chop is\n"
247 "determined by which direction you choose from the Command\n"
248 "widget.\n"
249 "\n"
250 "To cancel the image chopping, move the pointer back to the\n"
251 "starting point of the line and release the button.\n"
252 },
253 ImageColorEditHelp[] =
254 {
255 "In color edit mode, the Command widget has these options:\n"
256 "\n"
257 " Method\n"
258 " point\n"
259 " replace\n"
260 " floodfill\n"
261 " filltoborder\n"
262 " reset\n"
263 " Pixel Color\n"
264 " black\n"
265 " blue\n"
266 " cyan\n"
267 " green\n"
268 " gray\n"
269 " red\n"
270 " magenta\n"
271 " yellow\n"
272 " white\n"
273 " Browser...\n"
274 " Border Color\n"
275 " black\n"
276 " blue\n"
277 " cyan\n"
278 " green\n"
279 " gray\n"
280 " red\n"
281 " magenta\n"
282 " yellow\n"
283 " white\n"
284 " Browser...\n"
285 " Fuzz\n"
286 " 0%\n"
287 " 2%\n"
288 " 5%\n"
289 " 10%\n"
290 " 15%\n"
291 " Dialog...\n"
292 " Undo\n"
293 " Help\n"
294 " Dismiss\n"
295 "\n"
296 "Choose a color editing method from the Method sub-menu\n"
297 "of the Command widget. The point method recolors any pixel\n"
298 "selected with the pointer until the button is released. The\n"
299 "replace method recolors any pixel that matches the color of\n"
300 "the pixel you select with a button press. Floodfill recolors\n"
301 "any pixel that matches the color of the pixel you select with\n"
302 "a button press and is a neighbor. Whereas filltoborder recolors\n"
303 "any neighbor pixel that is not the border color. Finally reset\n"
304 "changes the entire image to the designated color.\n"
305 "\n"
306 "Next, choose a pixel color from the Pixel Color sub-menu.\n"
307 "Additional pixel colors can be specified with the color\n"
308 "browser. You can change the menu colors by setting the X\n"
309 "resources pen1 through pen9.\n"
310 "\n"
311 "Now press button 1 to select a pixel within the image window\n"
312 "to change its color. Additional pixels may be recolored as\n"
313 "prescribed by the method you choose.\n"
314 "\n"
315 "If the Magnify widget is mapped, it can be helpful in positioning\n"
316 "your pointer within the image (refer to button 2).\n"
317 "\n"
318 "The actual color you request for the pixels is saved in the\n"
319 "image. However, the color that appears in your image window\n"
320 "may be different. For example, on a monochrome screen the\n"
321 "pixel will appear black or white even if you choose the\n"
322 "color red as the pixel color. However, the image saved to a\n"
323 "file with -write is written with red pixels. To assure the\n"
324 "correct color text in the final image, any PseudoClass image\n"
325 "is promoted to DirectClass (see miff(5)). To force a\n"
326 "PseudoClass image to remain PseudoClass, use -colors.\n"
327 },
328 ImageCompositeHelp[] =
329 {
330 "First a widget window is displayed requesting you to enter an\n"
331 "image name. Press Composite, Grab or type a file name.\n"
332 "Press Cancel if you choose not to create a composite image.\n"
333 "When you choose Grab, move the pointer to the desired window\n"
334 "and press any button.\n"
335 "\n"
336 "If the Composite image does not have any matte information,\n"
337 "you are informed and the file browser is displayed again.\n"
338 "Enter the name of a mask image. The image is typically\n"
339 "grayscale and the same size as the composite image. If the\n"
340 "image is not grayscale, it is converted to grayscale and the\n"
341 "resulting intensities are used as matte information.\n"
342 "\n"
343 "A small window appears showing the location of the cursor in\n"
344 "the image window. You are now in composite mode. To exit\n"
345 "immediately, press Dismiss. In composite mode, the Command\n"
346 "widget has these options:\n"
347 "\n"
348 " Operators\n"
349 " Over\n"
350 " In\n"
351 " Out\n"
352 " Atop\n"
353 " Xor\n"
354 " Plus\n"
355 " Minus\n"
356 " Add\n"
357 " Subtract\n"
358 " Difference\n"
359 " Multiply\n"
360 " Bumpmap\n"
361 " Copy\n"
362 " CopyRed\n"
363 " CopyGreen\n"
364 " CopyBlue\n"
365 " CopyOpacity\n"
366 " Clear\n"
367 " Dissolve\n"
368 " Displace\n"
369 " Help\n"
370 " Dismiss\n"
371 "\n"
372 "Choose a composite operation from the Operators sub-menu of\n"
373 "the Command widget. How each operator behaves is described\n"
374 "below. Image window is the image currently displayed on\n"
375 "your X server and image is the image obtained with the File\n"
376 "Browser widget.\n"
377 "\n"
378 "Over The result is the union of the two image shapes,\n"
379 " with image obscuring image window in the region of\n"
380 " overlap.\n"
381 "\n"
382 "In The result is simply image cut by the shape of\n"
383 " image window. None of the image data of image\n"
384 " window is in the result.\n"
385 "\n"
386 "Out The resulting image is image with the shape of\n"
387 " image window cut out.\n"
388 "\n"
389 "Atop The result is the same shape as image image window,\n"
390 " with image obscuring image window where the image\n"
391 " shapes overlap. Note this differs from over\n"
392 " because the portion of image outside image window's\n"
393 " shape does not appear in the result.\n"
394 "\n"
395 "Xor The result is the image data from both image and\n"
396 " image window that is outside the overlap region.\n"
397 " The overlap region is blank.\n"
398 "\n"
399 "Plus The result is just the sum of the image data.\n"
400 " Output values are cropped to QuantumRange (no overflow).\n"
401 "\n"
402 "Minus The result of image - image window, with underflow\n"
403 " cropped to zero.\n"
404 "\n"
405 "Add The result of image + image window, with overflow\n"
406 " wrapping around (mod 256).\n"
407 "\n"
408 "Subtract The result of image - image window, with underflow\n"
409 " wrapping around (mod 256). The add and subtract\n"
410 " operators can be used to perform reversible\n"
411 " transformations.\n"
412 "\n"
413 "Difference\n"
414 " The result of abs(image - image window). This\n"
415 " useful for comparing two very similar images.\n"
416 "\n"
417 "Multiply\n"
418 " The result of image * image window. This\n"
419 " useful for the creation of drop-shadows.\n"
420 "\n"
421 "Bumpmap The result of surface normals from image * image\n"
422 " window.\n"
423 "\n"
424 "Copy The resulting image is image window replaced with\n"
425 " image. Here the matte information is ignored.\n"
426 "\n"
427 "CopyRed The red layer of the image window is replace with\n"
428 " the red layer of the image. The other layers are\n"
429 " untouched.\n"
430 "\n"
431 "CopyGreen\n"
432 " The green layer of the image window is replace with\n"
433 " the green layer of the image. The other layers are\n"
434 " untouched.\n"
435 "\n"
436 "CopyBlue The blue layer of the image window is replace with\n"
437 " the blue layer of the image. The other layers are\n"
438 " untouched.\n"
439 "\n"
440 "CopyOpacity\n"
441 " The matte layer of the image window is replace with\n"
442 " the matte layer of the image. The other layers are\n"
443 " untouched.\n"
444 "\n"
445 "The image compositor requires a matte, or alpha channel in\n"
446 "the image for some operations. This extra channel usually\n"
447 "defines a mask which represents a sort of a cookie-cutter\n"
448 "for the image. This the case when matte is opaque (full\n"
449 "coverage) for pixels inside the shape, zero outside, and\n"
450 "between 0 and QuantumRange on the boundary. If image does not\n"
451 "have a matte channel, it is initialized with 0 for any pixel\n"
452 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
453 "\n"
454 "If you choose Dissolve, the composite operator becomes Over. The\n"
455 "image matte channel percent transparency is initialized to factor.\n"
456 "The image window is initialized to (100-factor). Where factor is the\n"
457 "value you specify in the Dialog widget.\n"
458 "\n"
459 "Displace shifts the image pixels as defined by a displacement\n"
460 "map. With this option, image is used as a displacement map.\n"
461 "Black, within the displacement map, is a maximum positive\n"
462 "displacement. White is a maximum negative displacement and\n"
463 "middle gray is neutral. The displacement is scaled to determine\n"
464 "the pixel shift. By default, the displacement applies in both the\n"
465 "horizontal and vertical directions. However, if you specify a mask,\n"
466 "image is the horizontal X displacement and mask the vertical Y\n"
467 "displacement.\n"
468 "\n"
469 "Note that matte information for image window is not retained\n"
470 "for colormapped X server visuals (e.g. StaticColor,\n"
471 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
472 "behavior may require a TrueColor or DirectColor visual or a\n"
473 "Standard Colormap.\n"
474 "\n"
475 "Choosing a composite operator is optional. The default\n"
476 "operator is replace. However, you must choose a location to\n"
477 "composite your image and press button 1. Press and hold the\n"
478 "button before releasing and an outline of the image will\n"
479 "appear to help you identify your location.\n"
480 "\n"
481 "The actual colors of the composite image is saved. However,\n"
482 "the color that appears in image window may be different.\n"
483 "For example, on a monochrome screen image window will appear\n"
484 "black or white even though your composited image may have\n"
485 "many colors. If the image is saved to a file it is written\n"
486 "with the correct colors. To assure the correct colors are\n"
487 "saved in the final image, any PseudoClass image is promoted\n"
488 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
489 "to remain PseudoClass, use -colors.\n"
490 },
491 ImageCutHelp[] =
492 {
493 "In cut mode, the Command widget has these options:\n"
494 "\n"
495 " Help\n"
496 " Dismiss\n"
497 "\n"
498 "To define a cut region, press button 1 and drag. The\n"
499 "cut region is defined by a highlighted rectangle that\n"
500 "expands or contracts as it follows the pointer. Once you\n"
501 "are satisfied with the cut region, release the button.\n"
502 "You are now in rectify mode. In rectify mode, the Command\n"
503 "widget has these options:\n"
504 "\n"
505 " Cut\n"
506 " Help\n"
507 " Dismiss\n"
508 "\n"
509 "You can make adjustments by moving the pointer to one of the\n"
510 "cut rectangle corners, pressing a button, and dragging.\n"
511 "Finally, press Cut to commit your copy region. To\n"
512 "exit without cutting the image, press Dismiss.\n"
513 },
514 ImageCopyHelp[] =
515 {
516 "In copy mode, the Command widget has these options:\n"
517 "\n"
518 " Help\n"
519 " Dismiss\n"
520 "\n"
521 "To define a copy region, press button 1 and drag. The\n"
522 "copy region is defined by a highlighted rectangle that\n"
523 "expands or contracts as it follows the pointer. Once you\n"
524 "are satisfied with the copy region, release the button.\n"
525 "You are now in rectify mode. In rectify mode, the Command\n"
526 "widget has these options:\n"
527 "\n"
528 " Copy\n"
529 " Help\n"
530 " Dismiss\n"
531 "\n"
532 "You can make adjustments by moving the pointer to one of the\n"
533 "copy rectangle corners, pressing a button, and dragging.\n"
534 "Finally, press Copy to commit your copy region. To\n"
535 "exit without copying the image, press Dismiss.\n"
536 },
537 ImageCropHelp[] =
538 {
539 "In crop mode, the Command widget has these options:\n"
540 "\n"
541 " Help\n"
542 " Dismiss\n"
543 "\n"
544 "To define a cropping region, press button 1 and drag. The\n"
545 "cropping region is defined by a highlighted rectangle that\n"
546 "expands or contracts as it follows the pointer. Once you\n"
547 "are satisfied with the cropping region, release the button.\n"
548 "You are now in rectify mode. In rectify mode, the Command\n"
549 "widget has these options:\n"
550 "\n"
551 " Crop\n"
552 " Help\n"
553 " Dismiss\n"
554 "\n"
555 "You can make adjustments by moving the pointer to one of the\n"
556 "cropping rectangle corners, pressing a button, and dragging.\n"
557 "Finally, press Crop to commit your cropping region. To\n"
558 "exit without cropping the image, press Dismiss.\n"
559 },
560 ImageDrawHelp[] =
561 {
562 "The cursor changes to a crosshair to indicate you are in\n"
563 "draw mode. To exit immediately, press Dismiss. In draw mode,\n"
564 "the Command widget has these options:\n"
565 "\n"
566 " Element\n"
567 " point\n"
568 " line\n"
569 " rectangle\n"
570 " fill rectangle\n"
571 " circle\n"
572 " fill circle\n"
573 " ellipse\n"
574 " fill ellipse\n"
575 " polygon\n"
576 " fill polygon\n"
577 " Color\n"
578 " black\n"
579 " blue\n"
580 " cyan\n"
581 " green\n"
582 " gray\n"
583 " red\n"
584 " magenta\n"
585 " yellow\n"
586 " white\n"
587 " transparent\n"
588 " Browser...\n"
589 " Stipple\n"
590 " Brick\n"
591 " Diagonal\n"
592 " Scales\n"
593 " Vertical\n"
594 " Wavy\n"
595 " Translucent\n"
596 " Opaque\n"
597 " Open...\n"
598 " Width\n"
599 " 1\n"
600 " 2\n"
601 " 4\n"
602 " 8\n"
603 " 16\n"
604 " Dialog...\n"
605 " Undo\n"
606 " Help\n"
607 " Dismiss\n"
608 "\n"
609 "Choose a drawing primitive from the Element sub-menu.\n"
610 "\n"
611 "Choose a color from the Color sub-menu. Additional\n"
612 "colors can be specified with the color browser.\n"
613 "\n"
614 "If you choose the color browser and press Grab, you can\n"
615 "select the color by moving the pointer to the desired\n"
616 "color on the screen and press any button. The transparent\n"
617 "color updates the image matte channel and is useful for\n"
618 "image compositing.\n"
619 "\n"
620 "Choose a stipple, if appropriate, from the Stipple sub-menu.\n"
621 "Additional stipples can be specified with the file browser.\n"
622 "Stipples obtained from the file browser must be on disk in the\n"
623 "X11 bitmap format.\n"
624 "\n"
625 "Choose a width, if appropriate, from the Width sub-menu. To\n"
626 "choose a specific width select the Dialog widget.\n"
627 "\n"
628 "Choose a point in the Image window and press button 1 and\n"
629 "hold. Next, move the pointer to another location in the\n"
630 "image. As you move, a line connects the initial location and\n"
631 "the pointer. When you release the button, the image is\n"
632 "updated with the primitive you just drew. For polygons, the\n"
633 "image is updated when you press and release the button without\n"
634 "moving the pointer.\n"
635 "\n"
636 "To cancel image drawing, move the pointer back to the\n"
637 "starting point of the line and release the button.\n"
638 },
639 DisplayHelp[] =
640 {
641 "BUTTONS\n"
642 " The effects of each button press is described below. Three\n"
643 " buttons are required. If you have a two button mouse,\n"
644 " button 1 and 3 are returned. Press ALT and button 3 to\n"
645 " simulate button 2.\n"
646 "\n"
647 " 1 Press this button to map or unmap the Command widget.\n"
648 "\n"
649 " 2 Press and drag to define a region of the image to\n"
650 " magnify.\n"
651 "\n"
652 " 3 Press and drag to choose from a select set of commands.\n"
653 " This button behaves differently if the image being\n"
654 " displayed is a visual image directory. Here, choose a\n"
655 " particular tile of the directory and press this button and\n"
656 " drag to select a command from a pop-up menu. Choose from\n"
657 " these menu items:\n"
658 "\n"
659 " Open\n"
660 " Next\n"
661 " Former\n"
662 " Delete\n"
663 " Update\n"
664 "\n"
665 " If you choose Open, the image represented by the tile is\n"
666 " displayed. To return to the visual image directory, choose\n"
667 " Next from the Command widget. Next and Former moves to the\n"
668 " next or former image respectively. Choose Delete to delete\n"
669 " a particular image tile. Finally, choose Update to\n"
670 " synchronize all the image tiles with their respective\n"
671 " images.\n"
672 "\n"
673 "COMMAND WIDGET\n"
674 " The Command widget lists a number of sub-menus and commands.\n"
675 " They are\n"
676 "\n"
677 " File\n"
678 " Open...\n"
679 " Next\n"
680 " Former\n"
681 " Select...\n"
682 " Save...\n"
683 " Print...\n"
684 " Delete...\n"
685 " New...\n"
686 " Visual Directory...\n"
687 " Quit\n"
688 " Edit\n"
689 " Undo\n"
690 " Redo\n"
691 " Cut\n"
692 " Copy\n"
693 " Paste\n"
694 " View\n"
695 " Half Size\n"
696 " Original Size\n"
697 " Double Size\n"
698 " Resize...\n"
699 " Apply\n"
700 " Refresh\n"
701 " Restore\n"
702 " Transform\n"
703 " Crop\n"
704 " Chop\n"
705 " Flop\n"
706 " Flip\n"
707 " Rotate Right\n"
708 " Rotate Left\n"
709 " Rotate...\n"
710 " Shear...\n"
711 " Roll...\n"
712 " Trim Edges\n"
713 " Enhance\n"
714 " Brightness...\n"
715 " Saturation...\n"
716 " Hue...\n"
717 " Gamma...\n"
718 " Sharpen...\n"
719 " Dull\n"
720 " Contrast Stretch...\n"
721 " Sigmoidal Contrast...\n"
722 " Normalize\n"
723 " Equalize\n"
724 " Negate\n"
725 " Grayscale\n"
726 " Map...\n"
727 " Quantize...\n"
728 " Effects\n"
729 " Despeckle\n"
730 " Emboss\n"
731 " Reduce Noise\n"
732 " Add Noise\n"
733 " Sharpen...\n"
734 " Blur...\n"
735 " Threshold...\n"
736 " Edge Detect...\n"
737 " Spread...\n"
738 " Shade...\n"
739 " Painting...\n"
740 " Segment...\n"
741 " F/X\n"
742 " Solarize...\n"
743 " Sepia Tone...\n"
744 " Swirl...\n"
745 " Implode...\n"
746 " Vignette...\n"
747 " Wave...\n"
748 " Oil Painting...\n"
749 " Charcoal Drawing...\n"
750 " Image Edit\n"
751 " Annotate...\n"
752 " Draw...\n"
753 " Color...\n"
754 " Matte...\n"
755 " Composite...\n"
756 " Add Border...\n"
757 " Add Frame...\n"
758 " Comment...\n"
759 " Launch...\n"
760 " Region of Interest...\n"
761 " Miscellany\n"
762 " Image Info\n"
763 " Zoom Image\n"
764 " Show Preview...\n"
765 " Show Histogram\n"
766 " Show Matte\n"
767 " Background...\n"
768 " Slide Show\n"
769 " Preferences...\n"
770 " Help\n"
771 " Overview\n"
772 " Browse Documentation\n"
773 " About Display\n"
774 "\n"
775 " Menu items with a indented triangle have a sub-menu. They\n"
776 " are represented above as the indented items. To access a\n"
777 " sub-menu item, move the pointer to the appropriate menu and\n"
778 " press a button and drag. When you find the desired sub-menu\n"
779 " item, release the button and the command is executed. Move\n"
780 " the pointer away from the sub-menu if you decide not to\n"
781 " execute a particular command.\n"
782 "\n"
783 "KEYBOARD ACCELERATORS\n"
784 " Accelerators are one or two key presses that effect a\n"
785 " particular command. The keyboard accelerators that\n"
786 " display(1) understands is:\n"
787 "\n"
788 " Ctl+O Press to open an image from a file.\n"
789 "\n"
790 " space Press to display the next image.\n"
791 "\n"
792 " If the image is a multi-paged document such as a Postscript\n"
793 " document, you can skip ahead several pages by preceding\n"
794 " this command with a number. For example to display the\n"
795 " third page beyond the current page, press 3<space>.\n"
796 "\n"
797 " backspace Press to display the former image.\n"
798 "\n"
799 " If the image is a multi-paged document such as a Postscript\n"
800 " document, you can skip behind several pages by preceding\n"
801 " this command with a number. For example to display the\n"
802 " third page preceding the current page, press 3<backspace>.\n"
803 "\n"
804 " Ctl+S Press to write the image to a file.\n"
805 "\n"
806 " Ctl+P Press to print the image to a Postscript printer.\n"
807 "\n"
808 " Ctl+D Press to delete an image file.\n"
809 "\n"
810 " Ctl+N Press to create a blank canvas.\n"
811 "\n"
812 " Ctl+Q Press to discard all images and exit program.\n"
813 "\n"
814 " Ctl+Z Press to undo last image transformation.\n"
815 "\n"
816 " Ctl+R Press to redo last image transformation.\n"
817 "\n"
818 " Ctl+X Press to cut a region of the image.\n"
819 "\n"
820 " Ctl+C Press to copy a region of the image.\n"
821 "\n"
822 " Ctl+V Press to paste a region to the image.\n"
823 "\n"
824 " < Press to half the image size.\n"
825 "\n"
826 " - Press to return to the original image size.\n"
827 "\n"
828 " > Press to double the image size.\n"
829 "\n"
830 " % Press to resize the image to a width and height you\n"
831 " specify.\n"
832 "\n"
833 "Cmd-A Press to make any image transformations permanent."
834 "\n"
835 " By default, any image size transformations are applied\n"
836 " to the original image to create the image displayed on\n"
837 " the X server. However, the transformations are not\n"
838 " permanent (i.e. the original image does not change\n"
839 " size only the X image does). For example, if you\n"
840 " press > the X image will appear to double in size,\n"
841 " but the original image will in fact remain the same size.\n"
842 " To force the original image to double in size, press >\n"
843 " followed by Cmd-A.\n"
844 "\n"
845 " @ Press to refresh the image window.\n"
846 "\n"
847 " C Press to cut out a rectangular region of the image.\n"
848 "\n"
849 " [ Press to chop the image.\n"
850 "\n"
851 " H Press to flop image in the horizontal direction.\n"
852 "\n"
853 " V Press to flip image in the vertical direction.\n"
854 "\n"
855 " / Press to rotate the image 90 degrees clockwise.\n"
856 "\n"
857 " \\ Press to rotate the image 90 degrees counter-clockwise.\n"
858 "\n"
859 " * Press to rotate the image the number of degrees you\n"
860 " specify.\n"
861 "\n"
862 " S Press to shear the image the number of degrees you\n"
863 " specify.\n"
864 "\n"
865 " R Press to roll the image.\n"
866 "\n"
867 " T Press to trim the image edges.\n"
868 "\n"
869 " Shft-H Press to vary the image hue.\n"
870 "\n"
871 " Shft-S Press to vary the color saturation.\n"
872 "\n"
873 " Shft-L Press to vary the color brightness.\n"
874 "\n"
875 " Shft-G Press to gamma correct the image.\n"
876 "\n"
877 " Shft-C Press to sharpen the image contrast.\n"
878 "\n"
879 " Shft-Z Press to dull the image contrast.\n"
880 "\n"
881 " = Press to perform histogram equalization on the image.\n"
882 "\n"
883 " Shft-N Press to perform histogram normalization on the image.\n"
884 "\n"
885 " Shft-~ Press to negate the colors of the image.\n"
886 "\n"
887 " . Press to convert the image colors to gray.\n"
888 "\n"
889 " Shft-# Press to set the maximum number of unique colors in the\n"
890 " image.\n"
891 "\n"
892 " F2 Press to reduce the speckles in an image.\n"
893 "\n"
894 " F3 Press to eliminate peak noise from an image.\n"
895 "\n"
896 " F4 Press to add noise to an image.\n"
897 "\n"
898 " F5 Press to sharpen an image.\n"
899 "\n"
900 " F6 Press to delete an image file.\n"
901 "\n"
902 " F7 Press to threshold the image.\n"
903 "\n"
904 " F8 Press to detect edges within an image.\n"
905 "\n"
906 " F9 Press to emboss an image.\n"
907 "\n"
908 " F10 Press to displace pixels by a random amount.\n"
909 "\n"
910 " F11 Press to negate all pixels above the threshold level.\n"
911 "\n"
912 " F12 Press to shade the image using a distant light source.\n"
913 "\n"
914 " F13 Press to lighten or darken image edges to create a 3-D effect.\n"
915 "\n"
916 " F14 Press to segment the image by color.\n"
917 "\n"
918 " Meta-S Press to swirl image pixels about the center.\n"
919 "\n"
920 " Meta-I Press to implode image pixels about the center.\n"
921 "\n"
922 " Meta-W Press to alter an image along a sine wave.\n"
923 "\n"
924 " Meta-P Press to simulate an oil painting.\n"
925 "\n"
926 " Meta-C Press to simulate a charcoal drawing.\n"
927 "\n"
928 " Alt-A Press to annotate the image with text.\n"
929 "\n"
930 " Alt-D Press to draw on an image.\n"
931 "\n"
932 " Alt-P Press to edit an image pixel color.\n"
933 "\n"
934 " Alt-M Press to edit the image matte information.\n"
935 "\n"
936 " Alt-V Press to composite the image with another.\n"
937 "\n"
938 " Alt-B Press to add a border to the image.\n"
939 "\n"
940 " Alt-F Press to add an ornamental border to the image.\n"
941 "\n"
942 " Alt-Shft-!\n"
943 " Press to add an image comment.\n"
944 "\n"
945 " Ctl-A Press to apply image processing techniques to a region\n"
946 " of interest.\n"
947 "\n"
948 " Shft-? Press to display information about the image.\n"
949 "\n"
950 " Shft-+ Press to map the zoom image window.\n"
951 "\n"
952 " Shft-P Press to preview an image enhancement, effect, or f/x.\n"
953 "\n"
954 " F1 Press to display helpful information about display(1).\n"
955 "\n"
956 " Find Press to browse documentation about ImageMagick.\n"
957 "\n"
958 " 1-9 Press to change the level of magnification.\n"
959 "\n"
960 " Use the arrow keys to move the image one pixel up, down,\n"
961 " left, or right within the magnify window. Be sure to first\n"
962 " map the magnify window by pressing button 2.\n"
963 "\n"
964 " Press ALT and one of the arrow keys to trim off one pixel\n"
965 " from any side of the image.\n"
966 },
967 ImageMatteEditHelp[] =
968 {
969 "Matte information within an image is useful for some\n"
970 "operations such as image compositing (See IMAGE\n"
971 "COMPOSITING). This extra channel usually defines a mask\n"
972 "which represents a sort of a cookie-cutter for the image.\n"
973 "This the case when matte is opaque (full coverage) for\n"
974 "pixels inside the shape, zero outside, and between 0 and\n"
975 "QuantumRange on the boundary.\n"
976 "\n"
977 "A small window appears showing the location of the cursor in\n"
978 "the image window. You are now in matte edit mode. To exit\n"
979 "immediately, press Dismiss. In matte edit mode, the Command\n"
980 "widget has these options:\n"
981 "\n"
982 " Method\n"
983 " point\n"
984 " replace\n"
985 " floodfill\n"
986 " filltoborder\n"
987 " reset\n"
988 " Border Color\n"
989 " black\n"
990 " blue\n"
991 " cyan\n"
992 " green\n"
993 " gray\n"
994 " red\n"
995 " magenta\n"
996 " yellow\n"
997 " white\n"
998 " Browser...\n"
999 " Fuzz\n"
1000 " 0%\n"
1001 " 2%\n"
1002 " 5%\n"
1003 " 10%\n"
1004 " 15%\n"
1005 " Dialog...\n"
1006 " Matte\n"
1007 " Opaque\n"
1008 " Transparent\n"
1009 " Dialog...\n"
1010 " Undo\n"
1011 " Help\n"
1012 " Dismiss\n"
1013 "\n"
1014 "Choose a matte editing method from the Method sub-menu of\n"
1015 "the Command widget. The point method changes the matte value\n"
1016 "of any pixel selected with the pointer until the button is\n"
1017 "is released. The replace method changes the matte value of\n"
1018 "any pixel that matches the color of the pixel you select with\n"
1019 "a button press. Floodfill changes the matte value of any pixel\n"
1020 "that matches the color of the pixel you select with a button\n"
1021 "press and is a neighbor. Whereas filltoborder changes the matte\n"
1022 "value any neighbor pixel that is not the border color. Finally\n"
1023 "reset changes the entire image to the designated matte value.\n"
1024 "\n"
1025 "Choose Matte Value and pick Opaque or Transarent. For other values\n"
1026 "select the Dialog entry. Here a dialog appears requesting a matte\n"
1027 "value. The value you select is assigned as the opacity value of the\n"
1028 "selected pixel or pixels.\n"
1029 "\n"
1030 "Now, press any button to select a pixel within the image\n"
1031 "window to change its matte value.\n"
1032 "\n"
1033 "If the Magnify widget is mapped, it can be helpful in positioning\n"
1034 "your pointer within the image (refer to button 2).\n"
1035 "\n"
1036 "Matte information is only valid in a DirectClass image.\n"
1037 "Therefore, any PseudoClass image is promoted to DirectClass\n"
1038 "(see miff(5)). Note that matte information for PseudoClass\n"
1039 "is not retained for colormapped X server visuals (e.g.\n"
1040 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you\n"
1041 "immediately save your image to a file (refer to Write).\n"
1042 "Correct matte editing behavior may require a TrueColor or\n"
1043 "DirectColor visual or a Standard Colormap.\n"
1044 },
1045 ImagePanHelp[] =
1046 {
1047 "When an image exceeds the width or height of the X server\n"
1048 "screen, display maps a small panning icon. The rectangle\n"
1049 "within the panning icon shows the area that is currently\n"
1050 "displayed in the image window. To pan about the image,\n"
1051 "press any button and drag the pointer within the panning\n"
1052 "icon. The pan rectangle moves with the pointer and the\n"
1053 "image window is updated to reflect the location of the\n"
1054 "rectangle within the panning icon. When you have selected\n"
1055 "the area of the image you wish to view, release the button.\n"
1056 "\n"
1057 "Use the arrow keys to pan the image one pixel up, down,\n"
1058 "left, or right within the image window.\n"
1059 "\n"
1060 "The panning icon is withdrawn if the image becomes smaller\n"
1061 "than the dimensions of the X server screen.\n"
1062 },
1063 ImagePasteHelp[] =
1064 {
1065 "A small window appears showing the location of the cursor in\n"
1066 "the image window. You are now in paste mode. To exit\n"
1067 "immediately, press Dismiss. In paste mode, the Command\n"
1068 "widget has these options:\n"
1069 "\n"
1070 " Operators\n"
1071 " over\n"
1072 " in\n"
1073 " out\n"
1074 " atop\n"
1075 " xor\n"
1076 " plus\n"
1077 " minus\n"
1078 " add\n"
1079 " subtract\n"
1080 " difference\n"
1081 " replace\n"
1082 " Help\n"
1083 " Dismiss\n"
1084 "\n"
1085 "Choose a composite operation from the Operators sub-menu of\n"
1086 "the Command widget. How each operator behaves is described\n"
1087 "below. Image window is the image currently displayed on\n"
1088 "your X server and image is the image obtained with the File\n"
1089 "Browser widget.\n"
1090 "\n"
1091 "Over The result is the union of the two image shapes,\n"
1092 " with image obscuring image window in the region of\n"
1093 " overlap.\n"
1094 "\n"
1095 "In The result is simply image cut by the shape of\n"
1096 " image window. None of the image data of image\n"
1097 " window is in the result.\n"
1098 "\n"
1099 "Out The resulting image is image with the shape of\n"
1100 " image window cut out.\n"
1101 "\n"
1102 "Atop The result is the same shape as image image window,\n"
1103 " with image obscuring image window where the image\n"
1104 " shapes overlap. Note this differs from over\n"
1105 " because the portion of image outside image window's\n"
1106 " shape does not appear in the result.\n"
1107 "\n"
1108 "Xor The result is the image data from both image and\n"
1109 " image window that is outside the overlap region.\n"
1110 " The overlap region is blank.\n"
1111 "\n"
1112 "Plus The result is just the sum of the image data.\n"
1113 " Output values are cropped to QuantumRange (no overflow).\n"
1114 " This operation is independent of the matte\n"
1115 " channels.\n"
1116 "\n"
1117 "Minus The result of image - image window, with underflow\n"
1118 " cropped to zero.\n"
1119 "\n"
1120 "Add The result of image + image window, with overflow\n"
1121 " wrapping around (mod 256).\n"
1122 "\n"
1123 "Subtract The result of image - image window, with underflow\n"
1124 " wrapping around (mod 256). The add and subtract\n"
1125 " operators can be used to perform reversible\n"
1126 " transformations.\n"
1127 "\n"
1128 "Difference\n"
1129 " The result of abs(image - image window). This\n"
1130 " useful for comparing two very similar images.\n"
1131 "\n"
1132 "Copy The resulting image is image window replaced with\n"
1133 " image. Here the matte information is ignored.\n"
1134 "\n"
1135 "CopyRed The red layer of the image window is replace with\n"
1136 " the red layer of the image. The other layers are\n"
1137 " untouched.\n"
1138 "\n"
1139 "CopyGreen\n"
1140 " The green layer of the image window is replace with\n"
1141 " the green layer of the image. The other layers are\n"
1142 " untouched.\n"
1143 "\n"
1144 "CopyBlue The blue layer of the image window is replace with\n"
1145 " the blue layer of the image. The other layers are\n"
1146 " untouched.\n"
1147 "\n"
1148 "CopyOpacity\n"
1149 " The matte layer of the image window is replace with\n"
1150 " the matte layer of the image. The other layers are\n"
1151 " untouched.\n"
1152 "\n"
1153 "The image compositor requires a matte, or alpha channel in\n"
1154 "the image for some operations. This extra channel usually\n"
1155 "defines a mask which represents a sort of a cookie-cutter\n"
1156 "for the image. This the case when matte is opaque (full\n"
1157 "coverage) for pixels inside the shape, zero outside, and\n"
1158 "between 0 and QuantumRange on the boundary. If image does not\n"
1159 "have a matte channel, it is initialized with 0 for any pixel\n"
1160 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
1161 "\n"
1162 "Note that matte information for image window is not retained\n"
1163 "for colormapped X server visuals (e.g. StaticColor,\n"
1164 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
1165 "behavior may require a TrueColor or DirectColor visual or a\n"
1166 "Standard Colormap.\n"
1167 "\n"
1168 "Choosing a composite operator is optional. The default\n"
1169 "operator is replace. However, you must choose a location to\n"
1170 "paste your image and press button 1. Press and hold the\n"
1171 "button before releasing and an outline of the image will\n"
1172 "appear to help you identify your location.\n"
1173 "\n"
1174 "The actual colors of the pasted image is saved. However,\n"
1175 "the color that appears in image window may be different.\n"
1176 "For example, on a monochrome screen image window will appear\n"
1177 "black or white even though your pasted image may have\n"
1178 "many colors. If the image is saved to a file it is written\n"
1179 "with the correct colors. To assure the correct colors are\n"
1180 "saved in the final image, any PseudoClass image is promoted\n"
1181 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
1182 "to remain PseudoClass, use -colors.\n"
1183 },
1184 ImageROIHelp[] =
1185 {
1186 "In region of interest mode, the Command widget has these\n"
1187 "options:\n"
1188 "\n"
1189 " Help\n"
1190 " Dismiss\n"
1191 "\n"
1192 "To define a region of interest, press button 1 and drag.\n"
1193 "The region of interest is defined by a highlighted rectangle\n"
1194 "that expands or contracts as it follows the pointer. Once\n"
1195 "you are satisfied with the region of interest, release the\n"
1196 "button. You are now in apply mode. In apply mode the\n"
1197 "Command widget has these options:\n"
1198 "\n"
1199 " File\n"
1200 " Save...\n"
1201 " Print...\n"
1202 " Edit\n"
1203 " Undo\n"
1204 " Redo\n"
1205 " Transform\n"
1206 " Flop\n"
1207 " Flip\n"
1208 " Rotate Right\n"
1209 " Rotate Left\n"
1210 " Enhance\n"
1211 " Hue...\n"
1212 " Saturation...\n"
1213 " Brightness...\n"
1214 " Gamma...\n"
1215 " Spiff\n"
1216 " Dull\n"
1217 " Contrast Stretch\n"
1218 " Sigmoidal Contrast...\n"
1219 " Normalize\n"
1220 " Equalize\n"
1221 " Negate\n"
1222 " Grayscale\n"
1223 " Map...\n"
1224 " Quantize...\n"
1225 " Effects\n"
1226 " Despeckle\n"
1227 " Emboss\n"
1228 " Reduce Noise\n"
1229 " Sharpen...\n"
1230 " Blur...\n"
1231 " Threshold...\n"
1232 " Edge Detect...\n"
1233 " Spread...\n"
1234 " Shade...\n"
1235 " Raise...\n"
1236 " Segment...\n"
1237 " F/X\n"
1238 " Solarize...\n"
1239 " Sepia Tone...\n"
1240 " Swirl...\n"
1241 " Implode...\n"
1242 " Vignette...\n"
1243 " Wave...\n"
1244 " Oil Painting...\n"
1245 " Charcoal Drawing...\n"
1246 " Miscellany\n"
1247 " Image Info\n"
1248 " Zoom Image\n"
1249 " Show Preview...\n"
1250 " Show Histogram\n"
1251 " Show Matte\n"
1252 " Help\n"
1253 " Dismiss\n"
1254 "\n"
1255 "You can make adjustments to the region of interest by moving\n"
1256 "the pointer to one of the rectangle corners, pressing a\n"
1257 "button, and dragging. Finally, choose an image processing\n"
1258 "technique from the Command widget. You can choose more than\n"
1259 "one image processing technique to apply to an area.\n"
1260 "Alternatively, you can move the region of interest before\n"
1261 "applying another image processing technique. To exit, press\n"
1262 "Dismiss.\n"
1263 },
1264 ImageRotateHelp[] =
1265 {
1266 "In rotate mode, the Command widget has these options:\n"
1267 "\n"
1268 " Pixel Color\n"
1269 " black\n"
1270 " blue\n"
1271 " cyan\n"
1272 " green\n"
1273 " gray\n"
1274 " red\n"
1275 " magenta\n"
1276 " yellow\n"
1277 " white\n"
1278 " Browser...\n"
1279 " Direction\n"
1280 " horizontal\n"
1281 " vertical\n"
1282 " Help\n"
1283 " Dismiss\n"
1284 "\n"
1285 "Choose a background color from the Pixel Color sub-menu.\n"
1286 "Additional background colors can be specified with the color\n"
1287 "browser. You can change the menu colors by setting the X\n"
1288 "resources pen1 through pen9.\n"
1289 "\n"
1290 "If you choose the color browser and press Grab, you can\n"
1291 "select the background color by moving the pointer to the\n"
1292 "desired color on the screen and press any button.\n"
1293 "\n"
1294 "Choose a point in the image window and press this button and\n"
1295 "hold. Next, move the pointer to another location in the\n"
1296 "image. As you move a line connects the initial location and\n"
1297 "the pointer. When you release the button, the degree of\n"
1298 "image rotation is determined by the slope of the line you\n"
1299 "just drew. The slope is relative to the direction you\n"
1300 "choose from the Direction sub-menu of the Command widget.\n"
1301 "\n"
1302 "To cancel the image rotation, move the pointer back to the\n"
1303 "starting point of the line and release the button.\n"
1304 };
1305
1306 /*
1307 Enumeration declarations.
1308 */
1309 typedef enum
1310 {
1311 CopyMode,
1312 CropMode,
1313 CutMode
1314 } ClipboardMode;
1315
1316 typedef enum
1317 {
1318 OpenCommand,
1319 NextCommand,
1320 FormerCommand,
1321 SelectCommand,
1322 SaveCommand,
1323 PrintCommand,
1324 DeleteCommand,
1325 NewCommand,
1326 VisualDirectoryCommand,
1327 QuitCommand,
1328 UndoCommand,
1329 RedoCommand,
1330 CutCommand,
1331 CopyCommand,
1332 PasteCommand,
1333 HalfSizeCommand,
1334 OriginalSizeCommand,
1335 DoubleSizeCommand,
1336 ResizeCommand,
1337 ApplyCommand,
1338 RefreshCommand,
1339 RestoreCommand,
1340 CropCommand,
1341 ChopCommand,
1342 FlopCommand,
1343 FlipCommand,
1344 RotateRightCommand,
1345 RotateLeftCommand,
1346 RotateCommand,
1347 ShearCommand,
1348 RollCommand,
1349 TrimCommand,
1350 HueCommand,
1351 SaturationCommand,
1352 BrightnessCommand,
1353 GammaCommand,
1354 SpiffCommand,
1355 DullCommand,
1356 ContrastStretchCommand,
1357 SigmoidalContrastCommand,
1358 NormalizeCommand,
1359 EqualizeCommand,
1360 NegateCommand,
1361 GrayscaleCommand,
1362 MapCommand,
1363 QuantizeCommand,
1364 DespeckleCommand,
1365 EmbossCommand,
1366 ReduceNoiseCommand,
1367 AddNoiseCommand,
1368 SharpenCommand,
1369 BlurCommand,
1370 ThresholdCommand,
1371 EdgeDetectCommand,
1372 SpreadCommand,
1373 ShadeCommand,
1374 RaiseCommand,
1375 SegmentCommand,
1376 SolarizeCommand,
1377 SepiaToneCommand,
1378 SwirlCommand,
1379 ImplodeCommand,
1380 VignetteCommand,
1381 WaveCommand,
1382 OilPaintCommand,
1383 CharcoalDrawCommand,
1384 AnnotateCommand,
1385 DrawCommand,
1386 ColorCommand,
1387 MatteCommand,
1388 CompositeCommand,
1389 AddBorderCommand,
1390 AddFrameCommand,
1391 CommentCommand,
1392 LaunchCommand,
1393 RegionofInterestCommand,
1394 ROIHelpCommand,
1395 ROIDismissCommand,
1396 InfoCommand,
1397 ZoomCommand,
1398 ShowPreviewCommand,
1399 ShowHistogramCommand,
1400 ShowMatteCommand,
1401 BackgroundCommand,
1402 SlideShowCommand,
1403 PreferencesCommand,
1404 HelpCommand,
1405 BrowseDocumentationCommand,
1406 VersionCommand,
1407 SaveToUndoBufferCommand,
1408 FreeBuffersCommand,
1409 NullCommand
1410 } CommandType;
1411
1412 typedef enum
1413 {
1414 AnnotateNameCommand,
1415 AnnotateFontColorCommand,
1416 AnnotateBackgroundColorCommand,
1417 AnnotateRotateCommand,
1418 AnnotateHelpCommand,
1419 AnnotateDismissCommand,
1420 TextHelpCommand,
1421 TextApplyCommand,
1422 ChopDirectionCommand,
1423 ChopHelpCommand,
1424 ChopDismissCommand,
1425 HorizontalChopCommand,
1426 VerticalChopCommand,
1427 ColorEditMethodCommand,
1428 ColorEditColorCommand,
1429 ColorEditBorderCommand,
1430 ColorEditFuzzCommand,
1431 ColorEditUndoCommand,
1432 ColorEditHelpCommand,
1433 ColorEditDismissCommand,
1434 CompositeOperatorsCommand,
1435 CompositeDissolveCommand,
1436 CompositeDisplaceCommand,
1437 CompositeHelpCommand,
1438 CompositeDismissCommand,
1439 CropHelpCommand,
1440 CropDismissCommand,
1441 RectifyCopyCommand,
1442 RectifyHelpCommand,
1443 RectifyDismissCommand,
1444 DrawElementCommand,
1445 DrawColorCommand,
1446 DrawStippleCommand,
1447 DrawWidthCommand,
1448 DrawUndoCommand,
1449 DrawHelpCommand,
1450 DrawDismissCommand,
1451 MatteEditMethod,
1452 MatteEditBorderCommand,
1453 MatteEditFuzzCommand,
1454 MatteEditValueCommand,
1455 MatteEditUndoCommand,
1456 MatteEditHelpCommand,
1457 MatteEditDismissCommand,
1458 PasteOperatorsCommand,
1459 PasteHelpCommand,
1460 PasteDismissCommand,
1461 RotateColorCommand,
1462 RotateDirectionCommand,
1463 RotateCropCommand,
1464 RotateSharpenCommand,
1465 RotateHelpCommand,
1466 RotateDismissCommand,
1467 HorizontalRotateCommand,
1468 VerticalRotateCommand,
1469 TileLoadCommand,
1470 TileNextCommand,
1471 TileFormerCommand,
1472 TileDeleteCommand,
1473 TileUpdateCommand
1474 } ModeType;
1475
1476 /*
1477 Stipples.
1478 */
1479 #define BricksWidth 20
1480 #define BricksHeight 20
1481 #define DiagonalWidth 16
1482 #define DiagonalHeight 16
1483 #define HighlightWidth 8
1484 #define HighlightHeight 8
1485 #define OpaqueWidth 8
1486 #define OpaqueHeight 8
1487 #define ScalesWidth 16
1488 #define ScalesHeight 16
1489 #define ShadowWidth 8
1490 #define ShadowHeight 8
1491 #define VerticalWidth 16
1492 #define VerticalHeight 16
1493 #define WavyWidth 16
1494 #define WavyHeight 16
1495
1496 /*
1497 Constant declaration.
1498 */
1499 static const int
1500 RoiDelta = 8;
1501
1502 static const unsigned char
1503 BricksBitmap[] =
1504 {
1505 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1506 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1507 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1508 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1509 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1510 },
1511 DiagonalBitmap[] =
1512 {
1513 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1514 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1515 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1516 },
1517 ScalesBitmap[] =
1518 {
1519 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1520 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1521 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1522 },
1523 VerticalBitmap[] =
1524 {
1525 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1526 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1527 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1528 },
1529 WavyBitmap[] =
1530 {
1531 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1532 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1533 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1534 };
1535
1536 /*
1537 Function prototypes.
1538 */
1539 static CommandType
1540 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1541 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
1542
1543 static Image
1544 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1545 Image **,ExceptionInfo *),
1546 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1547 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1548 ExceptionInfo *),
1549 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1550 ExceptionInfo *);
1551
1552 static MagickBooleanType
1553 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1554 ExceptionInfo *),
1555 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1556 ExceptionInfo *),
1557 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1558 ExceptionInfo *),
1559 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1560 ExceptionInfo *),
1561 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1562 ExceptionInfo *),
1563 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1564 ExceptionInfo *),
1565 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1566 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1567 ExceptionInfo *),
1568 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1569 ExceptionInfo *),
1570 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1571 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1572 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1573 ExceptionInfo *),
1574 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1575 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1576 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
1577
1578 static void
1579 XDrawPanRectangle(Display *,XWindows *),
1580 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1581 ExceptionInfo *),
1582 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
1583 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1584 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
1585 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1586 const KeySym,ExceptionInfo *),
1587 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1588 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *),
1589 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1590
1591 /*
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593 % %
1594 % %
1595 % %
1596 % D i s p l a y I m a g e s %
1597 % %
1598 % %
1599 % %
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 %
1602 % DisplayImages() displays an image sequence to any X window screen. It
1603 % returns a value other than 0 if successful. Check the exception member
1604 % of image to determine the reason for any failure.
1605 %
1606 % The format of the DisplayImages method is:
1607 %
1608 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1609 % Image *images,ExceptionInfo *exception)
1610 %
1611 % A description of each parameter follows:
1612 %
1613 % o image_info: the image info.
1614 %
1615 % o image: the image.
1616 %
1617 % o exception: return any errors or warnings in this structure.
1618 %
1619 */
DisplayImages(const ImageInfo * image_info,Image * images,ExceptionInfo * exception)1620 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1621 Image *images,ExceptionInfo *exception)
1622 {
1623 char
1624 *argv[1];
1625
1626 Display
1627 *display;
1628
1629 Image
1630 *image;
1631
1632 ssize_t
1633 i;
1634
1635 size_t
1636 state;
1637
1638 XrmDatabase
1639 resource_database;
1640
1641 XResourceInfo
1642 resource_info;
1643
1644 assert(image_info != (const ImageInfo *) NULL);
1645 assert(image_info->signature == MagickCoreSignature);
1646 assert(images != (Image *) NULL);
1647 assert(images->signature == MagickCoreSignature);
1648 if (images->debug != MagickFalse)
1649 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1650 display=XOpenDisplay(image_info->server_name);
1651 if (display == (Display *) NULL)
1652 {
1653 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1654 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1655 return(MagickFalse);
1656 }
1657 if (exception->severity != UndefinedException)
1658 CatchException(exception);
1659 (void) XSetErrorHandler(XError);
1660 resource_database=XGetResourceDatabase(display,GetClientName());
1661 (void) memset(&resource_info,0,sizeof(resource_info));
1662 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1663 if (image_info->page != (char *) NULL)
1664 resource_info.image_geometry=AcquireString(image_info->page);
1665 resource_info.immutable=MagickTrue;
1666 argv[0]=AcquireString(GetClientName());
1667 state=DefaultState;
1668 for (i=0; (state & ExitState) == 0; i++)
1669 {
1670 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1671 break;
1672 image=GetImageFromList(images,i % GetImageListLength(images));
1673 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
1674 }
1675 (void) SetErrorHandler((ErrorHandler) NULL);
1676 (void) SetWarningHandler((WarningHandler) NULL);
1677 argv[0]=DestroyString(argv[0]);
1678 (void) XCloseDisplay(display);
1679 XDestroyResourceInfo(&resource_info);
1680 if (exception->severity != UndefinedException)
1681 return(MagickFalse);
1682 return(MagickTrue);
1683 }
1684
1685 /*
1686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 % %
1688 % %
1689 % %
1690 % R e m o t e D i s p l a y C o m m a n d %
1691 % %
1692 % %
1693 % %
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695 %
1696 % RemoteDisplayCommand() encourages a remote display program to display the
1697 % specified image filename.
1698 %
1699 % The format of the RemoteDisplayCommand method is:
1700 %
1701 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1702 % const char *window,const char *filename,ExceptionInfo *exception)
1703 %
1704 % A description of each parameter follows:
1705 %
1706 % o image_info: the image info.
1707 %
1708 % o window: Specifies the name or id of an X window.
1709 %
1710 % o filename: the name of the image filename to display.
1711 %
1712 % o exception: return any errors or warnings in this structure.
1713 %
1714 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)1715 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1716 const char *window,const char *filename,ExceptionInfo *exception)
1717 {
1718 Display
1719 *display;
1720
1721 MagickStatusType
1722 status;
1723
1724 assert(image_info != (const ImageInfo *) NULL);
1725 assert(image_info->signature == MagickCoreSignature);
1726 assert(filename != (char *) NULL);
1727 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1728 display=XOpenDisplay(image_info->server_name);
1729 if (display == (Display *) NULL)
1730 {
1731 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1732 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1733 return(MagickFalse);
1734 }
1735 (void) XSetErrorHandler(XError);
1736 status=XRemoteCommand(display,window,filename);
1737 (void) XCloseDisplay(display);
1738 return(status != 0 ? MagickTrue : MagickFalse);
1739 }
1740
1741 /*
1742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743 % %
1744 % %
1745 % %
1746 + X A n n o t a t e E d i t I m a g e %
1747 % %
1748 % %
1749 % %
1750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751 %
1752 % XAnnotateEditImage() annotates the image with text.
1753 %
1754 % The format of the XAnnotateEditImage method is:
1755 %
1756 % MagickBooleanType XAnnotateEditImage(Display *display,
1757 % XResourceInfo *resource_info,XWindows *windows,Image *image,
1758 % ExceptionInfo *exception)
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
XAnnotateEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)1773 static MagickBooleanType XAnnotateEditImage(Display *display,
1774 XResourceInfo *resource_info,XWindows *windows,Image *image,
1775 ExceptionInfo *exception)
1776 {
1777 const char
1778 *const AnnotateMenu[] =
1779 {
1780 "Font Name",
1781 "Font Color",
1782 "Box Color",
1783 "Rotate Text",
1784 "Help",
1785 "Dismiss",
1786 (char *) NULL
1787 },
1788 *const TextMenu[] =
1789 {
1790 "Help",
1791 "Apply",
1792 (char *) NULL
1793 };
1794
1795 static const ModeType
1796 AnnotateCommands[] =
1797 {
1798 AnnotateNameCommand,
1799 AnnotateFontColorCommand,
1800 AnnotateBackgroundColorCommand,
1801 AnnotateRotateCommand,
1802 AnnotateHelpCommand,
1803 AnnotateDismissCommand
1804 },
1805 TextCommands[] =
1806 {
1807 TextHelpCommand,
1808 TextApplyCommand
1809 };
1810
1811 static MagickBooleanType
1812 transparent_box = MagickTrue,
1813 transparent_pen = MagickFalse;
1814
1815 static double
1816 degrees = 0.0;
1817
1818 static unsigned int
1819 box_id = MaxNumberPens-2,
1820 font_id = 0,
1821 pen_id = 0;
1822
1823 char
1824 command[MagickPathExtent],
1825 text[MagickPathExtent];
1826
1827 const char
1828 *ColorMenu[MaxNumberPens+1];
1829
1830 Cursor
1831 cursor;
1832
1833 GC
1834 annotate_context;
1835
1836 int
1837 id,
1838 pen_number,
1839 status,
1840 x,
1841 y;
1842
1843 KeySym
1844 key_symbol;
1845
1846 char
1847 *p;
1848
1849 ssize_t
1850 i;
1851
1852 unsigned int
1853 height,
1854 width;
1855
1856 size_t
1857 state;
1858
1859 XAnnotateInfo
1860 *annotate_info,
1861 *previous_info;
1862
1863 XColor
1864 color;
1865
1866 XFontStruct
1867 *font_info;
1868
1869 XEvent
1870 event,
1871 text_event;
1872
1873 /*
1874 Map Command widget.
1875 */
1876 (void) CloneString(&windows->command.name,"Annotate");
1877 windows->command.data=4;
1878 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1879 (void) XMapRaised(display,windows->command.id);
1880 XClientMessage(display,windows->image.id,windows->im_protocols,
1881 windows->im_update_widget,CurrentTime);
1882 /*
1883 Track pointer until button 1 is pressed.
1884 */
1885 XQueryPosition(display,windows->image.id,&x,&y);
1886 (void) XSelectInput(display,windows->image.id,
1887 windows->image.attributes.event_mask | PointerMotionMask);
1888 cursor=XCreateFontCursor(display,XC_left_side);
1889 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1890 state=DefaultState;
1891 do
1892 {
1893 if (windows->info.mapped != MagickFalse)
1894 {
1895 /*
1896 Display pointer position.
1897 */
1898 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
1899 x+windows->image.x,y+windows->image.y);
1900 XInfoWidget(display,windows,text);
1901 }
1902 /*
1903 Wait for next event.
1904 */
1905 XScreenEvent(display,windows,&event,exception);
1906 if (event.xany.window == windows->command.id)
1907 {
1908 /*
1909 Select a command from the Command widget.
1910 */
1911 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1912 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1913 if (id < 0)
1914 continue;
1915 switch (AnnotateCommands[id])
1916 {
1917 case AnnotateNameCommand:
1918 {
1919 const char
1920 *FontMenu[MaxNumberFonts];
1921
1922 int
1923 font_number;
1924
1925 /*
1926 Initialize menu selections.
1927 */
1928 for (i=0; i < MaxNumberFonts; i++)
1929 FontMenu[i]=resource_info->font_name[i];
1930 FontMenu[MaxNumberFonts-2]="Browser...";
1931 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1932 /*
1933 Select a font name from the pop-up menu.
1934 */
1935 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1936 (const char **) FontMenu,command);
1937 if (font_number < 0)
1938 break;
1939 if (font_number == (MaxNumberFonts-2))
1940 {
1941 static char
1942 font_name[MagickPathExtent] = "fixed";
1943
1944 /*
1945 Select a font name from a browser.
1946 */
1947 resource_info->font_name[font_number]=font_name;
1948 XFontBrowserWidget(display,windows,"Select",font_name);
1949 if (*font_name == '\0')
1950 break;
1951 }
1952 /*
1953 Initialize font info.
1954 */
1955 font_info=XLoadQueryFont(display,resource_info->font_name[
1956 font_number]);
1957 if (font_info == (XFontStruct *) NULL)
1958 {
1959 XNoticeWidget(display,windows,"Unable to load font:",
1960 resource_info->font_name[font_number]);
1961 break;
1962 }
1963 font_id=(unsigned int) font_number;
1964 (void) XFreeFont(display,font_info);
1965 break;
1966 }
1967 case AnnotateFontColorCommand:
1968 {
1969 /*
1970 Initialize menu selections.
1971 */
1972 for (i=0; i < (int) (MaxNumberPens-2); i++)
1973 ColorMenu[i]=resource_info->pen_colors[i];
1974 ColorMenu[MaxNumberPens-2]="transparent";
1975 ColorMenu[MaxNumberPens-1]="Browser...";
1976 ColorMenu[MaxNumberPens]=(const char *) NULL;
1977 /*
1978 Select a pen color from the pop-up menu.
1979 */
1980 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
1981 (const char **) ColorMenu,command);
1982 if (pen_number < 0)
1983 break;
1984 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
1985 MagickFalse;
1986 if (transparent_pen != MagickFalse)
1987 break;
1988 if (pen_number == (MaxNumberPens-1))
1989 {
1990 static char
1991 color_name[MagickPathExtent] = "gray";
1992
1993 /*
1994 Select a pen color from a dialog.
1995 */
1996 resource_info->pen_colors[pen_number]=color_name;
1997 XColorBrowserWidget(display,windows,"Select",color_name);
1998 if (*color_name == '\0')
1999 break;
2000 }
2001 /*
2002 Set pen color.
2003 */
2004 (void) XParseColor(display,windows->map_info->colormap,
2005 resource_info->pen_colors[pen_number],&color);
2006 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2007 (unsigned int) MaxColors,&color);
2008 windows->pixel_info->pen_colors[pen_number]=color;
2009 pen_id=(unsigned int) pen_number;
2010 break;
2011 }
2012 case AnnotateBackgroundColorCommand:
2013 {
2014 /*
2015 Initialize menu selections.
2016 */
2017 for (i=0; i < (int) (MaxNumberPens-2); i++)
2018 ColorMenu[i]=resource_info->pen_colors[i];
2019 ColorMenu[MaxNumberPens-2]="transparent";
2020 ColorMenu[MaxNumberPens-1]="Browser...";
2021 ColorMenu[MaxNumberPens]=(const char *) NULL;
2022 /*
2023 Select a pen color from the pop-up menu.
2024 */
2025 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2026 (const char **) ColorMenu,command);
2027 if (pen_number < 0)
2028 break;
2029 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2030 MagickFalse;
2031 if (transparent_box != MagickFalse)
2032 break;
2033 if (pen_number == (MaxNumberPens-1))
2034 {
2035 static char
2036 color_name[MagickPathExtent] = "gray";
2037
2038 /*
2039 Select a pen color from a dialog.
2040 */
2041 resource_info->pen_colors[pen_number]=color_name;
2042 XColorBrowserWidget(display,windows,"Select",color_name);
2043 if (*color_name == '\0')
2044 break;
2045 }
2046 /*
2047 Set pen color.
2048 */
2049 (void) XParseColor(display,windows->map_info->colormap,
2050 resource_info->pen_colors[pen_number],&color);
2051 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2052 (unsigned int) MaxColors,&color);
2053 windows->pixel_info->pen_colors[pen_number]=color;
2054 box_id=(unsigned int) pen_number;
2055 break;
2056 }
2057 case AnnotateRotateCommand:
2058 {
2059 int
2060 entry;
2061
2062 const char
2063 *const RotateMenu[] =
2064 {
2065 "-90",
2066 "-45",
2067 "-30",
2068 "0",
2069 "30",
2070 "45",
2071 "90",
2072 "180",
2073 "Dialog...",
2074 (char *) NULL,
2075 };
2076
2077 static char
2078 angle[MagickPathExtent] = "30.0";
2079
2080 /*
2081 Select a command from the pop-up menu.
2082 */
2083 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2084 command);
2085 if (entry < 0)
2086 break;
2087 if (entry != 8)
2088 {
2089 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
2090 break;
2091 }
2092 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2093 angle);
2094 if (*angle == '\0')
2095 break;
2096 degrees=StringToDouble(angle,(char **) NULL);
2097 break;
2098 }
2099 case AnnotateHelpCommand:
2100 {
2101 XTextViewHelp(display,resource_info,windows,MagickFalse,
2102 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2103 break;
2104 }
2105 case AnnotateDismissCommand:
2106 {
2107 /*
2108 Prematurely exit.
2109 */
2110 state|=EscapeState;
2111 state|=ExitState;
2112 break;
2113 }
2114 default:
2115 break;
2116 }
2117 continue;
2118 }
2119 switch (event.type)
2120 {
2121 case ButtonPress:
2122 {
2123 if (event.xbutton.button != Button1)
2124 break;
2125 if (event.xbutton.window != windows->image.id)
2126 break;
2127 /*
2128 Change to text entering mode.
2129 */
2130 x=event.xbutton.x;
2131 y=event.xbutton.y;
2132 state|=ExitState;
2133 break;
2134 }
2135 case ButtonRelease:
2136 break;
2137 case Expose:
2138 break;
2139 case KeyPress:
2140 {
2141 if (event.xkey.window != windows->image.id)
2142 break;
2143 /*
2144 Respond to a user key press.
2145 */
2146 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2147 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2148 switch ((int) key_symbol)
2149 {
2150 case XK_Escape:
2151 case XK_F20:
2152 {
2153 /*
2154 Prematurely exit.
2155 */
2156 state|=EscapeState;
2157 state|=ExitState;
2158 break;
2159 }
2160 case XK_F1:
2161 case XK_Help:
2162 {
2163 XTextViewHelp(display,resource_info,windows,MagickFalse,
2164 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2165 break;
2166 }
2167 default:
2168 {
2169 (void) XBell(display,0);
2170 break;
2171 }
2172 }
2173 break;
2174 }
2175 case MotionNotify:
2176 {
2177 /*
2178 Map and unmap Info widget as cursor crosses its boundaries.
2179 */
2180 x=event.xmotion.x;
2181 y=event.xmotion.y;
2182 if (windows->info.mapped != MagickFalse)
2183 {
2184 if ((x < (int) (windows->info.x+windows->info.width)) &&
2185 (y < (int) (windows->info.y+windows->info.height)))
2186 (void) XWithdrawWindow(display,windows->info.id,
2187 windows->info.screen);
2188 }
2189 else
2190 if ((x > (int) (windows->info.x+windows->info.width)) ||
2191 (y > (int) (windows->info.y+windows->info.height)))
2192 (void) XMapWindow(display,windows->info.id);
2193 break;
2194 }
2195 default:
2196 break;
2197 }
2198 } while ((state & ExitState) == 0);
2199 (void) XSelectInput(display,windows->image.id,
2200 windows->image.attributes.event_mask);
2201 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2202 if ((state & EscapeState) != 0)
2203 return(MagickTrue);
2204 /*
2205 Set font info and check boundary conditions.
2206 */
2207 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2208 if (font_info == (XFontStruct *) NULL)
2209 {
2210 XNoticeWidget(display,windows,"Unable to load font:",
2211 resource_info->font_name[font_id]);
2212 font_info=windows->font_info;
2213 }
2214 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2215 x=(int) windows->image.width-font_info->max_bounds.width;
2216 if (y < (int) (font_info->ascent+font_info->descent))
2217 y=(int) font_info->ascent+font_info->descent;
2218 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2219 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2220 return(MagickFalse);
2221 /*
2222 Initialize annotate structure.
2223 */
2224 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2225 if (annotate_info == (XAnnotateInfo *) NULL)
2226 return(MagickFalse);
2227 XGetAnnotateInfo(annotate_info);
2228 annotate_info->x=x;
2229 annotate_info->y=y;
2230 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2231 annotate_info->stencil=OpaqueStencil;
2232 else
2233 if (transparent_box == MagickFalse)
2234 annotate_info->stencil=BackgroundStencil;
2235 else
2236 annotate_info->stencil=ForegroundStencil;
2237 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2238 annotate_info->degrees=degrees;
2239 annotate_info->font_info=font_info;
2240 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2241 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2242 sizeof(*annotate_info->text));
2243 if (annotate_info->text == (char *) NULL)
2244 return(MagickFalse);
2245 /*
2246 Create cursor and set graphic context.
2247 */
2248 cursor=XCreateFontCursor(display,XC_pencil);
2249 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2250 annotate_context=windows->image.annotate_context;
2251 (void) XSetFont(display,annotate_context,font_info->fid);
2252 (void) XSetBackground(display,annotate_context,
2253 windows->pixel_info->pen_colors[box_id].pixel);
2254 (void) XSetForeground(display,annotate_context,
2255 windows->pixel_info->pen_colors[pen_id].pixel);
2256 /*
2257 Begin annotating the image with text.
2258 */
2259 (void) CloneString(&windows->command.name,"Text");
2260 windows->command.data=0;
2261 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2262 state=DefaultState;
2263 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2264 text_event.xexpose.width=(int) font_info->max_bounds.width;
2265 text_event.xexpose.height=font_info->max_bounds.ascent+
2266 font_info->max_bounds.descent;
2267 p=annotate_info->text;
2268 do
2269 {
2270 /*
2271 Display text cursor.
2272 */
2273 *p='\0';
2274 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2275 /*
2276 Wait for next event.
2277 */
2278 XScreenEvent(display,windows,&event,exception);
2279 if (event.xany.window == windows->command.id)
2280 {
2281 /*
2282 Select a command from the Command widget.
2283 */
2284 (void) XSetBackground(display,annotate_context,
2285 windows->pixel_info->background_color.pixel);
2286 (void) XSetForeground(display,annotate_context,
2287 windows->pixel_info->foreground_color.pixel);
2288 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2289 (void) XSetBackground(display,annotate_context,
2290 windows->pixel_info->pen_colors[box_id].pixel);
2291 (void) XSetForeground(display,annotate_context,
2292 windows->pixel_info->pen_colors[pen_id].pixel);
2293 if (id < 0)
2294 continue;
2295 switch (TextCommands[id])
2296 {
2297 case TextHelpCommand:
2298 {
2299 XTextViewHelp(display,resource_info,windows,MagickFalse,
2300 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2301 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2302 break;
2303 }
2304 case TextApplyCommand:
2305 {
2306 /*
2307 Finished annotating.
2308 */
2309 annotate_info->width=(unsigned int) XTextWidth(font_info,
2310 annotate_info->text,(int) strlen(annotate_info->text));
2311 XRefreshWindow(display,&windows->image,&text_event);
2312 state|=ExitState;
2313 break;
2314 }
2315 default:
2316 break;
2317 }
2318 continue;
2319 }
2320 /*
2321 Erase text cursor.
2322 */
2323 text_event.xexpose.x=x;
2324 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2325 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2326 (unsigned int) text_event.xexpose.width,(unsigned int)
2327 text_event.xexpose.height,MagickFalse);
2328 XRefreshWindow(display,&windows->image,&text_event);
2329 switch (event.type)
2330 {
2331 case ButtonPress:
2332 {
2333 if (event.xbutton.window != windows->image.id)
2334 break;
2335 if (event.xbutton.button == Button2)
2336 {
2337 /*
2338 Request primary selection.
2339 */
2340 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2341 windows->image.id,CurrentTime);
2342 break;
2343 }
2344 break;
2345 }
2346 case Expose:
2347 {
2348 if (event.xexpose.count == 0)
2349 {
2350 XAnnotateInfo
2351 *text_info;
2352
2353 /*
2354 Refresh Image window.
2355 */
2356 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2357 text_info=annotate_info;
2358 while (text_info != (XAnnotateInfo *) NULL)
2359 {
2360 if (annotate_info->stencil == ForegroundStencil)
2361 (void) XDrawString(display,windows->image.id,annotate_context,
2362 text_info->x,text_info->y,text_info->text,
2363 (int) strlen(text_info->text));
2364 else
2365 (void) XDrawImageString(display,windows->image.id,
2366 annotate_context,text_info->x,text_info->y,text_info->text,
2367 (int) strlen(text_info->text));
2368 text_info=text_info->previous;
2369 }
2370 (void) XDrawString(display,windows->image.id,annotate_context,
2371 x,y,"_",1);
2372 }
2373 break;
2374 }
2375 case KeyPress:
2376 {
2377 int
2378 length;
2379
2380 if (event.xkey.window != windows->image.id)
2381 break;
2382 /*
2383 Respond to a user key press.
2384 */
2385 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2386 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2387 *(command+length)='\0';
2388 if (((event.xkey.state & ControlMask) != 0) ||
2389 ((event.xkey.state & Mod1Mask) != 0))
2390 state|=ModifierState;
2391 if ((state & ModifierState) != 0)
2392 switch ((int) key_symbol)
2393 {
2394 case XK_u:
2395 case XK_U:
2396 {
2397 key_symbol=DeleteCommand;
2398 break;
2399 }
2400 default:
2401 break;
2402 }
2403 switch ((int) key_symbol)
2404 {
2405 case XK_BackSpace:
2406 {
2407 /*
2408 Erase one character.
2409 */
2410 if (p == annotate_info->text)
2411 {
2412 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2413 break;
2414 else
2415 {
2416 /*
2417 Go to end of the previous line of text.
2418 */
2419 annotate_info=annotate_info->previous;
2420 p=annotate_info->text;
2421 x=annotate_info->x+annotate_info->width;
2422 y=annotate_info->y;
2423 if (annotate_info->width != 0)
2424 p+=strlen(annotate_info->text);
2425 break;
2426 }
2427 }
2428 p--;
2429 x-=XTextWidth(font_info,p,1);
2430 text_event.xexpose.x=x;
2431 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2432 XRefreshWindow(display,&windows->image,&text_event);
2433 break;
2434 }
2435 case XK_bracketleft:
2436 {
2437 key_symbol=XK_Escape;
2438 break;
2439 }
2440 case DeleteCommand:
2441 {
2442 /*
2443 Erase the entire line of text.
2444 */
2445 while (p != annotate_info->text)
2446 {
2447 p--;
2448 x-=XTextWidth(font_info,p,1);
2449 text_event.xexpose.x=x;
2450 XRefreshWindow(display,&windows->image,&text_event);
2451 }
2452 break;
2453 }
2454 case XK_Escape:
2455 case XK_F20:
2456 {
2457 /*
2458 Finished annotating.
2459 */
2460 annotate_info->width=(unsigned int) XTextWidth(font_info,
2461 annotate_info->text,(int) strlen(annotate_info->text));
2462 XRefreshWindow(display,&windows->image,&text_event);
2463 state|=ExitState;
2464 break;
2465 }
2466 default:
2467 {
2468 /*
2469 Draw a single character on the Image window.
2470 */
2471 if ((state & ModifierState) != 0)
2472 break;
2473 if (*command == '\0')
2474 break;
2475 *p=(*command);
2476 if (annotate_info->stencil == ForegroundStencil)
2477 (void) XDrawString(display,windows->image.id,annotate_context,
2478 x,y,p,1);
2479 else
2480 (void) XDrawImageString(display,windows->image.id,
2481 annotate_context,x,y,p,1);
2482 x+=XTextWidth(font_info,p,1);
2483 p++;
2484 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2485 break;
2486 }
2487 case XK_Return:
2488 case XK_KP_Enter:
2489 {
2490 /*
2491 Advance to the next line of text.
2492 */
2493 *p='\0';
2494 annotate_info->width=(unsigned int) XTextWidth(font_info,
2495 annotate_info->text,(int) strlen(annotate_info->text));
2496 if (annotate_info->next != (XAnnotateInfo *) NULL)
2497 {
2498 /*
2499 Line of text already exists.
2500 */
2501 annotate_info=annotate_info->next;
2502 x=annotate_info->x;
2503 y=annotate_info->y;
2504 p=annotate_info->text;
2505 break;
2506 }
2507 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2508 sizeof(*annotate_info->next));
2509 if (annotate_info->next == (XAnnotateInfo *) NULL)
2510 return(MagickFalse);
2511 *annotate_info->next=(*annotate_info);
2512 annotate_info->next->previous=annotate_info;
2513 annotate_info=annotate_info->next;
2514 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2515 windows->image.width/MagickMax((ssize_t)
2516 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2517 if (annotate_info->text == (char *) NULL)
2518 return(MagickFalse);
2519 annotate_info->y+=annotate_info->height;
2520 if (annotate_info->y > (int) windows->image.height)
2521 annotate_info->y=(int) annotate_info->height;
2522 annotate_info->next=(XAnnotateInfo *) NULL;
2523 x=annotate_info->x;
2524 y=annotate_info->y;
2525 p=annotate_info->text;
2526 break;
2527 }
2528 }
2529 break;
2530 }
2531 case KeyRelease:
2532 {
2533 /*
2534 Respond to a user key release.
2535 */
2536 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2537 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2538 state&=(~ModifierState);
2539 break;
2540 }
2541 case SelectionNotify:
2542 {
2543 Atom
2544 type;
2545
2546 int
2547 format;
2548
2549 unsigned char
2550 *data;
2551
2552 unsigned long
2553 after,
2554 length;
2555
2556 /*
2557 Obtain response from primary selection.
2558 */
2559 if (event.xselection.property == (Atom) None)
2560 break;
2561 status=XGetWindowProperty(display,event.xselection.requestor,
2562 event.xselection.property,0L,(long) MagickPathExtent,True,XA_STRING,
2563 &type,&format,&length,&after,&data);
2564 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2565 (length == 0))
2566 break;
2567 /*
2568 Annotate Image window with primary selection.
2569 */
2570 for (i=0; i < (ssize_t) length; i++)
2571 {
2572 if ((char) data[i] != '\n')
2573 {
2574 /*
2575 Draw a single character on the Image window.
2576 */
2577 *p=(char) data[i];
2578 (void) XDrawString(display,windows->image.id,annotate_context,
2579 x,y,p,1);
2580 x+=XTextWidth(font_info,p,1);
2581 p++;
2582 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2583 continue;
2584 }
2585 /*
2586 Advance to the next line of text.
2587 */
2588 *p='\0';
2589 annotate_info->width=(unsigned int) XTextWidth(font_info,
2590 annotate_info->text,(int) strlen(annotate_info->text));
2591 if (annotate_info->next != (XAnnotateInfo *) NULL)
2592 {
2593 /*
2594 Line of text already exists.
2595 */
2596 annotate_info=annotate_info->next;
2597 x=annotate_info->x;
2598 y=annotate_info->y;
2599 p=annotate_info->text;
2600 continue;
2601 }
2602 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2603 sizeof(*annotate_info->next));
2604 if (annotate_info->next == (XAnnotateInfo *) NULL)
2605 return(MagickFalse);
2606 *annotate_info->next=(*annotate_info);
2607 annotate_info->next->previous=annotate_info;
2608 annotate_info=annotate_info->next;
2609 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2610 windows->image.width/MagickMax((ssize_t)
2611 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2612 if (annotate_info->text == (char *) NULL)
2613 return(MagickFalse);
2614 annotate_info->y+=annotate_info->height;
2615 if (annotate_info->y > (int) windows->image.height)
2616 annotate_info->y=(int) annotate_info->height;
2617 annotate_info->next=(XAnnotateInfo *) NULL;
2618 x=annotate_info->x;
2619 y=annotate_info->y;
2620 p=annotate_info->text;
2621 }
2622 (void) XFree((void *) data);
2623 break;
2624 }
2625 default:
2626 break;
2627 }
2628 } while ((state & ExitState) == 0);
2629 (void) XFreeCursor(display,cursor);
2630 /*
2631 Annotation is relative to image configuration.
2632 */
2633 width=(unsigned int) image->columns;
2634 height=(unsigned int) image->rows;
2635 x=0;
2636 y=0;
2637 if (windows->image.crop_geometry != (char *) NULL)
2638 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2639 /*
2640 Initialize annotated image.
2641 */
2642 XSetCursorState(display,windows,MagickTrue);
2643 XCheckRefreshWindows(display,windows);
2644 while (annotate_info != (XAnnotateInfo *) NULL)
2645 {
2646 if (annotate_info->width == 0)
2647 {
2648 /*
2649 No text on this line-- go to the next line of text.
2650 */
2651 previous_info=annotate_info->previous;
2652 annotate_info->text=(char *)
2653 RelinquishMagickMemory(annotate_info->text);
2654 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2655 annotate_info=previous_info;
2656 continue;
2657 }
2658 /*
2659 Determine pixel index for box and pen color.
2660 */
2661 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2662 if (windows->pixel_info->colors != 0)
2663 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2664 if (windows->pixel_info->pixels[i] ==
2665 windows->pixel_info->pen_colors[box_id].pixel)
2666 {
2667 windows->pixel_info->box_index=(unsigned short) i;
2668 break;
2669 }
2670 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2671 if (windows->pixel_info->colors != 0)
2672 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2673 if (windows->pixel_info->pixels[i] ==
2674 windows->pixel_info->pen_colors[pen_id].pixel)
2675 {
2676 windows->pixel_info->pen_index=(unsigned short) i;
2677 break;
2678 }
2679 /*
2680 Define the annotate geometry string.
2681 */
2682 annotate_info->x=(int)
2683 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2684 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2685 windows->image.y)/windows->image.ximage->height;
2686 (void) FormatLocaleString(annotate_info->geometry,MagickPathExtent,
2687 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2688 height*annotate_info->height/windows->image.ximage->height,
2689 annotate_info->x+x,annotate_info->y+y);
2690 /*
2691 Annotate image with text.
2692 */
2693 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image,
2694 exception);
2695 if (status == 0)
2696 return(MagickFalse);
2697 /*
2698 Free up memory.
2699 */
2700 previous_info=annotate_info->previous;
2701 annotate_info->text=DestroyString(annotate_info->text);
2702 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2703 annotate_info=previous_info;
2704 }
2705 (void) XSetForeground(display,annotate_context,
2706 windows->pixel_info->foreground_color.pixel);
2707 (void) XSetBackground(display,annotate_context,
2708 windows->pixel_info->background_color.pixel);
2709 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2710 XSetCursorState(display,windows,MagickFalse);
2711 (void) XFreeFont(display,font_info);
2712 /*
2713 Update image configuration.
2714 */
2715 XConfigureImageColormap(display,resource_info,windows,image,exception);
2716 (void) XConfigureImage(display,resource_info,windows,image,exception);
2717 return(MagickTrue);
2718 }
2719
2720 /*
2721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722 % %
2723 % %
2724 % %
2725 + X B a c k g r o u n d I m a g e %
2726 % %
2727 % %
2728 % %
2729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730 %
2731 % XBackgroundImage() displays the image in the background of a window.
2732 %
2733 % The format of the XBackgroundImage method is:
2734 %
2735 % MagickBooleanType XBackgroundImage(Display *display,
2736 % XResourceInfo *resource_info,XWindows *windows,Image **image,
2737 % ExceptionInfo *exception)
2738 %
2739 % A description of each parameter follows:
2740 %
2741 % o display: Specifies a connection to an X server; returned from
2742 % XOpenDisplay.
2743 %
2744 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2745 %
2746 % o windows: Specifies a pointer to a XWindows structure.
2747 %
2748 % o image: the image.
2749 %
2750 % o exception: return any errors or warnings in this structure.
2751 %
2752 */
XBackgroundImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)2753 static MagickBooleanType XBackgroundImage(Display *display,
2754 XResourceInfo *resource_info,XWindows *windows,Image **image,
2755 ExceptionInfo *exception)
2756 {
2757 #define BackgroundImageTag "Background/Image"
2758
2759 int
2760 status;
2761
2762 static char
2763 window_id[MagickPathExtent] = "root";
2764
2765 XResourceInfo
2766 background_resources;
2767
2768 /*
2769 Put image in background.
2770 */
2771 status=XDialogWidget(display,windows,"Background",
2772 "Enter window id (id 0x00 selects window with pointer):",window_id);
2773 if (*window_id == '\0')
2774 return(MagickFalse);
2775 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2776 exception);
2777 XInfoWidget(display,windows,BackgroundImageTag);
2778 XSetCursorState(display,windows,MagickTrue);
2779 XCheckRefreshWindows(display,windows);
2780 background_resources=(*resource_info);
2781 background_resources.window_id=window_id;
2782 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2783 status=XDisplayBackgroundImage(display,&background_resources,*image,
2784 exception);
2785 if (status != MagickFalse)
2786 XClientMessage(display,windows->image.id,windows->im_protocols,
2787 windows->im_retain_colors,CurrentTime);
2788 XSetCursorState(display,windows,MagickFalse);
2789 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2790 exception);
2791 return(MagickTrue);
2792 }
2793
2794 /*
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796 % %
2797 % %
2798 % %
2799 + X C h o p I m a g e %
2800 % %
2801 % %
2802 % %
2803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804 %
2805 % XChopImage() chops the X image.
2806 %
2807 % The format of the XChopImage method is:
2808 %
2809 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2810 % XWindows *windows,Image **image,ExceptionInfo *exception)
2811 %
2812 % A description of each parameter follows:
2813 %
2814 % o display: Specifies a connection to an X server; returned from
2815 % XOpenDisplay.
2816 %
2817 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2818 %
2819 % o windows: Specifies a pointer to a XWindows structure.
2820 %
2821 % o image: the image.
2822 %
2823 % o exception: return any errors or warnings in this structure.
2824 %
2825 */
XChopImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)2826 static MagickBooleanType XChopImage(Display *display,
2827 XResourceInfo *resource_info,XWindows *windows,Image **image,
2828 ExceptionInfo *exception)
2829 {
2830 const char
2831 *const ChopMenu[] =
2832 {
2833 "Direction",
2834 "Help",
2835 "Dismiss",
2836 (char *) NULL
2837 };
2838
2839 static ModeType
2840 direction = HorizontalChopCommand;
2841
2842 static const ModeType
2843 ChopCommands[] =
2844 {
2845 ChopDirectionCommand,
2846 ChopHelpCommand,
2847 ChopDismissCommand
2848 },
2849 DirectionCommands[] =
2850 {
2851 HorizontalChopCommand,
2852 VerticalChopCommand
2853 };
2854
2855 char
2856 text[MagickPathExtent];
2857
2858 Image
2859 *chop_image;
2860
2861 int
2862 id,
2863 x,
2864 y;
2865
2866 double
2867 scale_factor;
2868
2869 RectangleInfo
2870 chop_info;
2871
2872 unsigned int
2873 distance,
2874 height,
2875 width;
2876
2877 size_t
2878 state;
2879
2880 XEvent
2881 event;
2882
2883 XSegment
2884 segment_info;
2885
2886 /*
2887 Map Command widget.
2888 */
2889 (void) CloneString(&windows->command.name,"Chop");
2890 windows->command.data=1;
2891 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2892 (void) XMapRaised(display,windows->command.id);
2893 XClientMessage(display,windows->image.id,windows->im_protocols,
2894 windows->im_update_widget,CurrentTime);
2895 /*
2896 Track pointer until button 1 is pressed.
2897 */
2898 XQueryPosition(display,windows->image.id,&x,&y);
2899 (void) XSelectInput(display,windows->image.id,
2900 windows->image.attributes.event_mask | PointerMotionMask);
2901 state=DefaultState;
2902 (void) memset(&segment_info,0,sizeof(segment_info));
2903 do
2904 {
2905 if (windows->info.mapped != MagickFalse)
2906 {
2907 /*
2908 Display pointer position.
2909 */
2910 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
2911 x+windows->image.x,y+windows->image.y);
2912 XInfoWidget(display,windows,text);
2913 }
2914 /*
2915 Wait for next event.
2916 */
2917 XScreenEvent(display,windows,&event,exception);
2918 if (event.xany.window == windows->command.id)
2919 {
2920 /*
2921 Select a command from the Command widget.
2922 */
2923 id=XCommandWidget(display,windows,ChopMenu,&event);
2924 if (id < 0)
2925 continue;
2926 switch (ChopCommands[id])
2927 {
2928 case ChopDirectionCommand:
2929 {
2930 char
2931 command[MagickPathExtent];
2932
2933 const char
2934 *const Directions[] =
2935 {
2936 "horizontal",
2937 "vertical",
2938 (char *) NULL,
2939 };
2940
2941 /*
2942 Select a command from the pop-up menu.
2943 */
2944 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2945 if (id >= 0)
2946 direction=DirectionCommands[id];
2947 break;
2948 }
2949 case ChopHelpCommand:
2950 {
2951 XTextViewHelp(display,resource_info,windows,MagickFalse,
2952 "Help Viewer - Image Chop",ImageChopHelp);
2953 break;
2954 }
2955 case ChopDismissCommand:
2956 {
2957 /*
2958 Prematurely exit.
2959 */
2960 state|=EscapeState;
2961 state|=ExitState;
2962 break;
2963 }
2964 default:
2965 break;
2966 }
2967 continue;
2968 }
2969 switch (event.type)
2970 {
2971 case ButtonPress:
2972 {
2973 if (event.xbutton.button != Button1)
2974 break;
2975 if (event.xbutton.window != windows->image.id)
2976 break;
2977 /*
2978 User has committed to start point of chopping line.
2979 */
2980 segment_info.x1=(short int) event.xbutton.x;
2981 segment_info.x2=(short int) event.xbutton.x;
2982 segment_info.y1=(short int) event.xbutton.y;
2983 segment_info.y2=(short int) event.xbutton.y;
2984 state|=ExitState;
2985 break;
2986 }
2987 case ButtonRelease:
2988 break;
2989 case Expose:
2990 break;
2991 case KeyPress:
2992 {
2993 char
2994 command[MagickPathExtent];
2995
2996 KeySym
2997 key_symbol;
2998
2999 if (event.xkey.window != windows->image.id)
3000 break;
3001 /*
3002 Respond to a user key press.
3003 */
3004 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3005 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3006 switch ((int) key_symbol)
3007 {
3008 case XK_Escape:
3009 case XK_F20:
3010 {
3011 /*
3012 Prematurely exit.
3013 */
3014 state|=EscapeState;
3015 state|=ExitState;
3016 break;
3017 }
3018 case XK_F1:
3019 case XK_Help:
3020 {
3021 (void) XSetFunction(display,windows->image.highlight_context,
3022 GXcopy);
3023 XTextViewHelp(display,resource_info,windows,MagickFalse,
3024 "Help Viewer - Image Chop",ImageChopHelp);
3025 (void) XSetFunction(display,windows->image.highlight_context,
3026 GXinvert);
3027 break;
3028 }
3029 default:
3030 {
3031 (void) XBell(display,0);
3032 break;
3033 }
3034 }
3035 break;
3036 }
3037 case MotionNotify:
3038 {
3039 /*
3040 Map and unmap Info widget as text cursor crosses its boundaries.
3041 */
3042 x=event.xmotion.x;
3043 y=event.xmotion.y;
3044 if (windows->info.mapped != MagickFalse)
3045 {
3046 if ((x < (int) (windows->info.x+windows->info.width)) &&
3047 (y < (int) (windows->info.y+windows->info.height)))
3048 (void) XWithdrawWindow(display,windows->info.id,
3049 windows->info.screen);
3050 }
3051 else
3052 if ((x > (int) (windows->info.x+windows->info.width)) ||
3053 (y > (int) (windows->info.y+windows->info.height)))
3054 (void) XMapWindow(display,windows->info.id);
3055 }
3056 }
3057 } while ((state & ExitState) == 0);
3058 (void) XSelectInput(display,windows->image.id,
3059 windows->image.attributes.event_mask);
3060 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3061 if ((state & EscapeState) != 0)
3062 return(MagickTrue);
3063 /*
3064 Draw line as pointer moves until the mouse button is released.
3065 */
3066 chop_info.width=0;
3067 chop_info.height=0;
3068 chop_info.x=0;
3069 chop_info.y=0;
3070 distance=0;
3071 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3072 state=DefaultState;
3073 do
3074 {
3075 if (distance > 9)
3076 {
3077 /*
3078 Display info and draw chopping line.
3079 */
3080 if (windows->info.mapped == MagickFalse)
3081 (void) XMapWindow(display,windows->info.id);
3082 (void) FormatLocaleString(text,MagickPathExtent,
3083 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3084 chop_info.height,(double) chop_info.x,(double) 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,exception);
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=(size_t) (segment_info.x2-segment_info.x1+1);
3149 chop_info.x=(ssize_t) 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=(size_t) (segment_info.x1-segment_info.x2+1);
3155 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3156 }
3157 }
3158 else
3159 {
3160 chop_info.width=0;
3161 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3162 chop_info.x=0;
3163 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3164 if (segment_info.y1 > segment_info.y2)
3165 {
3166 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3167 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3168 }
3169 }
3170 } while ((state & ExitState) == 0);
3171 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3172 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3173 if (distance <= 9)
3174 return(MagickTrue);
3175 /*
3176 Image chopping is relative to image configuration.
3177 */
3178 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3179 exception);
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=(double) width/windows->image.ximage->width;
3193 chop_info.x+=x;
3194 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3195 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3196 scale_factor=(double) height/windows->image.ximage->height;
3197 chop_info.y+=y;
3198 chop_info.y=(ssize_t) (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,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,exception);
3213 (void) XConfigureImage(display,resource_info,windows,*image,exception);
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 % ExceptionInfo *exception)
3236 %
3237 % A description of each parameter follows:
3238 %
3239 % o display: Specifies a connection to an X server; returned from
3240 % XOpenDisplay.
3241 %
3242 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3243 %
3244 % o windows: Specifies a pointer to a XWindows structure.
3245 %
3246 % o image: the image; returned from ReadImage.
3247 %
3248 % o exception: return any errors or warnings in this structure.
3249 %
3250 */
XColorEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)3251 static MagickBooleanType XColorEditImage(Display *display,
3252 XResourceInfo *resource_info,XWindows *windows,Image **image,
3253 ExceptionInfo *exception)
3254 {
3255 const char
3256 *const ColorEditMenu[] =
3257 {
3258 "Method",
3259 "Pixel Color",
3260 "Border Color",
3261 "Fuzz",
3262 "Undo",
3263 "Help",
3264 "Dismiss",
3265 (char *) NULL
3266 };
3267
3268 static const ModeType
3269 ColorEditCommands[] =
3270 {
3271 ColorEditMethodCommand,
3272 ColorEditColorCommand,
3273 ColorEditBorderCommand,
3274 ColorEditFuzzCommand,
3275 ColorEditUndoCommand,
3276 ColorEditHelpCommand,
3277 ColorEditDismissCommand
3278 };
3279
3280 static PaintMethod
3281 method = PointMethod;
3282
3283 static unsigned int
3284 pen_id = 0;
3285
3286 static XColor
3287 border_color = { 0, 0, 0, 0, 0, 0 };
3288
3289 char
3290 command[MagickPathExtent],
3291 text[MagickPathExtent];
3292
3293 Cursor
3294 cursor;
3295
3296 int
3297 entry,
3298 id,
3299 x,
3300 x_offset,
3301 y,
3302 y_offset;
3303
3304 Quantum
3305 *q;
3306
3307 ssize_t
3308 i;
3309
3310 unsigned int
3311 height,
3312 width;
3313
3314 size_t
3315 state;
3316
3317 XColor
3318 color;
3319
3320 XEvent
3321 event;
3322
3323 /*
3324 Map Command widget.
3325 */
3326 (void) CloneString(&windows->command.name,"Color Edit");
3327 windows->command.data=4;
3328 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3329 (void) XMapRaised(display,windows->command.id);
3330 XClientMessage(display,windows->image.id,windows->im_protocols,
3331 windows->im_update_widget,CurrentTime);
3332 /*
3333 Make cursor.
3334 */
3335 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3336 resource_info->background_color,resource_info->foreground_color);
3337 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3338 /*
3339 Track pointer until button 1 is pressed.
3340 */
3341 XQueryPosition(display,windows->image.id,&x,&y);
3342 (void) XSelectInput(display,windows->image.id,
3343 windows->image.attributes.event_mask | PointerMotionMask);
3344 state=DefaultState;
3345 do
3346 {
3347 if (windows->info.mapped != MagickFalse)
3348 {
3349 /*
3350 Display pointer position.
3351 */
3352 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
3353 x+windows->image.x,y+windows->image.y);
3354 XInfoWidget(display,windows,text);
3355 }
3356 /*
3357 Wait for next event.
3358 */
3359 XScreenEvent(display,windows,&event,exception);
3360 if (event.xany.window == windows->command.id)
3361 {
3362 /*
3363 Select a command from the Command widget.
3364 */
3365 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3366 if (id < 0)
3367 {
3368 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3369 continue;
3370 }
3371 switch (ColorEditCommands[id])
3372 {
3373 case ColorEditMethodCommand:
3374 {
3375 char
3376 **methods;
3377
3378 /*
3379 Select a method from the pop-up menu.
3380 */
3381 methods=(char **) GetCommandOptions(MagickMethodOptions);
3382 if (methods == (char **) NULL)
3383 break;
3384 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3385 (const char **) methods,command);
3386 if (entry >= 0)
3387 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3388 MagickFalse,methods[entry]);
3389 methods=DestroyStringList(methods);
3390 break;
3391 }
3392 case ColorEditColorCommand:
3393 {
3394 const char
3395 *ColorMenu[MaxNumberPens];
3396
3397 int
3398 pen_number;
3399
3400 /*
3401 Initialize menu selections.
3402 */
3403 for (i=0; i < (int) (MaxNumberPens-2); i++)
3404 ColorMenu[i]=resource_info->pen_colors[i];
3405 ColorMenu[MaxNumberPens-2]="Browser...";
3406 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3407 /*
3408 Select a pen color from the pop-up menu.
3409 */
3410 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3411 (const char **) ColorMenu,command);
3412 if (pen_number < 0)
3413 break;
3414 if (pen_number == (MaxNumberPens-2))
3415 {
3416 static char
3417 color_name[MagickPathExtent] = "gray";
3418
3419 /*
3420 Select a pen color from a dialog.
3421 */
3422 resource_info->pen_colors[pen_number]=color_name;
3423 XColorBrowserWidget(display,windows,"Select",color_name);
3424 if (*color_name == '\0')
3425 break;
3426 }
3427 /*
3428 Set pen color.
3429 */
3430 (void) XParseColor(display,windows->map_info->colormap,
3431 resource_info->pen_colors[pen_number],&color);
3432 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3433 (unsigned int) MaxColors,&color);
3434 windows->pixel_info->pen_colors[pen_number]=color;
3435 pen_id=(unsigned int) pen_number;
3436 break;
3437 }
3438 case ColorEditBorderCommand:
3439 {
3440 const char
3441 *ColorMenu[MaxNumberPens];
3442
3443 int
3444 pen_number;
3445
3446 /*
3447 Initialize menu selections.
3448 */
3449 for (i=0; i < (int) (MaxNumberPens-2); i++)
3450 ColorMenu[i]=resource_info->pen_colors[i];
3451 ColorMenu[MaxNumberPens-2]="Browser...";
3452 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3453 /*
3454 Select a pen color from the pop-up menu.
3455 */
3456 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3457 (const char **) ColorMenu,command);
3458 if (pen_number < 0)
3459 break;
3460 if (pen_number == (MaxNumberPens-2))
3461 {
3462 static char
3463 color_name[MagickPathExtent] = "gray";
3464
3465 /*
3466 Select a pen color from a dialog.
3467 */
3468 resource_info->pen_colors[pen_number]=color_name;
3469 XColorBrowserWidget(display,windows,"Select",color_name);
3470 if (*color_name == '\0')
3471 break;
3472 }
3473 /*
3474 Set border color.
3475 */
3476 (void) XParseColor(display,windows->map_info->colormap,
3477 resource_info->pen_colors[pen_number],&border_color);
3478 break;
3479 }
3480 case ColorEditFuzzCommand:
3481 {
3482 const char
3483 *const FuzzMenu[] =
3484 {
3485 "0%",
3486 "2%",
3487 "5%",
3488 "10%",
3489 "15%",
3490 "Dialog...",
3491 (char *) NULL,
3492 };
3493
3494 static char
3495 fuzz[MagickPathExtent];
3496
3497 /*
3498 Select a command from the pop-up menu.
3499 */
3500 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3501 command);
3502 if (entry < 0)
3503 break;
3504 if (entry != 5)
3505 {
3506 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
3507 QuantumRange+1.0);
3508 break;
3509 }
3510 (void) (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
3511 (void) XDialogWidget(display,windows,"Ok",
3512 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3513 if (*fuzz == '\0')
3514 break;
3515 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
3516 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3517 1.0);
3518 break;
3519 }
3520 case ColorEditUndoCommand:
3521 {
3522 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3523 image,exception);
3524 break;
3525 }
3526 case ColorEditHelpCommand:
3527 default:
3528 {
3529 XTextViewHelp(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,exception);
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,exception);
3578 (void) XConfigureImage(display,resource_info,windows,*image,exception);
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 XTextViewHelp(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 CacheView
3665 *image_view;
3666
3667 int
3668 x,
3669 y;
3670
3671 /*
3672 Pixel edit is relative to image configuration.
3673 */
3674 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3675 MagickTrue);
3676 color=windows->pixel_info->pen_colors[pen_id];
3677 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3678 width=(unsigned int) (*image)->columns;
3679 height=(unsigned int) (*image)->rows;
3680 x=0;
3681 y=0;
3682 if (windows->image.crop_geometry != (char *) NULL)
3683 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3684 &width,&height);
3685 x_offset=(int)
3686 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3687 y_offset=(int)
3688 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3689 if ((x_offset < 0) || (y_offset < 0))
3690 continue;
3691 if ((x_offset >= (int) (*image)->columns) ||
3692 (y_offset >= (int) (*image)->rows))
3693 continue;
3694 image_view=AcquireAuthenticCacheView(*image,exception);
3695 switch (method)
3696 {
3697 case PointMethod:
3698 default:
3699 {
3700 /*
3701 Update color information using point algorithm.
3702 */
3703 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3704 return(MagickFalse);
3705 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3706 (ssize_t) y_offset,1,1,exception);
3707 if (q == (Quantum *) NULL)
3708 break;
3709 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3710 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3711 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3712 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3713 break;
3714 }
3715 case ReplaceMethod:
3716 {
3717 PixelInfo
3718 pixel,
3719 target;
3720
3721 /*
3722 Update color information using replace algorithm.
3723 */
3724 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
3725 x_offset,(ssize_t) y_offset,&target,exception);
3726 if ((*image)->storage_class == DirectClass)
3727 {
3728 for (y=0; y < (int) (*image)->rows; y++)
3729 {
3730 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3731 (*image)->columns,1,exception);
3732 if (q == (Quantum *) NULL)
3733 break;
3734 for (x=0; x < (int) (*image)->columns; x++)
3735 {
3736 GetPixelInfoPixel(*image,q,&pixel);
3737 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
3738 {
3739 SetPixelRed(*image,ScaleShortToQuantum(
3740 color.red),q);
3741 SetPixelGreen(*image,ScaleShortToQuantum(
3742 color.green),q);
3743 SetPixelBlue(*image,ScaleShortToQuantum(
3744 color.blue),q);
3745 }
3746 q+=GetPixelChannels(*image);
3747 }
3748 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3749 break;
3750 }
3751 }
3752 else
3753 {
3754 for (i=0; i < (ssize_t) (*image)->colors; i++)
3755 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
3756 {
3757 (*image)->colormap[i].red=(double) ScaleShortToQuantum(
3758 color.red);
3759 (*image)->colormap[i].green=(double) ScaleShortToQuantum(
3760 color.green);
3761 (*image)->colormap[i].blue=(double) ScaleShortToQuantum(
3762 color.blue);
3763 }
3764 (void) SyncImage(*image,exception);
3765 }
3766 break;
3767 }
3768 case FloodfillMethod:
3769 case FillToBorderMethod:
3770 {
3771 DrawInfo
3772 *draw_info;
3773
3774 PixelInfo
3775 target;
3776
3777 /*
3778 Update color information using floodfill algorithm.
3779 */
3780 (void) GetOneVirtualPixelInfo(*image,
3781 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
3782 y_offset,&target,exception);
3783 if (method == FillToBorderMethod)
3784 {
3785 target.red=(double)
3786 ScaleShortToQuantum(border_color.red);
3787 target.green=(double)
3788 ScaleShortToQuantum(border_color.green);
3789 target.blue=(double)
3790 ScaleShortToQuantum(border_color.blue);
3791 }
3792 draw_info=CloneDrawInfo(resource_info->image_info,
3793 (DrawInfo *) NULL);
3794 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3795 AllCompliance,&draw_info->fill,exception);
3796 (void) FloodfillPaintImage(*image,draw_info,&target,
3797 (ssize_t)x_offset,(ssize_t)y_offset,
3798 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
3799 draw_info=DestroyDrawInfo(draw_info);
3800 break;
3801 }
3802 case ResetMethod:
3803 {
3804 /*
3805 Update color information using reset algorithm.
3806 */
3807 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3808 return(MagickFalse);
3809 for (y=0; y < (int) (*image)->rows; y++)
3810 {
3811 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3812 (*image)->columns,1,exception);
3813 if (q == (Quantum *) NULL)
3814 break;
3815 for (x=0; x < (int) (*image)->columns; x++)
3816 {
3817 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3818 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3819 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3820 q+=GetPixelChannels(*image);
3821 }
3822 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3823 break;
3824 }
3825 break;
3826 }
3827 }
3828 image_view=DestroyCacheView(image_view);
3829 state&=(~UpdateConfigurationState);
3830 }
3831 } while ((state & ExitState) == 0);
3832 (void) XSelectInput(display,windows->image.id,
3833 windows->image.attributes.event_mask);
3834 XSetCursorState(display,windows,MagickFalse);
3835 (void) XFreeCursor(display,cursor);
3836 return(MagickTrue);
3837 }
3838
3839 /*
3840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3841 % %
3842 % %
3843 % %
3844 + X C o m p o s i t e I m a g e %
3845 % %
3846 % %
3847 % %
3848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3849 %
3850 % XCompositeImage() requests an image name from the user, reads the image and
3851 % composites it with the X window image at a location the user chooses with
3852 % the pointer.
3853 %
3854 % The format of the XCompositeImage method is:
3855 %
3856 % MagickBooleanType XCompositeImage(Display *display,
3857 % XResourceInfo *resource_info,XWindows *windows,Image *image,
3858 % ExceptionInfo *exception)
3859 %
3860 % A description of each parameter follows:
3861 %
3862 % o display: Specifies a connection to an X server; returned from
3863 % XOpenDisplay.
3864 %
3865 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3866 %
3867 % o windows: Specifies a pointer to a XWindows structure.
3868 %
3869 % o image: the image; returned from ReadImage.
3870 %
3871 % o exception: return any errors or warnings in this structure.
3872 %
3873 */
XCompositeImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)3874 static MagickBooleanType XCompositeImage(Display *display,
3875 XResourceInfo *resource_info,XWindows *windows,Image *image,
3876 ExceptionInfo *exception)
3877 {
3878 const char
3879 *const CompositeMenu[] =
3880 {
3881 "Operators",
3882 "Dissolve",
3883 "Displace",
3884 "Help",
3885 "Dismiss",
3886 (char *) NULL
3887 };
3888
3889 static char
3890 displacement_geometry[MagickPathExtent] = "30x30",
3891 filename[MagickPathExtent] = "\0";
3892
3893 static CompositeOperator
3894 compose = CopyCompositeOp;
3895
3896 static const ModeType
3897 CompositeCommands[] =
3898 {
3899 CompositeOperatorsCommand,
3900 CompositeDissolveCommand,
3901 CompositeDisplaceCommand,
3902 CompositeHelpCommand,
3903 CompositeDismissCommand
3904 };
3905
3906 char
3907 text[MagickPathExtent];
3908
3909 Cursor
3910 cursor;
3911
3912 Image
3913 *composite_image;
3914
3915 int
3916 entry,
3917 id,
3918 x,
3919 y;
3920
3921 double
3922 blend,
3923 scale_factor;
3924
3925 RectangleInfo
3926 highlight_info,
3927 composite_info;
3928
3929 unsigned int
3930 height,
3931 width;
3932
3933 size_t
3934 state;
3935
3936 XEvent
3937 event;
3938
3939 /*
3940 Request image file name from user.
3941 */
3942 XFileBrowserWidget(display,windows,"Composite",filename);
3943 if (*filename == '\0')
3944 return(MagickTrue);
3945 /*
3946 Read image.
3947 */
3948 XSetCursorState(display,windows,MagickTrue);
3949 XCheckRefreshWindows(display,windows);
3950 (void) CopyMagickString(resource_info->image_info->filename,filename,
3951 MagickPathExtent);
3952 composite_image=ReadImage(resource_info->image_info,exception);
3953 CatchException(exception);
3954 XSetCursorState(display,windows,MagickFalse);
3955 if (composite_image == (Image *) NULL)
3956 return(MagickFalse);
3957 /*
3958 Map Command widget.
3959 */
3960 (void) CloneString(&windows->command.name,"Composite");
3961 windows->command.data=1;
3962 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3963 (void) XMapRaised(display,windows->command.id);
3964 XClientMessage(display,windows->image.id,windows->im_protocols,
3965 windows->im_update_widget,CurrentTime);
3966 /*
3967 Track pointer until button 1 is pressed.
3968 */
3969 XQueryPosition(display,windows->image.id,&x,&y);
3970 (void) XSelectInput(display,windows->image.id,
3971 windows->image.attributes.event_mask | PointerMotionMask);
3972 composite_info.x=(ssize_t) windows->image.x+x;
3973 composite_info.y=(ssize_t) windows->image.y+y;
3974 composite_info.width=0;
3975 composite_info.height=0;
3976 cursor=XCreateFontCursor(display,XC_ul_angle);
3977 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3978 blend=0.0;
3979 state=DefaultState;
3980 do
3981 {
3982 if (windows->info.mapped != MagickFalse)
3983 {
3984 /*
3985 Display pointer position.
3986 */
3987 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
3988 (long) composite_info.x,(long) composite_info.y);
3989 XInfoWidget(display,windows,text);
3990 }
3991 highlight_info=composite_info;
3992 highlight_info.x=composite_info.x-windows->image.x;
3993 highlight_info.y=composite_info.y-windows->image.y;
3994 XHighlightRectangle(display,windows->image.id,
3995 windows->image.highlight_context,&highlight_info);
3996 /*
3997 Wait for next event.
3998 */
3999 XScreenEvent(display,windows,&event,exception);
4000 XHighlightRectangle(display,windows->image.id,
4001 windows->image.highlight_context,&highlight_info);
4002 if (event.xany.window == windows->command.id)
4003 {
4004 /*
4005 Select a command from the Command widget.
4006 */
4007 id=XCommandWidget(display,windows,CompositeMenu,&event);
4008 if (id < 0)
4009 continue;
4010 switch (CompositeCommands[id])
4011 {
4012 case CompositeOperatorsCommand:
4013 {
4014 char
4015 command[MagickPathExtent],
4016 **operators;
4017
4018 /*
4019 Select a command from the pop-up menu.
4020 */
4021 operators=GetCommandOptions(MagickComposeOptions);
4022 if (operators == (char **) NULL)
4023 break;
4024 entry=XMenuWidget(display,windows,CompositeMenu[id],
4025 (const char **) operators,command);
4026 if (entry >= 0)
4027 compose=(CompositeOperator) ParseCommandOption(
4028 MagickComposeOptions,MagickFalse,operators[entry]);
4029 operators=DestroyStringList(operators);
4030 break;
4031 }
4032 case CompositeDissolveCommand:
4033 {
4034 static char
4035 factor[MagickPathExtent] = "20.0";
4036
4037 /*
4038 Dissolve the two images a given percent.
4039 */
4040 (void) XSetFunction(display,windows->image.highlight_context,
4041 GXcopy);
4042 (void) XDialogWidget(display,windows,"Dissolve",
4043 "Enter the blend factor (0.0 - 99.9%):",factor);
4044 (void) XSetFunction(display,windows->image.highlight_context,
4045 GXinvert);
4046 if (*factor == '\0')
4047 break;
4048 blend=StringToDouble(factor,(char **) NULL);
4049 compose=DissolveCompositeOp;
4050 break;
4051 }
4052 case CompositeDisplaceCommand:
4053 {
4054 /*
4055 Get horizontal and vertical scale displacement geometry.
4056 */
4057 (void) XSetFunction(display,windows->image.highlight_context,
4058 GXcopy);
4059 (void) XDialogWidget(display,windows,"Displace",
4060 "Enter the horizontal and vertical scale:",displacement_geometry);
4061 (void) XSetFunction(display,windows->image.highlight_context,
4062 GXinvert);
4063 if (*displacement_geometry == '\0')
4064 break;
4065 compose=DisplaceCompositeOp;
4066 break;
4067 }
4068 case CompositeHelpCommand:
4069 {
4070 (void) XSetFunction(display,windows->image.highlight_context,
4071 GXcopy);
4072 XTextViewHelp(display,resource_info,windows,MagickFalse,
4073 "Help Viewer - Image Composite",ImageCompositeHelp);
4074 (void) XSetFunction(display,windows->image.highlight_context,
4075 GXinvert);
4076 break;
4077 }
4078 case CompositeDismissCommand:
4079 {
4080 /*
4081 Prematurely exit.
4082 */
4083 state|=EscapeState;
4084 state|=ExitState;
4085 break;
4086 }
4087 default:
4088 break;
4089 }
4090 continue;
4091 }
4092 switch (event.type)
4093 {
4094 case ButtonPress:
4095 {
4096 if (image->debug != MagickFalse)
4097 (void) LogMagickEvent(X11Event,GetMagickModule(),
4098 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4099 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4100 if (event.xbutton.button != Button1)
4101 break;
4102 if (event.xbutton.window != windows->image.id)
4103 break;
4104 /*
4105 Change cursor.
4106 */
4107 composite_info.width=composite_image->columns;
4108 composite_info.height=composite_image->rows;
4109 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4110 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4111 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4112 break;
4113 }
4114 case ButtonRelease:
4115 {
4116 if (image->debug != MagickFalse)
4117 (void) LogMagickEvent(X11Event,GetMagickModule(),
4118 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4119 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4120 if (event.xbutton.button != Button1)
4121 break;
4122 if (event.xbutton.window != windows->image.id)
4123 break;
4124 if ((composite_info.width != 0) && (composite_info.height != 0))
4125 {
4126 /*
4127 User has selected the location of the composite image.
4128 */
4129 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4130 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4131 state|=ExitState;
4132 }
4133 break;
4134 }
4135 case Expose:
4136 break;
4137 case KeyPress:
4138 {
4139 char
4140 command[MagickPathExtent];
4141
4142 KeySym
4143 key_symbol;
4144
4145 int
4146 length;
4147
4148 if (event.xkey.window != windows->image.id)
4149 break;
4150 /*
4151 Respond to a user key press.
4152 */
4153 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4154 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4155 *(command+length)='\0';
4156 if (image->debug != MagickFalse)
4157 (void) LogMagickEvent(X11Event,GetMagickModule(),
4158 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4159 switch ((int) key_symbol)
4160 {
4161 case XK_Escape:
4162 case XK_F20:
4163 {
4164 /*
4165 Prematurely exit.
4166 */
4167 composite_image=DestroyImage(composite_image);
4168 state|=EscapeState;
4169 state|=ExitState;
4170 break;
4171 }
4172 case XK_F1:
4173 case XK_Help:
4174 {
4175 (void) XSetFunction(display,windows->image.highlight_context,
4176 GXcopy);
4177 XTextViewHelp(display,resource_info,windows,MagickFalse,
4178 "Help Viewer - Image Composite",ImageCompositeHelp);
4179 (void) XSetFunction(display,windows->image.highlight_context,
4180 GXinvert);
4181 break;
4182 }
4183 default:
4184 {
4185 (void) XBell(display,0);
4186 break;
4187 }
4188 }
4189 break;
4190 }
4191 case MotionNotify:
4192 {
4193 /*
4194 Map and unmap Info widget as text cursor crosses its boundaries.
4195 */
4196 x=event.xmotion.x;
4197 y=event.xmotion.y;
4198 if (windows->info.mapped != MagickFalse)
4199 {
4200 if ((x < (int) (windows->info.x+windows->info.width)) &&
4201 (y < (int) (windows->info.y+windows->info.height)))
4202 (void) XWithdrawWindow(display,windows->info.id,
4203 windows->info.screen);
4204 }
4205 else
4206 if ((x > (int) (windows->info.x+windows->info.width)) ||
4207 (y > (int) (windows->info.y+windows->info.height)))
4208 (void) XMapWindow(display,windows->info.id);
4209 composite_info.x=(ssize_t) windows->image.x+x;
4210 composite_info.y=(ssize_t) windows->image.y+y;
4211 break;
4212 }
4213 default:
4214 {
4215 if (image->debug != MagickFalse)
4216 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4217 event.type);
4218 break;
4219 }
4220 }
4221 } while ((state & ExitState) == 0);
4222 (void) XSelectInput(display,windows->image.id,
4223 windows->image.attributes.event_mask);
4224 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4225 XSetCursorState(display,windows,MagickFalse);
4226 (void) XFreeCursor(display,cursor);
4227 if ((state & EscapeState) != 0)
4228 return(MagickTrue);
4229 /*
4230 Image compositing is relative to image configuration.
4231 */
4232 XSetCursorState(display,windows,MagickTrue);
4233 XCheckRefreshWindows(display,windows);
4234 width=(unsigned int) image->columns;
4235 height=(unsigned int) image->rows;
4236 x=0;
4237 y=0;
4238 if (windows->image.crop_geometry != (char *) NULL)
4239 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4240 scale_factor=(double) width/windows->image.ximage->width;
4241 composite_info.x+=x;
4242 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4243 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4244 scale_factor=(double) height/windows->image.ximage->height;
4245 composite_info.y+=y;
4246 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4247 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4248 if ((composite_info.width != composite_image->columns) ||
4249 (composite_info.height != composite_image->rows))
4250 {
4251 Image
4252 *resize_image;
4253
4254 /*
4255 Scale composite image.
4256 */
4257 resize_image=ResizeImage(composite_image,composite_info.width,
4258 composite_info.height,composite_image->filter,exception);
4259 composite_image=DestroyImage(composite_image);
4260 if (resize_image == (Image *) NULL)
4261 {
4262 XSetCursorState(display,windows,MagickFalse);
4263 return(MagickFalse);
4264 }
4265 composite_image=resize_image;
4266 }
4267 if (compose == DisplaceCompositeOp)
4268 (void) SetImageArtifact(composite_image,"compose:args",
4269 displacement_geometry);
4270 if (blend != 0.0)
4271 {
4272 CacheView
4273 *image_view;
4274
4275 int
4276 y;
4277
4278 Quantum
4279 opacity;
4280
4281 int
4282 x;
4283
4284 Quantum
4285 *q;
4286
4287 /*
4288 Create mattes for blending.
4289 */
4290 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
4291 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4292 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
4293 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4294 return(MagickFalse);
4295 image->alpha_trait=BlendPixelTrait;
4296 image_view=AcquireAuthenticCacheView(image,exception);
4297 for (y=0; y < (int) image->rows; y++)
4298 {
4299 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4300 exception);
4301 if (q == (Quantum *) NULL)
4302 break;
4303 for (x=0; x < (int) image->columns; x++)
4304 {
4305 SetPixelAlpha(image,opacity,q);
4306 q+=GetPixelChannels(image);
4307 }
4308 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4309 break;
4310 }
4311 image_view=DestroyCacheView(image_view);
4312 }
4313 /*
4314 Composite image with X Image window.
4315 */
4316 (void) CompositeImage(image,composite_image,compose,MagickTrue,
4317 composite_info.x,composite_info.y,exception);
4318 composite_image=DestroyImage(composite_image);
4319 XSetCursorState(display,windows,MagickFalse);
4320 /*
4321 Update image configuration.
4322 */
4323 XConfigureImageColormap(display,resource_info,windows,image,exception);
4324 (void) XConfigureImage(display,resource_info,windows,image,exception);
4325 return(MagickTrue);
4326 }
4327
4328 /*
4329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330 % %
4331 % %
4332 % %
4333 + X C o n f i g u r e I m a g e %
4334 % %
4335 % %
4336 % %
4337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338 %
4339 % XConfigureImage() creates a new X image. It also notifies the window
4340 % manager of the new image size and configures the transient widows.
4341 %
4342 % The format of the XConfigureImage method is:
4343 %
4344 % MagickBooleanType XConfigureImage(Display *display,
4345 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4346 % ExceptionInfo *exception)
4347 %
4348 % A description of each parameter follows:
4349 %
4350 % o display: Specifies a connection to an X server; returned from
4351 % XOpenDisplay.
4352 %
4353 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4354 %
4355 % o windows: Specifies a pointer to a XWindows structure.
4356 %
4357 % o image: the image.
4358 %
4359 % o exception: return any errors or warnings in this structure.
4360 %
4361 % o exception: return any errors or warnings in this structure.
4362 %
4363 */
XConfigureImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)4364 static MagickBooleanType XConfigureImage(Display *display,
4365 XResourceInfo *resource_info,XWindows *windows,Image *image,
4366 ExceptionInfo *exception)
4367 {
4368 char
4369 geometry[MagickPathExtent];
4370
4371 MagickStatusType
4372 status;
4373
4374 size_t
4375 mask,
4376 height,
4377 width;
4378
4379 ssize_t
4380 x,
4381 y;
4382
4383 XSizeHints
4384 *size_hints;
4385
4386 XWindowChanges
4387 window_changes;
4388
4389 /*
4390 Dismiss if window dimensions are zero.
4391 */
4392 width=(unsigned int) windows->image.window_changes.width;
4393 height=(unsigned int) windows->image.window_changes.height;
4394 if (image->debug != MagickFalse)
4395 (void) LogMagickEvent(X11Event,GetMagickModule(),
4396 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4397 windows->image.ximage->height,(double) width,(double) height);
4398 if ((width*height) == 0)
4399 return(MagickTrue);
4400 x=0;
4401 y=0;
4402 /*
4403 Resize image to fit Image window dimensions.
4404 */
4405 XSetCursorState(display,windows,MagickTrue);
4406 (void) XFlush(display);
4407 if (((int) width != windows->image.ximage->width) ||
4408 ((int) height != windows->image.ximage->height))
4409 image->taint=MagickTrue;
4410 windows->magnify.x=(int)
4411 width*windows->magnify.x/windows->image.ximage->width;
4412 windows->magnify.y=(int)
4413 height*windows->magnify.y/windows->image.ximage->height;
4414 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4415 windows->image.y=(int)
4416 (height*windows->image.y/windows->image.ximage->height);
4417 status=XMakeImage(display,resource_info,&windows->image,image,
4418 (unsigned int) width,(unsigned int) height,exception);
4419 if (status == MagickFalse)
4420 XNoticeWidget(display,windows,"Unable to configure X image:",
4421 windows->image.name);
4422 /*
4423 Notify window manager of the new configuration.
4424 */
4425 if (resource_info->image_geometry != (char *) NULL)
4426 (void) FormatLocaleString(geometry,MagickPathExtent,"%s>!",
4427 resource_info->image_geometry);
4428 else
4429 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
4430 XDisplayWidth(display,windows->image.screen),
4431 XDisplayHeight(display,windows->image.screen));
4432 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4433 window_changes.width=(int) width;
4434 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4435 window_changes.width=XDisplayWidth(display,windows->image.screen);
4436 window_changes.height=(int) height;
4437 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4438 window_changes.height=XDisplayHeight(display,windows->image.screen);
4439 mask=(size_t) (CWWidth | CWHeight);
4440 if (resource_info->backdrop)
4441 {
4442 mask|=CWX | CWY;
4443 window_changes.x=(int)
4444 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4445 window_changes.y=(int)
4446 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4447 }
4448 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4449 (unsigned int) mask,&window_changes);
4450 (void) XClearWindow(display,windows->image.id);
4451 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4452 /*
4453 Update Magnify window configuration.
4454 */
4455 if (windows->magnify.mapped != MagickFalse)
4456 XMakeMagnifyImage(display,windows,exception);
4457 windows->pan.crop_geometry=windows->image.crop_geometry;
4458 XBestIconSize(display,&windows->pan,image);
4459 while (((windows->pan.width << 1) < MaxIconSize) &&
4460 ((windows->pan.height << 1) < MaxIconSize))
4461 {
4462 windows->pan.width<<=1;
4463 windows->pan.height<<=1;
4464 }
4465 if (windows->pan.geometry != (char *) NULL)
4466 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4467 &windows->pan.width,&windows->pan.height);
4468 window_changes.width=(int) windows->pan.width;
4469 window_changes.height=(int) windows->pan.height;
4470 size_hints=XAllocSizeHints();
4471 if (size_hints != (XSizeHints *) NULL)
4472 {
4473 /*
4474 Set new size hints.
4475 */
4476 size_hints->flags=PSize | PMinSize | PMaxSize;
4477 size_hints->width=window_changes.width;
4478 size_hints->height=window_changes.height;
4479 size_hints->min_width=size_hints->width;
4480 size_hints->min_height=size_hints->height;
4481 size_hints->max_width=size_hints->width;
4482 size_hints->max_height=size_hints->height;
4483 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4484 (void) XFree((void *) size_hints);
4485 }
4486 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4487 (unsigned int) (CWWidth | CWHeight),&window_changes);
4488 /*
4489 Update icon window configuration.
4490 */
4491 windows->icon.crop_geometry=windows->image.crop_geometry;
4492 XBestIconSize(display,&windows->icon,image);
4493 window_changes.width=(int) windows->icon.width;
4494 window_changes.height=(int) windows->icon.height;
4495 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4496 (unsigned int) (CWWidth | CWHeight),&window_changes);
4497 XSetCursorState(display,windows,MagickFalse);
4498 return(status != 0 ? MagickTrue : MagickFalse);
4499 }
4500
4501 /*
4502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4503 % %
4504 % %
4505 % %
4506 + X C r o p I m a g e %
4507 % %
4508 % %
4509 % %
4510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4511 %
4512 % XCropImage() allows the user to select a region of the image and crop, copy,
4513 % or cut it. For copy or cut, the image can subsequently be composited onto
4514 % the image with XPasteImage.
4515 %
4516 % The format of the XCropImage method is:
4517 %
4518 % MagickBooleanType XCropImage(Display *display,
4519 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4520 % const ClipboardMode mode,ExceptionInfo *exception)
4521 %
4522 % A description of each parameter follows:
4523 %
4524 % o display: Specifies a connection to an X server; returned from
4525 % XOpenDisplay.
4526 %
4527 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4528 %
4529 % o windows: Specifies a pointer to a XWindows structure.
4530 %
4531 % o image: the image; returned from ReadImage.
4532 %
4533 % o mode: This unsigned value specified whether the image should be
4534 % cropped, copied, or cut.
4535 %
4536 % o exception: return any errors or warnings in this structure.
4537 %
4538 */
XCropImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,const ClipboardMode mode,ExceptionInfo * exception)4539 static MagickBooleanType XCropImage(Display *display,
4540 XResourceInfo *resource_info,XWindows *windows,Image *image,
4541 const ClipboardMode mode,ExceptionInfo *exception)
4542 {
4543 const char
4544 *const CropModeMenu[] =
4545 {
4546 "Help",
4547 "Dismiss",
4548 (char *) NULL
4549 },
4550 *RectifyModeMenu[] =
4551 {
4552 "Crop",
4553 "Help",
4554 "Dismiss",
4555 (char *) NULL
4556 };
4557
4558 static const ModeType
4559 CropCommands[] =
4560 {
4561 CropHelpCommand,
4562 CropDismissCommand
4563 },
4564 RectifyCommands[] =
4565 {
4566 RectifyCopyCommand,
4567 RectifyHelpCommand,
4568 RectifyDismissCommand
4569 };
4570
4571 CacheView
4572 *image_view;
4573
4574 char
4575 command[MagickPathExtent],
4576 text[MagickPathExtent];
4577
4578 Cursor
4579 cursor;
4580
4581 int
4582 id,
4583 x,
4584 y;
4585
4586 KeySym
4587 key_symbol;
4588
4589 Image
4590 *crop_image;
4591
4592 double
4593 scale_factor;
4594
4595 RectangleInfo
4596 crop_info,
4597 highlight_info;
4598
4599 Quantum
4600 *q;
4601
4602 unsigned int
4603 height,
4604 width;
4605
4606 size_t
4607 state;
4608
4609 XEvent
4610 event;
4611
4612 /*
4613 Map Command widget.
4614 */
4615 switch (mode)
4616 {
4617 case CopyMode:
4618 {
4619 (void) CloneString(&windows->command.name,"Copy");
4620 break;
4621 }
4622 case CropMode:
4623 {
4624 (void) CloneString(&windows->command.name,"Crop");
4625 break;
4626 }
4627 case CutMode:
4628 {
4629 (void) CloneString(&windows->command.name,"Cut");
4630 break;
4631 }
4632 }
4633 RectifyModeMenu[0]=windows->command.name;
4634 windows->command.data=0;
4635 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4636 (void) XMapRaised(display,windows->command.id);
4637 XClientMessage(display,windows->image.id,windows->im_protocols,
4638 windows->im_update_widget,CurrentTime);
4639 /*
4640 Track pointer until button 1 is pressed.
4641 */
4642 XQueryPosition(display,windows->image.id,&x,&y);
4643 (void) XSelectInput(display,windows->image.id,
4644 windows->image.attributes.event_mask | PointerMotionMask);
4645 crop_info.x=(ssize_t) windows->image.x+x;
4646 crop_info.y=(ssize_t) windows->image.y+y;
4647 crop_info.width=0;
4648 crop_info.height=0;
4649 cursor=XCreateFontCursor(display,XC_fleur);
4650 state=DefaultState;
4651 do
4652 {
4653 if (windows->info.mapped != MagickFalse)
4654 {
4655 /*
4656 Display pointer position.
4657 */
4658 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
4659 (long) crop_info.x,(long) crop_info.y);
4660 XInfoWidget(display,windows,text);
4661 }
4662 /*
4663 Wait for next event.
4664 */
4665 XScreenEvent(display,windows,&event,exception);
4666 if (event.xany.window == windows->command.id)
4667 {
4668 /*
4669 Select a command from the Command widget.
4670 */
4671 id=XCommandWidget(display,windows,CropModeMenu,&event);
4672 if (id < 0)
4673 continue;
4674 switch (CropCommands[id])
4675 {
4676 case CropHelpCommand:
4677 {
4678 switch (mode)
4679 {
4680 case CopyMode:
4681 {
4682 XTextViewHelp(display,resource_info,windows,MagickFalse,
4683 "Help Viewer - Image Copy",ImageCopyHelp);
4684 break;
4685 }
4686 case CropMode:
4687 {
4688 XTextViewHelp(display,resource_info,windows,MagickFalse,
4689 "Help Viewer - Image Crop",ImageCropHelp);
4690 break;
4691 }
4692 case CutMode:
4693 {
4694 XTextViewHelp(display,resource_info,windows,MagickFalse,
4695 "Help Viewer - Image Cut",ImageCutHelp);
4696 break;
4697 }
4698 }
4699 break;
4700 }
4701 case CropDismissCommand:
4702 {
4703 /*
4704 Prematurely exit.
4705 */
4706 state|=EscapeState;
4707 state|=ExitState;
4708 break;
4709 }
4710 default:
4711 break;
4712 }
4713 continue;
4714 }
4715 switch (event.type)
4716 {
4717 case ButtonPress:
4718 {
4719 if (event.xbutton.button != Button1)
4720 break;
4721 if (event.xbutton.window != windows->image.id)
4722 break;
4723 /*
4724 Note first corner of cropping rectangle-- exit loop.
4725 */
4726 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4727 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4728 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4729 state|=ExitState;
4730 break;
4731 }
4732 case ButtonRelease:
4733 break;
4734 case Expose:
4735 break;
4736 case KeyPress:
4737 {
4738 if (event.xkey.window != windows->image.id)
4739 break;
4740 /*
4741 Respond to a user key press.
4742 */
4743 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4744 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4745 switch ((int) key_symbol)
4746 {
4747 case XK_Escape:
4748 case XK_F20:
4749 {
4750 /*
4751 Prematurely exit.
4752 */
4753 state|=EscapeState;
4754 state|=ExitState;
4755 break;
4756 }
4757 case XK_F1:
4758 case XK_Help:
4759 {
4760 switch (mode)
4761 {
4762 case CopyMode:
4763 {
4764 XTextViewHelp(display,resource_info,windows,MagickFalse,
4765 "Help Viewer - Image Copy",ImageCopyHelp);
4766 break;
4767 }
4768 case CropMode:
4769 {
4770 XTextViewHelp(display,resource_info,windows,MagickFalse,
4771 "Help Viewer - Image Crop",ImageCropHelp);
4772 break;
4773 }
4774 case CutMode:
4775 {
4776 XTextViewHelp(display,resource_info,windows,MagickFalse,
4777 "Help Viewer - Image Cut",ImageCutHelp);
4778 break;
4779 }
4780 }
4781 break;
4782 }
4783 default:
4784 {
4785 (void) XBell(display,0);
4786 break;
4787 }
4788 }
4789 break;
4790 }
4791 case MotionNotify:
4792 {
4793 if (event.xmotion.window != windows->image.id)
4794 break;
4795 /*
4796 Map and unmap Info widget as text cursor crosses its boundaries.
4797 */
4798 x=event.xmotion.x;
4799 y=event.xmotion.y;
4800 if (windows->info.mapped != MagickFalse)
4801 {
4802 if ((x < (int) (windows->info.x+windows->info.width)) &&
4803 (y < (int) (windows->info.y+windows->info.height)))
4804 (void) XWithdrawWindow(display,windows->info.id,
4805 windows->info.screen);
4806 }
4807 else
4808 if ((x > (int) (windows->info.x+windows->info.width)) ||
4809 (y > (int) (windows->info.y+windows->info.height)))
4810 (void) XMapWindow(display,windows->info.id);
4811 crop_info.x=(ssize_t) windows->image.x+x;
4812 crop_info.y=(ssize_t) windows->image.y+y;
4813 break;
4814 }
4815 default:
4816 break;
4817 }
4818 } while ((state & ExitState) == 0);
4819 (void) XSelectInput(display,windows->image.id,
4820 windows->image.attributes.event_mask);
4821 if ((state & EscapeState) != 0)
4822 {
4823 /*
4824 User want to exit without cropping.
4825 */
4826 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4827 (void) XFreeCursor(display,cursor);
4828 return(MagickTrue);
4829 }
4830 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4831 do
4832 {
4833 /*
4834 Size rectangle as pointer moves until the mouse button is released.
4835 */
4836 x=(int) crop_info.x;
4837 y=(int) crop_info.y;
4838 crop_info.width=0;
4839 crop_info.height=0;
4840 state=DefaultState;
4841 do
4842 {
4843 highlight_info=crop_info;
4844 highlight_info.x=crop_info.x-windows->image.x;
4845 highlight_info.y=crop_info.y-windows->image.y;
4846 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4847 {
4848 /*
4849 Display info and draw cropping rectangle.
4850 */
4851 if (windows->info.mapped == MagickFalse)
4852 (void) XMapWindow(display,windows->info.id);
4853 (void) FormatLocaleString(text,MagickPathExtent,
4854 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4855 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4856 XInfoWidget(display,windows,text);
4857 XHighlightRectangle(display,windows->image.id,
4858 windows->image.highlight_context,&highlight_info);
4859 }
4860 else
4861 if (windows->info.mapped != MagickFalse)
4862 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4863 /*
4864 Wait for next event.
4865 */
4866 XScreenEvent(display,windows,&event,exception);
4867 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4868 XHighlightRectangle(display,windows->image.id,
4869 windows->image.highlight_context,&highlight_info);
4870 switch (event.type)
4871 {
4872 case ButtonPress:
4873 {
4874 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4875 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4876 break;
4877 }
4878 case ButtonRelease:
4879 {
4880 /*
4881 User has committed to cropping rectangle.
4882 */
4883 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4884 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4885 XSetCursorState(display,windows,MagickFalse);
4886 state|=ExitState;
4887 windows->command.data=0;
4888 (void) XCommandWidget(display,windows,RectifyModeMenu,
4889 (XEvent *) NULL);
4890 break;
4891 }
4892 case Expose:
4893 break;
4894 case MotionNotify:
4895 {
4896 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4897 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4898 }
4899 default:
4900 break;
4901 }
4902 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4903 ((state & ExitState) != 0))
4904 {
4905 /*
4906 Check boundary conditions.
4907 */
4908 if (crop_info.x < 0)
4909 crop_info.x=0;
4910 else
4911 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4912 crop_info.x=(ssize_t) windows->image.ximage->width;
4913 if ((int) crop_info.x < x)
4914 crop_info.width=(unsigned int) (x-crop_info.x);
4915 else
4916 {
4917 crop_info.width=(unsigned int) (crop_info.x-x);
4918 crop_info.x=(ssize_t) x;
4919 }
4920 if (crop_info.y < 0)
4921 crop_info.y=0;
4922 else
4923 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4924 crop_info.y=(ssize_t) windows->image.ximage->height;
4925 if ((int) crop_info.y < y)
4926 crop_info.height=(unsigned int) (y-crop_info.y);
4927 else
4928 {
4929 crop_info.height=(unsigned int) (crop_info.y-y);
4930 crop_info.y=(ssize_t) y;
4931 }
4932 }
4933 } while ((state & ExitState) == 0);
4934 /*
4935 Wait for user to grab a corner of the rectangle or press return.
4936 */
4937 state=DefaultState;
4938 (void) XMapWindow(display,windows->info.id);
4939 do
4940 {
4941 if (windows->info.mapped != MagickFalse)
4942 {
4943 /*
4944 Display pointer position.
4945 */
4946 (void) FormatLocaleString(text,MagickPathExtent,
4947 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4948 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4949 XInfoWidget(display,windows,text);
4950 }
4951 highlight_info=crop_info;
4952 highlight_info.x=crop_info.x-windows->image.x;
4953 highlight_info.y=crop_info.y-windows->image.y;
4954 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4955 {
4956 state|=EscapeState;
4957 state|=ExitState;
4958 break;
4959 }
4960 XHighlightRectangle(display,windows->image.id,
4961 windows->image.highlight_context,&highlight_info);
4962 XScreenEvent(display,windows,&event,exception);
4963 if (event.xany.window == windows->command.id)
4964 {
4965 /*
4966 Select a command from the Command widget.
4967 */
4968 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4969 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4970 (void) XSetFunction(display,windows->image.highlight_context,
4971 GXinvert);
4972 XHighlightRectangle(display,windows->image.id,
4973 windows->image.highlight_context,&highlight_info);
4974 if (id >= 0)
4975 switch (RectifyCommands[id])
4976 {
4977 case RectifyCopyCommand:
4978 {
4979 state|=ExitState;
4980 break;
4981 }
4982 case RectifyHelpCommand:
4983 {
4984 (void) XSetFunction(display,windows->image.highlight_context,
4985 GXcopy);
4986 switch (mode)
4987 {
4988 case CopyMode:
4989 {
4990 XTextViewHelp(display,resource_info,windows,MagickFalse,
4991 "Help Viewer - Image Copy",ImageCopyHelp);
4992 break;
4993 }
4994 case CropMode:
4995 {
4996 XTextViewHelp(display,resource_info,windows,MagickFalse,
4997 "Help Viewer - Image Crop",ImageCropHelp);
4998 break;
4999 }
5000 case CutMode:
5001 {
5002 XTextViewHelp(display,resource_info,windows,MagickFalse,
5003 "Help Viewer - Image Cut",ImageCutHelp);
5004 break;
5005 }
5006 }
5007 (void) XSetFunction(display,windows->image.highlight_context,
5008 GXinvert);
5009 break;
5010 }
5011 case RectifyDismissCommand:
5012 {
5013 /*
5014 Prematurely exit.
5015 */
5016 state|=EscapeState;
5017 state|=ExitState;
5018 break;
5019 }
5020 default:
5021 break;
5022 }
5023 continue;
5024 }
5025 XHighlightRectangle(display,windows->image.id,
5026 windows->image.highlight_context,&highlight_info);
5027 switch (event.type)
5028 {
5029 case ButtonPress:
5030 {
5031 if (event.xbutton.button != Button1)
5032 break;
5033 if (event.xbutton.window != windows->image.id)
5034 break;
5035 x=windows->image.x+event.xbutton.x;
5036 y=windows->image.y+event.xbutton.y;
5037 if ((x < (int) (crop_info.x+RoiDelta)) &&
5038 (x > (int) (crop_info.x-RoiDelta)) &&
5039 (y < (int) (crop_info.y+RoiDelta)) &&
5040 (y > (int) (crop_info.y-RoiDelta)))
5041 {
5042 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5043 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5044 state|=UpdateConfigurationState;
5045 break;
5046 }
5047 if ((x < (int) (crop_info.x+RoiDelta)) &&
5048 (x > (int) (crop_info.x-RoiDelta)) &&
5049 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5050 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5051 {
5052 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5053 state|=UpdateConfigurationState;
5054 break;
5055 }
5056 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5057 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5058 (y < (int) (crop_info.y+RoiDelta)) &&
5059 (y > (int) (crop_info.y-RoiDelta)))
5060 {
5061 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5062 state|=UpdateConfigurationState;
5063 break;
5064 }
5065 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5066 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5067 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5068 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5069 {
5070 state|=UpdateConfigurationState;
5071 break;
5072 }
5073 }
5074 case ButtonRelease:
5075 {
5076 if (event.xbutton.window == windows->pan.id)
5077 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5078 (highlight_info.y != crop_info.y-windows->image.y))
5079 XHighlightRectangle(display,windows->image.id,
5080 windows->image.highlight_context,&highlight_info);
5081 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5082 event.xbutton.time);
5083 break;
5084 }
5085 case Expose:
5086 {
5087 if (event.xexpose.window == windows->image.id)
5088 if (event.xexpose.count == 0)
5089 {
5090 event.xexpose.x=(int) highlight_info.x;
5091 event.xexpose.y=(int) highlight_info.y;
5092 event.xexpose.width=(int) highlight_info.width;
5093 event.xexpose.height=(int) highlight_info.height;
5094 XRefreshWindow(display,&windows->image,&event);
5095 }
5096 if (event.xexpose.window == windows->info.id)
5097 if (event.xexpose.count == 0)
5098 XInfoWidget(display,windows,text);
5099 break;
5100 }
5101 case KeyPress:
5102 {
5103 if (event.xkey.window != windows->image.id)
5104 break;
5105 /*
5106 Respond to a user key press.
5107 */
5108 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5109 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5110 switch ((int) key_symbol)
5111 {
5112 case XK_Escape:
5113 case XK_F20:
5114 state|=EscapeState;
5115 case XK_Return:
5116 {
5117 state|=ExitState;
5118 break;
5119 }
5120 case XK_Home:
5121 case XK_KP_Home:
5122 {
5123 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/
5124 2L);
5125 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/
5126 2L);
5127 break;
5128 }
5129 case XK_Left:
5130 case XK_KP_Left:
5131 {
5132 crop_info.x--;
5133 break;
5134 }
5135 case XK_Up:
5136 case XK_KP_Up:
5137 case XK_Next:
5138 {
5139 crop_info.y--;
5140 break;
5141 }
5142 case XK_Right:
5143 case XK_KP_Right:
5144 {
5145 crop_info.x++;
5146 break;
5147 }
5148 case XK_Prior:
5149 case XK_Down:
5150 case XK_KP_Down:
5151 {
5152 crop_info.y++;
5153 break;
5154 }
5155 case XK_F1:
5156 case XK_Help:
5157 {
5158 (void) XSetFunction(display,windows->image.highlight_context,
5159 GXcopy);
5160 switch (mode)
5161 {
5162 case CopyMode:
5163 {
5164 XTextViewHelp(display,resource_info,windows,MagickFalse,
5165 "Help Viewer - Image Copy",ImageCopyHelp);
5166 break;
5167 }
5168 case CropMode:
5169 {
5170 XTextViewHelp(display,resource_info,windows,MagickFalse,
5171 "Help Viewer - Image Cropg",ImageCropHelp);
5172 break;
5173 }
5174 case CutMode:
5175 {
5176 XTextViewHelp(display,resource_info,windows,MagickFalse,
5177 "Help Viewer - Image Cutg",ImageCutHelp);
5178 break;
5179 }
5180 }
5181 (void) XSetFunction(display,windows->image.highlight_context,
5182 GXinvert);
5183 break;
5184 }
5185 default:
5186 {
5187 (void) XBell(display,0);
5188 break;
5189 }
5190 }
5191 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5192 event.xkey.time);
5193 break;
5194 }
5195 case KeyRelease:
5196 break;
5197 case MotionNotify:
5198 {
5199 if (event.xmotion.window != windows->image.id)
5200 break;
5201 /*
5202 Map and unmap Info widget as text cursor crosses its boundaries.
5203 */
5204 x=event.xmotion.x;
5205 y=event.xmotion.y;
5206 if (windows->info.mapped != MagickFalse)
5207 {
5208 if ((x < (int) (windows->info.x+windows->info.width)) &&
5209 (y < (int) (windows->info.y+windows->info.height)))
5210 (void) XWithdrawWindow(display,windows->info.id,
5211 windows->info.screen);
5212 }
5213 else
5214 if ((x > (int) (windows->info.x+windows->info.width)) ||
5215 (y > (int) (windows->info.y+windows->info.height)))
5216 (void) XMapWindow(display,windows->info.id);
5217 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5218 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5219 break;
5220 }
5221 case SelectionRequest:
5222 {
5223 XSelectionEvent
5224 notify;
5225
5226 XSelectionRequestEvent
5227 *request;
5228
5229 /*
5230 Set primary selection.
5231 */
5232 (void) FormatLocaleString(text,MagickPathExtent,
5233 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5234 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5235 request=(&(event.xselectionrequest));
5236 (void) XChangeProperty(request->display,request->requestor,
5237 request->property,request->target,8,PropModeReplace,
5238 (unsigned char *) text,(int) strlen(text));
5239 notify.type=SelectionNotify;
5240 notify.display=request->display;
5241 notify.requestor=request->requestor;
5242 notify.selection=request->selection;
5243 notify.target=request->target;
5244 notify.time=request->time;
5245 if (request->property == None)
5246 notify.property=request->target;
5247 else
5248 notify.property=request->property;
5249 (void) XSendEvent(request->display,request->requestor,False,0,
5250 (XEvent *) ¬ify);
5251 }
5252 default:
5253 break;
5254 }
5255 if ((state & UpdateConfigurationState) != 0)
5256 {
5257 (void) XPutBackEvent(display,&event);
5258 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5259 break;
5260 }
5261 } while ((state & ExitState) == 0);
5262 } while ((state & ExitState) == 0);
5263 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5264 XSetCursorState(display,windows,MagickFalse);
5265 if ((state & EscapeState) != 0)
5266 return(MagickTrue);
5267 if (mode == CropMode)
5268 if (((int) crop_info.width != windows->image.ximage->width) ||
5269 ((int) crop_info.height != windows->image.ximage->height))
5270 {
5271 /*
5272 Reconfigure Image window as defined by cropping rectangle.
5273 */
5274 XSetCropGeometry(display,windows,&crop_info,image);
5275 windows->image.window_changes.width=(int) crop_info.width;
5276 windows->image.window_changes.height=(int) crop_info.height;
5277 (void) XConfigureImage(display,resource_info,windows,image,exception);
5278 return(MagickTrue);
5279 }
5280 /*
5281 Copy image before applying image transforms.
5282 */
5283 XSetCursorState(display,windows,MagickTrue);
5284 XCheckRefreshWindows(display,windows);
5285 width=(unsigned int) image->columns;
5286 height=(unsigned int) image->rows;
5287 x=0;
5288 y=0;
5289 if (windows->image.crop_geometry != (char *) NULL)
5290 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5291 scale_factor=(double) width/windows->image.ximage->width;
5292 crop_info.x+=x;
5293 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5294 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5295 scale_factor=(double) height/windows->image.ximage->height;
5296 crop_info.y+=y;
5297 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5298 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5299 crop_info.x+=image->page.x;
5300 crop_info.y+=image->page.y;
5301 crop_image=CropImage(image,&crop_info,exception);
5302 XSetCursorState(display,windows,MagickFalse);
5303 if (crop_image == (Image *) NULL)
5304 return(MagickFalse);
5305 if (resource_info->copy_image != (Image *) NULL)
5306 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5307 resource_info->copy_image=crop_image;
5308 if (mode == CopyMode)
5309 {
5310 (void) XConfigureImage(display,resource_info,windows,image,exception);
5311 return(MagickTrue);
5312 }
5313 /*
5314 Cut image.
5315 */
5316 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
5317 return(MagickFalse);
5318 image->alpha_trait=BlendPixelTrait;
5319 image_view=AcquireAuthenticCacheView(image,exception);
5320 for (y=0; y < (int) crop_info.height; y++)
5321 {
5322 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5323 crop_info.width,1,exception);
5324 if (q == (Quantum *) NULL)
5325 break;
5326 for (x=0; x < (int) crop_info.width; x++)
5327 {
5328 SetPixelAlpha(image,TransparentAlpha,q);
5329 q+=GetPixelChannels(image);
5330 }
5331 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5332 break;
5333 }
5334 image_view=DestroyCacheView(image_view);
5335 /*
5336 Update image configuration.
5337 */
5338 XConfigureImageColormap(display,resource_info,windows,image,exception);
5339 (void) XConfigureImage(display,resource_info,windows,image,exception);
5340 return(MagickTrue);
5341 }
5342
5343 /*
5344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5345 % %
5346 % %
5347 % %
5348 + X D r a w I m a g e %
5349 % %
5350 % %
5351 % %
5352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5353 %
5354 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5355 % the image.
5356 %
5357 % The format of the XDrawEditImage method is:
5358 %
5359 % MagickBooleanType XDrawEditImage(Display *display,
5360 % XResourceInfo *resource_info,XWindows *windows,Image **image,
5361 % ExceptionInfo *exception)
5362 %
5363 % A description of each parameter follows:
5364 %
5365 % o display: Specifies a connection to an X server; returned from
5366 % XOpenDisplay.
5367 %
5368 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5369 %
5370 % o windows: Specifies a pointer to a XWindows structure.
5371 %
5372 % o image: the image.
5373 %
5374 % o exception: return any errors or warnings in this structure.
5375 %
5376 */
XDrawEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)5377 static MagickBooleanType XDrawEditImage(Display *display,
5378 XResourceInfo *resource_info,XWindows *windows,Image **image,
5379 ExceptionInfo *exception)
5380 {
5381 const char
5382 *const DrawMenu[] =
5383 {
5384 "Element",
5385 "Color",
5386 "Stipple",
5387 "Width",
5388 "Undo",
5389 "Help",
5390 "Dismiss",
5391 (char *) NULL
5392 };
5393
5394 static ElementType
5395 element = PointElement;
5396
5397 static const ModeType
5398 DrawCommands[] =
5399 {
5400 DrawElementCommand,
5401 DrawColorCommand,
5402 DrawStippleCommand,
5403 DrawWidthCommand,
5404 DrawUndoCommand,
5405 DrawHelpCommand,
5406 DrawDismissCommand
5407 };
5408
5409 static Pixmap
5410 stipple = (Pixmap) NULL;
5411
5412 static unsigned int
5413 pen_id = 0,
5414 line_width = 1;
5415
5416 char
5417 command[MagickPathExtent],
5418 text[MagickPathExtent];
5419
5420 Cursor
5421 cursor;
5422
5423 int
5424 entry,
5425 id,
5426 number_coordinates,
5427 x,
5428 y;
5429
5430 double
5431 degrees;
5432
5433 MagickStatusType
5434 status;
5435
5436 RectangleInfo
5437 rectangle_info;
5438
5439 int
5440 i;
5441
5442 unsigned int
5443 distance,
5444 height,
5445 max_coordinates,
5446 width;
5447
5448 size_t
5449 state;
5450
5451 Window
5452 root_window;
5453
5454 XDrawInfo
5455 draw_info;
5456
5457 XEvent
5458 event;
5459
5460 XPoint
5461 *coordinate_info;
5462
5463 XSegment
5464 line_info;
5465
5466 /*
5467 Allocate polygon info.
5468 */
5469 max_coordinates=2048;
5470 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5471 sizeof(*coordinate_info));
5472 if (coordinate_info == (XPoint *) NULL)
5473 {
5474 (void) ThrowMagickException(exception,GetMagickModule(),
5475 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5476 return(MagickFalse);
5477 }
5478 /*
5479 Map Command widget.
5480 */
5481 (void) CloneString(&windows->command.name,"Draw");
5482 windows->command.data=4;
5483 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5484 (void) XMapRaised(display,windows->command.id);
5485 XClientMessage(display,windows->image.id,windows->im_protocols,
5486 windows->im_update_widget,CurrentTime);
5487 /*
5488 Wait for first button press.
5489 */
5490 root_window=XRootWindow(display,XDefaultScreen(display));
5491 draw_info.stencil=OpaqueStencil;
5492 status=MagickTrue;
5493 cursor=XCreateFontCursor(display,XC_tcross);
5494 for ( ; ; )
5495 {
5496 XQueryPosition(display,windows->image.id,&x,&y);
5497 (void) XSelectInput(display,windows->image.id,
5498 windows->image.attributes.event_mask | PointerMotionMask);
5499 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5500 state=DefaultState;
5501 do
5502 {
5503 if (windows->info.mapped != MagickFalse)
5504 {
5505 /*
5506 Display pointer position.
5507 */
5508 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
5509 x+windows->image.x,y+windows->image.y);
5510 XInfoWidget(display,windows,text);
5511 }
5512 /*
5513 Wait for next event.
5514 */
5515 XScreenEvent(display,windows,&event,exception);
5516 if (event.xany.window == windows->command.id)
5517 {
5518 /*
5519 Select a command from the Command widget.
5520 */
5521 id=XCommandWidget(display,windows,DrawMenu,&event);
5522 if (id < 0)
5523 continue;
5524 switch (DrawCommands[id])
5525 {
5526 case DrawElementCommand:
5527 {
5528 const char
5529 *const Elements[] =
5530 {
5531 "point",
5532 "line",
5533 "rectangle",
5534 "fill rectangle",
5535 "circle",
5536 "fill circle",
5537 "ellipse",
5538 "fill ellipse",
5539 "polygon",
5540 "fill polygon",
5541 (char *) NULL,
5542 };
5543
5544 /*
5545 Select a command from the pop-up menu.
5546 */
5547 element=(ElementType) (XMenuWidget(display,windows,
5548 DrawMenu[id],Elements,command)+1);
5549 break;
5550 }
5551 case DrawColorCommand:
5552 {
5553 const char
5554 *ColorMenu[MaxNumberPens+1];
5555
5556 int
5557 pen_number;
5558
5559 MagickBooleanType
5560 transparent;
5561
5562 XColor
5563 color;
5564
5565 /*
5566 Initialize menu selections.
5567 */
5568 for (i=0; i < (int) (MaxNumberPens-2); i++)
5569 ColorMenu[i]=resource_info->pen_colors[i];
5570 ColorMenu[MaxNumberPens-2]="transparent";
5571 ColorMenu[MaxNumberPens-1]="Browser...";
5572 ColorMenu[MaxNumberPens]=(char *) NULL;
5573 /*
5574 Select a pen color from the pop-up menu.
5575 */
5576 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5577 (const char **) ColorMenu,command);
5578 if (pen_number < 0)
5579 break;
5580 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5581 MagickFalse;
5582 if (transparent != MagickFalse)
5583 {
5584 draw_info.stencil=TransparentStencil;
5585 break;
5586 }
5587 if (pen_number == (MaxNumberPens-1))
5588 {
5589 static char
5590 color_name[MagickPathExtent] = "gray";
5591
5592 /*
5593 Select a pen color from a dialog.
5594 */
5595 resource_info->pen_colors[pen_number]=color_name;
5596 XColorBrowserWidget(display,windows,"Select",color_name);
5597 if (*color_name == '\0')
5598 break;
5599 }
5600 /*
5601 Set pen color.
5602 */
5603 (void) XParseColor(display,windows->map_info->colormap,
5604 resource_info->pen_colors[pen_number],&color);
5605 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5606 (unsigned int) MaxColors,&color);
5607 windows->pixel_info->pen_colors[pen_number]=color;
5608 pen_id=(unsigned int) pen_number;
5609 draw_info.stencil=OpaqueStencil;
5610 break;
5611 }
5612 case DrawStippleCommand:
5613 {
5614 const char
5615 *StipplesMenu[] =
5616 {
5617 "Brick",
5618 "Diagonal",
5619 "Scales",
5620 "Vertical",
5621 "Wavy",
5622 "Translucent",
5623 "Opaque",
5624 (char *) NULL,
5625 (char *) NULL,
5626 };
5627
5628 Image
5629 *stipple_image;
5630
5631 ImageInfo
5632 *image_info;
5633
5634 int
5635 status;
5636
5637 static char
5638 filename[MagickPathExtent] = "\0";
5639
5640 /*
5641 Select a command from the pop-up menu.
5642 */
5643 StipplesMenu[7]="Open...";
5644 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5645 command);
5646 if (entry < 0)
5647 break;
5648 if (stipple != (Pixmap) NULL)
5649 (void) XFreePixmap(display,stipple);
5650 stipple=(Pixmap) NULL;
5651 if (entry != 7)
5652 {
5653 switch (entry)
5654 {
5655 case 0:
5656 {
5657 stipple=XCreateBitmapFromData(display,root_window,
5658 (char *) BricksBitmap,BricksWidth,BricksHeight);
5659 break;
5660 }
5661 case 1:
5662 {
5663 stipple=XCreateBitmapFromData(display,root_window,
5664 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5665 break;
5666 }
5667 case 2:
5668 {
5669 stipple=XCreateBitmapFromData(display,root_window,
5670 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5671 break;
5672 }
5673 case 3:
5674 {
5675 stipple=XCreateBitmapFromData(display,root_window,
5676 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5677 break;
5678 }
5679 case 4:
5680 {
5681 stipple=XCreateBitmapFromData(display,root_window,
5682 (char *) WavyBitmap,WavyWidth,WavyHeight);
5683 break;
5684 }
5685 case 5:
5686 {
5687 stipple=XCreateBitmapFromData(display,root_window,
5688 (char *) HighlightBitmap,HighlightWidth,
5689 HighlightHeight);
5690 break;
5691 }
5692 case 6:
5693 default:
5694 {
5695 stipple=XCreateBitmapFromData(display,root_window,
5696 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5697 break;
5698 }
5699 }
5700 break;
5701 }
5702 XFileBrowserWidget(display,windows,"Stipple",filename);
5703 if (*filename == '\0')
5704 break;
5705 /*
5706 Read image.
5707 */
5708 XSetCursorState(display,windows,MagickTrue);
5709 XCheckRefreshWindows(display,windows);
5710 image_info=AcquireImageInfo();
5711 (void) CopyMagickString(image_info->filename,filename,
5712 MagickPathExtent);
5713 stipple_image=ReadImage(image_info,exception);
5714 CatchException(exception);
5715 XSetCursorState(display,windows,MagickFalse);
5716 if (stipple_image == (Image *) NULL)
5717 break;
5718 (void) AcquireUniqueFileResource(filename);
5719 (void) FormatLocaleString(stipple_image->filename,
5720 MagickPathExtent,"xbm:%s",filename);
5721 (void) WriteImage(image_info,stipple_image,exception);
5722 stipple_image=DestroyImage(stipple_image);
5723 image_info=DestroyImageInfo(image_info);
5724 status=XReadBitmapFile(display,root_window,filename,&width,
5725 &height,&stipple,&x,&y);
5726 (void) RelinquishUniqueFileResource(filename);
5727 if ((status != BitmapSuccess) != 0)
5728 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5729 filename);
5730 break;
5731 }
5732 case DrawWidthCommand:
5733 {
5734 const char
5735 *const WidthsMenu[] =
5736 {
5737 "1",
5738 "2",
5739 "4",
5740 "8",
5741 "16",
5742 "Dialog...",
5743 (char *) NULL,
5744 };
5745
5746 static char
5747 width[MagickPathExtent] = "0";
5748
5749 /*
5750 Select a command from the pop-up menu.
5751 */
5752 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5753 command);
5754 if (entry < 0)
5755 break;
5756 if (entry != 5)
5757 {
5758 line_width=(unsigned int) StringToUnsignedLong(
5759 WidthsMenu[entry]);
5760 break;
5761 }
5762 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5763 width);
5764 if (*width == '\0')
5765 break;
5766 line_width=(unsigned int) StringToUnsignedLong(width);
5767 break;
5768 }
5769 case DrawUndoCommand:
5770 {
5771 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5772 image,exception);
5773 break;
5774 }
5775 case DrawHelpCommand:
5776 {
5777 XTextViewHelp(display,resource_info,windows,MagickFalse,
5778 "Help Viewer - Image Rotation",ImageDrawHelp);
5779 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5780 break;
5781 }
5782 case DrawDismissCommand:
5783 {
5784 /*
5785 Prematurely exit.
5786 */
5787 state|=EscapeState;
5788 state|=ExitState;
5789 break;
5790 }
5791 default:
5792 break;
5793 }
5794 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5795 continue;
5796 }
5797 switch (event.type)
5798 {
5799 case ButtonPress:
5800 {
5801 if (event.xbutton.button != Button1)
5802 break;
5803 if (event.xbutton.window != windows->image.id)
5804 break;
5805 /*
5806 exit loop.
5807 */
5808 x=event.xbutton.x;
5809 y=event.xbutton.y;
5810 state|=ExitState;
5811 break;
5812 }
5813 case ButtonRelease:
5814 break;
5815 case Expose:
5816 break;
5817 case KeyPress:
5818 {
5819 KeySym
5820 key_symbol;
5821
5822 if (event.xkey.window != windows->image.id)
5823 break;
5824 /*
5825 Respond to a user key press.
5826 */
5827 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5828 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5829 switch ((int) key_symbol)
5830 {
5831 case XK_Escape:
5832 case XK_F20:
5833 {
5834 /*
5835 Prematurely exit.
5836 */
5837 state|=EscapeState;
5838 state|=ExitState;
5839 break;
5840 }
5841 case XK_F1:
5842 case XK_Help:
5843 {
5844 XTextViewHelp(display,resource_info,windows,MagickFalse,
5845 "Help Viewer - Image Rotation",ImageDrawHelp);
5846 break;
5847 }
5848 default:
5849 {
5850 (void) XBell(display,0);
5851 break;
5852 }
5853 }
5854 break;
5855 }
5856 case MotionNotify:
5857 {
5858 /*
5859 Map and unmap Info widget as text cursor crosses its boundaries.
5860 */
5861 x=event.xmotion.x;
5862 y=event.xmotion.y;
5863 if (windows->info.mapped != MagickFalse)
5864 {
5865 if ((x < (int) (windows->info.x+windows->info.width)) &&
5866 (y < (int) (windows->info.y+windows->info.height)))
5867 (void) XWithdrawWindow(display,windows->info.id,
5868 windows->info.screen);
5869 }
5870 else
5871 if ((x > (int) (windows->info.x+windows->info.width)) ||
5872 (y > (int) (windows->info.y+windows->info.height)))
5873 (void) XMapWindow(display,windows->info.id);
5874 break;
5875 }
5876 }
5877 } while ((state & ExitState) == 0);
5878 (void) XSelectInput(display,windows->image.id,
5879 windows->image.attributes.event_mask);
5880 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5881 if ((state & EscapeState) != 0)
5882 break;
5883 /*
5884 Draw element as pointer moves until the button is released.
5885 */
5886 distance=0;
5887 degrees=0.0;
5888 line_info.x1=x;
5889 line_info.y1=y;
5890 line_info.x2=x;
5891 line_info.y2=y;
5892 rectangle_info.x=(ssize_t) x;
5893 rectangle_info.y=(ssize_t) y;
5894 rectangle_info.width=0;
5895 rectangle_info.height=0;
5896 number_coordinates=1;
5897 coordinate_info->x=x;
5898 coordinate_info->y=y;
5899 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5900 state=DefaultState;
5901 do
5902 {
5903 switch (element)
5904 {
5905 case PointElement:
5906 default:
5907 {
5908 if (number_coordinates > 1)
5909 {
5910 (void) XDrawLines(display,windows->image.id,
5911 windows->image.highlight_context,coordinate_info,
5912 number_coordinates,CoordModeOrigin);
5913 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d",
5914 coordinate_info[number_coordinates-1].x,
5915 coordinate_info[number_coordinates-1].y);
5916 XInfoWidget(display,windows,text);
5917 }
5918 break;
5919 }
5920 case LineElement:
5921 {
5922 if (distance > 9)
5923 {
5924 /*
5925 Display angle of the line.
5926 */
5927 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5928 line_info.y1),(double) (line_info.x2-line_info.x1)));
5929 (void) FormatLocaleString(text,MagickPathExtent," %g",
5930 (double) degrees);
5931 XInfoWidget(display,windows,text);
5932 XHighlightLine(display,windows->image.id,
5933 windows->image.highlight_context,&line_info);
5934 }
5935 else
5936 if (windows->info.mapped != MagickFalse)
5937 (void) XWithdrawWindow(display,windows->info.id,
5938 windows->info.screen);
5939 break;
5940 }
5941 case RectangleElement:
5942 case FillRectangleElement:
5943 {
5944 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5945 {
5946 /*
5947 Display info and draw drawing rectangle.
5948 */
5949 (void) FormatLocaleString(text,MagickPathExtent,
5950 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5951 (double) rectangle_info.height,(double) rectangle_info.x,
5952 (double) rectangle_info.y);
5953 XInfoWidget(display,windows,text);
5954 XHighlightRectangle(display,windows->image.id,
5955 windows->image.highlight_context,&rectangle_info);
5956 }
5957 else
5958 if (windows->info.mapped != MagickFalse)
5959 (void) XWithdrawWindow(display,windows->info.id,
5960 windows->info.screen);
5961 break;
5962 }
5963 case CircleElement:
5964 case FillCircleElement:
5965 case EllipseElement:
5966 case FillEllipseElement:
5967 {
5968 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5969 {
5970 /*
5971 Display info and draw drawing rectangle.
5972 */
5973 (void) FormatLocaleString(text,MagickPathExtent,
5974 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5975 (double) rectangle_info.height,(double) rectangle_info.x,
5976 (double) rectangle_info.y);
5977 XInfoWidget(display,windows,text);
5978 XHighlightEllipse(display,windows->image.id,
5979 windows->image.highlight_context,&rectangle_info);
5980 }
5981 else
5982 if (windows->info.mapped != MagickFalse)
5983 (void) XWithdrawWindow(display,windows->info.id,
5984 windows->info.screen);
5985 break;
5986 }
5987 case PolygonElement:
5988 case FillPolygonElement:
5989 {
5990 if (number_coordinates > 1)
5991 (void) XDrawLines(display,windows->image.id,
5992 windows->image.highlight_context,coordinate_info,
5993 number_coordinates,CoordModeOrigin);
5994 if (distance > 9)
5995 {
5996 /*
5997 Display angle of the line.
5998 */
5999 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6000 line_info.y1),(double) (line_info.x2-line_info.x1)));
6001 (void) FormatLocaleString(text,MagickPathExtent," %g",
6002 (double) degrees);
6003 XInfoWidget(display,windows,text);
6004 XHighlightLine(display,windows->image.id,
6005 windows->image.highlight_context,&line_info);
6006 }
6007 else
6008 if (windows->info.mapped != MagickFalse)
6009 (void) XWithdrawWindow(display,windows->info.id,
6010 windows->info.screen);
6011 break;
6012 }
6013 }
6014 /*
6015 Wait for next event.
6016 */
6017 XScreenEvent(display,windows,&event,exception);
6018 switch (element)
6019 {
6020 case PointElement:
6021 default:
6022 {
6023 if (number_coordinates > 1)
6024 (void) XDrawLines(display,windows->image.id,
6025 windows->image.highlight_context,coordinate_info,
6026 number_coordinates,CoordModeOrigin);
6027 break;
6028 }
6029 case LineElement:
6030 {
6031 if (distance > 9)
6032 XHighlightLine(display,windows->image.id,
6033 windows->image.highlight_context,&line_info);
6034 break;
6035 }
6036 case RectangleElement:
6037 case FillRectangleElement:
6038 {
6039 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6040 XHighlightRectangle(display,windows->image.id,
6041 windows->image.highlight_context,&rectangle_info);
6042 break;
6043 }
6044 case CircleElement:
6045 case FillCircleElement:
6046 case EllipseElement:
6047 case FillEllipseElement:
6048 {
6049 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6050 XHighlightEllipse(display,windows->image.id,
6051 windows->image.highlight_context,&rectangle_info);
6052 break;
6053 }
6054 case PolygonElement:
6055 case FillPolygonElement:
6056 {
6057 if (number_coordinates > 1)
6058 (void) XDrawLines(display,windows->image.id,
6059 windows->image.highlight_context,coordinate_info,
6060 number_coordinates,CoordModeOrigin);
6061 if (distance > 9)
6062 XHighlightLine(display,windows->image.id,
6063 windows->image.highlight_context,&line_info);
6064 break;
6065 }
6066 }
6067 switch (event.type)
6068 {
6069 case ButtonPress:
6070 break;
6071 case ButtonRelease:
6072 {
6073 /*
6074 User has committed to element.
6075 */
6076 line_info.x2=event.xbutton.x;
6077 line_info.y2=event.xbutton.y;
6078 rectangle_info.x=(ssize_t) event.xbutton.x;
6079 rectangle_info.y=(ssize_t) event.xbutton.y;
6080 coordinate_info[number_coordinates].x=event.xbutton.x;
6081 coordinate_info[number_coordinates].y=event.xbutton.y;
6082 if (((element != PolygonElement) &&
6083 (element != FillPolygonElement)) || (distance <= 9))
6084 {
6085 state|=ExitState;
6086 break;
6087 }
6088 number_coordinates++;
6089 if (number_coordinates < (int) max_coordinates)
6090 {
6091 line_info.x1=event.xbutton.x;
6092 line_info.y1=event.xbutton.y;
6093 break;
6094 }
6095 max_coordinates<<=1;
6096 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6097 max_coordinates,sizeof(*coordinate_info));
6098 if (coordinate_info == (XPoint *) NULL)
6099 (void) ThrowMagickException(exception,GetMagickModule(),
6100 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6101 break;
6102 }
6103 case Expose:
6104 break;
6105 case MotionNotify:
6106 {
6107 if (event.xmotion.window != windows->image.id)
6108 break;
6109 if (element != PointElement)
6110 {
6111 line_info.x2=event.xmotion.x;
6112 line_info.y2=event.xmotion.y;
6113 rectangle_info.x=(ssize_t) event.xmotion.x;
6114 rectangle_info.y=(ssize_t) event.xmotion.y;
6115 break;
6116 }
6117 coordinate_info[number_coordinates].x=event.xbutton.x;
6118 coordinate_info[number_coordinates].y=event.xbutton.y;
6119 number_coordinates++;
6120 if (number_coordinates < (int) max_coordinates)
6121 break;
6122 max_coordinates<<=1;
6123 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6124 max_coordinates,sizeof(*coordinate_info));
6125 if (coordinate_info == (XPoint *) NULL)
6126 (void) ThrowMagickException(exception,GetMagickModule(),
6127 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6128 break;
6129 }
6130 default:
6131 break;
6132 }
6133 /*
6134 Check boundary conditions.
6135 */
6136 if (line_info.x2 < 0)
6137 line_info.x2=0;
6138 else
6139 if (line_info.x2 > (int) windows->image.width)
6140 line_info.x2=(short) windows->image.width;
6141 if (line_info.y2 < 0)
6142 line_info.y2=0;
6143 else
6144 if (line_info.y2 > (int) windows->image.height)
6145 line_info.y2=(short) windows->image.height;
6146 distance=(unsigned int)
6147 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6148 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6149 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6150 ((state & ExitState) != 0))
6151 {
6152 if (rectangle_info.x < 0)
6153 rectangle_info.x=0;
6154 else
6155 if (rectangle_info.x > (ssize_t) windows->image.width)
6156 rectangle_info.x=(ssize_t) windows->image.width;
6157 if ((int) rectangle_info.x < x)
6158 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6159 else
6160 {
6161 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6162 rectangle_info.x=(ssize_t) x;
6163 }
6164 if (rectangle_info.y < 0)
6165 rectangle_info.y=0;
6166 else
6167 if (rectangle_info.y > (ssize_t) windows->image.height)
6168 rectangle_info.y=(ssize_t) windows->image.height;
6169 if ((int) rectangle_info.y < y)
6170 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6171 else
6172 {
6173 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6174 rectangle_info.y=(ssize_t) y;
6175 }
6176 }
6177 } while ((state & ExitState) == 0);
6178 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6179 if ((element == PointElement) || (element == PolygonElement) ||
6180 (element == FillPolygonElement))
6181 {
6182 /*
6183 Determine polygon bounding box.
6184 */
6185 rectangle_info.x=(ssize_t) coordinate_info->x;
6186 rectangle_info.y=(ssize_t) coordinate_info->y;
6187 x=coordinate_info->x;
6188 y=coordinate_info->y;
6189 for (i=1; i < number_coordinates; i++)
6190 {
6191 if (coordinate_info[i].x > x)
6192 x=coordinate_info[i].x;
6193 if (coordinate_info[i].y > y)
6194 y=coordinate_info[i].y;
6195 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6196 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6197 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6198 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6199 }
6200 rectangle_info.width=(size_t) (x-rectangle_info.x);
6201 rectangle_info.height=(size_t) (y-rectangle_info.y);
6202 for (i=0; i < number_coordinates; i++)
6203 {
6204 coordinate_info[i].x-=rectangle_info.x;
6205 coordinate_info[i].y-=rectangle_info.y;
6206 }
6207 }
6208 else
6209 if (distance <= 9)
6210 continue;
6211 else
6212 if ((element == RectangleElement) ||
6213 (element == CircleElement) || (element == EllipseElement))
6214 {
6215 rectangle_info.width--;
6216 rectangle_info.height--;
6217 }
6218 /*
6219 Drawing is relative to image configuration.
6220 */
6221 draw_info.x=(int) rectangle_info.x;
6222 draw_info.y=(int) rectangle_info.y;
6223 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6224 image,exception);
6225 width=(unsigned int) (*image)->columns;
6226 height=(unsigned int) (*image)->rows;
6227 x=0;
6228 y=0;
6229 if (windows->image.crop_geometry != (char *) NULL)
6230 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6231 draw_info.x+=windows->image.x-(line_width/2);
6232 if (draw_info.x < 0)
6233 draw_info.x=0;
6234 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6235 draw_info.y+=windows->image.y-(line_width/2);
6236 if (draw_info.y < 0)
6237 draw_info.y=0;
6238 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6239 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6240 if (draw_info.width > (unsigned int) (*image)->columns)
6241 draw_info.width=(unsigned int) (*image)->columns;
6242 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6243 if (draw_info.height > (unsigned int) (*image)->rows)
6244 draw_info.height=(unsigned int) (*image)->rows;
6245 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d",
6246 width*draw_info.width/windows->image.ximage->width,
6247 height*draw_info.height/windows->image.ximage->height,
6248 draw_info.x+x,draw_info.y+y);
6249 /*
6250 Initialize drawing attributes.
6251 */
6252 draw_info.degrees=0.0;
6253 draw_info.element=element;
6254 draw_info.stipple=stipple;
6255 draw_info.line_width=line_width;
6256 draw_info.line_info=line_info;
6257 if (line_info.x1 > (int) (line_width/2))
6258 draw_info.line_info.x1=(short) line_width/2;
6259 if (line_info.y1 > (int) (line_width/2))
6260 draw_info.line_info.y1=(short) line_width/2;
6261 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6262 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6263 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6264 {
6265 draw_info.line_info.x2=(-draw_info.line_info.x2);
6266 draw_info.line_info.y2=(-draw_info.line_info.y2);
6267 }
6268 if (draw_info.line_info.x2 < 0)
6269 {
6270 draw_info.line_info.x2=(-draw_info.line_info.x2);
6271 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6272 }
6273 if (draw_info.line_info.y2 < 0)
6274 {
6275 draw_info.line_info.y2=(-draw_info.line_info.y2);
6276 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6277 }
6278 draw_info.rectangle_info=rectangle_info;
6279 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6280 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6281 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6282 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6283 draw_info.number_coordinates=(unsigned int) number_coordinates;
6284 draw_info.coordinate_info=coordinate_info;
6285 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6286 /*
6287 Draw element on image.
6288 */
6289 XSetCursorState(display,windows,MagickTrue);
6290 XCheckRefreshWindows(display,windows);
6291 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
6292 XSetCursorState(display,windows,MagickFalse);
6293 /*
6294 Update image colormap and return to image drawing.
6295 */
6296 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6297 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6298 }
6299 XSetCursorState(display,windows,MagickFalse);
6300 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6301 return(status != 0 ? MagickTrue : MagickFalse);
6302 }
6303
6304 /*
6305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6306 % %
6307 % %
6308 % %
6309 + X D r a w P a n R e c t a n g l e %
6310 % %
6311 % %
6312 % %
6313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6314 %
6315 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6316 % displays a zoom image and the rectangle shows which portion of the image is
6317 % displayed in the Image window.
6318 %
6319 % The format of the XDrawPanRectangle method is:
6320 %
6321 % XDrawPanRectangle(Display *display,XWindows *windows)
6322 %
6323 % A description of each parameter follows:
6324 %
6325 % o display: Specifies a connection to an X server; returned from
6326 % XOpenDisplay.
6327 %
6328 % o windows: Specifies a pointer to a XWindows structure.
6329 %
6330 */
XDrawPanRectangle(Display * display,XWindows * windows)6331 static void XDrawPanRectangle(Display *display,XWindows *windows)
6332 {
6333 double
6334 scale_factor;
6335
6336 RectangleInfo
6337 highlight_info;
6338
6339 /*
6340 Determine dimensions of the panning rectangle.
6341 */
6342 scale_factor=(double) windows->pan.width/windows->image.ximage->width;
6343 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6344 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6345 scale_factor=(double)
6346 windows->pan.height/windows->image.ximage->height;
6347 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6348 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6349 /*
6350 Display the panning rectangle.
6351 */
6352 (void) XClearWindow(display,windows->pan.id);
6353 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6354 &highlight_info);
6355 }
6356
6357 /*
6358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6359 % %
6360 % %
6361 % %
6362 + X I m a g e C a c h e %
6363 % %
6364 % %
6365 % %
6366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6367 %
6368 % XImageCache() handles the creation, manipulation, and destruction of the
6369 % image cache (undo and redo buffers).
6370 %
6371 % The format of the XImageCache method is:
6372 %
6373 % void XImageCache(Display *display,XResourceInfo *resource_info,
6374 % XWindows *windows,const CommandType command,Image **image,
6375 % ExceptionInfo *exception)
6376 %
6377 % A description of each parameter follows:
6378 %
6379 % o display: Specifies a connection to an X server; returned from
6380 % XOpenDisplay.
6381 %
6382 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6383 %
6384 % o windows: Specifies a pointer to a XWindows structure.
6385 %
6386 % o command: Specifies a command to perform.
6387 %
6388 % o image: the image; XImageCache may transform the image and return a new
6389 % image pointer.
6390 %
6391 % o exception: return any errors or warnings in this structure.
6392 %
6393 */
XImageCache(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)6394 static void XImageCache(Display *display,XResourceInfo *resource_info,
6395 XWindows *windows,const CommandType command,Image **image,
6396 ExceptionInfo *exception)
6397 {
6398 Image
6399 *cache_image;
6400
6401 static Image
6402 *redo_image = (Image *) NULL,
6403 *undo_image = (Image *) NULL;
6404
6405 switch (command)
6406 {
6407 case FreeBuffersCommand:
6408 {
6409 /*
6410 Free memory from the undo and redo cache.
6411 */
6412 while (undo_image != (Image *) NULL)
6413 {
6414 cache_image=undo_image;
6415 undo_image=GetPreviousImageInList(undo_image);
6416 cache_image->list=DestroyImage(cache_image->list);
6417 cache_image=DestroyImage(cache_image);
6418 }
6419 undo_image=NewImageList();
6420 if (redo_image != (Image *) NULL)
6421 redo_image=DestroyImage(redo_image);
6422 redo_image=NewImageList();
6423 return;
6424 }
6425 case UndoCommand:
6426 {
6427 char
6428 image_geometry[MagickPathExtent];
6429
6430 /*
6431 Undo the last image transformation.
6432 */
6433 if (undo_image == (Image *) NULL)
6434 {
6435 (void) XBell(display,0);
6436 return;
6437 }
6438 cache_image=undo_image;
6439 undo_image=GetPreviousImageInList(undo_image);
6440 windows->image.window_changes.width=(int) cache_image->columns;
6441 windows->image.window_changes.height=(int) cache_image->rows;
6442 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
6443 windows->image.ximage->width,windows->image.ximage->height);
6444 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6445 exception);
6446 if (windows->image.crop_geometry != (char *) NULL)
6447 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6448 windows->image.crop_geometry);
6449 windows->image.crop_geometry=cache_image->geometry;
6450 if (redo_image != (Image *) NULL)
6451 redo_image=DestroyImage(redo_image);
6452 redo_image=(*image);
6453 *image=cache_image->list;
6454 cache_image=DestroyImage(cache_image);
6455 if (windows->image.orphan != MagickFalse)
6456 return;
6457 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6458 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6459 return;
6460 }
6461 case CutCommand:
6462 case PasteCommand:
6463 case ApplyCommand:
6464 case HalfSizeCommand:
6465 case OriginalSizeCommand:
6466 case DoubleSizeCommand:
6467 case ResizeCommand:
6468 case TrimCommand:
6469 case CropCommand:
6470 case ChopCommand:
6471 case FlipCommand:
6472 case FlopCommand:
6473 case RotateRightCommand:
6474 case RotateLeftCommand:
6475 case RotateCommand:
6476 case ShearCommand:
6477 case RollCommand:
6478 case NegateCommand:
6479 case ContrastStretchCommand:
6480 case SigmoidalContrastCommand:
6481 case NormalizeCommand:
6482 case EqualizeCommand:
6483 case HueCommand:
6484 case SaturationCommand:
6485 case BrightnessCommand:
6486 case GammaCommand:
6487 case SpiffCommand:
6488 case DullCommand:
6489 case GrayscaleCommand:
6490 case MapCommand:
6491 case QuantizeCommand:
6492 case DespeckleCommand:
6493 case EmbossCommand:
6494 case ReduceNoiseCommand:
6495 case AddNoiseCommand:
6496 case SharpenCommand:
6497 case BlurCommand:
6498 case ThresholdCommand:
6499 case EdgeDetectCommand:
6500 case SpreadCommand:
6501 case ShadeCommand:
6502 case RaiseCommand:
6503 case SegmentCommand:
6504 case SolarizeCommand:
6505 case SepiaToneCommand:
6506 case SwirlCommand:
6507 case ImplodeCommand:
6508 case VignetteCommand:
6509 case WaveCommand:
6510 case OilPaintCommand:
6511 case CharcoalDrawCommand:
6512 case AnnotateCommand:
6513 case AddBorderCommand:
6514 case AddFrameCommand:
6515 case CompositeCommand:
6516 case CommentCommand:
6517 case LaunchCommand:
6518 case RegionofInterestCommand:
6519 case SaveToUndoBufferCommand:
6520 case RedoCommand:
6521 {
6522 Image
6523 *previous_image;
6524
6525 ssize_t
6526 bytes;
6527
6528 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
6529 if (undo_image != (Image *) NULL)
6530 {
6531 /*
6532 Ensure the undo cache has enough memory available.
6533 */
6534 previous_image=undo_image;
6535 while (previous_image != (Image *) NULL)
6536 {
6537 bytes+=previous_image->list->columns*previous_image->list->rows*
6538 sizeof(PixelInfo);
6539 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6540 {
6541 previous_image=GetPreviousImageInList(previous_image);
6542 continue;
6543 }
6544 bytes-=previous_image->list->columns*previous_image->list->rows*
6545 sizeof(PixelInfo);
6546 if (previous_image == undo_image)
6547 undo_image=NewImageList();
6548 else
6549 previous_image->next->previous=NewImageList();
6550 break;
6551 }
6552 while (previous_image != (Image *) NULL)
6553 {
6554 /*
6555 Delete any excess memory from undo cache.
6556 */
6557 cache_image=previous_image;
6558 previous_image=GetPreviousImageInList(previous_image);
6559 cache_image->list=DestroyImage(cache_image->list);
6560 cache_image=DestroyImage(cache_image);
6561 }
6562 }
6563 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6564 break;
6565 /*
6566 Save image before transformations are applied.
6567 */
6568 cache_image=AcquireImage((ImageInfo *) NULL,exception);
6569 if (cache_image == (Image *) NULL)
6570 break;
6571 XSetCursorState(display,windows,MagickTrue);
6572 XCheckRefreshWindows(display,windows);
6573 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
6574 XSetCursorState(display,windows,MagickFalse);
6575 if (cache_image->list == (Image *) NULL)
6576 {
6577 cache_image=DestroyImage(cache_image);
6578 break;
6579 }
6580 cache_image->columns=(size_t) windows->image.ximage->width;
6581 cache_image->rows=(size_t) windows->image.ximage->height;
6582 cache_image->geometry=windows->image.crop_geometry;
6583 if (windows->image.crop_geometry != (char *) NULL)
6584 {
6585 cache_image->geometry=AcquireString((char *) NULL);
6586 (void) CopyMagickString(cache_image->geometry,
6587 windows->image.crop_geometry,MagickPathExtent);
6588 }
6589 if (undo_image == (Image *) NULL)
6590 {
6591 undo_image=cache_image;
6592 break;
6593 }
6594 undo_image->next=cache_image;
6595 undo_image->next->previous=undo_image;
6596 undo_image=undo_image->next;
6597 break;
6598 }
6599 default:
6600 break;
6601 }
6602 if (command == RedoCommand)
6603 {
6604 /*
6605 Redo the last image transformation.
6606 */
6607 if (redo_image == (Image *) NULL)
6608 {
6609 (void) XBell(display,0);
6610 return;
6611 }
6612 windows->image.window_changes.width=(int) redo_image->columns;
6613 windows->image.window_changes.height=(int) redo_image->rows;
6614 if (windows->image.crop_geometry != (char *) NULL)
6615 windows->image.crop_geometry=(char *)
6616 RelinquishMagickMemory(windows->image.crop_geometry);
6617 windows->image.crop_geometry=redo_image->geometry;
6618 *image=DestroyImage(*image);
6619 *image=redo_image;
6620 redo_image=NewImageList();
6621 if (windows->image.orphan != MagickFalse)
6622 return;
6623 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6624 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6625 return;
6626 }
6627 if (command != InfoCommand)
6628 return;
6629 /*
6630 Display image info.
6631 */
6632 XSetCursorState(display,windows,MagickTrue);
6633 XCheckRefreshWindows(display,windows);
6634 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
6635 XSetCursorState(display,windows,MagickFalse);
6636 }
6637
6638 /*
6639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6640 % %
6641 % %
6642 % %
6643 + X I m a g e W i n d o w C o m m a n d %
6644 % %
6645 % %
6646 % %
6647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6648 %
6649 % XImageWindowCommand() makes a transform to the image or Image window as
6650 % specified by a user menu button or keyboard command.
6651 %
6652 % The format of the XImageWindowCommand method is:
6653 %
6654 % CommandType XImageWindowCommand(Display *display,
6655 % XResourceInfo *resource_info,XWindows *windows,
6656 % const MagickStatusType state,KeySym key_symbol,Image **image,
6657 % ExceptionInfo *exception)
6658 %
6659 % A description of each parameter follows:
6660 %
6661 % o nexus: Method XImageWindowCommand returns an image when the
6662 % user chooses 'Open Image' from the command menu. Otherwise a null
6663 % image is returned.
6664 %
6665 % o display: Specifies a connection to an X server; returned from
6666 % XOpenDisplay.
6667 %
6668 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6669 %
6670 % o windows: Specifies a pointer to a XWindows structure.
6671 %
6672 % o state: key mask.
6673 %
6674 % o key_symbol: Specifies a command to perform.
6675 %
6676 % o image: the image; XImageWIndowCommand may transform the image and
6677 % return a new image pointer.
6678 %
6679 % o exception: return any errors or warnings in this structure.
6680 %
6681 */
XImageWindowCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickStatusType state,KeySym key_symbol,Image ** image,ExceptionInfo * exception)6682 static CommandType XImageWindowCommand(Display *display,
6683 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6684 KeySym key_symbol,Image **image,ExceptionInfo *exception)
6685 {
6686 static char
6687 delta[MagickPathExtent] = "";
6688
6689 static const char
6690 Digits[] = "01234567890";
6691
6692 static KeySym
6693 last_symbol = XK_0;
6694
6695 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6696 {
6697 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6698 {
6699 *delta='\0';
6700 resource_info->quantum=1;
6701 }
6702 last_symbol=key_symbol;
6703 delta[strlen(delta)+1]='\0';
6704 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6705 resource_info->quantum=StringToLong(delta);
6706 return(NullCommand);
6707 }
6708 last_symbol=key_symbol;
6709 if (resource_info->immutable)
6710 {
6711 /*
6712 Virtual image window has a restricted command set.
6713 */
6714 switch (key_symbol)
6715 {
6716 case XK_question:
6717 return(InfoCommand);
6718 case XK_p:
6719 case XK_Print:
6720 return(PrintCommand);
6721 case XK_space:
6722 return(NextCommand);
6723 case XK_q:
6724 case XK_Escape:
6725 return(QuitCommand);
6726 default:
6727 break;
6728 }
6729 return(NullCommand);
6730 }
6731 switch ((int) key_symbol)
6732 {
6733 case XK_o:
6734 {
6735 if ((state & ControlMask) == 0)
6736 break;
6737 return(OpenCommand);
6738 }
6739 case XK_space:
6740 return(NextCommand);
6741 case XK_BackSpace:
6742 return(FormerCommand);
6743 case XK_s:
6744 {
6745 if ((state & Mod1Mask) != 0)
6746 return(SwirlCommand);
6747 if ((state & ControlMask) == 0)
6748 return(ShearCommand);
6749 return(SaveCommand);
6750 }
6751 case XK_p:
6752 case XK_Print:
6753 {
6754 if ((state & Mod1Mask) != 0)
6755 return(OilPaintCommand);
6756 if ((state & Mod4Mask) != 0)
6757 return(ColorCommand);
6758 if ((state & ControlMask) == 0)
6759 return(NullCommand);
6760 return(PrintCommand);
6761 }
6762 case XK_d:
6763 {
6764 if ((state & Mod4Mask) != 0)
6765 return(DrawCommand);
6766 if ((state & ControlMask) == 0)
6767 return(NullCommand);
6768 return(DeleteCommand);
6769 }
6770 case XK_Select:
6771 {
6772 if ((state & ControlMask) == 0)
6773 return(NullCommand);
6774 return(SelectCommand);
6775 }
6776 case XK_n:
6777 {
6778 if ((state & ControlMask) == 0)
6779 return(NullCommand);
6780 return(NewCommand);
6781 }
6782 case XK_q:
6783 case XK_Escape:
6784 return(QuitCommand);
6785 case XK_z:
6786 case XK_Undo:
6787 {
6788 if ((state & ControlMask) == 0)
6789 return(NullCommand);
6790 return(UndoCommand);
6791 }
6792 case XK_r:
6793 case XK_Redo:
6794 {
6795 if ((state & ControlMask) == 0)
6796 return(RollCommand);
6797 return(RedoCommand);
6798 }
6799 case XK_x:
6800 {
6801 if ((state & ControlMask) == 0)
6802 return(NullCommand);
6803 return(CutCommand);
6804 }
6805 case XK_c:
6806 {
6807 if ((state & Mod1Mask) != 0)
6808 return(CharcoalDrawCommand);
6809 if ((state & ControlMask) == 0)
6810 return(CropCommand);
6811 return(CopyCommand);
6812 }
6813 case XK_v:
6814 case XK_Insert:
6815 {
6816 if ((state & Mod4Mask) != 0)
6817 return(CompositeCommand);
6818 if ((state & ControlMask) == 0)
6819 return(FlipCommand);
6820 return(PasteCommand);
6821 }
6822 case XK_less:
6823 return(HalfSizeCommand);
6824 case XK_minus:
6825 return(OriginalSizeCommand);
6826 case XK_greater:
6827 return(DoubleSizeCommand);
6828 case XK_percent:
6829 return(ResizeCommand);
6830 case XK_at:
6831 return(RefreshCommand);
6832 case XK_bracketleft:
6833 return(ChopCommand);
6834 case XK_h:
6835 return(FlopCommand);
6836 case XK_slash:
6837 return(RotateRightCommand);
6838 case XK_backslash:
6839 return(RotateLeftCommand);
6840 case XK_asterisk:
6841 return(RotateCommand);
6842 case XK_t:
6843 return(TrimCommand);
6844 case XK_H:
6845 return(HueCommand);
6846 case XK_S:
6847 return(SaturationCommand);
6848 case XK_L:
6849 return(BrightnessCommand);
6850 case XK_G:
6851 return(GammaCommand);
6852 case XK_C:
6853 return(SpiffCommand);
6854 case XK_Z:
6855 return(DullCommand);
6856 case XK_N:
6857 return(NormalizeCommand);
6858 case XK_equal:
6859 return(EqualizeCommand);
6860 case XK_asciitilde:
6861 return(NegateCommand);
6862 case XK_period:
6863 return(GrayscaleCommand);
6864 case XK_numbersign:
6865 return(QuantizeCommand);
6866 case XK_F2:
6867 return(DespeckleCommand);
6868 case XK_F3:
6869 return(EmbossCommand);
6870 case XK_F4:
6871 return(ReduceNoiseCommand);
6872 case XK_F5:
6873 return(AddNoiseCommand);
6874 case XK_F6:
6875 return(SharpenCommand);
6876 case XK_F7:
6877 return(BlurCommand);
6878 case XK_F8:
6879 return(ThresholdCommand);
6880 case XK_F9:
6881 return(EdgeDetectCommand);
6882 case XK_F10:
6883 return(SpreadCommand);
6884 case XK_F11:
6885 return(ShadeCommand);
6886 case XK_F12:
6887 return(RaiseCommand);
6888 case XK_F13:
6889 return(SegmentCommand);
6890 case XK_i:
6891 {
6892 if ((state & Mod1Mask) == 0)
6893 return(NullCommand);
6894 return(ImplodeCommand);
6895 }
6896 case XK_w:
6897 {
6898 if ((state & Mod1Mask) == 0)
6899 return(NullCommand);
6900 return(WaveCommand);
6901 }
6902 case XK_m:
6903 {
6904 if ((state & Mod4Mask) == 0)
6905 return(NullCommand);
6906 return(MatteCommand);
6907 }
6908 case XK_b:
6909 {
6910 if ((state & Mod4Mask) == 0)
6911 return(NullCommand);
6912 return(AddBorderCommand);
6913 }
6914 case XK_f:
6915 {
6916 if ((state & Mod4Mask) == 0)
6917 return(NullCommand);
6918 return(AddFrameCommand);
6919 }
6920 case XK_exclam:
6921 {
6922 if ((state & Mod4Mask) == 0)
6923 return(NullCommand);
6924 return(CommentCommand);
6925 }
6926 case XK_a:
6927 {
6928 if ((state & Mod1Mask) != 0)
6929 return(ApplyCommand);
6930 if ((state & Mod4Mask) != 0)
6931 return(AnnotateCommand);
6932 if ((state & ControlMask) == 0)
6933 return(NullCommand);
6934 return(RegionofInterestCommand);
6935 }
6936 case XK_question:
6937 return(InfoCommand);
6938 case XK_plus:
6939 return(ZoomCommand);
6940 case XK_P:
6941 {
6942 if ((state & ShiftMask) == 0)
6943 return(NullCommand);
6944 return(ShowPreviewCommand);
6945 }
6946 case XK_Execute:
6947 return(LaunchCommand);
6948 case XK_F1:
6949 return(HelpCommand);
6950 case XK_Find:
6951 return(BrowseDocumentationCommand);
6952 case XK_Menu:
6953 {
6954 (void) XMapRaised(display,windows->command.id);
6955 return(NullCommand);
6956 }
6957 case XK_Next:
6958 case XK_Prior:
6959 case XK_Home:
6960 case XK_KP_Home:
6961 {
6962 XTranslateImage(display,windows,*image,key_symbol);
6963 return(NullCommand);
6964 }
6965 case XK_Up:
6966 case XK_KP_Up:
6967 case XK_Down:
6968 case XK_KP_Down:
6969 case XK_Left:
6970 case XK_KP_Left:
6971 case XK_Right:
6972 case XK_KP_Right:
6973 {
6974 if ((state & Mod1Mask) != 0)
6975 {
6976 RectangleInfo
6977 crop_info;
6978
6979 /*
6980 Trim one pixel from edge of image.
6981 */
6982 crop_info.x=0;
6983 crop_info.y=0;
6984 crop_info.width=(size_t) windows->image.ximage->width;
6985 crop_info.height=(size_t) windows->image.ximage->height;
6986 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6987 {
6988 if (resource_info->quantum >= (int) crop_info.height)
6989 resource_info->quantum=(int) crop_info.height-1;
6990 crop_info.height-=resource_info->quantum;
6991 }
6992 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6993 {
6994 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6995 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6996 crop_info.y+=resource_info->quantum;
6997 crop_info.height-=resource_info->quantum;
6998 }
6999 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7000 {
7001 if (resource_info->quantum >= (int) crop_info.width)
7002 resource_info->quantum=(int) crop_info.width-1;
7003 crop_info.width-=resource_info->quantum;
7004 }
7005 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7006 {
7007 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7008 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7009 crop_info.x+=resource_info->quantum;
7010 crop_info.width-=resource_info->quantum;
7011 }
7012 if ((int) (windows->image.x+windows->image.width) >
7013 (int) crop_info.width)
7014 windows->image.x=(int) (crop_info.width-windows->image.width);
7015 if ((int) (windows->image.y+windows->image.height) >
7016 (int) crop_info.height)
7017 windows->image.y=(int) (crop_info.height-windows->image.height);
7018 XSetCropGeometry(display,windows,&crop_info,*image);
7019 windows->image.window_changes.width=(int) crop_info.width;
7020 windows->image.window_changes.height=(int) crop_info.height;
7021 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7022 (void) XConfigureImage(display,resource_info,windows,*image,
7023 exception);
7024 return(NullCommand);
7025 }
7026 XTranslateImage(display,windows,*image,key_symbol);
7027 return(NullCommand);
7028 }
7029 default:
7030 return(NullCommand);
7031 }
7032 return(NullCommand);
7033 }
7034
7035 /*
7036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7037 % %
7038 % %
7039 % %
7040 + X M a g i c k C o m m a n d %
7041 % %
7042 % %
7043 % %
7044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7045 %
7046 % XMagickCommand() makes a transform to the image or Image window as
7047 % specified by a user menu button or keyboard command.
7048 %
7049 % The format of the XMagickCommand method is:
7050 %
7051 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7052 % XWindows *windows,const CommandType command,Image **image,
7053 % ExceptionInfo *exception)
7054 %
7055 % A description of each parameter follows:
7056 %
7057 % o display: Specifies a connection to an X server; returned from
7058 % XOpenDisplay.
7059 %
7060 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7061 %
7062 % o windows: Specifies a pointer to a XWindows structure.
7063 %
7064 % o command: Specifies a command to perform.
7065 %
7066 % o image: the image; XMagickCommand may transform the image and return a
7067 % new image pointer.
7068 %
7069 % o exception: return any errors or warnings in this structure.
7070 %
7071 */
XMagickCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)7072 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7073 XWindows *windows,const CommandType command,Image **image,
7074 ExceptionInfo *exception)
7075 {
7076 char
7077 filename[MagickPathExtent],
7078 geometry[MagickPathExtent],
7079 modulate_factors[MagickPathExtent];
7080
7081 GeometryInfo
7082 geometry_info;
7083
7084 Image
7085 *nexus;
7086
7087 ImageInfo
7088 *image_info;
7089
7090 int
7091 x,
7092 y;
7093
7094 MagickStatusType
7095 flags,
7096 status;
7097
7098 QuantizeInfo
7099 quantize_info;
7100
7101 RectangleInfo
7102 page_geometry;
7103
7104 int
7105 i;
7106
7107 static char
7108 color[MagickPathExtent] = "gray";
7109
7110 unsigned int
7111 height,
7112 width;
7113
7114 /*
7115 Process user command.
7116 */
7117 XCheckRefreshWindows(display,windows);
7118 XImageCache(display,resource_info,windows,command,image,exception);
7119 nexus=NewImageList();
7120 windows->image.window_changes.width=windows->image.ximage->width;
7121 windows->image.window_changes.height=windows->image.ximage->height;
7122 image_info=CloneImageInfo(resource_info->image_info);
7123 SetGeometryInfo(&geometry_info);
7124 GetQuantizeInfo(&quantize_info);
7125 switch (command)
7126 {
7127 case OpenCommand:
7128 {
7129 /*
7130 Load image.
7131 */
7132 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7133 break;
7134 }
7135 case NextCommand:
7136 {
7137 /*
7138 Display next image.
7139 */
7140 for (i=0; i < resource_info->quantum; i++)
7141 XClientMessage(display,windows->image.id,windows->im_protocols,
7142 windows->im_next_image,CurrentTime);
7143 break;
7144 }
7145 case FormerCommand:
7146 {
7147 /*
7148 Display former image.
7149 */
7150 for (i=0; i < resource_info->quantum; i++)
7151 XClientMessage(display,windows->image.id,windows->im_protocols,
7152 windows->im_former_image,CurrentTime);
7153 break;
7154 }
7155 case SelectCommand:
7156 {
7157 int
7158 status;
7159
7160 /*
7161 Select image.
7162 */
7163 if (*resource_info->home_directory == '\0')
7164 (void) CopyMagickString(resource_info->home_directory,".",
7165 MagickPathExtent);
7166 status=chdir(resource_info->home_directory);
7167 if (status == -1)
7168 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7169 "UnableToOpenFile","%s",resource_info->home_directory);
7170 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7171 break;
7172 }
7173 case SaveCommand:
7174 {
7175 /*
7176 Save image.
7177 */
7178 status=XSaveImage(display,resource_info,windows,*image,exception);
7179 if (status == MagickFalse)
7180 {
7181 char
7182 message[MagickPathExtent];
7183
7184 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7185 exception->reason != (char *) NULL ? exception->reason : "",
7186 exception->description != (char *) NULL ? exception->description :
7187 "");
7188 XNoticeWidget(display,windows,"Unable to save file:",message);
7189 break;
7190 }
7191 break;
7192 }
7193 case PrintCommand:
7194 {
7195 /*
7196 Print image.
7197 */
7198 status=XPrintImage(display,resource_info,windows,*image,exception);
7199 if (status == MagickFalse)
7200 {
7201 char
7202 message[MagickPathExtent];
7203
7204 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7205 exception->reason != (char *) NULL ? exception->reason : "",
7206 exception->description != (char *) NULL ? exception->description :
7207 "");
7208 XNoticeWidget(display,windows,"Unable to print file:",message);
7209 break;
7210 }
7211 break;
7212 }
7213 case DeleteCommand:
7214 {
7215 static char
7216 filename[MagickPathExtent] = "\0";
7217
7218 /*
7219 Delete image file.
7220 */
7221 XFileBrowserWidget(display,windows,"Delete",filename);
7222 if (*filename == '\0')
7223 break;
7224 status=ShredFile(filename);
7225 if (status != MagickFalse)
7226 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7227 break;
7228 }
7229 case NewCommand:
7230 {
7231 int
7232 status;
7233
7234 static char
7235 color[MagickPathExtent] = "gray",
7236 geometry[MagickPathExtent] = "640x480";
7237
7238 static const char
7239 *format = "gradient";
7240
7241 /*
7242 Query user for canvas geometry.
7243 */
7244 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7245 geometry);
7246 if (*geometry == '\0')
7247 break;
7248 if (status == 0)
7249 format="xc";
7250 XColorBrowserWidget(display,windows,"Select",color);
7251 if (*color == '\0')
7252 break;
7253 /*
7254 Create canvas.
7255 */
7256 (void) FormatLocaleString(image_info->filename,MagickPathExtent,
7257 "%s:%s",format,color);
7258 (void) CloneString(&image_info->size,geometry);
7259 nexus=ReadImage(image_info,exception);
7260 CatchException(exception);
7261 XClientMessage(display,windows->image.id,windows->im_protocols,
7262 windows->im_next_image,CurrentTime);
7263 break;
7264 }
7265 case VisualDirectoryCommand:
7266 {
7267 /*
7268 Visual Image directory.
7269 */
7270 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
7271 break;
7272 }
7273 case QuitCommand:
7274 {
7275 /*
7276 exit program.
7277 */
7278 if (resource_info->confirm_exit == MagickFalse)
7279 XClientMessage(display,windows->image.id,windows->im_protocols,
7280 windows->im_exit,CurrentTime);
7281 else
7282 {
7283 int
7284 status;
7285
7286 /*
7287 Confirm program exit.
7288 */
7289 status=XConfirmWidget(display,windows,"Do you really want to exit",
7290 resource_info->client_name);
7291 if (status > 0)
7292 XClientMessage(display,windows->image.id,windows->im_protocols,
7293 windows->im_exit,CurrentTime);
7294 }
7295 break;
7296 }
7297 case CutCommand:
7298 {
7299 /*
7300 Cut image.
7301 */
7302 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
7303 break;
7304 }
7305 case CopyCommand:
7306 {
7307 /*
7308 Copy image.
7309 */
7310 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7311 exception);
7312 break;
7313 }
7314 case PasteCommand:
7315 {
7316 /*
7317 Paste image.
7318 */
7319 status=XPasteImage(display,resource_info,windows,*image,exception);
7320 if (status == MagickFalse)
7321 {
7322 XNoticeWidget(display,windows,"Unable to paste X image",
7323 (*image)->filename);
7324 break;
7325 }
7326 break;
7327 }
7328 case HalfSizeCommand:
7329 {
7330 /*
7331 Half image size.
7332 */
7333 windows->image.window_changes.width=windows->image.ximage->width/2;
7334 windows->image.window_changes.height=windows->image.ximage->height/2;
7335 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7336 break;
7337 }
7338 case OriginalSizeCommand:
7339 {
7340 /*
7341 Original image size.
7342 */
7343 windows->image.window_changes.width=(int) (*image)->columns;
7344 windows->image.window_changes.height=(int) (*image)->rows;
7345 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7346 break;
7347 }
7348 case DoubleSizeCommand:
7349 {
7350 /*
7351 Double the image size.
7352 */
7353 windows->image.window_changes.width=windows->image.ximage->width << 1;
7354 windows->image.window_changes.height=windows->image.ximage->height << 1;
7355 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7356 break;
7357 }
7358 case ResizeCommand:
7359 {
7360 int
7361 status;
7362
7363 size_t
7364 height,
7365 width;
7366
7367 ssize_t
7368 x,
7369 y;
7370
7371 /*
7372 Resize image.
7373 */
7374 width=(size_t) windows->image.ximage->width;
7375 height=(size_t) windows->image.ximage->height;
7376 x=0;
7377 y=0;
7378 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0",
7379 (double) width,(double) height);
7380 status=XDialogWidget(display,windows,"Resize",
7381 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7382 if (*geometry == '\0')
7383 break;
7384 if (status == 0)
7385 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent);
7386 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7387 windows->image.window_changes.width=(int) width;
7388 windows->image.window_changes.height=(int) height;
7389 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7390 break;
7391 }
7392 case ApplyCommand:
7393 {
7394 char
7395 image_geometry[MagickPathExtent];
7396
7397 if ((windows->image.crop_geometry == (char *) NULL) &&
7398 ((int) (*image)->columns == windows->image.ximage->width) &&
7399 ((int) (*image)->rows == windows->image.ximage->height))
7400 break;
7401 /*
7402 Apply size transforms to image.
7403 */
7404 XSetCursorState(display,windows,MagickTrue);
7405 XCheckRefreshWindows(display,windows);
7406 /*
7407 Crop and/or scale displayed image.
7408 */
7409 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
7410 windows->image.ximage->width,windows->image.ximage->height);
7411 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7412 exception);
7413 if (windows->image.crop_geometry != (char *) NULL)
7414 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7415 windows->image.crop_geometry);
7416 windows->image.x=0;
7417 windows->image.y=0;
7418 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7420 break;
7421 }
7422 case RefreshCommand:
7423 {
7424 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7425 break;
7426 }
7427 case RestoreCommand:
7428 {
7429 /*
7430 Restore Image window to its original size.
7431 */
7432 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7433 (windows->image.height == (unsigned int) (*image)->rows) &&
7434 (windows->image.crop_geometry == (char *) NULL))
7435 {
7436 (void) XBell(display,0);
7437 break;
7438 }
7439 windows->image.window_changes.width=(int) (*image)->columns;
7440 windows->image.window_changes.height=(int) (*image)->rows;
7441 if (windows->image.crop_geometry != (char *) NULL)
7442 {
7443 windows->image.crop_geometry=(char *)
7444 RelinquishMagickMemory(windows->image.crop_geometry);
7445 windows->image.crop_geometry=(char *) NULL;
7446 windows->image.x=0;
7447 windows->image.y=0;
7448 }
7449 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7450 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7451 break;
7452 }
7453 case CropCommand:
7454 {
7455 /*
7456 Crop image.
7457 */
7458 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7459 exception);
7460 break;
7461 }
7462 case ChopCommand:
7463 {
7464 /*
7465 Chop image.
7466 */
7467 status=XChopImage(display,resource_info,windows,image,exception);
7468 if (status == MagickFalse)
7469 {
7470 XNoticeWidget(display,windows,"Unable to cut X image",
7471 (*image)->filename);
7472 break;
7473 }
7474 break;
7475 }
7476 case FlopCommand:
7477 {
7478 Image
7479 *flop_image;
7480
7481 /*
7482 Flop image scanlines.
7483 */
7484 XSetCursorState(display,windows,MagickTrue);
7485 XCheckRefreshWindows(display,windows);
7486 flop_image=FlopImage(*image,exception);
7487 if (flop_image != (Image *) NULL)
7488 {
7489 *image=DestroyImage(*image);
7490 *image=flop_image;
7491 }
7492 CatchException(exception);
7493 XSetCursorState(display,windows,MagickFalse);
7494 if (windows->image.crop_geometry != (char *) NULL)
7495 {
7496 /*
7497 Flop crop geometry.
7498 */
7499 width=(unsigned int) (*image)->columns;
7500 height=(unsigned int) (*image)->rows;
7501 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7502 &width,&height);
7503 (void) FormatLocaleString(windows->image.crop_geometry,
7504 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) (*image)->columns-
7505 (int) width-x,y);
7506 }
7507 if (windows->image.orphan != MagickFalse)
7508 break;
7509 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7510 break;
7511 }
7512 case FlipCommand:
7513 {
7514 Image
7515 *flip_image;
7516
7517 /*
7518 Flip image scanlines.
7519 */
7520 XSetCursorState(display,windows,MagickTrue);
7521 XCheckRefreshWindows(display,windows);
7522 flip_image=FlipImage(*image,exception);
7523 if (flip_image != (Image *) NULL)
7524 {
7525 *image=DestroyImage(*image);
7526 *image=flip_image;
7527 }
7528 CatchException(exception);
7529 XSetCursorState(display,windows,MagickFalse);
7530 if (windows->image.crop_geometry != (char *) NULL)
7531 {
7532 /*
7533 Flip crop geometry.
7534 */
7535 width=(unsigned int) (*image)->columns;
7536 height=(unsigned int) (*image)->rows;
7537 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7538 &width,&height);
7539 (void) FormatLocaleString(windows->image.crop_geometry,
7540 MagickPathExtent,"%ux%u%+d%+d",width,height,x,(int) (*image)->rows-
7541 (int) height-y);
7542 }
7543 if (windows->image.orphan != MagickFalse)
7544 break;
7545 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7546 break;
7547 }
7548 case RotateRightCommand:
7549 {
7550 /*
7551 Rotate image 90 degrees clockwise.
7552 */
7553 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
7554 if (status == MagickFalse)
7555 {
7556 XNoticeWidget(display,windows,"Unable to rotate X image",
7557 (*image)->filename);
7558 break;
7559 }
7560 break;
7561 }
7562 case RotateLeftCommand:
7563 {
7564 /*
7565 Rotate image 90 degrees counter-clockwise.
7566 */
7567 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
7568 if (status == MagickFalse)
7569 {
7570 XNoticeWidget(display,windows,"Unable to rotate X image",
7571 (*image)->filename);
7572 break;
7573 }
7574 break;
7575 }
7576 case RotateCommand:
7577 {
7578 /*
7579 Rotate image.
7580 */
7581 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
7582 if (status == MagickFalse)
7583 {
7584 XNoticeWidget(display,windows,"Unable to rotate X image",
7585 (*image)->filename);
7586 break;
7587 }
7588 break;
7589 }
7590 case ShearCommand:
7591 {
7592 Image
7593 *shear_image;
7594
7595 static char
7596 geometry[MagickPathExtent] = "45.0x45.0";
7597
7598 /*
7599 Query user for shear color and geometry.
7600 */
7601 XColorBrowserWidget(display,windows,"Select",color);
7602 if (*color == '\0')
7603 break;
7604 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7605 geometry);
7606 if (*geometry == '\0')
7607 break;
7608 /*
7609 Shear image.
7610 */
7611 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7612 exception);
7613 XSetCursorState(display,windows,MagickTrue);
7614 XCheckRefreshWindows(display,windows);
7615 (void) QueryColorCompliance(color,AllCompliance,
7616 &(*image)->background_color,exception);
7617 flags=ParseGeometry(geometry,&geometry_info);
7618 if ((flags & SigmaValue) == 0)
7619 geometry_info.sigma=geometry_info.rho;
7620 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7621 exception);
7622 if (shear_image != (Image *) NULL)
7623 {
7624 *image=DestroyImage(*image);
7625 *image=shear_image;
7626 }
7627 CatchException(exception);
7628 XSetCursorState(display,windows,MagickFalse);
7629 if (windows->image.orphan != MagickFalse)
7630 break;
7631 windows->image.window_changes.width=(int) (*image)->columns;
7632 windows->image.window_changes.height=(int) (*image)->rows;
7633 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7634 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7635 break;
7636 }
7637 case RollCommand:
7638 {
7639 Image
7640 *roll_image;
7641
7642 static char
7643 geometry[MagickPathExtent] = "+2+2";
7644
7645 /*
7646 Query user for the roll geometry.
7647 */
7648 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7649 geometry);
7650 if (*geometry == '\0')
7651 break;
7652 /*
7653 Roll image.
7654 */
7655 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7656 exception);
7657 XSetCursorState(display,windows,MagickTrue);
7658 XCheckRefreshWindows(display,windows);
7659 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7660 exception);
7661 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7662 exception);
7663 if (roll_image != (Image *) NULL)
7664 {
7665 *image=DestroyImage(*image);
7666 *image=roll_image;
7667 }
7668 CatchException(exception);
7669 XSetCursorState(display,windows,MagickFalse);
7670 if (windows->image.orphan != MagickFalse)
7671 break;
7672 windows->image.window_changes.width=(int) (*image)->columns;
7673 windows->image.window_changes.height=(int) (*image)->rows;
7674 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7675 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7676 break;
7677 }
7678 case TrimCommand:
7679 {
7680 static char
7681 fuzz[MagickPathExtent];
7682
7683 /*
7684 Query user for the fuzz factor.
7685 */
7686 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0*
7687 (*image)->fuzz/(QuantumRange+1.0));
7688 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7689 if (*fuzz == '\0')
7690 break;
7691 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7692 /*
7693 Trim image.
7694 */
7695 status=XTrimImage(display,resource_info,windows,*image,exception);
7696 if (status == MagickFalse)
7697 {
7698 XNoticeWidget(display,windows,"Unable to trim X image",
7699 (*image)->filename);
7700 break;
7701 }
7702 break;
7703 }
7704 case HueCommand:
7705 {
7706 static char
7707 hue_percent[MagickPathExtent] = "110";
7708
7709 /*
7710 Query user for percent hue change.
7711 */
7712 (void) XDialogWidget(display,windows,"Apply",
7713 "Enter percent change in image hue (0-200):",hue_percent);
7714 if (*hue_percent == '\0')
7715 break;
7716 /*
7717 Vary the image hue.
7718 */
7719 XSetCursorState(display,windows,MagickTrue);
7720 XCheckRefreshWindows(display,windows);
7721 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent);
7722 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7723 MagickPathExtent);
7724 (void) ModulateImage(*image,modulate_factors,exception);
7725 XSetCursorState(display,windows,MagickFalse);
7726 if (windows->image.orphan != MagickFalse)
7727 break;
7728 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7729 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7730 break;
7731 }
7732 case SaturationCommand:
7733 {
7734 static char
7735 saturation_percent[MagickPathExtent] = "110";
7736
7737 /*
7738 Query user for percent saturation change.
7739 */
7740 (void) XDialogWidget(display,windows,"Apply",
7741 "Enter percent change in color saturation (0-200):",saturation_percent);
7742 if (*saturation_percent == '\0')
7743 break;
7744 /*
7745 Vary color saturation.
7746 */
7747 XSetCursorState(display,windows,MagickTrue);
7748 XCheckRefreshWindows(display,windows);
7749 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent);
7750 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7751 MagickPathExtent);
7752 (void) ModulateImage(*image,modulate_factors,exception);
7753 XSetCursorState(display,windows,MagickFalse);
7754 if (windows->image.orphan != MagickFalse)
7755 break;
7756 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7757 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7758 break;
7759 }
7760 case BrightnessCommand:
7761 {
7762 static char
7763 brightness_percent[MagickPathExtent] = "110";
7764
7765 /*
7766 Query user for percent brightness change.
7767 */
7768 (void) XDialogWidget(display,windows,"Apply",
7769 "Enter percent change in color brightness (0-200):",brightness_percent);
7770 if (*brightness_percent == '\0')
7771 break;
7772 /*
7773 Vary the color brightness.
7774 */
7775 XSetCursorState(display,windows,MagickTrue);
7776 XCheckRefreshWindows(display,windows);
7777 (void) CopyMagickString(modulate_factors,brightness_percent,
7778 MagickPathExtent);
7779 (void) ModulateImage(*image,modulate_factors,exception);
7780 XSetCursorState(display,windows,MagickFalse);
7781 if (windows->image.orphan != MagickFalse)
7782 break;
7783 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7784 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7785 break;
7786 }
7787 case GammaCommand:
7788 {
7789 static char
7790 factor[MagickPathExtent] = "1.6";
7791
7792 /*
7793 Query user for gamma value.
7794 */
7795 (void) XDialogWidget(display,windows,"Gamma",
7796 "Enter gamma value (e.g. 1.2):",factor);
7797 if (*factor == '\0')
7798 break;
7799 /*
7800 Gamma correct image.
7801 */
7802 XSetCursorState(display,windows,MagickTrue);
7803 XCheckRefreshWindows(display,windows);
7804 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception);
7805 XSetCursorState(display,windows,MagickFalse);
7806 if (windows->image.orphan != MagickFalse)
7807 break;
7808 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7809 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7810 break;
7811 }
7812 case SpiffCommand:
7813 {
7814 /*
7815 Sharpen the image contrast.
7816 */
7817 XSetCursorState(display,windows,MagickTrue);
7818 XCheckRefreshWindows(display,windows);
7819 (void) ContrastImage(*image,MagickTrue,exception);
7820 XSetCursorState(display,windows,MagickFalse);
7821 if (windows->image.orphan != MagickFalse)
7822 break;
7823 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7824 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7825 break;
7826 }
7827 case DullCommand:
7828 {
7829 /*
7830 Dull the image contrast.
7831 */
7832 XSetCursorState(display,windows,MagickTrue);
7833 XCheckRefreshWindows(display,windows);
7834 (void) ContrastImage(*image,MagickFalse,exception);
7835 XSetCursorState(display,windows,MagickFalse);
7836 if (windows->image.orphan != MagickFalse)
7837 break;
7838 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7839 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7840 break;
7841 }
7842 case ContrastStretchCommand:
7843 {
7844 double
7845 black_point,
7846 white_point;
7847
7848 static char
7849 levels[MagickPathExtent] = "1%";
7850
7851 /*
7852 Query user for gamma value.
7853 */
7854 (void) XDialogWidget(display,windows,"Contrast Stretch",
7855 "Enter black and white points:",levels);
7856 if (*levels == '\0')
7857 break;
7858 /*
7859 Contrast stretch image.
7860 */
7861 XSetCursorState(display,windows,MagickTrue);
7862 XCheckRefreshWindows(display,windows);
7863 flags=ParseGeometry(levels,&geometry_info);
7864 black_point=geometry_info.rho;
7865 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7866 if ((flags & PercentValue) != 0)
7867 {
7868 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7869 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7870 }
7871 white_point=(double) (*image)->columns*(*image)->rows-white_point;
7872 (void) ContrastStretchImage(*image,black_point,white_point,
7873 exception);
7874 XSetCursorState(display,windows,MagickFalse);
7875 if (windows->image.orphan != MagickFalse)
7876 break;
7877 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7878 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7879 break;
7880 }
7881 case SigmoidalContrastCommand:
7882 {
7883 GeometryInfo
7884 geometry_info;
7885
7886 MagickStatusType
7887 flags;
7888
7889 static char
7890 levels[MagickPathExtent] = "3x50%";
7891
7892 /*
7893 Query user for gamma value.
7894 */
7895 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7896 "Enter contrast and midpoint:",levels);
7897 if (*levels == '\0')
7898 break;
7899 /*
7900 Contrast stretch image.
7901 */
7902 XSetCursorState(display,windows,MagickTrue);
7903 XCheckRefreshWindows(display,windows);
7904 flags=ParseGeometry(levels,&geometry_info);
7905 if ((flags & SigmaValue) == 0)
7906 geometry_info.sigma=1.0*QuantumRange/2.0;
7907 if ((flags & PercentValue) != 0)
7908 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7909 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7910 geometry_info.sigma,exception);
7911 XSetCursorState(display,windows,MagickFalse);
7912 if (windows->image.orphan != MagickFalse)
7913 break;
7914 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7915 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7916 break;
7917 }
7918 case NormalizeCommand:
7919 {
7920 /*
7921 Perform histogram normalization on the image.
7922 */
7923 XSetCursorState(display,windows,MagickTrue);
7924 XCheckRefreshWindows(display,windows);
7925 (void) NormalizeImage(*image,exception);
7926 XSetCursorState(display,windows,MagickFalse);
7927 if (windows->image.orphan != MagickFalse)
7928 break;
7929 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7930 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7931 break;
7932 }
7933 case EqualizeCommand:
7934 {
7935 /*
7936 Perform histogram equalization on the image.
7937 */
7938 XSetCursorState(display,windows,MagickTrue);
7939 XCheckRefreshWindows(display,windows);
7940 (void) EqualizeImage(*image,exception);
7941 XSetCursorState(display,windows,MagickFalse);
7942 if (windows->image.orphan != MagickFalse)
7943 break;
7944 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7945 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7946 break;
7947 }
7948 case NegateCommand:
7949 {
7950 /*
7951 Negate colors in image.
7952 */
7953 XSetCursorState(display,windows,MagickTrue);
7954 XCheckRefreshWindows(display,windows);
7955 (void) NegateImage(*image,MagickFalse,exception);
7956 XSetCursorState(display,windows,MagickFalse);
7957 if (windows->image.orphan != MagickFalse)
7958 break;
7959 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7960 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7961 break;
7962 }
7963 case GrayscaleCommand:
7964 {
7965 /*
7966 Convert image to grayscale.
7967 */
7968 XSetCursorState(display,windows,MagickTrue);
7969 XCheckRefreshWindows(display,windows);
7970 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ?
7971 GrayscaleType : GrayscaleAlphaType,exception);
7972 XSetCursorState(display,windows,MagickFalse);
7973 if (windows->image.orphan != MagickFalse)
7974 break;
7975 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7976 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7977 break;
7978 }
7979 case MapCommand:
7980 {
7981 Image
7982 *affinity_image;
7983
7984 static char
7985 filename[MagickPathExtent] = "\0";
7986
7987 /*
7988 Request image file name from user.
7989 */
7990 XFileBrowserWidget(display,windows,"Map",filename);
7991 if (*filename == '\0')
7992 break;
7993 /*
7994 Map image.
7995 */
7996 XSetCursorState(display,windows,MagickTrue);
7997 XCheckRefreshWindows(display,windows);
7998 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
7999 affinity_image=ReadImage(image_info,exception);
8000 if (affinity_image != (Image *) NULL)
8001 {
8002 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
8003 affinity_image=DestroyImage(affinity_image);
8004 }
8005 CatchException(exception);
8006 XSetCursorState(display,windows,MagickFalse);
8007 if (windows->image.orphan != MagickFalse)
8008 break;
8009 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8010 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8011 break;
8012 }
8013 case QuantizeCommand:
8014 {
8015 int
8016 status;
8017
8018 static char
8019 colors[MagickPathExtent] = "256";
8020
8021 /*
8022 Query user for maximum number of colors.
8023 */
8024 status=XDialogWidget(display,windows,"Quantize",
8025 "Maximum number of colors:",colors);
8026 if (*colors == '\0')
8027 break;
8028 /*
8029 Color reduce the image.
8030 */
8031 XSetCursorState(display,windows,MagickTrue);
8032 XCheckRefreshWindows(display,windows);
8033 quantize_info.number_colors=StringToUnsignedLong(colors);
8034 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8035 NoDitherMethod;
8036 (void) QuantizeImage(&quantize_info,*image,exception);
8037 XSetCursorState(display,windows,MagickFalse);
8038 if (windows->image.orphan != MagickFalse)
8039 break;
8040 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8041 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8042 break;
8043 }
8044 case DespeckleCommand:
8045 {
8046 Image
8047 *despeckle_image;
8048
8049 /*
8050 Despeckle image.
8051 */
8052 XSetCursorState(display,windows,MagickTrue);
8053 XCheckRefreshWindows(display,windows);
8054 despeckle_image=DespeckleImage(*image,exception);
8055 if (despeckle_image != (Image *) NULL)
8056 {
8057 *image=DestroyImage(*image);
8058 *image=despeckle_image;
8059 }
8060 CatchException(exception);
8061 XSetCursorState(display,windows,MagickFalse);
8062 if (windows->image.orphan != MagickFalse)
8063 break;
8064 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8065 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8066 break;
8067 }
8068 case EmbossCommand:
8069 {
8070 Image
8071 *emboss_image;
8072
8073 static char
8074 radius[MagickPathExtent] = "0.0x1.0";
8075
8076 /*
8077 Query user for emboss radius.
8078 */
8079 (void) XDialogWidget(display,windows,"Emboss",
8080 "Enter the emboss radius and standard deviation:",radius);
8081 if (*radius == '\0')
8082 break;
8083 /*
8084 Reduce noise in the image.
8085 */
8086 XSetCursorState(display,windows,MagickTrue);
8087 XCheckRefreshWindows(display,windows);
8088 flags=ParseGeometry(radius,&geometry_info);
8089 if ((flags & SigmaValue) == 0)
8090 geometry_info.sigma=1.0;
8091 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8092 exception);
8093 if (emboss_image != (Image *) NULL)
8094 {
8095 *image=DestroyImage(*image);
8096 *image=emboss_image;
8097 }
8098 CatchException(exception);
8099 XSetCursorState(display,windows,MagickFalse);
8100 if (windows->image.orphan != MagickFalse)
8101 break;
8102 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8103 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8104 break;
8105 }
8106 case ReduceNoiseCommand:
8107 {
8108 Image
8109 *noise_image;
8110
8111 static char
8112 radius[MagickPathExtent] = "0";
8113
8114 /*
8115 Query user for noise radius.
8116 */
8117 (void) XDialogWidget(display,windows,"Reduce Noise",
8118 "Enter the noise radius:",radius);
8119 if (*radius == '\0')
8120 break;
8121 /*
8122 Reduce noise in the image.
8123 */
8124 XSetCursorState(display,windows,MagickTrue);
8125 XCheckRefreshWindows(display,windows);
8126 flags=ParseGeometry(radius,&geometry_info);
8127 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8128 geometry_info.rho,(size_t) geometry_info.rho,exception);
8129 if (noise_image != (Image *) NULL)
8130 {
8131 *image=DestroyImage(*image);
8132 *image=noise_image;
8133 }
8134 CatchException(exception);
8135 XSetCursorState(display,windows,MagickFalse);
8136 if (windows->image.orphan != MagickFalse)
8137 break;
8138 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8139 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8140 break;
8141 }
8142 case AddNoiseCommand:
8143 {
8144 char
8145 **noises;
8146
8147 Image
8148 *noise_image;
8149
8150 static char
8151 noise_type[MagickPathExtent] = "Gaussian";
8152
8153 /*
8154 Add noise to the image.
8155 */
8156 noises=GetCommandOptions(MagickNoiseOptions);
8157 if (noises == (char **) NULL)
8158 break;
8159 XListBrowserWidget(display,windows,&windows->widget,
8160 (const char **) noises,"Add Noise",
8161 "Select a type of noise to add to your image:",noise_type);
8162 noises=DestroyStringList(noises);
8163 if (*noise_type == '\0')
8164 break;
8165 XSetCursorState(display,windows,MagickTrue);
8166 XCheckRefreshWindows(display,windows);
8167 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8168 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
8169 if (noise_image != (Image *) NULL)
8170 {
8171 *image=DestroyImage(*image);
8172 *image=noise_image;
8173 }
8174 CatchException(exception);
8175 XSetCursorState(display,windows,MagickFalse);
8176 if (windows->image.orphan != MagickFalse)
8177 break;
8178 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8179 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8180 break;
8181 }
8182 case SharpenCommand:
8183 {
8184 Image
8185 *sharp_image;
8186
8187 static char
8188 radius[MagickPathExtent] = "0.0x1.0";
8189
8190 /*
8191 Query user for sharpen radius.
8192 */
8193 (void) XDialogWidget(display,windows,"Sharpen",
8194 "Enter the sharpen radius and standard deviation:",radius);
8195 if (*radius == '\0')
8196 break;
8197 /*
8198 Sharpen image scanlines.
8199 */
8200 XSetCursorState(display,windows,MagickTrue);
8201 XCheckRefreshWindows(display,windows);
8202 flags=ParseGeometry(radius,&geometry_info);
8203 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8204 exception);
8205 if (sharp_image != (Image *) NULL)
8206 {
8207 *image=DestroyImage(*image);
8208 *image=sharp_image;
8209 }
8210 CatchException(exception);
8211 XSetCursorState(display,windows,MagickFalse);
8212 if (windows->image.orphan != MagickFalse)
8213 break;
8214 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8215 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8216 break;
8217 }
8218 case BlurCommand:
8219 {
8220 Image
8221 *blur_image;
8222
8223 static char
8224 radius[MagickPathExtent] = "0.0x1.0";
8225
8226 /*
8227 Query user for blur radius.
8228 */
8229 (void) XDialogWidget(display,windows,"Blur",
8230 "Enter the blur radius and standard deviation:",radius);
8231 if (*radius == '\0')
8232 break;
8233 /*
8234 Blur an image.
8235 */
8236 XSetCursorState(display,windows,MagickTrue);
8237 XCheckRefreshWindows(display,windows);
8238 flags=ParseGeometry(radius,&geometry_info);
8239 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8240 exception);
8241 if (blur_image != (Image *) NULL)
8242 {
8243 *image=DestroyImage(*image);
8244 *image=blur_image;
8245 }
8246 CatchException(exception);
8247 XSetCursorState(display,windows,MagickFalse);
8248 if (windows->image.orphan != MagickFalse)
8249 break;
8250 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8251 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8252 break;
8253 }
8254 case ThresholdCommand:
8255 {
8256 double
8257 threshold;
8258
8259 static char
8260 factor[MagickPathExtent] = "128";
8261
8262 /*
8263 Query user for threshold value.
8264 */
8265 (void) XDialogWidget(display,windows,"Threshold",
8266 "Enter threshold value:",factor);
8267 if (*factor == '\0')
8268 break;
8269 /*
8270 Gamma correct image.
8271 */
8272 XSetCursorState(display,windows,MagickTrue);
8273 XCheckRefreshWindows(display,windows);
8274 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8275 (void) BilevelImage(*image,threshold,exception);
8276 XSetCursorState(display,windows,MagickFalse);
8277 if (windows->image.orphan != MagickFalse)
8278 break;
8279 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8280 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8281 break;
8282 }
8283 case EdgeDetectCommand:
8284 {
8285 Image
8286 *edge_image;
8287
8288 static char
8289 radius[MagickPathExtent] = "0";
8290
8291 /*
8292 Query user for edge factor.
8293 */
8294 (void) XDialogWidget(display,windows,"Detect Edges",
8295 "Enter the edge detect radius:",radius);
8296 if (*radius == '\0')
8297 break;
8298 /*
8299 Detect edge in image.
8300 */
8301 XSetCursorState(display,windows,MagickTrue);
8302 XCheckRefreshWindows(display,windows);
8303 flags=ParseGeometry(radius,&geometry_info);
8304 edge_image=EdgeImage(*image,geometry_info.rho,exception);
8305 if (edge_image != (Image *) NULL)
8306 {
8307 *image=DestroyImage(*image);
8308 *image=edge_image;
8309 }
8310 CatchException(exception);
8311 XSetCursorState(display,windows,MagickFalse);
8312 if (windows->image.orphan != MagickFalse)
8313 break;
8314 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8315 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8316 break;
8317 }
8318 case SpreadCommand:
8319 {
8320 Image
8321 *spread_image;
8322
8323 static char
8324 amount[MagickPathExtent] = "2";
8325
8326 /*
8327 Query user for spread amount.
8328 */
8329 (void) XDialogWidget(display,windows,"Spread",
8330 "Enter the displacement amount:",amount);
8331 if (*amount == '\0')
8332 break;
8333 /*
8334 Displace image pixels by a random amount.
8335 */
8336 XSetCursorState(display,windows,MagickTrue);
8337 XCheckRefreshWindows(display,windows);
8338 flags=ParseGeometry(amount,&geometry_info);
8339 spread_image=EdgeImage(*image,geometry_info.rho,exception);
8340 if (spread_image != (Image *) NULL)
8341 {
8342 *image=DestroyImage(*image);
8343 *image=spread_image;
8344 }
8345 CatchException(exception);
8346 XSetCursorState(display,windows,MagickFalse);
8347 if (windows->image.orphan != MagickFalse)
8348 break;
8349 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8350 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8351 break;
8352 }
8353 case ShadeCommand:
8354 {
8355 Image
8356 *shade_image;
8357
8358 int
8359 status;
8360
8361 static char
8362 geometry[MagickPathExtent] = "30x30";
8363
8364 /*
8365 Query user for the shade geometry.
8366 */
8367 status=XDialogWidget(display,windows,"Shade",
8368 "Enter the azimuth and elevation of the light source:",geometry);
8369 if (*geometry == '\0')
8370 break;
8371 /*
8372 Shade image pixels.
8373 */
8374 XSetCursorState(display,windows,MagickTrue);
8375 XCheckRefreshWindows(display,windows);
8376 flags=ParseGeometry(geometry,&geometry_info);
8377 if ((flags & SigmaValue) == 0)
8378 geometry_info.sigma=1.0;
8379 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse,
8380 geometry_info.rho,geometry_info.sigma,exception);
8381 if (shade_image != (Image *) NULL)
8382 {
8383 *image=DestroyImage(*image);
8384 *image=shade_image;
8385 }
8386 CatchException(exception);
8387 XSetCursorState(display,windows,MagickFalse);
8388 if (windows->image.orphan != MagickFalse)
8389 break;
8390 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8391 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8392 break;
8393 }
8394 case RaiseCommand:
8395 {
8396 static char
8397 bevel_width[MagickPathExtent] = "10";
8398
8399 /*
8400 Query user for bevel width.
8401 */
8402 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8403 if (*bevel_width == '\0')
8404 break;
8405 /*
8406 Raise an image.
8407 */
8408 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8409 exception);
8410 XSetCursorState(display,windows,MagickTrue);
8411 XCheckRefreshWindows(display,windows);
8412 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8413 exception);
8414 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
8415 XSetCursorState(display,windows,MagickFalse);
8416 if (windows->image.orphan != MagickFalse)
8417 break;
8418 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8420 break;
8421 }
8422 case SegmentCommand:
8423 {
8424 static char
8425 threshold[MagickPathExtent] = "1.0x1.5";
8426
8427 /*
8428 Query user for smoothing threshold.
8429 */
8430 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8431 threshold);
8432 if (*threshold == '\0')
8433 break;
8434 /*
8435 Segment an image.
8436 */
8437 XSetCursorState(display,windows,MagickTrue);
8438 XCheckRefreshWindows(display,windows);
8439 flags=ParseGeometry(threshold,&geometry_info);
8440 if ((flags & SigmaValue) == 0)
8441 geometry_info.sigma=1.0;
8442 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8443 geometry_info.sigma,exception);
8444 XSetCursorState(display,windows,MagickFalse);
8445 if (windows->image.orphan != MagickFalse)
8446 break;
8447 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8448 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8449 break;
8450 }
8451 case SepiaToneCommand:
8452 {
8453 double
8454 threshold;
8455
8456 Image
8457 *sepia_image;
8458
8459 static char
8460 factor[MagickPathExtent] = "80%";
8461
8462 /*
8463 Query user for sepia-tone factor.
8464 */
8465 (void) XDialogWidget(display,windows,"Sepia Tone",
8466 "Enter the sepia tone factor (0 - 99.9%):",factor);
8467 if (*factor == '\0')
8468 break;
8469 /*
8470 Sepia tone image pixels.
8471 */
8472 XSetCursorState(display,windows,MagickTrue);
8473 XCheckRefreshWindows(display,windows);
8474 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8475 sepia_image=SepiaToneImage(*image,threshold,exception);
8476 if (sepia_image != (Image *) NULL)
8477 {
8478 *image=DestroyImage(*image);
8479 *image=sepia_image;
8480 }
8481 CatchException(exception);
8482 XSetCursorState(display,windows,MagickFalse);
8483 if (windows->image.orphan != MagickFalse)
8484 break;
8485 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8486 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8487 break;
8488 }
8489 case SolarizeCommand:
8490 {
8491 double
8492 threshold;
8493
8494 static char
8495 factor[MagickPathExtent] = "60%";
8496
8497 /*
8498 Query user for solarize factor.
8499 */
8500 (void) XDialogWidget(display,windows,"Solarize",
8501 "Enter the solarize factor (0 - 99.9%):",factor);
8502 if (*factor == '\0')
8503 break;
8504 /*
8505 Solarize image pixels.
8506 */
8507 XSetCursorState(display,windows,MagickTrue);
8508 XCheckRefreshWindows(display,windows);
8509 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8510 (void) SolarizeImage(*image,threshold,exception);
8511 XSetCursorState(display,windows,MagickFalse);
8512 if (windows->image.orphan != MagickFalse)
8513 break;
8514 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8515 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8516 break;
8517 }
8518 case SwirlCommand:
8519 {
8520 Image
8521 *swirl_image;
8522
8523 static char
8524 degrees[MagickPathExtent] = "60";
8525
8526 /*
8527 Query user for swirl angle.
8528 */
8529 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8530 degrees);
8531 if (*degrees == '\0')
8532 break;
8533 /*
8534 Swirl image pixels about the center.
8535 */
8536 XSetCursorState(display,windows,MagickTrue);
8537 XCheckRefreshWindows(display,windows);
8538 flags=ParseGeometry(degrees,&geometry_info);
8539 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8540 exception);
8541 if (swirl_image != (Image *) NULL)
8542 {
8543 *image=DestroyImage(*image);
8544 *image=swirl_image;
8545 }
8546 CatchException(exception);
8547 XSetCursorState(display,windows,MagickFalse);
8548 if (windows->image.orphan != MagickFalse)
8549 break;
8550 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8551 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8552 break;
8553 }
8554 case ImplodeCommand:
8555 {
8556 Image
8557 *implode_image;
8558
8559 static char
8560 factor[MagickPathExtent] = "0.3";
8561
8562 /*
8563 Query user for implode factor.
8564 */
8565 (void) XDialogWidget(display,windows,"Implode",
8566 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8567 if (*factor == '\0')
8568 break;
8569 /*
8570 Implode image pixels about the center.
8571 */
8572 XSetCursorState(display,windows,MagickTrue);
8573 XCheckRefreshWindows(display,windows);
8574 flags=ParseGeometry(factor,&geometry_info);
8575 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8576 exception);
8577 if (implode_image != (Image *) NULL)
8578 {
8579 *image=DestroyImage(*image);
8580 *image=implode_image;
8581 }
8582 CatchException(exception);
8583 XSetCursorState(display,windows,MagickFalse);
8584 if (windows->image.orphan != MagickFalse)
8585 break;
8586 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8587 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8588 break;
8589 }
8590 case VignetteCommand:
8591 {
8592 Image
8593 *vignette_image;
8594
8595 static char
8596 geometry[MagickPathExtent] = "0x20";
8597
8598 /*
8599 Query user for the vignette geometry.
8600 */
8601 (void) XDialogWidget(display,windows,"Vignette",
8602 "Enter the radius, sigma, and x and y offsets:",geometry);
8603 if (*geometry == '\0')
8604 break;
8605 /*
8606 Soften the edges of the image in vignette style
8607 */
8608 XSetCursorState(display,windows,MagickTrue);
8609 XCheckRefreshWindows(display,windows);
8610 flags=ParseGeometry(geometry,&geometry_info);
8611 if ((flags & SigmaValue) == 0)
8612 geometry_info.sigma=1.0;
8613 if ((flags & XiValue) == 0)
8614 geometry_info.xi=0.1*(*image)->columns;
8615 if ((flags & PsiValue) == 0)
8616 geometry_info.psi=0.1*(*image)->rows;
8617 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8618 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8619 exception);
8620 if (vignette_image != (Image *) NULL)
8621 {
8622 *image=DestroyImage(*image);
8623 *image=vignette_image;
8624 }
8625 CatchException(exception);
8626 XSetCursorState(display,windows,MagickFalse);
8627 if (windows->image.orphan != MagickFalse)
8628 break;
8629 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8630 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8631 break;
8632 }
8633 case WaveCommand:
8634 {
8635 Image
8636 *wave_image;
8637
8638 static char
8639 geometry[MagickPathExtent] = "25x150";
8640
8641 /*
8642 Query user for the wave geometry.
8643 */
8644 (void) XDialogWidget(display,windows,"Wave",
8645 "Enter the amplitude and length of the wave:",geometry);
8646 if (*geometry == '\0')
8647 break;
8648 /*
8649 Alter an image along a sine wave.
8650 */
8651 XSetCursorState(display,windows,MagickTrue);
8652 XCheckRefreshWindows(display,windows);
8653 flags=ParseGeometry(geometry,&geometry_info);
8654 if ((flags & SigmaValue) == 0)
8655 geometry_info.sigma=1.0;
8656 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8657 (*image)->interpolate,exception);
8658 if (wave_image != (Image *) NULL)
8659 {
8660 *image=DestroyImage(*image);
8661 *image=wave_image;
8662 }
8663 CatchException(exception);
8664 XSetCursorState(display,windows,MagickFalse);
8665 if (windows->image.orphan != MagickFalse)
8666 break;
8667 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8668 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8669 break;
8670 }
8671 case OilPaintCommand:
8672 {
8673 Image
8674 *paint_image;
8675
8676 static char
8677 radius[MagickPathExtent] = "0";
8678
8679 /*
8680 Query user for circular neighborhood radius.
8681 */
8682 (void) XDialogWidget(display,windows,"Oil Paint",
8683 "Enter the mask radius:",radius);
8684 if (*radius == '\0')
8685 break;
8686 /*
8687 OilPaint image scanlines.
8688 */
8689 XSetCursorState(display,windows,MagickTrue);
8690 XCheckRefreshWindows(display,windows);
8691 flags=ParseGeometry(radius,&geometry_info);
8692 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8693 exception);
8694 if (paint_image != (Image *) NULL)
8695 {
8696 *image=DestroyImage(*image);
8697 *image=paint_image;
8698 }
8699 CatchException(exception);
8700 XSetCursorState(display,windows,MagickFalse);
8701 if (windows->image.orphan != MagickFalse)
8702 break;
8703 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8704 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8705 break;
8706 }
8707 case CharcoalDrawCommand:
8708 {
8709 Image
8710 *charcoal_image;
8711
8712 static char
8713 radius[MagickPathExtent] = "0x1";
8714
8715 /*
8716 Query user for charcoal radius.
8717 */
8718 (void) XDialogWidget(display,windows,"Charcoal Draw",
8719 "Enter the charcoal radius and sigma:",radius);
8720 if (*radius == '\0')
8721 break;
8722 /*
8723 Charcoal the image.
8724 */
8725 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8726 exception);
8727 XSetCursorState(display,windows,MagickTrue);
8728 XCheckRefreshWindows(display,windows);
8729 flags=ParseGeometry(radius,&geometry_info);
8730 if ((flags & SigmaValue) == 0)
8731 geometry_info.sigma=geometry_info.rho;
8732 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8733 exception);
8734 if (charcoal_image != (Image *) NULL)
8735 {
8736 *image=DestroyImage(*image);
8737 *image=charcoal_image;
8738 }
8739 CatchException(exception);
8740 XSetCursorState(display,windows,MagickFalse);
8741 if (windows->image.orphan != MagickFalse)
8742 break;
8743 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8744 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8745 break;
8746 }
8747 case AnnotateCommand:
8748 {
8749 /*
8750 Annotate the image with text.
8751 */
8752 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
8753 if (status == MagickFalse)
8754 {
8755 XNoticeWidget(display,windows,"Unable to annotate X image",
8756 (*image)->filename);
8757 break;
8758 }
8759 break;
8760 }
8761 case DrawCommand:
8762 {
8763 /*
8764 Draw image.
8765 */
8766 status=XDrawEditImage(display,resource_info,windows,image,exception);
8767 if (status == MagickFalse)
8768 {
8769 XNoticeWidget(display,windows,"Unable to draw on the X image",
8770 (*image)->filename);
8771 break;
8772 }
8773 break;
8774 }
8775 case ColorCommand:
8776 {
8777 /*
8778 Color edit.
8779 */
8780 status=XColorEditImage(display,resource_info,windows,image,exception);
8781 if (status == MagickFalse)
8782 {
8783 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8784 (*image)->filename);
8785 break;
8786 }
8787 break;
8788 }
8789 case MatteCommand:
8790 {
8791 /*
8792 Matte edit.
8793 */
8794 status=XMatteEditImage(display,resource_info,windows,image,exception);
8795 if (status == MagickFalse)
8796 {
8797 XNoticeWidget(display,windows,"Unable to matte edit X image",
8798 (*image)->filename);
8799 break;
8800 }
8801 break;
8802 }
8803 case CompositeCommand:
8804 {
8805 /*
8806 Composite image.
8807 */
8808 status=XCompositeImage(display,resource_info,windows,*image,
8809 exception);
8810 if (status == MagickFalse)
8811 {
8812 XNoticeWidget(display,windows,"Unable to composite X image",
8813 (*image)->filename);
8814 break;
8815 }
8816 break;
8817 }
8818 case AddBorderCommand:
8819 {
8820 Image
8821 *border_image;
8822
8823 static char
8824 geometry[MagickPathExtent] = "6x6";
8825
8826 /*
8827 Query user for border color and geometry.
8828 */
8829 XColorBrowserWidget(display,windows,"Select",color);
8830 if (*color == '\0')
8831 break;
8832 (void) XDialogWidget(display,windows,"Add Border",
8833 "Enter border geometry:",geometry);
8834 if (*geometry == '\0')
8835 break;
8836 /*
8837 Add a border to the image.
8838 */
8839 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8840 exception);
8841 XSetCursorState(display,windows,MagickTrue);
8842 XCheckRefreshWindows(display,windows);
8843 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
8844 exception);
8845 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8846 exception);
8847 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8848 exception);
8849 if (border_image != (Image *) NULL)
8850 {
8851 *image=DestroyImage(*image);
8852 *image=border_image;
8853 }
8854 CatchException(exception);
8855 XSetCursorState(display,windows,MagickFalse);
8856 if (windows->image.orphan != MagickFalse)
8857 break;
8858 windows->image.window_changes.width=(int) (*image)->columns;
8859 windows->image.window_changes.height=(int) (*image)->rows;
8860 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8861 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8862 break;
8863 }
8864 case AddFrameCommand:
8865 {
8866 FrameInfo
8867 frame_info;
8868
8869 Image
8870 *frame_image;
8871
8872 static char
8873 geometry[MagickPathExtent] = "6x6";
8874
8875 /*
8876 Query user for frame color and geometry.
8877 */
8878 XColorBrowserWidget(display,windows,"Select",color);
8879 if (*color == '\0')
8880 break;
8881 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8882 geometry);
8883 if (*geometry == '\0')
8884 break;
8885 /*
8886 Surround image with an ornamental border.
8887 */
8888 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8889 exception);
8890 XSetCursorState(display,windows,MagickTrue);
8891 XCheckRefreshWindows(display,windows);
8892 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
8893 exception);
8894 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8895 exception);
8896 frame_info.width=page_geometry.width;
8897 frame_info.height=page_geometry.height;
8898 frame_info.outer_bevel=page_geometry.x;
8899 frame_info.inner_bevel=page_geometry.y;
8900 frame_info.x=(ssize_t) frame_info.width;
8901 frame_info.y=(ssize_t) frame_info.height;
8902 frame_info.width=(*image)->columns+2*frame_info.width;
8903 frame_info.height=(*image)->rows+2*frame_info.height;
8904 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
8905 if (frame_image != (Image *) NULL)
8906 {
8907 *image=DestroyImage(*image);
8908 *image=frame_image;
8909 }
8910 CatchException(exception);
8911 XSetCursorState(display,windows,MagickFalse);
8912 if (windows->image.orphan != MagickFalse)
8913 break;
8914 windows->image.window_changes.width=(int) (*image)->columns;
8915 windows->image.window_changes.height=(int) (*image)->rows;
8916 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8917 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8918 break;
8919 }
8920 case CommentCommand:
8921 {
8922 const char
8923 *value;
8924
8925 FILE
8926 *file;
8927
8928 int
8929 unique_file;
8930
8931 /*
8932 Edit image comment.
8933 */
8934 unique_file=AcquireUniqueFileResource(image_info->filename);
8935 if (unique_file == -1)
8936 XNoticeWidget(display,windows,"Unable to edit image comment",
8937 image_info->filename);
8938 value=GetImageProperty(*image,"comment",exception);
8939 if (value == (char *) NULL)
8940 unique_file=close(unique_file)-1;
8941 else
8942 {
8943 const char
8944 *p;
8945
8946 file=fdopen(unique_file,"w");
8947 if (file == (FILE *) NULL)
8948 {
8949 XNoticeWidget(display,windows,"Unable to edit image comment",
8950 image_info->filename);
8951 break;
8952 }
8953 for (p=value; *p != '\0'; p++)
8954 (void) fputc((int) *p,file);
8955 (void) fputc('\n',file);
8956 (void) fclose(file);
8957 }
8958 XSetCursorState(display,windows,MagickTrue);
8959 XCheckRefreshWindows(display,windows);
8960 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8961 exception);
8962 if (status == MagickFalse)
8963 XNoticeWidget(display,windows,"Unable to edit image comment",
8964 (char *) NULL);
8965 else
8966 {
8967 char
8968 *comment;
8969
8970 comment=FileToString(image_info->filename,~0UL,exception);
8971 if (comment != (char *) NULL)
8972 {
8973 (void) SetImageProperty(*image,"comment",comment,exception);
8974 (*image)->taint=MagickTrue;
8975 }
8976 }
8977 (void) RelinquishUniqueFileResource(image_info->filename);
8978 XSetCursorState(display,windows,MagickFalse);
8979 break;
8980 }
8981 case LaunchCommand:
8982 {
8983 /*
8984 Launch program.
8985 */
8986 XSetCursorState(display,windows,MagickTrue);
8987 XCheckRefreshWindows(display,windows);
8988 (void) AcquireUniqueFilename(filename);
8989 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s",
8990 filename);
8991 status=WriteImage(image_info,*image,exception);
8992 if (status == MagickFalse)
8993 XNoticeWidget(display,windows,"Unable to launch image editor",
8994 (char *) NULL);
8995 else
8996 {
8997 nexus=ReadImage(resource_info->image_info,exception);
8998 CatchException(exception);
8999 XClientMessage(display,windows->image.id,windows->im_protocols,
9000 windows->im_next_image,CurrentTime);
9001 }
9002 (void) RelinquishUniqueFileResource(filename);
9003 XSetCursorState(display,windows,MagickFalse);
9004 break;
9005 }
9006 case RegionofInterestCommand:
9007 {
9008 /*
9009 Apply an image processing technique to a region of interest.
9010 */
9011 (void) XROIImage(display,resource_info,windows,image,exception);
9012 break;
9013 }
9014 case InfoCommand:
9015 break;
9016 case ZoomCommand:
9017 {
9018 /*
9019 Zoom image.
9020 */
9021 if (windows->magnify.mapped != MagickFalse)
9022 (void) XRaiseWindow(display,windows->magnify.id);
9023 else
9024 {
9025 /*
9026 Make magnify image.
9027 */
9028 XSetCursorState(display,windows,MagickTrue);
9029 (void) XMapRaised(display,windows->magnify.id);
9030 XSetCursorState(display,windows,MagickFalse);
9031 }
9032 break;
9033 }
9034 case ShowPreviewCommand:
9035 {
9036 char
9037 **previews;
9038
9039 Image
9040 *preview_image;
9041
9042 PreviewType
9043 preview;
9044
9045 static char
9046 preview_type[MagickPathExtent] = "Gamma";
9047
9048 /*
9049 Select preview type from menu.
9050 */
9051 previews=GetCommandOptions(MagickPreviewOptions);
9052 if (previews == (char **) NULL)
9053 break;
9054 XListBrowserWidget(display,windows,&windows->widget,
9055 (const char **) previews,"Preview",
9056 "Select an enhancement, effect, or F/X:",preview_type);
9057 previews=DestroyStringList(previews);
9058 if (*preview_type == '\0')
9059 break;
9060 /*
9061 Show image preview.
9062 */
9063 XSetCursorState(display,windows,MagickTrue);
9064 XCheckRefreshWindows(display,windows);
9065 preview=(PreviewType) ParseCommandOption(MagickPreviewOptions,
9066 MagickFalse,preview_type);
9067 (void) FormatImageProperty(*image,"group","%.20g",(double)
9068 windows->image.id);
9069 (void) DeleteImageProperty(*image,"label");
9070 (void) SetImageProperty(*image,"label","Preview",exception);
9071 preview_image=PreviewImage(*image,preview,exception);
9072 if (preview_image == (Image *) NULL)
9073 break;
9074 (void) AcquireUniqueFilename(filename);
9075 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
9076 "show:%s",filename);
9077 status=WriteImage(image_info,preview_image,exception);
9078 (void) RelinquishUniqueFileResource(filename);
9079 preview_image=DestroyImage(preview_image);
9080 if (status == MagickFalse)
9081 XNoticeWidget(display,windows,"Unable to show image preview",
9082 (*image)->filename);
9083 XDelay(display,1500);
9084 XSetCursorState(display,windows,MagickFalse);
9085 break;
9086 }
9087 case ShowHistogramCommand:
9088 {
9089 Image
9090 *histogram_image;
9091
9092 /*
9093 Show image histogram.
9094 */
9095 XSetCursorState(display,windows,MagickTrue);
9096 XCheckRefreshWindows(display,windows);
9097 (void) DeleteImageProperty(*image,"label");
9098 (void) FormatImageProperty(*image,"group","%.20g",(double)
9099 windows->image.id);
9100 (void) SetImageProperty(*image,"label","Histogram",exception);
9101 (void) AcquireUniqueFilename(filename);
9102 (void) FormatLocaleString((*image)->filename,MagickPathExtent,
9103 "histogram:%s",filename);
9104 status=WriteImage(image_info,*image,exception);
9105 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9106 histogram_image=ReadImage(image_info,exception);
9107 (void) RelinquishUniqueFileResource(filename);
9108 if (histogram_image == (Image *) NULL)
9109 break;
9110 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
9111 "show:%s",filename);
9112 status=WriteImage(image_info,histogram_image,exception);
9113 histogram_image=DestroyImage(histogram_image);
9114 if (status == MagickFalse)
9115 XNoticeWidget(display,windows,"Unable to show histogram",
9116 (*image)->filename);
9117 XDelay(display,1500);
9118 XSetCursorState(display,windows,MagickFalse);
9119 break;
9120 }
9121 case ShowMatteCommand:
9122 {
9123 Image
9124 *matte_image;
9125
9126 if ((*image)->alpha_trait == UndefinedPixelTrait)
9127 {
9128 XNoticeWidget(display,windows,
9129 "Image does not have any matte information",(*image)->filename);
9130 break;
9131 }
9132 /*
9133 Show image matte.
9134 */
9135 XSetCursorState(display,windows,MagickTrue);
9136 XCheckRefreshWindows(display,windows);
9137 (void) FormatImageProperty(*image,"group","%.20g",(double)
9138 windows->image.id);
9139 (void) DeleteImageProperty(*image,"label");
9140 (void) SetImageProperty(*image,"label","Matte",exception);
9141 (void) AcquireUniqueFilename(filename);
9142 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s",
9143 filename);
9144 status=WriteImage(image_info,*image,exception);
9145 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9146 matte_image=ReadImage(image_info,exception);
9147 (void) RelinquishUniqueFileResource(filename);
9148 if (matte_image == (Image *) NULL)
9149 break;
9150 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,
9151 "show:%s",filename);
9152 status=WriteImage(image_info,matte_image,exception);
9153 matte_image=DestroyImage(matte_image);
9154 if (status == MagickFalse)
9155 XNoticeWidget(display,windows,"Unable to show matte",
9156 (*image)->filename);
9157 XDelay(display,1500);
9158 XSetCursorState(display,windows,MagickFalse);
9159 break;
9160 }
9161 case BackgroundCommand:
9162 {
9163 /*
9164 Background image.
9165 */
9166 status=XBackgroundImage(display,resource_info,windows,image,exception);
9167 if (status == MagickFalse)
9168 break;
9169 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9170 if (nexus != (Image *) NULL)
9171 XClientMessage(display,windows->image.id,windows->im_protocols,
9172 windows->im_next_image,CurrentTime);
9173 break;
9174 }
9175 case SlideShowCommand:
9176 {
9177 static char
9178 delay[MagickPathExtent] = "5";
9179
9180 /*
9181 Display next image after pausing.
9182 */
9183 (void) XDialogWidget(display,windows,"Slide Show",
9184 "Pause how many 1/100ths of a second between images:",delay);
9185 if (*delay == '\0')
9186 break;
9187 resource_info->delay=StringToUnsignedLong(delay);
9188 XClientMessage(display,windows->image.id,windows->im_protocols,
9189 windows->im_next_image,CurrentTime);
9190 break;
9191 }
9192 case PreferencesCommand:
9193 {
9194 /*
9195 Set user preferences.
9196 */
9197 status=XPreferencesWidget(display,resource_info,windows);
9198 if (status == MagickFalse)
9199 break;
9200 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9201 if (nexus != (Image *) NULL)
9202 XClientMessage(display,windows->image.id,windows->im_protocols,
9203 windows->im_next_image,CurrentTime);
9204 break;
9205 }
9206 case HelpCommand:
9207 {
9208 /*
9209 User requested help.
9210 */
9211 XTextViewHelp(display,resource_info,windows,MagickFalse,
9212 "Help Viewer - Display",DisplayHelp);
9213 break;
9214 }
9215 case BrowseDocumentationCommand:
9216 {
9217 Atom
9218 mozilla_atom;
9219
9220 Window
9221 mozilla_window,
9222 root_window;
9223
9224 /*
9225 Browse the ImageMagick documentation.
9226 */
9227 root_window=XRootWindow(display,XDefaultScreen(display));
9228 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9229 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9230 if (mozilla_window != (Window) NULL)
9231 {
9232 char
9233 command[MagickPathExtent];
9234
9235 /*
9236 Display documentation using Netscape remote control.
9237 */
9238 (void) FormatLocaleString(command,MagickPathExtent,
9239 "openurl(%s,new-tab)",MagickAuthoritativeURL);
9240 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9241 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9242 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9243 XSetCursorState(display,windows,MagickFalse);
9244 break;
9245 }
9246 XSetCursorState(display,windows,MagickTrue);
9247 XCheckRefreshWindows(display,windows);
9248 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9249 exception);
9250 if (status == MagickFalse)
9251 XNoticeWidget(display,windows,"Unable to browse documentation",
9252 (char *) NULL);
9253 XDelay(display,1500);
9254 XSetCursorState(display,windows,MagickFalse);
9255 break;
9256 }
9257 case VersionCommand:
9258 {
9259 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9260 GetMagickCopyright());
9261 break;
9262 }
9263 case SaveToUndoBufferCommand:
9264 break;
9265 default:
9266 {
9267 (void) XBell(display,0);
9268 break;
9269 }
9270 }
9271 image_info=DestroyImageInfo(image_info);
9272 return(nexus);
9273 }
9274
9275 /*
9276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9277 % %
9278 % %
9279 % %
9280 + X M a g n i f y I m a g e %
9281 % %
9282 % %
9283 % %
9284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9285 %
9286 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9287 % The magnified portion is displayed in a separate window.
9288 %
9289 % The format of the XMagnifyImage method is:
9290 %
9291 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9292 % ExceptionInfo *exception)
9293 %
9294 % A description of each parameter follows:
9295 %
9296 % o display: Specifies a connection to an X server; returned from
9297 % XOpenDisplay.
9298 %
9299 % o windows: Specifies a pointer to a XWindows structure.
9300 %
9301 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9302 % the entire image is refreshed.
9303 %
9304 % o exception: return any errors or warnings in this structure.
9305 %
9306 */
XMagnifyImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)9307 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9308 ExceptionInfo *exception)
9309 {
9310 char
9311 text[MagickPathExtent];
9312
9313 int
9314 x,
9315 y;
9316
9317 size_t
9318 state;
9319
9320 /*
9321 Update magnified image until the mouse button is released.
9322 */
9323 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9324 state=DefaultState;
9325 x=event->xbutton.x;
9326 y=event->xbutton.y;
9327 windows->magnify.x=(int) windows->image.x+x;
9328 windows->magnify.y=(int) windows->image.y+y;
9329 do
9330 {
9331 /*
9332 Map and unmap Info widget as text cursor crosses its boundaries.
9333 */
9334 if (windows->info.mapped != MagickFalse)
9335 {
9336 if ((x < (int) (windows->info.x+windows->info.width)) &&
9337 (y < (int) (windows->info.y+windows->info.height)))
9338 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9339 }
9340 else
9341 if ((x > (int) (windows->info.x+windows->info.width)) ||
9342 (y > (int) (windows->info.y+windows->info.height)))
9343 (void) XMapWindow(display,windows->info.id);
9344 if (windows->info.mapped != MagickFalse)
9345 {
9346 /*
9347 Display pointer position.
9348 */
9349 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9350 windows->magnify.x,windows->magnify.y);
9351 XInfoWidget(display,windows,text);
9352 }
9353 /*
9354 Wait for next event.
9355 */
9356 XScreenEvent(display,windows,event,exception);
9357 switch (event->type)
9358 {
9359 case ButtonPress:
9360 break;
9361 case ButtonRelease:
9362 {
9363 /*
9364 User has finished magnifying image.
9365 */
9366 x=event->xbutton.x;
9367 y=event->xbutton.y;
9368 state|=ExitState;
9369 break;
9370 }
9371 case Expose:
9372 break;
9373 case MotionNotify:
9374 {
9375 x=event->xmotion.x;
9376 y=event->xmotion.y;
9377 break;
9378 }
9379 default:
9380 break;
9381 }
9382 /*
9383 Check boundary conditions.
9384 */
9385 if (x < 0)
9386 x=0;
9387 else
9388 if (x >= (int) windows->image.width)
9389 x=(int) windows->image.width-1;
9390 if (y < 0)
9391 y=0;
9392 else
9393 if (y >= (int) windows->image.height)
9394 y=(int) windows->image.height-1;
9395 } while ((state & ExitState) == 0);
9396 /*
9397 Display magnified image.
9398 */
9399 XSetCursorState(display,windows,MagickFalse);
9400 }
9401
9402 /*
9403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9404 % %
9405 % %
9406 % %
9407 + X M a g n i f y W i n d o w C o m m a n d %
9408 % %
9409 % %
9410 % %
9411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9412 %
9413 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9414 % pixel as specified by the key symbol.
9415 %
9416 % The format of the XMagnifyWindowCommand method is:
9417 %
9418 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9419 % const MagickStatusType state,const KeySym key_symbol,
9420 % ExceptionInfo *exception)
9421 %
9422 % A description of each parameter follows:
9423 %
9424 % o display: Specifies a connection to an X server; returned from
9425 % XOpenDisplay.
9426 %
9427 % o windows: Specifies a pointer to a XWindows structure.
9428 %
9429 % o state: key mask.
9430 %
9431 % o key_symbol: Specifies a KeySym which indicates which side of the image
9432 % to trim.
9433 %
9434 % o exception: return any errors or warnings in this structure.
9435 %
9436 */
XMagnifyWindowCommand(Display * display,XWindows * windows,const MagickStatusType state,const KeySym key_symbol,ExceptionInfo * exception)9437 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9438 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
9439 {
9440 unsigned int
9441 quantum;
9442
9443 /*
9444 User specified a magnify factor or position.
9445 */
9446 quantum=1;
9447 if ((state & Mod1Mask) != 0)
9448 quantum=10;
9449 switch ((int) key_symbol)
9450 {
9451 case QuitCommand:
9452 {
9453 (void) XWithdrawWindow(display,windows->magnify.id,
9454 windows->magnify.screen);
9455 break;
9456 }
9457 case XK_Home:
9458 case XK_KP_Home:
9459 {
9460 windows->magnify.x=(int) windows->image.width/2;
9461 windows->magnify.y=(int) windows->image.height/2;
9462 break;
9463 }
9464 case XK_Left:
9465 case XK_KP_Left:
9466 {
9467 if (windows->magnify.x > 0)
9468 windows->magnify.x-=quantum;
9469 break;
9470 }
9471 case XK_Up:
9472 case XK_KP_Up:
9473 {
9474 if (windows->magnify.y > 0)
9475 windows->magnify.y-=quantum;
9476 break;
9477 }
9478 case XK_Right:
9479 case XK_KP_Right:
9480 {
9481 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9482 windows->magnify.x+=quantum;
9483 break;
9484 }
9485 case XK_Down:
9486 case XK_KP_Down:
9487 {
9488 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9489 windows->magnify.y+=quantum;
9490 break;
9491 }
9492 case XK_0:
9493 case XK_1:
9494 case XK_2:
9495 case XK_3:
9496 case XK_4:
9497 case XK_5:
9498 case XK_6:
9499 case XK_7:
9500 case XK_8:
9501 case XK_9:
9502 {
9503 windows->magnify.data=(key_symbol-XK_0);
9504 break;
9505 }
9506 case XK_KP_0:
9507 case XK_KP_1:
9508 case XK_KP_2:
9509 case XK_KP_3:
9510 case XK_KP_4:
9511 case XK_KP_5:
9512 case XK_KP_6:
9513 case XK_KP_7:
9514 case XK_KP_8:
9515 case XK_KP_9:
9516 {
9517 windows->magnify.data=(key_symbol-XK_KP_0);
9518 break;
9519 }
9520 default:
9521 break;
9522 }
9523 XMakeMagnifyImage(display,windows,exception);
9524 }
9525
9526 /*
9527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9528 % %
9529 % %
9530 % %
9531 + X M a k e P a n I m a g e %
9532 % %
9533 % %
9534 % %
9535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9536 %
9537 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9538 % icon window.
9539 %
9540 % The format of the XMakePanImage method is:
9541 %
9542 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9543 % XWindows *windows,Image *image,ExceptionInfo *exception)
9544 %
9545 % A description of each parameter follows:
9546 %
9547 % o display: Specifies a connection to an X server; returned from
9548 % XOpenDisplay.
9549 %
9550 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9551 %
9552 % o windows: Specifies a pointer to a XWindows structure.
9553 %
9554 % o image: the image.
9555 %
9556 % o exception: return any errors or warnings in this structure.
9557 %
9558 */
XMakePanImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)9559 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9560 XWindows *windows,Image *image,ExceptionInfo *exception)
9561 {
9562 MagickStatusType
9563 status;
9564
9565 /*
9566 Create and display image for panning icon.
9567 */
9568 XSetCursorState(display,windows,MagickTrue);
9569 XCheckRefreshWindows(display,windows);
9570 windows->pan.x=(int) windows->image.x;
9571 windows->pan.y=(int) windows->image.y;
9572 status=XMakeImage(display,resource_info,&windows->pan,image,
9573 windows->pan.width,windows->pan.height,exception);
9574 if (status == MagickFalse)
9575 ThrowXWindowException(ResourceLimitError,
9576 "MemoryAllocationFailed",image->filename);
9577 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9578 windows->pan.pixmap);
9579 (void) XClearWindow(display,windows->pan.id);
9580 XDrawPanRectangle(display,windows);
9581 XSetCursorState(display,windows,MagickFalse);
9582 }
9583
9584 /*
9585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9586 % %
9587 % %
9588 % %
9589 + X M a t t a E d i t I m a g e %
9590 % %
9591 % %
9592 % %
9593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9594 %
9595 % XMatteEditImage() allows the user to interactively change the Matte channel
9596 % of an image. If the image is PseudoClass it is promoted to DirectClass
9597 % before the matte information is stored.
9598 %
9599 % The format of the XMatteEditImage method is:
9600 %
9601 % MagickBooleanType XMatteEditImage(Display *display,
9602 % XResourceInfo *resource_info,XWindows *windows,Image **image,
9603 % ExceptionInfo *exception)
9604 %
9605 % A description of each parameter follows:
9606 %
9607 % o display: Specifies a connection to an X server; returned from
9608 % XOpenDisplay.
9609 %
9610 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9611 %
9612 % o windows: Specifies a pointer to a XWindows structure.
9613 %
9614 % o image: the image; returned from ReadImage.
9615 %
9616 % o exception: return any errors or warnings in this structure.
9617 %
9618 */
XMatteEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)9619 static MagickBooleanType XMatteEditImage(Display *display,
9620 XResourceInfo *resource_info,XWindows *windows,Image **image,
9621 ExceptionInfo *exception)
9622 {
9623 const char
9624 *const MatteEditMenu[] =
9625 {
9626 "Method",
9627 "Border Color",
9628 "Fuzz",
9629 "Matte Value",
9630 "Undo",
9631 "Help",
9632 "Dismiss",
9633 (char *) NULL
9634 };
9635
9636 static char
9637 matte[MagickPathExtent] = "0";
9638
9639 static const ModeType
9640 MatteEditCommands[] =
9641 {
9642 MatteEditMethod,
9643 MatteEditBorderCommand,
9644 MatteEditFuzzCommand,
9645 MatteEditValueCommand,
9646 MatteEditUndoCommand,
9647 MatteEditHelpCommand,
9648 MatteEditDismissCommand
9649 };
9650
9651 static PaintMethod
9652 method = PointMethod;
9653
9654 static XColor
9655 border_color = { 0, 0, 0, 0, 0, 0 };
9656
9657 char
9658 command[MagickPathExtent],
9659 text[MagickPathExtent];
9660
9661 Cursor
9662 cursor;
9663
9664 int
9665 entry,
9666 id,
9667 x,
9668 x_offset,
9669 y,
9670 y_offset;
9671
9672 int
9673 i;
9674
9675 Quantum
9676 *q;
9677
9678 unsigned int
9679 height,
9680 width;
9681
9682 size_t
9683 state;
9684
9685 XEvent
9686 event;
9687
9688 /*
9689 Map Command widget.
9690 */
9691 (void) CloneString(&windows->command.name,"Matte Edit");
9692 windows->command.data=4;
9693 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9694 (void) XMapRaised(display,windows->command.id);
9695 XClientMessage(display,windows->image.id,windows->im_protocols,
9696 windows->im_update_widget,CurrentTime);
9697 /*
9698 Make cursor.
9699 */
9700 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9701 resource_info->background_color,resource_info->foreground_color);
9702 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9703 /*
9704 Track pointer until button 1 is pressed.
9705 */
9706 XQueryPosition(display,windows->image.id,&x,&y);
9707 (void) XSelectInput(display,windows->image.id,
9708 windows->image.attributes.event_mask | PointerMotionMask);
9709 state=DefaultState;
9710 do
9711 {
9712 if (windows->info.mapped != MagickFalse)
9713 {
9714 /*
9715 Display pointer position.
9716 */
9717 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9718 x+windows->image.x,y+windows->image.y);
9719 XInfoWidget(display,windows,text);
9720 }
9721 /*
9722 Wait for next event.
9723 */
9724 XScreenEvent(display,windows,&event,exception);
9725 if (event.xany.window == windows->command.id)
9726 {
9727 /*
9728 Select a command from the Command widget.
9729 */
9730 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9731 if (id < 0)
9732 {
9733 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9734 continue;
9735 }
9736 switch (MatteEditCommands[id])
9737 {
9738 case MatteEditMethod:
9739 {
9740 char
9741 **methods;
9742
9743 /*
9744 Select a method from the pop-up menu.
9745 */
9746 methods=GetCommandOptions(MagickMethodOptions);
9747 if (methods == (char **) NULL)
9748 break;
9749 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9750 (const char **) methods,command);
9751 if (entry >= 0)
9752 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9753 MagickFalse,methods[entry]);
9754 methods=DestroyStringList(methods);
9755 break;
9756 }
9757 case MatteEditBorderCommand:
9758 {
9759 const char
9760 *ColorMenu[MaxNumberPens];
9761
9762 int
9763 pen_number;
9764
9765 /*
9766 Initialize menu selections.
9767 */
9768 for (i=0; i < (int) (MaxNumberPens-2); i++)
9769 ColorMenu[i]=resource_info->pen_colors[i];
9770 ColorMenu[MaxNumberPens-2]="Browser...";
9771 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9772 /*
9773 Select a pen color from the pop-up menu.
9774 */
9775 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9776 (const char **) ColorMenu,command);
9777 if (pen_number < 0)
9778 break;
9779 if (pen_number == (MaxNumberPens-2))
9780 {
9781 static char
9782 color_name[MagickPathExtent] = "gray";
9783
9784 /*
9785 Select a pen color from a dialog.
9786 */
9787 resource_info->pen_colors[pen_number]=color_name;
9788 XColorBrowserWidget(display,windows,"Select",color_name);
9789 if (*color_name == '\0')
9790 break;
9791 }
9792 /*
9793 Set border color.
9794 */
9795 (void) XParseColor(display,windows->map_info->colormap,
9796 resource_info->pen_colors[pen_number],&border_color);
9797 break;
9798 }
9799 case MatteEditFuzzCommand:
9800 {
9801 const char
9802 *const FuzzMenu[] =
9803 {
9804 "0%",
9805 "2%",
9806 "5%",
9807 "10%",
9808 "15%",
9809 "Dialog...",
9810 (char *) NULL,
9811 };
9812
9813 static char
9814 fuzz[MagickPathExtent];
9815
9816 /*
9817 Select a command from the pop-up menu.
9818 */
9819 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9820 command);
9821 if (entry < 0)
9822 break;
9823 if (entry != 5)
9824 {
9825 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9826 QuantumRange+1.0);
9827 break;
9828 }
9829 (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
9830 (void) XDialogWidget(display,windows,"Ok",
9831 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9832 if (*fuzz == '\0')
9833 break;
9834 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
9835 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9836 1.0);
9837 break;
9838 }
9839 case MatteEditValueCommand:
9840 {
9841 const char
9842 *const MatteMenu[] =
9843 {
9844 "Opaque",
9845 "Transparent",
9846 "Dialog...",
9847 (char *) NULL,
9848 };
9849
9850 static char
9851 message[MagickPathExtent];
9852
9853 /*
9854 Select a command from the pop-up menu.
9855 */
9856 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9857 command);
9858 if (entry < 0)
9859 break;
9860 if (entry != 2)
9861 {
9862 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
9863 OpaqueAlpha);
9864 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9865 (void) FormatLocaleString(matte,MagickPathExtent,
9866 QuantumFormat,(Quantum) TransparentAlpha);
9867 break;
9868 }
9869 (void) FormatLocaleString(message,MagickPathExtent,
9870 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9871 QuantumRange);
9872 (void) XDialogWidget(display,windows,"Matte",message,matte);
9873 if (*matte == '\0')
9874 break;
9875 break;
9876 }
9877 case MatteEditUndoCommand:
9878 {
9879 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9880 image,exception);
9881 break;
9882 }
9883 case MatteEditHelpCommand:
9884 {
9885 XTextViewHelp(display,resource_info,windows,MagickFalse,
9886 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9887 break;
9888 }
9889 case MatteEditDismissCommand:
9890 {
9891 /*
9892 Prematurely exit.
9893 */
9894 state|=EscapeState;
9895 state|=ExitState;
9896 break;
9897 }
9898 default:
9899 break;
9900 }
9901 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9902 continue;
9903 }
9904 switch (event.type)
9905 {
9906 case ButtonPress:
9907 {
9908 if (event.xbutton.button != Button1)
9909 break;
9910 if ((event.xbutton.window != windows->image.id) &&
9911 (event.xbutton.window != windows->magnify.id))
9912 break;
9913 /*
9914 Update matte data.
9915 */
9916 x=event.xbutton.x;
9917 y=event.xbutton.y;
9918 (void) XMagickCommand(display,resource_info,windows,
9919 SaveToUndoBufferCommand,image,exception);
9920 state|=UpdateConfigurationState;
9921 break;
9922 }
9923 case ButtonRelease:
9924 {
9925 if (event.xbutton.button != Button1)
9926 break;
9927 if ((event.xbutton.window != windows->image.id) &&
9928 (event.xbutton.window != windows->magnify.id))
9929 break;
9930 /*
9931 Update colormap information.
9932 */
9933 x=event.xbutton.x;
9934 y=event.xbutton.y;
9935 XConfigureImageColormap(display,resource_info,windows,*image,exception);
9936 (void) XConfigureImage(display,resource_info,windows,*image,exception);
9937 XInfoWidget(display,windows,text);
9938 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9939 state&=(~UpdateConfigurationState);
9940 break;
9941 }
9942 case Expose:
9943 break;
9944 case KeyPress:
9945 {
9946 char
9947 command[MagickPathExtent];
9948
9949 KeySym
9950 key_symbol;
9951
9952 if (event.xkey.window == windows->magnify.id)
9953 {
9954 Window
9955 window;
9956
9957 window=windows->magnify.id;
9958 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9959 }
9960 if (event.xkey.window != windows->image.id)
9961 break;
9962 /*
9963 Respond to a user key press.
9964 */
9965 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9966 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9967 switch ((int) key_symbol)
9968 {
9969 case XK_Escape:
9970 case XK_F20:
9971 {
9972 /*
9973 Prematurely exit.
9974 */
9975 state|=ExitState;
9976 break;
9977 }
9978 case XK_F1:
9979 case XK_Help:
9980 {
9981 XTextViewHelp(display,resource_info,windows,MagickFalse,
9982 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9983 break;
9984 }
9985 default:
9986 {
9987 (void) XBell(display,0);
9988 break;
9989 }
9990 }
9991 break;
9992 }
9993 case MotionNotify:
9994 {
9995 /*
9996 Map and unmap Info widget as cursor crosses its boundaries.
9997 */
9998 x=event.xmotion.x;
9999 y=event.xmotion.y;
10000 if (windows->info.mapped != MagickFalse)
10001 {
10002 if ((x < (int) (windows->info.x+windows->info.width)) &&
10003 (y < (int) (windows->info.y+windows->info.height)))
10004 (void) XWithdrawWindow(display,windows->info.id,
10005 windows->info.screen);
10006 }
10007 else
10008 if ((x > (int) (windows->info.x+windows->info.width)) ||
10009 (y > (int) (windows->info.y+windows->info.height)))
10010 (void) XMapWindow(display,windows->info.id);
10011 break;
10012 }
10013 default:
10014 break;
10015 }
10016 if (event.xany.window == windows->magnify.id)
10017 {
10018 x=windows->magnify.x-windows->image.x;
10019 y=windows->magnify.y-windows->image.y;
10020 }
10021 x_offset=x;
10022 y_offset=y;
10023 if ((state & UpdateConfigurationState) != 0)
10024 {
10025 CacheView
10026 *image_view;
10027
10028 int
10029 x,
10030 y;
10031
10032 /*
10033 Matte edit is relative to image configuration.
10034 */
10035 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10036 MagickTrue);
10037 XPutPixel(windows->image.ximage,x_offset,y_offset,
10038 windows->pixel_info->background_color.pixel);
10039 width=(unsigned int) (*image)->columns;
10040 height=(unsigned int) (*image)->rows;
10041 x=0;
10042 y=0;
10043 if (windows->image.crop_geometry != (char *) NULL)
10044 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10045 &height);
10046 x_offset=(int) (width*(windows->image.x+x_offset)/
10047 windows->image.ximage->width+x);
10048 y_offset=(int) (height*(windows->image.y+y_offset)/
10049 windows->image.ximage->height+y);
10050 if ((x_offset < 0) || (y_offset < 0))
10051 continue;
10052 if ((x_offset >= (int) (*image)->columns) ||
10053 (y_offset >= (int) (*image)->rows))
10054 continue;
10055 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10056 return(MagickFalse);
10057 if ((*image)->alpha_trait == UndefinedPixelTrait)
10058 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
10059 image_view=AcquireAuthenticCacheView(*image,exception);
10060 switch (method)
10061 {
10062 case PointMethod:
10063 default:
10064 {
10065 /*
10066 Update matte information using point algorithm.
10067 */
10068 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10069 (ssize_t) y_offset,1,1,exception);
10070 if (q == (Quantum *) NULL)
10071 break;
10072 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10073 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10074 break;
10075 }
10076 case ReplaceMethod:
10077 {
10078 PixelInfo
10079 pixel,
10080 target;
10081
10082 /*
10083 Update matte information using replace algorithm.
10084 */
10085 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10086 x_offset,(ssize_t) y_offset,&target,exception);
10087 for (y=0; y < (int) (*image)->rows; y++)
10088 {
10089 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10090 (*image)->columns,1,exception);
10091 if (q == (Quantum *) NULL)
10092 break;
10093 for (x=0; x < (int) (*image)->columns; x++)
10094 {
10095 GetPixelInfoPixel(*image,q,&pixel);
10096 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
10097 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10098 q+=GetPixelChannels(*image);
10099 }
10100 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10101 break;
10102 }
10103 break;
10104 }
10105 case FloodfillMethod:
10106 case FillToBorderMethod:
10107 {
10108 ChannelType
10109 channel_mask;
10110
10111 DrawInfo
10112 *draw_info;
10113
10114 PixelInfo
10115 target;
10116
10117 /*
10118 Update matte information using floodfill algorithm.
10119 */
10120 (void) GetOneVirtualPixelInfo(*image,
10121 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10122 y_offset,&target,exception);
10123 if (method == FillToBorderMethod)
10124 {
10125 target.red=(double) ScaleShortToQuantum(
10126 border_color.red);
10127 target.green=(double) ScaleShortToQuantum(
10128 border_color.green);
10129 target.blue=(double) ScaleShortToQuantum(
10130 border_color.blue);
10131 }
10132 draw_info=CloneDrawInfo(resource_info->image_info,
10133 (DrawInfo *) NULL);
10134 draw_info->fill.alpha=(double) ClampToQuantum(
10135 StringToDouble(matte,(char **) NULL));
10136 channel_mask=SetImageChannelMask(*image,AlphaChannel);
10137 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10138 x_offset,(ssize_t) y_offset,
10139 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
10140 (void) SetPixelChannelMask(*image,channel_mask);
10141 draw_info=DestroyDrawInfo(draw_info);
10142 break;
10143 }
10144 case ResetMethod:
10145 {
10146 /*
10147 Update matte information using reset algorithm.
10148 */
10149 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10150 return(MagickFalse);
10151 for (y=0; y < (int) (*image)->rows; y++)
10152 {
10153 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10154 (*image)->columns,1,exception);
10155 if (q == (Quantum *) NULL)
10156 break;
10157 for (x=0; x < (int) (*image)->columns; x++)
10158 {
10159 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10160 q+=GetPixelChannels(*image);
10161 }
10162 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10163 break;
10164 }
10165 if (StringToLong(matte) == (long) OpaqueAlpha)
10166 (*image)->alpha_trait=UndefinedPixelTrait;
10167 break;
10168 }
10169 }
10170 image_view=DestroyCacheView(image_view);
10171 state&=(~UpdateConfigurationState);
10172 }
10173 } while ((state & ExitState) == 0);
10174 (void) XSelectInput(display,windows->image.id,
10175 windows->image.attributes.event_mask);
10176 XSetCursorState(display,windows,MagickFalse);
10177 (void) XFreeCursor(display,cursor);
10178 return(MagickTrue);
10179 }
10180
10181 /*
10182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10183 % %
10184 % %
10185 % %
10186 + X O p e n I m a g e %
10187 % %
10188 % %
10189 % %
10190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10191 %
10192 % XOpenImage() loads an image from a file.
10193 %
10194 % The format of the XOpenImage method is:
10195 %
10196 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10197 % XWindows *windows,const unsigned int command)
10198 %
10199 % A description of each parameter follows:
10200 %
10201 % o display: Specifies a connection to an X server; returned from
10202 % XOpenDisplay.
10203 %
10204 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10205 %
10206 % o windows: Specifies a pointer to a XWindows structure.
10207 %
10208 % o command: A value other than zero indicates that the file is selected
10209 % from the command line argument list.
10210 %
10211 */
XOpenImage(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickBooleanType command)10212 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10213 XWindows *windows,const MagickBooleanType command)
10214 {
10215 const MagickInfo
10216 *magick_info;
10217
10218 ExceptionInfo
10219 *exception;
10220
10221 Image
10222 *nexus;
10223
10224 ImageInfo
10225 *image_info;
10226
10227 static char
10228 filename[MagickPathExtent] = "\0";
10229
10230 /*
10231 Request file name from user.
10232 */
10233 if (command == MagickFalse)
10234 XFileBrowserWidget(display,windows,"Open",filename);
10235 else
10236 {
10237 char
10238 **filelist,
10239 **files;
10240
10241 int
10242 count,
10243 status;
10244
10245 int
10246 i,
10247 j;
10248
10249 /*
10250 Select next image from the command line.
10251 */
10252 status=XGetCommand(display,windows->image.id,&files,&count);
10253 if (status == 0)
10254 {
10255 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10256 return((Image *) NULL);
10257 }
10258 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10259 if (filelist == (char **) NULL)
10260 {
10261 ThrowXWindowException(ResourceLimitError,
10262 "MemoryAllocationFailed","...");
10263 (void) XFreeStringList(files);
10264 return((Image *) NULL);
10265 }
10266 j=0;
10267 for (i=1; i < count; i++)
10268 if (*files[i] != '-')
10269 filelist[j++]=files[i];
10270 filelist[j]=(char *) NULL;
10271 XListBrowserWidget(display,windows,&windows->widget,
10272 (const char **) filelist,"Load","Select Image to Load:",filename);
10273 filelist=(char **) RelinquishMagickMemory(filelist);
10274 (void) XFreeStringList(files);
10275 }
10276 if (*filename == '\0')
10277 return((Image *) NULL);
10278 image_info=CloneImageInfo(resource_info->image_info);
10279 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10280 (void *) NULL);
10281 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10282 exception=AcquireExceptionInfo();
10283 (void) SetImageInfo(image_info,0,exception);
10284 if (LocaleCompare(image_info->magick,"X") == 0)
10285 {
10286 char
10287 seconds[MagickPathExtent];
10288
10289 /*
10290 User may want to delay the X server screen grab.
10291 */
10292 (void) CopyMagickString(seconds,"0",MagickPathExtent);
10293 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10294 seconds);
10295 if (*seconds == '\0')
10296 return((Image *) NULL);
10297 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10298 }
10299 magick_info=GetMagickInfo(image_info->magick,exception);
10300 if ((magick_info != (const MagickInfo *) NULL) &&
10301 GetMagickRawSupport(magick_info) == MagickTrue)
10302 {
10303 char
10304 geometry[MagickPathExtent];
10305
10306 /*
10307 Request image size from the user.
10308 */
10309 (void) CopyMagickString(geometry,"512x512",MagickPathExtent);
10310 if (image_info->size != (char *) NULL)
10311 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent);
10312 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10313 geometry);
10314 (void) CloneString(&image_info->size,geometry);
10315 }
10316 /*
10317 Load the image.
10318 */
10319 XSetCursorState(display,windows,MagickTrue);
10320 XCheckRefreshWindows(display,windows);
10321 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10322 nexus=ReadImage(image_info,exception);
10323 CatchException(exception);
10324 XSetCursorState(display,windows,MagickFalse);
10325 if (nexus != (Image *) NULL)
10326 XClientMessage(display,windows->image.id,windows->im_protocols,
10327 windows->im_next_image,CurrentTime);
10328 else
10329 {
10330 char
10331 *text,
10332 **textlist;
10333
10334 /*
10335 Unknown image format.
10336 */
10337 text=FileToString(filename,~0UL,exception);
10338 if (text == (char *) NULL)
10339 return((Image *) NULL);
10340 textlist=StringToList(text);
10341 if (textlist != (char **) NULL)
10342 {
10343 char
10344 title[MagickPathExtent];
10345
10346 int
10347 i;
10348
10349 (void) FormatLocaleString(title,MagickPathExtent,
10350 "Unknown format: %s",filename);
10351 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10352 (const char **) textlist);
10353 for (i=0; textlist[i] != (char *) NULL; i++)
10354 textlist[i]=DestroyString(textlist[i]);
10355 textlist=(char **) RelinquishMagickMemory(textlist);
10356 }
10357 text=DestroyString(text);
10358 }
10359 exception=DestroyExceptionInfo(exception);
10360 image_info=DestroyImageInfo(image_info);
10361 return(nexus);
10362 }
10363
10364 /*
10365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10366 % %
10367 % %
10368 % %
10369 + X P a n I m a g e %
10370 % %
10371 % %
10372 % %
10373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10374 %
10375 % XPanImage() pans the image until the mouse button is released.
10376 %
10377 % The format of the XPanImage method is:
10378 %
10379 % void XPanImage(Display *display,XWindows *windows,XEvent *event,
10380 % ExceptionInfo *exception)
10381 %
10382 % A description of each parameter follows:
10383 %
10384 % o display: Specifies a connection to an X server; returned from
10385 % XOpenDisplay.
10386 %
10387 % o windows: Specifies a pointer to a XWindows structure.
10388 %
10389 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10390 % the entire image is refreshed.
10391 %
10392 % o exception: return any errors or warnings in this structure.
10393 %
10394 */
XPanImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)10395 static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10396 ExceptionInfo *exception)
10397 {
10398 char
10399 text[MagickPathExtent];
10400
10401 Cursor
10402 cursor;
10403
10404 double
10405 x_factor,
10406 y_factor;
10407
10408 RectangleInfo
10409 pan_info;
10410
10411 size_t
10412 state;
10413
10414 /*
10415 Define cursor.
10416 */
10417 if ((windows->image.ximage->width > (int) windows->image.width) &&
10418 (windows->image.ximage->height > (int) windows->image.height))
10419 cursor=XCreateFontCursor(display,XC_fleur);
10420 else
10421 if (windows->image.ximage->width > (int) windows->image.width)
10422 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10423 else
10424 if (windows->image.ximage->height > (int) windows->image.height)
10425 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10426 else
10427 cursor=XCreateFontCursor(display,XC_arrow);
10428 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10429 /*
10430 Pan image as pointer moves until the mouse button is released.
10431 */
10432 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10433 y_factor=(double) windows->image.ximage->height/windows->pan.height;
10434 pan_info.width=windows->pan.width*windows->image.width/
10435 windows->image.ximage->width;
10436 pan_info.height=windows->pan.height*windows->image.height/
10437 windows->image.ximage->height;
10438 pan_info.x=0;
10439 pan_info.y=0;
10440 state=UpdateConfigurationState;
10441 do
10442 {
10443 switch (event->type)
10444 {
10445 case ButtonPress:
10446 {
10447 /*
10448 User choose an initial pan location.
10449 */
10450 pan_info.x=(ssize_t) event->xbutton.x;
10451 pan_info.y=(ssize_t) event->xbutton.y;
10452 state|=UpdateConfigurationState;
10453 break;
10454 }
10455 case ButtonRelease:
10456 {
10457 /*
10458 User has finished panning the image.
10459 */
10460 pan_info.x=(ssize_t) event->xbutton.x;
10461 pan_info.y=(ssize_t) event->xbutton.y;
10462 state|=UpdateConfigurationState | ExitState;
10463 break;
10464 }
10465 case MotionNotify:
10466 {
10467 pan_info.x=(ssize_t) event->xmotion.x;
10468 pan_info.y=(ssize_t) event->xmotion.y;
10469 state|=UpdateConfigurationState;
10470 }
10471 default:
10472 break;
10473 }
10474 if ((state & UpdateConfigurationState) != 0)
10475 {
10476 /*
10477 Check boundary conditions.
10478 */
10479 if (pan_info.x < (ssize_t) (pan_info.width/2))
10480 pan_info.x=0;
10481 else
10482 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10483 if (pan_info.x < 0)
10484 pan_info.x=0;
10485 else
10486 if ((int) (pan_info.x+windows->image.width) >
10487 windows->image.ximage->width)
10488 pan_info.x=(ssize_t)
10489 (windows->image.ximage->width-windows->image.width);
10490 if (pan_info.y < (ssize_t) (pan_info.height/2))
10491 pan_info.y=0;
10492 else
10493 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10494 if (pan_info.y < 0)
10495 pan_info.y=0;
10496 else
10497 if ((int) (pan_info.y+windows->image.height) >
10498 windows->image.ximage->height)
10499 pan_info.y=(ssize_t)
10500 (windows->image.ximage->height-windows->image.height);
10501 if ((windows->image.x != (int) pan_info.x) ||
10502 (windows->image.y != (int) pan_info.y))
10503 {
10504 /*
10505 Display image pan offset.
10506 */
10507 windows->image.x=(int) pan_info.x;
10508 windows->image.y=(int) pan_info.y;
10509 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
10510 windows->image.width,windows->image.height,windows->image.x,
10511 windows->image.y);
10512 XInfoWidget(display,windows,text);
10513 /*
10514 Refresh Image window.
10515 */
10516 XDrawPanRectangle(display,windows);
10517 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10518 }
10519 state&=(~UpdateConfigurationState);
10520 }
10521 /*
10522 Wait for next event.
10523 */
10524 if ((state & ExitState) == 0)
10525 XScreenEvent(display,windows,event,exception);
10526 } while ((state & ExitState) == 0);
10527 /*
10528 Restore cursor.
10529 */
10530 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10531 (void) XFreeCursor(display,cursor);
10532 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10533 }
10534
10535 /*
10536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10537 % %
10538 % %
10539 % %
10540 + X P a s t e I m a g e %
10541 % %
10542 % %
10543 % %
10544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10545 %
10546 % XPasteImage() pastes an image previously saved with XCropImage in the X
10547 % window image at a location the user chooses with the pointer.
10548 %
10549 % The format of the XPasteImage method is:
10550 %
10551 % MagickBooleanType XPasteImage(Display *display,
10552 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10553 % ExceptionInfo *exception)
10554 %
10555 % A description of each parameter follows:
10556 %
10557 % o display: Specifies a connection to an X server; returned from
10558 % XOpenDisplay.
10559 %
10560 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10561 %
10562 % o windows: Specifies a pointer to a XWindows structure.
10563 %
10564 % o image: the image; returned from ReadImage.
10565 %
10566 % o exception: return any errors or warnings in this structure.
10567 %
10568 */
XPasteImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10569 static MagickBooleanType XPasteImage(Display *display,
10570 XResourceInfo *resource_info,XWindows *windows,Image *image,
10571 ExceptionInfo *exception)
10572 {
10573 const char
10574 *const PasteMenu[] =
10575 {
10576 "Operator",
10577 "Help",
10578 "Dismiss",
10579 (char *) NULL
10580 };
10581
10582 static const ModeType
10583 PasteCommands[] =
10584 {
10585 PasteOperatorsCommand,
10586 PasteHelpCommand,
10587 PasteDismissCommand
10588 };
10589
10590 static CompositeOperator
10591 compose = CopyCompositeOp;
10592
10593 char
10594 text[MagickPathExtent];
10595
10596 Cursor
10597 cursor;
10598
10599 Image
10600 *paste_image;
10601
10602 int
10603 entry,
10604 id,
10605 x,
10606 y;
10607
10608 double
10609 scale_factor;
10610
10611 RectangleInfo
10612 highlight_info,
10613 paste_info;
10614
10615 unsigned int
10616 height,
10617 width;
10618
10619 size_t
10620 state;
10621
10622 XEvent
10623 event;
10624
10625 /*
10626 Copy image.
10627 */
10628 if (resource_info->copy_image == (Image *) NULL)
10629 return(MagickFalse);
10630 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
10631 if (paste_image == (Image *) NULL)
10632 return(MagickFalse);
10633 /*
10634 Map Command widget.
10635 */
10636 (void) CloneString(&windows->command.name,"Paste");
10637 windows->command.data=1;
10638 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10639 (void) XMapRaised(display,windows->command.id);
10640 XClientMessage(display,windows->image.id,windows->im_protocols,
10641 windows->im_update_widget,CurrentTime);
10642 /*
10643 Track pointer until button 1 is pressed.
10644 */
10645 XSetCursorState(display,windows,MagickFalse);
10646 XQueryPosition(display,windows->image.id,&x,&y);
10647 (void) XSelectInput(display,windows->image.id,
10648 windows->image.attributes.event_mask | PointerMotionMask);
10649 paste_info.x=(ssize_t) windows->image.x+x;
10650 paste_info.y=(ssize_t) windows->image.y+y;
10651 paste_info.width=0;
10652 paste_info.height=0;
10653 cursor=XCreateFontCursor(display,XC_ul_angle);
10654 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10655 state=DefaultState;
10656 do
10657 {
10658 if (windows->info.mapped != MagickFalse)
10659 {
10660 /*
10661 Display pointer position.
10662 */
10663 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
10664 (long) paste_info.x,(long) paste_info.y);
10665 XInfoWidget(display,windows,text);
10666 }
10667 highlight_info=paste_info;
10668 highlight_info.x=paste_info.x-windows->image.x;
10669 highlight_info.y=paste_info.y-windows->image.y;
10670 XHighlightRectangle(display,windows->image.id,
10671 windows->image.highlight_context,&highlight_info);
10672 /*
10673 Wait for next event.
10674 */
10675 XScreenEvent(display,windows,&event,exception);
10676 XHighlightRectangle(display,windows->image.id,
10677 windows->image.highlight_context,&highlight_info);
10678 if (event.xany.window == windows->command.id)
10679 {
10680 /*
10681 Select a command from the Command widget.
10682 */
10683 id=XCommandWidget(display,windows,PasteMenu,&event);
10684 if (id < 0)
10685 continue;
10686 switch (PasteCommands[id])
10687 {
10688 case PasteOperatorsCommand:
10689 {
10690 char
10691 command[MagickPathExtent],
10692 **operators;
10693
10694 /*
10695 Select a command from the pop-up menu.
10696 */
10697 operators=GetCommandOptions(MagickComposeOptions);
10698 if (operators == (char **) NULL)
10699 break;
10700 entry=XMenuWidget(display,windows,PasteMenu[id],
10701 (const char **) operators,command);
10702 if (entry >= 0)
10703 compose=(CompositeOperator) ParseCommandOption(
10704 MagickComposeOptions,MagickFalse,operators[entry]);
10705 operators=DestroyStringList(operators);
10706 break;
10707 }
10708 case PasteHelpCommand:
10709 {
10710 XTextViewHelp(display,resource_info,windows,MagickFalse,
10711 "Help Viewer - Image Composite",ImagePasteHelp);
10712 break;
10713 }
10714 case PasteDismissCommand:
10715 {
10716 /*
10717 Prematurely exit.
10718 */
10719 state|=EscapeState;
10720 state|=ExitState;
10721 break;
10722 }
10723 default:
10724 break;
10725 }
10726 continue;
10727 }
10728 switch (event.type)
10729 {
10730 case ButtonPress:
10731 {
10732 if (image->debug != MagickFalse)
10733 (void) LogMagickEvent(X11Event,GetMagickModule(),
10734 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10735 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10736 if (event.xbutton.button != Button1)
10737 break;
10738 if (event.xbutton.window != windows->image.id)
10739 break;
10740 /*
10741 Paste rectangle is relative to image configuration.
10742 */
10743 width=(unsigned int) image->columns;
10744 height=(unsigned int) image->rows;
10745 x=0;
10746 y=0;
10747 if (windows->image.crop_geometry != (char *) NULL)
10748 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10749 &width,&height);
10750 scale_factor=(double) windows->image.ximage->width/width;
10751 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10752 scale_factor=(double) windows->image.ximage->height/height;
10753 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10754 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10755 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10756 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10757 break;
10758 }
10759 case ButtonRelease:
10760 {
10761 if (image->debug != MagickFalse)
10762 (void) LogMagickEvent(X11Event,GetMagickModule(),
10763 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10764 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10765 if (event.xbutton.button != Button1)
10766 break;
10767 if (event.xbutton.window != windows->image.id)
10768 break;
10769 if ((paste_info.width != 0) && (paste_info.height != 0))
10770 {
10771 /*
10772 User has selected the location of the paste image.
10773 */
10774 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10775 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10776 state|=ExitState;
10777 }
10778 break;
10779 }
10780 case Expose:
10781 break;
10782 case KeyPress:
10783 {
10784 char
10785 command[MagickPathExtent];
10786
10787 KeySym
10788 key_symbol;
10789
10790 int
10791 length;
10792
10793 if (event.xkey.window != windows->image.id)
10794 break;
10795 /*
10796 Respond to a user key press.
10797 */
10798 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10799 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10800 *(command+length)='\0';
10801 if (image->debug != MagickFalse)
10802 (void) LogMagickEvent(X11Event,GetMagickModule(),
10803 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10804 switch ((int) key_symbol)
10805 {
10806 case XK_Escape:
10807 case XK_F20:
10808 {
10809 /*
10810 Prematurely exit.
10811 */
10812 paste_image=DestroyImage(paste_image);
10813 state|=EscapeState;
10814 state|=ExitState;
10815 break;
10816 }
10817 case XK_F1:
10818 case XK_Help:
10819 {
10820 (void) XSetFunction(display,windows->image.highlight_context,
10821 GXcopy);
10822 XTextViewHelp(display,resource_info,windows,MagickFalse,
10823 "Help Viewer - Image Composite",ImagePasteHelp);
10824 (void) XSetFunction(display,windows->image.highlight_context,
10825 GXinvert);
10826 break;
10827 }
10828 default:
10829 {
10830 (void) XBell(display,0);
10831 break;
10832 }
10833 }
10834 break;
10835 }
10836 case MotionNotify:
10837 {
10838 /*
10839 Map and unmap Info widget as text cursor crosses its boundaries.
10840 */
10841 x=event.xmotion.x;
10842 y=event.xmotion.y;
10843 if (windows->info.mapped != MagickFalse)
10844 {
10845 if ((x < (int) (windows->info.x+windows->info.width)) &&
10846 (y < (int) (windows->info.y+windows->info.height)))
10847 (void) XWithdrawWindow(display,windows->info.id,
10848 windows->info.screen);
10849 }
10850 else
10851 if ((x > (int) (windows->info.x+windows->info.width)) ||
10852 (y > (int) (windows->info.y+windows->info.height)))
10853 (void) XMapWindow(display,windows->info.id);
10854 paste_info.x=(ssize_t) windows->image.x+x;
10855 paste_info.y=(ssize_t) windows->image.y+y;
10856 break;
10857 }
10858 default:
10859 {
10860 if (image->debug != MagickFalse)
10861 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10862 event.type);
10863 break;
10864 }
10865 }
10866 } while ((state & ExitState) == 0);
10867 (void) XSelectInput(display,windows->image.id,
10868 windows->image.attributes.event_mask);
10869 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10870 XSetCursorState(display,windows,MagickFalse);
10871 (void) XFreeCursor(display,cursor);
10872 if ((state & EscapeState) != 0)
10873 return(MagickTrue);
10874 /*
10875 Image pasting is relative to image configuration.
10876 */
10877 XSetCursorState(display,windows,MagickTrue);
10878 XCheckRefreshWindows(display,windows);
10879 width=(unsigned int) image->columns;
10880 height=(unsigned int) image->rows;
10881 x=0;
10882 y=0;
10883 if (windows->image.crop_geometry != (char *) NULL)
10884 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10885 scale_factor=(double) width/windows->image.ximage->width;
10886 paste_info.x+=x;
10887 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10888 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10889 scale_factor=(double) height/windows->image.ximage->height;
10890 paste_info.y+=y;
10891 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10892 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10893 /*
10894 Paste image with X Image window.
10895 */
10896 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
10897 paste_info.y,exception);
10898 paste_image=DestroyImage(paste_image);
10899 XSetCursorState(display,windows,MagickFalse);
10900 /*
10901 Update image colormap.
10902 */
10903 XConfigureImageColormap(display,resource_info,windows,image,exception);
10904 (void) XConfigureImage(display,resource_info,windows,image,exception);
10905 return(MagickTrue);
10906 }
10907
10908 /*
10909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10910 % %
10911 % %
10912 % %
10913 + X P r i n t I m a g e %
10914 % %
10915 % %
10916 % %
10917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10918 %
10919 % XPrintImage() prints an image to a Postscript printer.
10920 %
10921 % The format of the XPrintImage method is:
10922 %
10923 % MagickBooleanType XPrintImage(Display *display,
10924 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10925 % ExceptionInfo *exception)
10926 %
10927 % A description of each parameter follows:
10928 %
10929 % o display: Specifies a connection to an X server; returned from
10930 % XOpenDisplay.
10931 %
10932 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10933 %
10934 % o windows: Specifies a pointer to a XWindows structure.
10935 %
10936 % o image: the image.
10937 %
10938 % o exception: return any errors or warnings in this structure.
10939 %
10940 */
XPrintImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10941 static MagickBooleanType XPrintImage(Display *display,
10942 XResourceInfo *resource_info,XWindows *windows,Image *image,
10943 ExceptionInfo *exception)
10944 {
10945 char
10946 filename[MagickPathExtent],
10947 geometry[MagickPathExtent];
10948
10949 const char
10950 *const PageSizes[] =
10951 {
10952 "Letter",
10953 "Tabloid",
10954 "Ledger",
10955 "Legal",
10956 "Statement",
10957 "Executive",
10958 "A3",
10959 "A4",
10960 "A5",
10961 "B4",
10962 "B5",
10963 "Folio",
10964 "Quarto",
10965 "10x14",
10966 (char *) NULL
10967 };
10968
10969 Image
10970 *print_image;
10971
10972 ImageInfo
10973 *image_info;
10974
10975 MagickStatusType
10976 status;
10977
10978 /*
10979 Request Postscript page geometry from user.
10980 */
10981 image_info=CloneImageInfo(resource_info->image_info);
10982 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter");
10983 if (image_info->page != (char *) NULL)
10984 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
10985 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10986 "Select Postscript Page Geometry:",geometry);
10987 if (*geometry == '\0')
10988 return(MagickTrue);
10989 image_info->page=GetPageGeometry(geometry);
10990 /*
10991 Apply image transforms.
10992 */
10993 XSetCursorState(display,windows,MagickTrue);
10994 XCheckRefreshWindows(display,windows);
10995 print_image=CloneImage(image,0,0,MagickTrue,exception);
10996 if (print_image == (Image *) NULL)
10997 return(MagickFalse);
10998 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
10999 windows->image.ximage->width,windows->image.ximage->height);
11000 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11001 exception);
11002 /*
11003 Print image.
11004 */
11005 (void) AcquireUniqueFilename(filename);
11006 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s",
11007 filename);
11008 status=WriteImage(image_info,print_image,exception);
11009 (void) RelinquishUniqueFileResource(filename);
11010 print_image=DestroyImage(print_image);
11011 image_info=DestroyImageInfo(image_info);
11012 XSetCursorState(display,windows,MagickFalse);
11013 return(status != 0 ? MagickTrue : MagickFalse);
11014 }
11015
11016 /*
11017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11018 % %
11019 % %
11020 % %
11021 + X R O I I m a g e %
11022 % %
11023 % %
11024 % %
11025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11026 %
11027 % XROIImage() applies an image processing technique to a region of interest.
11028 %
11029 % The format of the XROIImage method is:
11030 %
11031 % MagickBooleanType XROIImage(Display *display,
11032 % XResourceInfo *resource_info,XWindows *windows,Image **image,
11033 % ExceptionInfo *exception)
11034 %
11035 % A description of each parameter follows:
11036 %
11037 % o display: Specifies a connection to an X server; returned from
11038 % XOpenDisplay.
11039 %
11040 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11041 %
11042 % o windows: Specifies a pointer to a XWindows structure.
11043 %
11044 % o image: the image; returned from ReadImage.
11045 %
11046 % o exception: return any errors or warnings in this structure.
11047 %
11048 */
XROIImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)11049 static MagickBooleanType XROIImage(Display *display,
11050 XResourceInfo *resource_info,XWindows *windows,Image **image,
11051 ExceptionInfo *exception)
11052 {
11053 #define ApplyMenus 7
11054
11055 const char
11056 *const ROIMenu[] =
11057 {
11058 "Help",
11059 "Dismiss",
11060 (char *) NULL
11061 },
11062 *const ApplyMenu[] =
11063 {
11064 "File",
11065 "Edit",
11066 "Transform",
11067 "Enhance",
11068 "Effects",
11069 "F/X",
11070 "Miscellany",
11071 "Help",
11072 "Dismiss",
11073 (char *) NULL
11074 },
11075 *const FileMenu[] =
11076 {
11077 "Save...",
11078 "Print...",
11079 (char *) NULL
11080 },
11081 *const EditMenu[] =
11082 {
11083 "Undo",
11084 "Redo",
11085 (char *) NULL
11086 },
11087 *const TransformMenu[] =
11088 {
11089 "Flop",
11090 "Flip",
11091 "Rotate Right",
11092 "Rotate Left",
11093 (char *) NULL
11094 },
11095 *const EnhanceMenu[] =
11096 {
11097 "Hue...",
11098 "Saturation...",
11099 "Brightness...",
11100 "Gamma...",
11101 "Spiff",
11102 "Dull",
11103 "Contrast Stretch...",
11104 "Sigmoidal Contrast...",
11105 "Normalize",
11106 "Equalize",
11107 "Negate",
11108 "Grayscale",
11109 "Map...",
11110 "Quantize...",
11111 (char *) NULL
11112 },
11113 *const EffectsMenu[] =
11114 {
11115 "Despeckle",
11116 "Emboss",
11117 "Reduce Noise",
11118 "Add Noise",
11119 "Sharpen...",
11120 "Blur...",
11121 "Threshold...",
11122 "Edge Detect...",
11123 "Spread...",
11124 "Shade...",
11125 "Raise...",
11126 "Segment...",
11127 (char *) NULL
11128 },
11129 *const FXMenu[] =
11130 {
11131 "Solarize...",
11132 "Sepia Tone...",
11133 "Swirl...",
11134 "Implode...",
11135 "Vignette...",
11136 "Wave...",
11137 "Oil Paint...",
11138 "Charcoal Draw...",
11139 (char *) NULL
11140 },
11141 *const MiscellanyMenu[] =
11142 {
11143 "Image Info",
11144 "Zoom Image",
11145 "Show Preview...",
11146 "Show Histogram",
11147 "Show Matte",
11148 (char *) NULL
11149 };
11150
11151 const char
11152 *const *Menus[ApplyMenus] =
11153 {
11154 FileMenu,
11155 EditMenu,
11156 TransformMenu,
11157 EnhanceMenu,
11158 EffectsMenu,
11159 FXMenu,
11160 MiscellanyMenu
11161 };
11162
11163 static const CommandType
11164 ApplyCommands[] =
11165 {
11166 NullCommand,
11167 NullCommand,
11168 NullCommand,
11169 NullCommand,
11170 NullCommand,
11171 NullCommand,
11172 NullCommand,
11173 HelpCommand,
11174 QuitCommand
11175 },
11176 FileCommands[] =
11177 {
11178 SaveCommand,
11179 PrintCommand
11180 },
11181 EditCommands[] =
11182 {
11183 UndoCommand,
11184 RedoCommand
11185 },
11186 TransformCommands[] =
11187 {
11188 FlopCommand,
11189 FlipCommand,
11190 RotateRightCommand,
11191 RotateLeftCommand
11192 },
11193 EnhanceCommands[] =
11194 {
11195 HueCommand,
11196 SaturationCommand,
11197 BrightnessCommand,
11198 GammaCommand,
11199 SpiffCommand,
11200 DullCommand,
11201 ContrastStretchCommand,
11202 SigmoidalContrastCommand,
11203 NormalizeCommand,
11204 EqualizeCommand,
11205 NegateCommand,
11206 GrayscaleCommand,
11207 MapCommand,
11208 QuantizeCommand
11209 },
11210 EffectsCommands[] =
11211 {
11212 DespeckleCommand,
11213 EmbossCommand,
11214 ReduceNoiseCommand,
11215 AddNoiseCommand,
11216 SharpenCommand,
11217 BlurCommand,
11218 EdgeDetectCommand,
11219 SpreadCommand,
11220 ShadeCommand,
11221 RaiseCommand,
11222 SegmentCommand
11223 },
11224 FXCommands[] =
11225 {
11226 SolarizeCommand,
11227 SepiaToneCommand,
11228 SwirlCommand,
11229 ImplodeCommand,
11230 VignetteCommand,
11231 WaveCommand,
11232 OilPaintCommand,
11233 CharcoalDrawCommand
11234 },
11235 MiscellanyCommands[] =
11236 {
11237 InfoCommand,
11238 ZoomCommand,
11239 ShowPreviewCommand,
11240 ShowHistogramCommand,
11241 ShowMatteCommand
11242 },
11243 ROICommands[] =
11244 {
11245 ROIHelpCommand,
11246 ROIDismissCommand
11247 };
11248
11249 static const CommandType
11250 *Commands[ApplyMenus] =
11251 {
11252 FileCommands,
11253 EditCommands,
11254 TransformCommands,
11255 EnhanceCommands,
11256 EffectsCommands,
11257 FXCommands,
11258 MiscellanyCommands
11259 };
11260
11261 char
11262 command[MagickPathExtent],
11263 text[MagickPathExtent];
11264
11265 CommandType
11266 command_type;
11267
11268 Cursor
11269 cursor;
11270
11271 Image
11272 *roi_image;
11273
11274 int
11275 entry,
11276 id,
11277 x,
11278 y;
11279
11280 double
11281 scale_factor;
11282
11283 MagickProgressMonitor
11284 progress_monitor;
11285
11286 RectangleInfo
11287 crop_info,
11288 highlight_info,
11289 roi_info;
11290
11291 unsigned int
11292 height,
11293 width;
11294
11295 size_t
11296 state;
11297
11298 XEvent
11299 event;
11300
11301 /*
11302 Map Command widget.
11303 */
11304 (void) CloneString(&windows->command.name,"ROI");
11305 windows->command.data=0;
11306 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11307 (void) XMapRaised(display,windows->command.id);
11308 XClientMessage(display,windows->image.id,windows->im_protocols,
11309 windows->im_update_widget,CurrentTime);
11310 /*
11311 Track pointer until button 1 is pressed.
11312 */
11313 XQueryPosition(display,windows->image.id,&x,&y);
11314 (void) XSelectInput(display,windows->image.id,
11315 windows->image.attributes.event_mask | PointerMotionMask);
11316 roi_info.x=(ssize_t) windows->image.x+x;
11317 roi_info.y=(ssize_t) windows->image.y+y;
11318 roi_info.width=0;
11319 roi_info.height=0;
11320 cursor=XCreateFontCursor(display,XC_fleur);
11321 state=DefaultState;
11322 do
11323 {
11324 if (windows->info.mapped != MagickFalse)
11325 {
11326 /*
11327 Display pointer position.
11328 */
11329 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
11330 (long) roi_info.x,(long) roi_info.y);
11331 XInfoWidget(display,windows,text);
11332 }
11333 /*
11334 Wait for next event.
11335 */
11336 XScreenEvent(display,windows,&event,exception);
11337 if (event.xany.window == windows->command.id)
11338 {
11339 /*
11340 Select a command from the Command widget.
11341 */
11342 id=XCommandWidget(display,windows,ROIMenu,&event);
11343 if (id < 0)
11344 continue;
11345 switch (ROICommands[id])
11346 {
11347 case ROIHelpCommand:
11348 {
11349 XTextViewHelp(display,resource_info,windows,MagickFalse,
11350 "Help Viewer - Region of Interest",ImageROIHelp);
11351 break;
11352 }
11353 case ROIDismissCommand:
11354 {
11355 /*
11356 Prematurely exit.
11357 */
11358 state|=EscapeState;
11359 state|=ExitState;
11360 break;
11361 }
11362 default:
11363 break;
11364 }
11365 continue;
11366 }
11367 switch (event.type)
11368 {
11369 case ButtonPress:
11370 {
11371 if (event.xbutton.button != Button1)
11372 break;
11373 if (event.xbutton.window != windows->image.id)
11374 break;
11375 /*
11376 Note first corner of region of interest rectangle-- exit loop.
11377 */
11378 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11379 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11380 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11381 state|=ExitState;
11382 break;
11383 }
11384 case ButtonRelease:
11385 break;
11386 case Expose:
11387 break;
11388 case KeyPress:
11389 {
11390 KeySym
11391 key_symbol;
11392
11393 if (event.xkey.window != windows->image.id)
11394 break;
11395 /*
11396 Respond to a user key press.
11397 */
11398 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11399 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11400 switch ((int) key_symbol)
11401 {
11402 case XK_Escape:
11403 case XK_F20:
11404 {
11405 /*
11406 Prematurely exit.
11407 */
11408 state|=EscapeState;
11409 state|=ExitState;
11410 break;
11411 }
11412 case XK_F1:
11413 case XK_Help:
11414 {
11415 XTextViewHelp(display,resource_info,windows,MagickFalse,
11416 "Help Viewer - Region of Interest",ImageROIHelp);
11417 break;
11418 }
11419 default:
11420 {
11421 (void) XBell(display,0);
11422 break;
11423 }
11424 }
11425 break;
11426 }
11427 case MotionNotify:
11428 {
11429 /*
11430 Map and unmap Info widget as text cursor crosses its boundaries.
11431 */
11432 x=event.xmotion.x;
11433 y=event.xmotion.y;
11434 if (windows->info.mapped != MagickFalse)
11435 {
11436 if ((x < (int) (windows->info.x+windows->info.width)) &&
11437 (y < (int) (windows->info.y+windows->info.height)))
11438 (void) XWithdrawWindow(display,windows->info.id,
11439 windows->info.screen);
11440 }
11441 else
11442 if ((x > (int) (windows->info.x+windows->info.width)) ||
11443 (y > (int) (windows->info.y+windows->info.height)))
11444 (void) XMapWindow(display,windows->info.id);
11445 roi_info.x=(ssize_t) windows->image.x+x;
11446 roi_info.y=(ssize_t) windows->image.y+y;
11447 break;
11448 }
11449 default:
11450 break;
11451 }
11452 } while ((state & ExitState) == 0);
11453 (void) XSelectInput(display,windows->image.id,
11454 windows->image.attributes.event_mask);
11455 if ((state & EscapeState) != 0)
11456 {
11457 /*
11458 User want to exit without region of interest.
11459 */
11460 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11461 (void) XFreeCursor(display,cursor);
11462 return(MagickTrue);
11463 }
11464 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11465 do
11466 {
11467 /*
11468 Size rectangle as pointer moves until the mouse button is released.
11469 */
11470 x=(int) roi_info.x;
11471 y=(int) roi_info.y;
11472 roi_info.width=0;
11473 roi_info.height=0;
11474 state=DefaultState;
11475 do
11476 {
11477 highlight_info=roi_info;
11478 highlight_info.x=roi_info.x-windows->image.x;
11479 highlight_info.y=roi_info.y-windows->image.y;
11480 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11481 {
11482 /*
11483 Display info and draw region of interest rectangle.
11484 */
11485 if (windows->info.mapped == MagickFalse)
11486 (void) XMapWindow(display,windows->info.id);
11487 (void) FormatLocaleString(text,MagickPathExtent,
11488 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11489 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11490 XInfoWidget(display,windows,text);
11491 XHighlightRectangle(display,windows->image.id,
11492 windows->image.highlight_context,&highlight_info);
11493 }
11494 else
11495 if (windows->info.mapped != MagickFalse)
11496 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11497 /*
11498 Wait for next event.
11499 */
11500 XScreenEvent(display,windows,&event,exception);
11501 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11502 XHighlightRectangle(display,windows->image.id,
11503 windows->image.highlight_context,&highlight_info);
11504 switch (event.type)
11505 {
11506 case ButtonPress:
11507 {
11508 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11509 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11510 break;
11511 }
11512 case ButtonRelease:
11513 {
11514 /*
11515 User has committed to region of interest rectangle.
11516 */
11517 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11518 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11519 XSetCursorState(display,windows,MagickFalse);
11520 state|=ExitState;
11521 if (LocaleCompare(windows->command.name,"Apply") == 0)
11522 break;
11523 (void) CloneString(&windows->command.name,"Apply");
11524 windows->command.data=ApplyMenus;
11525 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11526 break;
11527 }
11528 case Expose:
11529 break;
11530 case MotionNotify:
11531 {
11532 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11533 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11534 }
11535 default:
11536 break;
11537 }
11538 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11539 ((state & ExitState) != 0))
11540 {
11541 /*
11542 Check boundary conditions.
11543 */
11544 if (roi_info.x < 0)
11545 roi_info.x=0;
11546 else
11547 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11548 roi_info.x=(ssize_t) windows->image.ximage->width;
11549 if ((int) roi_info.x < x)
11550 roi_info.width=(unsigned int) (x-roi_info.x);
11551 else
11552 {
11553 roi_info.width=(unsigned int) (roi_info.x-x);
11554 roi_info.x=(ssize_t) x;
11555 }
11556 if (roi_info.y < 0)
11557 roi_info.y=0;
11558 else
11559 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11560 roi_info.y=(ssize_t) windows->image.ximage->height;
11561 if ((int) roi_info.y < y)
11562 roi_info.height=(unsigned int) (y-roi_info.y);
11563 else
11564 {
11565 roi_info.height=(unsigned int) (roi_info.y-y);
11566 roi_info.y=(ssize_t) y;
11567 }
11568 }
11569 } while ((state & ExitState) == 0);
11570 /*
11571 Wait for user to grab a corner of the rectangle or press return.
11572 */
11573 state=DefaultState;
11574 command_type=NullCommand;
11575 crop_info.x=0;
11576 crop_info.y=0;
11577 (void) XMapWindow(display,windows->info.id);
11578 do
11579 {
11580 if (windows->info.mapped != MagickFalse)
11581 {
11582 /*
11583 Display pointer position.
11584 */
11585 (void) FormatLocaleString(text,MagickPathExtent,
11586 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11587 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11588 XInfoWidget(display,windows,text);
11589 }
11590 highlight_info=roi_info;
11591 highlight_info.x=roi_info.x-windows->image.x;
11592 highlight_info.y=roi_info.y-windows->image.y;
11593 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11594 {
11595 state|=EscapeState;
11596 state|=ExitState;
11597 break;
11598 }
11599 if ((state & UpdateRegionState) != 0)
11600 {
11601 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11602 switch (command_type)
11603 {
11604 case UndoCommand:
11605 case RedoCommand:
11606 {
11607 (void) XMagickCommand(display,resource_info,windows,command_type,
11608 image,exception);
11609 break;
11610 }
11611 default:
11612 {
11613 /*
11614 Region of interest is relative to image configuration.
11615 */
11616 progress_monitor=SetImageProgressMonitor(*image,
11617 (MagickProgressMonitor) NULL,(*image)->client_data);
11618 crop_info=roi_info;
11619 width=(unsigned int) (*image)->columns;
11620 height=(unsigned int) (*image)->rows;
11621 x=0;
11622 y=0;
11623 if (windows->image.crop_geometry != (char *) NULL)
11624 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11625 &width,&height);
11626 scale_factor=(double) width/windows->image.ximage->width;
11627 crop_info.x+=x;
11628 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11629 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11630 scale_factor=(double)
11631 height/windows->image.ximage->height;
11632 crop_info.y+=y;
11633 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11634 crop_info.height=(unsigned int)
11635 (scale_factor*crop_info.height+0.5);
11636 roi_image=CropImage(*image,&crop_info,exception);
11637 (void) SetImageProgressMonitor(*image,progress_monitor,
11638 (*image)->client_data);
11639 if (roi_image == (Image *) NULL)
11640 continue;
11641 /*
11642 Apply image processing technique to the region of interest.
11643 */
11644 windows->image.orphan=MagickTrue;
11645 (void) XMagickCommand(display,resource_info,windows,command_type,
11646 &roi_image,exception);
11647 progress_monitor=SetImageProgressMonitor(*image,
11648 (MagickProgressMonitor) NULL,(*image)->client_data);
11649 (void) XMagickCommand(display,resource_info,windows,
11650 SaveToUndoBufferCommand,image,exception);
11651 windows->image.orphan=MagickFalse;
11652 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
11653 MagickTrue,crop_info.x,crop_info.y,exception);
11654 roi_image=DestroyImage(roi_image);
11655 (void) SetImageProgressMonitor(*image,progress_monitor,
11656 (*image)->client_data);
11657 break;
11658 }
11659 }
11660 if (command_type != InfoCommand)
11661 {
11662 XConfigureImageColormap(display,resource_info,windows,*image,
11663 exception);
11664 (void) XConfigureImage(display,resource_info,windows,*image,
11665 exception);
11666 }
11667 XCheckRefreshWindows(display,windows);
11668 XInfoWidget(display,windows,text);
11669 (void) XSetFunction(display,windows->image.highlight_context,
11670 GXinvert);
11671 state&=(~UpdateRegionState);
11672 }
11673 XHighlightRectangle(display,windows->image.id,
11674 windows->image.highlight_context,&highlight_info);
11675 XScreenEvent(display,windows,&event,exception);
11676 if (event.xany.window == windows->command.id)
11677 {
11678 /*
11679 Select a command from the Command widget.
11680 */
11681 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11682 command_type=NullCommand;
11683 id=XCommandWidget(display,windows,ApplyMenu,&event);
11684 if (id >= 0)
11685 {
11686 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent);
11687 command_type=ApplyCommands[id];
11688 if (id < ApplyMenus)
11689 {
11690 /*
11691 Select a command from a pop-up menu.
11692 */
11693 entry=XMenuWidget(display,windows,ApplyMenu[id],
11694 (const char **) Menus[id],command);
11695 if (entry >= 0)
11696 {
11697 (void) CopyMagickString(command,Menus[id][entry],
11698 MagickPathExtent);
11699 command_type=Commands[id][entry];
11700 }
11701 }
11702 }
11703 (void) XSetFunction(display,windows->image.highlight_context,
11704 GXinvert);
11705 XHighlightRectangle(display,windows->image.id,
11706 windows->image.highlight_context,&highlight_info);
11707 if (command_type == HelpCommand)
11708 {
11709 (void) XSetFunction(display,windows->image.highlight_context,
11710 GXcopy);
11711 XTextViewHelp(display,resource_info,windows,MagickFalse,
11712 "Help Viewer - Region of Interest",ImageROIHelp);
11713 (void) XSetFunction(display,windows->image.highlight_context,
11714 GXinvert);
11715 continue;
11716 }
11717 if (command_type == QuitCommand)
11718 {
11719 /*
11720 exit.
11721 */
11722 state|=EscapeState;
11723 state|=ExitState;
11724 continue;
11725 }
11726 if (command_type != NullCommand)
11727 state|=UpdateRegionState;
11728 continue;
11729 }
11730 XHighlightRectangle(display,windows->image.id,
11731 windows->image.highlight_context,&highlight_info);
11732 switch (event.type)
11733 {
11734 case ButtonPress:
11735 {
11736 x=windows->image.x;
11737 y=windows->image.y;
11738 if (event.xbutton.button != Button1)
11739 break;
11740 if (event.xbutton.window != windows->image.id)
11741 break;
11742 x=windows->image.x+event.xbutton.x;
11743 y=windows->image.y+event.xbutton.y;
11744 if ((x < (int) (roi_info.x+RoiDelta)) &&
11745 (x > (int) (roi_info.x-RoiDelta)) &&
11746 (y < (int) (roi_info.y+RoiDelta)) &&
11747 (y > (int) (roi_info.y-RoiDelta)))
11748 {
11749 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11750 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11751 state|=UpdateConfigurationState;
11752 break;
11753 }
11754 if ((x < (int) (roi_info.x+RoiDelta)) &&
11755 (x > (int) (roi_info.x-RoiDelta)) &&
11756 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11757 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11758 {
11759 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11760 state|=UpdateConfigurationState;
11761 break;
11762 }
11763 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11764 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11765 (y < (int) (roi_info.y+RoiDelta)) &&
11766 (y > (int) (roi_info.y-RoiDelta)))
11767 {
11768 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11769 state|=UpdateConfigurationState;
11770 break;
11771 }
11772 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11773 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11774 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11775 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11776 {
11777 state|=UpdateConfigurationState;
11778 break;
11779 }
11780 }
11781 case ButtonRelease:
11782 {
11783 if (event.xbutton.window == windows->pan.id)
11784 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11785 (highlight_info.y != crop_info.y-windows->image.y))
11786 XHighlightRectangle(display,windows->image.id,
11787 windows->image.highlight_context,&highlight_info);
11788 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11789 event.xbutton.time);
11790 break;
11791 }
11792 case Expose:
11793 {
11794 if (event.xexpose.window == windows->image.id)
11795 if (event.xexpose.count == 0)
11796 {
11797 event.xexpose.x=(int) highlight_info.x;
11798 event.xexpose.y=(int) highlight_info.y;
11799 event.xexpose.width=(int) highlight_info.width;
11800 event.xexpose.height=(int) highlight_info.height;
11801 XRefreshWindow(display,&windows->image,&event);
11802 }
11803 if (event.xexpose.window == windows->info.id)
11804 if (event.xexpose.count == 0)
11805 XInfoWidget(display,windows,text);
11806 break;
11807 }
11808 case KeyPress:
11809 {
11810 KeySym
11811 key_symbol;
11812
11813 if (event.xkey.window != windows->image.id)
11814 break;
11815 /*
11816 Respond to a user key press.
11817 */
11818 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11819 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11820 switch ((int) key_symbol)
11821 {
11822 case XK_Shift_L:
11823 case XK_Shift_R:
11824 break;
11825 case XK_Escape:
11826 case XK_F20:
11827 state|=EscapeState;
11828 case XK_Return:
11829 {
11830 state|=ExitState;
11831 break;
11832 }
11833 case XK_Home:
11834 case XK_KP_Home:
11835 {
11836 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11837 roi_info.y=(ssize_t) (windows->image.height/2L-
11838 roi_info.height/2L);
11839 break;
11840 }
11841 case XK_Left:
11842 case XK_KP_Left:
11843 {
11844 roi_info.x--;
11845 break;
11846 }
11847 case XK_Up:
11848 case XK_KP_Up:
11849 case XK_Next:
11850 {
11851 roi_info.y--;
11852 break;
11853 }
11854 case XK_Right:
11855 case XK_KP_Right:
11856 {
11857 roi_info.x++;
11858 break;
11859 }
11860 case XK_Prior:
11861 case XK_Down:
11862 case XK_KP_Down:
11863 {
11864 roi_info.y++;
11865 break;
11866 }
11867 case XK_F1:
11868 case XK_Help:
11869 {
11870 (void) XSetFunction(display,windows->image.highlight_context,
11871 GXcopy);
11872 XTextViewHelp(display,resource_info,windows,MagickFalse,
11873 "Help Viewer - Region of Interest",ImageROIHelp);
11874 (void) XSetFunction(display,windows->image.highlight_context,
11875 GXinvert);
11876 break;
11877 }
11878 default:
11879 {
11880 command_type=XImageWindowCommand(display,resource_info,windows,
11881 event.xkey.state,key_symbol,image,exception);
11882 if (command_type != NullCommand)
11883 state|=UpdateRegionState;
11884 break;
11885 }
11886 }
11887 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11888 event.xkey.time);
11889 break;
11890 }
11891 case KeyRelease:
11892 break;
11893 case MotionNotify:
11894 {
11895 if (event.xbutton.window != windows->image.id)
11896 break;
11897 /*
11898 Map and unmap Info widget as text cursor crosses its boundaries.
11899 */
11900 x=event.xmotion.x;
11901 y=event.xmotion.y;
11902 if (windows->info.mapped != MagickFalse)
11903 {
11904 if ((x < (int) (windows->info.x+windows->info.width)) &&
11905 (y < (int) (windows->info.y+windows->info.height)))
11906 (void) XWithdrawWindow(display,windows->info.id,
11907 windows->info.screen);
11908 }
11909 else
11910 if ((x > (int) (windows->info.x+windows->info.width)) ||
11911 (y > (int) (windows->info.y+windows->info.height)))
11912 (void) XMapWindow(display,windows->info.id);
11913 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11914 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11915 break;
11916 }
11917 case SelectionRequest:
11918 {
11919 XSelectionEvent
11920 notify;
11921
11922 XSelectionRequestEvent
11923 *request;
11924
11925 /*
11926 Set primary selection.
11927 */
11928 (void) FormatLocaleString(text,MagickPathExtent,
11929 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11930 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11931 request=(&(event.xselectionrequest));
11932 (void) XChangeProperty(request->display,request->requestor,
11933 request->property,request->target,8,PropModeReplace,
11934 (unsigned char *) text,(int) strlen(text));
11935 notify.type=SelectionNotify;
11936 notify.display=request->display;
11937 notify.requestor=request->requestor;
11938 notify.selection=request->selection;
11939 notify.target=request->target;
11940 notify.time=request->time;
11941 if (request->property == None)
11942 notify.property=request->target;
11943 else
11944 notify.property=request->property;
11945 (void) XSendEvent(request->display,request->requestor,False,0,
11946 (XEvent *) ¬ify);
11947 }
11948 default:
11949 break;
11950 }
11951 if ((state & UpdateConfigurationState) != 0)
11952 {
11953 (void) XPutBackEvent(display,&event);
11954 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11955 break;
11956 }
11957 } while ((state & ExitState) == 0);
11958 } while ((state & ExitState) == 0);
11959 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11960 XSetCursorState(display,windows,MagickFalse);
11961 if ((state & EscapeState) != 0)
11962 return(MagickTrue);
11963 return(MagickTrue);
11964 }
11965
11966 /*
11967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11968 % %
11969 % %
11970 % %
11971 + X R o t a t e I m a g e %
11972 % %
11973 % %
11974 % %
11975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11976 %
11977 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11978 % rotation angle is computed from the slope of a line drawn by the user.
11979 %
11980 % The format of the XRotateImage method is:
11981 %
11982 % MagickBooleanType XRotateImage(Display *display,
11983 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11984 % Image **image,ExceptionInfo *exception)
11985 %
11986 % A description of each parameter follows:
11987 %
11988 % o display: Specifies a connection to an X server; returned from
11989 % XOpenDisplay.
11990 %
11991 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11992 %
11993 % o windows: Specifies a pointer to a XWindows structure.
11994 %
11995 % o degrees: Specifies the number of degrees to rotate the image.
11996 %
11997 % o image: the image.
11998 %
11999 % o exception: return any errors or warnings in this structure.
12000 %
12001 */
XRotateImage(Display * display,XResourceInfo * resource_info,XWindows * windows,double degrees,Image ** image,ExceptionInfo * exception)12002 static MagickBooleanType XRotateImage(Display *display,
12003 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12004 ExceptionInfo *exception)
12005 {
12006 const char
12007 *const RotateMenu[] =
12008 {
12009 "Pixel Color",
12010 "Direction",
12011 "Help",
12012 "Dismiss",
12013 (char *) NULL
12014 };
12015
12016 static ModeType
12017 direction = HorizontalRotateCommand;
12018
12019 static const ModeType
12020 DirectionCommands[] =
12021 {
12022 HorizontalRotateCommand,
12023 VerticalRotateCommand
12024 },
12025 RotateCommands[] =
12026 {
12027 RotateColorCommand,
12028 RotateDirectionCommand,
12029 RotateHelpCommand,
12030 RotateDismissCommand
12031 };
12032
12033 static unsigned int
12034 pen_id = 0;
12035
12036 char
12037 command[MagickPathExtent],
12038 text[MagickPathExtent];
12039
12040 Image
12041 *rotate_image;
12042
12043 int
12044 id,
12045 x,
12046 y;
12047
12048 double
12049 normalized_degrees;
12050
12051 int
12052 i;
12053
12054 unsigned int
12055 height,
12056 rotations,
12057 width;
12058
12059 if (degrees == 0.0)
12060 {
12061 unsigned int
12062 distance;
12063
12064 size_t
12065 state;
12066
12067 XEvent
12068 event;
12069
12070 XSegment
12071 rotate_info;
12072
12073 /*
12074 Map Command widget.
12075 */
12076 (void) CloneString(&windows->command.name,"Rotate");
12077 windows->command.data=2;
12078 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12079 (void) XMapRaised(display,windows->command.id);
12080 XClientMessage(display,windows->image.id,windows->im_protocols,
12081 windows->im_update_widget,CurrentTime);
12082 /*
12083 Wait for first button press.
12084 */
12085 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12086 XQueryPosition(display,windows->image.id,&x,&y);
12087 rotate_info.x1=x;
12088 rotate_info.y1=y;
12089 rotate_info.x2=x;
12090 rotate_info.y2=y;
12091 state=DefaultState;
12092 do
12093 {
12094 XHighlightLine(display,windows->image.id,
12095 windows->image.highlight_context,&rotate_info);
12096 /*
12097 Wait for next event.
12098 */
12099 XScreenEvent(display,windows,&event,exception);
12100 XHighlightLine(display,windows->image.id,
12101 windows->image.highlight_context,&rotate_info);
12102 if (event.xany.window == windows->command.id)
12103 {
12104 /*
12105 Select a command from the Command widget.
12106 */
12107 id=XCommandWidget(display,windows,RotateMenu,&event);
12108 if (id < 0)
12109 continue;
12110 (void) XSetFunction(display,windows->image.highlight_context,
12111 GXcopy);
12112 switch (RotateCommands[id])
12113 {
12114 case RotateColorCommand:
12115 {
12116 const char
12117 *ColorMenu[MaxNumberPens];
12118
12119 int
12120 pen_number;
12121
12122 XColor
12123 color;
12124
12125 /*
12126 Initialize menu selections.
12127 */
12128 for (i=0; i < (int) (MaxNumberPens-2); i++)
12129 ColorMenu[i]=resource_info->pen_colors[i];
12130 ColorMenu[MaxNumberPens-2]="Browser...";
12131 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12132 /*
12133 Select a pen color from the pop-up menu.
12134 */
12135 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12136 (const char **) ColorMenu,command);
12137 if (pen_number < 0)
12138 break;
12139 if (pen_number == (MaxNumberPens-2))
12140 {
12141 static char
12142 color_name[MagickPathExtent] = "gray";
12143
12144 /*
12145 Select a pen color from a dialog.
12146 */
12147 resource_info->pen_colors[pen_number]=color_name;
12148 XColorBrowserWidget(display,windows,"Select",color_name);
12149 if (*color_name == '\0')
12150 break;
12151 }
12152 /*
12153 Set pen color.
12154 */
12155 (void) XParseColor(display,windows->map_info->colormap,
12156 resource_info->pen_colors[pen_number],&color);
12157 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12158 (unsigned int) MaxColors,&color);
12159 windows->pixel_info->pen_colors[pen_number]=color;
12160 pen_id=(unsigned int) pen_number;
12161 break;
12162 }
12163 case RotateDirectionCommand:
12164 {
12165 const char
12166 *Directions[] =
12167 {
12168 "horizontal",
12169 "vertical",
12170 (char *) NULL,
12171 };
12172
12173 /*
12174 Select a command from the pop-up menu.
12175 */
12176 id=XMenuWidget(display,windows,RotateMenu[id],
12177 Directions,command);
12178 if (id >= 0)
12179 direction=DirectionCommands[id];
12180 break;
12181 }
12182 case RotateHelpCommand:
12183 {
12184 XTextViewHelp(display,resource_info,windows,MagickFalse,
12185 "Help Viewer - Image Rotation",ImageRotateHelp);
12186 break;
12187 }
12188 case RotateDismissCommand:
12189 {
12190 /*
12191 Prematurely exit.
12192 */
12193 state|=EscapeState;
12194 state|=ExitState;
12195 break;
12196 }
12197 default:
12198 break;
12199 }
12200 (void) XSetFunction(display,windows->image.highlight_context,
12201 GXinvert);
12202 continue;
12203 }
12204 switch (event.type)
12205 {
12206 case ButtonPress:
12207 {
12208 if (event.xbutton.button != Button1)
12209 break;
12210 if (event.xbutton.window != windows->image.id)
12211 break;
12212 /*
12213 exit loop.
12214 */
12215 (void) XSetFunction(display,windows->image.highlight_context,
12216 GXcopy);
12217 rotate_info.x1=event.xbutton.x;
12218 rotate_info.y1=event.xbutton.y;
12219 state|=ExitState;
12220 break;
12221 }
12222 case ButtonRelease:
12223 break;
12224 case Expose:
12225 break;
12226 case KeyPress:
12227 {
12228 char
12229 command[MagickPathExtent];
12230
12231 KeySym
12232 key_symbol;
12233
12234 if (event.xkey.window != windows->image.id)
12235 break;
12236 /*
12237 Respond to a user key press.
12238 */
12239 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12240 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12241 switch ((int) key_symbol)
12242 {
12243 case XK_Escape:
12244 case XK_F20:
12245 {
12246 /*
12247 Prematurely exit.
12248 */
12249 state|=EscapeState;
12250 state|=ExitState;
12251 break;
12252 }
12253 case XK_F1:
12254 case XK_Help:
12255 {
12256 (void) XSetFunction(display,windows->image.highlight_context,
12257 GXcopy);
12258 XTextViewHelp(display,resource_info,windows,MagickFalse,
12259 "Help Viewer - Image Rotation",ImageRotateHelp);
12260 (void) XSetFunction(display,windows->image.highlight_context,
12261 GXinvert);
12262 break;
12263 }
12264 default:
12265 {
12266 (void) XBell(display,0);
12267 break;
12268 }
12269 }
12270 break;
12271 }
12272 case MotionNotify:
12273 {
12274 rotate_info.x1=event.xmotion.x;
12275 rotate_info.y1=event.xmotion.y;
12276 }
12277 }
12278 rotate_info.x2=rotate_info.x1;
12279 rotate_info.y2=rotate_info.y1;
12280 if (direction == HorizontalRotateCommand)
12281 rotate_info.x2+=32;
12282 else
12283 rotate_info.y2-=32;
12284 } while ((state & ExitState) == 0);
12285 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12286 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12287 if ((state & EscapeState) != 0)
12288 return(MagickTrue);
12289 /*
12290 Draw line as pointer moves until the mouse button is released.
12291 */
12292 distance=0;
12293 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12294 state=DefaultState;
12295 do
12296 {
12297 if (distance > 9)
12298 {
12299 /*
12300 Display info and draw rotation line.
12301 */
12302 if (windows->info.mapped == MagickFalse)
12303 (void) XMapWindow(display,windows->info.id);
12304 (void) FormatLocaleString(text,MagickPathExtent," %g",
12305 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12306 XInfoWidget(display,windows,text);
12307 XHighlightLine(display,windows->image.id,
12308 windows->image.highlight_context,&rotate_info);
12309 }
12310 else
12311 if (windows->info.mapped != MagickFalse)
12312 (void) XWithdrawWindow(display,windows->info.id,
12313 windows->info.screen);
12314 /*
12315 Wait for next event.
12316 */
12317 XScreenEvent(display,windows,&event,exception);
12318 if (distance > 9)
12319 XHighlightLine(display,windows->image.id,
12320 windows->image.highlight_context,&rotate_info);
12321 switch (event.type)
12322 {
12323 case ButtonPress:
12324 break;
12325 case ButtonRelease:
12326 {
12327 /*
12328 User has committed to rotation line.
12329 */
12330 rotate_info.x2=event.xbutton.x;
12331 rotate_info.y2=event.xbutton.y;
12332 state|=ExitState;
12333 break;
12334 }
12335 case Expose:
12336 break;
12337 case MotionNotify:
12338 {
12339 rotate_info.x2=event.xmotion.x;
12340 rotate_info.y2=event.xmotion.y;
12341 }
12342 default:
12343 break;
12344 }
12345 /*
12346 Check boundary conditions.
12347 */
12348 if (rotate_info.x2 < 0)
12349 rotate_info.x2=0;
12350 else
12351 if (rotate_info.x2 > (int) windows->image.width)
12352 rotate_info.x2=(short) windows->image.width;
12353 if (rotate_info.y2 < 0)
12354 rotate_info.y2=0;
12355 else
12356 if (rotate_info.y2 > (int) windows->image.height)
12357 rotate_info.y2=(short) windows->image.height;
12358 /*
12359 Compute rotation angle from the slope of the line.
12360 */
12361 degrees=0.0;
12362 distance=(unsigned int)
12363 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12364 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12365 if (distance > 9)
12366 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12367 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12368 } while ((state & ExitState) == 0);
12369 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12370 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12371 if (distance <= 9)
12372 return(MagickTrue);
12373 }
12374 if (direction == VerticalRotateCommand)
12375 degrees-=90.0;
12376 if (degrees == 0.0)
12377 return(MagickTrue);
12378 /*
12379 Rotate image.
12380 */
12381 normalized_degrees=degrees;
12382 while (normalized_degrees < -45.0)
12383 normalized_degrees+=360.0;
12384 for (rotations=0; normalized_degrees > 45.0; rotations++)
12385 normalized_degrees-=90.0;
12386 if (normalized_degrees != 0.0)
12387 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12388 exception);
12389 XSetCursorState(display,windows,MagickTrue);
12390 XCheckRefreshWindows(display,windows);
12391 (*image)->background_color.red=(double) ScaleShortToQuantum(
12392 windows->pixel_info->pen_colors[pen_id].red);
12393 (*image)->background_color.green=(double) ScaleShortToQuantum(
12394 windows->pixel_info->pen_colors[pen_id].green);
12395 (*image)->background_color.blue=(double) ScaleShortToQuantum(
12396 windows->pixel_info->pen_colors[pen_id].blue);
12397 rotate_image=RotateImage(*image,degrees,exception);
12398 XSetCursorState(display,windows,MagickFalse);
12399 if (rotate_image == (Image *) NULL)
12400 return(MagickFalse);
12401 *image=DestroyImage(*image);
12402 *image=rotate_image;
12403 if (windows->image.crop_geometry != (char *) NULL)
12404 {
12405 /*
12406 Rotate crop geometry.
12407 */
12408 width=(unsigned int) (*image)->columns;
12409 height=(unsigned int) (*image)->rows;
12410 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12411 switch (rotations % 4)
12412 {
12413 default:
12414 case 0:
12415 break;
12416 case 1:
12417 {
12418 /*
12419 Rotate 90 degrees.
12420 */
12421 (void) FormatLocaleString(windows->image.crop_geometry,
12422 MagickPathExtent,"%ux%u%+d%+d",height,width,(int) (*image)->columns-
12423 (int) height-y,x);
12424 break;
12425 }
12426 case 2:
12427 {
12428 /*
12429 Rotate 180 degrees.
12430 */
12431 (void) FormatLocaleString(windows->image.crop_geometry,
12432 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) width-x,(int)
12433 height-y);
12434 break;
12435 }
12436 case 3:
12437 {
12438 /*
12439 Rotate 270 degrees.
12440 */
12441 (void) FormatLocaleString(windows->image.crop_geometry,
12442 MagickPathExtent,"%ux%u%+d%+d",height,width,y,(int) (*image)->rows-
12443 (int) width-x);
12444 break;
12445 }
12446 }
12447 }
12448 if (windows->image.orphan != MagickFalse)
12449 return(MagickTrue);
12450 if (normalized_degrees != 0.0)
12451 {
12452 /*
12453 Update image colormap.
12454 */
12455 windows->image.window_changes.width=(int) (*image)->columns;
12456 windows->image.window_changes.height=(int) (*image)->rows;
12457 if (windows->image.crop_geometry != (char *) NULL)
12458 {
12459 /*
12460 Obtain dimensions of image from crop geometry.
12461 */
12462 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12463 &width,&height);
12464 windows->image.window_changes.width=(int) width;
12465 windows->image.window_changes.height=(int) height;
12466 }
12467 XConfigureImageColormap(display,resource_info,windows,*image,exception);
12468 }
12469 else
12470 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12471 {
12472 windows->image.window_changes.width=windows->image.ximage->height;
12473 windows->image.window_changes.height=windows->image.ximage->width;
12474 }
12475 /*
12476 Update image configuration.
12477 */
12478 (void) XConfigureImage(display,resource_info,windows,*image,exception);
12479 return(MagickTrue);
12480 }
12481
12482 /*
12483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12484 % %
12485 % %
12486 % %
12487 + X S a v e I m a g e %
12488 % %
12489 % %
12490 % %
12491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12492 %
12493 % XSaveImage() saves an image to a file.
12494 %
12495 % The format of the XSaveImage method is:
12496 %
12497 % MagickBooleanType XSaveImage(Display *display,
12498 % XResourceInfo *resource_info,XWindows *windows,Image *image,
12499 % ExceptionInfo *exception)
12500 %
12501 % A description of each parameter follows:
12502 %
12503 % o display: Specifies a connection to an X server; returned from
12504 % XOpenDisplay.
12505 %
12506 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12507 %
12508 % o windows: Specifies a pointer to a XWindows structure.
12509 %
12510 % o image: the image.
12511 %
12512 % o exception: return any errors or warnings in this structure.
12513 %
12514 */
XSaveImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)12515 static MagickBooleanType XSaveImage(Display *display,
12516 XResourceInfo *resource_info,XWindows *windows,Image *image,
12517 ExceptionInfo *exception)
12518 {
12519 char
12520 filename[MagickPathExtent],
12521 geometry[MagickPathExtent];
12522
12523 Image
12524 *save_image;
12525
12526 ImageInfo
12527 *image_info;
12528
12529 MagickStatusType
12530 status;
12531
12532 /*
12533 Request file name from user.
12534 */
12535 if (resource_info->write_filename != (char *) NULL)
12536 (void) CopyMagickString(filename,resource_info->write_filename,
12537 MagickPathExtent);
12538 else
12539 {
12540 char
12541 path[MagickPathExtent];
12542
12543 int
12544 status;
12545
12546 GetPathComponent(image->filename,HeadPath,path);
12547 GetPathComponent(image->filename,TailPath,filename);
12548 if (*path != '\0')
12549 {
12550 status=chdir(path);
12551 if (status == -1)
12552 (void) ThrowMagickException(exception,GetMagickModule(),
12553 FileOpenError,"UnableToOpenFile","%s",path);
12554 }
12555 }
12556 XFileBrowserWidget(display,windows,"Save",filename);
12557 if (*filename == '\0')
12558 return(MagickTrue);
12559 if (IsPathAccessible(filename) != MagickFalse)
12560 {
12561 int
12562 status;
12563
12564 /*
12565 File exists-- seek user's permission before overwriting.
12566 */
12567 status=XConfirmWidget(display,windows,"Overwrite",filename);
12568 if (status <= 0)
12569 return(MagickTrue);
12570 }
12571 image_info=CloneImageInfo(resource_info->image_info);
12572 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
12573 (void) SetImageInfo(image_info,1,exception);
12574 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12575 (LocaleCompare(image_info->magick,"JPG") == 0))
12576 {
12577 char
12578 quality[MagickPathExtent];
12579
12580 int
12581 status;
12582
12583 /*
12584 Request JPEG quality from user.
12585 */
12586 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
12587 image->quality);
12588 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12589 quality);
12590 if (*quality == '\0')
12591 return(MagickTrue);
12592 image->quality=StringToUnsignedLong(quality);
12593 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12594 }
12595 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12596 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12597 (LocaleCompare(image_info->magick,"PS") == 0) ||
12598 (LocaleCompare(image_info->magick,"PS2") == 0))
12599 {
12600 char
12601 geometry[MagickPathExtent];
12602
12603 const char
12604 *const PageSizes[] =
12605 {
12606 "Letter",
12607 "Tabloid",
12608 "Ledger",
12609 "Legal",
12610 "Statement",
12611 "Executive",
12612 "A3",
12613 "A4",
12614 "A5",
12615 "B4",
12616 "B5",
12617 "Folio",
12618 "Quarto",
12619 "10x14",
12620 (char *) NULL
12621 };
12622
12623 /*
12624 Request page geometry from user.
12625 */
12626 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12627 if (LocaleCompare(image_info->magick,"PDF") == 0)
12628 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12629 if (image_info->page != (char *) NULL)
12630 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
12631 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12632 "Select page geometry:",geometry);
12633 if (*geometry != '\0')
12634 image_info->page=GetPageGeometry(geometry);
12635 }
12636 /*
12637 Apply image transforms.
12638 */
12639 XSetCursorState(display,windows,MagickTrue);
12640 XCheckRefreshWindows(display,windows);
12641 save_image=CloneImage(image,0,0,MagickTrue,exception);
12642 if (save_image == (Image *) NULL)
12643 return(MagickFalse);
12644 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
12645 windows->image.ximage->width,windows->image.ximage->height);
12646 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12647 exception);
12648 /*
12649 Write image.
12650 */
12651 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent);
12652 status=WriteImage(image_info,save_image,exception);
12653 if (status != MagickFalse)
12654 image->taint=MagickFalse;
12655 save_image=DestroyImage(save_image);
12656 image_info=DestroyImageInfo(image_info);
12657 XSetCursorState(display,windows,MagickFalse);
12658 return(status != 0 ? MagickTrue : MagickFalse);
12659 }
12660
12661 /*
12662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12663 % %
12664 % %
12665 % %
12666 + X S c r e e n E v e n t %
12667 % %
12668 % %
12669 % %
12670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12671 %
12672 % XScreenEvent() handles global events associated with the Pan and Magnify
12673 % windows.
12674 %
12675 % The format of the XScreenEvent function is:
12676 %
12677 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12678 % ExceptionInfo *exception)
12679 %
12680 % A description of each parameter follows:
12681 %
12682 % o display: Specifies a pointer to the Display structure; returned from
12683 % XOpenDisplay.
12684 %
12685 % o windows: Specifies a pointer to a XWindows structure.
12686 %
12687 % o event: Specifies a pointer to a X11 XEvent structure.
12688 %
12689 % o exception: return any errors or warnings in this structure.
12690 %
12691 */
12692
12693 #if defined(__cplusplus) || defined(c_plusplus)
12694 extern "C" {
12695 #endif
12696
XPredicate(Display * magick_unused (display),XEvent * event,char * data)12697 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12698 {
12699 XWindows
12700 *windows;
12701
12702 windows=(XWindows *) data;
12703 if ((event->type == ClientMessage) &&
12704 (event->xclient.window == windows->image.id))
12705 return(MagickFalse);
12706 return(MagickTrue);
12707 }
12708
12709 #if defined(__cplusplus) || defined(c_plusplus)
12710 }
12711 #endif
12712
XScreenEvent(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)12713 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12714 ExceptionInfo *exception)
12715 {
12716 int
12717 x,
12718 y;
12719
12720 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12721 if (event->xany.window == windows->command.id)
12722 return;
12723 switch (event->type)
12724 {
12725 case ButtonPress:
12726 case ButtonRelease:
12727 {
12728 if ((event->xbutton.button == Button3) &&
12729 (event->xbutton.state & Mod1Mask))
12730 {
12731 /*
12732 Convert Alt-Button3 to Button2.
12733 */
12734 event->xbutton.button=Button2;
12735 event->xbutton.state&=(~Mod1Mask);
12736 }
12737 if (event->xbutton.window == windows->backdrop.id)
12738 {
12739 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12740 event->xbutton.time);
12741 break;
12742 }
12743 if (event->xbutton.window == windows->pan.id)
12744 {
12745 XPanImage(display,windows,event,exception);
12746 break;
12747 }
12748 if (event->xbutton.window == windows->image.id)
12749 if (event->xbutton.button == Button2)
12750 {
12751 /*
12752 Update magnified image.
12753 */
12754 x=event->xbutton.x;
12755 y=event->xbutton.y;
12756 if (x < 0)
12757 x=0;
12758 else
12759 if (x >= (int) windows->image.width)
12760 x=(int) (windows->image.width-1);
12761 windows->magnify.x=(int) windows->image.x+x;
12762 if (y < 0)
12763 y=0;
12764 else
12765 if (y >= (int) windows->image.height)
12766 y=(int) (windows->image.height-1);
12767 windows->magnify.y=windows->image.y+y;
12768 if (windows->magnify.mapped == MagickFalse)
12769 (void) XMapRaised(display,windows->magnify.id);
12770 XMakeMagnifyImage(display,windows,exception);
12771 if (event->type == ButtonRelease)
12772 (void) XWithdrawWindow(display,windows->info.id,
12773 windows->info.screen);
12774 break;
12775 }
12776 break;
12777 }
12778 case ClientMessage:
12779 {
12780 /*
12781 If client window delete message, exit.
12782 */
12783 if (event->xclient.message_type != windows->wm_protocols)
12784 break;
12785 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12786 break;
12787 if (event->xclient.window == windows->magnify.id)
12788 {
12789 (void) XWithdrawWindow(display,windows->magnify.id,
12790 windows->magnify.screen);
12791 break;
12792 }
12793 break;
12794 }
12795 case ConfigureNotify:
12796 {
12797 if (event->xconfigure.window == windows->magnify.id)
12798 {
12799 unsigned int
12800 magnify;
12801
12802 /*
12803 Magnify window has a new configuration.
12804 */
12805 windows->magnify.width=(unsigned int) event->xconfigure.width;
12806 windows->magnify.height=(unsigned int) event->xconfigure.height;
12807 if (windows->magnify.mapped == MagickFalse)
12808 break;
12809 magnify=1;
12810 while ((int) magnify <= event->xconfigure.width)
12811 magnify<<=1;
12812 while ((int) magnify <= event->xconfigure.height)
12813 magnify<<=1;
12814 magnify>>=1;
12815 if (((int) magnify != event->xconfigure.width) ||
12816 ((int) magnify != event->xconfigure.height))
12817 {
12818 XWindowChanges
12819 window_changes;
12820
12821 window_changes.width=(int) magnify;
12822 window_changes.height=(int) magnify;
12823 (void) XReconfigureWMWindow(display,windows->magnify.id,
12824 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12825 &window_changes);
12826 break;
12827 }
12828 XMakeMagnifyImage(display,windows,exception);
12829 break;
12830 }
12831 break;
12832 }
12833 case Expose:
12834 {
12835 if (event->xexpose.window == windows->image.id)
12836 {
12837 XRefreshWindow(display,&windows->image,event);
12838 break;
12839 }
12840 if (event->xexpose.window == windows->pan.id)
12841 if (event->xexpose.count == 0)
12842 {
12843 XDrawPanRectangle(display,windows);
12844 break;
12845 }
12846 if (event->xexpose.window == windows->magnify.id)
12847 if (event->xexpose.count == 0)
12848 {
12849 XMakeMagnifyImage(display,windows,exception);
12850 break;
12851 }
12852 break;
12853 }
12854 case KeyPress:
12855 {
12856 char
12857 command[MagickPathExtent];
12858
12859 KeySym
12860 key_symbol;
12861
12862 if (event->xkey.window != windows->magnify.id)
12863 break;
12864 /*
12865 Respond to a user key press.
12866 */
12867 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12868 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12869 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12870 exception);
12871 break;
12872 }
12873 case MapNotify:
12874 {
12875 if (event->xmap.window == windows->magnify.id)
12876 {
12877 windows->magnify.mapped=MagickTrue;
12878 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12879 break;
12880 }
12881 if (event->xmap.window == windows->info.id)
12882 {
12883 windows->info.mapped=MagickTrue;
12884 break;
12885 }
12886 break;
12887 }
12888 case MotionNotify:
12889 {
12890 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12891 if (event->xmotion.window == windows->image.id)
12892 if (windows->magnify.mapped != MagickFalse)
12893 {
12894 /*
12895 Update magnified image.
12896 */
12897 x=event->xmotion.x;
12898 y=event->xmotion.y;
12899 if (x < 0)
12900 x=0;
12901 else
12902 if (x >= (int) windows->image.width)
12903 x=(int) (windows->image.width-1);
12904 windows->magnify.x=(int) windows->image.x+x;
12905 if (y < 0)
12906 y=0;
12907 else
12908 if (y >= (int) windows->image.height)
12909 y=(int) (windows->image.height-1);
12910 windows->magnify.y=windows->image.y+y;
12911 XMakeMagnifyImage(display,windows,exception);
12912 }
12913 break;
12914 }
12915 case UnmapNotify:
12916 {
12917 if (event->xunmap.window == windows->magnify.id)
12918 {
12919 windows->magnify.mapped=MagickFalse;
12920 break;
12921 }
12922 if (event->xunmap.window == windows->info.id)
12923 {
12924 windows->info.mapped=MagickFalse;
12925 break;
12926 }
12927 break;
12928 }
12929 default:
12930 break;
12931 }
12932 }
12933
12934 /*
12935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12936 % %
12937 % %
12938 % %
12939 + X S e t C r o p G e o m e t r y %
12940 % %
12941 % %
12942 % %
12943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12944 %
12945 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12946 % and translates it to a cropping geometry relative to the image.
12947 %
12948 % The format of the XSetCropGeometry method is:
12949 %
12950 % void XSetCropGeometry(Display *display,XWindows *windows,
12951 % RectangleInfo *crop_info,Image *image)
12952 %
12953 % A description of each parameter follows:
12954 %
12955 % o display: Specifies a connection to an X server; returned from
12956 % XOpenDisplay.
12957 %
12958 % o windows: Specifies a pointer to a XWindows structure.
12959 %
12960 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12961 % Image window to crop.
12962 %
12963 % o image: the image.
12964 %
12965 */
XSetCropGeometry(Display * display,XWindows * windows,RectangleInfo * crop_info,Image * image)12966 static void XSetCropGeometry(Display *display,XWindows *windows,
12967 RectangleInfo *crop_info,Image *image)
12968 {
12969 char
12970 text[MagickPathExtent];
12971
12972 int
12973 x,
12974 y;
12975
12976 double
12977 scale_factor;
12978
12979 unsigned int
12980 height,
12981 width;
12982
12983 if (windows->info.mapped != MagickFalse)
12984 {
12985 /*
12986 Display info on cropping rectangle.
12987 */
12988 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g",
12989 (double) crop_info->width,(double) crop_info->height,(double)
12990 crop_info->x,(double) crop_info->y);
12991 XInfoWidget(display,windows,text);
12992 }
12993 /*
12994 Cropping geometry is relative to any previous crop geometry.
12995 */
12996 x=0;
12997 y=0;
12998 width=(unsigned int) image->columns;
12999 height=(unsigned int) image->rows;
13000 if (windows->image.crop_geometry != (char *) NULL)
13001 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13002 else
13003 windows->image.crop_geometry=AcquireString((char *) NULL);
13004 /*
13005 Define the crop geometry string from the cropping rectangle.
13006 */
13007 scale_factor=(double) width/windows->image.ximage->width;
13008 if (crop_info->x > 0)
13009 x+=(int) (scale_factor*crop_info->x+0.5);
13010 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13011 if (width == 0)
13012 width=1;
13013 scale_factor=(double) height/windows->image.ximage->height;
13014 if (crop_info->y > 0)
13015 y+=(int) (scale_factor*crop_info->y+0.5);
13016 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13017 if (height == 0)
13018 height=1;
13019 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
13020 "%ux%u%+d%+d",width,height,x,y);
13021 }
13022
13023 /*
13024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13025 % %
13026 % %
13027 % %
13028 + X T i l e I m a g e %
13029 % %
13030 % %
13031 % %
13032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13033 %
13034 % XTileImage() loads or deletes a selected tile from a visual image directory.
13035 % The load or delete command is chosen from a menu.
13036 %
13037 % The format of the XTileImage method is:
13038 %
13039 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
13040 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13041 %
13042 % A description of each parameter follows:
13043 %
13044 % o tile_image: XTileImage reads or deletes the tile image
13045 % and returns it. A null image is returned if an error occurs.
13046 %
13047 % o display: Specifies a connection to an X server; returned from
13048 % XOpenDisplay.
13049 %
13050 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13051 %
13052 % o windows: Specifies a pointer to a XWindows structure.
13053 %
13054 % o image: the image; returned from ReadImage.
13055 %
13056 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
13057 % the entire image is refreshed.
13058 %
13059 % o exception: return any errors or warnings in this structure.
13060 %
13061 */
XTileImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,XEvent * event,ExceptionInfo * exception)13062 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
13063 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13064 {
13065 const char
13066 *const VerbMenu[] =
13067 {
13068 "Load",
13069 "Next",
13070 "Former",
13071 "Delete",
13072 "Update",
13073 (char *) NULL,
13074 };
13075
13076 static const ModeType
13077 TileCommands[] =
13078 {
13079 TileLoadCommand,
13080 TileNextCommand,
13081 TileFormerCommand,
13082 TileDeleteCommand,
13083 TileUpdateCommand
13084 };
13085
13086 char
13087 command[MagickPathExtent],
13088 filename[MagickPathExtent];
13089
13090 Image
13091 *tile_image;
13092
13093 int
13094 id,
13095 status,
13096 tile,
13097 x,
13098 y;
13099
13100 double
13101 scale_factor;
13102
13103 char
13104 *p,
13105 *q;
13106
13107 int
13108 i;
13109
13110 unsigned int
13111 height,
13112 width;
13113
13114 /*
13115 Tile image is relative to montage image configuration.
13116 */
13117 x=0;
13118 y=0;
13119 width=(unsigned int) image->columns;
13120 height=(unsigned int) image->rows;
13121 if (windows->image.crop_geometry != (char *) NULL)
13122 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13123 scale_factor=(double) width/windows->image.ximage->width;
13124 event->xbutton.x+=windows->image.x;
13125 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13126 scale_factor=(double) height/windows->image.ximage->height;
13127 event->xbutton.y+=windows->image.y;
13128 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13129 /*
13130 Determine size and location of each tile in the visual image directory.
13131 */
13132 width=(unsigned int) image->columns;
13133 height=(unsigned int) image->rows;
13134 x=0;
13135 y=0;
13136 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13137 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13138 (event->xbutton.x-x)/width;
13139 if (tile < 0)
13140 {
13141 /*
13142 Button press is outside any tile.
13143 */
13144 (void) XBell(display,0);
13145 return((Image *) NULL);
13146 }
13147 /*
13148 Determine file name from the tile directory.
13149 */
13150 p=image->directory;
13151 for (i=tile; (i != 0) && (*p != '\0'); )
13152 {
13153 if (*p == '\xff')
13154 i--;
13155 p++;
13156 }
13157 if (*p == '\0')
13158 {
13159 /*
13160 Button press is outside any tile.
13161 */
13162 (void) XBell(display,0);
13163 return((Image *) NULL);
13164 }
13165 /*
13166 Select a command from the pop-up menu.
13167 */
13168 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13169 if (id < 0)
13170 return((Image *) NULL);
13171 q=p;
13172 while ((*q != '\xff') && (*q != '\0'))
13173 q++;
13174 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13175 /*
13176 Perform command for the selected tile.
13177 */
13178 XSetCursorState(display,windows,MagickTrue);
13179 XCheckRefreshWindows(display,windows);
13180 tile_image=NewImageList();
13181 switch (TileCommands[id])
13182 {
13183 case TileLoadCommand:
13184 {
13185 /*
13186 Load tile image.
13187 */
13188 XCheckRefreshWindows(display,windows);
13189 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13190 MagickPathExtent);
13191 (void) CopyMagickString(resource_info->image_info->filename,filename,
13192 MagickPathExtent);
13193 tile_image=ReadImage(resource_info->image_info,exception);
13194 CatchException(exception);
13195 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13196 break;
13197 }
13198 case TileNextCommand:
13199 {
13200 /*
13201 Display next image.
13202 */
13203 XClientMessage(display,windows->image.id,windows->im_protocols,
13204 windows->im_next_image,CurrentTime);
13205 break;
13206 }
13207 case TileFormerCommand:
13208 {
13209 /*
13210 Display former image.
13211 */
13212 XClientMessage(display,windows->image.id,windows->im_protocols,
13213 windows->im_former_image,CurrentTime);
13214 break;
13215 }
13216 case TileDeleteCommand:
13217 {
13218 /*
13219 Delete tile image.
13220 */
13221 if (IsPathAccessible(filename) == MagickFalse)
13222 {
13223 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13224 break;
13225 }
13226 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13227 if (status <= 0)
13228 break;
13229 status=ShredFile(filename);
13230 if (status != MagickFalse)
13231 {
13232 XNoticeWidget(display,windows,"Unable to delete image file:",
13233 filename);
13234 break;
13235 }
13236 }
13237 case TileUpdateCommand:
13238 {
13239 int
13240 x_offset,
13241 y_offset;
13242
13243 PixelInfo
13244 pixel;
13245
13246 int
13247 j;
13248
13249 Quantum
13250 *s;
13251
13252 /*
13253 Ensure all the images exist.
13254 */
13255 tile=0;
13256 GetPixelInfo(image,&pixel);
13257 for (p=image->directory; *p != '\0'; p++)
13258 {
13259 CacheView
13260 *image_view;
13261
13262 q=p;
13263 while ((*q != '\xff') && (*q != '\0'))
13264 q++;
13265 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13266 p=q;
13267 if (IsPathAccessible(filename) != MagickFalse)
13268 {
13269 tile++;
13270 continue;
13271 }
13272 /*
13273 Overwrite tile with background color.
13274 */
13275 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13276 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13277 image_view=AcquireAuthenticCacheView(image,exception);
13278 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
13279 for (i=0; i < (int) height; i++)
13280 {
13281 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13282 y_offset+i,width,1,exception);
13283 if (s == (Quantum *) NULL)
13284 break;
13285 for (j=0; j < (int) width; j++)
13286 {
13287 SetPixelViaPixelInfo(image,&pixel,s);
13288 s+=GetPixelChannels(image);
13289 }
13290 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13291 break;
13292 }
13293 image_view=DestroyCacheView(image_view);
13294 tile++;
13295 }
13296 windows->image.window_changes.width=(int) image->columns;
13297 windows->image.window_changes.height=(int) image->rows;
13298 XConfigureImageColormap(display,resource_info,windows,image,exception);
13299 (void) XConfigureImage(display,resource_info,windows,image,exception);
13300 break;
13301 }
13302 default:
13303 break;
13304 }
13305 XSetCursorState(display,windows,MagickFalse);
13306 return(tile_image);
13307 }
13308
13309 /*
13310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13311 % %
13312 % %
13313 % %
13314 + X T r a n s l a t e I m a g e %
13315 % %
13316 % %
13317 % %
13318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13319 %
13320 % XTranslateImage() translates the image within an Image window by one pixel
13321 % as specified by the key symbol. If the image has a montage string the
13322 % translation is respect to the width and height contained within the string.
13323 %
13324 % The format of the XTranslateImage method is:
13325 %
13326 % void XTranslateImage(Display *display,XWindows *windows,
13327 % Image *image,const KeySym key_symbol)
13328 %
13329 % A description of each parameter follows:
13330 %
13331 % o display: Specifies a connection to an X server; returned from
13332 % XOpenDisplay.
13333 %
13334 % o windows: Specifies a pointer to a XWindows structure.
13335 %
13336 % o image: the image.
13337 %
13338 % o key_symbol: Specifies a KeySym which indicates which side of the image
13339 % to trim.
13340 %
13341 */
XTranslateImage(Display * display,XWindows * windows,Image * image,const KeySym key_symbol)13342 static void XTranslateImage(Display *display,XWindows *windows,
13343 Image *image,const KeySym key_symbol)
13344 {
13345 char
13346 text[MagickPathExtent];
13347
13348 int
13349 x,
13350 y;
13351
13352 unsigned int
13353 x_offset,
13354 y_offset;
13355
13356 /*
13357 User specified a pan position offset.
13358 */
13359 x_offset=windows->image.width;
13360 y_offset=windows->image.height;
13361 if (image->montage != (char *) NULL)
13362 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13363 switch ((int) key_symbol)
13364 {
13365 case XK_Home:
13366 case XK_KP_Home:
13367 {
13368 windows->image.x=(int) windows->image.width/2;
13369 windows->image.y=(int) windows->image.height/2;
13370 break;
13371 }
13372 case XK_Left:
13373 case XK_KP_Left:
13374 {
13375 windows->image.x-=x_offset;
13376 break;
13377 }
13378 case XK_Next:
13379 case XK_Up:
13380 case XK_KP_Up:
13381 {
13382 windows->image.y-=y_offset;
13383 break;
13384 }
13385 case XK_Right:
13386 case XK_KP_Right:
13387 {
13388 windows->image.x+=x_offset;
13389 break;
13390 }
13391 case XK_Prior:
13392 case XK_Down:
13393 case XK_KP_Down:
13394 {
13395 windows->image.y+=y_offset;
13396 break;
13397 }
13398 default:
13399 return;
13400 }
13401 /*
13402 Check boundary conditions.
13403 */
13404 if (windows->image.x < 0)
13405 windows->image.x=0;
13406 else
13407 if ((int) (windows->image.x+windows->image.width) >
13408 windows->image.ximage->width)
13409 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13410 if (windows->image.y < 0)
13411 windows->image.y=0;
13412 else
13413 if ((int) (windows->image.y+windows->image.height) >
13414 windows->image.ximage->height)
13415 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13416 /*
13417 Refresh Image window.
13418 */
13419 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
13420 windows->image.width,windows->image.height,windows->image.x,
13421 windows->image.y);
13422 XInfoWidget(display,windows,text);
13423 XCheckRefreshWindows(display,windows);
13424 XDrawPanRectangle(display,windows);
13425 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13426 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13427 }
13428
13429 /*
13430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13431 % %
13432 % %
13433 % %
13434 + X T r i m I m a g e %
13435 % %
13436 % %
13437 % %
13438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13439 %
13440 % XTrimImage() trims the edges from the Image window.
13441 %
13442 % The format of the XTrimImage method is:
13443 %
13444 % MagickBooleanType XTrimImage(Display *display,
13445 % XResourceInfo *resource_info,XWindows *windows,Image *image,
13446 % ExceptionInfo *exception)
13447 %
13448 % A description of each parameter follows:
13449 %
13450 % o display: Specifies a connection to an X server; returned from
13451 % XOpenDisplay.
13452 %
13453 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13454 %
13455 % o windows: Specifies a pointer to a XWindows structure.
13456 %
13457 % o image: the image.
13458 %
13459 % o exception: return any errors or warnings in this structure.
13460 %
13461 */
XTrimImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)13462 static MagickBooleanType XTrimImage(Display *display,
13463 XResourceInfo *resource_info,XWindows *windows,Image *image,
13464 ExceptionInfo *exception)
13465 {
13466 RectangleInfo
13467 trim_info;
13468
13469 int
13470 x,
13471 y;
13472
13473 size_t
13474 background,
13475 pixel;
13476
13477 /*
13478 Trim edges from image.
13479 */
13480 XSetCursorState(display,windows,MagickTrue);
13481 XCheckRefreshWindows(display,windows);
13482 /*
13483 Crop the left edge.
13484 */
13485 background=XGetPixel(windows->image.ximage,0,0);
13486 trim_info.width=(size_t) windows->image.ximage->width;
13487 for (x=0; x < windows->image.ximage->width; x++)
13488 {
13489 for (y=0; y < windows->image.ximage->height; y++)
13490 {
13491 pixel=XGetPixel(windows->image.ximage,x,y);
13492 if (pixel != background)
13493 break;
13494 }
13495 if (y < windows->image.ximage->height)
13496 break;
13497 }
13498 trim_info.x=(ssize_t) x;
13499 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13500 {
13501 XSetCursorState(display,windows,MagickFalse);
13502 return(MagickFalse);
13503 }
13504 /*
13505 Crop the right edge.
13506 */
13507 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13508 for (x=windows->image.ximage->width-1; x != 0; x--)
13509 {
13510 for (y=0; y < windows->image.ximage->height; y++)
13511 {
13512 pixel=XGetPixel(windows->image.ximage,x,y);
13513 if (pixel != background)
13514 break;
13515 }
13516 if (y < windows->image.ximage->height)
13517 break;
13518 }
13519 trim_info.width=(size_t) (x-trim_info.x+1);
13520 /*
13521 Crop the top edge.
13522 */
13523 background=XGetPixel(windows->image.ximage,0,0);
13524 trim_info.height=(size_t) windows->image.ximage->height;
13525 for (y=0; y < windows->image.ximage->height; y++)
13526 {
13527 for (x=0; x < windows->image.ximage->width; x++)
13528 {
13529 pixel=XGetPixel(windows->image.ximage,x,y);
13530 if (pixel != background)
13531 break;
13532 }
13533 if (x < windows->image.ximage->width)
13534 break;
13535 }
13536 trim_info.y=(ssize_t) y;
13537 /*
13538 Crop the bottom edge.
13539 */
13540 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13541 for (y=windows->image.ximage->height-1; y != 0; y--)
13542 {
13543 for (x=0; x < windows->image.ximage->width; x++)
13544 {
13545 pixel=XGetPixel(windows->image.ximage,x,y);
13546 if (pixel != background)
13547 break;
13548 }
13549 if (x < windows->image.ximage->width)
13550 break;
13551 }
13552 trim_info.height=(size_t) y-trim_info.y+1;
13553 if (((unsigned int) trim_info.width != windows->image.width) ||
13554 ((unsigned int) trim_info.height != windows->image.height))
13555 {
13556 /*
13557 Reconfigure Image window as defined by the trimming rectangle.
13558 */
13559 XSetCropGeometry(display,windows,&trim_info,image);
13560 windows->image.window_changes.width=(int) trim_info.width;
13561 windows->image.window_changes.height=(int) trim_info.height;
13562 (void) XConfigureImage(display,resource_info,windows,image,exception);
13563 }
13564 XSetCursorState(display,windows,MagickFalse);
13565 return(MagickTrue);
13566 }
13567
13568 /*
13569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13570 % %
13571 % %
13572 % %
13573 + X V i s u a l D i r e c t o r y I m a g e %
13574 % %
13575 % %
13576 % %
13577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13578 %
13579 % XVisualDirectoryImage() creates a Visual Image Directory.
13580 %
13581 % The format of the XVisualDirectoryImage method is:
13582 %
13583 % Image *XVisualDirectoryImage(Display *display,
13584 % XResourceInfo *resource_info,XWindows *windows,
13585 % ExceptionInfo *exception)
13586 %
13587 % A description of each parameter follows:
13588 %
13589 % o display: Specifies a connection to an X server; returned from
13590 % XOpenDisplay.
13591 %
13592 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13593 %
13594 % o windows: Specifies a pointer to a XWindows structure.
13595 %
13596 % o exception: return any errors or warnings in this structure.
13597 %
13598 */
XVisualDirectoryImage(Display * display,XResourceInfo * resource_info,XWindows * windows,ExceptionInfo * exception)13599 static Image *XVisualDirectoryImage(Display *display,
13600 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
13601 {
13602 #define TileImageTag "Scale/Image"
13603 #define XClientName "montage"
13604
13605 char
13606 **filelist;
13607
13608 Image
13609 *images,
13610 *montage_image,
13611 *next_image,
13612 *thumbnail_image;
13613
13614 ImageInfo
13615 *read_info;
13616
13617 int
13618 number_files;
13619
13620 MagickBooleanType
13621 backdrop;
13622
13623 MagickStatusType
13624 status;
13625
13626 MontageInfo
13627 *montage_info;
13628
13629 RectangleInfo
13630 geometry;
13631
13632 int
13633 i;
13634
13635 static char
13636 filename[MagickPathExtent] = "\0",
13637 filenames[MagickPathExtent] = "*";
13638
13639 XResourceInfo
13640 background_resources;
13641
13642 /*
13643 Request file name from user.
13644 */
13645 XFileBrowserWidget(display,windows,"Directory",filenames);
13646 if (*filenames == '\0')
13647 return((Image *) NULL);
13648 /*
13649 Expand the filenames.
13650 */
13651 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13652 if (filelist == (char **) NULL)
13653 {
13654 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13655 filenames);
13656 return((Image *) NULL);
13657 }
13658 number_files=1;
13659 filelist[0]=filenames;
13660 status=ExpandFilenames(&number_files,&filelist);
13661 if ((status == MagickFalse) || (number_files == 0))
13662 {
13663 if (number_files == 0)
13664 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13665 else
13666 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13667 filenames);
13668 return((Image *) NULL);
13669 }
13670 /*
13671 Set image background resources.
13672 */
13673 background_resources=(*resource_info);
13674 background_resources.window_id=AcquireString("");
13675 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent,
13676 "0x%lx",windows->image.id);
13677 background_resources.backdrop=MagickTrue;
13678 /*
13679 Read each image and convert them to a tile.
13680 */
13681 backdrop=((windows->visual_info->klass == TrueColor) ||
13682 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse;
13683 read_info=CloneImageInfo(resource_info->image_info);
13684 (void) SetImageOption(read_info,"jpeg:size","120x120");
13685 (void) CloneString(&read_info->size,DefaultTileGeometry);
13686 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13687 (void *) NULL);
13688 images=NewImageList();
13689 XSetCursorState(display,windows,MagickTrue);
13690 XCheckRefreshWindows(display,windows);
13691 for (i=0; i < (int) number_files; i++)
13692 {
13693 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
13694 filelist[i]=DestroyString(filelist[i]);
13695 *read_info->magick='\0';
13696 next_image=ReadImage(read_info,exception);
13697 CatchException(exception);
13698 if (next_image != (Image *) NULL)
13699 {
13700 (void) DeleteImageProperty(next_image,"label");
13701 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13702 read_info,next_image,DefaultTileLabel,exception),exception);
13703 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13704 exception);
13705 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13706 geometry.height,exception);
13707 if (thumbnail_image != (Image *) NULL)
13708 {
13709 next_image=DestroyImage(next_image);
13710 next_image=thumbnail_image;
13711 }
13712 if (backdrop)
13713 {
13714 (void) XDisplayBackgroundImage(display,&background_resources,
13715 next_image,exception);
13716 XSetCursorState(display,windows,MagickTrue);
13717 }
13718 AppendImageToList(&images,next_image);
13719 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13720 {
13721 MagickBooleanType
13722 proceed;
13723
13724 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13725 (MagickSizeType) number_files);
13726 if (proceed == MagickFalse)
13727 break;
13728 }
13729 }
13730 }
13731 filelist=(char **) RelinquishMagickMemory(filelist);
13732 if (images == (Image *) NULL)
13733 {
13734 read_info=DestroyImageInfo(read_info);
13735 XSetCursorState(display,windows,MagickFalse);
13736 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13737 return((Image *) NULL);
13738 }
13739 /*
13740 Create the Visual Image Directory.
13741 */
13742 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13743 montage_info->pointsize=10;
13744 if (resource_info->font != (char *) NULL)
13745 (void) CloneString(&montage_info->font,resource_info->font);
13746 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent);
13747 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13748 images),exception);
13749 images=DestroyImageList(images);
13750 montage_info=DestroyMontageInfo(montage_info);
13751 read_info=DestroyImageInfo(read_info);
13752 XSetCursorState(display,windows,MagickFalse);
13753 if (montage_image == (Image *) NULL)
13754 return(montage_image);
13755 XClientMessage(display,windows->image.id,windows->im_protocols,
13756 windows->im_next_image,CurrentTime);
13757 return(montage_image);
13758 }
13759
13760 /*
13761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13762 % %
13763 % %
13764 % %
13765 % X D i s p l a y B a c k g r o u n d I m a g e %
13766 % %
13767 % %
13768 % %
13769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13770 %
13771 % XDisplayBackgroundImage() displays an image in the background of a window.
13772 %
13773 % The format of the XDisplayBackgroundImage method is:
13774 %
13775 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13776 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13777 %
13778 % A description of each parameter follows:
13779 %
13780 % o display: Specifies a connection to an X server; returned from
13781 % XOpenDisplay.
13782 %
13783 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13784 %
13785 % o image: the image.
13786 %
13787 % o exception: return any errors or warnings in this structure.
13788 %
13789 */
XDisplayBackgroundImage(Display * display,XResourceInfo * resource_info,Image * image,ExceptionInfo * exception)13790 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13791 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13792 {
13793 char
13794 geometry[MagickPathExtent],
13795 visual_type[MagickPathExtent];
13796
13797 int
13798 height,
13799 status,
13800 width;
13801
13802 RectangleInfo
13803 geometry_info;
13804
13805 static XPixelInfo
13806 pixel;
13807
13808 static XStandardColormap
13809 *map_info;
13810
13811 static XVisualInfo
13812 *visual_info = (XVisualInfo *) NULL;
13813
13814 static XWindowInfo
13815 window_info;
13816
13817 size_t
13818 delay;
13819
13820 Window
13821 root_window;
13822
13823 XGCValues
13824 context_values;
13825
13826 XResourceInfo
13827 resources;
13828
13829 XWindowAttributes
13830 window_attributes;
13831
13832 /*
13833 Determine target window.
13834 */
13835 assert(image != (Image *) NULL);
13836 assert(image->signature == MagickCoreSignature);
13837 if (image->debug != MagickFalse)
13838 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13839 resources=(*resource_info);
13840 window_info.id=(Window) NULL;
13841 root_window=XRootWindow(display,XDefaultScreen(display));
13842 if (LocaleCompare(resources.window_id,"root") == 0)
13843 window_info.id=root_window;
13844 else
13845 {
13846 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13847 window_info.id=XWindowByID(display,root_window,
13848 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13849 if (window_info.id == (Window) NULL)
13850 window_info.id=XWindowByName(display,root_window,resources.window_id);
13851 }
13852 if (window_info.id == (Window) NULL)
13853 {
13854 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13855 resources.window_id);
13856 return(MagickFalse);
13857 }
13858 /*
13859 Determine window visual id.
13860 */
13861 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13862 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13863 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
13864 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13865 if (status != 0)
13866 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
13867 XVisualIDFromVisual(window_attributes.visual));
13868 if (visual_info == (XVisualInfo *) NULL)
13869 {
13870 /*
13871 Allocate standard colormap.
13872 */
13873 map_info=XAllocStandardColormap();
13874 if (map_info == (XStandardColormap *) NULL)
13875 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13876 image->filename);
13877 map_info->colormap=(Colormap) NULL;
13878 pixel.pixels=(unsigned long *) NULL;
13879 /*
13880 Initialize visual info.
13881 */
13882 resources.map_type=(char *) NULL;
13883 resources.visual_type=visual_type;
13884 visual_info=XBestVisualInfo(display,map_info,&resources);
13885 if (visual_info == (XVisualInfo *) NULL)
13886 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13887 resources.visual_type);
13888 /*
13889 Initialize window info.
13890 */
13891 window_info.ximage=(XImage *) NULL;
13892 window_info.matte_image=(XImage *) NULL;
13893 window_info.pixmap=(Pixmap) NULL;
13894 window_info.matte_pixmap=(Pixmap) NULL;
13895 }
13896 /*
13897 Free previous root colors.
13898 */
13899 if (window_info.id == root_window)
13900 (void) XDestroyWindowColors(display,root_window);
13901 /*
13902 Initialize Standard Colormap.
13903 */
13904 resources.colormap=SharedColormap;
13905 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13906 exception);
13907 /*
13908 Graphic context superclass.
13909 */
13910 context_values.background=pixel.foreground_color.pixel;
13911 context_values.foreground=pixel.background_color.pixel;
13912 pixel.annotate_context=XCreateGC(display,window_info.id,
13913 (size_t) (GCBackground | GCForeground),&context_values);
13914 if (pixel.annotate_context == (GC) NULL)
13915 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13916 image->filename);
13917 /*
13918 Initialize Image window attributes.
13919 */
13920 window_info.name=AcquireString("\0");
13921 window_info.icon_name=AcquireString("\0");
13922 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13923 &resources,&window_info);
13924 /*
13925 Create the X image.
13926 */
13927 window_info.width=(unsigned int) image->columns;
13928 window_info.height=(unsigned int) image->rows;
13929 if ((image->columns != window_info.width) ||
13930 (image->rows != window_info.height))
13931 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13932 image->filename);
13933 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
13934 window_attributes.width,window_attributes.height);
13935 geometry_info.width=window_info.width;
13936 geometry_info.height=window_info.height;
13937 geometry_info.x=(ssize_t) window_info.x;
13938 geometry_info.y=(ssize_t) window_info.y;
13939 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13940 &geometry_info.width,&geometry_info.height);
13941 window_info.width=(unsigned int) geometry_info.width;
13942 window_info.height=(unsigned int) geometry_info.height;
13943 window_info.x=(int) geometry_info.x;
13944 window_info.y=(int) geometry_info.y;
13945 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13946 window_info.height,exception);
13947 if (status == MagickFalse)
13948 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13949 image->filename);
13950 window_info.x=0;
13951 window_info.y=0;
13952 if (image->debug != MagickFalse)
13953 {
13954 (void) LogMagickEvent(X11Event,GetMagickModule(),
13955 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13956 (double) image->columns,(double) image->rows);
13957 if (image->colors != 0)
13958 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13959 image->colors);
13960 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13961 }
13962 /*
13963 Adjust image dimensions as specified by backdrop or geometry options.
13964 */
13965 width=(int) window_info.width;
13966 height=(int) window_info.height;
13967 if (resources.backdrop != MagickFalse)
13968 {
13969 /*
13970 Center image on window.
13971 */
13972 window_info.x=(window_attributes.width/2)-(window_info.ximage->width/2);
13973 window_info.y=(window_attributes.height/2)-(window_info.ximage->height/2);
13974 width=window_attributes.width;
13975 height=window_attributes.height;
13976 }
13977 if ((resources.image_geometry != (char *) NULL) &&
13978 (*resources.image_geometry != '\0'))
13979 {
13980 char
13981 default_geometry[MagickPathExtent];
13982
13983 int
13984 flags,
13985 gravity;
13986
13987 XSizeHints
13988 *size_hints;
13989
13990 /*
13991 User specified geometry.
13992 */
13993 size_hints=XAllocSizeHints();
13994 if (size_hints == (XSizeHints *) NULL)
13995 ThrowXWindowFatalException(ResourceLimitFatalError,
13996 "MemoryAllocationFailed",image->filename);
13997 size_hints->flags=0L;
13998 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d",
13999 width,height);
14000 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
14001 default_geometry,window_info.border_width,size_hints,&window_info.x,
14002 &window_info.y,&width,&height,&gravity);
14003 if (flags & (XValue | YValue))
14004 {
14005 width=window_attributes.width;
14006 height=window_attributes.height;
14007 }
14008 (void) XFree((void *) size_hints);
14009 }
14010 /*
14011 Create the X pixmap.
14012 */
14013 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14014 (unsigned int) height,window_info.depth);
14015 if (window_info.pixmap == (Pixmap) NULL)
14016 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14017 image->filename);
14018 /*
14019 Display pixmap on the window.
14020 */
14021 if (((unsigned int) width > window_info.width) ||
14022 ((unsigned int) height > window_info.height))
14023 (void) XFillRectangle(display,window_info.pixmap,
14024 window_info.annotate_context,0,0,(unsigned int) width,
14025 (unsigned int) height);
14026 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14027 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14028 window_info.width,(unsigned int) window_info.height);
14029 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14030 (void) XClearWindow(display,window_info.id);
14031 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14032 XDelay(display,delay == 0UL ? 10UL : delay);
14033 (void) XSync(display,MagickFalse);
14034 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14035 }
14036
14037 /*
14038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14039 % %
14040 % %
14041 % %
14042 + X D i s p l a y I m a g e %
14043 % %
14044 % %
14045 % %
14046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14047 %
14048 % XDisplayImage() displays an image via X11. A new image is created and
14049 % returned if the user interactively transforms the displayed image.
14050 %
14051 % The format of the XDisplayImage method is:
14052 %
14053 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14054 % char **argv,int argc,Image **image,size_t *state,
14055 % ExceptionInfo *exception)
14056 %
14057 % A description of each parameter follows:
14058 %
14059 % o nexus: Method XDisplayImage returns an image when the
14060 % user chooses 'Open Image' from the command menu or picks a tile
14061 % from the image directory. Otherwise a null image is returned.
14062 %
14063 % o display: Specifies a connection to an X server; returned from
14064 % XOpenDisplay.
14065 %
14066 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14067 %
14068 % o argv: Specifies the application's argument list.
14069 %
14070 % o argc: Specifies the number of arguments.
14071 %
14072 % o image: Specifies an address to an address of an Image structure;
14073 %
14074 % o exception: return any errors or warnings in this structure.
14075 %
14076 */
XDisplayImage(Display * display,XResourceInfo * resource_info,char ** argv,int argc,Image ** image,size_t * state,ExceptionInfo * exception)14077 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14078 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
14079 {
14080 #define MagnifySize 256 /* must be a power of 2 */
14081 #define MagickMenus 10
14082 #define MagickTitle "Commands"
14083
14084 const char
14085 *const CommandMenu[] =
14086 {
14087 "File",
14088 "Edit",
14089 "View",
14090 "Transform",
14091 "Enhance",
14092 "Effects",
14093 "F/X",
14094 "Image Edit",
14095 "Miscellany",
14096 "Help",
14097 (char *) NULL
14098 },
14099 *const FileMenu[] =
14100 {
14101 "Open...",
14102 "Next",
14103 "Former",
14104 "Select...",
14105 "Save...",
14106 "Print...",
14107 "Delete...",
14108 "New...",
14109 "Visual Directory...",
14110 "Quit",
14111 (char *) NULL
14112 },
14113 *const EditMenu[] =
14114 {
14115 "Undo",
14116 "Redo",
14117 "Cut",
14118 "Copy",
14119 "Paste",
14120 (char *) NULL
14121 },
14122 *const ViewMenu[] =
14123 {
14124 "Half Size",
14125 "Original Size",
14126 "Double Size",
14127 "Resize...",
14128 "Apply",
14129 "Refresh",
14130 "Restore",
14131 (char *) NULL
14132 },
14133 *const TransformMenu[] =
14134 {
14135 "Crop",
14136 "Chop",
14137 "Flop",
14138 "Flip",
14139 "Rotate Right",
14140 "Rotate Left",
14141 "Rotate...",
14142 "Shear...",
14143 "Roll...",
14144 "Trim Edges",
14145 (char *) NULL
14146 },
14147 *const EnhanceMenu[] =
14148 {
14149 "Hue...",
14150 "Saturation...",
14151 "Brightness...",
14152 "Gamma...",
14153 "Spiff",
14154 "Dull",
14155 "Contrast Stretch...",
14156 "Sigmoidal Contrast...",
14157 "Normalize",
14158 "Equalize",
14159 "Negate",
14160 "Grayscale",
14161 "Map...",
14162 "Quantize...",
14163 (char *) NULL
14164 },
14165 *const EffectsMenu[] =
14166 {
14167 "Despeckle",
14168 "Emboss",
14169 "Reduce Noise",
14170 "Add Noise...",
14171 "Sharpen...",
14172 "Blur...",
14173 "Threshold...",
14174 "Edge Detect...",
14175 "Spread...",
14176 "Shade...",
14177 "Raise...",
14178 "Segment...",
14179 (char *) NULL
14180 },
14181 *const FXMenu[] =
14182 {
14183 "Solarize...",
14184 "Sepia Tone...",
14185 "Swirl...",
14186 "Implode...",
14187 "Vignette...",
14188 "Wave...",
14189 "Oil Paint...",
14190 "Charcoal Draw...",
14191 (char *) NULL
14192 },
14193 *const ImageEditMenu[] =
14194 {
14195 "Annotate...",
14196 "Draw...",
14197 "Color...",
14198 "Matte...",
14199 "Composite...",
14200 "Add Border...",
14201 "Add Frame...",
14202 "Comment...",
14203 "Launch...",
14204 "Region of Interest...",
14205 (char *) NULL
14206 },
14207 *const MiscellanyMenu[] =
14208 {
14209 "Image Info",
14210 "Zoom Image",
14211 "Show Preview...",
14212 "Show Histogram",
14213 "Show Matte",
14214 "Background...",
14215 "Slide Show...",
14216 "Preferences...",
14217 (char *) NULL
14218 },
14219 *const HelpMenu[] =
14220 {
14221 "Overview",
14222 "Browse Documentation",
14223 "About Display",
14224 (char *) NULL
14225 },
14226 *const ShortCutsMenu[] =
14227 {
14228 "Next",
14229 "Former",
14230 "Open...",
14231 "Save...",
14232 "Print...",
14233 "Undo",
14234 "Restore",
14235 "Image Info",
14236 "Quit",
14237 (char *) NULL
14238 },
14239 *const VirtualMenu[] =
14240 {
14241 "Image Info",
14242 "Print",
14243 "Next",
14244 "Quit",
14245 (char *) NULL
14246 };
14247
14248 const char
14249 *const *Menus[MagickMenus] =
14250 {
14251 FileMenu,
14252 EditMenu,
14253 ViewMenu,
14254 TransformMenu,
14255 EnhanceMenu,
14256 EffectsMenu,
14257 FXMenu,
14258 ImageEditMenu,
14259 MiscellanyMenu,
14260 HelpMenu
14261 };
14262
14263 static CommandType
14264 CommandMenus[] =
14265 {
14266 NullCommand,
14267 NullCommand,
14268 NullCommand,
14269 NullCommand,
14270 NullCommand,
14271 NullCommand,
14272 NullCommand,
14273 NullCommand,
14274 NullCommand,
14275 NullCommand,
14276 },
14277 FileCommands[] =
14278 {
14279 OpenCommand,
14280 NextCommand,
14281 FormerCommand,
14282 SelectCommand,
14283 SaveCommand,
14284 PrintCommand,
14285 DeleteCommand,
14286 NewCommand,
14287 VisualDirectoryCommand,
14288 QuitCommand
14289 },
14290 EditCommands[] =
14291 {
14292 UndoCommand,
14293 RedoCommand,
14294 CutCommand,
14295 CopyCommand,
14296 PasteCommand
14297 },
14298 ViewCommands[] =
14299 {
14300 HalfSizeCommand,
14301 OriginalSizeCommand,
14302 DoubleSizeCommand,
14303 ResizeCommand,
14304 ApplyCommand,
14305 RefreshCommand,
14306 RestoreCommand
14307 },
14308 TransformCommands[] =
14309 {
14310 CropCommand,
14311 ChopCommand,
14312 FlopCommand,
14313 FlipCommand,
14314 RotateRightCommand,
14315 RotateLeftCommand,
14316 RotateCommand,
14317 ShearCommand,
14318 RollCommand,
14319 TrimCommand
14320 },
14321 EnhanceCommands[] =
14322 {
14323 HueCommand,
14324 SaturationCommand,
14325 BrightnessCommand,
14326 GammaCommand,
14327 SpiffCommand,
14328 DullCommand,
14329 ContrastStretchCommand,
14330 SigmoidalContrastCommand,
14331 NormalizeCommand,
14332 EqualizeCommand,
14333 NegateCommand,
14334 GrayscaleCommand,
14335 MapCommand,
14336 QuantizeCommand
14337 },
14338 EffectsCommands[] =
14339 {
14340 DespeckleCommand,
14341 EmbossCommand,
14342 ReduceNoiseCommand,
14343 AddNoiseCommand,
14344 SharpenCommand,
14345 BlurCommand,
14346 ThresholdCommand,
14347 EdgeDetectCommand,
14348 SpreadCommand,
14349 ShadeCommand,
14350 RaiseCommand,
14351 SegmentCommand
14352 },
14353 FXCommands[] =
14354 {
14355 SolarizeCommand,
14356 SepiaToneCommand,
14357 SwirlCommand,
14358 ImplodeCommand,
14359 VignetteCommand,
14360 WaveCommand,
14361 OilPaintCommand,
14362 CharcoalDrawCommand
14363 },
14364 ImageEditCommands[] =
14365 {
14366 AnnotateCommand,
14367 DrawCommand,
14368 ColorCommand,
14369 MatteCommand,
14370 CompositeCommand,
14371 AddBorderCommand,
14372 AddFrameCommand,
14373 CommentCommand,
14374 LaunchCommand,
14375 RegionofInterestCommand
14376 },
14377 MiscellanyCommands[] =
14378 {
14379 InfoCommand,
14380 ZoomCommand,
14381 ShowPreviewCommand,
14382 ShowHistogramCommand,
14383 ShowMatteCommand,
14384 BackgroundCommand,
14385 SlideShowCommand,
14386 PreferencesCommand
14387 },
14388 HelpCommands[] =
14389 {
14390 HelpCommand,
14391 BrowseDocumentationCommand,
14392 VersionCommand
14393 },
14394 ShortCutsCommands[] =
14395 {
14396 NextCommand,
14397 FormerCommand,
14398 OpenCommand,
14399 SaveCommand,
14400 PrintCommand,
14401 UndoCommand,
14402 RestoreCommand,
14403 InfoCommand,
14404 QuitCommand
14405 },
14406 VirtualCommands[] =
14407 {
14408 InfoCommand,
14409 PrintCommand,
14410 NextCommand,
14411 QuitCommand
14412 };
14413
14414 static CommandType
14415 *Commands[MagickMenus] =
14416 {
14417 FileCommands,
14418 EditCommands,
14419 ViewCommands,
14420 TransformCommands,
14421 EnhanceCommands,
14422 EffectsCommands,
14423 FXCommands,
14424 ImageEditCommands,
14425 MiscellanyCommands,
14426 HelpCommands
14427 };
14428
14429 char
14430 command[MagickPathExtent],
14431 *directory,
14432 geometry[MagickPathExtent],
14433 resource_name[MagickPathExtent];
14434
14435 CommandType
14436 command_type;
14437
14438 Image
14439 *display_image,
14440 *nexus;
14441
14442 int
14443 entry,
14444 id;
14445
14446 KeySym
14447 key_symbol;
14448
14449 MagickStatusType
14450 context_mask,
14451 status;
14452
14453 RectangleInfo
14454 geometry_info;
14455
14456 int
14457 i;
14458
14459 static char
14460 working_directory[MagickPathExtent];
14461
14462 static XPoint
14463 vid_info;
14464
14465 static XWindowInfo
14466 *magick_windows[MaxXWindows];
14467
14468 static unsigned int
14469 number_windows;
14470
14471 struct stat
14472 attributes;
14473
14474 time_t
14475 timer,
14476 timestamp,
14477 update_time;
14478
14479 unsigned int
14480 height,
14481 width;
14482
14483 size_t
14484 delay;
14485
14486 WarningHandler
14487 warning_handler;
14488
14489 Window
14490 root_window;
14491
14492 XClassHint
14493 *class_hints;
14494
14495 XEvent
14496 event;
14497
14498 XFontStruct
14499 *font_info;
14500
14501 XGCValues
14502 context_values;
14503
14504 XPixelInfo
14505 *icon_pixel,
14506 *pixel;
14507
14508 XResourceInfo
14509 *icon_resources;
14510
14511 XStandardColormap
14512 *icon_map,
14513 *map_info;
14514
14515 XVisualInfo
14516 *icon_visual,
14517 *visual_info;
14518
14519 XWindowChanges
14520 window_changes;
14521
14522 XWindows
14523 *windows;
14524
14525 XWMHints
14526 *manager_hints;
14527
14528 assert(image != (Image **) NULL);
14529 assert((*image)->signature == MagickCoreSignature);
14530 if ((*image)->debug != MagickFalse)
14531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14532 display_image=(*image);
14533 warning_handler=(WarningHandler) NULL;
14534 windows=XSetWindows((XWindows *) ~0);
14535 if (windows != (XWindows *) NULL)
14536 {
14537 int
14538 status;
14539
14540 if (*working_directory == '\0')
14541 (void) CopyMagickString(working_directory,".",MagickPathExtent);
14542 status=chdir(working_directory);
14543 if (status == -1)
14544 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14545 "UnableToOpenFile","%s",working_directory);
14546 warning_handler=resource_info->display_warnings ?
14547 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14548 warning_handler=resource_info->display_warnings ?
14549 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14550 }
14551 else
14552 {
14553 /*
14554 Allocate windows structure.
14555 */
14556 resource_info->colors=display_image->colors;
14557 windows=XSetWindows(XInitializeWindows(display,resource_info));
14558 if (windows == (XWindows *) NULL)
14559 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14560 (*image)->filename);
14561 /*
14562 Initialize window id's.
14563 */
14564 number_windows=0;
14565 magick_windows[number_windows++]=(&windows->icon);
14566 magick_windows[number_windows++]=(&windows->backdrop);
14567 magick_windows[number_windows++]=(&windows->image);
14568 magick_windows[number_windows++]=(&windows->info);
14569 magick_windows[number_windows++]=(&windows->command);
14570 magick_windows[number_windows++]=(&windows->widget);
14571 magick_windows[number_windows++]=(&windows->popup);
14572 magick_windows[number_windows++]=(&windows->magnify);
14573 magick_windows[number_windows++]=(&windows->pan);
14574 for (i=0; i < (int) number_windows; i++)
14575 magick_windows[i]->id=(Window) NULL;
14576 vid_info.x=0;
14577 vid_info.y=0;
14578 }
14579 /*
14580 Initialize font info.
14581 */
14582 if (windows->font_info != (XFontStruct *) NULL)
14583 (void) XFreeFont(display,windows->font_info);
14584 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14585 if (windows->font_info == (XFontStruct *) NULL)
14586 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14587 resource_info->font);
14588 /*
14589 Initialize Standard Colormap.
14590 */
14591 map_info=windows->map_info;
14592 icon_map=windows->icon_map;
14593 visual_info=windows->visual_info;
14594 icon_visual=windows->icon_visual;
14595 pixel=windows->pixel_info;
14596 icon_pixel=windows->icon_pixel;
14597 font_info=windows->font_info;
14598 icon_resources=windows->icon_resources;
14599 class_hints=windows->class_hints;
14600 manager_hints=windows->manager_hints;
14601 root_window=XRootWindow(display,visual_info->screen);
14602 nexus=NewImageList();
14603 if (display_image->debug != MagickFalse)
14604 {
14605 (void) LogMagickEvent(X11Event,GetMagickModule(),
14606 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14607 (double) display_image->scene,(double) display_image->columns,
14608 (double) display_image->rows);
14609 if (display_image->colors != 0)
14610 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14611 display_image->colors);
14612 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14613 display_image->magick);
14614 }
14615 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14616 map_info,pixel,exception);
14617 display_image->taint=MagickFalse;
14618 /*
14619 Initialize graphic context.
14620 */
14621 windows->context.id=(Window) NULL;
14622 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14623 resource_info,&windows->context);
14624 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14625 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14626 class_hints->res_class[0]=(char) LocaleUppercase((int)
14627 class_hints->res_class[0]);
14628 manager_hints->flags=InputHint | StateHint;
14629 manager_hints->input=MagickFalse;
14630 manager_hints->initial_state=WithdrawnState;
14631 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14632 &windows->context);
14633 if (display_image->debug != MagickFalse)
14634 (void) LogMagickEvent(X11Event,GetMagickModule(),
14635 "Window id: 0x%lx (context)",windows->context.id);
14636 context_values.background=pixel->background_color.pixel;
14637 context_values.font=font_info->fid;
14638 context_values.foreground=pixel->foreground_color.pixel;
14639 context_values.graphics_exposures=MagickFalse;
14640 context_mask=(MagickStatusType)
14641 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14642 if (pixel->annotate_context != (GC) NULL)
14643 (void) XFreeGC(display,pixel->annotate_context);
14644 pixel->annotate_context=XCreateGC(display,windows->context.id,
14645 context_mask,&context_values);
14646 if (pixel->annotate_context == (GC) NULL)
14647 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14648 display_image->filename);
14649 context_values.background=pixel->depth_color.pixel;
14650 if (pixel->widget_context != (GC) NULL)
14651 (void) XFreeGC(display,pixel->widget_context);
14652 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14653 &context_values);
14654 if (pixel->widget_context == (GC) NULL)
14655 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14656 display_image->filename);
14657 context_values.background=pixel->foreground_color.pixel;
14658 context_values.foreground=pixel->background_color.pixel;
14659 context_values.plane_mask=context_values.background ^
14660 context_values.foreground;
14661 if (pixel->highlight_context != (GC) NULL)
14662 (void) XFreeGC(display,pixel->highlight_context);
14663 pixel->highlight_context=XCreateGC(display,windows->context.id,
14664 (size_t) (context_mask | GCPlaneMask),&context_values);
14665 if (pixel->highlight_context == (GC) NULL)
14666 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14667 display_image->filename);
14668 (void) XDestroyWindow(display,windows->context.id);
14669 /*
14670 Initialize icon window.
14671 */
14672 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14673 icon_resources,&windows->icon);
14674 windows->icon.geometry=resource_info->icon_geometry;
14675 XBestIconSize(display,&windows->icon,display_image);
14676 windows->icon.attributes.colormap=XDefaultColormap(display,
14677 icon_visual->screen);
14678 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14679 manager_hints->flags=InputHint | StateHint;
14680 manager_hints->input=MagickFalse;
14681 manager_hints->initial_state=IconicState;
14682 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14683 &windows->icon);
14684 if (display_image->debug != MagickFalse)
14685 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14686 windows->icon.id);
14687 /*
14688 Initialize graphic context for icon window.
14689 */
14690 if (icon_pixel->annotate_context != (GC) NULL)
14691 (void) XFreeGC(display,icon_pixel->annotate_context);
14692 context_values.background=icon_pixel->background_color.pixel;
14693 context_values.foreground=icon_pixel->foreground_color.pixel;
14694 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14695 (size_t) (GCBackground | GCForeground),&context_values);
14696 if (icon_pixel->annotate_context == (GC) NULL)
14697 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14698 display_image->filename);
14699 windows->icon.annotate_context=icon_pixel->annotate_context;
14700 /*
14701 Initialize Image window.
14702 */
14703 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14704 &windows->image);
14705 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14706 if (resource_info->use_shared_memory == MagickFalse)
14707 windows->image.shared_memory=MagickFalse;
14708 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14709 {
14710 char
14711 *title;
14712
14713 title=InterpretImageProperties(resource_info->image_info,display_image,
14714 resource_info->title,exception);
14715 (void) CloneString(&windows->image.name,title);
14716 (void) CloneString(&windows->image.icon_name,title);
14717 title=DestroyString(title);
14718 }
14719 else
14720 {
14721 char
14722 filename[MagickPathExtent],
14723 window_name[MagickPathExtent];
14724
14725 /*
14726 Window name is the base of the filename.
14727 */
14728 GetPathComponent(display_image->magick_filename,TailPath,filename);
14729 if (display_image->scene == 0)
14730 (void) FormatLocaleString(window_name,MagickPathExtent,"%s: %s",
14731 MagickPackageName,filename);
14732 else
14733 (void) FormatLocaleString(window_name,MagickPathExtent,
14734 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14735 (double) display_image->scene,(double) GetImageListLength(
14736 display_image));
14737 (void) CloneString(&windows->image.name,window_name);
14738 (void) CloneString(&windows->image.icon_name,filename);
14739 }
14740 if (resource_info->immutable)
14741 windows->image.immutable=MagickTrue;
14742 windows->image.use_pixmap=resource_info->use_pixmap;
14743 windows->image.geometry=resource_info->image_geometry;
14744 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
14745 XDisplayWidth(display,visual_info->screen),
14746 XDisplayHeight(display,visual_info->screen));
14747 geometry_info.width=display_image->columns;
14748 geometry_info.height=display_image->rows;
14749 geometry_info.x=0;
14750 geometry_info.y=0;
14751 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14752 &geometry_info.width,&geometry_info.height);
14753 windows->image.width=(unsigned int) geometry_info.width;
14754 windows->image.height=(unsigned int) geometry_info.height;
14755 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14756 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14757 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14758 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14759 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14760 resource_info,&windows->backdrop);
14761 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14762 {
14763 /*
14764 Initialize backdrop window.
14765 */
14766 windows->backdrop.x=0;
14767 windows->backdrop.y=0;
14768 (void) CloneString(&windows->backdrop.name,"Backdrop");
14769 windows->backdrop.flags=(size_t) (USSize | USPosition);
14770 windows->backdrop.width=(unsigned int)
14771 XDisplayWidth(display,visual_info->screen);
14772 windows->backdrop.height=(unsigned int)
14773 XDisplayHeight(display,visual_info->screen);
14774 windows->backdrop.border_width=0;
14775 windows->backdrop.immutable=MagickTrue;
14776 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14777 ButtonReleaseMask;
14778 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14779 StructureNotifyMask;
14780 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14781 manager_hints->icon_window=windows->icon.id;
14782 manager_hints->input=MagickTrue;
14783 manager_hints->initial_state=resource_info->iconic ? IconicState :
14784 NormalState;
14785 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14786 &windows->backdrop);
14787 if (display_image->debug != MagickFalse)
14788 (void) LogMagickEvent(X11Event,GetMagickModule(),
14789 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14790 (void) XMapWindow(display,windows->backdrop.id);
14791 (void) XClearWindow(display,windows->backdrop.id);
14792 if (windows->image.id != (Window) NULL)
14793 {
14794 (void) XDestroyWindow(display,windows->image.id);
14795 windows->image.id=(Window) NULL;
14796 }
14797 /*
14798 Position image in the center the backdrop.
14799 */
14800 windows->image.flags|=USPosition;
14801 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14802 (windows->image.width/2);
14803 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14804 (windows->image.height/2);
14805 }
14806 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14807 manager_hints->icon_window=windows->icon.id;
14808 manager_hints->input=MagickTrue;
14809 manager_hints->initial_state=resource_info->iconic ? IconicState :
14810 NormalState;
14811 if (windows->group_leader.id != (Window) NULL)
14812 {
14813 /*
14814 Follow the leader.
14815 */
14816 manager_hints->flags|=WindowGroupHint;
14817 manager_hints->window_group=windows->group_leader.id;
14818 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14819 if (display_image->debug != MagickFalse)
14820 (void) LogMagickEvent(X11Event,GetMagickModule(),
14821 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14822 }
14823 XMakeWindow(display,
14824 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14825 argv,argc,class_hints,manager_hints,&windows->image);
14826 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14827 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14828 if (windows->group_leader.id != (Window) NULL)
14829 (void) XSetTransientForHint(display,windows->image.id,
14830 windows->group_leader.id);
14831 if (display_image->debug != MagickFalse)
14832 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14833 windows->image.id);
14834 /*
14835 Initialize Info widget.
14836 */
14837 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14838 &windows->info);
14839 (void) CloneString(&windows->info.name,"Info");
14840 (void) CloneString(&windows->info.icon_name,"Info");
14841 windows->info.border_width=1;
14842 windows->info.x=2;
14843 windows->info.y=2;
14844 windows->info.flags|=PPosition;
14845 windows->info.attributes.win_gravity=UnmapGravity;
14846 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14847 StructureNotifyMask;
14848 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14849 manager_hints->input=MagickFalse;
14850 manager_hints->initial_state=NormalState;
14851 manager_hints->window_group=windows->image.id;
14852 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14853 &windows->info);
14854 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14855 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14856 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14857 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14858 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14859 if (windows->image.mapped != MagickFalse)
14860 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14861 if (display_image->debug != MagickFalse)
14862 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14863 windows->info.id);
14864 /*
14865 Initialize Command widget.
14866 */
14867 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14868 resource_info,&windows->command);
14869 windows->command.data=MagickMenus;
14870 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14871 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
14872 resource_info->client_name);
14873 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14874 resource_name,"geometry",(char *) NULL);
14875 (void) CloneString(&windows->command.name,MagickTitle);
14876 windows->command.border_width=0;
14877 windows->command.flags|=PPosition;
14878 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14879 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14880 OwnerGrabButtonMask | StructureNotifyMask;
14881 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14882 manager_hints->input=MagickTrue;
14883 manager_hints->initial_state=NormalState;
14884 manager_hints->window_group=windows->image.id;
14885 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14886 &windows->command);
14887 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14888 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14889 HighlightHeight);
14890 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14891 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14892 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14893 if (windows->command.mapped != MagickFalse)
14894 (void) XMapRaised(display,windows->command.id);
14895 if (display_image->debug != MagickFalse)
14896 (void) LogMagickEvent(X11Event,GetMagickModule(),
14897 "Window id: 0x%lx (command)",windows->command.id);
14898 /*
14899 Initialize Widget window.
14900 */
14901 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14902 resource_info,&windows->widget);
14903 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
14904 resource_info->client_name);
14905 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14906 resource_name,"geometry",(char *) NULL);
14907 windows->widget.border_width=0;
14908 windows->widget.flags|=PPosition;
14909 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14910 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14911 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14912 StructureNotifyMask;
14913 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14914 manager_hints->input=MagickTrue;
14915 manager_hints->initial_state=NormalState;
14916 manager_hints->window_group=windows->image.id;
14917 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14918 &windows->widget);
14919 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14920 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14921 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14922 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14923 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14924 if (display_image->debug != MagickFalse)
14925 (void) LogMagickEvent(X11Event,GetMagickModule(),
14926 "Window id: 0x%lx (widget)",windows->widget.id);
14927 /*
14928 Initialize popup window.
14929 */
14930 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14931 resource_info,&windows->popup);
14932 windows->popup.border_width=0;
14933 windows->popup.flags|=PPosition;
14934 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14935 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14936 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14937 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14938 manager_hints->input=MagickTrue;
14939 manager_hints->initial_state=NormalState;
14940 manager_hints->window_group=windows->image.id;
14941 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14942 &windows->popup);
14943 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14944 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14945 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14946 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14947 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14948 if (display_image->debug != MagickFalse)
14949 (void) LogMagickEvent(X11Event,GetMagickModule(),
14950 "Window id: 0x%lx (pop up)",windows->popup.id);
14951 /*
14952 Initialize Magnify window and cursor.
14953 */
14954 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14955 resource_info,&windows->magnify);
14956 if (resource_info->use_shared_memory == MagickFalse)
14957 windows->magnify.shared_memory=MagickFalse;
14958 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify",
14959 resource_info->client_name);
14960 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14961 resource_name,"geometry",(char *) NULL);
14962 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,
14963 "Magnify %uX",resource_info->magnify);
14964 if (windows->magnify.cursor != (Cursor) NULL)
14965 (void) XFreeCursor(display,windows->magnify.cursor);
14966 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14967 map_info->colormap,resource_info->background_color,
14968 resource_info->foreground_color);
14969 if (windows->magnify.cursor == (Cursor) NULL)
14970 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14971 display_image->filename);
14972 windows->magnify.width=MagnifySize;
14973 windows->magnify.height=MagnifySize;
14974 windows->magnify.flags|=PPosition;
14975 windows->magnify.min_width=MagnifySize;
14976 windows->magnify.min_height=MagnifySize;
14977 windows->magnify.width_inc=MagnifySize;
14978 windows->magnify.height_inc=MagnifySize;
14979 windows->magnify.data=resource_info->magnify;
14980 windows->magnify.attributes.cursor=windows->magnify.cursor;
14981 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14982 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14983 StructureNotifyMask;
14984 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14985 manager_hints->input=MagickTrue;
14986 manager_hints->initial_state=NormalState;
14987 manager_hints->window_group=windows->image.id;
14988 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14989 &windows->magnify);
14990 if (display_image->debug != MagickFalse)
14991 (void) LogMagickEvent(X11Event,GetMagickModule(),
14992 "Window id: 0x%lx (magnify)",windows->magnify.id);
14993 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14994 /*
14995 Initialize panning window.
14996 */
14997 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14998 resource_info,&windows->pan);
14999 (void) CloneString(&windows->pan.name,"Pan Icon");
15000 windows->pan.width=windows->icon.width;
15001 windows->pan.height=windows->icon.height;
15002 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan",
15003 resource_info->client_name);
15004 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
15005 resource_name,"geometry",(char *) NULL);
15006 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
15007 &windows->pan.width,&windows->pan.height);
15008 windows->pan.flags|=PPosition;
15009 windows->pan.immutable=MagickTrue;
15010 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
15011 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15012 StructureNotifyMask;
15013 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15014 manager_hints->input=MagickFalse;
15015 manager_hints->initial_state=NormalState;
15016 manager_hints->window_group=windows->image.id;
15017 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15018 &windows->pan);
15019 if (display_image->debug != MagickFalse)
15020 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15021 windows->pan.id);
15022 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15023 if (windows->info.mapped != MagickFalse)
15024 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15025 if ((windows->image.mapped == MagickFalse) ||
15026 (windows->backdrop.id != (Window) NULL))
15027 (void) XMapWindow(display,windows->image.id);
15028 /*
15029 Set our progress monitor and warning handlers.
15030 */
15031 if (warning_handler == (WarningHandler) NULL)
15032 {
15033 warning_handler=resource_info->display_warnings ?
15034 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15035 warning_handler=resource_info->display_warnings ?
15036 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15037 }
15038 /*
15039 Initialize Image and Magnify X images.
15040 */
15041 windows->image.x=0;
15042 windows->image.y=0;
15043 windows->magnify.shape=MagickFalse;
15044 width=(unsigned int) display_image->columns;
15045 height=(unsigned int) display_image->rows;
15046 if ((display_image->columns != width) || (display_image->rows != height))
15047 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15048 display_image->filename);
15049 status=XMakeImage(display,resource_info,&windows->image,display_image,
15050 width,height,exception);
15051 if (status == MagickFalse)
15052 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15053 display_image->filename);
15054 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
15055 windows->magnify.width,windows->magnify.height,exception);
15056 if (status == MagickFalse)
15057 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15058 display_image->filename);
15059 if (windows->magnify.mapped != MagickFalse)
15060 (void) XMapRaised(display,windows->magnify.id);
15061 if (windows->pan.mapped != MagickFalse)
15062 (void) XMapRaised(display,windows->pan.id);
15063 windows->image.window_changes.width=(int) display_image->columns;
15064 windows->image.window_changes.height=(int) display_image->rows;
15065 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
15066 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15067 (void) XSync(display,MagickFalse);
15068 /*
15069 Respond to events.
15070 */
15071 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15072 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15073 update_time=0;
15074 if (resource_info->update != MagickFalse)
15075 {
15076 MagickBooleanType
15077 status;
15078
15079 /*
15080 Determine when file data was last modified.
15081 */
15082 status=GetPathAttributes(display_image->filename,&attributes);
15083 if (status != MagickFalse)
15084 update_time=attributes.st_mtime;
15085 }
15086 *state&=(~FormerImageState);
15087 *state&=(~MontageImageState);
15088 *state&=(~NextImageState);
15089 do
15090 {
15091 /*
15092 Handle a window event.
15093 */
15094 if (windows->image.mapped != MagickFalse)
15095 if ((display_image->delay != 0) || (resource_info->update != 0))
15096 {
15097 if (timer < GetMagickTime())
15098 {
15099 if (resource_info->update == MagickFalse)
15100 *state|=NextImageState | ExitState;
15101 else
15102 {
15103 MagickBooleanType
15104 status;
15105
15106 /*
15107 Determine if image file was modified.
15108 */
15109 status=GetPathAttributes(display_image->filename,&attributes);
15110 if (status != MagickFalse)
15111 if (update_time != attributes.st_mtime)
15112 {
15113 /*
15114 Redisplay image.
15115 */
15116 (void) FormatLocaleString(
15117 resource_info->image_info->filename,MagickPathExtent,
15118 "%s:%s",display_image->magick,
15119 display_image->filename);
15120 nexus=ReadImage(resource_info->image_info,exception);
15121 if (nexus != (Image *) NULL)
15122 *state|=NextImageState | ExitState;
15123 }
15124 delay=display_image->delay/MagickMax(
15125 display_image->ticks_per_second,1L);
15126 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15127 }
15128 }
15129 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15130 {
15131 /*
15132 Do not block if delay > 0.
15133 */
15134 XDelay(display,SuspendTime << 2);
15135 continue;
15136 }
15137 }
15138 timestamp=GetMagickTime();
15139 (void) XNextEvent(display,&event);
15140 if ((windows->image.stasis == MagickFalse) ||
15141 (windows->magnify.stasis == MagickFalse))
15142 {
15143 if ((GetMagickTime()-timestamp) > 0)
15144 {
15145 windows->image.stasis=MagickTrue;
15146 windows->magnify.stasis=MagickTrue;
15147 }
15148 }
15149 if (event.xany.window == windows->command.id)
15150 {
15151 /*
15152 Select a command from the Command widget.
15153 */
15154 id=XCommandWidget(display,windows,CommandMenu,&event);
15155 if (id < 0)
15156 continue;
15157 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
15158 command_type=CommandMenus[id];
15159 if (id < MagickMenus)
15160 {
15161 /*
15162 Select a command from a pop-up menu.
15163 */
15164 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15165 command);
15166 if (entry < 0)
15167 continue;
15168 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
15169 command_type=Commands[id][entry];
15170 }
15171 if (command_type != NullCommand)
15172 nexus=XMagickCommand(display,resource_info,windows,command_type,
15173 &display_image,exception);
15174 continue;
15175 }
15176 switch (event.type)
15177 {
15178 case ButtonPress:
15179 {
15180 if (display_image->debug != MagickFalse)
15181 (void) LogMagickEvent(X11Event,GetMagickModule(),
15182 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15183 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15184 if ((event.xbutton.button == Button3) &&
15185 (event.xbutton.state & Mod1Mask))
15186 {
15187 /*
15188 Convert Alt-Button3 to Button2.
15189 */
15190 event.xbutton.button=Button2;
15191 event.xbutton.state&=(~Mod1Mask);
15192 }
15193 if (event.xbutton.window == windows->backdrop.id)
15194 {
15195 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15196 event.xbutton.time);
15197 break;
15198 }
15199 if (event.xbutton.window == windows->image.id)
15200 {
15201 switch (event.xbutton.button)
15202 {
15203 case Button1:
15204 {
15205 if (resource_info->immutable)
15206 {
15207 /*
15208 Select a command from the Virtual menu.
15209 */
15210 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15211 command);
15212 if (entry >= 0)
15213 nexus=XMagickCommand(display,resource_info,windows,
15214 VirtualCommands[entry],&display_image,exception);
15215 break;
15216 }
15217 /*
15218 Map/unmap Command widget.
15219 */
15220 if (windows->command.mapped != MagickFalse)
15221 (void) XWithdrawWindow(display,windows->command.id,
15222 windows->command.screen);
15223 else
15224 {
15225 (void) XCommandWidget(display,windows,CommandMenu,
15226 (XEvent *) NULL);
15227 (void) XMapRaised(display,windows->command.id);
15228 }
15229 break;
15230 }
15231 case Button2:
15232 {
15233 /*
15234 User pressed the image magnify button.
15235 */
15236 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15237 &display_image,exception);
15238 XMagnifyImage(display,windows,&event,exception);
15239 break;
15240 }
15241 case Button3:
15242 {
15243 if (resource_info->immutable)
15244 {
15245 /*
15246 Select a command from the Virtual menu.
15247 */
15248 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15249 command);
15250 if (entry >= 0)
15251 nexus=XMagickCommand(display,resource_info,windows,
15252 VirtualCommands[entry],&display_image,exception);
15253 break;
15254 }
15255 if (display_image->montage != (char *) NULL)
15256 {
15257 /*
15258 Open or delete a tile from a visual image directory.
15259 */
15260 nexus=XTileImage(display,resource_info,windows,
15261 display_image,&event,exception);
15262 if (nexus != (Image *) NULL)
15263 *state|=MontageImageState | NextImageState | ExitState;
15264 vid_info.x=(short int) windows->image.x;
15265 vid_info.y=(short int) windows->image.y;
15266 break;
15267 }
15268 /*
15269 Select a command from the Short Cuts menu.
15270 */
15271 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15272 command);
15273 if (entry >= 0)
15274 nexus=XMagickCommand(display,resource_info,windows,
15275 ShortCutsCommands[entry],&display_image,exception);
15276 break;
15277 }
15278 case Button4:
15279 {
15280 /*
15281 Wheel up.
15282 */
15283 XTranslateImage(display,windows,*image,XK_Up);
15284 break;
15285 }
15286 case Button5:
15287 {
15288 /*
15289 Wheel down.
15290 */
15291 XTranslateImage(display,windows,*image,XK_Down);
15292 break;
15293 }
15294 default:
15295 break;
15296 }
15297 break;
15298 }
15299 if (event.xbutton.window == windows->magnify.id)
15300 {
15301 const char
15302 *const MagnifyMenu[] =
15303 {
15304 "2",
15305 "4",
15306 "5",
15307 "6",
15308 "7",
15309 "8",
15310 "9",
15311 "3",
15312 (char *) NULL,
15313 };
15314
15315 int
15316 factor;
15317
15318 static KeySym
15319 MagnifyCommands[] =
15320 {
15321 XK_2,
15322 XK_4,
15323 XK_5,
15324 XK_6,
15325 XK_7,
15326 XK_8,
15327 XK_9,
15328 XK_3
15329 };
15330
15331 /*
15332 Select a magnify factor from the pop-up menu.
15333 */
15334 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15335 if (factor >= 0)
15336 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15337 exception);
15338 break;
15339 }
15340 if (event.xbutton.window == windows->pan.id)
15341 {
15342 switch (event.xbutton.button)
15343 {
15344 case Button4:
15345 {
15346 /*
15347 Wheel up.
15348 */
15349 XTranslateImage(display,windows,*image,XK_Up);
15350 break;
15351 }
15352 case Button5:
15353 {
15354 /*
15355 Wheel down.
15356 */
15357 XTranslateImage(display,windows,*image,XK_Down);
15358 break;
15359 }
15360 default:
15361 {
15362 XPanImage(display,windows,&event,exception);
15363 break;
15364 }
15365 }
15366 break;
15367 }
15368 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15369 1L);
15370 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15371 break;
15372 }
15373 case ButtonRelease:
15374 {
15375 if (display_image->debug != MagickFalse)
15376 (void) LogMagickEvent(X11Event,GetMagickModule(),
15377 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15378 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15379 break;
15380 }
15381 case ClientMessage:
15382 {
15383 if (display_image->debug != MagickFalse)
15384 (void) LogMagickEvent(X11Event,GetMagickModule(),
15385 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15386 event.xclient.message_type,event.xclient.format,(unsigned long)
15387 event.xclient.data.l[0]);
15388 if (event.xclient.message_type == windows->im_protocols)
15389 {
15390 if (*event.xclient.data.l == (long) windows->im_update_widget)
15391 {
15392 (void) CloneString(&windows->command.name,MagickTitle);
15393 windows->command.data=MagickMenus;
15394 (void) XCommandWidget(display,windows,CommandMenu,
15395 (XEvent *) NULL);
15396 break;
15397 }
15398 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15399 {
15400 /*
15401 Update graphic context and window colormap.
15402 */
15403 for (i=0; i < (int) number_windows; i++)
15404 {
15405 if (magick_windows[i]->id == windows->icon.id)
15406 continue;
15407 context_values.background=pixel->background_color.pixel;
15408 context_values.foreground=pixel->foreground_color.pixel;
15409 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15410 context_mask,&context_values);
15411 (void) XChangeGC(display,magick_windows[i]->widget_context,
15412 context_mask,&context_values);
15413 context_values.background=pixel->foreground_color.pixel;
15414 context_values.foreground=pixel->background_color.pixel;
15415 context_values.plane_mask=context_values.background ^
15416 context_values.foreground;
15417 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15418 (size_t) (context_mask | GCPlaneMask),
15419 &context_values);
15420 magick_windows[i]->attributes.background_pixel=
15421 pixel->background_color.pixel;
15422 magick_windows[i]->attributes.border_pixel=
15423 pixel->border_color.pixel;
15424 magick_windows[i]->attributes.colormap=map_info->colormap;
15425 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15426 (unsigned long) magick_windows[i]->mask,
15427 &magick_windows[i]->attributes);
15428 }
15429 if (windows->pan.mapped != MagickFalse)
15430 {
15431 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15432 windows->pan.pixmap);
15433 (void) XClearWindow(display,windows->pan.id);
15434 XDrawPanRectangle(display,windows);
15435 }
15436 if (windows->backdrop.id != (Window) NULL)
15437 (void) XInstallColormap(display,map_info->colormap);
15438 break;
15439 }
15440 if (*event.xclient.data.l == (long) windows->im_former_image)
15441 {
15442 *state|=FormerImageState | ExitState;
15443 break;
15444 }
15445 if (*event.xclient.data.l == (long) windows->im_next_image)
15446 {
15447 *state|=NextImageState | ExitState;
15448 break;
15449 }
15450 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15451 {
15452 *state|=RetainColorsState;
15453 break;
15454 }
15455 if (*event.xclient.data.l == (long) windows->im_exit)
15456 {
15457 *state|=ExitState;
15458 break;
15459 }
15460 break;
15461 }
15462 if (event.xclient.message_type == windows->dnd_protocols)
15463 {
15464 Atom
15465 selection,
15466 type;
15467
15468 int
15469 format,
15470 status;
15471
15472 unsigned char
15473 *data;
15474
15475 unsigned long
15476 after,
15477 length;
15478
15479 /*
15480 Display image named by the Drag-and-Drop selection.
15481 */
15482 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15483 break;
15484 selection=XInternAtom(display,"DndSelection",MagickFalse);
15485 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15486 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15487 &length,&after,&data);
15488 if ((status != Success) || (length == 0))
15489 break;
15490 if (*event.xclient.data.l == 2)
15491 {
15492 /*
15493 Offix DND.
15494 */
15495 (void) CopyMagickString(resource_info->image_info->filename,
15496 (char *) data,MagickPathExtent);
15497 }
15498 else
15499 {
15500 /*
15501 XDND.
15502 */
15503 if (strncmp((char *) data, "file:", 5) != 0)
15504 {
15505 (void) XFree((void *) data);
15506 break;
15507 }
15508 (void) CopyMagickString(resource_info->image_info->filename,
15509 ((char *) data)+5,MagickPathExtent);
15510 }
15511 nexus=ReadImage(resource_info->image_info,exception);
15512 CatchException(exception);
15513 if (nexus != (Image *) NULL)
15514 *state|=NextImageState | ExitState;
15515 (void) XFree((void *) data);
15516 break;
15517 }
15518 /*
15519 If client window delete message, exit.
15520 */
15521 if (event.xclient.message_type != windows->wm_protocols)
15522 break;
15523 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15524 break;
15525 (void) XWithdrawWindow(display,event.xclient.window,
15526 visual_info->screen);
15527 if (event.xclient.window == windows->image.id)
15528 {
15529 *state|=ExitState;
15530 break;
15531 }
15532 if (event.xclient.window == windows->pan.id)
15533 {
15534 /*
15535 Restore original image size when pan window is deleted.
15536 */
15537 windows->image.window_changes.width=windows->image.ximage->width;
15538 windows->image.window_changes.height=windows->image.ximage->height;
15539 (void) XConfigureImage(display,resource_info,windows,
15540 display_image,exception);
15541 }
15542 break;
15543 }
15544 case ConfigureNotify:
15545 {
15546 if (display_image->debug != MagickFalse)
15547 (void) LogMagickEvent(X11Event,GetMagickModule(),
15548 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15549 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15550 event.xconfigure.y,event.xconfigure.send_event);
15551 if (event.xconfigure.window == windows->image.id)
15552 {
15553 /*
15554 Image window has a new configuration.
15555 */
15556 if (event.xconfigure.send_event != 0)
15557 {
15558 XWindowChanges
15559 window_changes;
15560
15561 /*
15562 Position the transient windows relative of the Image window.
15563 */
15564 if (windows->command.geometry == (char *) NULL)
15565 if (windows->command.mapped == MagickFalse)
15566 {
15567 windows->command.x=event.xconfigure.x-
15568 windows->command.width-25;
15569 windows->command.y=event.xconfigure.y;
15570 XConstrainWindowPosition(display,&windows->command);
15571 window_changes.x=windows->command.x;
15572 window_changes.y=windows->command.y;
15573 (void) XReconfigureWMWindow(display,windows->command.id,
15574 windows->command.screen,(unsigned int) (CWX | CWY),
15575 &window_changes);
15576 }
15577 if (windows->widget.geometry == (char *) NULL)
15578 if (windows->widget.mapped == MagickFalse)
15579 {
15580 windows->widget.x=event.xconfigure.x+
15581 event.xconfigure.width/10;
15582 windows->widget.y=event.xconfigure.y+
15583 event.xconfigure.height/10;
15584 XConstrainWindowPosition(display,&windows->widget);
15585 window_changes.x=windows->widget.x;
15586 window_changes.y=windows->widget.y;
15587 (void) XReconfigureWMWindow(display,windows->widget.id,
15588 windows->widget.screen,(unsigned int) (CWX | CWY),
15589 &window_changes);
15590 }
15591 if (windows->magnify.geometry == (char *) NULL)
15592 if (windows->magnify.mapped == MagickFalse)
15593 {
15594 windows->magnify.x=event.xconfigure.x+
15595 event.xconfigure.width+25;
15596 windows->magnify.y=event.xconfigure.y;
15597 XConstrainWindowPosition(display,&windows->magnify);
15598 window_changes.x=windows->magnify.x;
15599 window_changes.y=windows->magnify.y;
15600 (void) XReconfigureWMWindow(display,windows->magnify.id,
15601 windows->magnify.screen,(unsigned int) (CWX | CWY),
15602 &window_changes);
15603 }
15604 if (windows->pan.geometry == (char *) NULL)
15605 if (windows->pan.mapped == MagickFalse)
15606 {
15607 windows->pan.x=event.xconfigure.x+
15608 event.xconfigure.width+25;
15609 windows->pan.y=event.xconfigure.y+
15610 windows->magnify.height+50;
15611 XConstrainWindowPosition(display,&windows->pan);
15612 window_changes.x=windows->pan.x;
15613 window_changes.y=windows->pan.y;
15614 (void) XReconfigureWMWindow(display,windows->pan.id,
15615 windows->pan.screen,(unsigned int) (CWX | CWY),
15616 &window_changes);
15617 }
15618 }
15619 if ((event.xconfigure.width == (int) windows->image.width) &&
15620 (event.xconfigure.height == (int) windows->image.height))
15621 break;
15622 windows->image.width=(unsigned int) event.xconfigure.width;
15623 windows->image.height=(unsigned int) event.xconfigure.height;
15624 windows->image.x=0;
15625 windows->image.y=0;
15626 if (display_image->montage != (char *) NULL)
15627 {
15628 windows->image.x=vid_info.x;
15629 windows->image.y=vid_info.y;
15630 }
15631 if (windows->image.mapped != MagickFalse &&
15632 windows->image.stasis != MagickFalse)
15633 {
15634 /*
15635 Update image window configuration.
15636 */
15637 windows->image.window_changes.width=event.xconfigure.width;
15638 windows->image.window_changes.height=event.xconfigure.height;
15639 (void) XConfigureImage(display,resource_info,windows,
15640 display_image,exception);
15641 }
15642 /*
15643 Update pan window configuration.
15644 */
15645 if ((event.xconfigure.width < windows->image.ximage->width) ||
15646 (event.xconfigure.height < windows->image.ximage->height))
15647 {
15648 (void) XMapRaised(display,windows->pan.id);
15649 XDrawPanRectangle(display,windows);
15650 }
15651 else
15652 if (windows->pan.mapped != MagickFalse)
15653 (void) XWithdrawWindow(display,windows->pan.id,
15654 windows->pan.screen);
15655 break;
15656 }
15657 if (event.xconfigure.window == windows->magnify.id)
15658 {
15659 unsigned int
15660 magnify;
15661
15662 /*
15663 Magnify window has a new configuration.
15664 */
15665 windows->magnify.width=(unsigned int) event.xconfigure.width;
15666 windows->magnify.height=(unsigned int) event.xconfigure.height;
15667 if (windows->magnify.mapped == MagickFalse)
15668 break;
15669 magnify=1;
15670 while ((int) magnify <= event.xconfigure.width)
15671 magnify<<=1;
15672 while ((int) magnify <= event.xconfigure.height)
15673 magnify<<=1;
15674 magnify>>=1;
15675 if (((int) magnify != event.xconfigure.width) ||
15676 ((int) magnify != event.xconfigure.height))
15677 {
15678 window_changes.width=(int) magnify;
15679 window_changes.height=(int) magnify;
15680 (void) XReconfigureWMWindow(display,windows->magnify.id,
15681 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15682 &window_changes);
15683 break;
15684 }
15685 if (windows->magnify.mapped != MagickFalse &&
15686 windows->magnify.stasis != MagickFalse)
15687 {
15688 status=XMakeImage(display,resource_info,&windows->magnify,
15689 display_image,windows->magnify.width,windows->magnify.height,
15690 exception);
15691 XMakeMagnifyImage(display,windows,exception);
15692 }
15693 break;
15694 }
15695 if (windows->magnify.mapped != MagickFalse &&
15696 (event.xconfigure.window == windows->pan.id))
15697 {
15698 /*
15699 Pan icon window has a new configuration.
15700 */
15701 if (event.xconfigure.send_event != 0)
15702 {
15703 windows->pan.x=event.xconfigure.x;
15704 windows->pan.y=event.xconfigure.y;
15705 }
15706 windows->pan.width=(unsigned int) event.xconfigure.width;
15707 windows->pan.height=(unsigned int) event.xconfigure.height;
15708 break;
15709 }
15710 if (event.xconfigure.window == windows->icon.id)
15711 {
15712 /*
15713 Icon window has a new configuration.
15714 */
15715 windows->icon.width=(unsigned int) event.xconfigure.width;
15716 windows->icon.height=(unsigned int) event.xconfigure.height;
15717 break;
15718 }
15719 break;
15720 }
15721 case DestroyNotify:
15722 {
15723 /*
15724 Group leader has exited.
15725 */
15726 if (display_image->debug != MagickFalse)
15727 (void) LogMagickEvent(X11Event,GetMagickModule(),
15728 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15729 if (event.xdestroywindow.window == windows->group_leader.id)
15730 {
15731 *state|=ExitState;
15732 break;
15733 }
15734 break;
15735 }
15736 case EnterNotify:
15737 {
15738 /*
15739 Selectively install colormap.
15740 */
15741 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15742 if (event.xcrossing.mode != NotifyUngrab)
15743 XInstallColormap(display,map_info->colormap);
15744 break;
15745 }
15746 case Expose:
15747 {
15748 if (display_image->debug != MagickFalse)
15749 (void) LogMagickEvent(X11Event,GetMagickModule(),
15750 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15751 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15752 event.xexpose.y);
15753 /*
15754 Refresh windows that are now exposed.
15755 */
15756 if ((event.xexpose.window == windows->image.id) &&
15757 windows->image.mapped != MagickFalse)
15758 {
15759 XRefreshWindow(display,&windows->image,&event);
15760 delay=display_image->delay/MagickMax(
15761 display_image->ticks_per_second,1L);
15762 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15763 break;
15764 }
15765 if ((event.xexpose.window == windows->magnify.id) &&
15766 windows->magnify.mapped != MagickFalse)
15767 {
15768 XMakeMagnifyImage(display,windows,exception);
15769 break;
15770 }
15771 if (event.xexpose.window == windows->pan.id)
15772 {
15773 XDrawPanRectangle(display,windows);
15774 break;
15775 }
15776 if (event.xexpose.window == windows->icon.id)
15777 {
15778 XRefreshWindow(display,&windows->icon,&event);
15779 break;
15780 }
15781 break;
15782 }
15783 case KeyPress:
15784 {
15785 int
15786 length;
15787
15788 /*
15789 Respond to a user key press.
15790 */
15791 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15792 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15793 *(command+length)='\0';
15794 if (display_image->debug != MagickFalse)
15795 (void) LogMagickEvent(X11Event,GetMagickModule(),
15796 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15797 key_symbol,command);
15798 if (event.xkey.window == windows->image.id)
15799 {
15800 command_type=XImageWindowCommand(display,resource_info,windows,
15801 event.xkey.state,key_symbol,&display_image,exception);
15802 if (command_type != NullCommand)
15803 nexus=XMagickCommand(display,resource_info,windows,command_type,
15804 &display_image,exception);
15805 }
15806 if (event.xkey.window == windows->magnify.id)
15807 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15808 exception);
15809 if (event.xkey.window == windows->pan.id)
15810 {
15811 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15812 (void) XWithdrawWindow(display,windows->pan.id,
15813 windows->pan.screen);
15814 else
15815 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15816 XTextViewHelp(display,resource_info,windows,MagickFalse,
15817 "Help Viewer - Image Pan",ImagePanHelp);
15818 else
15819 XTranslateImage(display,windows,*image,key_symbol);
15820 }
15821 delay=display_image->delay/MagickMax(
15822 display_image->ticks_per_second,1L);
15823 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15824 break;
15825 }
15826 case KeyRelease:
15827 {
15828 /*
15829 Respond to a user key release.
15830 */
15831 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15832 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15833 if (display_image->debug != MagickFalse)
15834 (void) LogMagickEvent(X11Event,GetMagickModule(),
15835 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15836 break;
15837 }
15838 case LeaveNotify:
15839 {
15840 /*
15841 Selectively uninstall colormap.
15842 */
15843 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15844 if (event.xcrossing.mode != NotifyUngrab)
15845 XUninstallColormap(display,map_info->colormap);
15846 break;
15847 }
15848 case MapNotify:
15849 {
15850 if (display_image->debug != MagickFalse)
15851 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15852 event.xmap.window);
15853 if (event.xmap.window == windows->backdrop.id)
15854 {
15855 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15856 CurrentTime);
15857 windows->backdrop.mapped=MagickTrue;
15858 break;
15859 }
15860 if (event.xmap.window == windows->image.id)
15861 {
15862 if (windows->backdrop.id != (Window) NULL)
15863 (void) XInstallColormap(display,map_info->colormap);
15864 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15865 {
15866 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15867 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15868 }
15869 if (((int) windows->image.width < windows->image.ximage->width) ||
15870 ((int) windows->image.height < windows->image.ximage->height))
15871 (void) XMapRaised(display,windows->pan.id);
15872 windows->image.mapped=MagickTrue;
15873 break;
15874 }
15875 if (event.xmap.window == windows->magnify.id)
15876 {
15877 XMakeMagnifyImage(display,windows,exception);
15878 windows->magnify.mapped=MagickTrue;
15879 (void) XWithdrawWindow(display,windows->info.id,
15880 windows->info.screen);
15881 break;
15882 }
15883 if (event.xmap.window == windows->pan.id)
15884 {
15885 XMakePanImage(display,resource_info,windows,display_image,
15886 exception);
15887 windows->pan.mapped=MagickTrue;
15888 break;
15889 }
15890 if (event.xmap.window == windows->info.id)
15891 {
15892 windows->info.mapped=MagickTrue;
15893 break;
15894 }
15895 if (event.xmap.window == windows->icon.id)
15896 {
15897 MagickBooleanType
15898 taint;
15899
15900 /*
15901 Create an icon image.
15902 */
15903 taint=display_image->taint;
15904 XMakeStandardColormap(display,icon_visual,icon_resources,
15905 display_image,icon_map,icon_pixel,exception);
15906 (void) XMakeImage(display,icon_resources,&windows->icon,
15907 display_image,windows->icon.width,windows->icon.height,
15908 exception);
15909 display_image->taint=taint;
15910 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15911 windows->icon.pixmap);
15912 (void) XClearWindow(display,windows->icon.id);
15913 (void) XWithdrawWindow(display,windows->info.id,
15914 windows->info.screen);
15915 windows->icon.mapped=MagickTrue;
15916 break;
15917 }
15918 if (event.xmap.window == windows->command.id)
15919 {
15920 windows->command.mapped=MagickTrue;
15921 break;
15922 }
15923 if (event.xmap.window == windows->popup.id)
15924 {
15925 windows->popup.mapped=MagickTrue;
15926 break;
15927 }
15928 if (event.xmap.window == windows->widget.id)
15929 {
15930 windows->widget.mapped=MagickTrue;
15931 break;
15932 }
15933 break;
15934 }
15935 case MappingNotify:
15936 {
15937 (void) XRefreshKeyboardMapping(&event.xmapping);
15938 break;
15939 }
15940 case NoExpose:
15941 break;
15942 case PropertyNotify:
15943 {
15944 Atom
15945 type;
15946
15947 int
15948 format,
15949 status;
15950
15951 unsigned char
15952 *data;
15953
15954 unsigned long
15955 after,
15956 length;
15957
15958 if (display_image->debug != MagickFalse)
15959 (void) LogMagickEvent(X11Event,GetMagickModule(),
15960 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15961 event.xproperty.atom,event.xproperty.state);
15962 if (event.xproperty.atom != windows->im_remote_command)
15963 break;
15964 /*
15965 Display image named by the remote command protocol.
15966 */
15967 status=XGetWindowProperty(display,event.xproperty.window,
15968 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
15969 AnyPropertyType,&type,&format,&length,&after,&data);
15970 if ((status != Success) || (length == 0))
15971 break;
15972 if (LocaleCompare((char *) data,"-quit") == 0)
15973 {
15974 XClientMessage(display,windows->image.id,windows->im_protocols,
15975 windows->im_exit,CurrentTime);
15976 (void) XFree((void *) data);
15977 break;
15978 }
15979 (void) CopyMagickString(resource_info->image_info->filename,
15980 (char *) data,MagickPathExtent);
15981 (void) XFree((void *) data);
15982 nexus=ReadImage(resource_info->image_info,exception);
15983 CatchException(exception);
15984 if (nexus != (Image *) NULL)
15985 *state|=NextImageState | ExitState;
15986 break;
15987 }
15988 case ReparentNotify:
15989 {
15990 if (display_image->debug != MagickFalse)
15991 (void) LogMagickEvent(X11Event,GetMagickModule(),
15992 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15993 event.xreparent.window);
15994 break;
15995 }
15996 case UnmapNotify:
15997 {
15998 if (display_image->debug != MagickFalse)
15999 (void) LogMagickEvent(X11Event,GetMagickModule(),
16000 "Unmap Notify: 0x%lx",event.xunmap.window);
16001 if (event.xunmap.window == windows->backdrop.id)
16002 {
16003 windows->backdrop.mapped=MagickFalse;
16004 break;
16005 }
16006 if (event.xunmap.window == windows->image.id)
16007 {
16008 windows->image.mapped=MagickFalse;
16009 break;
16010 }
16011 if (event.xunmap.window == windows->magnify.id)
16012 {
16013 windows->magnify.mapped=MagickFalse;
16014 break;
16015 }
16016 if (event.xunmap.window == windows->pan.id)
16017 {
16018 windows->pan.mapped=MagickFalse;
16019 break;
16020 }
16021 if (event.xunmap.window == windows->info.id)
16022 {
16023 windows->info.mapped=MagickFalse;
16024 break;
16025 }
16026 if (event.xunmap.window == windows->icon.id)
16027 {
16028 if (map_info->colormap == icon_map->colormap)
16029 XConfigureImageColormap(display,resource_info,windows,
16030 display_image,exception);
16031 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16032 icon_pixel);
16033 windows->icon.mapped=MagickFalse;
16034 break;
16035 }
16036 if (event.xunmap.window == windows->command.id)
16037 {
16038 windows->command.mapped=MagickFalse;
16039 break;
16040 }
16041 if (event.xunmap.window == windows->popup.id)
16042 {
16043 if (windows->backdrop.id != (Window) NULL)
16044 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16045 CurrentTime);
16046 windows->popup.mapped=MagickFalse;
16047 break;
16048 }
16049 if (event.xunmap.window == windows->widget.id)
16050 {
16051 if (windows->backdrop.id != (Window) NULL)
16052 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16053 CurrentTime);
16054 windows->widget.mapped=MagickFalse;
16055 break;
16056 }
16057 break;
16058 }
16059 default:
16060 {
16061 if (display_image->debug != MagickFalse)
16062 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16063 event.type);
16064 break;
16065 }
16066 }
16067 } while (!(*state & ExitState));
16068 if ((*state & ExitState) == 0)
16069 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
16070 &display_image,exception);
16071 else
16072 if (resource_info->confirm_edit != MagickFalse)
16073 {
16074 /*
16075 Query user if image has changed.
16076 */
16077 if ((resource_info->immutable == MagickFalse) &&
16078 display_image->taint != MagickFalse)
16079 {
16080 int
16081 status;
16082
16083 status=XConfirmWidget(display,windows,"Your image changed.",
16084 "Do you want to save it");
16085 if (status == 0)
16086 *state&=(~ExitState);
16087 else
16088 if (status > 0)
16089 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
16090 &display_image,exception);
16091 }
16092 }
16093 if ((windows->visual_info->klass == GrayScale) ||
16094 (windows->visual_info->klass == PseudoColor) ||
16095 (windows->visual_info->klass == DirectColor))
16096 {
16097 /*
16098 Withdraw pan and Magnify window.
16099 */
16100 if (windows->info.mapped != MagickFalse)
16101 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16102 if (windows->magnify.mapped != MagickFalse)
16103 (void) XWithdrawWindow(display,windows->magnify.id,
16104 windows->magnify.screen);
16105 if (windows->command.mapped != MagickFalse)
16106 (void) XWithdrawWindow(display,windows->command.id,
16107 windows->command.screen);
16108 }
16109 if (windows->pan.mapped != MagickFalse)
16110 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16111 if (resource_info->backdrop == MagickFalse)
16112 if (windows->backdrop.mapped)
16113 {
16114 (void) XWithdrawWindow(display,windows->backdrop.id,
16115 windows->backdrop.screen);
16116 (void) XDestroyWindow(display,windows->backdrop.id);
16117 windows->backdrop.id=(Window) NULL;
16118 (void) XWithdrawWindow(display,windows->image.id,
16119 windows->image.screen);
16120 (void) XDestroyWindow(display,windows->image.id);
16121 windows->image.id=(Window) NULL;
16122 }
16123 XSetCursorState(display,windows,MagickTrue);
16124 XCheckRefreshWindows(display,windows);
16125 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16126 *state&=(~ExitState);
16127 if (*state & ExitState)
16128 {
16129 /*
16130 Free Standard Colormap.
16131 */
16132 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16133 if (resource_info->map_type == (char *) NULL)
16134 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16135 /*
16136 Free X resources.
16137 */
16138 if (resource_info->copy_image != (Image *) NULL)
16139 {
16140 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16141 resource_info->copy_image=NewImageList();
16142 }
16143 DestroyXResources();
16144 }
16145 (void) XSync(display,MagickFalse);
16146 /*
16147 Restore our progress monitor and warning handlers.
16148 */
16149 (void) SetErrorHandler(warning_handler);
16150 (void) SetWarningHandler(warning_handler);
16151 /*
16152 Change to home directory.
16153 */
16154 directory=getcwd(working_directory,MagickPathExtent);
16155 (void) directory;
16156 {
16157 int
16158 status;
16159
16160 if (*resource_info->home_directory == '\0')
16161 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
16162 status=chdir(resource_info->home_directory);
16163 if (status == -1)
16164 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16165 "UnableToOpenFile","%s",resource_info->home_directory);
16166 }
16167 *image=display_image;
16168 return(nexus);
16169 }
16170 #else
16171
16172 /*
16173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16174 % %
16175 % %
16176 % %
16177 + D i s p l a y I m a g e s %
16178 % %
16179 % %
16180 % %
16181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16182 %
16183 % DisplayImages() displays an image sequence to any X window screen. It
16184 % returns a value other than 0 if successful. Check the exception member
16185 % of image to determine the reason for any failure.
16186 %
16187 % The format of the DisplayImages method is:
16188 %
16189 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16190 % Image *images,ExceptionInfo *exception)
16191 %
16192 % A description of each parameter follows:
16193 %
16194 % o image_info: the image info.
16195 %
16196 % o image: the image.
16197 %
16198 % o exception: return any errors or warnings in this structure.
16199 %
16200 */
DisplayImages(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)16201 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16202 Image *image,ExceptionInfo *exception)
16203 {
16204 assert(image_info != (const ImageInfo *) NULL);
16205 assert(image_info->signature == MagickCoreSignature);
16206 assert(image != (Image *) NULL);
16207 assert(image->signature == MagickCoreSignature);
16208 (void) image_info;
16209 if (image->debug != MagickFalse)
16210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16211 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16212 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
16213 return(MagickFalse);
16214 }
16215
16216 /*
16217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16218 % %
16219 % %
16220 % %
16221 + R e m o t e D i s p l a y C o m m a n d %
16222 % %
16223 % %
16224 % %
16225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16226 %
16227 % RemoteDisplayCommand() encourages a remote display program to display the
16228 % specified image filename.
16229 %
16230 % The format of the RemoteDisplayCommand method is:
16231 %
16232 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16233 % const char *window,const char *filename,ExceptionInfo *exception)
16234 %
16235 % A description of each parameter follows:
16236 %
16237 % o image_info: the image info.
16238 %
16239 % o window: Specifies the name or id of an X window.
16240 %
16241 % o filename: the name of the image filename to display.
16242 %
16243 % o exception: return any errors or warnings in this structure.
16244 %
16245 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)16246 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16247 const char *window,const char *filename,ExceptionInfo *exception)
16248 {
16249 assert(image_info != (const ImageInfo *) NULL);
16250 assert(image_info->signature == MagickCoreSignature);
16251 assert(filename != (char *) NULL);
16252 (void) window;
16253 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16254 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16255 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
16256 return(MagickFalse);
16257 }
16258 #endif
16259