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-2020 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 register 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 register char
1847 *p;
1848
1849 register 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 *) AcquireMagickMemory(
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 *) AcquireMagickMemory(
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 register Quantum
3305 *q;
3306
3307 register 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 register int
4282 x;
4283
4284 register 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 register 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_image=CropImage(image,&crop_info,exception);
5300 XSetCursorState(display,windows,MagickFalse);
5301 if (crop_image == (Image *) NULL)
5302 return(MagickFalse);
5303 if (resource_info->copy_image != (Image *) NULL)
5304 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5305 resource_info->copy_image=crop_image;
5306 if (mode == CopyMode)
5307 {
5308 (void) XConfigureImage(display,resource_info,windows,image,exception);
5309 return(MagickTrue);
5310 }
5311 /*
5312 Cut image.
5313 */
5314 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
5315 return(MagickFalse);
5316 image->alpha_trait=BlendPixelTrait;
5317 image_view=AcquireAuthenticCacheView(image,exception);
5318 for (y=0; y < (int) crop_info.height; y++)
5319 {
5320 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5321 crop_info.width,1,exception);
5322 if (q == (Quantum *) NULL)
5323 break;
5324 for (x=0; x < (int) crop_info.width; x++)
5325 {
5326 SetPixelAlpha(image,TransparentAlpha,q);
5327 q+=GetPixelChannels(image);
5328 }
5329 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5330 break;
5331 }
5332 image_view=DestroyCacheView(image_view);
5333 /*
5334 Update image configuration.
5335 */
5336 XConfigureImageColormap(display,resource_info,windows,image,exception);
5337 (void) XConfigureImage(display,resource_info,windows,image,exception);
5338 return(MagickTrue);
5339 }
5340
5341 /*
5342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5343 % %
5344 % %
5345 % %
5346 + X D r a w I m a g e %
5347 % %
5348 % %
5349 % %
5350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5351 %
5352 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5353 % the image.
5354 %
5355 % The format of the XDrawEditImage method is:
5356 %
5357 % MagickBooleanType XDrawEditImage(Display *display,
5358 % XResourceInfo *resource_info,XWindows *windows,Image **image,
5359 % ExceptionInfo *exception)
5360 %
5361 % A description of each parameter follows:
5362 %
5363 % o display: Specifies a connection to an X server; returned from
5364 % XOpenDisplay.
5365 %
5366 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5367 %
5368 % o windows: Specifies a pointer to a XWindows structure.
5369 %
5370 % o image: the image.
5371 %
5372 % o exception: return any errors or warnings in this structure.
5373 %
5374 */
XDrawEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)5375 static MagickBooleanType XDrawEditImage(Display *display,
5376 XResourceInfo *resource_info,XWindows *windows,Image **image,
5377 ExceptionInfo *exception)
5378 {
5379 const char
5380 *const DrawMenu[] =
5381 {
5382 "Element",
5383 "Color",
5384 "Stipple",
5385 "Width",
5386 "Undo",
5387 "Help",
5388 "Dismiss",
5389 (char *) NULL
5390 };
5391
5392 static ElementType
5393 element = PointElement;
5394
5395 static const ModeType
5396 DrawCommands[] =
5397 {
5398 DrawElementCommand,
5399 DrawColorCommand,
5400 DrawStippleCommand,
5401 DrawWidthCommand,
5402 DrawUndoCommand,
5403 DrawHelpCommand,
5404 DrawDismissCommand
5405 };
5406
5407 static Pixmap
5408 stipple = (Pixmap) NULL;
5409
5410 static unsigned int
5411 pen_id = 0,
5412 line_width = 1;
5413
5414 char
5415 command[MagickPathExtent],
5416 text[MagickPathExtent];
5417
5418 Cursor
5419 cursor;
5420
5421 int
5422 entry,
5423 id,
5424 number_coordinates,
5425 x,
5426 y;
5427
5428 double
5429 degrees;
5430
5431 MagickStatusType
5432 status;
5433
5434 RectangleInfo
5435 rectangle_info;
5436
5437 register int
5438 i;
5439
5440 unsigned int
5441 distance,
5442 height,
5443 max_coordinates,
5444 width;
5445
5446 size_t
5447 state;
5448
5449 Window
5450 root_window;
5451
5452 XDrawInfo
5453 draw_info;
5454
5455 XEvent
5456 event;
5457
5458 XPoint
5459 *coordinate_info;
5460
5461 XSegment
5462 line_info;
5463
5464 /*
5465 Allocate polygon info.
5466 */
5467 max_coordinates=2048;
5468 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5469 sizeof(*coordinate_info));
5470 if (coordinate_info == (XPoint *) NULL)
5471 {
5472 (void) ThrowMagickException(exception,GetMagickModule(),
5473 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5474 return(MagickFalse);
5475 }
5476 /*
5477 Map Command widget.
5478 */
5479 (void) CloneString(&windows->command.name,"Draw");
5480 windows->command.data=4;
5481 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5482 (void) XMapRaised(display,windows->command.id);
5483 XClientMessage(display,windows->image.id,windows->im_protocols,
5484 windows->im_update_widget,CurrentTime);
5485 /*
5486 Wait for first button press.
5487 */
5488 root_window=XRootWindow(display,XDefaultScreen(display));
5489 draw_info.stencil=OpaqueStencil;
5490 status=MagickTrue;
5491 cursor=XCreateFontCursor(display,XC_tcross);
5492 for ( ; ; )
5493 {
5494 XQueryPosition(display,windows->image.id,&x,&y);
5495 (void) XSelectInput(display,windows->image.id,
5496 windows->image.attributes.event_mask | PointerMotionMask);
5497 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5498 state=DefaultState;
5499 do
5500 {
5501 if (windows->info.mapped != MagickFalse )
5502 {
5503 /*
5504 Display pointer position.
5505 */
5506 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
5507 x+windows->image.x,y+windows->image.y);
5508 XInfoWidget(display,windows,text);
5509 }
5510 /*
5511 Wait for next event.
5512 */
5513 XScreenEvent(display,windows,&event,exception);
5514 if (event.xany.window == windows->command.id)
5515 {
5516 /*
5517 Select a command from the Command widget.
5518 */
5519 id=XCommandWidget(display,windows,DrawMenu,&event);
5520 if (id < 0)
5521 continue;
5522 switch (DrawCommands[id])
5523 {
5524 case DrawElementCommand:
5525 {
5526 const char
5527 *const Elements[] =
5528 {
5529 "point",
5530 "line",
5531 "rectangle",
5532 "fill rectangle",
5533 "circle",
5534 "fill circle",
5535 "ellipse",
5536 "fill ellipse",
5537 "polygon",
5538 "fill polygon",
5539 (char *) NULL,
5540 };
5541
5542 /*
5543 Select a command from the pop-up menu.
5544 */
5545 element=(ElementType) (XMenuWidget(display,windows,
5546 DrawMenu[id],Elements,command)+1);
5547 break;
5548 }
5549 case DrawColorCommand:
5550 {
5551 const char
5552 *ColorMenu[MaxNumberPens+1];
5553
5554 int
5555 pen_number;
5556
5557 MagickBooleanType
5558 transparent;
5559
5560 XColor
5561 color;
5562
5563 /*
5564 Initialize menu selections.
5565 */
5566 for (i=0; i < (int) (MaxNumberPens-2); i++)
5567 ColorMenu[i]=resource_info->pen_colors[i];
5568 ColorMenu[MaxNumberPens-2]="transparent";
5569 ColorMenu[MaxNumberPens-1]="Browser...";
5570 ColorMenu[MaxNumberPens]=(char *) NULL;
5571 /*
5572 Select a pen color from the pop-up menu.
5573 */
5574 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5575 (const char **) ColorMenu,command);
5576 if (pen_number < 0)
5577 break;
5578 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5579 MagickFalse;
5580 if (transparent != MagickFalse )
5581 {
5582 draw_info.stencil=TransparentStencil;
5583 break;
5584 }
5585 if (pen_number == (MaxNumberPens-1))
5586 {
5587 static char
5588 color_name[MagickPathExtent] = "gray";
5589
5590 /*
5591 Select a pen color from a dialog.
5592 */
5593 resource_info->pen_colors[pen_number]=color_name;
5594 XColorBrowserWidget(display,windows,"Select",color_name);
5595 if (*color_name == '\0')
5596 break;
5597 }
5598 /*
5599 Set pen color.
5600 */
5601 (void) XParseColor(display,windows->map_info->colormap,
5602 resource_info->pen_colors[pen_number],&color);
5603 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5604 (unsigned int) MaxColors,&color);
5605 windows->pixel_info->pen_colors[pen_number]=color;
5606 pen_id=(unsigned int) pen_number;
5607 draw_info.stencil=OpaqueStencil;
5608 break;
5609 }
5610 case DrawStippleCommand:
5611 {
5612 const char
5613 *StipplesMenu[] =
5614 {
5615 "Brick",
5616 "Diagonal",
5617 "Scales",
5618 "Vertical",
5619 "Wavy",
5620 "Translucent",
5621 "Opaque",
5622 (char *) NULL,
5623 (char *) NULL,
5624 };
5625
5626 Image
5627 *stipple_image;
5628
5629 ImageInfo
5630 *image_info;
5631
5632 int
5633 status;
5634
5635 static char
5636 filename[MagickPathExtent] = "\0";
5637
5638 /*
5639 Select a command from the pop-up menu.
5640 */
5641 StipplesMenu[7]="Open...";
5642 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5643 command);
5644 if (entry < 0)
5645 break;
5646 if (stipple != (Pixmap) NULL)
5647 (void) XFreePixmap(display,stipple);
5648 stipple=(Pixmap) NULL;
5649 if (entry != 7)
5650 {
5651 switch (entry)
5652 {
5653 case 0:
5654 {
5655 stipple=XCreateBitmapFromData(display,root_window,
5656 (char *) BricksBitmap,BricksWidth,BricksHeight);
5657 break;
5658 }
5659 case 1:
5660 {
5661 stipple=XCreateBitmapFromData(display,root_window,
5662 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5663 break;
5664 }
5665 case 2:
5666 {
5667 stipple=XCreateBitmapFromData(display,root_window,
5668 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5669 break;
5670 }
5671 case 3:
5672 {
5673 stipple=XCreateBitmapFromData(display,root_window,
5674 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5675 break;
5676 }
5677 case 4:
5678 {
5679 stipple=XCreateBitmapFromData(display,root_window,
5680 (char *) WavyBitmap,WavyWidth,WavyHeight);
5681 break;
5682 }
5683 case 5:
5684 {
5685 stipple=XCreateBitmapFromData(display,root_window,
5686 (char *) HighlightBitmap,HighlightWidth,
5687 HighlightHeight);
5688 break;
5689 }
5690 case 6:
5691 default:
5692 {
5693 stipple=XCreateBitmapFromData(display,root_window,
5694 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5695 break;
5696 }
5697 }
5698 break;
5699 }
5700 XFileBrowserWidget(display,windows,"Stipple",filename);
5701 if (*filename == '\0')
5702 break;
5703 /*
5704 Read image.
5705 */
5706 XSetCursorState(display,windows,MagickTrue);
5707 XCheckRefreshWindows(display,windows);
5708 image_info=AcquireImageInfo();
5709 (void) CopyMagickString(image_info->filename,filename,
5710 MagickPathExtent);
5711 stipple_image=ReadImage(image_info,exception);
5712 CatchException(exception);
5713 XSetCursorState(display,windows,MagickFalse);
5714 if (stipple_image == (Image *) NULL)
5715 break;
5716 (void) AcquireUniqueFileResource(filename);
5717 (void) FormatLocaleString(stipple_image->filename,
5718 MagickPathExtent,"xbm:%s",filename);
5719 (void) WriteImage(image_info,stipple_image,exception);
5720 stipple_image=DestroyImage(stipple_image);
5721 image_info=DestroyImageInfo(image_info);
5722 status=XReadBitmapFile(display,root_window,filename,&width,
5723 &height,&stipple,&x,&y);
5724 (void) RelinquishUniqueFileResource(filename);
5725 if ((status != BitmapSuccess) != 0)
5726 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5727 filename);
5728 break;
5729 }
5730 case DrawWidthCommand:
5731 {
5732 const char
5733 *const WidthsMenu[] =
5734 {
5735 "1",
5736 "2",
5737 "4",
5738 "8",
5739 "16",
5740 "Dialog...",
5741 (char *) NULL,
5742 };
5743
5744 static char
5745 width[MagickPathExtent] = "0";
5746
5747 /*
5748 Select a command from the pop-up menu.
5749 */
5750 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5751 command);
5752 if (entry < 0)
5753 break;
5754 if (entry != 5)
5755 {
5756 line_width=(unsigned int) StringToUnsignedLong(
5757 WidthsMenu[entry]);
5758 break;
5759 }
5760 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5761 width);
5762 if (*width == '\0')
5763 break;
5764 line_width=(unsigned int) StringToUnsignedLong(width);
5765 break;
5766 }
5767 case DrawUndoCommand:
5768 {
5769 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5770 image,exception);
5771 break;
5772 }
5773 case DrawHelpCommand:
5774 {
5775 XTextViewHelp(display,resource_info,windows,MagickFalse,
5776 "Help Viewer - Image Rotation",ImageDrawHelp);
5777 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5778 break;
5779 }
5780 case DrawDismissCommand:
5781 {
5782 /*
5783 Prematurely exit.
5784 */
5785 state|=EscapeState;
5786 state|=ExitState;
5787 break;
5788 }
5789 default:
5790 break;
5791 }
5792 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5793 continue;
5794 }
5795 switch (event.type)
5796 {
5797 case ButtonPress:
5798 {
5799 if (event.xbutton.button != Button1)
5800 break;
5801 if (event.xbutton.window != windows->image.id)
5802 break;
5803 /*
5804 exit loop.
5805 */
5806 x=event.xbutton.x;
5807 y=event.xbutton.y;
5808 state|=ExitState;
5809 break;
5810 }
5811 case ButtonRelease:
5812 break;
5813 case Expose:
5814 break;
5815 case KeyPress:
5816 {
5817 KeySym
5818 key_symbol;
5819
5820 if (event.xkey.window != windows->image.id)
5821 break;
5822 /*
5823 Respond to a user key press.
5824 */
5825 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5826 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5827 switch ((int) key_symbol)
5828 {
5829 case XK_Escape:
5830 case XK_F20:
5831 {
5832 /*
5833 Prematurely exit.
5834 */
5835 state|=EscapeState;
5836 state|=ExitState;
5837 break;
5838 }
5839 case XK_F1:
5840 case XK_Help:
5841 {
5842 XTextViewHelp(display,resource_info,windows,MagickFalse,
5843 "Help Viewer - Image Rotation",ImageDrawHelp);
5844 break;
5845 }
5846 default:
5847 {
5848 (void) XBell(display,0);
5849 break;
5850 }
5851 }
5852 break;
5853 }
5854 case MotionNotify:
5855 {
5856 /*
5857 Map and unmap Info widget as text cursor crosses its boundaries.
5858 */
5859 x=event.xmotion.x;
5860 y=event.xmotion.y;
5861 if (windows->info.mapped != MagickFalse )
5862 {
5863 if ((x < (int) (windows->info.x+windows->info.width)) &&
5864 (y < (int) (windows->info.y+windows->info.height)))
5865 (void) XWithdrawWindow(display,windows->info.id,
5866 windows->info.screen);
5867 }
5868 else
5869 if ((x > (int) (windows->info.x+windows->info.width)) ||
5870 (y > (int) (windows->info.y+windows->info.height)))
5871 (void) XMapWindow(display,windows->info.id);
5872 break;
5873 }
5874 }
5875 } while ((state & ExitState) == 0);
5876 (void) XSelectInput(display,windows->image.id,
5877 windows->image.attributes.event_mask);
5878 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5879 if ((state & EscapeState) != 0)
5880 break;
5881 /*
5882 Draw element as pointer moves until the button is released.
5883 */
5884 distance=0;
5885 degrees=0.0;
5886 line_info.x1=x;
5887 line_info.y1=y;
5888 line_info.x2=x;
5889 line_info.y2=y;
5890 rectangle_info.x=(ssize_t) x;
5891 rectangle_info.y=(ssize_t) y;
5892 rectangle_info.width=0;
5893 rectangle_info.height=0;
5894 number_coordinates=1;
5895 coordinate_info->x=x;
5896 coordinate_info->y=y;
5897 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5898 state=DefaultState;
5899 do
5900 {
5901 switch (element)
5902 {
5903 case PointElement:
5904 default:
5905 {
5906 if (number_coordinates > 1)
5907 {
5908 (void) XDrawLines(display,windows->image.id,
5909 windows->image.highlight_context,coordinate_info,
5910 number_coordinates,CoordModeOrigin);
5911 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d",
5912 coordinate_info[number_coordinates-1].x,
5913 coordinate_info[number_coordinates-1].y);
5914 XInfoWidget(display,windows,text);
5915 }
5916 break;
5917 }
5918 case LineElement:
5919 {
5920 if (distance > 9)
5921 {
5922 /*
5923 Display angle of the line.
5924 */
5925 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5926 line_info.y1),(double) (line_info.x2-line_info.x1)));
5927 (void) FormatLocaleString(text,MagickPathExtent," %g",
5928 (double) degrees);
5929 XInfoWidget(display,windows,text);
5930 XHighlightLine(display,windows->image.id,
5931 windows->image.highlight_context,&line_info);
5932 }
5933 else
5934 if (windows->info.mapped != MagickFalse )
5935 (void) XWithdrawWindow(display,windows->info.id,
5936 windows->info.screen);
5937 break;
5938 }
5939 case RectangleElement:
5940 case FillRectangleElement:
5941 {
5942 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5943 {
5944 /*
5945 Display info and draw drawing rectangle.
5946 */
5947 (void) FormatLocaleString(text,MagickPathExtent,
5948 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5949 (double) rectangle_info.height,(double) rectangle_info.x,
5950 (double) rectangle_info.y);
5951 XInfoWidget(display,windows,text);
5952 XHighlightRectangle(display,windows->image.id,
5953 windows->image.highlight_context,&rectangle_info);
5954 }
5955 else
5956 if (windows->info.mapped != MagickFalse )
5957 (void) XWithdrawWindow(display,windows->info.id,
5958 windows->info.screen);
5959 break;
5960 }
5961 case CircleElement:
5962 case FillCircleElement:
5963 case EllipseElement:
5964 case FillEllipseElement:
5965 {
5966 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5967 {
5968 /*
5969 Display info and draw drawing rectangle.
5970 */
5971 (void) FormatLocaleString(text,MagickPathExtent,
5972 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5973 (double) rectangle_info.height,(double) rectangle_info.x,
5974 (double) rectangle_info.y);
5975 XInfoWidget(display,windows,text);
5976 XHighlightEllipse(display,windows->image.id,
5977 windows->image.highlight_context,&rectangle_info);
5978 }
5979 else
5980 if (windows->info.mapped != MagickFalse )
5981 (void) XWithdrawWindow(display,windows->info.id,
5982 windows->info.screen);
5983 break;
5984 }
5985 case PolygonElement:
5986 case FillPolygonElement:
5987 {
5988 if (number_coordinates > 1)
5989 (void) XDrawLines(display,windows->image.id,
5990 windows->image.highlight_context,coordinate_info,
5991 number_coordinates,CoordModeOrigin);
5992 if (distance > 9)
5993 {
5994 /*
5995 Display angle of the line.
5996 */
5997 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5998 line_info.y1),(double) (line_info.x2-line_info.x1)));
5999 (void) FormatLocaleString(text,MagickPathExtent," %g",
6000 (double) degrees);
6001 XInfoWidget(display,windows,text);
6002 XHighlightLine(display,windows->image.id,
6003 windows->image.highlight_context,&line_info);
6004 }
6005 else
6006 if (windows->info.mapped != MagickFalse )
6007 (void) XWithdrawWindow(display,windows->info.id,
6008 windows->info.screen);
6009 break;
6010 }
6011 }
6012 /*
6013 Wait for next event.
6014 */
6015 XScreenEvent(display,windows,&event,exception);
6016 switch (element)
6017 {
6018 case PointElement:
6019 default:
6020 {
6021 if (number_coordinates > 1)
6022 (void) XDrawLines(display,windows->image.id,
6023 windows->image.highlight_context,coordinate_info,
6024 number_coordinates,CoordModeOrigin);
6025 break;
6026 }
6027 case LineElement:
6028 {
6029 if (distance > 9)
6030 XHighlightLine(display,windows->image.id,
6031 windows->image.highlight_context,&line_info);
6032 break;
6033 }
6034 case RectangleElement:
6035 case FillRectangleElement:
6036 {
6037 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6038 XHighlightRectangle(display,windows->image.id,
6039 windows->image.highlight_context,&rectangle_info);
6040 break;
6041 }
6042 case CircleElement:
6043 case FillCircleElement:
6044 case EllipseElement:
6045 case FillEllipseElement:
6046 {
6047 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6048 XHighlightEllipse(display,windows->image.id,
6049 windows->image.highlight_context,&rectangle_info);
6050 break;
6051 }
6052 case PolygonElement:
6053 case FillPolygonElement:
6054 {
6055 if (number_coordinates > 1)
6056 (void) XDrawLines(display,windows->image.id,
6057 windows->image.highlight_context,coordinate_info,
6058 number_coordinates,CoordModeOrigin);
6059 if (distance > 9)
6060 XHighlightLine(display,windows->image.id,
6061 windows->image.highlight_context,&line_info);
6062 break;
6063 }
6064 }
6065 switch (event.type)
6066 {
6067 case ButtonPress:
6068 break;
6069 case ButtonRelease:
6070 {
6071 /*
6072 User has committed to element.
6073 */
6074 line_info.x2=event.xbutton.x;
6075 line_info.y2=event.xbutton.y;
6076 rectangle_info.x=(ssize_t) event.xbutton.x;
6077 rectangle_info.y=(ssize_t) event.xbutton.y;
6078 coordinate_info[number_coordinates].x=event.xbutton.x;
6079 coordinate_info[number_coordinates].y=event.xbutton.y;
6080 if (((element != PolygonElement) &&
6081 (element != FillPolygonElement)) || (distance <= 9))
6082 {
6083 state|=ExitState;
6084 break;
6085 }
6086 number_coordinates++;
6087 if (number_coordinates < (int) max_coordinates)
6088 {
6089 line_info.x1=event.xbutton.x;
6090 line_info.y1=event.xbutton.y;
6091 break;
6092 }
6093 max_coordinates<<=1;
6094 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6095 max_coordinates,sizeof(*coordinate_info));
6096 if (coordinate_info == (XPoint *) NULL)
6097 (void) ThrowMagickException(exception,GetMagickModule(),
6098 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6099 break;
6100 }
6101 case Expose:
6102 break;
6103 case MotionNotify:
6104 {
6105 if (event.xmotion.window != windows->image.id)
6106 break;
6107 if (element != PointElement)
6108 {
6109 line_info.x2=event.xmotion.x;
6110 line_info.y2=event.xmotion.y;
6111 rectangle_info.x=(ssize_t) event.xmotion.x;
6112 rectangle_info.y=(ssize_t) event.xmotion.y;
6113 break;
6114 }
6115 coordinate_info[number_coordinates].x=event.xbutton.x;
6116 coordinate_info[number_coordinates].y=event.xbutton.y;
6117 number_coordinates++;
6118 if (number_coordinates < (int) max_coordinates)
6119 break;
6120 max_coordinates<<=1;
6121 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6122 max_coordinates,sizeof(*coordinate_info));
6123 if (coordinate_info == (XPoint *) NULL)
6124 (void) ThrowMagickException(exception,GetMagickModule(),
6125 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6126 break;
6127 }
6128 default:
6129 break;
6130 }
6131 /*
6132 Check boundary conditions.
6133 */
6134 if (line_info.x2 < 0)
6135 line_info.x2=0;
6136 else
6137 if (line_info.x2 > (int) windows->image.width)
6138 line_info.x2=(short) windows->image.width;
6139 if (line_info.y2 < 0)
6140 line_info.y2=0;
6141 else
6142 if (line_info.y2 > (int) windows->image.height)
6143 line_info.y2=(short) windows->image.height;
6144 distance=(unsigned int)
6145 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6146 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6147 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6148 ((state & ExitState) != 0))
6149 {
6150 if (rectangle_info.x < 0)
6151 rectangle_info.x=0;
6152 else
6153 if (rectangle_info.x > (ssize_t) windows->image.width)
6154 rectangle_info.x=(ssize_t) windows->image.width;
6155 if ((int) rectangle_info.x < x)
6156 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6157 else
6158 {
6159 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6160 rectangle_info.x=(ssize_t) x;
6161 }
6162 if (rectangle_info.y < 0)
6163 rectangle_info.y=0;
6164 else
6165 if (rectangle_info.y > (ssize_t) windows->image.height)
6166 rectangle_info.y=(ssize_t) windows->image.height;
6167 if ((int) rectangle_info.y < y)
6168 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6169 else
6170 {
6171 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6172 rectangle_info.y=(ssize_t) y;
6173 }
6174 }
6175 } while ((state & ExitState) == 0);
6176 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6177 if ((element == PointElement) || (element == PolygonElement) ||
6178 (element == FillPolygonElement))
6179 {
6180 /*
6181 Determine polygon bounding box.
6182 */
6183 rectangle_info.x=(ssize_t) coordinate_info->x;
6184 rectangle_info.y=(ssize_t) coordinate_info->y;
6185 x=coordinate_info->x;
6186 y=coordinate_info->y;
6187 for (i=1; i < number_coordinates; i++)
6188 {
6189 if (coordinate_info[i].x > x)
6190 x=coordinate_info[i].x;
6191 if (coordinate_info[i].y > y)
6192 y=coordinate_info[i].y;
6193 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6194 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6195 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6196 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6197 }
6198 rectangle_info.width=(size_t) (x-rectangle_info.x);
6199 rectangle_info.height=(size_t) (y-rectangle_info.y);
6200 for (i=0; i < number_coordinates; i++)
6201 {
6202 coordinate_info[i].x-=rectangle_info.x;
6203 coordinate_info[i].y-=rectangle_info.y;
6204 }
6205 }
6206 else
6207 if (distance <= 9)
6208 continue;
6209 else
6210 if ((element == RectangleElement) ||
6211 (element == CircleElement) || (element == EllipseElement))
6212 {
6213 rectangle_info.width--;
6214 rectangle_info.height--;
6215 }
6216 /*
6217 Drawing is relative to image configuration.
6218 */
6219 draw_info.x=(int) rectangle_info.x;
6220 draw_info.y=(int) rectangle_info.y;
6221 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6222 image,exception);
6223 width=(unsigned int) (*image)->columns;
6224 height=(unsigned int) (*image)->rows;
6225 x=0;
6226 y=0;
6227 if (windows->image.crop_geometry != (char *) NULL)
6228 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6229 draw_info.x+=windows->image.x-(line_width/2);
6230 if (draw_info.x < 0)
6231 draw_info.x=0;
6232 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6233 draw_info.y+=windows->image.y-(line_width/2);
6234 if (draw_info.y < 0)
6235 draw_info.y=0;
6236 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6237 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6238 if (draw_info.width > (unsigned int) (*image)->columns)
6239 draw_info.width=(unsigned int) (*image)->columns;
6240 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6241 if (draw_info.height > (unsigned int) (*image)->rows)
6242 draw_info.height=(unsigned int) (*image)->rows;
6243 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d",
6244 width*draw_info.width/windows->image.ximage->width,
6245 height*draw_info.height/windows->image.ximage->height,
6246 draw_info.x+x,draw_info.y+y);
6247 /*
6248 Initialize drawing attributes.
6249 */
6250 draw_info.degrees=0.0;
6251 draw_info.element=element;
6252 draw_info.stipple=stipple;
6253 draw_info.line_width=line_width;
6254 draw_info.line_info=line_info;
6255 if (line_info.x1 > (int) (line_width/2))
6256 draw_info.line_info.x1=(short) line_width/2;
6257 if (line_info.y1 > (int) (line_width/2))
6258 draw_info.line_info.y1=(short) line_width/2;
6259 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6260 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6261 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6262 {
6263 draw_info.line_info.x2=(-draw_info.line_info.x2);
6264 draw_info.line_info.y2=(-draw_info.line_info.y2);
6265 }
6266 if (draw_info.line_info.x2 < 0)
6267 {
6268 draw_info.line_info.x2=(-draw_info.line_info.x2);
6269 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6270 }
6271 if (draw_info.line_info.y2 < 0)
6272 {
6273 draw_info.line_info.y2=(-draw_info.line_info.y2);
6274 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6275 }
6276 draw_info.rectangle_info=rectangle_info;
6277 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6278 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6279 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6280 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6281 draw_info.number_coordinates=(unsigned int) number_coordinates;
6282 draw_info.coordinate_info=coordinate_info;
6283 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6284 /*
6285 Draw element on image.
6286 */
6287 XSetCursorState(display,windows,MagickTrue);
6288 XCheckRefreshWindows(display,windows);
6289 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
6290 XSetCursorState(display,windows,MagickFalse);
6291 /*
6292 Update image colormap and return to image drawing.
6293 */
6294 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6295 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6296 }
6297 XSetCursorState(display,windows,MagickFalse);
6298 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6299 return(status != 0 ? MagickTrue : MagickFalse);
6300 }
6301
6302 /*
6303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6304 % %
6305 % %
6306 % %
6307 + X D r a w P a n R e c t a n g l e %
6308 % %
6309 % %
6310 % %
6311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6312 %
6313 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6314 % displays a zoom image and the rectangle shows which portion of the image is
6315 % displayed in the Image window.
6316 %
6317 % The format of the XDrawPanRectangle method is:
6318 %
6319 % XDrawPanRectangle(Display *display,XWindows *windows)
6320 %
6321 % A description of each parameter follows:
6322 %
6323 % o display: Specifies a connection to an X server; returned from
6324 % XOpenDisplay.
6325 %
6326 % o windows: Specifies a pointer to a XWindows structure.
6327 %
6328 */
XDrawPanRectangle(Display * display,XWindows * windows)6329 static void XDrawPanRectangle(Display *display,XWindows *windows)
6330 {
6331 double
6332 scale_factor;
6333
6334 RectangleInfo
6335 highlight_info;
6336
6337 /*
6338 Determine dimensions of the panning rectangle.
6339 */
6340 scale_factor=(double) windows->pan.width/windows->image.ximage->width;
6341 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6342 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6343 scale_factor=(double)
6344 windows->pan.height/windows->image.ximage->height;
6345 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6346 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6347 /*
6348 Display the panning rectangle.
6349 */
6350 (void) XClearWindow(display,windows->pan.id);
6351 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6352 &highlight_info);
6353 }
6354
6355 /*
6356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6357 % %
6358 % %
6359 % %
6360 + X I m a g e C a c h e %
6361 % %
6362 % %
6363 % %
6364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6365 %
6366 % XImageCache() handles the creation, manipulation, and destruction of the
6367 % image cache (undo and redo buffers).
6368 %
6369 % The format of the XImageCache method is:
6370 %
6371 % void XImageCache(Display *display,XResourceInfo *resource_info,
6372 % XWindows *windows,const CommandType command,Image **image,
6373 % ExceptionInfo *exception)
6374 %
6375 % A description of each parameter follows:
6376 %
6377 % o display: Specifies a connection to an X server; returned from
6378 % XOpenDisplay.
6379 %
6380 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6381 %
6382 % o windows: Specifies a pointer to a XWindows structure.
6383 %
6384 % o command: Specifies a command to perform.
6385 %
6386 % o image: the image; XImageCache may transform the image and return a new
6387 % image pointer.
6388 %
6389 % o exception: return any errors or warnings in this structure.
6390 %
6391 */
XImageCache(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)6392 static void XImageCache(Display *display,XResourceInfo *resource_info,
6393 XWindows *windows,const CommandType command,Image **image,
6394 ExceptionInfo *exception)
6395 {
6396 Image
6397 *cache_image;
6398
6399 static Image
6400 *redo_image = (Image *) NULL,
6401 *undo_image = (Image *) NULL;
6402
6403 switch (command)
6404 {
6405 case FreeBuffersCommand:
6406 {
6407 /*
6408 Free memory from the undo and redo cache.
6409 */
6410 while (undo_image != (Image *) NULL)
6411 {
6412 cache_image=undo_image;
6413 undo_image=GetPreviousImageInList(undo_image);
6414 cache_image->list=DestroyImage(cache_image->list);
6415 cache_image=DestroyImage(cache_image);
6416 }
6417 undo_image=NewImageList();
6418 if (redo_image != (Image *) NULL)
6419 redo_image=DestroyImage(redo_image);
6420 redo_image=NewImageList();
6421 return;
6422 }
6423 case UndoCommand:
6424 {
6425 char
6426 image_geometry[MagickPathExtent];
6427
6428 /*
6429 Undo the last image transformation.
6430 */
6431 if (undo_image == (Image *) NULL)
6432 {
6433 (void) XBell(display,0);
6434 return;
6435 }
6436 cache_image=undo_image;
6437 undo_image=GetPreviousImageInList(undo_image);
6438 windows->image.window_changes.width=(int) cache_image->columns;
6439 windows->image.window_changes.height=(int) cache_image->rows;
6440 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
6441 windows->image.ximage->width,windows->image.ximage->height);
6442 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6443 exception);
6444 if (windows->image.crop_geometry != (char *) NULL)
6445 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6446 windows->image.crop_geometry);
6447 windows->image.crop_geometry=cache_image->geometry;
6448 if (redo_image != (Image *) NULL)
6449 redo_image=DestroyImage(redo_image);
6450 redo_image=(*image);
6451 *image=cache_image->list;
6452 cache_image=DestroyImage(cache_image);
6453 if (windows->image.orphan != MagickFalse )
6454 return;
6455 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6456 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6457 return;
6458 }
6459 case CutCommand:
6460 case PasteCommand:
6461 case ApplyCommand:
6462 case HalfSizeCommand:
6463 case OriginalSizeCommand:
6464 case DoubleSizeCommand:
6465 case ResizeCommand:
6466 case TrimCommand:
6467 case CropCommand:
6468 case ChopCommand:
6469 case FlipCommand:
6470 case FlopCommand:
6471 case RotateRightCommand:
6472 case RotateLeftCommand:
6473 case RotateCommand:
6474 case ShearCommand:
6475 case RollCommand:
6476 case NegateCommand:
6477 case ContrastStretchCommand:
6478 case SigmoidalContrastCommand:
6479 case NormalizeCommand:
6480 case EqualizeCommand:
6481 case HueCommand:
6482 case SaturationCommand:
6483 case BrightnessCommand:
6484 case GammaCommand:
6485 case SpiffCommand:
6486 case DullCommand:
6487 case GrayscaleCommand:
6488 case MapCommand:
6489 case QuantizeCommand:
6490 case DespeckleCommand:
6491 case EmbossCommand:
6492 case ReduceNoiseCommand:
6493 case AddNoiseCommand:
6494 case SharpenCommand:
6495 case BlurCommand:
6496 case ThresholdCommand:
6497 case EdgeDetectCommand:
6498 case SpreadCommand:
6499 case ShadeCommand:
6500 case RaiseCommand:
6501 case SegmentCommand:
6502 case SolarizeCommand:
6503 case SepiaToneCommand:
6504 case SwirlCommand:
6505 case ImplodeCommand:
6506 case VignetteCommand:
6507 case WaveCommand:
6508 case OilPaintCommand:
6509 case CharcoalDrawCommand:
6510 case AnnotateCommand:
6511 case AddBorderCommand:
6512 case AddFrameCommand:
6513 case CompositeCommand:
6514 case CommentCommand:
6515 case LaunchCommand:
6516 case RegionofInterestCommand:
6517 case SaveToUndoBufferCommand:
6518 case RedoCommand:
6519 {
6520 Image
6521 *previous_image;
6522
6523 ssize_t
6524 bytes;
6525
6526 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
6527 if (undo_image != (Image *) NULL)
6528 {
6529 /*
6530 Ensure the undo cache has enough memory available.
6531 */
6532 previous_image=undo_image;
6533 while (previous_image != (Image *) NULL)
6534 {
6535 bytes+=previous_image->list->columns*previous_image->list->rows*
6536 sizeof(PixelInfo);
6537 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6538 {
6539 previous_image=GetPreviousImageInList(previous_image);
6540 continue;
6541 }
6542 bytes-=previous_image->list->columns*previous_image->list->rows*
6543 sizeof(PixelInfo);
6544 if (previous_image == undo_image)
6545 undo_image=NewImageList();
6546 else
6547 previous_image->next->previous=NewImageList();
6548 break;
6549 }
6550 while (previous_image != (Image *) NULL)
6551 {
6552 /*
6553 Delete any excess memory from undo cache.
6554 */
6555 cache_image=previous_image;
6556 previous_image=GetPreviousImageInList(previous_image);
6557 cache_image->list=DestroyImage(cache_image->list);
6558 cache_image=DestroyImage(cache_image);
6559 }
6560 }
6561 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6562 break;
6563 /*
6564 Save image before transformations are applied.
6565 */
6566 cache_image=AcquireImage((ImageInfo *) NULL,exception);
6567 if (cache_image == (Image *) NULL)
6568 break;
6569 XSetCursorState(display,windows,MagickTrue);
6570 XCheckRefreshWindows(display,windows);
6571 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
6572 XSetCursorState(display,windows,MagickFalse);
6573 if (cache_image->list == (Image *) NULL)
6574 {
6575 cache_image=DestroyImage(cache_image);
6576 break;
6577 }
6578 cache_image->columns=(size_t) windows->image.ximage->width;
6579 cache_image->rows=(size_t) windows->image.ximage->height;
6580 cache_image->geometry=windows->image.crop_geometry;
6581 if (windows->image.crop_geometry != (char *) NULL)
6582 {
6583 cache_image->geometry=AcquireString((char *) NULL);
6584 (void) CopyMagickString(cache_image->geometry,
6585 windows->image.crop_geometry,MagickPathExtent);
6586 }
6587 if (undo_image == (Image *) NULL)
6588 {
6589 undo_image=cache_image;
6590 break;
6591 }
6592 undo_image->next=cache_image;
6593 undo_image->next->previous=undo_image;
6594 undo_image=undo_image->next;
6595 break;
6596 }
6597 default:
6598 break;
6599 }
6600 if (command == RedoCommand)
6601 {
6602 /*
6603 Redo the last image transformation.
6604 */
6605 if (redo_image == (Image *) NULL)
6606 {
6607 (void) XBell(display,0);
6608 return;
6609 }
6610 windows->image.window_changes.width=(int) redo_image->columns;
6611 windows->image.window_changes.height=(int) redo_image->rows;
6612 if (windows->image.crop_geometry != (char *) NULL)
6613 windows->image.crop_geometry=(char *)
6614 RelinquishMagickMemory(windows->image.crop_geometry);
6615 windows->image.crop_geometry=redo_image->geometry;
6616 *image=DestroyImage(*image);
6617 *image=redo_image;
6618 redo_image=NewImageList();
6619 if (windows->image.orphan != MagickFalse )
6620 return;
6621 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6622 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6623 return;
6624 }
6625 if (command != InfoCommand)
6626 return;
6627 /*
6628 Display image info.
6629 */
6630 XSetCursorState(display,windows,MagickTrue);
6631 XCheckRefreshWindows(display,windows);
6632 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
6633 XSetCursorState(display,windows,MagickFalse);
6634 }
6635
6636 /*
6637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6638 % %
6639 % %
6640 % %
6641 + X I m a g e W i n d o w C o m m a n d %
6642 % %
6643 % %
6644 % %
6645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6646 %
6647 % XImageWindowCommand() makes a transform to the image or Image window as
6648 % specified by a user menu button or keyboard command.
6649 %
6650 % The format of the XImageWindowCommand method is:
6651 %
6652 % CommandType XImageWindowCommand(Display *display,
6653 % XResourceInfo *resource_info,XWindows *windows,
6654 % const MagickStatusType state,KeySym key_symbol,Image **image,
6655 % ExceptionInfo *exception)
6656 %
6657 % A description of each parameter follows:
6658 %
6659 % o nexus: Method XImageWindowCommand returns an image when the
6660 % user chooses 'Open Image' from the command menu. Otherwise a null
6661 % image is returned.
6662 %
6663 % o display: Specifies a connection to an X server; returned from
6664 % XOpenDisplay.
6665 %
6666 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6667 %
6668 % o windows: Specifies a pointer to a XWindows structure.
6669 %
6670 % o state: key mask.
6671 %
6672 % o key_symbol: Specifies a command to perform.
6673 %
6674 % o image: the image; XImageWIndowCommand may transform the image and
6675 % return a new image pointer.
6676 %
6677 % o exception: return any errors or warnings in this structure.
6678 %
6679 */
XImageWindowCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickStatusType state,KeySym key_symbol,Image ** image,ExceptionInfo * exception)6680 static CommandType XImageWindowCommand(Display *display,
6681 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6682 KeySym key_symbol,Image **image,ExceptionInfo *exception)
6683 {
6684 static char
6685 delta[MagickPathExtent] = "";
6686
6687 static const char
6688 Digits[] = "01234567890";
6689
6690 static KeySym
6691 last_symbol = XK_0;
6692
6693 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6694 {
6695 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6696 {
6697 *delta='\0';
6698 resource_info->quantum=1;
6699 }
6700 last_symbol=key_symbol;
6701 delta[strlen(delta)+1]='\0';
6702 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6703 resource_info->quantum=StringToLong(delta);
6704 return(NullCommand);
6705 }
6706 last_symbol=key_symbol;
6707 if (resource_info->immutable)
6708 {
6709 /*
6710 Virtual image window has a restricted command set.
6711 */
6712 switch (key_symbol)
6713 {
6714 case XK_question:
6715 return(InfoCommand);
6716 case XK_p:
6717 case XK_Print:
6718 return(PrintCommand);
6719 case XK_space:
6720 return(NextCommand);
6721 case XK_q:
6722 case XK_Escape:
6723 return(QuitCommand);
6724 default:
6725 break;
6726 }
6727 return(NullCommand);
6728 }
6729 switch ((int) key_symbol)
6730 {
6731 case XK_o:
6732 {
6733 if ((state & ControlMask) == 0)
6734 break;
6735 return(OpenCommand);
6736 }
6737 case XK_space:
6738 return(NextCommand);
6739 case XK_BackSpace:
6740 return(FormerCommand);
6741 case XK_s:
6742 {
6743 if ((state & Mod1Mask) != 0)
6744 return(SwirlCommand);
6745 if ((state & ControlMask) == 0)
6746 return(ShearCommand);
6747 return(SaveCommand);
6748 }
6749 case XK_p:
6750 case XK_Print:
6751 {
6752 if ((state & Mod1Mask) != 0)
6753 return(OilPaintCommand);
6754 if ((state & Mod4Mask) != 0)
6755 return(ColorCommand);
6756 if ((state & ControlMask) == 0)
6757 return(NullCommand);
6758 return(PrintCommand);
6759 }
6760 case XK_d:
6761 {
6762 if ((state & Mod4Mask) != 0)
6763 return(DrawCommand);
6764 if ((state & ControlMask) == 0)
6765 return(NullCommand);
6766 return(DeleteCommand);
6767 }
6768 case XK_Select:
6769 {
6770 if ((state & ControlMask) == 0)
6771 return(NullCommand);
6772 return(SelectCommand);
6773 }
6774 case XK_n:
6775 {
6776 if ((state & ControlMask) == 0)
6777 return(NullCommand);
6778 return(NewCommand);
6779 }
6780 case XK_q:
6781 case XK_Escape:
6782 return(QuitCommand);
6783 case XK_z:
6784 case XK_Undo:
6785 {
6786 if ((state & ControlMask) == 0)
6787 return(NullCommand);
6788 return(UndoCommand);
6789 }
6790 case XK_r:
6791 case XK_Redo:
6792 {
6793 if ((state & ControlMask) == 0)
6794 return(RollCommand);
6795 return(RedoCommand);
6796 }
6797 case XK_x:
6798 {
6799 if ((state & ControlMask) == 0)
6800 return(NullCommand);
6801 return(CutCommand);
6802 }
6803 case XK_c:
6804 {
6805 if ((state & Mod1Mask) != 0)
6806 return(CharcoalDrawCommand);
6807 if ((state & ControlMask) == 0)
6808 return(CropCommand);
6809 return(CopyCommand);
6810 }
6811 case XK_v:
6812 case XK_Insert:
6813 {
6814 if ((state & Mod4Mask) != 0)
6815 return(CompositeCommand);
6816 if ((state & ControlMask) == 0)
6817 return(FlipCommand);
6818 return(PasteCommand);
6819 }
6820 case XK_less:
6821 return(HalfSizeCommand);
6822 case XK_minus:
6823 return(OriginalSizeCommand);
6824 case XK_greater:
6825 return(DoubleSizeCommand);
6826 case XK_percent:
6827 return(ResizeCommand);
6828 case XK_at:
6829 return(RefreshCommand);
6830 case XK_bracketleft:
6831 return(ChopCommand);
6832 case XK_h:
6833 return(FlopCommand);
6834 case XK_slash:
6835 return(RotateRightCommand);
6836 case XK_backslash:
6837 return(RotateLeftCommand);
6838 case XK_asterisk:
6839 return(RotateCommand);
6840 case XK_t:
6841 return(TrimCommand);
6842 case XK_H:
6843 return(HueCommand);
6844 case XK_S:
6845 return(SaturationCommand);
6846 case XK_L:
6847 return(BrightnessCommand);
6848 case XK_G:
6849 return(GammaCommand);
6850 case XK_C:
6851 return(SpiffCommand);
6852 case XK_Z:
6853 return(DullCommand);
6854 case XK_N:
6855 return(NormalizeCommand);
6856 case XK_equal:
6857 return(EqualizeCommand);
6858 case XK_asciitilde:
6859 return(NegateCommand);
6860 case XK_period:
6861 return(GrayscaleCommand);
6862 case XK_numbersign:
6863 return(QuantizeCommand);
6864 case XK_F2:
6865 return(DespeckleCommand);
6866 case XK_F3:
6867 return(EmbossCommand);
6868 case XK_F4:
6869 return(ReduceNoiseCommand);
6870 case XK_F5:
6871 return(AddNoiseCommand);
6872 case XK_F6:
6873 return(SharpenCommand);
6874 case XK_F7:
6875 return(BlurCommand);
6876 case XK_F8:
6877 return(ThresholdCommand);
6878 case XK_F9:
6879 return(EdgeDetectCommand);
6880 case XK_F10:
6881 return(SpreadCommand);
6882 case XK_F11:
6883 return(ShadeCommand);
6884 case XK_F12:
6885 return(RaiseCommand);
6886 case XK_F13:
6887 return(SegmentCommand);
6888 case XK_i:
6889 {
6890 if ((state & Mod1Mask) == 0)
6891 return(NullCommand);
6892 return(ImplodeCommand);
6893 }
6894 case XK_w:
6895 {
6896 if ((state & Mod1Mask) == 0)
6897 return(NullCommand);
6898 return(WaveCommand);
6899 }
6900 case XK_m:
6901 {
6902 if ((state & Mod4Mask) == 0)
6903 return(NullCommand);
6904 return(MatteCommand);
6905 }
6906 case XK_b:
6907 {
6908 if ((state & Mod4Mask) == 0)
6909 return(NullCommand);
6910 return(AddBorderCommand);
6911 }
6912 case XK_f:
6913 {
6914 if ((state & Mod4Mask) == 0)
6915 return(NullCommand);
6916 return(AddFrameCommand);
6917 }
6918 case XK_exclam:
6919 {
6920 if ((state & Mod4Mask) == 0)
6921 return(NullCommand);
6922 return(CommentCommand);
6923 }
6924 case XK_a:
6925 {
6926 if ((state & Mod1Mask) != 0)
6927 return(ApplyCommand);
6928 if ((state & Mod4Mask) != 0)
6929 return(AnnotateCommand);
6930 if ((state & ControlMask) == 0)
6931 return(NullCommand);
6932 return(RegionofInterestCommand);
6933 }
6934 case XK_question:
6935 return(InfoCommand);
6936 case XK_plus:
6937 return(ZoomCommand);
6938 case XK_P:
6939 {
6940 if ((state & ShiftMask) == 0)
6941 return(NullCommand);
6942 return(ShowPreviewCommand);
6943 }
6944 case XK_Execute:
6945 return(LaunchCommand);
6946 case XK_F1:
6947 return(HelpCommand);
6948 case XK_Find:
6949 return(BrowseDocumentationCommand);
6950 case XK_Menu:
6951 {
6952 (void) XMapRaised(display,windows->command.id);
6953 return(NullCommand);
6954 }
6955 case XK_Next:
6956 case XK_Prior:
6957 case XK_Home:
6958 case XK_KP_Home:
6959 {
6960 XTranslateImage(display,windows,*image,key_symbol);
6961 return(NullCommand);
6962 }
6963 case XK_Up:
6964 case XK_KP_Up:
6965 case XK_Down:
6966 case XK_KP_Down:
6967 case XK_Left:
6968 case XK_KP_Left:
6969 case XK_Right:
6970 case XK_KP_Right:
6971 {
6972 if ((state & Mod1Mask) != 0)
6973 {
6974 RectangleInfo
6975 crop_info;
6976
6977 /*
6978 Trim one pixel from edge of image.
6979 */
6980 crop_info.x=0;
6981 crop_info.y=0;
6982 crop_info.width=(size_t) windows->image.ximage->width;
6983 crop_info.height=(size_t) windows->image.ximage->height;
6984 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6985 {
6986 if (resource_info->quantum >= (int) crop_info.height)
6987 resource_info->quantum=(int) crop_info.height-1;
6988 crop_info.height-=resource_info->quantum;
6989 }
6990 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6991 {
6992 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6993 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6994 crop_info.y+=resource_info->quantum;
6995 crop_info.height-=resource_info->quantum;
6996 }
6997 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6998 {
6999 if (resource_info->quantum >= (int) crop_info.width)
7000 resource_info->quantum=(int) crop_info.width-1;
7001 crop_info.width-=resource_info->quantum;
7002 }
7003 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7004 {
7005 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7006 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7007 crop_info.x+=resource_info->quantum;
7008 crop_info.width-=resource_info->quantum;
7009 }
7010 if ((int) (windows->image.x+windows->image.width) >
7011 (int) crop_info.width)
7012 windows->image.x=(int) (crop_info.width-windows->image.width);
7013 if ((int) (windows->image.y+windows->image.height) >
7014 (int) crop_info.height)
7015 windows->image.y=(int) (crop_info.height-windows->image.height);
7016 XSetCropGeometry(display,windows,&crop_info,*image);
7017 windows->image.window_changes.width=(int) crop_info.width;
7018 windows->image.window_changes.height=(int) crop_info.height;
7019 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7020 (void) XConfigureImage(display,resource_info,windows,*image,
7021 exception);
7022 return(NullCommand);
7023 }
7024 XTranslateImage(display,windows,*image,key_symbol);
7025 return(NullCommand);
7026 }
7027 default:
7028 return(NullCommand);
7029 }
7030 return(NullCommand);
7031 }
7032
7033 /*
7034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7035 % %
7036 % %
7037 % %
7038 + X M a g i c k C o m m a n d %
7039 % %
7040 % %
7041 % %
7042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7043 %
7044 % XMagickCommand() makes a transform to the image or Image window as
7045 % specified by a user menu button or keyboard command.
7046 %
7047 % The format of the XMagickCommand method is:
7048 %
7049 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7050 % XWindows *windows,const CommandType command,Image **image,
7051 % ExceptionInfo *exception)
7052 %
7053 % A description of each parameter follows:
7054 %
7055 % o display: Specifies a connection to an X server; returned from
7056 % XOpenDisplay.
7057 %
7058 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7059 %
7060 % o windows: Specifies a pointer to a XWindows structure.
7061 %
7062 % o command: Specifies a command to perform.
7063 %
7064 % o image: the image; XMagickCommand may transform the image and return a
7065 % new image pointer.
7066 %
7067 % o exception: return any errors or warnings in this structure.
7068 %
7069 */
XMagickCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)7070 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7071 XWindows *windows,const CommandType command,Image **image,
7072 ExceptionInfo *exception)
7073 {
7074 char
7075 filename[MagickPathExtent],
7076 geometry[MagickPathExtent],
7077 modulate_factors[MagickPathExtent];
7078
7079 GeometryInfo
7080 geometry_info;
7081
7082 Image
7083 *nexus;
7084
7085 ImageInfo
7086 *image_info;
7087
7088 int
7089 x,
7090 y;
7091
7092 MagickStatusType
7093 flags,
7094 status;
7095
7096 QuantizeInfo
7097 quantize_info;
7098
7099 RectangleInfo
7100 page_geometry;
7101
7102 register int
7103 i;
7104
7105 static char
7106 color[MagickPathExtent] = "gray";
7107
7108 unsigned int
7109 height,
7110 width;
7111
7112 /*
7113 Process user command.
7114 */
7115 XCheckRefreshWindows(display,windows);
7116 XImageCache(display,resource_info,windows,command,image,exception);
7117 nexus=NewImageList();
7118 windows->image.window_changes.width=windows->image.ximage->width;
7119 windows->image.window_changes.height=windows->image.ximage->height;
7120 image_info=CloneImageInfo(resource_info->image_info);
7121 SetGeometryInfo(&geometry_info);
7122 GetQuantizeInfo(&quantize_info);
7123 switch (command)
7124 {
7125 case OpenCommand:
7126 {
7127 /*
7128 Load image.
7129 */
7130 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7131 break;
7132 }
7133 case NextCommand:
7134 {
7135 /*
7136 Display next image.
7137 */
7138 for (i=0; i < resource_info->quantum; i++)
7139 XClientMessage(display,windows->image.id,windows->im_protocols,
7140 windows->im_next_image,CurrentTime);
7141 break;
7142 }
7143 case FormerCommand:
7144 {
7145 /*
7146 Display former image.
7147 */
7148 for (i=0; i < resource_info->quantum; i++)
7149 XClientMessage(display,windows->image.id,windows->im_protocols,
7150 windows->im_former_image,CurrentTime);
7151 break;
7152 }
7153 case SelectCommand:
7154 {
7155 int
7156 status;
7157
7158 /*
7159 Select image.
7160 */
7161 if (*resource_info->home_directory == '\0')
7162 (void) CopyMagickString(resource_info->home_directory,".",
7163 MagickPathExtent);
7164 status=chdir(resource_info->home_directory);
7165 if (status == -1)
7166 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7167 "UnableToOpenFile","%s",resource_info->home_directory);
7168 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7169 break;
7170 }
7171 case SaveCommand:
7172 {
7173 /*
7174 Save image.
7175 */
7176 status=XSaveImage(display,resource_info,windows,*image,exception);
7177 if (status == MagickFalse)
7178 {
7179 char
7180 message[MagickPathExtent];
7181
7182 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7183 exception->reason != (char *) NULL ? exception->reason : "",
7184 exception->description != (char *) NULL ? exception->description :
7185 "");
7186 XNoticeWidget(display,windows,"Unable to save file:",message);
7187 break;
7188 }
7189 break;
7190 }
7191 case PrintCommand:
7192 {
7193 /*
7194 Print image.
7195 */
7196 status=XPrintImage(display,resource_info,windows,*image,exception);
7197 if (status == MagickFalse)
7198 {
7199 char
7200 message[MagickPathExtent];
7201
7202 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7203 exception->reason != (char *) NULL ? exception->reason : "",
7204 exception->description != (char *) NULL ? exception->description :
7205 "");
7206 XNoticeWidget(display,windows,"Unable to print file:",message);
7207 break;
7208 }
7209 break;
7210 }
7211 case DeleteCommand:
7212 {
7213 static char
7214 filename[MagickPathExtent] = "\0";
7215
7216 /*
7217 Delete image file.
7218 */
7219 XFileBrowserWidget(display,windows,"Delete",filename);
7220 if (*filename == '\0')
7221 break;
7222 status=ShredFile(filename);
7223 if (status != MagickFalse )
7224 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7225 break;
7226 }
7227 case NewCommand:
7228 {
7229 int
7230 status;
7231
7232 static char
7233 color[MagickPathExtent] = "gray",
7234 geometry[MagickPathExtent] = "640x480";
7235
7236 static const char
7237 *format = "gradient";
7238
7239 /*
7240 Query user for canvas geometry.
7241 */
7242 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7243 geometry);
7244 if (*geometry == '\0')
7245 break;
7246 if (status == 0)
7247 format="xc";
7248 XColorBrowserWidget(display,windows,"Select",color);
7249 if (*color == '\0')
7250 break;
7251 /*
7252 Create canvas.
7253 */
7254 (void) FormatLocaleString(image_info->filename,MagickPathExtent,
7255 "%s:%s",format,color);
7256 (void) CloneString(&image_info->size,geometry);
7257 nexus=ReadImage(image_info,exception);
7258 CatchException(exception);
7259 XClientMessage(display,windows->image.id,windows->im_protocols,
7260 windows->im_next_image,CurrentTime);
7261 break;
7262 }
7263 case VisualDirectoryCommand:
7264 {
7265 /*
7266 Visual Image directory.
7267 */
7268 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
7269 break;
7270 }
7271 case QuitCommand:
7272 {
7273 /*
7274 exit program.
7275 */
7276 if (resource_info->confirm_exit == MagickFalse)
7277 XClientMessage(display,windows->image.id,windows->im_protocols,
7278 windows->im_exit,CurrentTime);
7279 else
7280 {
7281 int
7282 status;
7283
7284 /*
7285 Confirm program exit.
7286 */
7287 status=XConfirmWidget(display,windows,"Do you really want to exit",
7288 resource_info->client_name);
7289 if (status > 0)
7290 XClientMessage(display,windows->image.id,windows->im_protocols,
7291 windows->im_exit,CurrentTime);
7292 }
7293 break;
7294 }
7295 case CutCommand:
7296 {
7297 /*
7298 Cut image.
7299 */
7300 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
7301 break;
7302 }
7303 case CopyCommand:
7304 {
7305 /*
7306 Copy image.
7307 */
7308 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7309 exception);
7310 break;
7311 }
7312 case PasteCommand:
7313 {
7314 /*
7315 Paste image.
7316 */
7317 status=XPasteImage(display,resource_info,windows,*image,exception);
7318 if (status == MagickFalse)
7319 {
7320 XNoticeWidget(display,windows,"Unable to paste X image",
7321 (*image)->filename);
7322 break;
7323 }
7324 break;
7325 }
7326 case HalfSizeCommand:
7327 {
7328 /*
7329 Half image size.
7330 */
7331 windows->image.window_changes.width=windows->image.ximage->width/2;
7332 windows->image.window_changes.height=windows->image.ximage->height/2;
7333 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7334 break;
7335 }
7336 case OriginalSizeCommand:
7337 {
7338 /*
7339 Original image size.
7340 */
7341 windows->image.window_changes.width=(int) (*image)->columns;
7342 windows->image.window_changes.height=(int) (*image)->rows;
7343 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7344 break;
7345 }
7346 case DoubleSizeCommand:
7347 {
7348 /*
7349 Double the image size.
7350 */
7351 windows->image.window_changes.width=windows->image.ximage->width << 1;
7352 windows->image.window_changes.height=windows->image.ximage->height << 1;
7353 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7354 break;
7355 }
7356 case ResizeCommand:
7357 {
7358 int
7359 status;
7360
7361 size_t
7362 height,
7363 width;
7364
7365 ssize_t
7366 x,
7367 y;
7368
7369 /*
7370 Resize image.
7371 */
7372 width=(size_t) windows->image.ximage->width;
7373 height=(size_t) windows->image.ximage->height;
7374 x=0;
7375 y=0;
7376 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0",
7377 (double) width,(double) height);
7378 status=XDialogWidget(display,windows,"Resize",
7379 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7380 if (*geometry == '\0')
7381 break;
7382 if (status == 0)
7383 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent);
7384 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7385 windows->image.window_changes.width=(int) width;
7386 windows->image.window_changes.height=(int) height;
7387 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7388 break;
7389 }
7390 case ApplyCommand:
7391 {
7392 char
7393 image_geometry[MagickPathExtent];
7394
7395 if ((windows->image.crop_geometry == (char *) NULL) &&
7396 ((int) (*image)->columns == windows->image.ximage->width) &&
7397 ((int) (*image)->rows == windows->image.ximage->height))
7398 break;
7399 /*
7400 Apply size transforms to image.
7401 */
7402 XSetCursorState(display,windows,MagickTrue);
7403 XCheckRefreshWindows(display,windows);
7404 /*
7405 Crop and/or scale displayed image.
7406 */
7407 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
7408 windows->image.ximage->width,windows->image.ximage->height);
7409 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7410 exception);
7411 if (windows->image.crop_geometry != (char *) NULL)
7412 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7413 windows->image.crop_geometry);
7414 windows->image.x=0;
7415 windows->image.y=0;
7416 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7417 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7418 break;
7419 }
7420 case RefreshCommand:
7421 {
7422 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7423 break;
7424 }
7425 case RestoreCommand:
7426 {
7427 /*
7428 Restore Image window to its original size.
7429 */
7430 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7431 (windows->image.height == (unsigned int) (*image)->rows) &&
7432 (windows->image.crop_geometry == (char *) NULL))
7433 {
7434 (void) XBell(display,0);
7435 break;
7436 }
7437 windows->image.window_changes.width=(int) (*image)->columns;
7438 windows->image.window_changes.height=(int) (*image)->rows;
7439 if (windows->image.crop_geometry != (char *) NULL)
7440 {
7441 windows->image.crop_geometry=(char *)
7442 RelinquishMagickMemory(windows->image.crop_geometry);
7443 windows->image.crop_geometry=(char *) NULL;
7444 windows->image.x=0;
7445 windows->image.y=0;
7446 }
7447 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7448 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7449 break;
7450 }
7451 case CropCommand:
7452 {
7453 /*
7454 Crop image.
7455 */
7456 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7457 exception);
7458 break;
7459 }
7460 case ChopCommand:
7461 {
7462 /*
7463 Chop image.
7464 */
7465 status=XChopImage(display,resource_info,windows,image,exception);
7466 if (status == MagickFalse)
7467 {
7468 XNoticeWidget(display,windows,"Unable to cut X image",
7469 (*image)->filename);
7470 break;
7471 }
7472 break;
7473 }
7474 case FlopCommand:
7475 {
7476 Image
7477 *flop_image;
7478
7479 /*
7480 Flop image scanlines.
7481 */
7482 XSetCursorState(display,windows,MagickTrue);
7483 XCheckRefreshWindows(display,windows);
7484 flop_image=FlopImage(*image,exception);
7485 if (flop_image != (Image *) NULL)
7486 {
7487 *image=DestroyImage(*image);
7488 *image=flop_image;
7489 }
7490 CatchException(exception);
7491 XSetCursorState(display,windows,MagickFalse);
7492 if (windows->image.crop_geometry != (char *) NULL)
7493 {
7494 /*
7495 Flop crop geometry.
7496 */
7497 width=(unsigned int) (*image)->columns;
7498 height=(unsigned int) (*image)->rows;
7499 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7500 &width,&height);
7501 (void) FormatLocaleString(windows->image.crop_geometry,
7502 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) (*image)->columns-
7503 (int) width-x,y);
7504 }
7505 if (windows->image.orphan != MagickFalse )
7506 break;
7507 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7508 break;
7509 }
7510 case FlipCommand:
7511 {
7512 Image
7513 *flip_image;
7514
7515 /*
7516 Flip image scanlines.
7517 */
7518 XSetCursorState(display,windows,MagickTrue);
7519 XCheckRefreshWindows(display,windows);
7520 flip_image=FlipImage(*image,exception);
7521 if (flip_image != (Image *) NULL)
7522 {
7523 *image=DestroyImage(*image);
7524 *image=flip_image;
7525 }
7526 CatchException(exception);
7527 XSetCursorState(display,windows,MagickFalse);
7528 if (windows->image.crop_geometry != (char *) NULL)
7529 {
7530 /*
7531 Flip crop geometry.
7532 */
7533 width=(unsigned int) (*image)->columns;
7534 height=(unsigned int) (*image)->rows;
7535 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7536 &width,&height);
7537 (void) FormatLocaleString(windows->image.crop_geometry,
7538 MagickPathExtent,"%ux%u%+d%+d",width,height,x,(int) (*image)->rows-
7539 (int) height-y);
7540 }
7541 if (windows->image.orphan != MagickFalse )
7542 break;
7543 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7544 break;
7545 }
7546 case RotateRightCommand:
7547 {
7548 /*
7549 Rotate image 90 degrees clockwise.
7550 */
7551 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
7552 if (status == MagickFalse)
7553 {
7554 XNoticeWidget(display,windows,"Unable to rotate X image",
7555 (*image)->filename);
7556 break;
7557 }
7558 break;
7559 }
7560 case RotateLeftCommand:
7561 {
7562 /*
7563 Rotate image 90 degrees counter-clockwise.
7564 */
7565 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
7566 if (status == MagickFalse)
7567 {
7568 XNoticeWidget(display,windows,"Unable to rotate X image",
7569 (*image)->filename);
7570 break;
7571 }
7572 break;
7573 }
7574 case RotateCommand:
7575 {
7576 /*
7577 Rotate image.
7578 */
7579 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
7580 if (status == MagickFalse)
7581 {
7582 XNoticeWidget(display,windows,"Unable to rotate X image",
7583 (*image)->filename);
7584 break;
7585 }
7586 break;
7587 }
7588 case ShearCommand:
7589 {
7590 Image
7591 *shear_image;
7592
7593 static char
7594 geometry[MagickPathExtent] = "45.0x45.0";
7595
7596 /*
7597 Query user for shear color and geometry.
7598 */
7599 XColorBrowserWidget(display,windows,"Select",color);
7600 if (*color == '\0')
7601 break;
7602 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7603 geometry);
7604 if (*geometry == '\0')
7605 break;
7606 /*
7607 Shear image.
7608 */
7609 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7610 exception);
7611 XSetCursorState(display,windows,MagickTrue);
7612 XCheckRefreshWindows(display,windows);
7613 (void) QueryColorCompliance(color,AllCompliance,
7614 &(*image)->background_color,exception);
7615 flags=ParseGeometry(geometry,&geometry_info);
7616 if ((flags & SigmaValue) == 0)
7617 geometry_info.sigma=geometry_info.rho;
7618 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7619 exception);
7620 if (shear_image != (Image *) NULL)
7621 {
7622 *image=DestroyImage(*image);
7623 *image=shear_image;
7624 }
7625 CatchException(exception);
7626 XSetCursorState(display,windows,MagickFalse);
7627 if (windows->image.orphan != MagickFalse )
7628 break;
7629 windows->image.window_changes.width=(int) (*image)->columns;
7630 windows->image.window_changes.height=(int) (*image)->rows;
7631 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7632 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7633 break;
7634 }
7635 case RollCommand:
7636 {
7637 Image
7638 *roll_image;
7639
7640 static char
7641 geometry[MagickPathExtent] = "+2+2";
7642
7643 /*
7644 Query user for the roll geometry.
7645 */
7646 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7647 geometry);
7648 if (*geometry == '\0')
7649 break;
7650 /*
7651 Roll image.
7652 */
7653 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7654 exception);
7655 XSetCursorState(display,windows,MagickTrue);
7656 XCheckRefreshWindows(display,windows);
7657 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7658 exception);
7659 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7660 exception);
7661 if (roll_image != (Image *) NULL)
7662 {
7663 *image=DestroyImage(*image);
7664 *image=roll_image;
7665 }
7666 CatchException(exception);
7667 XSetCursorState(display,windows,MagickFalse);
7668 if (windows->image.orphan != MagickFalse )
7669 break;
7670 windows->image.window_changes.width=(int) (*image)->columns;
7671 windows->image.window_changes.height=(int) (*image)->rows;
7672 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7673 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7674 break;
7675 }
7676 case TrimCommand:
7677 {
7678 static char
7679 fuzz[MagickPathExtent];
7680
7681 /*
7682 Query user for the fuzz factor.
7683 */
7684 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0*
7685 (*image)->fuzz/(QuantumRange+1.0));
7686 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7687 if (*fuzz == '\0')
7688 break;
7689 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7690 /*
7691 Trim image.
7692 */
7693 status=XTrimImage(display,resource_info,windows,*image,exception);
7694 if (status == MagickFalse)
7695 {
7696 XNoticeWidget(display,windows,"Unable to trim X image",
7697 (*image)->filename);
7698 break;
7699 }
7700 break;
7701 }
7702 case HueCommand:
7703 {
7704 static char
7705 hue_percent[MagickPathExtent] = "110";
7706
7707 /*
7708 Query user for percent hue change.
7709 */
7710 (void) XDialogWidget(display,windows,"Apply",
7711 "Enter percent change in image hue (0-200):",hue_percent);
7712 if (*hue_percent == '\0')
7713 break;
7714 /*
7715 Vary the image hue.
7716 */
7717 XSetCursorState(display,windows,MagickTrue);
7718 XCheckRefreshWindows(display,windows);
7719 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent);
7720 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7721 MagickPathExtent);
7722 (void) ModulateImage(*image,modulate_factors,exception);
7723 XSetCursorState(display,windows,MagickFalse);
7724 if (windows->image.orphan != MagickFalse )
7725 break;
7726 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7727 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7728 break;
7729 }
7730 case SaturationCommand:
7731 {
7732 static char
7733 saturation_percent[MagickPathExtent] = "110";
7734
7735 /*
7736 Query user for percent saturation change.
7737 */
7738 (void) XDialogWidget(display,windows,"Apply",
7739 "Enter percent change in color saturation (0-200):",saturation_percent);
7740 if (*saturation_percent == '\0')
7741 break;
7742 /*
7743 Vary color saturation.
7744 */
7745 XSetCursorState(display,windows,MagickTrue);
7746 XCheckRefreshWindows(display,windows);
7747 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent);
7748 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7749 MagickPathExtent);
7750 (void) ModulateImage(*image,modulate_factors,exception);
7751 XSetCursorState(display,windows,MagickFalse);
7752 if (windows->image.orphan != MagickFalse )
7753 break;
7754 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7755 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7756 break;
7757 }
7758 case BrightnessCommand:
7759 {
7760 static char
7761 brightness_percent[MagickPathExtent] = "110";
7762
7763 /*
7764 Query user for percent brightness change.
7765 */
7766 (void) XDialogWidget(display,windows,"Apply",
7767 "Enter percent change in color brightness (0-200):",brightness_percent);
7768 if (*brightness_percent == '\0')
7769 break;
7770 /*
7771 Vary the color brightness.
7772 */
7773 XSetCursorState(display,windows,MagickTrue);
7774 XCheckRefreshWindows(display,windows);
7775 (void) CopyMagickString(modulate_factors,brightness_percent,
7776 MagickPathExtent);
7777 (void) ModulateImage(*image,modulate_factors,exception);
7778 XSetCursorState(display,windows,MagickFalse);
7779 if (windows->image.orphan != MagickFalse )
7780 break;
7781 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7782 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7783 break;
7784 }
7785 case GammaCommand:
7786 {
7787 static char
7788 factor[MagickPathExtent] = "1.6";
7789
7790 /*
7791 Query user for gamma value.
7792 */
7793 (void) XDialogWidget(display,windows,"Gamma",
7794 "Enter gamma value (e.g. 1.2):",factor);
7795 if (*factor == '\0')
7796 break;
7797 /*
7798 Gamma correct image.
7799 */
7800 XSetCursorState(display,windows,MagickTrue);
7801 XCheckRefreshWindows(display,windows);
7802 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception);
7803 XSetCursorState(display,windows,MagickFalse);
7804 if (windows->image.orphan != MagickFalse )
7805 break;
7806 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7807 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7808 break;
7809 }
7810 case SpiffCommand:
7811 {
7812 /*
7813 Sharpen the image contrast.
7814 */
7815 XSetCursorState(display,windows,MagickTrue);
7816 XCheckRefreshWindows(display,windows);
7817 (void) ContrastImage(*image,MagickTrue,exception);
7818 XSetCursorState(display,windows,MagickFalse);
7819 if (windows->image.orphan != MagickFalse )
7820 break;
7821 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7822 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7823 break;
7824 }
7825 case DullCommand:
7826 {
7827 /*
7828 Dull the image contrast.
7829 */
7830 XSetCursorState(display,windows,MagickTrue);
7831 XCheckRefreshWindows(display,windows);
7832 (void) ContrastImage(*image,MagickFalse,exception);
7833 XSetCursorState(display,windows,MagickFalse);
7834 if (windows->image.orphan != MagickFalse )
7835 break;
7836 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7837 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7838 break;
7839 }
7840 case ContrastStretchCommand:
7841 {
7842 double
7843 black_point,
7844 white_point;
7845
7846 static char
7847 levels[MagickPathExtent] = "1%";
7848
7849 /*
7850 Query user for gamma value.
7851 */
7852 (void) XDialogWidget(display,windows,"Contrast Stretch",
7853 "Enter black and white points:",levels);
7854 if (*levels == '\0')
7855 break;
7856 /*
7857 Contrast stretch image.
7858 */
7859 XSetCursorState(display,windows,MagickTrue);
7860 XCheckRefreshWindows(display,windows);
7861 flags=ParseGeometry(levels,&geometry_info);
7862 black_point=geometry_info.rho;
7863 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7864 if ((flags & PercentValue) != 0)
7865 {
7866 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7867 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7868 }
7869 white_point=(double) (*image)->columns*(*image)->rows-white_point;
7870 (void) ContrastStretchImage(*image,black_point,white_point,
7871 exception);
7872 XSetCursorState(display,windows,MagickFalse);
7873 if (windows->image.orphan != MagickFalse )
7874 break;
7875 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7876 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7877 break;
7878 }
7879 case SigmoidalContrastCommand:
7880 {
7881 GeometryInfo
7882 geometry_info;
7883
7884 MagickStatusType
7885 flags;
7886
7887 static char
7888 levels[MagickPathExtent] = "3x50%";
7889
7890 /*
7891 Query user for gamma value.
7892 */
7893 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7894 "Enter contrast and midpoint:",levels);
7895 if (*levels == '\0')
7896 break;
7897 /*
7898 Contrast stretch image.
7899 */
7900 XSetCursorState(display,windows,MagickTrue);
7901 XCheckRefreshWindows(display,windows);
7902 flags=ParseGeometry(levels,&geometry_info);
7903 if ((flags & SigmaValue) == 0)
7904 geometry_info.sigma=1.0*QuantumRange/2.0;
7905 if ((flags & PercentValue) != 0)
7906 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7907 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7908 geometry_info.sigma,exception);
7909 XSetCursorState(display,windows,MagickFalse);
7910 if (windows->image.orphan != MagickFalse )
7911 break;
7912 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7913 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7914 break;
7915 }
7916 case NormalizeCommand:
7917 {
7918 /*
7919 Perform histogram normalization on the image.
7920 */
7921 XSetCursorState(display,windows,MagickTrue);
7922 XCheckRefreshWindows(display,windows);
7923 (void) NormalizeImage(*image,exception);
7924 XSetCursorState(display,windows,MagickFalse);
7925 if (windows->image.orphan != MagickFalse )
7926 break;
7927 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7928 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7929 break;
7930 }
7931 case EqualizeCommand:
7932 {
7933 /*
7934 Perform histogram equalization on the image.
7935 */
7936 XSetCursorState(display,windows,MagickTrue);
7937 XCheckRefreshWindows(display,windows);
7938 (void) EqualizeImage(*image,exception);
7939 XSetCursorState(display,windows,MagickFalse);
7940 if (windows->image.orphan != MagickFalse )
7941 break;
7942 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7943 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7944 break;
7945 }
7946 case NegateCommand:
7947 {
7948 /*
7949 Negate colors in image.
7950 */
7951 XSetCursorState(display,windows,MagickTrue);
7952 XCheckRefreshWindows(display,windows);
7953 (void) NegateImage(*image,MagickFalse,exception);
7954 XSetCursorState(display,windows,MagickFalse);
7955 if (windows->image.orphan != MagickFalse )
7956 break;
7957 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7958 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7959 break;
7960 }
7961 case GrayscaleCommand:
7962 {
7963 /*
7964 Convert image to grayscale.
7965 */
7966 XSetCursorState(display,windows,MagickTrue);
7967 XCheckRefreshWindows(display,windows);
7968 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ?
7969 GrayscaleType : GrayscaleAlphaType,exception);
7970 XSetCursorState(display,windows,MagickFalse);
7971 if (windows->image.orphan != MagickFalse )
7972 break;
7973 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7974 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7975 break;
7976 }
7977 case MapCommand:
7978 {
7979 Image
7980 *affinity_image;
7981
7982 static char
7983 filename[MagickPathExtent] = "\0";
7984
7985 /*
7986 Request image file name from user.
7987 */
7988 XFileBrowserWidget(display,windows,"Map",filename);
7989 if (*filename == '\0')
7990 break;
7991 /*
7992 Map image.
7993 */
7994 XSetCursorState(display,windows,MagickTrue);
7995 XCheckRefreshWindows(display,windows);
7996 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
7997 affinity_image=ReadImage(image_info,exception);
7998 if (affinity_image != (Image *) NULL)
7999 {
8000 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
8001 affinity_image=DestroyImage(affinity_image);
8002 }
8003 CatchException(exception);
8004 XSetCursorState(display,windows,MagickFalse);
8005 if (windows->image.orphan != MagickFalse )
8006 break;
8007 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8008 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8009 break;
8010 }
8011 case QuantizeCommand:
8012 {
8013 int
8014 status;
8015
8016 static char
8017 colors[MagickPathExtent] = "256";
8018
8019 /*
8020 Query user for maximum number of colors.
8021 */
8022 status=XDialogWidget(display,windows,"Quantize",
8023 "Maximum number of colors:",colors);
8024 if (*colors == '\0')
8025 break;
8026 /*
8027 Color reduce the image.
8028 */
8029 XSetCursorState(display,windows,MagickTrue);
8030 XCheckRefreshWindows(display,windows);
8031 quantize_info.number_colors=StringToUnsignedLong(colors);
8032 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8033 NoDitherMethod;
8034 (void) QuantizeImage(&quantize_info,*image,exception);
8035 XSetCursorState(display,windows,MagickFalse);
8036 if (windows->image.orphan != MagickFalse )
8037 break;
8038 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8039 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8040 break;
8041 }
8042 case DespeckleCommand:
8043 {
8044 Image
8045 *despeckle_image;
8046
8047 /*
8048 Despeckle image.
8049 */
8050 XSetCursorState(display,windows,MagickTrue);
8051 XCheckRefreshWindows(display,windows);
8052 despeckle_image=DespeckleImage(*image,exception);
8053 if (despeckle_image != (Image *) NULL)
8054 {
8055 *image=DestroyImage(*image);
8056 *image=despeckle_image;
8057 }
8058 CatchException(exception);
8059 XSetCursorState(display,windows,MagickFalse);
8060 if (windows->image.orphan != MagickFalse )
8061 break;
8062 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8063 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8064 break;
8065 }
8066 case EmbossCommand:
8067 {
8068 Image
8069 *emboss_image;
8070
8071 static char
8072 radius[MagickPathExtent] = "0.0x1.0";
8073
8074 /*
8075 Query user for emboss radius.
8076 */
8077 (void) XDialogWidget(display,windows,"Emboss",
8078 "Enter the emboss radius and standard deviation:",radius);
8079 if (*radius == '\0')
8080 break;
8081 /*
8082 Reduce noise in the image.
8083 */
8084 XSetCursorState(display,windows,MagickTrue);
8085 XCheckRefreshWindows(display,windows);
8086 flags=ParseGeometry(radius,&geometry_info);
8087 if ((flags & SigmaValue) == 0)
8088 geometry_info.sigma=1.0;
8089 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8090 exception);
8091 if (emboss_image != (Image *) NULL)
8092 {
8093 *image=DestroyImage(*image);
8094 *image=emboss_image;
8095 }
8096 CatchException(exception);
8097 XSetCursorState(display,windows,MagickFalse);
8098 if (windows->image.orphan != MagickFalse )
8099 break;
8100 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8101 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8102 break;
8103 }
8104 case ReduceNoiseCommand:
8105 {
8106 Image
8107 *noise_image;
8108
8109 static char
8110 radius[MagickPathExtent] = "0";
8111
8112 /*
8113 Query user for noise radius.
8114 */
8115 (void) XDialogWidget(display,windows,"Reduce Noise",
8116 "Enter the noise radius:",radius);
8117 if (*radius == '\0')
8118 break;
8119 /*
8120 Reduce noise in the image.
8121 */
8122 XSetCursorState(display,windows,MagickTrue);
8123 XCheckRefreshWindows(display,windows);
8124 flags=ParseGeometry(radius,&geometry_info);
8125 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8126 geometry_info.rho,(size_t) geometry_info.rho,exception);
8127 if (noise_image != (Image *) NULL)
8128 {
8129 *image=DestroyImage(*image);
8130 *image=noise_image;
8131 }
8132 CatchException(exception);
8133 XSetCursorState(display,windows,MagickFalse);
8134 if (windows->image.orphan != MagickFalse )
8135 break;
8136 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8137 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8138 break;
8139 }
8140 case AddNoiseCommand:
8141 {
8142 char
8143 **noises;
8144
8145 Image
8146 *noise_image;
8147
8148 static char
8149 noise_type[MagickPathExtent] = "Gaussian";
8150
8151 /*
8152 Add noise to the image.
8153 */
8154 noises=GetCommandOptions(MagickNoiseOptions);
8155 if (noises == (char **) NULL)
8156 break;
8157 XListBrowserWidget(display,windows,&windows->widget,
8158 (const char **) noises,"Add Noise",
8159 "Select a type of noise to add to your image:",noise_type);
8160 noises=DestroyStringList(noises);
8161 if (*noise_type == '\0')
8162 break;
8163 XSetCursorState(display,windows,MagickTrue);
8164 XCheckRefreshWindows(display,windows);
8165 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8166 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
8167 if (noise_image != (Image *) NULL)
8168 {
8169 *image=DestroyImage(*image);
8170 *image=noise_image;
8171 }
8172 CatchException(exception);
8173 XSetCursorState(display,windows,MagickFalse);
8174 if (windows->image.orphan != MagickFalse )
8175 break;
8176 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8177 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8178 break;
8179 }
8180 case SharpenCommand:
8181 {
8182 Image
8183 *sharp_image;
8184
8185 static char
8186 radius[MagickPathExtent] = "0.0x1.0";
8187
8188 /*
8189 Query user for sharpen radius.
8190 */
8191 (void) XDialogWidget(display,windows,"Sharpen",
8192 "Enter the sharpen radius and standard deviation:",radius);
8193 if (*radius == '\0')
8194 break;
8195 /*
8196 Sharpen image scanlines.
8197 */
8198 XSetCursorState(display,windows,MagickTrue);
8199 XCheckRefreshWindows(display,windows);
8200 flags=ParseGeometry(radius,&geometry_info);
8201 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8202 exception);
8203 if (sharp_image != (Image *) NULL)
8204 {
8205 *image=DestroyImage(*image);
8206 *image=sharp_image;
8207 }
8208 CatchException(exception);
8209 XSetCursorState(display,windows,MagickFalse);
8210 if (windows->image.orphan != MagickFalse )
8211 break;
8212 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8213 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8214 break;
8215 }
8216 case BlurCommand:
8217 {
8218 Image
8219 *blur_image;
8220
8221 static char
8222 radius[MagickPathExtent] = "0.0x1.0";
8223
8224 /*
8225 Query user for blur radius.
8226 */
8227 (void) XDialogWidget(display,windows,"Blur",
8228 "Enter the blur radius and standard deviation:",radius);
8229 if (*radius == '\0')
8230 break;
8231 /*
8232 Blur an image.
8233 */
8234 XSetCursorState(display,windows,MagickTrue);
8235 XCheckRefreshWindows(display,windows);
8236 flags=ParseGeometry(radius,&geometry_info);
8237 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8238 exception);
8239 if (blur_image != (Image *) NULL)
8240 {
8241 *image=DestroyImage(*image);
8242 *image=blur_image;
8243 }
8244 CatchException(exception);
8245 XSetCursorState(display,windows,MagickFalse);
8246 if (windows->image.orphan != MagickFalse )
8247 break;
8248 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8249 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8250 break;
8251 }
8252 case ThresholdCommand:
8253 {
8254 double
8255 threshold;
8256
8257 static char
8258 factor[MagickPathExtent] = "128";
8259
8260 /*
8261 Query user for threshold value.
8262 */
8263 (void) XDialogWidget(display,windows,"Threshold",
8264 "Enter threshold value:",factor);
8265 if (*factor == '\0')
8266 break;
8267 /*
8268 Gamma correct image.
8269 */
8270 XSetCursorState(display,windows,MagickTrue);
8271 XCheckRefreshWindows(display,windows);
8272 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8273 (void) BilevelImage(*image,threshold,exception);
8274 XSetCursorState(display,windows,MagickFalse);
8275 if (windows->image.orphan != MagickFalse )
8276 break;
8277 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8278 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8279 break;
8280 }
8281 case EdgeDetectCommand:
8282 {
8283 Image
8284 *edge_image;
8285
8286 static char
8287 radius[MagickPathExtent] = "0";
8288
8289 /*
8290 Query user for edge factor.
8291 */
8292 (void) XDialogWidget(display,windows,"Detect Edges",
8293 "Enter the edge detect radius:",radius);
8294 if (*radius == '\0')
8295 break;
8296 /*
8297 Detect edge in image.
8298 */
8299 XSetCursorState(display,windows,MagickTrue);
8300 XCheckRefreshWindows(display,windows);
8301 flags=ParseGeometry(radius,&geometry_info);
8302 edge_image=EdgeImage(*image,geometry_info.rho,exception);
8303 if (edge_image != (Image *) NULL)
8304 {
8305 *image=DestroyImage(*image);
8306 *image=edge_image;
8307 }
8308 CatchException(exception);
8309 XSetCursorState(display,windows,MagickFalse);
8310 if (windows->image.orphan != MagickFalse )
8311 break;
8312 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8313 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8314 break;
8315 }
8316 case SpreadCommand:
8317 {
8318 Image
8319 *spread_image;
8320
8321 static char
8322 amount[MagickPathExtent] = "2";
8323
8324 /*
8325 Query user for spread amount.
8326 */
8327 (void) XDialogWidget(display,windows,"Spread",
8328 "Enter the displacement amount:",amount);
8329 if (*amount == '\0')
8330 break;
8331 /*
8332 Displace image pixels by a random amount.
8333 */
8334 XSetCursorState(display,windows,MagickTrue);
8335 XCheckRefreshWindows(display,windows);
8336 flags=ParseGeometry(amount,&geometry_info);
8337 spread_image=EdgeImage(*image,geometry_info.rho,exception);
8338 if (spread_image != (Image *) NULL)
8339 {
8340 *image=DestroyImage(*image);
8341 *image=spread_image;
8342 }
8343 CatchException(exception);
8344 XSetCursorState(display,windows,MagickFalse);
8345 if (windows->image.orphan != MagickFalse )
8346 break;
8347 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8348 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8349 break;
8350 }
8351 case ShadeCommand:
8352 {
8353 Image
8354 *shade_image;
8355
8356 int
8357 status;
8358
8359 static char
8360 geometry[MagickPathExtent] = "30x30";
8361
8362 /*
8363 Query user for the shade geometry.
8364 */
8365 status=XDialogWidget(display,windows,"Shade",
8366 "Enter the azimuth and elevation of the light source:",geometry);
8367 if (*geometry == '\0')
8368 break;
8369 /*
8370 Shade image pixels.
8371 */
8372 XSetCursorState(display,windows,MagickTrue);
8373 XCheckRefreshWindows(display,windows);
8374 flags=ParseGeometry(geometry,&geometry_info);
8375 if ((flags & SigmaValue) == 0)
8376 geometry_info.sigma=1.0;
8377 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse,
8378 geometry_info.rho,geometry_info.sigma,exception);
8379 if (shade_image != (Image *) NULL)
8380 {
8381 *image=DestroyImage(*image);
8382 *image=shade_image;
8383 }
8384 CatchException(exception);
8385 XSetCursorState(display,windows,MagickFalse);
8386 if (windows->image.orphan != MagickFalse )
8387 break;
8388 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8389 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8390 break;
8391 }
8392 case RaiseCommand:
8393 {
8394 static char
8395 bevel_width[MagickPathExtent] = "10";
8396
8397 /*
8398 Query user for bevel width.
8399 */
8400 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8401 if (*bevel_width == '\0')
8402 break;
8403 /*
8404 Raise an image.
8405 */
8406 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8407 exception);
8408 XSetCursorState(display,windows,MagickTrue);
8409 XCheckRefreshWindows(display,windows);
8410 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8411 exception);
8412 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
8413 XSetCursorState(display,windows,MagickFalse);
8414 if (windows->image.orphan != MagickFalse )
8415 break;
8416 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8417 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8418 break;
8419 }
8420 case SegmentCommand:
8421 {
8422 static char
8423 threshold[MagickPathExtent] = "1.0x1.5";
8424
8425 /*
8426 Query user for smoothing threshold.
8427 */
8428 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8429 threshold);
8430 if (*threshold == '\0')
8431 break;
8432 /*
8433 Segment an image.
8434 */
8435 XSetCursorState(display,windows,MagickTrue);
8436 XCheckRefreshWindows(display,windows);
8437 flags=ParseGeometry(threshold,&geometry_info);
8438 if ((flags & SigmaValue) == 0)
8439 geometry_info.sigma=1.0;
8440 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8441 geometry_info.sigma,exception);
8442 XSetCursorState(display,windows,MagickFalse);
8443 if (windows->image.orphan != MagickFalse )
8444 break;
8445 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8446 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8447 break;
8448 }
8449 case SepiaToneCommand:
8450 {
8451 double
8452 threshold;
8453
8454 Image
8455 *sepia_image;
8456
8457 static char
8458 factor[MagickPathExtent] = "80%";
8459
8460 /*
8461 Query user for sepia-tone factor.
8462 */
8463 (void) XDialogWidget(display,windows,"Sepia Tone",
8464 "Enter the sepia tone factor (0 - 99.9%):",factor);
8465 if (*factor == '\0')
8466 break;
8467 /*
8468 Sepia tone image pixels.
8469 */
8470 XSetCursorState(display,windows,MagickTrue);
8471 XCheckRefreshWindows(display,windows);
8472 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8473 sepia_image=SepiaToneImage(*image,threshold,exception);
8474 if (sepia_image != (Image *) NULL)
8475 {
8476 *image=DestroyImage(*image);
8477 *image=sepia_image;
8478 }
8479 CatchException(exception);
8480 XSetCursorState(display,windows,MagickFalse);
8481 if (windows->image.orphan != MagickFalse )
8482 break;
8483 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8484 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8485 break;
8486 }
8487 case SolarizeCommand:
8488 {
8489 double
8490 threshold;
8491
8492 static char
8493 factor[MagickPathExtent] = "60%";
8494
8495 /*
8496 Query user for solarize factor.
8497 */
8498 (void) XDialogWidget(display,windows,"Solarize",
8499 "Enter the solarize factor (0 - 99.9%):",factor);
8500 if (*factor == '\0')
8501 break;
8502 /*
8503 Solarize image pixels.
8504 */
8505 XSetCursorState(display,windows,MagickTrue);
8506 XCheckRefreshWindows(display,windows);
8507 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8508 (void) SolarizeImage(*image,threshold,exception);
8509 XSetCursorState(display,windows,MagickFalse);
8510 if (windows->image.orphan != MagickFalse )
8511 break;
8512 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8513 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8514 break;
8515 }
8516 case SwirlCommand:
8517 {
8518 Image
8519 *swirl_image;
8520
8521 static char
8522 degrees[MagickPathExtent] = "60";
8523
8524 /*
8525 Query user for swirl angle.
8526 */
8527 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8528 degrees);
8529 if (*degrees == '\0')
8530 break;
8531 /*
8532 Swirl image pixels about the center.
8533 */
8534 XSetCursorState(display,windows,MagickTrue);
8535 XCheckRefreshWindows(display,windows);
8536 flags=ParseGeometry(degrees,&geometry_info);
8537 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8538 exception);
8539 if (swirl_image != (Image *) NULL)
8540 {
8541 *image=DestroyImage(*image);
8542 *image=swirl_image;
8543 }
8544 CatchException(exception);
8545 XSetCursorState(display,windows,MagickFalse);
8546 if (windows->image.orphan != MagickFalse )
8547 break;
8548 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8549 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8550 break;
8551 }
8552 case ImplodeCommand:
8553 {
8554 Image
8555 *implode_image;
8556
8557 static char
8558 factor[MagickPathExtent] = "0.3";
8559
8560 /*
8561 Query user for implode factor.
8562 */
8563 (void) XDialogWidget(display,windows,"Implode",
8564 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8565 if (*factor == '\0')
8566 break;
8567 /*
8568 Implode image pixels about the center.
8569 */
8570 XSetCursorState(display,windows,MagickTrue);
8571 XCheckRefreshWindows(display,windows);
8572 flags=ParseGeometry(factor,&geometry_info);
8573 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8574 exception);
8575 if (implode_image != (Image *) NULL)
8576 {
8577 *image=DestroyImage(*image);
8578 *image=implode_image;
8579 }
8580 CatchException(exception);
8581 XSetCursorState(display,windows,MagickFalse);
8582 if (windows->image.orphan != MagickFalse )
8583 break;
8584 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8585 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8586 break;
8587 }
8588 case VignetteCommand:
8589 {
8590 Image
8591 *vignette_image;
8592
8593 static char
8594 geometry[MagickPathExtent] = "0x20";
8595
8596 /*
8597 Query user for the vignette geometry.
8598 */
8599 (void) XDialogWidget(display,windows,"Vignette",
8600 "Enter the radius, sigma, and x and y offsets:",geometry);
8601 if (*geometry == '\0')
8602 break;
8603 /*
8604 Soften the edges of the image in vignette style
8605 */
8606 XSetCursorState(display,windows,MagickTrue);
8607 XCheckRefreshWindows(display,windows);
8608 flags=ParseGeometry(geometry,&geometry_info);
8609 if ((flags & SigmaValue) == 0)
8610 geometry_info.sigma=1.0;
8611 if ((flags & XiValue) == 0)
8612 geometry_info.xi=0.1*(*image)->columns;
8613 if ((flags & PsiValue) == 0)
8614 geometry_info.psi=0.1*(*image)->rows;
8615 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8616 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8617 exception);
8618 if (vignette_image != (Image *) NULL)
8619 {
8620 *image=DestroyImage(*image);
8621 *image=vignette_image;
8622 }
8623 CatchException(exception);
8624 XSetCursorState(display,windows,MagickFalse);
8625 if (windows->image.orphan != MagickFalse )
8626 break;
8627 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8628 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8629 break;
8630 }
8631 case WaveCommand:
8632 {
8633 Image
8634 *wave_image;
8635
8636 static char
8637 geometry[MagickPathExtent] = "25x150";
8638
8639 /*
8640 Query user for the wave geometry.
8641 */
8642 (void) XDialogWidget(display,windows,"Wave",
8643 "Enter the amplitude and length of the wave:",geometry);
8644 if (*geometry == '\0')
8645 break;
8646 /*
8647 Alter an image along a sine wave.
8648 */
8649 XSetCursorState(display,windows,MagickTrue);
8650 XCheckRefreshWindows(display,windows);
8651 flags=ParseGeometry(geometry,&geometry_info);
8652 if ((flags & SigmaValue) == 0)
8653 geometry_info.sigma=1.0;
8654 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8655 (*image)->interpolate,exception);
8656 if (wave_image != (Image *) NULL)
8657 {
8658 *image=DestroyImage(*image);
8659 *image=wave_image;
8660 }
8661 CatchException(exception);
8662 XSetCursorState(display,windows,MagickFalse);
8663 if (windows->image.orphan != MagickFalse )
8664 break;
8665 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8666 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8667 break;
8668 }
8669 case OilPaintCommand:
8670 {
8671 Image
8672 *paint_image;
8673
8674 static char
8675 radius[MagickPathExtent] = "0";
8676
8677 /*
8678 Query user for circular neighborhood radius.
8679 */
8680 (void) XDialogWidget(display,windows,"Oil Paint",
8681 "Enter the mask radius:",radius);
8682 if (*radius == '\0')
8683 break;
8684 /*
8685 OilPaint image scanlines.
8686 */
8687 XSetCursorState(display,windows,MagickTrue);
8688 XCheckRefreshWindows(display,windows);
8689 flags=ParseGeometry(radius,&geometry_info);
8690 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8691 exception);
8692 if (paint_image != (Image *) NULL)
8693 {
8694 *image=DestroyImage(*image);
8695 *image=paint_image;
8696 }
8697 CatchException(exception);
8698 XSetCursorState(display,windows,MagickFalse);
8699 if (windows->image.orphan != MagickFalse )
8700 break;
8701 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8702 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8703 break;
8704 }
8705 case CharcoalDrawCommand:
8706 {
8707 Image
8708 *charcoal_image;
8709
8710 static char
8711 radius[MagickPathExtent] = "0x1";
8712
8713 /*
8714 Query user for charcoal radius.
8715 */
8716 (void) XDialogWidget(display,windows,"Charcoal Draw",
8717 "Enter the charcoal radius and sigma:",radius);
8718 if (*radius == '\0')
8719 break;
8720 /*
8721 Charcoal the image.
8722 */
8723 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8724 exception);
8725 XSetCursorState(display,windows,MagickTrue);
8726 XCheckRefreshWindows(display,windows);
8727 flags=ParseGeometry(radius,&geometry_info);
8728 if ((flags & SigmaValue) == 0)
8729 geometry_info.sigma=geometry_info.rho;
8730 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8731 exception);
8732 if (charcoal_image != (Image *) NULL)
8733 {
8734 *image=DestroyImage(*image);
8735 *image=charcoal_image;
8736 }
8737 CatchException(exception);
8738 XSetCursorState(display,windows,MagickFalse);
8739 if (windows->image.orphan != MagickFalse )
8740 break;
8741 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8742 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8743 break;
8744 }
8745 case AnnotateCommand:
8746 {
8747 /*
8748 Annotate the image with text.
8749 */
8750 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
8751 if (status == MagickFalse)
8752 {
8753 XNoticeWidget(display,windows,"Unable to annotate X image",
8754 (*image)->filename);
8755 break;
8756 }
8757 break;
8758 }
8759 case DrawCommand:
8760 {
8761 /*
8762 Draw image.
8763 */
8764 status=XDrawEditImage(display,resource_info,windows,image,exception);
8765 if (status == MagickFalse)
8766 {
8767 XNoticeWidget(display,windows,"Unable to draw on the X image",
8768 (*image)->filename);
8769 break;
8770 }
8771 break;
8772 }
8773 case ColorCommand:
8774 {
8775 /*
8776 Color edit.
8777 */
8778 status=XColorEditImage(display,resource_info,windows,image,exception);
8779 if (status == MagickFalse)
8780 {
8781 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8782 (*image)->filename);
8783 break;
8784 }
8785 break;
8786 }
8787 case MatteCommand:
8788 {
8789 /*
8790 Matte edit.
8791 */
8792 status=XMatteEditImage(display,resource_info,windows,image,exception);
8793 if (status == MagickFalse)
8794 {
8795 XNoticeWidget(display,windows,"Unable to matte edit X image",
8796 (*image)->filename);
8797 break;
8798 }
8799 break;
8800 }
8801 case CompositeCommand:
8802 {
8803 /*
8804 Composite image.
8805 */
8806 status=XCompositeImage(display,resource_info,windows,*image,
8807 exception);
8808 if (status == MagickFalse)
8809 {
8810 XNoticeWidget(display,windows,"Unable to composite X image",
8811 (*image)->filename);
8812 break;
8813 }
8814 break;
8815 }
8816 case AddBorderCommand:
8817 {
8818 Image
8819 *border_image;
8820
8821 static char
8822 geometry[MagickPathExtent] = "6x6";
8823
8824 /*
8825 Query user for border color and geometry.
8826 */
8827 XColorBrowserWidget(display,windows,"Select",color);
8828 if (*color == '\0')
8829 break;
8830 (void) XDialogWidget(display,windows,"Add Border",
8831 "Enter border geometry:",geometry);
8832 if (*geometry == '\0')
8833 break;
8834 /*
8835 Add a border to the image.
8836 */
8837 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8838 exception);
8839 XSetCursorState(display,windows,MagickTrue);
8840 XCheckRefreshWindows(display,windows);
8841 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
8842 exception);
8843 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8844 exception);
8845 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8846 exception);
8847 if (border_image != (Image *) NULL)
8848 {
8849 *image=DestroyImage(*image);
8850 *image=border_image;
8851 }
8852 CatchException(exception);
8853 XSetCursorState(display,windows,MagickFalse);
8854 if (windows->image.orphan != MagickFalse )
8855 break;
8856 windows->image.window_changes.width=(int) (*image)->columns;
8857 windows->image.window_changes.height=(int) (*image)->rows;
8858 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8859 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8860 break;
8861 }
8862 case AddFrameCommand:
8863 {
8864 FrameInfo
8865 frame_info;
8866
8867 Image
8868 *frame_image;
8869
8870 static char
8871 geometry[MagickPathExtent] = "6x6";
8872
8873 /*
8874 Query user for frame color and geometry.
8875 */
8876 XColorBrowserWidget(display,windows,"Select",color);
8877 if (*color == '\0')
8878 break;
8879 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8880 geometry);
8881 if (*geometry == '\0')
8882 break;
8883 /*
8884 Surround image with an ornamental border.
8885 */
8886 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8887 exception);
8888 XSetCursorState(display,windows,MagickTrue);
8889 XCheckRefreshWindows(display,windows);
8890 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
8891 exception);
8892 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8893 exception);
8894 frame_info.width=page_geometry.width;
8895 frame_info.height=page_geometry.height;
8896 frame_info.outer_bevel=page_geometry.x;
8897 frame_info.inner_bevel=page_geometry.y;
8898 frame_info.x=(ssize_t) frame_info.width;
8899 frame_info.y=(ssize_t) frame_info.height;
8900 frame_info.width=(*image)->columns+2*frame_info.width;
8901 frame_info.height=(*image)->rows+2*frame_info.height;
8902 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
8903 if (frame_image != (Image *) NULL)
8904 {
8905 *image=DestroyImage(*image);
8906 *image=frame_image;
8907 }
8908 CatchException(exception);
8909 XSetCursorState(display,windows,MagickFalse);
8910 if (windows->image.orphan != MagickFalse )
8911 break;
8912 windows->image.window_changes.width=(int) (*image)->columns;
8913 windows->image.window_changes.height=(int) (*image)->rows;
8914 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8915 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8916 break;
8917 }
8918 case CommentCommand:
8919 {
8920 const char
8921 *value;
8922
8923 FILE
8924 *file;
8925
8926 int
8927 unique_file;
8928
8929 /*
8930 Edit image comment.
8931 */
8932 unique_file=AcquireUniqueFileResource(image_info->filename);
8933 if (unique_file == -1)
8934 XNoticeWidget(display,windows,"Unable to edit image comment",
8935 image_info->filename);
8936 value=GetImageProperty(*image,"comment",exception);
8937 if (value == (char *) NULL)
8938 unique_file=close(unique_file)-1;
8939 else
8940 {
8941 register const char
8942 *p;
8943
8944 file=fdopen(unique_file,"w");
8945 if (file == (FILE *) NULL)
8946 {
8947 XNoticeWidget(display,windows,"Unable to edit image comment",
8948 image_info->filename);
8949 break;
8950 }
8951 for (p=value; *p != '\0'; p++)
8952 (void) fputc((int) *p,file);
8953 (void) fputc('\n',file);
8954 (void) fclose(file);
8955 }
8956 XSetCursorState(display,windows,MagickTrue);
8957 XCheckRefreshWindows(display,windows);
8958 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8959 exception);
8960 if (status == MagickFalse)
8961 XNoticeWidget(display,windows,"Unable to edit image comment",
8962 (char *) NULL);
8963 else
8964 {
8965 char
8966 *comment;
8967
8968 comment=FileToString(image_info->filename,~0UL,exception);
8969 if (comment != (char *) NULL)
8970 {
8971 (void) SetImageProperty(*image,"comment",comment,exception);
8972 (*image)->taint=MagickTrue;
8973 }
8974 }
8975 (void) RelinquishUniqueFileResource(image_info->filename);
8976 XSetCursorState(display,windows,MagickFalse);
8977 break;
8978 }
8979 case LaunchCommand:
8980 {
8981 /*
8982 Launch program.
8983 */
8984 XSetCursorState(display,windows,MagickTrue);
8985 XCheckRefreshWindows(display,windows);
8986 (void) AcquireUniqueFilename(filename);
8987 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s",
8988 filename);
8989 status=WriteImage(image_info,*image,exception);
8990 if (status == MagickFalse)
8991 XNoticeWidget(display,windows,"Unable to launch image editor",
8992 (char *) NULL);
8993 else
8994 {
8995 nexus=ReadImage(resource_info->image_info,exception);
8996 CatchException(exception);
8997 XClientMessage(display,windows->image.id,windows->im_protocols,
8998 windows->im_next_image,CurrentTime);
8999 }
9000 (void) RelinquishUniqueFileResource(filename);
9001 XSetCursorState(display,windows,MagickFalse);
9002 break;
9003 }
9004 case RegionofInterestCommand:
9005 {
9006 /*
9007 Apply an image processing technique to a region of interest.
9008 */
9009 (void) XROIImage(display,resource_info,windows,image,exception);
9010 break;
9011 }
9012 case InfoCommand:
9013 break;
9014 case ZoomCommand:
9015 {
9016 /*
9017 Zoom image.
9018 */
9019 if (windows->magnify.mapped != MagickFalse )
9020 (void) XRaiseWindow(display,windows->magnify.id);
9021 else
9022 {
9023 /*
9024 Make magnify image.
9025 */
9026 XSetCursorState(display,windows,MagickTrue);
9027 (void) XMapRaised(display,windows->magnify.id);
9028 XSetCursorState(display,windows,MagickFalse);
9029 }
9030 break;
9031 }
9032 case ShowPreviewCommand:
9033 {
9034 char
9035 **previews,
9036 value[MagickPathExtent];
9037
9038 Image
9039 *preview_image;
9040
9041 PreviewType
9042 preview;
9043
9044 static char
9045 preview_type[MagickPathExtent] = "Gamma";
9046
9047 /*
9048 Select preview type from menu.
9049 */
9050 previews=GetCommandOptions(MagickPreviewOptions);
9051 if (previews == (char **) NULL)
9052 break;
9053 XListBrowserWidget(display,windows,&windows->widget,
9054 (const char **) previews,"Preview",
9055 "Select an enhancement, effect, or F/X:",preview_type);
9056 previews=DestroyStringList(previews);
9057 if (*preview_type == '\0')
9058 break;
9059 /*
9060 Show image preview.
9061 */
9062 XSetCursorState(display,windows,MagickTrue);
9063 XCheckRefreshWindows(display,windows);
9064 preview=(PreviewType) ParseCommandOption(MagickPreviewOptions,
9065 MagickFalse,preview_type);
9066 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9067 windows->image.id);
9068 (void) SetImageProperty(*image,"group",value,exception);
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 char
9090 value[MagickPathExtent];
9091
9092 Image
9093 *histogram_image;
9094
9095 /*
9096 Show image histogram.
9097 */
9098 XSetCursorState(display,windows,MagickTrue);
9099 XCheckRefreshWindows(display,windows);
9100 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9101 windows->image.id);
9102 (void) SetImageProperty(*image,"group",value,exception);
9103 (void) DeleteImageProperty(*image,"label");
9104 (void) SetImageProperty(*image,"label","Histogram",exception);
9105 (void) AcquireUniqueFilename(filename);
9106 (void) FormatLocaleString((*image)->filename,MagickPathExtent,
9107 "histogram:%s",filename);
9108 status=WriteImage(image_info,*image,exception);
9109 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9110 histogram_image=ReadImage(image_info,exception);
9111 (void) RelinquishUniqueFileResource(filename);
9112 if (histogram_image == (Image *) NULL)
9113 break;
9114 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
9115 "show:%s",filename);
9116 status=WriteImage(image_info,histogram_image,exception);
9117 histogram_image=DestroyImage(histogram_image);
9118 if (status == MagickFalse)
9119 XNoticeWidget(display,windows,"Unable to show histogram",
9120 (*image)->filename);
9121 XDelay(display,1500);
9122 XSetCursorState(display,windows,MagickFalse);
9123 break;
9124 }
9125 case ShowMatteCommand:
9126 {
9127 char
9128 value[MagickPathExtent];
9129
9130 Image
9131 *matte_image;
9132
9133 if ((*image)->alpha_trait == UndefinedPixelTrait)
9134 {
9135 XNoticeWidget(display,windows,
9136 "Image does not have any matte information",(*image)->filename);
9137 break;
9138 }
9139 /*
9140 Show image matte.
9141 */
9142 XSetCursorState(display,windows,MagickTrue);
9143 XCheckRefreshWindows(display,windows);
9144 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9145 windows->image.id);
9146 (void) SetImageProperty(*image,"group",value,exception);
9147 (void) DeleteImageProperty(*image,"label");
9148 (void) SetImageProperty(*image,"label","Matte",exception);
9149 (void) AcquireUniqueFilename(filename);
9150 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s",
9151 filename);
9152 status=WriteImage(image_info,*image,exception);
9153 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9154 matte_image=ReadImage(image_info,exception);
9155 (void) RelinquishUniqueFileResource(filename);
9156 if (matte_image == (Image *) NULL)
9157 break;
9158 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s",
9159 filename);
9160 status=WriteImage(image_info,matte_image,exception);
9161 matte_image=DestroyImage(matte_image);
9162 if (status == MagickFalse)
9163 XNoticeWidget(display,windows,"Unable to show matte",
9164 (*image)->filename);
9165 XDelay(display,1500);
9166 XSetCursorState(display,windows,MagickFalse);
9167 break;
9168 }
9169 case BackgroundCommand:
9170 {
9171 /*
9172 Background image.
9173 */
9174 status=XBackgroundImage(display,resource_info,windows,image,exception);
9175 if (status == MagickFalse)
9176 break;
9177 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9178 if (nexus != (Image *) NULL)
9179 XClientMessage(display,windows->image.id,windows->im_protocols,
9180 windows->im_next_image,CurrentTime);
9181 break;
9182 }
9183 case SlideShowCommand:
9184 {
9185 static char
9186 delay[MagickPathExtent] = "5";
9187
9188 /*
9189 Display next image after pausing.
9190 */
9191 (void) XDialogWidget(display,windows,"Slide Show",
9192 "Pause how many 1/100ths of a second between images:",delay);
9193 if (*delay == '\0')
9194 break;
9195 resource_info->delay=StringToUnsignedLong(delay);
9196 XClientMessage(display,windows->image.id,windows->im_protocols,
9197 windows->im_next_image,CurrentTime);
9198 break;
9199 }
9200 case PreferencesCommand:
9201 {
9202 /*
9203 Set user preferences.
9204 */
9205 status=XPreferencesWidget(display,resource_info,windows);
9206 if (status == MagickFalse)
9207 break;
9208 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9209 if (nexus != (Image *) NULL)
9210 XClientMessage(display,windows->image.id,windows->im_protocols,
9211 windows->im_next_image,CurrentTime);
9212 break;
9213 }
9214 case HelpCommand:
9215 {
9216 /*
9217 User requested help.
9218 */
9219 XTextViewHelp(display,resource_info,windows,MagickFalse,
9220 "Help Viewer - Display",DisplayHelp);
9221 break;
9222 }
9223 case BrowseDocumentationCommand:
9224 {
9225 Atom
9226 mozilla_atom;
9227
9228 Window
9229 mozilla_window,
9230 root_window;
9231
9232 /*
9233 Browse the ImageMagick documentation.
9234 */
9235 root_window=XRootWindow(display,XDefaultScreen(display));
9236 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9237 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9238 if (mozilla_window != (Window) NULL)
9239 {
9240 char
9241 command[MagickPathExtent],
9242 *url;
9243
9244 /*
9245 Display documentation using Netscape remote control.
9246 */
9247 url=GetMagickHomeURL();
9248 (void) FormatLocaleString(command,MagickPathExtent,
9249 "openurl(%s,new-tab)",url);
9250 url=DestroyString(url);
9251 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9252 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9253 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9254 XSetCursorState(display,windows,MagickFalse);
9255 break;
9256 }
9257 XSetCursorState(display,windows,MagickTrue);
9258 XCheckRefreshWindows(display,windows);
9259 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9260 exception);
9261 if (status == MagickFalse)
9262 XNoticeWidget(display,windows,"Unable to browse documentation",
9263 (char *) NULL);
9264 XDelay(display,1500);
9265 XSetCursorState(display,windows,MagickFalse);
9266 break;
9267 }
9268 case VersionCommand:
9269 {
9270 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9271 GetMagickCopyright());
9272 break;
9273 }
9274 case SaveToUndoBufferCommand:
9275 break;
9276 default:
9277 {
9278 (void) XBell(display,0);
9279 break;
9280 }
9281 }
9282 image_info=DestroyImageInfo(image_info);
9283 return(nexus);
9284 }
9285
9286 /*
9287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9288 % %
9289 % %
9290 % %
9291 + X M a g n i f y I m a g e %
9292 % %
9293 % %
9294 % %
9295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9296 %
9297 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9298 % The magnified portion is displayed in a separate window.
9299 %
9300 % The format of the XMagnifyImage method is:
9301 %
9302 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9303 % ExceptionInfo *exception)
9304 %
9305 % A description of each parameter follows:
9306 %
9307 % o display: Specifies a connection to an X server; returned from
9308 % XOpenDisplay.
9309 %
9310 % o windows: Specifies a pointer to a XWindows structure.
9311 %
9312 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9313 % the entire image is refreshed.
9314 %
9315 % o exception: return any errors or warnings in this structure.
9316 %
9317 */
XMagnifyImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)9318 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9319 ExceptionInfo *exception)
9320 {
9321 char
9322 text[MagickPathExtent];
9323
9324 register int
9325 x,
9326 y;
9327
9328 size_t
9329 state;
9330
9331 /*
9332 Update magnified image until the mouse button is released.
9333 */
9334 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9335 state=DefaultState;
9336 x=event->xbutton.x;
9337 y=event->xbutton.y;
9338 windows->magnify.x=(int) windows->image.x+x;
9339 windows->magnify.y=(int) windows->image.y+y;
9340 do
9341 {
9342 /*
9343 Map and unmap Info widget as text cursor crosses its boundaries.
9344 */
9345 if (windows->info.mapped != MagickFalse )
9346 {
9347 if ((x < (int) (windows->info.x+windows->info.width)) &&
9348 (y < (int) (windows->info.y+windows->info.height)))
9349 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9350 }
9351 else
9352 if ((x > (int) (windows->info.x+windows->info.width)) ||
9353 (y > (int) (windows->info.y+windows->info.height)))
9354 (void) XMapWindow(display,windows->info.id);
9355 if (windows->info.mapped != MagickFalse )
9356 {
9357 /*
9358 Display pointer position.
9359 */
9360 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9361 windows->magnify.x,windows->magnify.y);
9362 XInfoWidget(display,windows,text);
9363 }
9364 /*
9365 Wait for next event.
9366 */
9367 XScreenEvent(display,windows,event,exception);
9368 switch (event->type)
9369 {
9370 case ButtonPress:
9371 break;
9372 case ButtonRelease:
9373 {
9374 /*
9375 User has finished magnifying image.
9376 */
9377 x=event->xbutton.x;
9378 y=event->xbutton.y;
9379 state|=ExitState;
9380 break;
9381 }
9382 case Expose:
9383 break;
9384 case MotionNotify:
9385 {
9386 x=event->xmotion.x;
9387 y=event->xmotion.y;
9388 break;
9389 }
9390 default:
9391 break;
9392 }
9393 /*
9394 Check boundary conditions.
9395 */
9396 if (x < 0)
9397 x=0;
9398 else
9399 if (x >= (int) windows->image.width)
9400 x=(int) windows->image.width-1;
9401 if (y < 0)
9402 y=0;
9403 else
9404 if (y >= (int) windows->image.height)
9405 y=(int) windows->image.height-1;
9406 } while ((state & ExitState) == 0);
9407 /*
9408 Display magnified image.
9409 */
9410 XSetCursorState(display,windows,MagickFalse);
9411 }
9412
9413 /*
9414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9415 % %
9416 % %
9417 % %
9418 + X M a g n i f y W i n d o w C o m m a n d %
9419 % %
9420 % %
9421 % %
9422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9423 %
9424 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9425 % pixel as specified by the key symbol.
9426 %
9427 % The format of the XMagnifyWindowCommand method is:
9428 %
9429 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9430 % const MagickStatusType state,const KeySym key_symbol,
9431 % ExceptionInfo *exception)
9432 %
9433 % A description of each parameter follows:
9434 %
9435 % o display: Specifies a connection to an X server; returned from
9436 % XOpenDisplay.
9437 %
9438 % o windows: Specifies a pointer to a XWindows structure.
9439 %
9440 % o state: key mask.
9441 %
9442 % o key_symbol: Specifies a KeySym which indicates which side of the image
9443 % to trim.
9444 %
9445 % o exception: return any errors or warnings in this structure.
9446 %
9447 */
XMagnifyWindowCommand(Display * display,XWindows * windows,const MagickStatusType state,const KeySym key_symbol,ExceptionInfo * exception)9448 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9449 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
9450 {
9451 unsigned int
9452 quantum;
9453
9454 /*
9455 User specified a magnify factor or position.
9456 */
9457 quantum=1;
9458 if ((state & Mod1Mask) != 0)
9459 quantum=10;
9460 switch ((int) key_symbol)
9461 {
9462 case QuitCommand:
9463 {
9464 (void) XWithdrawWindow(display,windows->magnify.id,
9465 windows->magnify.screen);
9466 break;
9467 }
9468 case XK_Home:
9469 case XK_KP_Home:
9470 {
9471 windows->magnify.x=(int) windows->image.width/2;
9472 windows->magnify.y=(int) windows->image.height/2;
9473 break;
9474 }
9475 case XK_Left:
9476 case XK_KP_Left:
9477 {
9478 if (windows->magnify.x > 0)
9479 windows->magnify.x-=quantum;
9480 break;
9481 }
9482 case XK_Up:
9483 case XK_KP_Up:
9484 {
9485 if (windows->magnify.y > 0)
9486 windows->magnify.y-=quantum;
9487 break;
9488 }
9489 case XK_Right:
9490 case XK_KP_Right:
9491 {
9492 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9493 windows->magnify.x+=quantum;
9494 break;
9495 }
9496 case XK_Down:
9497 case XK_KP_Down:
9498 {
9499 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9500 windows->magnify.y+=quantum;
9501 break;
9502 }
9503 case XK_0:
9504 case XK_1:
9505 case XK_2:
9506 case XK_3:
9507 case XK_4:
9508 case XK_5:
9509 case XK_6:
9510 case XK_7:
9511 case XK_8:
9512 case XK_9:
9513 {
9514 windows->magnify.data=(key_symbol-XK_0);
9515 break;
9516 }
9517 case XK_KP_0:
9518 case XK_KP_1:
9519 case XK_KP_2:
9520 case XK_KP_3:
9521 case XK_KP_4:
9522 case XK_KP_5:
9523 case XK_KP_6:
9524 case XK_KP_7:
9525 case XK_KP_8:
9526 case XK_KP_9:
9527 {
9528 windows->magnify.data=(key_symbol-XK_KP_0);
9529 break;
9530 }
9531 default:
9532 break;
9533 }
9534 XMakeMagnifyImage(display,windows,exception);
9535 }
9536
9537 /*
9538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9539 % %
9540 % %
9541 % %
9542 + X M a k e P a n I m a g e %
9543 % %
9544 % %
9545 % %
9546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9547 %
9548 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9549 % icon window.
9550 %
9551 % The format of the XMakePanImage method is:
9552 %
9553 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9554 % XWindows *windows,Image *image,ExceptionInfo *exception)
9555 %
9556 % A description of each parameter follows:
9557 %
9558 % o display: Specifies a connection to an X server; returned from
9559 % XOpenDisplay.
9560 %
9561 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9562 %
9563 % o windows: Specifies a pointer to a XWindows structure.
9564 %
9565 % o image: the image.
9566 %
9567 % o exception: return any errors or warnings in this structure.
9568 %
9569 */
XMakePanImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)9570 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9571 XWindows *windows,Image *image,ExceptionInfo *exception)
9572 {
9573 MagickStatusType
9574 status;
9575
9576 /*
9577 Create and display image for panning icon.
9578 */
9579 XSetCursorState(display,windows,MagickTrue);
9580 XCheckRefreshWindows(display,windows);
9581 windows->pan.x=(int) windows->image.x;
9582 windows->pan.y=(int) windows->image.y;
9583 status=XMakeImage(display,resource_info,&windows->pan,image,
9584 windows->pan.width,windows->pan.height,exception);
9585 if (status == MagickFalse)
9586 ThrowXWindowException(ResourceLimitError,
9587 "MemoryAllocationFailed",image->filename);
9588 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9589 windows->pan.pixmap);
9590 (void) XClearWindow(display,windows->pan.id);
9591 XDrawPanRectangle(display,windows);
9592 XSetCursorState(display,windows,MagickFalse);
9593 }
9594
9595 /*
9596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9597 % %
9598 % %
9599 % %
9600 + X M a t t a E d i t I m a g e %
9601 % %
9602 % %
9603 % %
9604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9605 %
9606 % XMatteEditImage() allows the user to interactively change the Matte channel
9607 % of an image. If the image is PseudoClass it is promoted to DirectClass
9608 % before the matte information is stored.
9609 %
9610 % The format of the XMatteEditImage method is:
9611 %
9612 % MagickBooleanType XMatteEditImage(Display *display,
9613 % XResourceInfo *resource_info,XWindows *windows,Image **image,
9614 % ExceptionInfo *exception)
9615 %
9616 % A description of each parameter follows:
9617 %
9618 % o display: Specifies a connection to an X server; returned from
9619 % XOpenDisplay.
9620 %
9621 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9622 %
9623 % o windows: Specifies a pointer to a XWindows structure.
9624 %
9625 % o image: the image; returned from ReadImage.
9626 %
9627 % o exception: return any errors or warnings in this structure.
9628 %
9629 */
XMatteEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)9630 static MagickBooleanType XMatteEditImage(Display *display,
9631 XResourceInfo *resource_info,XWindows *windows,Image **image,
9632 ExceptionInfo *exception)
9633 {
9634 const char
9635 *const MatteEditMenu[] =
9636 {
9637 "Method",
9638 "Border Color",
9639 "Fuzz",
9640 "Matte Value",
9641 "Undo",
9642 "Help",
9643 "Dismiss",
9644 (char *) NULL
9645 };
9646
9647 static char
9648 matte[MagickPathExtent] = "0";
9649
9650 static const ModeType
9651 MatteEditCommands[] =
9652 {
9653 MatteEditMethod,
9654 MatteEditBorderCommand,
9655 MatteEditFuzzCommand,
9656 MatteEditValueCommand,
9657 MatteEditUndoCommand,
9658 MatteEditHelpCommand,
9659 MatteEditDismissCommand
9660 };
9661
9662 static PaintMethod
9663 method = PointMethod;
9664
9665 static XColor
9666 border_color = { 0, 0, 0, 0, 0, 0 };
9667
9668 char
9669 command[MagickPathExtent],
9670 text[MagickPathExtent];
9671
9672 Cursor
9673 cursor;
9674
9675 int
9676 entry,
9677 id,
9678 x,
9679 x_offset,
9680 y,
9681 y_offset;
9682
9683 register int
9684 i;
9685
9686 register Quantum
9687 *q;
9688
9689 unsigned int
9690 height,
9691 width;
9692
9693 size_t
9694 state;
9695
9696 XEvent
9697 event;
9698
9699 /*
9700 Map Command widget.
9701 */
9702 (void) CloneString(&windows->command.name,"Matte Edit");
9703 windows->command.data=4;
9704 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9705 (void) XMapRaised(display,windows->command.id);
9706 XClientMessage(display,windows->image.id,windows->im_protocols,
9707 windows->im_update_widget,CurrentTime);
9708 /*
9709 Make cursor.
9710 */
9711 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9712 resource_info->background_color,resource_info->foreground_color);
9713 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9714 /*
9715 Track pointer until button 1 is pressed.
9716 */
9717 XQueryPosition(display,windows->image.id,&x,&y);
9718 (void) XSelectInput(display,windows->image.id,
9719 windows->image.attributes.event_mask | PointerMotionMask);
9720 state=DefaultState;
9721 do
9722 {
9723 if (windows->info.mapped != MagickFalse )
9724 {
9725 /*
9726 Display pointer position.
9727 */
9728 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9729 x+windows->image.x,y+windows->image.y);
9730 XInfoWidget(display,windows,text);
9731 }
9732 /*
9733 Wait for next event.
9734 */
9735 XScreenEvent(display,windows,&event,exception);
9736 if (event.xany.window == windows->command.id)
9737 {
9738 /*
9739 Select a command from the Command widget.
9740 */
9741 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9742 if (id < 0)
9743 {
9744 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9745 continue;
9746 }
9747 switch (MatteEditCommands[id])
9748 {
9749 case MatteEditMethod:
9750 {
9751 char
9752 **methods;
9753
9754 /*
9755 Select a method from the pop-up menu.
9756 */
9757 methods=GetCommandOptions(MagickMethodOptions);
9758 if (methods == (char **) NULL)
9759 break;
9760 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9761 (const char **) methods,command);
9762 if (entry >= 0)
9763 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9764 MagickFalse,methods[entry]);
9765 methods=DestroyStringList(methods);
9766 break;
9767 }
9768 case MatteEditBorderCommand:
9769 {
9770 const char
9771 *ColorMenu[MaxNumberPens];
9772
9773 int
9774 pen_number;
9775
9776 /*
9777 Initialize menu selections.
9778 */
9779 for (i=0; i < (int) (MaxNumberPens-2); i++)
9780 ColorMenu[i]=resource_info->pen_colors[i];
9781 ColorMenu[MaxNumberPens-2]="Browser...";
9782 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9783 /*
9784 Select a pen color from the pop-up menu.
9785 */
9786 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9787 (const char **) ColorMenu,command);
9788 if (pen_number < 0)
9789 break;
9790 if (pen_number == (MaxNumberPens-2))
9791 {
9792 static char
9793 color_name[MagickPathExtent] = "gray";
9794
9795 /*
9796 Select a pen color from a dialog.
9797 */
9798 resource_info->pen_colors[pen_number]=color_name;
9799 XColorBrowserWidget(display,windows,"Select",color_name);
9800 if (*color_name == '\0')
9801 break;
9802 }
9803 /*
9804 Set border color.
9805 */
9806 (void) XParseColor(display,windows->map_info->colormap,
9807 resource_info->pen_colors[pen_number],&border_color);
9808 break;
9809 }
9810 case MatteEditFuzzCommand:
9811 {
9812 const char
9813 *const FuzzMenu[] =
9814 {
9815 "0%",
9816 "2%",
9817 "5%",
9818 "10%",
9819 "15%",
9820 "Dialog...",
9821 (char *) NULL,
9822 };
9823
9824 static char
9825 fuzz[MagickPathExtent];
9826
9827 /*
9828 Select a command from the pop-up menu.
9829 */
9830 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9831 command);
9832 if (entry < 0)
9833 break;
9834 if (entry != 5)
9835 {
9836 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9837 QuantumRange+1.0);
9838 break;
9839 }
9840 (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
9841 (void) XDialogWidget(display,windows,"Ok",
9842 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9843 if (*fuzz == '\0')
9844 break;
9845 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
9846 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9847 1.0);
9848 break;
9849 }
9850 case MatteEditValueCommand:
9851 {
9852 const char
9853 *const MatteMenu[] =
9854 {
9855 "Opaque",
9856 "Transparent",
9857 "Dialog...",
9858 (char *) NULL,
9859 };
9860
9861 static char
9862 message[MagickPathExtent];
9863
9864 /*
9865 Select a command from the pop-up menu.
9866 */
9867 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9868 command);
9869 if (entry < 0)
9870 break;
9871 if (entry != 2)
9872 {
9873 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
9874 OpaqueAlpha);
9875 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9876 (void) FormatLocaleString(matte,MagickPathExtent,
9877 QuantumFormat,(Quantum) TransparentAlpha);
9878 break;
9879 }
9880 (void) FormatLocaleString(message,MagickPathExtent,
9881 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9882 QuantumRange);
9883 (void) XDialogWidget(display,windows,"Matte",message,matte);
9884 if (*matte == '\0')
9885 break;
9886 break;
9887 }
9888 case MatteEditUndoCommand:
9889 {
9890 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9891 image,exception);
9892 break;
9893 }
9894 case MatteEditHelpCommand:
9895 {
9896 XTextViewHelp(display,resource_info,windows,MagickFalse,
9897 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9898 break;
9899 }
9900 case MatteEditDismissCommand:
9901 {
9902 /*
9903 Prematurely exit.
9904 */
9905 state|=EscapeState;
9906 state|=ExitState;
9907 break;
9908 }
9909 default:
9910 break;
9911 }
9912 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9913 continue;
9914 }
9915 switch (event.type)
9916 {
9917 case ButtonPress:
9918 {
9919 if (event.xbutton.button != Button1)
9920 break;
9921 if ((event.xbutton.window != windows->image.id) &&
9922 (event.xbutton.window != windows->magnify.id))
9923 break;
9924 /*
9925 Update matte data.
9926 */
9927 x=event.xbutton.x;
9928 y=event.xbutton.y;
9929 (void) XMagickCommand(display,resource_info,windows,
9930 SaveToUndoBufferCommand,image,exception);
9931 state|=UpdateConfigurationState;
9932 break;
9933 }
9934 case ButtonRelease:
9935 {
9936 if (event.xbutton.button != Button1)
9937 break;
9938 if ((event.xbutton.window != windows->image.id) &&
9939 (event.xbutton.window != windows->magnify.id))
9940 break;
9941 /*
9942 Update colormap information.
9943 */
9944 x=event.xbutton.x;
9945 y=event.xbutton.y;
9946 XConfigureImageColormap(display,resource_info,windows,*image,exception);
9947 (void) XConfigureImage(display,resource_info,windows,*image,exception);
9948 XInfoWidget(display,windows,text);
9949 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9950 state&=(~UpdateConfigurationState);
9951 break;
9952 }
9953 case Expose:
9954 break;
9955 case KeyPress:
9956 {
9957 char
9958 command[MagickPathExtent];
9959
9960 KeySym
9961 key_symbol;
9962
9963 if (event.xkey.window == windows->magnify.id)
9964 {
9965 Window
9966 window;
9967
9968 window=windows->magnify.id;
9969 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9970 }
9971 if (event.xkey.window != windows->image.id)
9972 break;
9973 /*
9974 Respond to a user key press.
9975 */
9976 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9977 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9978 switch ((int) key_symbol)
9979 {
9980 case XK_Escape:
9981 case XK_F20:
9982 {
9983 /*
9984 Prematurely exit.
9985 */
9986 state|=ExitState;
9987 break;
9988 }
9989 case XK_F1:
9990 case XK_Help:
9991 {
9992 XTextViewHelp(display,resource_info,windows,MagickFalse,
9993 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9994 break;
9995 }
9996 default:
9997 {
9998 (void) XBell(display,0);
9999 break;
10000 }
10001 }
10002 break;
10003 }
10004 case MotionNotify:
10005 {
10006 /*
10007 Map and unmap Info widget as cursor crosses its boundaries.
10008 */
10009 x=event.xmotion.x;
10010 y=event.xmotion.y;
10011 if (windows->info.mapped != MagickFalse )
10012 {
10013 if ((x < (int) (windows->info.x+windows->info.width)) &&
10014 (y < (int) (windows->info.y+windows->info.height)))
10015 (void) XWithdrawWindow(display,windows->info.id,
10016 windows->info.screen);
10017 }
10018 else
10019 if ((x > (int) (windows->info.x+windows->info.width)) ||
10020 (y > (int) (windows->info.y+windows->info.height)))
10021 (void) XMapWindow(display,windows->info.id);
10022 break;
10023 }
10024 default:
10025 break;
10026 }
10027 if (event.xany.window == windows->magnify.id)
10028 {
10029 x=windows->magnify.x-windows->image.x;
10030 y=windows->magnify.y-windows->image.y;
10031 }
10032 x_offset=x;
10033 y_offset=y;
10034 if ((state & UpdateConfigurationState) != 0)
10035 {
10036 CacheView
10037 *image_view;
10038
10039 int
10040 x,
10041 y;
10042
10043 /*
10044 Matte edit is relative to image configuration.
10045 */
10046 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10047 MagickTrue);
10048 XPutPixel(windows->image.ximage,x_offset,y_offset,
10049 windows->pixel_info->background_color.pixel);
10050 width=(unsigned int) (*image)->columns;
10051 height=(unsigned int) (*image)->rows;
10052 x=0;
10053 y=0;
10054 if (windows->image.crop_geometry != (char *) NULL)
10055 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10056 &height);
10057 x_offset=(int) (width*(windows->image.x+x_offset)/
10058 windows->image.ximage->width+x);
10059 y_offset=(int) (height*(windows->image.y+y_offset)/
10060 windows->image.ximage->height+y);
10061 if ((x_offset < 0) || (y_offset < 0))
10062 continue;
10063 if ((x_offset >= (int) (*image)->columns) ||
10064 (y_offset >= (int) (*image)->rows))
10065 continue;
10066 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10067 return(MagickFalse);
10068 if ((*image)->alpha_trait == UndefinedPixelTrait)
10069 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
10070 image_view=AcquireAuthenticCacheView(*image,exception);
10071 switch (method)
10072 {
10073 case PointMethod:
10074 default:
10075 {
10076 /*
10077 Update matte information using point algorithm.
10078 */
10079 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10080 (ssize_t) y_offset,1,1,exception);
10081 if (q == (Quantum *) NULL)
10082 break;
10083 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10084 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10085 break;
10086 }
10087 case ReplaceMethod:
10088 {
10089 PixelInfo
10090 pixel,
10091 target;
10092
10093 /*
10094 Update matte information using replace algorithm.
10095 */
10096 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10097 x_offset,(ssize_t) y_offset,&target,exception);
10098 for (y=0; y < (int) (*image)->rows; y++)
10099 {
10100 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10101 (*image)->columns,1,exception);
10102 if (q == (Quantum *) NULL)
10103 break;
10104 for (x=0; x < (int) (*image)->columns; x++)
10105 {
10106 GetPixelInfoPixel(*image,q,&pixel);
10107 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
10108 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10109 q+=GetPixelChannels(*image);
10110 }
10111 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10112 break;
10113 }
10114 break;
10115 }
10116 case FloodfillMethod:
10117 case FillToBorderMethod:
10118 {
10119 ChannelType
10120 channel_mask;
10121
10122 DrawInfo
10123 *draw_info;
10124
10125 PixelInfo
10126 target;
10127
10128 /*
10129 Update matte information using floodfill algorithm.
10130 */
10131 (void) GetOneVirtualPixelInfo(*image,
10132 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10133 y_offset,&target,exception);
10134 if (method == FillToBorderMethod)
10135 {
10136 target.red=(double) ScaleShortToQuantum(
10137 border_color.red);
10138 target.green=(double) ScaleShortToQuantum(
10139 border_color.green);
10140 target.blue=(double) ScaleShortToQuantum(
10141 border_color.blue);
10142 }
10143 draw_info=CloneDrawInfo(resource_info->image_info,
10144 (DrawInfo *) NULL);
10145 draw_info->fill.alpha=(double) ClampToQuantum(
10146 StringToDouble(matte,(char **) NULL));
10147 channel_mask=SetImageChannelMask(*image,AlphaChannel);
10148 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10149 x_offset,(ssize_t) y_offset,
10150 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
10151 (void) SetPixelChannelMask(*image,channel_mask);
10152 draw_info=DestroyDrawInfo(draw_info);
10153 break;
10154 }
10155 case ResetMethod:
10156 {
10157 /*
10158 Update matte information using reset algorithm.
10159 */
10160 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10161 return(MagickFalse);
10162 for (y=0; y < (int) (*image)->rows; y++)
10163 {
10164 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10165 (*image)->columns,1,exception);
10166 if (q == (Quantum *) NULL)
10167 break;
10168 for (x=0; x < (int) (*image)->columns; x++)
10169 {
10170 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10171 q+=GetPixelChannels(*image);
10172 }
10173 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10174 break;
10175 }
10176 if (StringToLong(matte) == (long) OpaqueAlpha)
10177 (*image)->alpha_trait=UndefinedPixelTrait;
10178 break;
10179 }
10180 }
10181 image_view=DestroyCacheView(image_view);
10182 state&=(~UpdateConfigurationState);
10183 }
10184 } while ((state & ExitState) == 0);
10185 (void) XSelectInput(display,windows->image.id,
10186 windows->image.attributes.event_mask);
10187 XSetCursorState(display,windows,MagickFalse);
10188 (void) XFreeCursor(display,cursor);
10189 return(MagickTrue);
10190 }
10191
10192 /*
10193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10194 % %
10195 % %
10196 % %
10197 + X O p e n I m a g e %
10198 % %
10199 % %
10200 % %
10201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10202 %
10203 % XOpenImage() loads an image from a file.
10204 %
10205 % The format of the XOpenImage method is:
10206 %
10207 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10208 % XWindows *windows,const unsigned int command)
10209 %
10210 % A description of each parameter follows:
10211 %
10212 % o display: Specifies a connection to an X server; returned from
10213 % XOpenDisplay.
10214 %
10215 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10216 %
10217 % o windows: Specifies a pointer to a XWindows structure.
10218 %
10219 % o command: A value other than zero indicates that the file is selected
10220 % from the command line argument list.
10221 %
10222 */
XOpenImage(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickBooleanType command)10223 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10224 XWindows *windows,const MagickBooleanType command)
10225 {
10226 const MagickInfo
10227 *magick_info;
10228
10229 ExceptionInfo
10230 *exception;
10231
10232 Image
10233 *nexus;
10234
10235 ImageInfo
10236 *image_info;
10237
10238 static char
10239 filename[MagickPathExtent] = "\0";
10240
10241 /*
10242 Request file name from user.
10243 */
10244 if (command == MagickFalse)
10245 XFileBrowserWidget(display,windows,"Open",filename);
10246 else
10247 {
10248 char
10249 **filelist,
10250 **files;
10251
10252 int
10253 count,
10254 status;
10255
10256 register int
10257 i,
10258 j;
10259
10260 /*
10261 Select next image from the command line.
10262 */
10263 status=XGetCommand(display,windows->image.id,&files,&count);
10264 if (status == 0)
10265 {
10266 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10267 return((Image *) NULL);
10268 }
10269 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10270 if (filelist == (char **) NULL)
10271 {
10272 ThrowXWindowException(ResourceLimitError,
10273 "MemoryAllocationFailed","...");
10274 (void) XFreeStringList(files);
10275 return((Image *) NULL);
10276 }
10277 j=0;
10278 for (i=1; i < count; i++)
10279 if (*files[i] != '-')
10280 filelist[j++]=files[i];
10281 filelist[j]=(char *) NULL;
10282 XListBrowserWidget(display,windows,&windows->widget,
10283 (const char **) filelist,"Load","Select Image to Load:",filename);
10284 filelist=(char **) RelinquishMagickMemory(filelist);
10285 (void) XFreeStringList(files);
10286 }
10287 if (*filename == '\0')
10288 return((Image *) NULL);
10289 image_info=CloneImageInfo(resource_info->image_info);
10290 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10291 (void *) NULL);
10292 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10293 exception=AcquireExceptionInfo();
10294 (void) SetImageInfo(image_info,0,exception);
10295 if (LocaleCompare(image_info->magick,"X") == 0)
10296 {
10297 char
10298 seconds[MagickPathExtent];
10299
10300 /*
10301 User may want to delay the X server screen grab.
10302 */
10303 (void) CopyMagickString(seconds,"0",MagickPathExtent);
10304 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10305 seconds);
10306 if (*seconds == '\0')
10307 return((Image *) NULL);
10308 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10309 }
10310 magick_info=GetMagickInfo(image_info->magick,exception);
10311 if ((magick_info != (const MagickInfo *) NULL) &&
10312 GetMagickRawSupport(magick_info) == MagickTrue)
10313 {
10314 char
10315 geometry[MagickPathExtent];
10316
10317 /*
10318 Request image size from the user.
10319 */
10320 (void) CopyMagickString(geometry,"512x512",MagickPathExtent);
10321 if (image_info->size != (char *) NULL)
10322 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent);
10323 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10324 geometry);
10325 (void) CloneString(&image_info->size,geometry);
10326 }
10327 /*
10328 Load the image.
10329 */
10330 XSetCursorState(display,windows,MagickTrue);
10331 XCheckRefreshWindows(display,windows);
10332 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10333 nexus=ReadImage(image_info,exception);
10334 CatchException(exception);
10335 XSetCursorState(display,windows,MagickFalse);
10336 if (nexus != (Image *) NULL)
10337 XClientMessage(display,windows->image.id,windows->im_protocols,
10338 windows->im_next_image,CurrentTime);
10339 else
10340 {
10341 char
10342 *text,
10343 **textlist;
10344
10345 /*
10346 Unknown image format.
10347 */
10348 text=FileToString(filename,~0UL,exception);
10349 if (text == (char *) NULL)
10350 return((Image *) NULL);
10351 textlist=StringToList(text);
10352 if (textlist != (char **) NULL)
10353 {
10354 char
10355 title[MagickPathExtent];
10356
10357 register int
10358 i;
10359
10360 (void) FormatLocaleString(title,MagickPathExtent,
10361 "Unknown format: %s",filename);
10362 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10363 (const char **) textlist);
10364 for (i=0; textlist[i] != (char *) NULL; i++)
10365 textlist[i]=DestroyString(textlist[i]);
10366 textlist=(char **) RelinquishMagickMemory(textlist);
10367 }
10368 text=DestroyString(text);
10369 }
10370 exception=DestroyExceptionInfo(exception);
10371 image_info=DestroyImageInfo(image_info);
10372 return(nexus);
10373 }
10374
10375 /*
10376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10377 % %
10378 % %
10379 % %
10380 + X P a n I m a g e %
10381 % %
10382 % %
10383 % %
10384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10385 %
10386 % XPanImage() pans the image until the mouse button is released.
10387 %
10388 % The format of the XPanImage method is:
10389 %
10390 % void XPanImage(Display *display,XWindows *windows,XEvent *event,
10391 % ExceptionInfo *exception)
10392 %
10393 % A description of each parameter follows:
10394 %
10395 % o display: Specifies a connection to an X server; returned from
10396 % XOpenDisplay.
10397 %
10398 % o windows: Specifies a pointer to a XWindows structure.
10399 %
10400 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10401 % the entire image is refreshed.
10402 %
10403 % o exception: return any errors or warnings in this structure.
10404 %
10405 */
XPanImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)10406 static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10407 ExceptionInfo *exception)
10408 {
10409 char
10410 text[MagickPathExtent];
10411
10412 Cursor
10413 cursor;
10414
10415 double
10416 x_factor,
10417 y_factor;
10418
10419 RectangleInfo
10420 pan_info;
10421
10422 size_t
10423 state;
10424
10425 /*
10426 Define cursor.
10427 */
10428 if ((windows->image.ximage->width > (int) windows->image.width) &&
10429 (windows->image.ximage->height > (int) windows->image.height))
10430 cursor=XCreateFontCursor(display,XC_fleur);
10431 else
10432 if (windows->image.ximage->width > (int) windows->image.width)
10433 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10434 else
10435 if (windows->image.ximage->height > (int) windows->image.height)
10436 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10437 else
10438 cursor=XCreateFontCursor(display,XC_arrow);
10439 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10440 /*
10441 Pan image as pointer moves until the mouse button is released.
10442 */
10443 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10444 y_factor=(double) windows->image.ximage->height/windows->pan.height;
10445 pan_info.width=windows->pan.width*windows->image.width/
10446 windows->image.ximage->width;
10447 pan_info.height=windows->pan.height*windows->image.height/
10448 windows->image.ximage->height;
10449 pan_info.x=0;
10450 pan_info.y=0;
10451 state=UpdateConfigurationState;
10452 do
10453 {
10454 switch (event->type)
10455 {
10456 case ButtonPress:
10457 {
10458 /*
10459 User choose an initial pan location.
10460 */
10461 pan_info.x=(ssize_t) event->xbutton.x;
10462 pan_info.y=(ssize_t) event->xbutton.y;
10463 state|=UpdateConfigurationState;
10464 break;
10465 }
10466 case ButtonRelease:
10467 {
10468 /*
10469 User has finished panning the image.
10470 */
10471 pan_info.x=(ssize_t) event->xbutton.x;
10472 pan_info.y=(ssize_t) event->xbutton.y;
10473 state|=UpdateConfigurationState | ExitState;
10474 break;
10475 }
10476 case MotionNotify:
10477 {
10478 pan_info.x=(ssize_t) event->xmotion.x;
10479 pan_info.y=(ssize_t) event->xmotion.y;
10480 state|=UpdateConfigurationState;
10481 }
10482 default:
10483 break;
10484 }
10485 if ((state & UpdateConfigurationState) != 0)
10486 {
10487 /*
10488 Check boundary conditions.
10489 */
10490 if (pan_info.x < (ssize_t) (pan_info.width/2))
10491 pan_info.x=0;
10492 else
10493 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10494 if (pan_info.x < 0)
10495 pan_info.x=0;
10496 else
10497 if ((int) (pan_info.x+windows->image.width) >
10498 windows->image.ximage->width)
10499 pan_info.x=(ssize_t)
10500 (windows->image.ximage->width-windows->image.width);
10501 if (pan_info.y < (ssize_t) (pan_info.height/2))
10502 pan_info.y=0;
10503 else
10504 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10505 if (pan_info.y < 0)
10506 pan_info.y=0;
10507 else
10508 if ((int) (pan_info.y+windows->image.height) >
10509 windows->image.ximage->height)
10510 pan_info.y=(ssize_t)
10511 (windows->image.ximage->height-windows->image.height);
10512 if ((windows->image.x != (int) pan_info.x) ||
10513 (windows->image.y != (int) pan_info.y))
10514 {
10515 /*
10516 Display image pan offset.
10517 */
10518 windows->image.x=(int) pan_info.x;
10519 windows->image.y=(int) pan_info.y;
10520 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
10521 windows->image.width,windows->image.height,windows->image.x,
10522 windows->image.y);
10523 XInfoWidget(display,windows,text);
10524 /*
10525 Refresh Image window.
10526 */
10527 XDrawPanRectangle(display,windows);
10528 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10529 }
10530 state&=(~UpdateConfigurationState);
10531 }
10532 /*
10533 Wait for next event.
10534 */
10535 if ((state & ExitState) == 0)
10536 XScreenEvent(display,windows,event,exception);
10537 } while ((state & ExitState) == 0);
10538 /*
10539 Restore cursor.
10540 */
10541 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10542 (void) XFreeCursor(display,cursor);
10543 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10544 }
10545
10546 /*
10547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10548 % %
10549 % %
10550 % %
10551 + X P a s t e I m a g e %
10552 % %
10553 % %
10554 % %
10555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10556 %
10557 % XPasteImage() pastes an image previously saved with XCropImage in the X
10558 % window image at a location the user chooses with the pointer.
10559 %
10560 % The format of the XPasteImage method is:
10561 %
10562 % MagickBooleanType XPasteImage(Display *display,
10563 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10564 % ExceptionInfo *exception)
10565 %
10566 % A description of each parameter follows:
10567 %
10568 % o display: Specifies a connection to an X server; returned from
10569 % XOpenDisplay.
10570 %
10571 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10572 %
10573 % o windows: Specifies a pointer to a XWindows structure.
10574 %
10575 % o image: the image; returned from ReadImage.
10576 %
10577 % o exception: return any errors or warnings in this structure.
10578 %
10579 */
XPasteImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10580 static MagickBooleanType XPasteImage(Display *display,
10581 XResourceInfo *resource_info,XWindows *windows,Image *image,
10582 ExceptionInfo *exception)
10583 {
10584 const char
10585 *const PasteMenu[] =
10586 {
10587 "Operator",
10588 "Help",
10589 "Dismiss",
10590 (char *) NULL
10591 };
10592
10593 static const ModeType
10594 PasteCommands[] =
10595 {
10596 PasteOperatorsCommand,
10597 PasteHelpCommand,
10598 PasteDismissCommand
10599 };
10600
10601 static CompositeOperator
10602 compose = CopyCompositeOp;
10603
10604 char
10605 text[MagickPathExtent];
10606
10607 Cursor
10608 cursor;
10609
10610 Image
10611 *paste_image;
10612
10613 int
10614 entry,
10615 id,
10616 x,
10617 y;
10618
10619 double
10620 scale_factor;
10621
10622 RectangleInfo
10623 highlight_info,
10624 paste_info;
10625
10626 unsigned int
10627 height,
10628 width;
10629
10630 size_t
10631 state;
10632
10633 XEvent
10634 event;
10635
10636 /*
10637 Copy image.
10638 */
10639 if (resource_info->copy_image == (Image *) NULL)
10640 return(MagickFalse);
10641 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
10642 if (paste_image == (Image *) NULL)
10643 return(MagickFalse);
10644 /*
10645 Map Command widget.
10646 */
10647 (void) CloneString(&windows->command.name,"Paste");
10648 windows->command.data=1;
10649 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10650 (void) XMapRaised(display,windows->command.id);
10651 XClientMessage(display,windows->image.id,windows->im_protocols,
10652 windows->im_update_widget,CurrentTime);
10653 /*
10654 Track pointer until button 1 is pressed.
10655 */
10656 XSetCursorState(display,windows,MagickFalse);
10657 XQueryPosition(display,windows->image.id,&x,&y);
10658 (void) XSelectInput(display,windows->image.id,
10659 windows->image.attributes.event_mask | PointerMotionMask);
10660 paste_info.x=(ssize_t) windows->image.x+x;
10661 paste_info.y=(ssize_t) windows->image.y+y;
10662 paste_info.width=0;
10663 paste_info.height=0;
10664 cursor=XCreateFontCursor(display,XC_ul_angle);
10665 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10666 state=DefaultState;
10667 do
10668 {
10669 if (windows->info.mapped != MagickFalse )
10670 {
10671 /*
10672 Display pointer position.
10673 */
10674 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
10675 (long) paste_info.x,(long) paste_info.y);
10676 XInfoWidget(display,windows,text);
10677 }
10678 highlight_info=paste_info;
10679 highlight_info.x=paste_info.x-windows->image.x;
10680 highlight_info.y=paste_info.y-windows->image.y;
10681 XHighlightRectangle(display,windows->image.id,
10682 windows->image.highlight_context,&highlight_info);
10683 /*
10684 Wait for next event.
10685 */
10686 XScreenEvent(display,windows,&event,exception);
10687 XHighlightRectangle(display,windows->image.id,
10688 windows->image.highlight_context,&highlight_info);
10689 if (event.xany.window == windows->command.id)
10690 {
10691 /*
10692 Select a command from the Command widget.
10693 */
10694 id=XCommandWidget(display,windows,PasteMenu,&event);
10695 if (id < 0)
10696 continue;
10697 switch (PasteCommands[id])
10698 {
10699 case PasteOperatorsCommand:
10700 {
10701 char
10702 command[MagickPathExtent],
10703 **operators;
10704
10705 /*
10706 Select a command from the pop-up menu.
10707 */
10708 operators=GetCommandOptions(MagickComposeOptions);
10709 if (operators == (char **) NULL)
10710 break;
10711 entry=XMenuWidget(display,windows,PasteMenu[id],
10712 (const char **) operators,command);
10713 if (entry >= 0)
10714 compose=(CompositeOperator) ParseCommandOption(
10715 MagickComposeOptions,MagickFalse,operators[entry]);
10716 operators=DestroyStringList(operators);
10717 break;
10718 }
10719 case PasteHelpCommand:
10720 {
10721 XTextViewHelp(display,resource_info,windows,MagickFalse,
10722 "Help Viewer - Image Composite",ImagePasteHelp);
10723 break;
10724 }
10725 case PasteDismissCommand:
10726 {
10727 /*
10728 Prematurely exit.
10729 */
10730 state|=EscapeState;
10731 state|=ExitState;
10732 break;
10733 }
10734 default:
10735 break;
10736 }
10737 continue;
10738 }
10739 switch (event.type)
10740 {
10741 case ButtonPress:
10742 {
10743 if (image->debug != MagickFalse )
10744 (void) LogMagickEvent(X11Event,GetMagickModule(),
10745 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10746 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10747 if (event.xbutton.button != Button1)
10748 break;
10749 if (event.xbutton.window != windows->image.id)
10750 break;
10751 /*
10752 Paste rectangle is relative to image configuration.
10753 */
10754 width=(unsigned int) image->columns;
10755 height=(unsigned int) image->rows;
10756 x=0;
10757 y=0;
10758 if (windows->image.crop_geometry != (char *) NULL)
10759 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10760 &width,&height);
10761 scale_factor=(double) windows->image.ximage->width/width;
10762 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10763 scale_factor=(double) windows->image.ximage->height/height;
10764 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10765 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10766 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10767 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10768 break;
10769 }
10770 case ButtonRelease:
10771 {
10772 if (image->debug != MagickFalse )
10773 (void) LogMagickEvent(X11Event,GetMagickModule(),
10774 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10775 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10776 if (event.xbutton.button != Button1)
10777 break;
10778 if (event.xbutton.window != windows->image.id)
10779 break;
10780 if ((paste_info.width != 0) && (paste_info.height != 0))
10781 {
10782 /*
10783 User has selected the location of the paste image.
10784 */
10785 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10786 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10787 state|=ExitState;
10788 }
10789 break;
10790 }
10791 case Expose:
10792 break;
10793 case KeyPress:
10794 {
10795 char
10796 command[MagickPathExtent];
10797
10798 KeySym
10799 key_symbol;
10800
10801 int
10802 length;
10803
10804 if (event.xkey.window != windows->image.id)
10805 break;
10806 /*
10807 Respond to a user key press.
10808 */
10809 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10810 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10811 *(command+length)='\0';
10812 if (image->debug != MagickFalse )
10813 (void) LogMagickEvent(X11Event,GetMagickModule(),
10814 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10815 switch ((int) key_symbol)
10816 {
10817 case XK_Escape:
10818 case XK_F20:
10819 {
10820 /*
10821 Prematurely exit.
10822 */
10823 paste_image=DestroyImage(paste_image);
10824 state|=EscapeState;
10825 state|=ExitState;
10826 break;
10827 }
10828 case XK_F1:
10829 case XK_Help:
10830 {
10831 (void) XSetFunction(display,windows->image.highlight_context,
10832 GXcopy);
10833 XTextViewHelp(display,resource_info,windows,MagickFalse,
10834 "Help Viewer - Image Composite",ImagePasteHelp);
10835 (void) XSetFunction(display,windows->image.highlight_context,
10836 GXinvert);
10837 break;
10838 }
10839 default:
10840 {
10841 (void) XBell(display,0);
10842 break;
10843 }
10844 }
10845 break;
10846 }
10847 case MotionNotify:
10848 {
10849 /*
10850 Map and unmap Info widget as text cursor crosses its boundaries.
10851 */
10852 x=event.xmotion.x;
10853 y=event.xmotion.y;
10854 if (windows->info.mapped != MagickFalse )
10855 {
10856 if ((x < (int) (windows->info.x+windows->info.width)) &&
10857 (y < (int) (windows->info.y+windows->info.height)))
10858 (void) XWithdrawWindow(display,windows->info.id,
10859 windows->info.screen);
10860 }
10861 else
10862 if ((x > (int) (windows->info.x+windows->info.width)) ||
10863 (y > (int) (windows->info.y+windows->info.height)))
10864 (void) XMapWindow(display,windows->info.id);
10865 paste_info.x=(ssize_t) windows->image.x+x;
10866 paste_info.y=(ssize_t) windows->image.y+y;
10867 break;
10868 }
10869 default:
10870 {
10871 if (image->debug != MagickFalse )
10872 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10873 event.type);
10874 break;
10875 }
10876 }
10877 } while ((state & ExitState) == 0);
10878 (void) XSelectInput(display,windows->image.id,
10879 windows->image.attributes.event_mask);
10880 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10881 XSetCursorState(display,windows,MagickFalse);
10882 (void) XFreeCursor(display,cursor);
10883 if ((state & EscapeState) != 0)
10884 return(MagickTrue);
10885 /*
10886 Image pasting is relative to image configuration.
10887 */
10888 XSetCursorState(display,windows,MagickTrue);
10889 XCheckRefreshWindows(display,windows);
10890 width=(unsigned int) image->columns;
10891 height=(unsigned int) image->rows;
10892 x=0;
10893 y=0;
10894 if (windows->image.crop_geometry != (char *) NULL)
10895 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10896 scale_factor=(double) width/windows->image.ximage->width;
10897 paste_info.x+=x;
10898 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10899 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10900 scale_factor=(double) height/windows->image.ximage->height;
10901 paste_info.y+=y;
10902 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10903 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10904 /*
10905 Paste image with X Image window.
10906 */
10907 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
10908 paste_info.y,exception);
10909 paste_image=DestroyImage(paste_image);
10910 XSetCursorState(display,windows,MagickFalse);
10911 /*
10912 Update image colormap.
10913 */
10914 XConfigureImageColormap(display,resource_info,windows,image,exception);
10915 (void) XConfigureImage(display,resource_info,windows,image,exception);
10916 return(MagickTrue);
10917 }
10918
10919 /*
10920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10921 % %
10922 % %
10923 % %
10924 + X P r i n t I m a g e %
10925 % %
10926 % %
10927 % %
10928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10929 %
10930 % XPrintImage() prints an image to a Postscript printer.
10931 %
10932 % The format of the XPrintImage method is:
10933 %
10934 % MagickBooleanType XPrintImage(Display *display,
10935 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10936 % ExceptionInfo *exception)
10937 %
10938 % A description of each parameter follows:
10939 %
10940 % o display: Specifies a connection to an X server; returned from
10941 % XOpenDisplay.
10942 %
10943 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10944 %
10945 % o windows: Specifies a pointer to a XWindows structure.
10946 %
10947 % o image: the image.
10948 %
10949 % o exception: return any errors or warnings in this structure.
10950 %
10951 */
XPrintImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10952 static MagickBooleanType XPrintImage(Display *display,
10953 XResourceInfo *resource_info,XWindows *windows,Image *image,
10954 ExceptionInfo *exception)
10955 {
10956 char
10957 filename[MagickPathExtent],
10958 geometry[MagickPathExtent];
10959
10960 const char
10961 *const PageSizes[] =
10962 {
10963 "Letter",
10964 "Tabloid",
10965 "Ledger",
10966 "Legal",
10967 "Statement",
10968 "Executive",
10969 "A3",
10970 "A4",
10971 "A5",
10972 "B4",
10973 "B5",
10974 "Folio",
10975 "Quarto",
10976 "10x14",
10977 (char *) NULL
10978 };
10979
10980 Image
10981 *print_image;
10982
10983 ImageInfo
10984 *image_info;
10985
10986 MagickStatusType
10987 status;
10988
10989 /*
10990 Request Postscript page geometry from user.
10991 */
10992 image_info=CloneImageInfo(resource_info->image_info);
10993 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter");
10994 if (image_info->page != (char *) NULL)
10995 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
10996 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10997 "Select Postscript Page Geometry:",geometry);
10998 if (*geometry == '\0')
10999 return(MagickTrue);
11000 image_info->page=GetPageGeometry(geometry);
11001 /*
11002 Apply image transforms.
11003 */
11004 XSetCursorState(display,windows,MagickTrue);
11005 XCheckRefreshWindows(display,windows);
11006 print_image=CloneImage(image,0,0,MagickTrue,exception);
11007 if (print_image == (Image *) NULL)
11008 return(MagickFalse);
11009 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
11010 windows->image.ximage->width,windows->image.ximage->height);
11011 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11012 exception);
11013 /*
11014 Print image.
11015 */
11016 (void) AcquireUniqueFilename(filename);
11017 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s",
11018 filename);
11019 status=WriteImage(image_info,print_image,exception);
11020 (void) RelinquishUniqueFileResource(filename);
11021 print_image=DestroyImage(print_image);
11022 image_info=DestroyImageInfo(image_info);
11023 XSetCursorState(display,windows,MagickFalse);
11024 return(status != 0 ? MagickTrue : MagickFalse);
11025 }
11026
11027 /*
11028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11029 % %
11030 % %
11031 % %
11032 + X R O I I m a g e %
11033 % %
11034 % %
11035 % %
11036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11037 %
11038 % XROIImage() applies an image processing technique to a region of interest.
11039 %
11040 % The format of the XROIImage method is:
11041 %
11042 % MagickBooleanType XROIImage(Display *display,
11043 % XResourceInfo *resource_info,XWindows *windows,Image **image,
11044 % ExceptionInfo *exception)
11045 %
11046 % A description of each parameter follows:
11047 %
11048 % o display: Specifies a connection to an X server; returned from
11049 % XOpenDisplay.
11050 %
11051 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11052 %
11053 % o windows: Specifies a pointer to a XWindows structure.
11054 %
11055 % o image: the image; returned from ReadImage.
11056 %
11057 % o exception: return any errors or warnings in this structure.
11058 %
11059 */
XROIImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)11060 static MagickBooleanType XROIImage(Display *display,
11061 XResourceInfo *resource_info,XWindows *windows,Image **image,
11062 ExceptionInfo *exception)
11063 {
11064 #define ApplyMenus 7
11065
11066 const char
11067 *const ROIMenu[] =
11068 {
11069 "Help",
11070 "Dismiss",
11071 (char *) NULL
11072 },
11073 *const ApplyMenu[] =
11074 {
11075 "File",
11076 "Edit",
11077 "Transform",
11078 "Enhance",
11079 "Effects",
11080 "F/X",
11081 "Miscellany",
11082 "Help",
11083 "Dismiss",
11084 (char *) NULL
11085 },
11086 *const FileMenu[] =
11087 {
11088 "Save...",
11089 "Print...",
11090 (char *) NULL
11091 },
11092 *const EditMenu[] =
11093 {
11094 "Undo",
11095 "Redo",
11096 (char *) NULL
11097 },
11098 *const TransformMenu[] =
11099 {
11100 "Flop",
11101 "Flip",
11102 "Rotate Right",
11103 "Rotate Left",
11104 (char *) NULL
11105 },
11106 *const EnhanceMenu[] =
11107 {
11108 "Hue...",
11109 "Saturation...",
11110 "Brightness...",
11111 "Gamma...",
11112 "Spiff",
11113 "Dull",
11114 "Contrast Stretch...",
11115 "Sigmoidal Contrast...",
11116 "Normalize",
11117 "Equalize",
11118 "Negate",
11119 "Grayscale",
11120 "Map...",
11121 "Quantize...",
11122 (char *) NULL
11123 },
11124 *const EffectsMenu[] =
11125 {
11126 "Despeckle",
11127 "Emboss",
11128 "Reduce Noise",
11129 "Add Noise",
11130 "Sharpen...",
11131 "Blur...",
11132 "Threshold...",
11133 "Edge Detect...",
11134 "Spread...",
11135 "Shade...",
11136 "Raise...",
11137 "Segment...",
11138 (char *) NULL
11139 },
11140 *const FXMenu[] =
11141 {
11142 "Solarize...",
11143 "Sepia Tone...",
11144 "Swirl...",
11145 "Implode...",
11146 "Vignette...",
11147 "Wave...",
11148 "Oil Paint...",
11149 "Charcoal Draw...",
11150 (char *) NULL
11151 },
11152 *const MiscellanyMenu[] =
11153 {
11154 "Image Info",
11155 "Zoom Image",
11156 "Show Preview...",
11157 "Show Histogram",
11158 "Show Matte",
11159 (char *) NULL
11160 };
11161
11162 const char
11163 *const *Menus[ApplyMenus] =
11164 {
11165 FileMenu,
11166 EditMenu,
11167 TransformMenu,
11168 EnhanceMenu,
11169 EffectsMenu,
11170 FXMenu,
11171 MiscellanyMenu
11172 };
11173
11174 static const CommandType
11175 ApplyCommands[] =
11176 {
11177 NullCommand,
11178 NullCommand,
11179 NullCommand,
11180 NullCommand,
11181 NullCommand,
11182 NullCommand,
11183 NullCommand,
11184 HelpCommand,
11185 QuitCommand
11186 },
11187 FileCommands[] =
11188 {
11189 SaveCommand,
11190 PrintCommand
11191 },
11192 EditCommands[] =
11193 {
11194 UndoCommand,
11195 RedoCommand
11196 },
11197 TransformCommands[] =
11198 {
11199 FlopCommand,
11200 FlipCommand,
11201 RotateRightCommand,
11202 RotateLeftCommand
11203 },
11204 EnhanceCommands[] =
11205 {
11206 HueCommand,
11207 SaturationCommand,
11208 BrightnessCommand,
11209 GammaCommand,
11210 SpiffCommand,
11211 DullCommand,
11212 ContrastStretchCommand,
11213 SigmoidalContrastCommand,
11214 NormalizeCommand,
11215 EqualizeCommand,
11216 NegateCommand,
11217 GrayscaleCommand,
11218 MapCommand,
11219 QuantizeCommand
11220 },
11221 EffectsCommands[] =
11222 {
11223 DespeckleCommand,
11224 EmbossCommand,
11225 ReduceNoiseCommand,
11226 AddNoiseCommand,
11227 SharpenCommand,
11228 BlurCommand,
11229 EdgeDetectCommand,
11230 SpreadCommand,
11231 ShadeCommand,
11232 RaiseCommand,
11233 SegmentCommand
11234 },
11235 FXCommands[] =
11236 {
11237 SolarizeCommand,
11238 SepiaToneCommand,
11239 SwirlCommand,
11240 ImplodeCommand,
11241 VignetteCommand,
11242 WaveCommand,
11243 OilPaintCommand,
11244 CharcoalDrawCommand
11245 },
11246 MiscellanyCommands[] =
11247 {
11248 InfoCommand,
11249 ZoomCommand,
11250 ShowPreviewCommand,
11251 ShowHistogramCommand,
11252 ShowMatteCommand
11253 },
11254 ROICommands[] =
11255 {
11256 ROIHelpCommand,
11257 ROIDismissCommand
11258 };
11259
11260 static const CommandType
11261 *Commands[ApplyMenus] =
11262 {
11263 FileCommands,
11264 EditCommands,
11265 TransformCommands,
11266 EnhanceCommands,
11267 EffectsCommands,
11268 FXCommands,
11269 MiscellanyCommands
11270 };
11271
11272 char
11273 command[MagickPathExtent],
11274 text[MagickPathExtent];
11275
11276 CommandType
11277 command_type;
11278
11279 Cursor
11280 cursor;
11281
11282 Image
11283 *roi_image;
11284
11285 int
11286 entry,
11287 id,
11288 x,
11289 y;
11290
11291 double
11292 scale_factor;
11293
11294 MagickProgressMonitor
11295 progress_monitor;
11296
11297 RectangleInfo
11298 crop_info,
11299 highlight_info,
11300 roi_info;
11301
11302 unsigned int
11303 height,
11304 width;
11305
11306 size_t
11307 state;
11308
11309 XEvent
11310 event;
11311
11312 /*
11313 Map Command widget.
11314 */
11315 (void) CloneString(&windows->command.name,"ROI");
11316 windows->command.data=0;
11317 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11318 (void) XMapRaised(display,windows->command.id);
11319 XClientMessage(display,windows->image.id,windows->im_protocols,
11320 windows->im_update_widget,CurrentTime);
11321 /*
11322 Track pointer until button 1 is pressed.
11323 */
11324 XQueryPosition(display,windows->image.id,&x,&y);
11325 (void) XSelectInput(display,windows->image.id,
11326 windows->image.attributes.event_mask | PointerMotionMask);
11327 roi_info.x=(ssize_t) windows->image.x+x;
11328 roi_info.y=(ssize_t) windows->image.y+y;
11329 roi_info.width=0;
11330 roi_info.height=0;
11331 cursor=XCreateFontCursor(display,XC_fleur);
11332 state=DefaultState;
11333 do
11334 {
11335 if (windows->info.mapped != MagickFalse )
11336 {
11337 /*
11338 Display pointer position.
11339 */
11340 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
11341 (long) roi_info.x,(long) roi_info.y);
11342 XInfoWidget(display,windows,text);
11343 }
11344 /*
11345 Wait for next event.
11346 */
11347 XScreenEvent(display,windows,&event,exception);
11348 if (event.xany.window == windows->command.id)
11349 {
11350 /*
11351 Select a command from the Command widget.
11352 */
11353 id=XCommandWidget(display,windows,ROIMenu,&event);
11354 if (id < 0)
11355 continue;
11356 switch (ROICommands[id])
11357 {
11358 case ROIHelpCommand:
11359 {
11360 XTextViewHelp(display,resource_info,windows,MagickFalse,
11361 "Help Viewer - Region of Interest",ImageROIHelp);
11362 break;
11363 }
11364 case ROIDismissCommand:
11365 {
11366 /*
11367 Prematurely exit.
11368 */
11369 state|=EscapeState;
11370 state|=ExitState;
11371 break;
11372 }
11373 default:
11374 break;
11375 }
11376 continue;
11377 }
11378 switch (event.type)
11379 {
11380 case ButtonPress:
11381 {
11382 if (event.xbutton.button != Button1)
11383 break;
11384 if (event.xbutton.window != windows->image.id)
11385 break;
11386 /*
11387 Note first corner of region of interest rectangle-- exit loop.
11388 */
11389 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11390 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11391 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11392 state|=ExitState;
11393 break;
11394 }
11395 case ButtonRelease:
11396 break;
11397 case Expose:
11398 break;
11399 case KeyPress:
11400 {
11401 KeySym
11402 key_symbol;
11403
11404 if (event.xkey.window != windows->image.id)
11405 break;
11406 /*
11407 Respond to a user key press.
11408 */
11409 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11410 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11411 switch ((int) key_symbol)
11412 {
11413 case XK_Escape:
11414 case XK_F20:
11415 {
11416 /*
11417 Prematurely exit.
11418 */
11419 state|=EscapeState;
11420 state|=ExitState;
11421 break;
11422 }
11423 case XK_F1:
11424 case XK_Help:
11425 {
11426 XTextViewHelp(display,resource_info,windows,MagickFalse,
11427 "Help Viewer - Region of Interest",ImageROIHelp);
11428 break;
11429 }
11430 default:
11431 {
11432 (void) XBell(display,0);
11433 break;
11434 }
11435 }
11436 break;
11437 }
11438 case MotionNotify:
11439 {
11440 /*
11441 Map and unmap Info widget as text cursor crosses its boundaries.
11442 */
11443 x=event.xmotion.x;
11444 y=event.xmotion.y;
11445 if (windows->info.mapped != MagickFalse )
11446 {
11447 if ((x < (int) (windows->info.x+windows->info.width)) &&
11448 (y < (int) (windows->info.y+windows->info.height)))
11449 (void) XWithdrawWindow(display,windows->info.id,
11450 windows->info.screen);
11451 }
11452 else
11453 if ((x > (int) (windows->info.x+windows->info.width)) ||
11454 (y > (int) (windows->info.y+windows->info.height)))
11455 (void) XMapWindow(display,windows->info.id);
11456 roi_info.x=(ssize_t) windows->image.x+x;
11457 roi_info.y=(ssize_t) windows->image.y+y;
11458 break;
11459 }
11460 default:
11461 break;
11462 }
11463 } while ((state & ExitState) == 0);
11464 (void) XSelectInput(display,windows->image.id,
11465 windows->image.attributes.event_mask);
11466 if ((state & EscapeState) != 0)
11467 {
11468 /*
11469 User want to exit without region of interest.
11470 */
11471 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11472 (void) XFreeCursor(display,cursor);
11473 return(MagickTrue);
11474 }
11475 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11476 do
11477 {
11478 /*
11479 Size rectangle as pointer moves until the mouse button is released.
11480 */
11481 x=(int) roi_info.x;
11482 y=(int) roi_info.y;
11483 roi_info.width=0;
11484 roi_info.height=0;
11485 state=DefaultState;
11486 do
11487 {
11488 highlight_info=roi_info;
11489 highlight_info.x=roi_info.x-windows->image.x;
11490 highlight_info.y=roi_info.y-windows->image.y;
11491 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11492 {
11493 /*
11494 Display info and draw region of interest rectangle.
11495 */
11496 if (windows->info.mapped == MagickFalse)
11497 (void) XMapWindow(display,windows->info.id);
11498 (void) FormatLocaleString(text,MagickPathExtent,
11499 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11500 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11501 XInfoWidget(display,windows,text);
11502 XHighlightRectangle(display,windows->image.id,
11503 windows->image.highlight_context,&highlight_info);
11504 }
11505 else
11506 if (windows->info.mapped != MagickFalse )
11507 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11508 /*
11509 Wait for next event.
11510 */
11511 XScreenEvent(display,windows,&event,exception);
11512 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11513 XHighlightRectangle(display,windows->image.id,
11514 windows->image.highlight_context,&highlight_info);
11515 switch (event.type)
11516 {
11517 case ButtonPress:
11518 {
11519 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11520 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11521 break;
11522 }
11523 case ButtonRelease:
11524 {
11525 /*
11526 User has committed to region of interest rectangle.
11527 */
11528 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11529 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11530 XSetCursorState(display,windows,MagickFalse);
11531 state|=ExitState;
11532 if (LocaleCompare(windows->command.name,"Apply") == 0)
11533 break;
11534 (void) CloneString(&windows->command.name,"Apply");
11535 windows->command.data=ApplyMenus;
11536 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11537 break;
11538 }
11539 case Expose:
11540 break;
11541 case MotionNotify:
11542 {
11543 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11544 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11545 }
11546 default:
11547 break;
11548 }
11549 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11550 ((state & ExitState) != 0))
11551 {
11552 /*
11553 Check boundary conditions.
11554 */
11555 if (roi_info.x < 0)
11556 roi_info.x=0;
11557 else
11558 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11559 roi_info.x=(ssize_t) windows->image.ximage->width;
11560 if ((int) roi_info.x < x)
11561 roi_info.width=(unsigned int) (x-roi_info.x);
11562 else
11563 {
11564 roi_info.width=(unsigned int) (roi_info.x-x);
11565 roi_info.x=(ssize_t) x;
11566 }
11567 if (roi_info.y < 0)
11568 roi_info.y=0;
11569 else
11570 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11571 roi_info.y=(ssize_t) windows->image.ximage->height;
11572 if ((int) roi_info.y < y)
11573 roi_info.height=(unsigned int) (y-roi_info.y);
11574 else
11575 {
11576 roi_info.height=(unsigned int) (roi_info.y-y);
11577 roi_info.y=(ssize_t) y;
11578 }
11579 }
11580 } while ((state & ExitState) == 0);
11581 /*
11582 Wait for user to grab a corner of the rectangle or press return.
11583 */
11584 state=DefaultState;
11585 command_type=NullCommand;
11586 crop_info.x=0;
11587 crop_info.y=0;
11588 (void) XMapWindow(display,windows->info.id);
11589 do
11590 {
11591 if (windows->info.mapped != MagickFalse )
11592 {
11593 /*
11594 Display pointer position.
11595 */
11596 (void) FormatLocaleString(text,MagickPathExtent,
11597 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11598 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11599 XInfoWidget(display,windows,text);
11600 }
11601 highlight_info=roi_info;
11602 highlight_info.x=roi_info.x-windows->image.x;
11603 highlight_info.y=roi_info.y-windows->image.y;
11604 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11605 {
11606 state|=EscapeState;
11607 state|=ExitState;
11608 break;
11609 }
11610 if ((state & UpdateRegionState) != 0)
11611 {
11612 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11613 switch (command_type)
11614 {
11615 case UndoCommand:
11616 case RedoCommand:
11617 {
11618 (void) XMagickCommand(display,resource_info,windows,command_type,
11619 image,exception);
11620 break;
11621 }
11622 default:
11623 {
11624 /*
11625 Region of interest is relative to image configuration.
11626 */
11627 progress_monitor=SetImageProgressMonitor(*image,
11628 (MagickProgressMonitor) NULL,(*image)->client_data);
11629 crop_info=roi_info;
11630 width=(unsigned int) (*image)->columns;
11631 height=(unsigned int) (*image)->rows;
11632 x=0;
11633 y=0;
11634 if (windows->image.crop_geometry != (char *) NULL)
11635 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11636 &width,&height);
11637 scale_factor=(double) width/windows->image.ximage->width;
11638 crop_info.x+=x;
11639 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11640 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11641 scale_factor=(double)
11642 height/windows->image.ximage->height;
11643 crop_info.y+=y;
11644 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11645 crop_info.height=(unsigned int)
11646 (scale_factor*crop_info.height+0.5);
11647 roi_image=CropImage(*image,&crop_info,exception);
11648 (void) SetImageProgressMonitor(*image,progress_monitor,
11649 (*image)->client_data);
11650 if (roi_image == (Image *) NULL)
11651 continue;
11652 /*
11653 Apply image processing technique to the region of interest.
11654 */
11655 windows->image.orphan=MagickTrue;
11656 (void) XMagickCommand(display,resource_info,windows,command_type,
11657 &roi_image,exception);
11658 progress_monitor=SetImageProgressMonitor(*image,
11659 (MagickProgressMonitor) NULL,(*image)->client_data);
11660 (void) XMagickCommand(display,resource_info,windows,
11661 SaveToUndoBufferCommand,image,exception);
11662 windows->image.orphan=MagickFalse;
11663 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
11664 MagickTrue,crop_info.x,crop_info.y,exception);
11665 roi_image=DestroyImage(roi_image);
11666 (void) SetImageProgressMonitor(*image,progress_monitor,
11667 (*image)->client_data);
11668 break;
11669 }
11670 }
11671 if (command_type != InfoCommand)
11672 {
11673 XConfigureImageColormap(display,resource_info,windows,*image,
11674 exception);
11675 (void) XConfigureImage(display,resource_info,windows,*image,
11676 exception);
11677 }
11678 XCheckRefreshWindows(display,windows);
11679 XInfoWidget(display,windows,text);
11680 (void) XSetFunction(display,windows->image.highlight_context,
11681 GXinvert);
11682 state&=(~UpdateRegionState);
11683 }
11684 XHighlightRectangle(display,windows->image.id,
11685 windows->image.highlight_context,&highlight_info);
11686 XScreenEvent(display,windows,&event,exception);
11687 if (event.xany.window == windows->command.id)
11688 {
11689 /*
11690 Select a command from the Command widget.
11691 */
11692 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11693 command_type=NullCommand;
11694 id=XCommandWidget(display,windows,ApplyMenu,&event);
11695 if (id >= 0)
11696 {
11697 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent);
11698 command_type=ApplyCommands[id];
11699 if (id < ApplyMenus)
11700 {
11701 /*
11702 Select a command from a pop-up menu.
11703 */
11704 entry=XMenuWidget(display,windows,ApplyMenu[id],
11705 (const char **) Menus[id],command);
11706 if (entry >= 0)
11707 {
11708 (void) CopyMagickString(command,Menus[id][entry],
11709 MagickPathExtent);
11710 command_type=Commands[id][entry];
11711 }
11712 }
11713 }
11714 (void) XSetFunction(display,windows->image.highlight_context,
11715 GXinvert);
11716 XHighlightRectangle(display,windows->image.id,
11717 windows->image.highlight_context,&highlight_info);
11718 if (command_type == HelpCommand)
11719 {
11720 (void) XSetFunction(display,windows->image.highlight_context,
11721 GXcopy);
11722 XTextViewHelp(display,resource_info,windows,MagickFalse,
11723 "Help Viewer - Region of Interest",ImageROIHelp);
11724 (void) XSetFunction(display,windows->image.highlight_context,
11725 GXinvert);
11726 continue;
11727 }
11728 if (command_type == QuitCommand)
11729 {
11730 /*
11731 exit.
11732 */
11733 state|=EscapeState;
11734 state|=ExitState;
11735 continue;
11736 }
11737 if (command_type != NullCommand)
11738 state|=UpdateRegionState;
11739 continue;
11740 }
11741 XHighlightRectangle(display,windows->image.id,
11742 windows->image.highlight_context,&highlight_info);
11743 switch (event.type)
11744 {
11745 case ButtonPress:
11746 {
11747 x=windows->image.x;
11748 y=windows->image.y;
11749 if (event.xbutton.button != Button1)
11750 break;
11751 if (event.xbutton.window != windows->image.id)
11752 break;
11753 x=windows->image.x+event.xbutton.x;
11754 y=windows->image.y+event.xbutton.y;
11755 if ((x < (int) (roi_info.x+RoiDelta)) &&
11756 (x > (int) (roi_info.x-RoiDelta)) &&
11757 (y < (int) (roi_info.y+RoiDelta)) &&
11758 (y > (int) (roi_info.y-RoiDelta)))
11759 {
11760 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11761 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11762 state|=UpdateConfigurationState;
11763 break;
11764 }
11765 if ((x < (int) (roi_info.x+RoiDelta)) &&
11766 (x > (int) (roi_info.x-RoiDelta)) &&
11767 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11768 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11769 {
11770 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11771 state|=UpdateConfigurationState;
11772 break;
11773 }
11774 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11775 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11776 (y < (int) (roi_info.y+RoiDelta)) &&
11777 (y > (int) (roi_info.y-RoiDelta)))
11778 {
11779 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11780 state|=UpdateConfigurationState;
11781 break;
11782 }
11783 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11784 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11785 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11786 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11787 {
11788 state|=UpdateConfigurationState;
11789 break;
11790 }
11791 }
11792 case ButtonRelease:
11793 {
11794 if (event.xbutton.window == windows->pan.id)
11795 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11796 (highlight_info.y != crop_info.y-windows->image.y))
11797 XHighlightRectangle(display,windows->image.id,
11798 windows->image.highlight_context,&highlight_info);
11799 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11800 event.xbutton.time);
11801 break;
11802 }
11803 case Expose:
11804 {
11805 if (event.xexpose.window == windows->image.id)
11806 if (event.xexpose.count == 0)
11807 {
11808 event.xexpose.x=(int) highlight_info.x;
11809 event.xexpose.y=(int) highlight_info.y;
11810 event.xexpose.width=(int) highlight_info.width;
11811 event.xexpose.height=(int) highlight_info.height;
11812 XRefreshWindow(display,&windows->image,&event);
11813 }
11814 if (event.xexpose.window == windows->info.id)
11815 if (event.xexpose.count == 0)
11816 XInfoWidget(display,windows,text);
11817 break;
11818 }
11819 case KeyPress:
11820 {
11821 KeySym
11822 key_symbol;
11823
11824 if (event.xkey.window != windows->image.id)
11825 break;
11826 /*
11827 Respond to a user key press.
11828 */
11829 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11830 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11831 switch ((int) key_symbol)
11832 {
11833 case XK_Shift_L:
11834 case XK_Shift_R:
11835 break;
11836 case XK_Escape:
11837 case XK_F20:
11838 state|=EscapeState;
11839 case XK_Return:
11840 {
11841 state|=ExitState;
11842 break;
11843 }
11844 case XK_Home:
11845 case XK_KP_Home:
11846 {
11847 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11848 roi_info.y=(ssize_t) (windows->image.height/2L-
11849 roi_info.height/2L);
11850 break;
11851 }
11852 case XK_Left:
11853 case XK_KP_Left:
11854 {
11855 roi_info.x--;
11856 break;
11857 }
11858 case XK_Up:
11859 case XK_KP_Up:
11860 case XK_Next:
11861 {
11862 roi_info.y--;
11863 break;
11864 }
11865 case XK_Right:
11866 case XK_KP_Right:
11867 {
11868 roi_info.x++;
11869 break;
11870 }
11871 case XK_Prior:
11872 case XK_Down:
11873 case XK_KP_Down:
11874 {
11875 roi_info.y++;
11876 break;
11877 }
11878 case XK_F1:
11879 case XK_Help:
11880 {
11881 (void) XSetFunction(display,windows->image.highlight_context,
11882 GXcopy);
11883 XTextViewHelp(display,resource_info,windows,MagickFalse,
11884 "Help Viewer - Region of Interest",ImageROIHelp);
11885 (void) XSetFunction(display,windows->image.highlight_context,
11886 GXinvert);
11887 break;
11888 }
11889 default:
11890 {
11891 command_type=XImageWindowCommand(display,resource_info,windows,
11892 event.xkey.state,key_symbol,image,exception);
11893 if (command_type != NullCommand)
11894 state|=UpdateRegionState;
11895 break;
11896 }
11897 }
11898 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11899 event.xkey.time);
11900 break;
11901 }
11902 case KeyRelease:
11903 break;
11904 case MotionNotify:
11905 {
11906 if (event.xbutton.window != windows->image.id)
11907 break;
11908 /*
11909 Map and unmap Info widget as text cursor crosses its boundaries.
11910 */
11911 x=event.xmotion.x;
11912 y=event.xmotion.y;
11913 if (windows->info.mapped != MagickFalse )
11914 {
11915 if ((x < (int) (windows->info.x+windows->info.width)) &&
11916 (y < (int) (windows->info.y+windows->info.height)))
11917 (void) XWithdrawWindow(display,windows->info.id,
11918 windows->info.screen);
11919 }
11920 else
11921 if ((x > (int) (windows->info.x+windows->info.width)) ||
11922 (y > (int) (windows->info.y+windows->info.height)))
11923 (void) XMapWindow(display,windows->info.id);
11924 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11925 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11926 break;
11927 }
11928 case SelectionRequest:
11929 {
11930 XSelectionEvent
11931 notify;
11932
11933 XSelectionRequestEvent
11934 *request;
11935
11936 /*
11937 Set primary selection.
11938 */
11939 (void) FormatLocaleString(text,MagickPathExtent,
11940 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11941 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11942 request=(&(event.xselectionrequest));
11943 (void) XChangeProperty(request->display,request->requestor,
11944 request->property,request->target,8,PropModeReplace,
11945 (unsigned char *) text,(int) strlen(text));
11946 notify.type=SelectionNotify;
11947 notify.display=request->display;
11948 notify.requestor=request->requestor;
11949 notify.selection=request->selection;
11950 notify.target=request->target;
11951 notify.time=request->time;
11952 if (request->property == None)
11953 notify.property=request->target;
11954 else
11955 notify.property=request->property;
11956 (void) XSendEvent(request->display,request->requestor,False,0,
11957 (XEvent *) ¬ify);
11958 }
11959 default:
11960 break;
11961 }
11962 if ((state & UpdateConfigurationState) != 0)
11963 {
11964 (void) XPutBackEvent(display,&event);
11965 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11966 break;
11967 }
11968 } while ((state & ExitState) == 0);
11969 } while ((state & ExitState) == 0);
11970 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11971 XSetCursorState(display,windows,MagickFalse);
11972 if ((state & EscapeState) != 0)
11973 return(MagickTrue);
11974 return(MagickTrue);
11975 }
11976
11977 /*
11978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11979 % %
11980 % %
11981 % %
11982 + X R o t a t e I m a g e %
11983 % %
11984 % %
11985 % %
11986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11987 %
11988 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11989 % rotation angle is computed from the slope of a line drawn by the user.
11990 %
11991 % The format of the XRotateImage method is:
11992 %
11993 % MagickBooleanType XRotateImage(Display *display,
11994 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11995 % Image **image,ExceptionInfo *exception)
11996 %
11997 % A description of each parameter follows:
11998 %
11999 % o display: Specifies a connection to an X server; returned from
12000 % XOpenDisplay.
12001 %
12002 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12003 %
12004 % o windows: Specifies a pointer to a XWindows structure.
12005 %
12006 % o degrees: Specifies the number of degrees to rotate the image.
12007 %
12008 % o image: the image.
12009 %
12010 % o exception: return any errors or warnings in this structure.
12011 %
12012 */
XRotateImage(Display * display,XResourceInfo * resource_info,XWindows * windows,double degrees,Image ** image,ExceptionInfo * exception)12013 static MagickBooleanType XRotateImage(Display *display,
12014 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12015 ExceptionInfo *exception)
12016 {
12017 const char
12018 *const RotateMenu[] =
12019 {
12020 "Pixel Color",
12021 "Direction",
12022 "Help",
12023 "Dismiss",
12024 (char *) NULL
12025 };
12026
12027 static ModeType
12028 direction = HorizontalRotateCommand;
12029
12030 static const ModeType
12031 DirectionCommands[] =
12032 {
12033 HorizontalRotateCommand,
12034 VerticalRotateCommand
12035 },
12036 RotateCommands[] =
12037 {
12038 RotateColorCommand,
12039 RotateDirectionCommand,
12040 RotateHelpCommand,
12041 RotateDismissCommand
12042 };
12043
12044 static unsigned int
12045 pen_id = 0;
12046
12047 char
12048 command[MagickPathExtent],
12049 text[MagickPathExtent];
12050
12051 Image
12052 *rotate_image;
12053
12054 int
12055 id,
12056 x,
12057 y;
12058
12059 double
12060 normalized_degrees;
12061
12062 register int
12063 i;
12064
12065 unsigned int
12066 height,
12067 rotations,
12068 width;
12069
12070 if (degrees == 0.0)
12071 {
12072 unsigned int
12073 distance;
12074
12075 size_t
12076 state;
12077
12078 XEvent
12079 event;
12080
12081 XSegment
12082 rotate_info;
12083
12084 /*
12085 Map Command widget.
12086 */
12087 (void) CloneString(&windows->command.name,"Rotate");
12088 windows->command.data=2;
12089 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12090 (void) XMapRaised(display,windows->command.id);
12091 XClientMessage(display,windows->image.id,windows->im_protocols,
12092 windows->im_update_widget,CurrentTime);
12093 /*
12094 Wait for first button press.
12095 */
12096 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12097 XQueryPosition(display,windows->image.id,&x,&y);
12098 rotate_info.x1=x;
12099 rotate_info.y1=y;
12100 rotate_info.x2=x;
12101 rotate_info.y2=y;
12102 state=DefaultState;
12103 do
12104 {
12105 XHighlightLine(display,windows->image.id,
12106 windows->image.highlight_context,&rotate_info);
12107 /*
12108 Wait for next event.
12109 */
12110 XScreenEvent(display,windows,&event,exception);
12111 XHighlightLine(display,windows->image.id,
12112 windows->image.highlight_context,&rotate_info);
12113 if (event.xany.window == windows->command.id)
12114 {
12115 /*
12116 Select a command from the Command widget.
12117 */
12118 id=XCommandWidget(display,windows,RotateMenu,&event);
12119 if (id < 0)
12120 continue;
12121 (void) XSetFunction(display,windows->image.highlight_context,
12122 GXcopy);
12123 switch (RotateCommands[id])
12124 {
12125 case RotateColorCommand:
12126 {
12127 const char
12128 *ColorMenu[MaxNumberPens];
12129
12130 int
12131 pen_number;
12132
12133 XColor
12134 color;
12135
12136 /*
12137 Initialize menu selections.
12138 */
12139 for (i=0; i < (int) (MaxNumberPens-2); i++)
12140 ColorMenu[i]=resource_info->pen_colors[i];
12141 ColorMenu[MaxNumberPens-2]="Browser...";
12142 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12143 /*
12144 Select a pen color from the pop-up menu.
12145 */
12146 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12147 (const char **) ColorMenu,command);
12148 if (pen_number < 0)
12149 break;
12150 if (pen_number == (MaxNumberPens-2))
12151 {
12152 static char
12153 color_name[MagickPathExtent] = "gray";
12154
12155 /*
12156 Select a pen color from a dialog.
12157 */
12158 resource_info->pen_colors[pen_number]=color_name;
12159 XColorBrowserWidget(display,windows,"Select",color_name);
12160 if (*color_name == '\0')
12161 break;
12162 }
12163 /*
12164 Set pen color.
12165 */
12166 (void) XParseColor(display,windows->map_info->colormap,
12167 resource_info->pen_colors[pen_number],&color);
12168 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12169 (unsigned int) MaxColors,&color);
12170 windows->pixel_info->pen_colors[pen_number]=color;
12171 pen_id=(unsigned int) pen_number;
12172 break;
12173 }
12174 case RotateDirectionCommand:
12175 {
12176 const char
12177 *Directions[] =
12178 {
12179 "horizontal",
12180 "vertical",
12181 (char *) NULL,
12182 };
12183
12184 /*
12185 Select a command from the pop-up menu.
12186 */
12187 id=XMenuWidget(display,windows,RotateMenu[id],
12188 Directions,command);
12189 if (id >= 0)
12190 direction=DirectionCommands[id];
12191 break;
12192 }
12193 case RotateHelpCommand:
12194 {
12195 XTextViewHelp(display,resource_info,windows,MagickFalse,
12196 "Help Viewer - Image Rotation",ImageRotateHelp);
12197 break;
12198 }
12199 case RotateDismissCommand:
12200 {
12201 /*
12202 Prematurely exit.
12203 */
12204 state|=EscapeState;
12205 state|=ExitState;
12206 break;
12207 }
12208 default:
12209 break;
12210 }
12211 (void) XSetFunction(display,windows->image.highlight_context,
12212 GXinvert);
12213 continue;
12214 }
12215 switch (event.type)
12216 {
12217 case ButtonPress:
12218 {
12219 if (event.xbutton.button != Button1)
12220 break;
12221 if (event.xbutton.window != windows->image.id)
12222 break;
12223 /*
12224 exit loop.
12225 */
12226 (void) XSetFunction(display,windows->image.highlight_context,
12227 GXcopy);
12228 rotate_info.x1=event.xbutton.x;
12229 rotate_info.y1=event.xbutton.y;
12230 state|=ExitState;
12231 break;
12232 }
12233 case ButtonRelease:
12234 break;
12235 case Expose:
12236 break;
12237 case KeyPress:
12238 {
12239 char
12240 command[MagickPathExtent];
12241
12242 KeySym
12243 key_symbol;
12244
12245 if (event.xkey.window != windows->image.id)
12246 break;
12247 /*
12248 Respond to a user key press.
12249 */
12250 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12251 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12252 switch ((int) key_symbol)
12253 {
12254 case XK_Escape:
12255 case XK_F20:
12256 {
12257 /*
12258 Prematurely exit.
12259 */
12260 state|=EscapeState;
12261 state|=ExitState;
12262 break;
12263 }
12264 case XK_F1:
12265 case XK_Help:
12266 {
12267 (void) XSetFunction(display,windows->image.highlight_context,
12268 GXcopy);
12269 XTextViewHelp(display,resource_info,windows,MagickFalse,
12270 "Help Viewer - Image Rotation",ImageRotateHelp);
12271 (void) XSetFunction(display,windows->image.highlight_context,
12272 GXinvert);
12273 break;
12274 }
12275 default:
12276 {
12277 (void) XBell(display,0);
12278 break;
12279 }
12280 }
12281 break;
12282 }
12283 case MotionNotify:
12284 {
12285 rotate_info.x1=event.xmotion.x;
12286 rotate_info.y1=event.xmotion.y;
12287 }
12288 }
12289 rotate_info.x2=rotate_info.x1;
12290 rotate_info.y2=rotate_info.y1;
12291 if (direction == HorizontalRotateCommand)
12292 rotate_info.x2+=32;
12293 else
12294 rotate_info.y2-=32;
12295 } while ((state & ExitState) == 0);
12296 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12297 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12298 if ((state & EscapeState) != 0)
12299 return(MagickTrue);
12300 /*
12301 Draw line as pointer moves until the mouse button is released.
12302 */
12303 distance=0;
12304 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12305 state=DefaultState;
12306 do
12307 {
12308 if (distance > 9)
12309 {
12310 /*
12311 Display info and draw rotation line.
12312 */
12313 if (windows->info.mapped == MagickFalse)
12314 (void) XMapWindow(display,windows->info.id);
12315 (void) FormatLocaleString(text,MagickPathExtent," %g",
12316 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12317 XInfoWidget(display,windows,text);
12318 XHighlightLine(display,windows->image.id,
12319 windows->image.highlight_context,&rotate_info);
12320 }
12321 else
12322 if (windows->info.mapped != MagickFalse )
12323 (void) XWithdrawWindow(display,windows->info.id,
12324 windows->info.screen);
12325 /*
12326 Wait for next event.
12327 */
12328 XScreenEvent(display,windows,&event,exception);
12329 if (distance > 9)
12330 XHighlightLine(display,windows->image.id,
12331 windows->image.highlight_context,&rotate_info);
12332 switch (event.type)
12333 {
12334 case ButtonPress:
12335 break;
12336 case ButtonRelease:
12337 {
12338 /*
12339 User has committed to rotation line.
12340 */
12341 rotate_info.x2=event.xbutton.x;
12342 rotate_info.y2=event.xbutton.y;
12343 state|=ExitState;
12344 break;
12345 }
12346 case Expose:
12347 break;
12348 case MotionNotify:
12349 {
12350 rotate_info.x2=event.xmotion.x;
12351 rotate_info.y2=event.xmotion.y;
12352 }
12353 default:
12354 break;
12355 }
12356 /*
12357 Check boundary conditions.
12358 */
12359 if (rotate_info.x2 < 0)
12360 rotate_info.x2=0;
12361 else
12362 if (rotate_info.x2 > (int) windows->image.width)
12363 rotate_info.x2=(short) windows->image.width;
12364 if (rotate_info.y2 < 0)
12365 rotate_info.y2=0;
12366 else
12367 if (rotate_info.y2 > (int) windows->image.height)
12368 rotate_info.y2=(short) windows->image.height;
12369 /*
12370 Compute rotation angle from the slope of the line.
12371 */
12372 degrees=0.0;
12373 distance=(unsigned int)
12374 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12375 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12376 if (distance > 9)
12377 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12378 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12379 } while ((state & ExitState) == 0);
12380 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12381 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12382 if (distance <= 9)
12383 return(MagickTrue);
12384 }
12385 if (direction == VerticalRotateCommand)
12386 degrees-=90.0;
12387 if (degrees == 0.0)
12388 return(MagickTrue);
12389 /*
12390 Rotate image.
12391 */
12392 normalized_degrees=degrees;
12393 while (normalized_degrees < -45.0)
12394 normalized_degrees+=360.0;
12395 for (rotations=0; normalized_degrees > 45.0; rotations++)
12396 normalized_degrees-=90.0;
12397 if (normalized_degrees != 0.0)
12398 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12399 exception);
12400 XSetCursorState(display,windows,MagickTrue);
12401 XCheckRefreshWindows(display,windows);
12402 (*image)->background_color.red=(double) ScaleShortToQuantum(
12403 windows->pixel_info->pen_colors[pen_id].red);
12404 (*image)->background_color.green=(double) ScaleShortToQuantum(
12405 windows->pixel_info->pen_colors[pen_id].green);
12406 (*image)->background_color.blue=(double) ScaleShortToQuantum(
12407 windows->pixel_info->pen_colors[pen_id].blue);
12408 rotate_image=RotateImage(*image,degrees,exception);
12409 XSetCursorState(display,windows,MagickFalse);
12410 if (rotate_image == (Image *) NULL)
12411 return(MagickFalse);
12412 *image=DestroyImage(*image);
12413 *image=rotate_image;
12414 if (windows->image.crop_geometry != (char *) NULL)
12415 {
12416 /*
12417 Rotate crop geometry.
12418 */
12419 width=(unsigned int) (*image)->columns;
12420 height=(unsigned int) (*image)->rows;
12421 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12422 switch (rotations % 4)
12423 {
12424 default:
12425 case 0:
12426 break;
12427 case 1:
12428 {
12429 /*
12430 Rotate 90 degrees.
12431 */
12432 (void) FormatLocaleString(windows->image.crop_geometry,
12433 MagickPathExtent,"%ux%u%+d%+d",height,width,(int) (*image)->columns-
12434 (int) height-y,x);
12435 break;
12436 }
12437 case 2:
12438 {
12439 /*
12440 Rotate 180 degrees.
12441 */
12442 (void) FormatLocaleString(windows->image.crop_geometry,
12443 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) width-x,(int)
12444 height-y);
12445 break;
12446 }
12447 case 3:
12448 {
12449 /*
12450 Rotate 270 degrees.
12451 */
12452 (void) FormatLocaleString(windows->image.crop_geometry,
12453 MagickPathExtent,"%ux%u%+d%+d",height,width,y,(int) (*image)->rows-
12454 (int) width-x);
12455 break;
12456 }
12457 }
12458 }
12459 if (windows->image.orphan != MagickFalse )
12460 return(MagickTrue);
12461 if (normalized_degrees != 0.0)
12462 {
12463 /*
12464 Update image colormap.
12465 */
12466 windows->image.window_changes.width=(int) (*image)->columns;
12467 windows->image.window_changes.height=(int) (*image)->rows;
12468 if (windows->image.crop_geometry != (char *) NULL)
12469 {
12470 /*
12471 Obtain dimensions of image from crop geometry.
12472 */
12473 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12474 &width,&height);
12475 windows->image.window_changes.width=(int) width;
12476 windows->image.window_changes.height=(int) height;
12477 }
12478 XConfigureImageColormap(display,resource_info,windows,*image,exception);
12479 }
12480 else
12481 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12482 {
12483 windows->image.window_changes.width=windows->image.ximage->height;
12484 windows->image.window_changes.height=windows->image.ximage->width;
12485 }
12486 /*
12487 Update image configuration.
12488 */
12489 (void) XConfigureImage(display,resource_info,windows,*image,exception);
12490 return(MagickTrue);
12491 }
12492
12493 /*
12494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12495 % %
12496 % %
12497 % %
12498 + X S a v e I m a g e %
12499 % %
12500 % %
12501 % %
12502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12503 %
12504 % XSaveImage() saves an image to a file.
12505 %
12506 % The format of the XSaveImage method is:
12507 %
12508 % MagickBooleanType XSaveImage(Display *display,
12509 % XResourceInfo *resource_info,XWindows *windows,Image *image,
12510 % ExceptionInfo *exception)
12511 %
12512 % A description of each parameter follows:
12513 %
12514 % o display: Specifies a connection to an X server; returned from
12515 % XOpenDisplay.
12516 %
12517 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12518 %
12519 % o windows: Specifies a pointer to a XWindows structure.
12520 %
12521 % o image: the image.
12522 %
12523 % o exception: return any errors or warnings in this structure.
12524 %
12525 */
XSaveImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)12526 static MagickBooleanType XSaveImage(Display *display,
12527 XResourceInfo *resource_info,XWindows *windows,Image *image,
12528 ExceptionInfo *exception)
12529 {
12530 char
12531 filename[MagickPathExtent],
12532 geometry[MagickPathExtent];
12533
12534 Image
12535 *save_image;
12536
12537 ImageInfo
12538 *image_info;
12539
12540 MagickStatusType
12541 status;
12542
12543 /*
12544 Request file name from user.
12545 */
12546 if (resource_info->write_filename != (char *) NULL)
12547 (void) CopyMagickString(filename,resource_info->write_filename,
12548 MagickPathExtent);
12549 else
12550 {
12551 char
12552 path[MagickPathExtent];
12553
12554 int
12555 status;
12556
12557 GetPathComponent(image->filename,HeadPath,path);
12558 GetPathComponent(image->filename,TailPath,filename);
12559 if (*path != '\0')
12560 {
12561 status=chdir(path);
12562 if (status == -1)
12563 (void) ThrowMagickException(exception,GetMagickModule(),
12564 FileOpenError,"UnableToOpenFile","%s",path);
12565 }
12566 }
12567 XFileBrowserWidget(display,windows,"Save",filename);
12568 if (*filename == '\0')
12569 return(MagickTrue);
12570 if (IsPathAccessible(filename) != MagickFalse )
12571 {
12572 int
12573 status;
12574
12575 /*
12576 File exists-- seek user's permission before overwriting.
12577 */
12578 status=XConfirmWidget(display,windows,"Overwrite",filename);
12579 if (status <= 0)
12580 return(MagickTrue);
12581 }
12582 image_info=CloneImageInfo(resource_info->image_info);
12583 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
12584 (void) SetImageInfo(image_info,1,exception);
12585 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12586 (LocaleCompare(image_info->magick,"JPG") == 0))
12587 {
12588 char
12589 quality[MagickPathExtent];
12590
12591 int
12592 status;
12593
12594 /*
12595 Request JPEG quality from user.
12596 */
12597 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
12598 image->quality);
12599 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12600 quality);
12601 if (*quality == '\0')
12602 return(MagickTrue);
12603 image->quality=StringToUnsignedLong(quality);
12604 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12605 }
12606 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12607 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12608 (LocaleCompare(image_info->magick,"PS") == 0) ||
12609 (LocaleCompare(image_info->magick,"PS2") == 0))
12610 {
12611 char
12612 geometry[MagickPathExtent];
12613
12614 const char
12615 *const PageSizes[] =
12616 {
12617 "Letter",
12618 "Tabloid",
12619 "Ledger",
12620 "Legal",
12621 "Statement",
12622 "Executive",
12623 "A3",
12624 "A4",
12625 "A5",
12626 "B4",
12627 "B5",
12628 "Folio",
12629 "Quarto",
12630 "10x14",
12631 (char *) NULL
12632 };
12633
12634 /*
12635 Request page geometry from user.
12636 */
12637 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12638 if (LocaleCompare(image_info->magick,"PDF") == 0)
12639 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12640 if (image_info->page != (char *) NULL)
12641 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
12642 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12643 "Select page geometry:",geometry);
12644 if (*geometry != '\0')
12645 image_info->page=GetPageGeometry(geometry);
12646 }
12647 /*
12648 Apply image transforms.
12649 */
12650 XSetCursorState(display,windows,MagickTrue);
12651 XCheckRefreshWindows(display,windows);
12652 save_image=CloneImage(image,0,0,MagickTrue,exception);
12653 if (save_image == (Image *) NULL)
12654 return(MagickFalse);
12655 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
12656 windows->image.ximage->width,windows->image.ximage->height);
12657 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12658 exception);
12659 /*
12660 Write image.
12661 */
12662 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent);
12663 status=WriteImage(image_info,save_image,exception);
12664 if (status != MagickFalse )
12665 image->taint=MagickFalse;
12666 save_image=DestroyImage(save_image);
12667 image_info=DestroyImageInfo(image_info);
12668 XSetCursorState(display,windows,MagickFalse);
12669 return(status != 0 ? MagickTrue : MagickFalse);
12670 }
12671
12672 /*
12673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12674 % %
12675 % %
12676 % %
12677 + X S c r e e n E v e n t %
12678 % %
12679 % %
12680 % %
12681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12682 %
12683 % XScreenEvent() handles global events associated with the Pan and Magnify
12684 % windows.
12685 %
12686 % The format of the XScreenEvent function is:
12687 %
12688 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12689 % ExceptionInfo *exception)
12690 %
12691 % A description of each parameter follows:
12692 %
12693 % o display: Specifies a pointer to the Display structure; returned from
12694 % XOpenDisplay.
12695 %
12696 % o windows: Specifies a pointer to a XWindows structure.
12697 %
12698 % o event: Specifies a pointer to a X11 XEvent structure.
12699 %
12700 % o exception: return any errors or warnings in this structure.
12701 %
12702 */
12703
12704 #if defined(__cplusplus) || defined(c_plusplus)
12705 extern "C" {
12706 #endif
12707
XPredicate(Display * magick_unused (display),XEvent * event,char * data)12708 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12709 {
12710 register XWindows
12711 *windows;
12712
12713 windows=(XWindows *) data;
12714 if ((event->type == ClientMessage) &&
12715 (event->xclient.window == windows->image.id))
12716 return(MagickFalse);
12717 return(MagickTrue);
12718 }
12719
12720 #if defined(__cplusplus) || defined(c_plusplus)
12721 }
12722 #endif
12723
XScreenEvent(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)12724 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12725 ExceptionInfo *exception)
12726 {
12727 register int
12728 x,
12729 y;
12730
12731 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12732 if (event->xany.window == windows->command.id)
12733 return;
12734 switch (event->type)
12735 {
12736 case ButtonPress:
12737 case ButtonRelease:
12738 {
12739 if ((event->xbutton.button == Button3) &&
12740 (event->xbutton.state & Mod1Mask))
12741 {
12742 /*
12743 Convert Alt-Button3 to Button2.
12744 */
12745 event->xbutton.button=Button2;
12746 event->xbutton.state&=(~Mod1Mask);
12747 }
12748 if (event->xbutton.window == windows->backdrop.id)
12749 {
12750 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12751 event->xbutton.time);
12752 break;
12753 }
12754 if (event->xbutton.window == windows->pan.id)
12755 {
12756 XPanImage(display,windows,event,exception);
12757 break;
12758 }
12759 if (event->xbutton.window == windows->image.id)
12760 if (event->xbutton.button == Button2)
12761 {
12762 /*
12763 Update magnified image.
12764 */
12765 x=event->xbutton.x;
12766 y=event->xbutton.y;
12767 if (x < 0)
12768 x=0;
12769 else
12770 if (x >= (int) windows->image.width)
12771 x=(int) (windows->image.width-1);
12772 windows->magnify.x=(int) windows->image.x+x;
12773 if (y < 0)
12774 y=0;
12775 else
12776 if (y >= (int) windows->image.height)
12777 y=(int) (windows->image.height-1);
12778 windows->magnify.y=windows->image.y+y;
12779 if (windows->magnify.mapped == MagickFalse)
12780 (void) XMapRaised(display,windows->magnify.id);
12781 XMakeMagnifyImage(display,windows,exception);
12782 if (event->type == ButtonRelease)
12783 (void) XWithdrawWindow(display,windows->info.id,
12784 windows->info.screen);
12785 break;
12786 }
12787 break;
12788 }
12789 case ClientMessage:
12790 {
12791 /*
12792 If client window delete message, exit.
12793 */
12794 if (event->xclient.message_type != windows->wm_protocols)
12795 break;
12796 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12797 break;
12798 if (event->xclient.window == windows->magnify.id)
12799 {
12800 (void) XWithdrawWindow(display,windows->magnify.id,
12801 windows->magnify.screen);
12802 break;
12803 }
12804 break;
12805 }
12806 case ConfigureNotify:
12807 {
12808 if (event->xconfigure.window == windows->magnify.id)
12809 {
12810 unsigned int
12811 magnify;
12812
12813 /*
12814 Magnify window has a new configuration.
12815 */
12816 windows->magnify.width=(unsigned int) event->xconfigure.width;
12817 windows->magnify.height=(unsigned int) event->xconfigure.height;
12818 if (windows->magnify.mapped == MagickFalse)
12819 break;
12820 magnify=1;
12821 while ((int) magnify <= event->xconfigure.width)
12822 magnify<<=1;
12823 while ((int) magnify <= event->xconfigure.height)
12824 magnify<<=1;
12825 magnify>>=1;
12826 if (((int) magnify != event->xconfigure.width) ||
12827 ((int) magnify != event->xconfigure.height))
12828 {
12829 XWindowChanges
12830 window_changes;
12831
12832 window_changes.width=(int) magnify;
12833 window_changes.height=(int) magnify;
12834 (void) XReconfigureWMWindow(display,windows->magnify.id,
12835 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12836 &window_changes);
12837 break;
12838 }
12839 XMakeMagnifyImage(display,windows,exception);
12840 break;
12841 }
12842 break;
12843 }
12844 case Expose:
12845 {
12846 if (event->xexpose.window == windows->image.id)
12847 {
12848 XRefreshWindow(display,&windows->image,event);
12849 break;
12850 }
12851 if (event->xexpose.window == windows->pan.id)
12852 if (event->xexpose.count == 0)
12853 {
12854 XDrawPanRectangle(display,windows);
12855 break;
12856 }
12857 if (event->xexpose.window == windows->magnify.id)
12858 if (event->xexpose.count == 0)
12859 {
12860 XMakeMagnifyImage(display,windows,exception);
12861 break;
12862 }
12863 break;
12864 }
12865 case KeyPress:
12866 {
12867 char
12868 command[MagickPathExtent];
12869
12870 KeySym
12871 key_symbol;
12872
12873 if (event->xkey.window != windows->magnify.id)
12874 break;
12875 /*
12876 Respond to a user key press.
12877 */
12878 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12879 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12880 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12881 exception);
12882 break;
12883 }
12884 case MapNotify:
12885 {
12886 if (event->xmap.window == windows->magnify.id)
12887 {
12888 windows->magnify.mapped=MagickTrue;
12889 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12890 break;
12891 }
12892 if (event->xmap.window == windows->info.id)
12893 {
12894 windows->info.mapped=MagickTrue;
12895 break;
12896 }
12897 break;
12898 }
12899 case MotionNotify:
12900 {
12901 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12902 if (event->xmotion.window == windows->image.id)
12903 if (windows->magnify.mapped != MagickFalse )
12904 {
12905 /*
12906 Update magnified image.
12907 */
12908 x=event->xmotion.x;
12909 y=event->xmotion.y;
12910 if (x < 0)
12911 x=0;
12912 else
12913 if (x >= (int) windows->image.width)
12914 x=(int) (windows->image.width-1);
12915 windows->magnify.x=(int) windows->image.x+x;
12916 if (y < 0)
12917 y=0;
12918 else
12919 if (y >= (int) windows->image.height)
12920 y=(int) (windows->image.height-1);
12921 windows->magnify.y=windows->image.y+y;
12922 XMakeMagnifyImage(display,windows,exception);
12923 }
12924 break;
12925 }
12926 case UnmapNotify:
12927 {
12928 if (event->xunmap.window == windows->magnify.id)
12929 {
12930 windows->magnify.mapped=MagickFalse;
12931 break;
12932 }
12933 if (event->xunmap.window == windows->info.id)
12934 {
12935 windows->info.mapped=MagickFalse;
12936 break;
12937 }
12938 break;
12939 }
12940 default:
12941 break;
12942 }
12943 }
12944
12945 /*
12946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12947 % %
12948 % %
12949 % %
12950 + X S e t C r o p G e o m e t r y %
12951 % %
12952 % %
12953 % %
12954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12955 %
12956 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12957 % and translates it to a cropping geometry relative to the image.
12958 %
12959 % The format of the XSetCropGeometry method is:
12960 %
12961 % void XSetCropGeometry(Display *display,XWindows *windows,
12962 % RectangleInfo *crop_info,Image *image)
12963 %
12964 % A description of each parameter follows:
12965 %
12966 % o display: Specifies a connection to an X server; returned from
12967 % XOpenDisplay.
12968 %
12969 % o windows: Specifies a pointer to a XWindows structure.
12970 %
12971 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12972 % Image window to crop.
12973 %
12974 % o image: the image.
12975 %
12976 */
XSetCropGeometry(Display * display,XWindows * windows,RectangleInfo * crop_info,Image * image)12977 static void XSetCropGeometry(Display *display,XWindows *windows,
12978 RectangleInfo *crop_info,Image *image)
12979 {
12980 char
12981 text[MagickPathExtent];
12982
12983 int
12984 x,
12985 y;
12986
12987 double
12988 scale_factor;
12989
12990 unsigned int
12991 height,
12992 width;
12993
12994 if (windows->info.mapped != MagickFalse )
12995 {
12996 /*
12997 Display info on cropping rectangle.
12998 */
12999 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g",
13000 (double) crop_info->width,(double) crop_info->height,(double)
13001 crop_info->x,(double) crop_info->y);
13002 XInfoWidget(display,windows,text);
13003 }
13004 /*
13005 Cropping geometry is relative to any previous crop geometry.
13006 */
13007 x=0;
13008 y=0;
13009 width=(unsigned int) image->columns;
13010 height=(unsigned int) image->rows;
13011 if (windows->image.crop_geometry != (char *) NULL)
13012 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13013 else
13014 windows->image.crop_geometry=AcquireString((char *) NULL);
13015 /*
13016 Define the crop geometry string from the cropping rectangle.
13017 */
13018 scale_factor=(double) width/windows->image.ximage->width;
13019 if (crop_info->x > 0)
13020 x+=(int) (scale_factor*crop_info->x+0.5);
13021 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13022 if (width == 0)
13023 width=1;
13024 scale_factor=(double) height/windows->image.ximage->height;
13025 if (crop_info->y > 0)
13026 y+=(int) (scale_factor*crop_info->y+0.5);
13027 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13028 if (height == 0)
13029 height=1;
13030 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
13031 "%ux%u%+d%+d",width,height,x,y);
13032 }
13033
13034 /*
13035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13036 % %
13037 % %
13038 % %
13039 + X T i l e I m a g e %
13040 % %
13041 % %
13042 % %
13043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13044 %
13045 % XTileImage() loads or deletes a selected tile from a visual image directory.
13046 % The load or delete command is chosen from a menu.
13047 %
13048 % The format of the XTileImage method is:
13049 %
13050 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
13051 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13052 %
13053 % A description of each parameter follows:
13054 %
13055 % o tile_image: XTileImage reads or deletes the tile image
13056 % and returns it. A null image is returned if an error occurs.
13057 %
13058 % o display: Specifies a connection to an X server; returned from
13059 % XOpenDisplay.
13060 %
13061 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13062 %
13063 % o windows: Specifies a pointer to a XWindows structure.
13064 %
13065 % o image: the image; returned from ReadImage.
13066 %
13067 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
13068 % the entire image is refreshed.
13069 %
13070 % o exception: return any errors or warnings in this structure.
13071 %
13072 */
XTileImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,XEvent * event,ExceptionInfo * exception)13073 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
13074 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13075 {
13076 const char
13077 *const VerbMenu[] =
13078 {
13079 "Load",
13080 "Next",
13081 "Former",
13082 "Delete",
13083 "Update",
13084 (char *) NULL,
13085 };
13086
13087 static const ModeType
13088 TileCommands[] =
13089 {
13090 TileLoadCommand,
13091 TileNextCommand,
13092 TileFormerCommand,
13093 TileDeleteCommand,
13094 TileUpdateCommand
13095 };
13096
13097 char
13098 command[MagickPathExtent],
13099 filename[MagickPathExtent];
13100
13101 Image
13102 *tile_image;
13103
13104 int
13105 id,
13106 status,
13107 tile,
13108 x,
13109 y;
13110
13111 double
13112 scale_factor;
13113
13114 register char
13115 *p,
13116 *q;
13117
13118 register int
13119 i;
13120
13121 unsigned int
13122 height,
13123 width;
13124
13125 /*
13126 Tile image is relative to montage image configuration.
13127 */
13128 x=0;
13129 y=0;
13130 width=(unsigned int) image->columns;
13131 height=(unsigned int) image->rows;
13132 if (windows->image.crop_geometry != (char *) NULL)
13133 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13134 scale_factor=(double) width/windows->image.ximage->width;
13135 event->xbutton.x+=windows->image.x;
13136 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13137 scale_factor=(double) height/windows->image.ximage->height;
13138 event->xbutton.y+=windows->image.y;
13139 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13140 /*
13141 Determine size and location of each tile in the visual image directory.
13142 */
13143 width=(unsigned int) image->columns;
13144 height=(unsigned int) image->rows;
13145 x=0;
13146 y=0;
13147 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13148 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13149 (event->xbutton.x-x)/width;
13150 if (tile < 0)
13151 {
13152 /*
13153 Button press is outside any tile.
13154 */
13155 (void) XBell(display,0);
13156 return((Image *) NULL);
13157 }
13158 /*
13159 Determine file name from the tile directory.
13160 */
13161 p=image->directory;
13162 for (i=tile; (i != 0) && (*p != '\0'); )
13163 {
13164 if (*p == '\xff')
13165 i--;
13166 p++;
13167 }
13168 if (*p == '\0')
13169 {
13170 /*
13171 Button press is outside any tile.
13172 */
13173 (void) XBell(display,0);
13174 return((Image *) NULL);
13175 }
13176 /*
13177 Select a command from the pop-up menu.
13178 */
13179 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13180 if (id < 0)
13181 return((Image *) NULL);
13182 q=p;
13183 while ((*q != '\xff') && (*q != '\0'))
13184 q++;
13185 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13186 /*
13187 Perform command for the selected tile.
13188 */
13189 XSetCursorState(display,windows,MagickTrue);
13190 XCheckRefreshWindows(display,windows);
13191 tile_image=NewImageList();
13192 switch (TileCommands[id])
13193 {
13194 case TileLoadCommand:
13195 {
13196 /*
13197 Load tile image.
13198 */
13199 XCheckRefreshWindows(display,windows);
13200 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13201 MagickPathExtent);
13202 (void) CopyMagickString(resource_info->image_info->filename,filename,
13203 MagickPathExtent);
13204 tile_image=ReadImage(resource_info->image_info,exception);
13205 CatchException(exception);
13206 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13207 break;
13208 }
13209 case TileNextCommand:
13210 {
13211 /*
13212 Display next image.
13213 */
13214 XClientMessage(display,windows->image.id,windows->im_protocols,
13215 windows->im_next_image,CurrentTime);
13216 break;
13217 }
13218 case TileFormerCommand:
13219 {
13220 /*
13221 Display former image.
13222 */
13223 XClientMessage(display,windows->image.id,windows->im_protocols,
13224 windows->im_former_image,CurrentTime);
13225 break;
13226 }
13227 case TileDeleteCommand:
13228 {
13229 /*
13230 Delete tile image.
13231 */
13232 if (IsPathAccessible(filename) == MagickFalse)
13233 {
13234 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13235 break;
13236 }
13237 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13238 if (status <= 0)
13239 break;
13240 status=ShredFile(filename);
13241 if (status != MagickFalse )
13242 {
13243 XNoticeWidget(display,windows,"Unable to delete image file:",
13244 filename);
13245 break;
13246 }
13247 }
13248 case TileUpdateCommand:
13249 {
13250 int
13251 x_offset,
13252 y_offset;
13253
13254 PixelInfo
13255 pixel;
13256
13257 register int
13258 j;
13259
13260 register Quantum
13261 *s;
13262
13263 /*
13264 Ensure all the images exist.
13265 */
13266 tile=0;
13267 GetPixelInfo(image,&pixel);
13268 for (p=image->directory; *p != '\0'; p++)
13269 {
13270 CacheView
13271 *image_view;
13272
13273 q=p;
13274 while ((*q != '\xff') && (*q != '\0'))
13275 q++;
13276 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13277 p=q;
13278 if (IsPathAccessible(filename) != MagickFalse )
13279 {
13280 tile++;
13281 continue;
13282 }
13283 /*
13284 Overwrite tile with background color.
13285 */
13286 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13287 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13288 image_view=AcquireAuthenticCacheView(image,exception);
13289 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
13290 for (i=0; i < (int) height; i++)
13291 {
13292 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13293 y_offset+i,width,1,exception);
13294 if (s == (Quantum *) NULL)
13295 break;
13296 for (j=0; j < (int) width; j++)
13297 {
13298 SetPixelViaPixelInfo(image,&pixel,s);
13299 s+=GetPixelChannels(image);
13300 }
13301 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13302 break;
13303 }
13304 image_view=DestroyCacheView(image_view);
13305 tile++;
13306 }
13307 windows->image.window_changes.width=(int) image->columns;
13308 windows->image.window_changes.height=(int) image->rows;
13309 XConfigureImageColormap(display,resource_info,windows,image,exception);
13310 (void) XConfigureImage(display,resource_info,windows,image,exception);
13311 break;
13312 }
13313 default:
13314 break;
13315 }
13316 XSetCursorState(display,windows,MagickFalse);
13317 return(tile_image);
13318 }
13319
13320 /*
13321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13322 % %
13323 % %
13324 % %
13325 + X T r a n s l a t e I m a g e %
13326 % %
13327 % %
13328 % %
13329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13330 %
13331 % XTranslateImage() translates the image within an Image window by one pixel
13332 % as specified by the key symbol. If the image has a montage string the
13333 % translation is respect to the width and height contained within the string.
13334 %
13335 % The format of the XTranslateImage method is:
13336 %
13337 % void XTranslateImage(Display *display,XWindows *windows,
13338 % Image *image,const KeySym key_symbol)
13339 %
13340 % A description of each parameter follows:
13341 %
13342 % o display: Specifies a connection to an X server; returned from
13343 % XOpenDisplay.
13344 %
13345 % o windows: Specifies a pointer to a XWindows structure.
13346 %
13347 % o image: the image.
13348 %
13349 % o key_symbol: Specifies a KeySym which indicates which side of the image
13350 % to trim.
13351 %
13352 */
XTranslateImage(Display * display,XWindows * windows,Image * image,const KeySym key_symbol)13353 static void XTranslateImage(Display *display,XWindows *windows,
13354 Image *image,const KeySym key_symbol)
13355 {
13356 char
13357 text[MagickPathExtent];
13358
13359 int
13360 x,
13361 y;
13362
13363 unsigned int
13364 x_offset,
13365 y_offset;
13366
13367 /*
13368 User specified a pan position offset.
13369 */
13370 x_offset=windows->image.width;
13371 y_offset=windows->image.height;
13372 if (image->montage != (char *) NULL)
13373 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13374 switch ((int) key_symbol)
13375 {
13376 case XK_Home:
13377 case XK_KP_Home:
13378 {
13379 windows->image.x=(int) windows->image.width/2;
13380 windows->image.y=(int) windows->image.height/2;
13381 break;
13382 }
13383 case XK_Left:
13384 case XK_KP_Left:
13385 {
13386 windows->image.x-=x_offset;
13387 break;
13388 }
13389 case XK_Next:
13390 case XK_Up:
13391 case XK_KP_Up:
13392 {
13393 windows->image.y-=y_offset;
13394 break;
13395 }
13396 case XK_Right:
13397 case XK_KP_Right:
13398 {
13399 windows->image.x+=x_offset;
13400 break;
13401 }
13402 case XK_Prior:
13403 case XK_Down:
13404 case XK_KP_Down:
13405 {
13406 windows->image.y+=y_offset;
13407 break;
13408 }
13409 default:
13410 return;
13411 }
13412 /*
13413 Check boundary conditions.
13414 */
13415 if (windows->image.x < 0)
13416 windows->image.x=0;
13417 else
13418 if ((int) (windows->image.x+windows->image.width) >
13419 windows->image.ximage->width)
13420 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13421 if (windows->image.y < 0)
13422 windows->image.y=0;
13423 else
13424 if ((int) (windows->image.y+windows->image.height) >
13425 windows->image.ximage->height)
13426 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13427 /*
13428 Refresh Image window.
13429 */
13430 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
13431 windows->image.width,windows->image.height,windows->image.x,
13432 windows->image.y);
13433 XInfoWidget(display,windows,text);
13434 XCheckRefreshWindows(display,windows);
13435 XDrawPanRectangle(display,windows);
13436 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13437 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13438 }
13439
13440 /*
13441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13442 % %
13443 % %
13444 % %
13445 + X T r i m I m a g e %
13446 % %
13447 % %
13448 % %
13449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13450 %
13451 % XTrimImage() trims the edges from the Image window.
13452 %
13453 % The format of the XTrimImage method is:
13454 %
13455 % MagickBooleanType XTrimImage(Display *display,
13456 % XResourceInfo *resource_info,XWindows *windows,Image *image,
13457 % ExceptionInfo *exception)
13458 %
13459 % A description of each parameter follows:
13460 %
13461 % o display: Specifies a connection to an X server; returned from
13462 % XOpenDisplay.
13463 %
13464 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13465 %
13466 % o windows: Specifies a pointer to a XWindows structure.
13467 %
13468 % o image: the image.
13469 %
13470 % o exception: return any errors or warnings in this structure.
13471 %
13472 */
XTrimImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)13473 static MagickBooleanType XTrimImage(Display *display,
13474 XResourceInfo *resource_info,XWindows *windows,Image *image,
13475 ExceptionInfo *exception)
13476 {
13477 RectangleInfo
13478 trim_info;
13479
13480 register int
13481 x,
13482 y;
13483
13484 size_t
13485 background,
13486 pixel;
13487
13488 /*
13489 Trim edges from image.
13490 */
13491 XSetCursorState(display,windows,MagickTrue);
13492 XCheckRefreshWindows(display,windows);
13493 /*
13494 Crop the left edge.
13495 */
13496 background=XGetPixel(windows->image.ximage,0,0);
13497 trim_info.width=(size_t) windows->image.ximage->width;
13498 for (x=0; x < windows->image.ximage->width; x++)
13499 {
13500 for (y=0; y < windows->image.ximage->height; y++)
13501 {
13502 pixel=XGetPixel(windows->image.ximage,x,y);
13503 if (pixel != background)
13504 break;
13505 }
13506 if (y < windows->image.ximage->height)
13507 break;
13508 }
13509 trim_info.x=(ssize_t) x;
13510 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13511 {
13512 XSetCursorState(display,windows,MagickFalse);
13513 return(MagickFalse);
13514 }
13515 /*
13516 Crop the right edge.
13517 */
13518 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13519 for (x=windows->image.ximage->width-1; x != 0; x--)
13520 {
13521 for (y=0; y < windows->image.ximage->height; y++)
13522 {
13523 pixel=XGetPixel(windows->image.ximage,x,y);
13524 if (pixel != background)
13525 break;
13526 }
13527 if (y < windows->image.ximage->height)
13528 break;
13529 }
13530 trim_info.width=(size_t) (x-trim_info.x+1);
13531 /*
13532 Crop the top edge.
13533 */
13534 background=XGetPixel(windows->image.ximage,0,0);
13535 trim_info.height=(size_t) windows->image.ximage->height;
13536 for (y=0; y < windows->image.ximage->height; y++)
13537 {
13538 for (x=0; x < windows->image.ximage->width; x++)
13539 {
13540 pixel=XGetPixel(windows->image.ximage,x,y);
13541 if (pixel != background)
13542 break;
13543 }
13544 if (x < windows->image.ximage->width)
13545 break;
13546 }
13547 trim_info.y=(ssize_t) y;
13548 /*
13549 Crop the bottom edge.
13550 */
13551 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13552 for (y=windows->image.ximage->height-1; y != 0; y--)
13553 {
13554 for (x=0; x < windows->image.ximage->width; x++)
13555 {
13556 pixel=XGetPixel(windows->image.ximage,x,y);
13557 if (pixel != background)
13558 break;
13559 }
13560 if (x < windows->image.ximage->width)
13561 break;
13562 }
13563 trim_info.height=(size_t) y-trim_info.y+1;
13564 if (((unsigned int) trim_info.width != windows->image.width) ||
13565 ((unsigned int) trim_info.height != windows->image.height))
13566 {
13567 /*
13568 Reconfigure Image window as defined by the trimming rectangle.
13569 */
13570 XSetCropGeometry(display,windows,&trim_info,image);
13571 windows->image.window_changes.width=(int) trim_info.width;
13572 windows->image.window_changes.height=(int) trim_info.height;
13573 (void) XConfigureImage(display,resource_info,windows,image,exception);
13574 }
13575 XSetCursorState(display,windows,MagickFalse);
13576 return(MagickTrue);
13577 }
13578
13579 /*
13580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13581 % %
13582 % %
13583 % %
13584 + X V i s u a l D i r e c t o r y I m a g e %
13585 % %
13586 % %
13587 % %
13588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13589 %
13590 % XVisualDirectoryImage() creates a Visual Image Directory.
13591 %
13592 % The format of the XVisualDirectoryImage method is:
13593 %
13594 % Image *XVisualDirectoryImage(Display *display,
13595 % XResourceInfo *resource_info,XWindows *windows,
13596 % ExceptionInfo *exception)
13597 %
13598 % A description of each parameter follows:
13599 %
13600 % o display: Specifies a connection to an X server; returned from
13601 % XOpenDisplay.
13602 %
13603 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13604 %
13605 % o windows: Specifies a pointer to a XWindows structure.
13606 %
13607 % o exception: return any errors or warnings in this structure.
13608 %
13609 */
XVisualDirectoryImage(Display * display,XResourceInfo * resource_info,XWindows * windows,ExceptionInfo * exception)13610 static Image *XVisualDirectoryImage(Display *display,
13611 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
13612 {
13613 #define TileImageTag "Scale/Image"
13614 #define XClientName "montage"
13615
13616 char
13617 **filelist;
13618
13619 Image
13620 *images,
13621 *montage_image,
13622 *next_image,
13623 *thumbnail_image;
13624
13625 ImageInfo
13626 *read_info;
13627
13628 int
13629 number_files;
13630
13631 MagickBooleanType
13632 backdrop;
13633
13634 MagickStatusType
13635 status;
13636
13637 MontageInfo
13638 *montage_info;
13639
13640 RectangleInfo
13641 geometry;
13642
13643 register int
13644 i;
13645
13646 static char
13647 filename[MagickPathExtent] = "\0",
13648 filenames[MagickPathExtent] = "*";
13649
13650 XResourceInfo
13651 background_resources;
13652
13653 /*
13654 Request file name from user.
13655 */
13656 XFileBrowserWidget(display,windows,"Directory",filenames);
13657 if (*filenames == '\0')
13658 return((Image *) NULL);
13659 /*
13660 Expand the filenames.
13661 */
13662 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13663 if (filelist == (char **) NULL)
13664 {
13665 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13666 filenames);
13667 return((Image *) NULL);
13668 }
13669 number_files=1;
13670 filelist[0]=filenames;
13671 status=ExpandFilenames(&number_files,&filelist);
13672 if ((status == MagickFalse) || (number_files == 0))
13673 {
13674 if (number_files == 0)
13675 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13676 else
13677 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13678 filenames);
13679 return((Image *) NULL);
13680 }
13681 /*
13682 Set image background resources.
13683 */
13684 background_resources=(*resource_info);
13685 background_resources.window_id=AcquireString("");
13686 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent,
13687 "0x%lx",windows->image.id);
13688 background_resources.backdrop=MagickTrue;
13689 /*
13690 Read each image and convert them to a tile.
13691 */
13692 backdrop=((windows->visual_info->klass == TrueColor) ||
13693 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse;
13694 read_info=CloneImageInfo(resource_info->image_info);
13695 (void) SetImageOption(read_info,"jpeg:size","120x120");
13696 (void) CloneString(&read_info->size,DefaultTileGeometry);
13697 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13698 (void *) NULL);
13699 images=NewImageList();
13700 XSetCursorState(display,windows,MagickTrue);
13701 XCheckRefreshWindows(display,windows);
13702 for (i=0; i < (int) number_files; i++)
13703 {
13704 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
13705 filelist[i]=DestroyString(filelist[i]);
13706 *read_info->magick='\0';
13707 next_image=ReadImage(read_info,exception);
13708 CatchException(exception);
13709 if (next_image != (Image *) NULL)
13710 {
13711 (void) DeleteImageProperty(next_image,"label");
13712 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13713 read_info,next_image,DefaultTileLabel,exception),exception);
13714 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13715 exception);
13716 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13717 geometry.height,exception);
13718 if (thumbnail_image != (Image *) NULL)
13719 {
13720 next_image=DestroyImage(next_image);
13721 next_image=thumbnail_image;
13722 }
13723 if (backdrop)
13724 {
13725 (void) XDisplayBackgroundImage(display,&background_resources,
13726 next_image,exception);
13727 XSetCursorState(display,windows,MagickTrue);
13728 }
13729 AppendImageToList(&images,next_image);
13730 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13731 {
13732 MagickBooleanType
13733 proceed;
13734
13735 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13736 (MagickSizeType) number_files);
13737 if (proceed == MagickFalse)
13738 break;
13739 }
13740 }
13741 }
13742 filelist=(char **) RelinquishMagickMemory(filelist);
13743 if (images == (Image *) NULL)
13744 {
13745 read_info=DestroyImageInfo(read_info);
13746 XSetCursorState(display,windows,MagickFalse);
13747 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13748 return((Image *) NULL);
13749 }
13750 /*
13751 Create the Visual Image Directory.
13752 */
13753 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13754 montage_info->pointsize=10;
13755 if (resource_info->font != (char *) NULL)
13756 (void) CloneString(&montage_info->font,resource_info->font);
13757 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent);
13758 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13759 images),exception);
13760 images=DestroyImageList(images);
13761 montage_info=DestroyMontageInfo(montage_info);
13762 read_info=DestroyImageInfo(read_info);
13763 XSetCursorState(display,windows,MagickFalse);
13764 if (montage_image == (Image *) NULL)
13765 return(montage_image);
13766 XClientMessage(display,windows->image.id,windows->im_protocols,
13767 windows->im_next_image,CurrentTime);
13768 return(montage_image);
13769 }
13770
13771 /*
13772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13773 % %
13774 % %
13775 % %
13776 % X D i s p l a y B a c k g r o u n d I m a g e %
13777 % %
13778 % %
13779 % %
13780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13781 %
13782 % XDisplayBackgroundImage() displays an image in the background of a window.
13783 %
13784 % The format of the XDisplayBackgroundImage method is:
13785 %
13786 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13787 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13788 %
13789 % A description of each parameter follows:
13790 %
13791 % o display: Specifies a connection to an X server; returned from
13792 % XOpenDisplay.
13793 %
13794 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13795 %
13796 % o image: the image.
13797 %
13798 % o exception: return any errors or warnings in this structure.
13799 %
13800 */
XDisplayBackgroundImage(Display * display,XResourceInfo * resource_info,Image * image,ExceptionInfo * exception)13801 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13802 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13803 {
13804 char
13805 geometry[MagickPathExtent],
13806 visual_type[MagickPathExtent];
13807
13808 int
13809 height,
13810 status,
13811 width;
13812
13813 RectangleInfo
13814 geometry_info;
13815
13816 static XPixelInfo
13817 pixel;
13818
13819 static XStandardColormap
13820 *map_info;
13821
13822 static XVisualInfo
13823 *visual_info = (XVisualInfo *) NULL;
13824
13825 static XWindowInfo
13826 window_info;
13827
13828 size_t
13829 delay;
13830
13831 Window
13832 root_window;
13833
13834 XGCValues
13835 context_values;
13836
13837 XResourceInfo
13838 resources;
13839
13840 XWindowAttributes
13841 window_attributes;
13842
13843 /*
13844 Determine target window.
13845 */
13846 assert(image != (Image *) NULL);
13847 assert(image->signature == MagickCoreSignature);
13848 if (image->debug != MagickFalse )
13849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13850 resources=(*resource_info);
13851 window_info.id=(Window) NULL;
13852 root_window=XRootWindow(display,XDefaultScreen(display));
13853 if (LocaleCompare(resources.window_id,"root") == 0)
13854 window_info.id=root_window;
13855 else
13856 {
13857 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13858 window_info.id=XWindowByID(display,root_window,
13859 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13860 if (window_info.id == (Window) NULL)
13861 window_info.id=XWindowByName(display,root_window,resources.window_id);
13862 }
13863 if (window_info.id == (Window) NULL)
13864 {
13865 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13866 resources.window_id);
13867 return(MagickFalse);
13868 }
13869 /*
13870 Determine window visual id.
13871 */
13872 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13873 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13874 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
13875 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13876 if (status != 0)
13877 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
13878 XVisualIDFromVisual(window_attributes.visual));
13879 if (visual_info == (XVisualInfo *) NULL)
13880 {
13881 /*
13882 Allocate standard colormap.
13883 */
13884 map_info=XAllocStandardColormap();
13885 if (map_info == (XStandardColormap *) NULL)
13886 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13887 image->filename);
13888 map_info->colormap=(Colormap) NULL;
13889 pixel.pixels=(unsigned long *) NULL;
13890 /*
13891 Initialize visual info.
13892 */
13893 resources.map_type=(char *) NULL;
13894 resources.visual_type=visual_type;
13895 visual_info=XBestVisualInfo(display,map_info,&resources);
13896 if (visual_info == (XVisualInfo *) NULL)
13897 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13898 resources.visual_type);
13899 /*
13900 Initialize window info.
13901 */
13902 window_info.ximage=(XImage *) NULL;
13903 window_info.matte_image=(XImage *) NULL;
13904 window_info.pixmap=(Pixmap) NULL;
13905 window_info.matte_pixmap=(Pixmap) NULL;
13906 }
13907 /*
13908 Free previous root colors.
13909 */
13910 if (window_info.id == root_window)
13911 (void) XDestroyWindowColors(display,root_window);
13912 /*
13913 Initialize Standard Colormap.
13914 */
13915 resources.colormap=SharedColormap;
13916 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13917 exception);
13918 /*
13919 Graphic context superclass.
13920 */
13921 context_values.background=pixel.background_color.pixel;
13922 context_values.foreground=pixel.foreground_color.pixel;
13923 pixel.annotate_context=XCreateGC(display,window_info.id,
13924 (size_t) (GCBackground | GCForeground),&context_values);
13925 if (pixel.annotate_context == (GC) NULL)
13926 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13927 image->filename);
13928 /*
13929 Initialize Image window attributes.
13930 */
13931 window_info.name=AcquireString("\0");
13932 window_info.icon_name=AcquireString("\0");
13933 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13934 &resources,&window_info);
13935 /*
13936 Create the X image.
13937 */
13938 window_info.width=(unsigned int) image->columns;
13939 window_info.height=(unsigned int) image->rows;
13940 if ((image->columns != window_info.width) ||
13941 (image->rows != window_info.height))
13942 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13943 image->filename);
13944 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
13945 window_attributes.width,window_attributes.height);
13946 geometry_info.width=window_info.width;
13947 geometry_info.height=window_info.height;
13948 geometry_info.x=(ssize_t) window_info.x;
13949 geometry_info.y=(ssize_t) window_info.y;
13950 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13951 &geometry_info.width,&geometry_info.height);
13952 window_info.width=(unsigned int) geometry_info.width;
13953 window_info.height=(unsigned int) geometry_info.height;
13954 window_info.x=(int) geometry_info.x;
13955 window_info.y=(int) geometry_info.y;
13956 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13957 window_info.height,exception);
13958 if (status == MagickFalse)
13959 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13960 image->filename);
13961 window_info.x=0;
13962 window_info.y=0;
13963 if (image->debug != MagickFalse )
13964 {
13965 (void) LogMagickEvent(X11Event,GetMagickModule(),
13966 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13967 (double) image->columns,(double) image->rows);
13968 if (image->colors != 0)
13969 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13970 image->colors);
13971 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13972 }
13973 /*
13974 Adjust image dimensions as specified by backdrop or geometry options.
13975 */
13976 width=(int) window_info.width;
13977 height=(int) window_info.height;
13978 if (resources.backdrop != MagickFalse )
13979 {
13980 /*
13981 Center image on window.
13982 */
13983 window_info.x=(window_attributes.width/2)-
13984 (window_info.ximage->width/2);
13985 window_info.y=(window_attributes.height/2)-
13986 (window_info.ximage->height/2);
13987 width=window_attributes.width;
13988 height=window_attributes.height;
13989 }
13990 if ((resources.image_geometry != (char *) NULL) &&
13991 (*resources.image_geometry != '\0'))
13992 {
13993 char
13994 default_geometry[MagickPathExtent];
13995
13996 int
13997 flags,
13998 gravity;
13999
14000 XSizeHints
14001 *size_hints;
14002
14003 /*
14004 User specified geometry.
14005 */
14006 size_hints=XAllocSizeHints();
14007 if (size_hints == (XSizeHints *) NULL)
14008 ThrowXWindowFatalException(ResourceLimitFatalError,
14009 "MemoryAllocationFailed",image->filename);
14010 size_hints->flags=0L;
14011 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d",
14012 width,height);
14013 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
14014 default_geometry,window_info.border_width,size_hints,&window_info.x,
14015 &window_info.y,&width,&height,&gravity);
14016 if (flags & (XValue | YValue))
14017 {
14018 width=window_attributes.width;
14019 height=window_attributes.height;
14020 }
14021 (void) XFree((void *) size_hints);
14022 }
14023 /*
14024 Create the X pixmap.
14025 */
14026 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14027 (unsigned int) height,window_info.depth);
14028 if (window_info.pixmap == (Pixmap) NULL)
14029 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14030 image->filename);
14031 /*
14032 Display pixmap on the window.
14033 */
14034 if (((unsigned int) width > window_info.width) ||
14035 ((unsigned int) height > window_info.height))
14036 (void) XFillRectangle(display,window_info.pixmap,
14037 window_info.annotate_context,0,0,(unsigned int) width,
14038 (unsigned int) height);
14039 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14040 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14041 window_info.width,(unsigned int) window_info.height);
14042 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14043 (void) XClearWindow(display,window_info.id);
14044 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14045 XDelay(display,delay == 0UL ? 10UL : delay);
14046 (void) XSync(display,MagickFalse);
14047 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14048 }
14049
14050 /*
14051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14052 % %
14053 % %
14054 % %
14055 + X D i s p l a y I m a g e %
14056 % %
14057 % %
14058 % %
14059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14060 %
14061 % XDisplayImage() displays an image via X11. A new image is created and
14062 % returned if the user interactively transforms the displayed image.
14063 %
14064 % The format of the XDisplayImage method is:
14065 %
14066 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14067 % char **argv,int argc,Image **image,size_t *state,
14068 % ExceptionInfo *exception)
14069 %
14070 % A description of each parameter follows:
14071 %
14072 % o nexus: Method XDisplayImage returns an image when the
14073 % user chooses 'Open Image' from the command menu or picks a tile
14074 % from the image directory. Otherwise a null image is returned.
14075 %
14076 % o display: Specifies a connection to an X server; returned from
14077 % XOpenDisplay.
14078 %
14079 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14080 %
14081 % o argv: Specifies the application's argument list.
14082 %
14083 % o argc: Specifies the number of arguments.
14084 %
14085 % o image: Specifies an address to an address of an Image structure;
14086 %
14087 % o exception: return any errors or warnings in this structure.
14088 %
14089 */
XDisplayImage(Display * display,XResourceInfo * resource_info,char ** argv,int argc,Image ** image,size_t * state,ExceptionInfo * exception)14090 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14091 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
14092 {
14093 #define MagnifySize 256 /* must be a power of 2 */
14094 #define MagickMenus 10
14095 #define MagickTitle "Commands"
14096
14097 const char
14098 *const CommandMenu[] =
14099 {
14100 "File",
14101 "Edit",
14102 "View",
14103 "Transform",
14104 "Enhance",
14105 "Effects",
14106 "F/X",
14107 "Image Edit",
14108 "Miscellany",
14109 "Help",
14110 (char *) NULL
14111 },
14112 *const FileMenu[] =
14113 {
14114 "Open...",
14115 "Next",
14116 "Former",
14117 "Select...",
14118 "Save...",
14119 "Print...",
14120 "Delete...",
14121 "New...",
14122 "Visual Directory...",
14123 "Quit",
14124 (char *) NULL
14125 },
14126 *const EditMenu[] =
14127 {
14128 "Undo",
14129 "Redo",
14130 "Cut",
14131 "Copy",
14132 "Paste",
14133 (char *) NULL
14134 },
14135 *const ViewMenu[] =
14136 {
14137 "Half Size",
14138 "Original Size",
14139 "Double Size",
14140 "Resize...",
14141 "Apply",
14142 "Refresh",
14143 "Restore",
14144 (char *) NULL
14145 },
14146 *const TransformMenu[] =
14147 {
14148 "Crop",
14149 "Chop",
14150 "Flop",
14151 "Flip",
14152 "Rotate Right",
14153 "Rotate Left",
14154 "Rotate...",
14155 "Shear...",
14156 "Roll...",
14157 "Trim Edges",
14158 (char *) NULL
14159 },
14160 *const EnhanceMenu[] =
14161 {
14162 "Hue...",
14163 "Saturation...",
14164 "Brightness...",
14165 "Gamma...",
14166 "Spiff",
14167 "Dull",
14168 "Contrast Stretch...",
14169 "Sigmoidal Contrast...",
14170 "Normalize",
14171 "Equalize",
14172 "Negate",
14173 "Grayscale",
14174 "Map...",
14175 "Quantize...",
14176 (char *) NULL
14177 },
14178 *const EffectsMenu[] =
14179 {
14180 "Despeckle",
14181 "Emboss",
14182 "Reduce Noise",
14183 "Add Noise...",
14184 "Sharpen...",
14185 "Blur...",
14186 "Threshold...",
14187 "Edge Detect...",
14188 "Spread...",
14189 "Shade...",
14190 "Raise...",
14191 "Segment...",
14192 (char *) NULL
14193 },
14194 *const FXMenu[] =
14195 {
14196 "Solarize...",
14197 "Sepia Tone...",
14198 "Swirl...",
14199 "Implode...",
14200 "Vignette...",
14201 "Wave...",
14202 "Oil Paint...",
14203 "Charcoal Draw...",
14204 (char *) NULL
14205 },
14206 *const ImageEditMenu[] =
14207 {
14208 "Annotate...",
14209 "Draw...",
14210 "Color...",
14211 "Matte...",
14212 "Composite...",
14213 "Add Border...",
14214 "Add Frame...",
14215 "Comment...",
14216 "Launch...",
14217 "Region of Interest...",
14218 (char *) NULL
14219 },
14220 *const MiscellanyMenu[] =
14221 {
14222 "Image Info",
14223 "Zoom Image",
14224 "Show Preview...",
14225 "Show Histogram",
14226 "Show Matte",
14227 "Background...",
14228 "Slide Show...",
14229 "Preferences...",
14230 (char *) NULL
14231 },
14232 *const HelpMenu[] =
14233 {
14234 "Overview",
14235 "Browse Documentation",
14236 "About Display",
14237 (char *) NULL
14238 },
14239 *const ShortCutsMenu[] =
14240 {
14241 "Next",
14242 "Former",
14243 "Open...",
14244 "Save...",
14245 "Print...",
14246 "Undo",
14247 "Restore",
14248 "Image Info",
14249 "Quit",
14250 (char *) NULL
14251 },
14252 *const VirtualMenu[] =
14253 {
14254 "Image Info",
14255 "Print",
14256 "Next",
14257 "Quit",
14258 (char *) NULL
14259 };
14260
14261 const char
14262 *const *Menus[MagickMenus] =
14263 {
14264 FileMenu,
14265 EditMenu,
14266 ViewMenu,
14267 TransformMenu,
14268 EnhanceMenu,
14269 EffectsMenu,
14270 FXMenu,
14271 ImageEditMenu,
14272 MiscellanyMenu,
14273 HelpMenu
14274 };
14275
14276 static CommandType
14277 CommandMenus[] =
14278 {
14279 NullCommand,
14280 NullCommand,
14281 NullCommand,
14282 NullCommand,
14283 NullCommand,
14284 NullCommand,
14285 NullCommand,
14286 NullCommand,
14287 NullCommand,
14288 NullCommand,
14289 },
14290 FileCommands[] =
14291 {
14292 OpenCommand,
14293 NextCommand,
14294 FormerCommand,
14295 SelectCommand,
14296 SaveCommand,
14297 PrintCommand,
14298 DeleteCommand,
14299 NewCommand,
14300 VisualDirectoryCommand,
14301 QuitCommand
14302 },
14303 EditCommands[] =
14304 {
14305 UndoCommand,
14306 RedoCommand,
14307 CutCommand,
14308 CopyCommand,
14309 PasteCommand
14310 },
14311 ViewCommands[] =
14312 {
14313 HalfSizeCommand,
14314 OriginalSizeCommand,
14315 DoubleSizeCommand,
14316 ResizeCommand,
14317 ApplyCommand,
14318 RefreshCommand,
14319 RestoreCommand
14320 },
14321 TransformCommands[] =
14322 {
14323 CropCommand,
14324 ChopCommand,
14325 FlopCommand,
14326 FlipCommand,
14327 RotateRightCommand,
14328 RotateLeftCommand,
14329 RotateCommand,
14330 ShearCommand,
14331 RollCommand,
14332 TrimCommand
14333 },
14334 EnhanceCommands[] =
14335 {
14336 HueCommand,
14337 SaturationCommand,
14338 BrightnessCommand,
14339 GammaCommand,
14340 SpiffCommand,
14341 DullCommand,
14342 ContrastStretchCommand,
14343 SigmoidalContrastCommand,
14344 NormalizeCommand,
14345 EqualizeCommand,
14346 NegateCommand,
14347 GrayscaleCommand,
14348 MapCommand,
14349 QuantizeCommand
14350 },
14351 EffectsCommands[] =
14352 {
14353 DespeckleCommand,
14354 EmbossCommand,
14355 ReduceNoiseCommand,
14356 AddNoiseCommand,
14357 SharpenCommand,
14358 BlurCommand,
14359 ThresholdCommand,
14360 EdgeDetectCommand,
14361 SpreadCommand,
14362 ShadeCommand,
14363 RaiseCommand,
14364 SegmentCommand
14365 },
14366 FXCommands[] =
14367 {
14368 SolarizeCommand,
14369 SepiaToneCommand,
14370 SwirlCommand,
14371 ImplodeCommand,
14372 VignetteCommand,
14373 WaveCommand,
14374 OilPaintCommand,
14375 CharcoalDrawCommand
14376 },
14377 ImageEditCommands[] =
14378 {
14379 AnnotateCommand,
14380 DrawCommand,
14381 ColorCommand,
14382 MatteCommand,
14383 CompositeCommand,
14384 AddBorderCommand,
14385 AddFrameCommand,
14386 CommentCommand,
14387 LaunchCommand,
14388 RegionofInterestCommand
14389 },
14390 MiscellanyCommands[] =
14391 {
14392 InfoCommand,
14393 ZoomCommand,
14394 ShowPreviewCommand,
14395 ShowHistogramCommand,
14396 ShowMatteCommand,
14397 BackgroundCommand,
14398 SlideShowCommand,
14399 PreferencesCommand
14400 },
14401 HelpCommands[] =
14402 {
14403 HelpCommand,
14404 BrowseDocumentationCommand,
14405 VersionCommand
14406 },
14407 ShortCutsCommands[] =
14408 {
14409 NextCommand,
14410 FormerCommand,
14411 OpenCommand,
14412 SaveCommand,
14413 PrintCommand,
14414 UndoCommand,
14415 RestoreCommand,
14416 InfoCommand,
14417 QuitCommand
14418 },
14419 VirtualCommands[] =
14420 {
14421 InfoCommand,
14422 PrintCommand,
14423 NextCommand,
14424 QuitCommand
14425 };
14426
14427 static CommandType
14428 *Commands[MagickMenus] =
14429 {
14430 FileCommands,
14431 EditCommands,
14432 ViewCommands,
14433 TransformCommands,
14434 EnhanceCommands,
14435 EffectsCommands,
14436 FXCommands,
14437 ImageEditCommands,
14438 MiscellanyCommands,
14439 HelpCommands
14440 };
14441
14442 char
14443 command[MagickPathExtent],
14444 *directory,
14445 geometry[MagickPathExtent],
14446 resource_name[MagickPathExtent];
14447
14448 CommandType
14449 command_type;
14450
14451 Image
14452 *display_image,
14453 *nexus;
14454
14455 int
14456 entry,
14457 id;
14458
14459 KeySym
14460 key_symbol;
14461
14462 MagickStatusType
14463 context_mask,
14464 status;
14465
14466 RectangleInfo
14467 geometry_info;
14468
14469 register int
14470 i;
14471
14472 static char
14473 working_directory[MagickPathExtent];
14474
14475 static XPoint
14476 vid_info;
14477
14478 static XWindowInfo
14479 *magick_windows[MaxXWindows];
14480
14481 static unsigned int
14482 number_windows;
14483
14484 struct stat
14485 attributes;
14486
14487 time_t
14488 timer,
14489 timestamp,
14490 update_time;
14491
14492 unsigned int
14493 height,
14494 width;
14495
14496 size_t
14497 delay;
14498
14499 WarningHandler
14500 warning_handler;
14501
14502 Window
14503 root_window;
14504
14505 XClassHint
14506 *class_hints;
14507
14508 XEvent
14509 event;
14510
14511 XFontStruct
14512 *font_info;
14513
14514 XGCValues
14515 context_values;
14516
14517 XPixelInfo
14518 *icon_pixel,
14519 *pixel;
14520
14521 XResourceInfo
14522 *icon_resources;
14523
14524 XStandardColormap
14525 *icon_map,
14526 *map_info;
14527
14528 XVisualInfo
14529 *icon_visual,
14530 *visual_info;
14531
14532 XWindowChanges
14533 window_changes;
14534
14535 XWindows
14536 *windows;
14537
14538 XWMHints
14539 *manager_hints;
14540
14541 assert(image != (Image **) NULL);
14542 assert((*image)->signature == MagickCoreSignature);
14543 if ((*image)->debug != MagickFalse )
14544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14545 display_image=(*image);
14546 warning_handler=(WarningHandler) NULL;
14547 windows=XSetWindows((XWindows *) ~0);
14548 if (windows != (XWindows *) NULL)
14549 {
14550 int
14551 status;
14552
14553 if (*working_directory == '\0')
14554 (void) CopyMagickString(working_directory,".",MagickPathExtent);
14555 status=chdir(working_directory);
14556 if (status == -1)
14557 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14558 "UnableToOpenFile","%s",working_directory);
14559 warning_handler=resource_info->display_warnings ?
14560 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14561 warning_handler=resource_info->display_warnings ?
14562 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14563 }
14564 else
14565 {
14566 /*
14567 Allocate windows structure.
14568 */
14569 resource_info->colors=display_image->colors;
14570 windows=XSetWindows(XInitializeWindows(display,resource_info));
14571 if (windows == (XWindows *) NULL)
14572 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14573 (*image)->filename);
14574 /*
14575 Initialize window id's.
14576 */
14577 number_windows=0;
14578 magick_windows[number_windows++]=(&windows->icon);
14579 magick_windows[number_windows++]=(&windows->backdrop);
14580 magick_windows[number_windows++]=(&windows->image);
14581 magick_windows[number_windows++]=(&windows->info);
14582 magick_windows[number_windows++]=(&windows->command);
14583 magick_windows[number_windows++]=(&windows->widget);
14584 magick_windows[number_windows++]=(&windows->popup);
14585 magick_windows[number_windows++]=(&windows->magnify);
14586 magick_windows[number_windows++]=(&windows->pan);
14587 for (i=0; i < (int) number_windows; i++)
14588 magick_windows[i]->id=(Window) NULL;
14589 vid_info.x=0;
14590 vid_info.y=0;
14591 }
14592 /*
14593 Initialize font info.
14594 */
14595 if (windows->font_info != (XFontStruct *) NULL)
14596 (void) XFreeFont(display,windows->font_info);
14597 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14598 if (windows->font_info == (XFontStruct *) NULL)
14599 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14600 resource_info->font);
14601 /*
14602 Initialize Standard Colormap.
14603 */
14604 map_info=windows->map_info;
14605 icon_map=windows->icon_map;
14606 visual_info=windows->visual_info;
14607 icon_visual=windows->icon_visual;
14608 pixel=windows->pixel_info;
14609 icon_pixel=windows->icon_pixel;
14610 font_info=windows->font_info;
14611 icon_resources=windows->icon_resources;
14612 class_hints=windows->class_hints;
14613 manager_hints=windows->manager_hints;
14614 root_window=XRootWindow(display,visual_info->screen);
14615 nexus=NewImageList();
14616 if (display_image->debug != MagickFalse )
14617 {
14618 (void) LogMagickEvent(X11Event,GetMagickModule(),
14619 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14620 (double) display_image->scene,(double) display_image->columns,
14621 (double) display_image->rows);
14622 if (display_image->colors != 0)
14623 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14624 display_image->colors);
14625 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14626 display_image->magick);
14627 }
14628 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14629 map_info,pixel,exception);
14630 display_image->taint=MagickFalse;
14631 /*
14632 Initialize graphic context.
14633 */
14634 windows->context.id=(Window) NULL;
14635 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14636 resource_info,&windows->context);
14637 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14638 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14639 class_hints->res_class[0]=(char) LocaleUppercase((int)
14640 class_hints->res_class[0]);
14641 manager_hints->flags=InputHint | StateHint;
14642 manager_hints->input=MagickFalse;
14643 manager_hints->initial_state=WithdrawnState;
14644 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14645 &windows->context);
14646 if (display_image->debug != MagickFalse )
14647 (void) LogMagickEvent(X11Event,GetMagickModule(),
14648 "Window id: 0x%lx (context)",windows->context.id);
14649 context_values.background=pixel->background_color.pixel;
14650 context_values.font=font_info->fid;
14651 context_values.foreground=pixel->foreground_color.pixel;
14652 context_values.graphics_exposures=MagickFalse;
14653 context_mask=(MagickStatusType)
14654 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14655 if (pixel->annotate_context != (GC) NULL)
14656 (void) XFreeGC(display,pixel->annotate_context);
14657 pixel->annotate_context=XCreateGC(display,windows->context.id,
14658 context_mask,&context_values);
14659 if (pixel->annotate_context == (GC) NULL)
14660 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14661 display_image->filename);
14662 context_values.background=pixel->depth_color.pixel;
14663 if (pixel->widget_context != (GC) NULL)
14664 (void) XFreeGC(display,pixel->widget_context);
14665 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14666 &context_values);
14667 if (pixel->widget_context == (GC) NULL)
14668 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14669 display_image->filename);
14670 context_values.background=pixel->foreground_color.pixel;
14671 context_values.foreground=pixel->background_color.pixel;
14672 context_values.plane_mask=context_values.background ^
14673 context_values.foreground;
14674 if (pixel->highlight_context != (GC) NULL)
14675 (void) XFreeGC(display,pixel->highlight_context);
14676 pixel->highlight_context=XCreateGC(display,windows->context.id,
14677 (size_t) (context_mask | GCPlaneMask),&context_values);
14678 if (pixel->highlight_context == (GC) NULL)
14679 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14680 display_image->filename);
14681 (void) XDestroyWindow(display,windows->context.id);
14682 /*
14683 Initialize icon window.
14684 */
14685 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14686 icon_resources,&windows->icon);
14687 windows->icon.geometry=resource_info->icon_geometry;
14688 XBestIconSize(display,&windows->icon,display_image);
14689 windows->icon.attributes.colormap=XDefaultColormap(display,
14690 icon_visual->screen);
14691 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14692 manager_hints->flags=InputHint | StateHint;
14693 manager_hints->input=MagickFalse;
14694 manager_hints->initial_state=IconicState;
14695 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14696 &windows->icon);
14697 if (display_image->debug != MagickFalse )
14698 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14699 windows->icon.id);
14700 /*
14701 Initialize graphic context for icon window.
14702 */
14703 if (icon_pixel->annotate_context != (GC) NULL)
14704 (void) XFreeGC(display,icon_pixel->annotate_context);
14705 context_values.background=icon_pixel->background_color.pixel;
14706 context_values.foreground=icon_pixel->foreground_color.pixel;
14707 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14708 (size_t) (GCBackground | GCForeground),&context_values);
14709 if (icon_pixel->annotate_context == (GC) NULL)
14710 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14711 display_image->filename);
14712 windows->icon.annotate_context=icon_pixel->annotate_context;
14713 /*
14714 Initialize Image window.
14715 */
14716 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14717 &windows->image);
14718 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14719 if (resource_info->use_shared_memory == MagickFalse)
14720 windows->image.shared_memory=MagickFalse;
14721 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14722 {
14723 char
14724 *title;
14725
14726 title=InterpretImageProperties(resource_info->image_info,display_image,
14727 resource_info->title,exception);
14728 (void) CloneString(&windows->image.name,title);
14729 (void) CloneString(&windows->image.icon_name,title);
14730 title=DestroyString(title);
14731 }
14732 else
14733 {
14734 char
14735 filename[MagickPathExtent],
14736 window_name[MagickPathExtent];
14737
14738 /*
14739 Window name is the base of the filename.
14740 */
14741 GetPathComponent(display_image->magick_filename,TailPath,filename);
14742 if (display_image->scene == 0)
14743 (void) FormatLocaleString(window_name,MagickPathExtent,"%s: %s",
14744 MagickPackageName,filename);
14745 else
14746 (void) FormatLocaleString(window_name,MagickPathExtent,
14747 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14748 (double) display_image->scene,(double) GetImageListLength(
14749 display_image));
14750 (void) CloneString(&windows->image.name,window_name);
14751 (void) CloneString(&windows->image.icon_name,filename);
14752 }
14753 if (resource_info->immutable)
14754 windows->image.immutable=MagickTrue;
14755 windows->image.use_pixmap=resource_info->use_pixmap;
14756 windows->image.geometry=resource_info->image_geometry;
14757 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
14758 XDisplayWidth(display,visual_info->screen),
14759 XDisplayHeight(display,visual_info->screen));
14760 geometry_info.width=display_image->columns;
14761 geometry_info.height=display_image->rows;
14762 geometry_info.x=0;
14763 geometry_info.y=0;
14764 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14765 &geometry_info.width,&geometry_info.height);
14766 windows->image.width=(unsigned int) geometry_info.width;
14767 windows->image.height=(unsigned int) geometry_info.height;
14768 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14769 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14770 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14771 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14772 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14773 resource_info,&windows->backdrop);
14774 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14775 {
14776 /*
14777 Initialize backdrop window.
14778 */
14779 windows->backdrop.x=0;
14780 windows->backdrop.y=0;
14781 (void) CloneString(&windows->backdrop.name,"Backdrop");
14782 windows->backdrop.flags=(size_t) (USSize | USPosition);
14783 windows->backdrop.width=(unsigned int)
14784 XDisplayWidth(display,visual_info->screen);
14785 windows->backdrop.height=(unsigned int)
14786 XDisplayHeight(display,visual_info->screen);
14787 windows->backdrop.border_width=0;
14788 windows->backdrop.immutable=MagickTrue;
14789 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14790 ButtonReleaseMask;
14791 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14792 StructureNotifyMask;
14793 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14794 manager_hints->icon_window=windows->icon.id;
14795 manager_hints->input=MagickTrue;
14796 manager_hints->initial_state=resource_info->iconic ? IconicState :
14797 NormalState;
14798 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14799 &windows->backdrop);
14800 if (display_image->debug != MagickFalse )
14801 (void) LogMagickEvent(X11Event,GetMagickModule(),
14802 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14803 (void) XMapWindow(display,windows->backdrop.id);
14804 (void) XClearWindow(display,windows->backdrop.id);
14805 if (windows->image.id != (Window) NULL)
14806 {
14807 (void) XDestroyWindow(display,windows->image.id);
14808 windows->image.id=(Window) NULL;
14809 }
14810 /*
14811 Position image in the center the backdrop.
14812 */
14813 windows->image.flags|=USPosition;
14814 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14815 (windows->image.width/2);
14816 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14817 (windows->image.height/2);
14818 }
14819 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14820 manager_hints->icon_window=windows->icon.id;
14821 manager_hints->input=MagickTrue;
14822 manager_hints->initial_state=resource_info->iconic ? IconicState :
14823 NormalState;
14824 if (windows->group_leader.id != (Window) NULL)
14825 {
14826 /*
14827 Follow the leader.
14828 */
14829 manager_hints->flags|=WindowGroupHint;
14830 manager_hints->window_group=windows->group_leader.id;
14831 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14832 if (display_image->debug != MagickFalse )
14833 (void) LogMagickEvent(X11Event,GetMagickModule(),
14834 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14835 }
14836 XMakeWindow(display,
14837 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14838 argv,argc,class_hints,manager_hints,&windows->image);
14839 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14840 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14841 if (windows->group_leader.id != (Window) NULL)
14842 (void) XSetTransientForHint(display,windows->image.id,
14843 windows->group_leader.id);
14844 if (display_image->debug != MagickFalse )
14845 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14846 windows->image.id);
14847 /*
14848 Initialize Info widget.
14849 */
14850 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14851 &windows->info);
14852 (void) CloneString(&windows->info.name,"Info");
14853 (void) CloneString(&windows->info.icon_name,"Info");
14854 windows->info.border_width=1;
14855 windows->info.x=2;
14856 windows->info.y=2;
14857 windows->info.flags|=PPosition;
14858 windows->info.attributes.win_gravity=UnmapGravity;
14859 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14860 StructureNotifyMask;
14861 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14862 manager_hints->input=MagickFalse;
14863 manager_hints->initial_state=NormalState;
14864 manager_hints->window_group=windows->image.id;
14865 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14866 &windows->info);
14867 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14868 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14869 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14870 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14871 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14872 if (windows->image.mapped != MagickFalse )
14873 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14874 if (display_image->debug != MagickFalse )
14875 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14876 windows->info.id);
14877 /*
14878 Initialize Command widget.
14879 */
14880 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14881 resource_info,&windows->command);
14882 windows->command.data=MagickMenus;
14883 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14884 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
14885 resource_info->client_name);
14886 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14887 resource_name,"geometry",(char *) NULL);
14888 (void) CloneString(&windows->command.name,MagickTitle);
14889 windows->command.border_width=0;
14890 windows->command.flags|=PPosition;
14891 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14892 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14893 OwnerGrabButtonMask | StructureNotifyMask;
14894 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14895 manager_hints->input=MagickTrue;
14896 manager_hints->initial_state=NormalState;
14897 manager_hints->window_group=windows->image.id;
14898 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14899 &windows->command);
14900 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14901 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14902 HighlightHeight);
14903 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14904 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14905 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14906 if (windows->command.mapped != MagickFalse )
14907 (void) XMapRaised(display,windows->command.id);
14908 if (display_image->debug != MagickFalse )
14909 (void) LogMagickEvent(X11Event,GetMagickModule(),
14910 "Window id: 0x%lx (command)",windows->command.id);
14911 /*
14912 Initialize Widget window.
14913 */
14914 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14915 resource_info,&windows->widget);
14916 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
14917 resource_info->client_name);
14918 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14919 resource_name,"geometry",(char *) NULL);
14920 windows->widget.border_width=0;
14921 windows->widget.flags|=PPosition;
14922 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14923 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14924 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14925 StructureNotifyMask;
14926 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14927 manager_hints->input=MagickTrue;
14928 manager_hints->initial_state=NormalState;
14929 manager_hints->window_group=windows->image.id;
14930 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14931 &windows->widget);
14932 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14933 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14934 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14935 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14936 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14937 if (display_image->debug != MagickFalse )
14938 (void) LogMagickEvent(X11Event,GetMagickModule(),
14939 "Window id: 0x%lx (widget)",windows->widget.id);
14940 /*
14941 Initialize popup window.
14942 */
14943 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14944 resource_info,&windows->popup);
14945 windows->popup.border_width=0;
14946 windows->popup.flags|=PPosition;
14947 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14948 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14949 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14950 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14951 manager_hints->input=MagickTrue;
14952 manager_hints->initial_state=NormalState;
14953 manager_hints->window_group=windows->image.id;
14954 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14955 &windows->popup);
14956 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14957 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14958 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14959 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14960 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14961 if (display_image->debug != MagickFalse )
14962 (void) LogMagickEvent(X11Event,GetMagickModule(),
14963 "Window id: 0x%lx (pop up)",windows->popup.id);
14964 /*
14965 Initialize Magnify window and cursor.
14966 */
14967 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14968 resource_info,&windows->magnify);
14969 if (resource_info->use_shared_memory == MagickFalse)
14970 windows->magnify.shared_memory=MagickFalse;
14971 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify",
14972 resource_info->client_name);
14973 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14974 resource_name,"geometry",(char *) NULL);
14975 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,
14976 "Magnify %uX",resource_info->magnify);
14977 if (windows->magnify.cursor != (Cursor) NULL)
14978 (void) XFreeCursor(display,windows->magnify.cursor);
14979 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14980 map_info->colormap,resource_info->background_color,
14981 resource_info->foreground_color);
14982 if (windows->magnify.cursor == (Cursor) NULL)
14983 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14984 display_image->filename);
14985 windows->magnify.width=MagnifySize;
14986 windows->magnify.height=MagnifySize;
14987 windows->magnify.flags|=PPosition;
14988 windows->magnify.min_width=MagnifySize;
14989 windows->magnify.min_height=MagnifySize;
14990 windows->magnify.width_inc=MagnifySize;
14991 windows->magnify.height_inc=MagnifySize;
14992 windows->magnify.data=resource_info->magnify;
14993 windows->magnify.attributes.cursor=windows->magnify.cursor;
14994 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14995 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14996 StructureNotifyMask;
14997 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14998 manager_hints->input=MagickTrue;
14999 manager_hints->initial_state=NormalState;
15000 manager_hints->window_group=windows->image.id;
15001 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15002 &windows->magnify);
15003 if (display_image->debug != MagickFalse )
15004 (void) LogMagickEvent(X11Event,GetMagickModule(),
15005 "Window id: 0x%lx (magnify)",windows->magnify.id);
15006 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
15007 /*
15008 Initialize panning window.
15009 */
15010 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
15011 resource_info,&windows->pan);
15012 (void) CloneString(&windows->pan.name,"Pan Icon");
15013 windows->pan.width=windows->icon.width;
15014 windows->pan.height=windows->icon.height;
15015 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan",
15016 resource_info->client_name);
15017 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
15018 resource_name,"geometry",(char *) NULL);
15019 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
15020 &windows->pan.width,&windows->pan.height);
15021 windows->pan.flags|=PPosition;
15022 windows->pan.immutable=MagickTrue;
15023 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
15024 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15025 StructureNotifyMask;
15026 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15027 manager_hints->input=MagickFalse;
15028 manager_hints->initial_state=NormalState;
15029 manager_hints->window_group=windows->image.id;
15030 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15031 &windows->pan);
15032 if (display_image->debug != MagickFalse )
15033 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15034 windows->pan.id);
15035 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15036 if (windows->info.mapped != MagickFalse )
15037 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15038 if ((windows->image.mapped == MagickFalse) ||
15039 (windows->backdrop.id != (Window) NULL))
15040 (void) XMapWindow(display,windows->image.id);
15041 /*
15042 Set our progress monitor and warning handlers.
15043 */
15044 if (warning_handler == (WarningHandler) NULL)
15045 {
15046 warning_handler=resource_info->display_warnings ?
15047 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15048 warning_handler=resource_info->display_warnings ?
15049 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15050 }
15051 /*
15052 Initialize Image and Magnify X images.
15053 */
15054 windows->image.x=0;
15055 windows->image.y=0;
15056 windows->magnify.shape=MagickFalse;
15057 width=(unsigned int) display_image->columns;
15058 height=(unsigned int) display_image->rows;
15059 if ((display_image->columns != width) || (display_image->rows != height))
15060 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15061 display_image->filename);
15062 status=XMakeImage(display,resource_info,&windows->image,display_image,
15063 width,height,exception);
15064 if (status == MagickFalse)
15065 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15066 display_image->filename);
15067 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
15068 windows->magnify.width,windows->magnify.height,exception);
15069 if (status == MagickFalse)
15070 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15071 display_image->filename);
15072 if (windows->magnify.mapped != MagickFalse )
15073 (void) XMapRaised(display,windows->magnify.id);
15074 if (windows->pan.mapped != MagickFalse )
15075 (void) XMapRaised(display,windows->pan.id);
15076 windows->image.window_changes.width=(int) display_image->columns;
15077 windows->image.window_changes.height=(int) display_image->rows;
15078 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
15079 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15080 (void) XSync(display,MagickFalse);
15081 /*
15082 Respond to events.
15083 */
15084 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15085 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15086 update_time=0;
15087 if (resource_info->update != MagickFalse )
15088 {
15089 MagickBooleanType
15090 status;
15091
15092 /*
15093 Determine when file data was last modified.
15094 */
15095 status=GetPathAttributes(display_image->filename,&attributes);
15096 if (status != MagickFalse )
15097 update_time=attributes.st_mtime;
15098 }
15099 *state&=(~FormerImageState);
15100 *state&=(~MontageImageState);
15101 *state&=(~NextImageState);
15102 do
15103 {
15104 /*
15105 Handle a window event.
15106 */
15107 if (windows->image.mapped != MagickFalse )
15108 if ((display_image->delay != 0) || (resource_info->update != 0))
15109 {
15110 if (timer < GetMagickTime())
15111 {
15112 if (resource_info->update == MagickFalse)
15113 *state|=NextImageState | ExitState;
15114 else
15115 {
15116 MagickBooleanType
15117 status;
15118
15119 /*
15120 Determine if image file was modified.
15121 */
15122 status=GetPathAttributes(display_image->filename,&attributes);
15123 if (status != MagickFalse )
15124 if (update_time != attributes.st_mtime)
15125 {
15126 /*
15127 Redisplay image.
15128 */
15129 (void) FormatLocaleString(
15130 resource_info->image_info->filename,MagickPathExtent,
15131 "%s:%s",display_image->magick,
15132 display_image->filename);
15133 nexus=ReadImage(resource_info->image_info,exception);
15134 if (nexus != (Image *) NULL)
15135 *state|=NextImageState | ExitState;
15136 }
15137 delay=display_image->delay/MagickMax(
15138 display_image->ticks_per_second,1L);
15139 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15140 }
15141 }
15142 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15143 {
15144 /*
15145 Do not block if delay > 0.
15146 */
15147 XDelay(display,SuspendTime << 2);
15148 continue;
15149 }
15150 }
15151 timestamp=GetMagickTime();
15152 (void) XNextEvent(display,&event);
15153 if ((windows->image.stasis == MagickFalse) ||
15154 (windows->magnify.stasis == MagickFalse))
15155 {
15156 if ((GetMagickTime()-timestamp) > 0)
15157 {
15158 windows->image.stasis=MagickTrue;
15159 windows->magnify.stasis=MagickTrue;
15160 }
15161 }
15162 if (event.xany.window == windows->command.id)
15163 {
15164 /*
15165 Select a command from the Command widget.
15166 */
15167 id=XCommandWidget(display,windows,CommandMenu,&event);
15168 if (id < 0)
15169 continue;
15170 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
15171 command_type=CommandMenus[id];
15172 if (id < MagickMenus)
15173 {
15174 /*
15175 Select a command from a pop-up menu.
15176 */
15177 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15178 command);
15179 if (entry < 0)
15180 continue;
15181 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
15182 command_type=Commands[id][entry];
15183 }
15184 if (command_type != NullCommand)
15185 nexus=XMagickCommand(display,resource_info,windows,command_type,
15186 &display_image,exception);
15187 continue;
15188 }
15189 switch (event.type)
15190 {
15191 case ButtonPress:
15192 {
15193 if (display_image->debug != MagickFalse )
15194 (void) LogMagickEvent(X11Event,GetMagickModule(),
15195 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15196 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15197 if ((event.xbutton.button == Button3) &&
15198 (event.xbutton.state & Mod1Mask))
15199 {
15200 /*
15201 Convert Alt-Button3 to Button2.
15202 */
15203 event.xbutton.button=Button2;
15204 event.xbutton.state&=(~Mod1Mask);
15205 }
15206 if (event.xbutton.window == windows->backdrop.id)
15207 {
15208 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15209 event.xbutton.time);
15210 break;
15211 }
15212 if (event.xbutton.window == windows->image.id)
15213 {
15214 switch (event.xbutton.button)
15215 {
15216 case Button1:
15217 {
15218 if (resource_info->immutable)
15219 {
15220 /*
15221 Select a command from the Virtual menu.
15222 */
15223 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15224 command);
15225 if (entry >= 0)
15226 nexus=XMagickCommand(display,resource_info,windows,
15227 VirtualCommands[entry],&display_image,exception);
15228 break;
15229 }
15230 /*
15231 Map/unmap Command widget.
15232 */
15233 if (windows->command.mapped != MagickFalse )
15234 (void) XWithdrawWindow(display,windows->command.id,
15235 windows->command.screen);
15236 else
15237 {
15238 (void) XCommandWidget(display,windows,CommandMenu,
15239 (XEvent *) NULL);
15240 (void) XMapRaised(display,windows->command.id);
15241 }
15242 break;
15243 }
15244 case Button2:
15245 {
15246 /*
15247 User pressed the image magnify button.
15248 */
15249 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15250 &display_image,exception);
15251 XMagnifyImage(display,windows,&event,exception);
15252 break;
15253 }
15254 case Button3:
15255 {
15256 if (resource_info->immutable)
15257 {
15258 /*
15259 Select a command from the Virtual menu.
15260 */
15261 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15262 command);
15263 if (entry >= 0)
15264 nexus=XMagickCommand(display,resource_info,windows,
15265 VirtualCommands[entry],&display_image,exception);
15266 break;
15267 }
15268 if (display_image->montage != (char *) NULL)
15269 {
15270 /*
15271 Open or delete a tile from a visual image directory.
15272 */
15273 nexus=XTileImage(display,resource_info,windows,
15274 display_image,&event,exception);
15275 if (nexus != (Image *) NULL)
15276 *state|=MontageImageState | NextImageState | ExitState;
15277 vid_info.x=(short int) windows->image.x;
15278 vid_info.y=(short int) windows->image.y;
15279 break;
15280 }
15281 /*
15282 Select a command from the Short Cuts menu.
15283 */
15284 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15285 command);
15286 if (entry >= 0)
15287 nexus=XMagickCommand(display,resource_info,windows,
15288 ShortCutsCommands[entry],&display_image,exception);
15289 break;
15290 }
15291 case Button4:
15292 {
15293 /*
15294 Wheel up.
15295 */
15296 XTranslateImage(display,windows,*image,XK_Up);
15297 break;
15298 }
15299 case Button5:
15300 {
15301 /*
15302 Wheel down.
15303 */
15304 XTranslateImage(display,windows,*image,XK_Down);
15305 break;
15306 }
15307 default:
15308 break;
15309 }
15310 break;
15311 }
15312 if (event.xbutton.window == windows->magnify.id)
15313 {
15314 const char
15315 *const MagnifyMenu[] =
15316 {
15317 "2",
15318 "4",
15319 "5",
15320 "6",
15321 "7",
15322 "8",
15323 "9",
15324 "3",
15325 (char *) NULL,
15326 };
15327
15328 int
15329 factor;
15330
15331 static KeySym
15332 MagnifyCommands[] =
15333 {
15334 XK_2,
15335 XK_4,
15336 XK_5,
15337 XK_6,
15338 XK_7,
15339 XK_8,
15340 XK_9,
15341 XK_3
15342 };
15343
15344 /*
15345 Select a magnify factor from the pop-up menu.
15346 */
15347 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15348 if (factor >= 0)
15349 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15350 exception);
15351 break;
15352 }
15353 if (event.xbutton.window == windows->pan.id)
15354 {
15355 switch (event.xbutton.button)
15356 {
15357 case Button4:
15358 {
15359 /*
15360 Wheel up.
15361 */
15362 XTranslateImage(display,windows,*image,XK_Up);
15363 break;
15364 }
15365 case Button5:
15366 {
15367 /*
15368 Wheel down.
15369 */
15370 XTranslateImage(display,windows,*image,XK_Down);
15371 break;
15372 }
15373 default:
15374 {
15375 XPanImage(display,windows,&event,exception);
15376 break;
15377 }
15378 }
15379 break;
15380 }
15381 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15382 1L);
15383 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15384 break;
15385 }
15386 case ButtonRelease:
15387 {
15388 if (display_image->debug != MagickFalse )
15389 (void) LogMagickEvent(X11Event,GetMagickModule(),
15390 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15391 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15392 break;
15393 }
15394 case ClientMessage:
15395 {
15396 if (display_image->debug != MagickFalse )
15397 (void) LogMagickEvent(X11Event,GetMagickModule(),
15398 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15399 event.xclient.message_type,event.xclient.format,(unsigned long)
15400 event.xclient.data.l[0]);
15401 if (event.xclient.message_type == windows->im_protocols)
15402 {
15403 if (*event.xclient.data.l == (long) windows->im_update_widget)
15404 {
15405 (void) CloneString(&windows->command.name,MagickTitle);
15406 windows->command.data=MagickMenus;
15407 (void) XCommandWidget(display,windows,CommandMenu,
15408 (XEvent *) NULL);
15409 break;
15410 }
15411 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15412 {
15413 /*
15414 Update graphic context and window colormap.
15415 */
15416 for (i=0; i < (int) number_windows; i++)
15417 {
15418 if (magick_windows[i]->id == windows->icon.id)
15419 continue;
15420 context_values.background=pixel->background_color.pixel;
15421 context_values.foreground=pixel->foreground_color.pixel;
15422 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15423 context_mask,&context_values);
15424 (void) XChangeGC(display,magick_windows[i]->widget_context,
15425 context_mask,&context_values);
15426 context_values.background=pixel->foreground_color.pixel;
15427 context_values.foreground=pixel->background_color.pixel;
15428 context_values.plane_mask=context_values.background ^
15429 context_values.foreground;
15430 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15431 (size_t) (context_mask | GCPlaneMask),
15432 &context_values);
15433 magick_windows[i]->attributes.background_pixel=
15434 pixel->background_color.pixel;
15435 magick_windows[i]->attributes.border_pixel=
15436 pixel->border_color.pixel;
15437 magick_windows[i]->attributes.colormap=map_info->colormap;
15438 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15439 (unsigned long) magick_windows[i]->mask,
15440 &magick_windows[i]->attributes);
15441 }
15442 if (windows->pan.mapped != MagickFalse )
15443 {
15444 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15445 windows->pan.pixmap);
15446 (void) XClearWindow(display,windows->pan.id);
15447 XDrawPanRectangle(display,windows);
15448 }
15449 if (windows->backdrop.id != (Window) NULL)
15450 (void) XInstallColormap(display,map_info->colormap);
15451 break;
15452 }
15453 if (*event.xclient.data.l == (long) windows->im_former_image)
15454 {
15455 *state|=FormerImageState | ExitState;
15456 break;
15457 }
15458 if (*event.xclient.data.l == (long) windows->im_next_image)
15459 {
15460 *state|=NextImageState | ExitState;
15461 break;
15462 }
15463 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15464 {
15465 *state|=RetainColorsState;
15466 break;
15467 }
15468 if (*event.xclient.data.l == (long) windows->im_exit)
15469 {
15470 *state|=ExitState;
15471 break;
15472 }
15473 break;
15474 }
15475 if (event.xclient.message_type == windows->dnd_protocols)
15476 {
15477 Atom
15478 selection,
15479 type;
15480
15481 int
15482 format,
15483 status;
15484
15485 unsigned char
15486 *data;
15487
15488 unsigned long
15489 after,
15490 length;
15491
15492 /*
15493 Display image named by the Drag-and-Drop selection.
15494 */
15495 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15496 break;
15497 selection=XInternAtom(display,"DndSelection",MagickFalse);
15498 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15499 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15500 &length,&after,&data);
15501 if ((status != Success) || (length == 0))
15502 break;
15503 if (*event.xclient.data.l == 2)
15504 {
15505 /*
15506 Offix DND.
15507 */
15508 (void) CopyMagickString(resource_info->image_info->filename,
15509 (char *) data,MagickPathExtent);
15510 }
15511 else
15512 {
15513 /*
15514 XDND.
15515 */
15516 if (strncmp((char *) data, "file:", 5) != 0)
15517 {
15518 (void) XFree((void *) data);
15519 break;
15520 }
15521 (void) CopyMagickString(resource_info->image_info->filename,
15522 ((char *) data)+5,MagickPathExtent);
15523 }
15524 nexus=ReadImage(resource_info->image_info,exception);
15525 CatchException(exception);
15526 if (nexus != (Image *) NULL)
15527 *state|=NextImageState | ExitState;
15528 (void) XFree((void *) data);
15529 break;
15530 }
15531 /*
15532 If client window delete message, exit.
15533 */
15534 if (event.xclient.message_type != windows->wm_protocols)
15535 break;
15536 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15537 break;
15538 (void) XWithdrawWindow(display,event.xclient.window,
15539 visual_info->screen);
15540 if (event.xclient.window == windows->image.id)
15541 {
15542 *state|=ExitState;
15543 break;
15544 }
15545 if (event.xclient.window == windows->pan.id)
15546 {
15547 /*
15548 Restore original image size when pan window is deleted.
15549 */
15550 windows->image.window_changes.width=windows->image.ximage->width;
15551 windows->image.window_changes.height=windows->image.ximage->height;
15552 (void) XConfigureImage(display,resource_info,windows,
15553 display_image,exception);
15554 }
15555 break;
15556 }
15557 case ConfigureNotify:
15558 {
15559 if (display_image->debug != MagickFalse )
15560 (void) LogMagickEvent(X11Event,GetMagickModule(),
15561 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15562 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15563 event.xconfigure.y,event.xconfigure.send_event);
15564 if (event.xconfigure.window == windows->image.id)
15565 {
15566 /*
15567 Image window has a new configuration.
15568 */
15569 if (event.xconfigure.send_event != 0)
15570 {
15571 XWindowChanges
15572 window_changes;
15573
15574 /*
15575 Position the transient windows relative of the Image window.
15576 */
15577 if (windows->command.geometry == (char *) NULL)
15578 if (windows->command.mapped == MagickFalse)
15579 {
15580 windows->command.x=event.xconfigure.x-
15581 windows->command.width-25;
15582 windows->command.y=event.xconfigure.y;
15583 XConstrainWindowPosition(display,&windows->command);
15584 window_changes.x=windows->command.x;
15585 window_changes.y=windows->command.y;
15586 (void) XReconfigureWMWindow(display,windows->command.id,
15587 windows->command.screen,(unsigned int) (CWX | CWY),
15588 &window_changes);
15589 }
15590 if (windows->widget.geometry == (char *) NULL)
15591 if (windows->widget.mapped == MagickFalse)
15592 {
15593 windows->widget.x=event.xconfigure.x+
15594 event.xconfigure.width/10;
15595 windows->widget.y=event.xconfigure.y+
15596 event.xconfigure.height/10;
15597 XConstrainWindowPosition(display,&windows->widget);
15598 window_changes.x=windows->widget.x;
15599 window_changes.y=windows->widget.y;
15600 (void) XReconfigureWMWindow(display,windows->widget.id,
15601 windows->widget.screen,(unsigned int) (CWX | CWY),
15602 &window_changes);
15603 }
15604 if (windows->magnify.geometry == (char *) NULL)
15605 if (windows->magnify.mapped == MagickFalse)
15606 {
15607 windows->magnify.x=event.xconfigure.x+
15608 event.xconfigure.width+25;
15609 windows->magnify.y=event.xconfigure.y;
15610 XConstrainWindowPosition(display,&windows->magnify);
15611 window_changes.x=windows->magnify.x;
15612 window_changes.y=windows->magnify.y;
15613 (void) XReconfigureWMWindow(display,windows->magnify.id,
15614 windows->magnify.screen,(unsigned int) (CWX | CWY),
15615 &window_changes);
15616 }
15617 if (windows->pan.geometry == (char *) NULL)
15618 if (windows->pan.mapped == MagickFalse)
15619 {
15620 windows->pan.x=event.xconfigure.x+
15621 event.xconfigure.width+25;
15622 windows->pan.y=event.xconfigure.y+
15623 windows->magnify.height+50;
15624 XConstrainWindowPosition(display,&windows->pan);
15625 window_changes.x=windows->pan.x;
15626 window_changes.y=windows->pan.y;
15627 (void) XReconfigureWMWindow(display,windows->pan.id,
15628 windows->pan.screen,(unsigned int) (CWX | CWY),
15629 &window_changes);
15630 }
15631 }
15632 if ((event.xconfigure.width == (int) windows->image.width) &&
15633 (event.xconfigure.height == (int) windows->image.height))
15634 break;
15635 windows->image.width=(unsigned int) event.xconfigure.width;
15636 windows->image.height=(unsigned int) event.xconfigure.height;
15637 windows->image.x=0;
15638 windows->image.y=0;
15639 if (display_image->montage != (char *) NULL)
15640 {
15641 windows->image.x=vid_info.x;
15642 windows->image.y=vid_info.y;
15643 }
15644 if (windows->image.mapped != MagickFalse &&
15645 windows->image.stasis != MagickFalse )
15646 {
15647 /*
15648 Update image window configuration.
15649 */
15650 windows->image.window_changes.width=event.xconfigure.width;
15651 windows->image.window_changes.height=event.xconfigure.height;
15652 (void) XConfigureImage(display,resource_info,windows,
15653 display_image,exception);
15654 }
15655 /*
15656 Update pan window configuration.
15657 */
15658 if ((event.xconfigure.width < windows->image.ximage->width) ||
15659 (event.xconfigure.height < windows->image.ximage->height))
15660 {
15661 (void) XMapRaised(display,windows->pan.id);
15662 XDrawPanRectangle(display,windows);
15663 }
15664 else
15665 if (windows->pan.mapped != MagickFalse )
15666 (void) XWithdrawWindow(display,windows->pan.id,
15667 windows->pan.screen);
15668 break;
15669 }
15670 if (event.xconfigure.window == windows->magnify.id)
15671 {
15672 unsigned int
15673 magnify;
15674
15675 /*
15676 Magnify window has a new configuration.
15677 */
15678 windows->magnify.width=(unsigned int) event.xconfigure.width;
15679 windows->magnify.height=(unsigned int) event.xconfigure.height;
15680 if (windows->magnify.mapped == MagickFalse)
15681 break;
15682 magnify=1;
15683 while ((int) magnify <= event.xconfigure.width)
15684 magnify<<=1;
15685 while ((int) magnify <= event.xconfigure.height)
15686 magnify<<=1;
15687 magnify>>=1;
15688 if (((int) magnify != event.xconfigure.width) ||
15689 ((int) magnify != event.xconfigure.height))
15690 {
15691 window_changes.width=(int) magnify;
15692 window_changes.height=(int) magnify;
15693 (void) XReconfigureWMWindow(display,windows->magnify.id,
15694 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15695 &window_changes);
15696 break;
15697 }
15698 if (windows->magnify.mapped != MagickFalse &&
15699 windows->magnify.stasis != MagickFalse )
15700 {
15701 status=XMakeImage(display,resource_info,&windows->magnify,
15702 display_image,windows->magnify.width,windows->magnify.height,
15703 exception);
15704 XMakeMagnifyImage(display,windows,exception);
15705 }
15706 break;
15707 }
15708 if (windows->magnify.mapped != MagickFalse &&
15709 (event.xconfigure.window == windows->pan.id))
15710 {
15711 /*
15712 Pan icon window has a new configuration.
15713 */
15714 if (event.xconfigure.send_event != 0)
15715 {
15716 windows->pan.x=event.xconfigure.x;
15717 windows->pan.y=event.xconfigure.y;
15718 }
15719 windows->pan.width=(unsigned int) event.xconfigure.width;
15720 windows->pan.height=(unsigned int) event.xconfigure.height;
15721 break;
15722 }
15723 if (event.xconfigure.window == windows->icon.id)
15724 {
15725 /*
15726 Icon window has a new configuration.
15727 */
15728 windows->icon.width=(unsigned int) event.xconfigure.width;
15729 windows->icon.height=(unsigned int) event.xconfigure.height;
15730 break;
15731 }
15732 break;
15733 }
15734 case DestroyNotify:
15735 {
15736 /*
15737 Group leader has exited.
15738 */
15739 if (display_image->debug != MagickFalse )
15740 (void) LogMagickEvent(X11Event,GetMagickModule(),
15741 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15742 if (event.xdestroywindow.window == windows->group_leader.id)
15743 {
15744 *state|=ExitState;
15745 break;
15746 }
15747 break;
15748 }
15749 case EnterNotify:
15750 {
15751 /*
15752 Selectively install colormap.
15753 */
15754 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15755 if (event.xcrossing.mode != NotifyUngrab)
15756 XInstallColormap(display,map_info->colormap);
15757 break;
15758 }
15759 case Expose:
15760 {
15761 if (display_image->debug != MagickFalse )
15762 (void) LogMagickEvent(X11Event,GetMagickModule(),
15763 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15764 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15765 event.xexpose.y);
15766 /*
15767 Refresh windows that are now exposed.
15768 */
15769 if ((event.xexpose.window == windows->image.id) &&
15770 windows->image.mapped != MagickFalse )
15771 {
15772 XRefreshWindow(display,&windows->image,&event);
15773 delay=display_image->delay/MagickMax(
15774 display_image->ticks_per_second,1L);
15775 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15776 break;
15777 }
15778 if ((event.xexpose.window == windows->magnify.id) &&
15779 windows->magnify.mapped != MagickFalse)
15780 {
15781 XMakeMagnifyImage(display,windows,exception);
15782 break;
15783 }
15784 if (event.xexpose.window == windows->pan.id)
15785 {
15786 XDrawPanRectangle(display,windows);
15787 break;
15788 }
15789 if (event.xexpose.window == windows->icon.id)
15790 {
15791 XRefreshWindow(display,&windows->icon,&event);
15792 break;
15793 }
15794 break;
15795 }
15796 case KeyPress:
15797 {
15798 int
15799 length;
15800
15801 /*
15802 Respond to a user key press.
15803 */
15804 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15805 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15806 *(command+length)='\0';
15807 if (display_image->debug != MagickFalse )
15808 (void) LogMagickEvent(X11Event,GetMagickModule(),
15809 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15810 key_symbol,command);
15811 if (event.xkey.window == windows->image.id)
15812 {
15813 command_type=XImageWindowCommand(display,resource_info,windows,
15814 event.xkey.state,key_symbol,&display_image,exception);
15815 if (command_type != NullCommand)
15816 nexus=XMagickCommand(display,resource_info,windows,command_type,
15817 &display_image,exception);
15818 }
15819 if (event.xkey.window == windows->magnify.id)
15820 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15821 exception);
15822 if (event.xkey.window == windows->pan.id)
15823 {
15824 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15825 (void) XWithdrawWindow(display,windows->pan.id,
15826 windows->pan.screen);
15827 else
15828 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15829 XTextViewHelp(display,resource_info,windows,MagickFalse,
15830 "Help Viewer - Image Pan",ImagePanHelp);
15831 else
15832 XTranslateImage(display,windows,*image,key_symbol);
15833 }
15834 delay=display_image->delay/MagickMax(
15835 display_image->ticks_per_second,1L);
15836 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15837 break;
15838 }
15839 case KeyRelease:
15840 {
15841 /*
15842 Respond to a user key release.
15843 */
15844 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15845 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15846 if (display_image->debug != MagickFalse )
15847 (void) LogMagickEvent(X11Event,GetMagickModule(),
15848 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15849 break;
15850 }
15851 case LeaveNotify:
15852 {
15853 /*
15854 Selectively uninstall colormap.
15855 */
15856 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15857 if (event.xcrossing.mode != NotifyUngrab)
15858 XUninstallColormap(display,map_info->colormap);
15859 break;
15860 }
15861 case MapNotify:
15862 {
15863 if (display_image->debug != MagickFalse )
15864 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15865 event.xmap.window);
15866 if (event.xmap.window == windows->backdrop.id)
15867 {
15868 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15869 CurrentTime);
15870 windows->backdrop.mapped=MagickTrue;
15871 break;
15872 }
15873 if (event.xmap.window == windows->image.id)
15874 {
15875 if (windows->backdrop.id != (Window) NULL)
15876 (void) XInstallColormap(display,map_info->colormap);
15877 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15878 {
15879 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15880 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15881 }
15882 if (((int) windows->image.width < windows->image.ximage->width) ||
15883 ((int) windows->image.height < windows->image.ximage->height))
15884 (void) XMapRaised(display,windows->pan.id);
15885 windows->image.mapped=MagickTrue;
15886 break;
15887 }
15888 if (event.xmap.window == windows->magnify.id)
15889 {
15890 XMakeMagnifyImage(display,windows,exception);
15891 windows->magnify.mapped=MagickTrue;
15892 (void) XWithdrawWindow(display,windows->info.id,
15893 windows->info.screen);
15894 break;
15895 }
15896 if (event.xmap.window == windows->pan.id)
15897 {
15898 XMakePanImage(display,resource_info,windows,display_image,
15899 exception);
15900 windows->pan.mapped=MagickTrue;
15901 break;
15902 }
15903 if (event.xmap.window == windows->info.id)
15904 {
15905 windows->info.mapped=MagickTrue;
15906 break;
15907 }
15908 if (event.xmap.window == windows->icon.id)
15909 {
15910 MagickBooleanType
15911 taint;
15912
15913 /*
15914 Create an icon image.
15915 */
15916 taint=display_image->taint;
15917 XMakeStandardColormap(display,icon_visual,icon_resources,
15918 display_image,icon_map,icon_pixel,exception);
15919 (void) XMakeImage(display,icon_resources,&windows->icon,
15920 display_image,windows->icon.width,windows->icon.height,
15921 exception);
15922 display_image->taint=taint;
15923 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15924 windows->icon.pixmap);
15925 (void) XClearWindow(display,windows->icon.id);
15926 (void) XWithdrawWindow(display,windows->info.id,
15927 windows->info.screen);
15928 windows->icon.mapped=MagickTrue;
15929 break;
15930 }
15931 if (event.xmap.window == windows->command.id)
15932 {
15933 windows->command.mapped=MagickTrue;
15934 break;
15935 }
15936 if (event.xmap.window == windows->popup.id)
15937 {
15938 windows->popup.mapped=MagickTrue;
15939 break;
15940 }
15941 if (event.xmap.window == windows->widget.id)
15942 {
15943 windows->widget.mapped=MagickTrue;
15944 break;
15945 }
15946 break;
15947 }
15948 case MappingNotify:
15949 {
15950 (void) XRefreshKeyboardMapping(&event.xmapping);
15951 break;
15952 }
15953 case NoExpose:
15954 break;
15955 case PropertyNotify:
15956 {
15957 Atom
15958 type;
15959
15960 int
15961 format,
15962 status;
15963
15964 unsigned char
15965 *data;
15966
15967 unsigned long
15968 after,
15969 length;
15970
15971 if (display_image->debug != MagickFalse )
15972 (void) LogMagickEvent(X11Event,GetMagickModule(),
15973 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15974 event.xproperty.atom,event.xproperty.state);
15975 if (event.xproperty.atom != windows->im_remote_command)
15976 break;
15977 /*
15978 Display image named by the remote command protocol.
15979 */
15980 status=XGetWindowProperty(display,event.xproperty.window,
15981 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
15982 AnyPropertyType,&type,&format,&length,&after,&data);
15983 if ((status != Success) || (length == 0))
15984 break;
15985 if (LocaleCompare((char *) data,"-quit") == 0)
15986 {
15987 XClientMessage(display,windows->image.id,windows->im_protocols,
15988 windows->im_exit,CurrentTime);
15989 (void) XFree((void *) data);
15990 break;
15991 }
15992 (void) CopyMagickString(resource_info->image_info->filename,
15993 (char *) data,MagickPathExtent);
15994 (void) XFree((void *) data);
15995 nexus=ReadImage(resource_info->image_info,exception);
15996 CatchException(exception);
15997 if (nexus != (Image *) NULL)
15998 *state|=NextImageState | ExitState;
15999 break;
16000 }
16001 case ReparentNotify:
16002 {
16003 if (display_image->debug != MagickFalse )
16004 (void) LogMagickEvent(X11Event,GetMagickModule(),
16005 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
16006 event.xreparent.window);
16007 break;
16008 }
16009 case UnmapNotify:
16010 {
16011 if (display_image->debug != MagickFalse )
16012 (void) LogMagickEvent(X11Event,GetMagickModule(),
16013 "Unmap Notify: 0x%lx",event.xunmap.window);
16014 if (event.xunmap.window == windows->backdrop.id)
16015 {
16016 windows->backdrop.mapped=MagickFalse;
16017 break;
16018 }
16019 if (event.xunmap.window == windows->image.id)
16020 {
16021 windows->image.mapped=MagickFalse;
16022 break;
16023 }
16024 if (event.xunmap.window == windows->magnify.id)
16025 {
16026 windows->magnify.mapped=MagickFalse;
16027 break;
16028 }
16029 if (event.xunmap.window == windows->pan.id)
16030 {
16031 windows->pan.mapped=MagickFalse;
16032 break;
16033 }
16034 if (event.xunmap.window == windows->info.id)
16035 {
16036 windows->info.mapped=MagickFalse;
16037 break;
16038 }
16039 if (event.xunmap.window == windows->icon.id)
16040 {
16041 if (map_info->colormap == icon_map->colormap)
16042 XConfigureImageColormap(display,resource_info,windows,
16043 display_image,exception);
16044 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16045 icon_pixel);
16046 windows->icon.mapped=MagickFalse;
16047 break;
16048 }
16049 if (event.xunmap.window == windows->command.id)
16050 {
16051 windows->command.mapped=MagickFalse;
16052 break;
16053 }
16054 if (event.xunmap.window == windows->popup.id)
16055 {
16056 if (windows->backdrop.id != (Window) NULL)
16057 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16058 CurrentTime);
16059 windows->popup.mapped=MagickFalse;
16060 break;
16061 }
16062 if (event.xunmap.window == windows->widget.id)
16063 {
16064 if (windows->backdrop.id != (Window) NULL)
16065 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16066 CurrentTime);
16067 windows->widget.mapped=MagickFalse;
16068 break;
16069 }
16070 break;
16071 }
16072 default:
16073 {
16074 if (display_image->debug != MagickFalse )
16075 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16076 event.type);
16077 break;
16078 }
16079 }
16080 } while (!(*state & ExitState));
16081 if ((*state & ExitState) == 0)
16082 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
16083 &display_image,exception);
16084 else
16085 if (resource_info->confirm_edit != MagickFalse )
16086 {
16087 /*
16088 Query user if image has changed.
16089 */
16090 if ((resource_info->immutable == MagickFalse) &&
16091 display_image->taint != MagickFalse)
16092 {
16093 int
16094 status;
16095
16096 status=XConfirmWidget(display,windows,"Your image changed.",
16097 "Do you want to save it");
16098 if (status == 0)
16099 *state&=(~ExitState);
16100 else
16101 if (status > 0)
16102 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
16103 &display_image,exception);
16104 }
16105 }
16106 if ((windows->visual_info->klass == GrayScale) ||
16107 (windows->visual_info->klass == PseudoColor) ||
16108 (windows->visual_info->klass == DirectColor))
16109 {
16110 /*
16111 Withdraw pan and Magnify window.
16112 */
16113 if (windows->info.mapped != MagickFalse )
16114 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16115 if (windows->magnify.mapped != MagickFalse )
16116 (void) XWithdrawWindow(display,windows->magnify.id,
16117 windows->magnify.screen);
16118 if (windows->command.mapped != MagickFalse )
16119 (void) XWithdrawWindow(display,windows->command.id,
16120 windows->command.screen);
16121 }
16122 if (windows->pan.mapped != MagickFalse )
16123 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16124 if (resource_info->backdrop == MagickFalse)
16125 if (windows->backdrop.mapped)
16126 {
16127 (void) XWithdrawWindow(display,windows->backdrop.id,
16128 windows->backdrop.screen);
16129 (void) XDestroyWindow(display,windows->backdrop.id);
16130 windows->backdrop.id=(Window) NULL;
16131 (void) XWithdrawWindow(display,windows->image.id,
16132 windows->image.screen);
16133 (void) XDestroyWindow(display,windows->image.id);
16134 windows->image.id=(Window) NULL;
16135 }
16136 XSetCursorState(display,windows,MagickTrue);
16137 XCheckRefreshWindows(display,windows);
16138 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16139 *state&=(~ExitState);
16140 if (*state & ExitState)
16141 {
16142 /*
16143 Free Standard Colormap.
16144 */
16145 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16146 if (resource_info->map_type == (char *) NULL)
16147 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16148 /*
16149 Free X resources.
16150 */
16151 if (resource_info->copy_image != (Image *) NULL)
16152 {
16153 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16154 resource_info->copy_image=NewImageList();
16155 }
16156 DestroyXResources();
16157 }
16158 (void) XSync(display,MagickFalse);
16159 /*
16160 Restore our progress monitor and warning handlers.
16161 */
16162 (void) SetErrorHandler(warning_handler);
16163 (void) SetWarningHandler(warning_handler);
16164 /*
16165 Change to home directory.
16166 */
16167 directory=getcwd(working_directory,MagickPathExtent);
16168 (void) directory;
16169 {
16170 int
16171 status;
16172
16173 if (*resource_info->home_directory == '\0')
16174 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
16175 status=chdir(resource_info->home_directory);
16176 if (status == -1)
16177 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16178 "UnableToOpenFile","%s",resource_info->home_directory);
16179 }
16180 *image=display_image;
16181 return(nexus);
16182 }
16183 #else
16184
16185 /*
16186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16187 % %
16188 % %
16189 % %
16190 + D i s p l a y I m a g e s %
16191 % %
16192 % %
16193 % %
16194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16195 %
16196 % DisplayImages() displays an image sequence to any X window screen. It
16197 % returns a value other than 0 if successful. Check the exception member
16198 % of image to determine the reason for any failure.
16199 %
16200 % The format of the DisplayImages method is:
16201 %
16202 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16203 % Image *images,ExceptionInfo *exception)
16204 %
16205 % A description of each parameter follows:
16206 %
16207 % o image_info: the image info.
16208 %
16209 % o image: the image.
16210 %
16211 % o exception: return any errors or warnings in this structure.
16212 %
16213 */
DisplayImages(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)16214 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16215 Image *image,ExceptionInfo *exception)
16216 {
16217 assert(image_info != (const ImageInfo *) NULL);
16218 assert(image_info->signature == MagickCoreSignature);
16219 assert(image != (Image *) NULL);
16220 assert(image->signature == MagickCoreSignature);
16221 (void) image_info;
16222 if (image->debug != MagickFalse )
16223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16224 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16225 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
16226 return(MagickFalse);
16227 }
16228
16229 /*
16230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16231 % %
16232 % %
16233 % %
16234 + R e m o t e D i s p l a y C o m m a n d %
16235 % %
16236 % %
16237 % %
16238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16239 %
16240 % RemoteDisplayCommand() encourages a remote display program to display the
16241 % specified image filename.
16242 %
16243 % The format of the RemoteDisplayCommand method is:
16244 %
16245 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16246 % const char *window,const char *filename,ExceptionInfo *exception)
16247 %
16248 % A description of each parameter follows:
16249 %
16250 % o image_info: the image info.
16251 %
16252 % o window: Specifies the name or id of an X window.
16253 %
16254 % o filename: the name of the image filename to display.
16255 %
16256 % o exception: return any errors or warnings in this structure.
16257 %
16258 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)16259 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16260 const char *window,const char *filename,ExceptionInfo *exception)
16261 {
16262 assert(image_info != (const ImageInfo *) NULL);
16263 assert(image_info->signature == MagickCoreSignature);
16264 assert(filename != (char *) NULL);
16265 (void) window;
16266 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16267 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16268 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
16269 return(MagickFalse);
16270 }
16271 #endif
16272