1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % DDDD IIIII SSSSS PPPP L AAA Y Y %
7 % D D I SS P P L A A Y Y %
8 % D D I SSS PPPP L AAAAA Y %
9 % D D I SS P L A A Y %
10 % DDDD IIIII SSSSS P LLLLL A A Y %
11 % %
12 % %
13 % MagickCore Methods to Interactively Display and Edit an Image %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/artifact.h"
44 #include "magick/attribute.h"
45 #include "magick/blob.h"
46 #include "magick/cache.h"
47 #include "magick/channel.h"
48 #include "magick/client.h"
49 #include "magick/color.h"
50 #include "magick/colorspace.h"
51 #include "magick/composite.h"
52 #include "magick/constitute.h"
53 #include "magick/decorate.h"
54 #include "magick/delegate.h"
55 #include "magick/display.h"
56 #include "magick/display-private.h"
57 #include "magick/distort.h"
58 #include "magick/draw.h"
59 #include "magick/effect.h"
60 #include "magick/enhance.h"
61 #include "magick/exception.h"
62 #include "magick/exception-private.h"
63 #include "magick/fx.h"
64 #include "magick/geometry.h"
65 #include "magick/image.h"
66 #include "magick/image-private.h"
67 #include "magick/list.h"
68 #include "magick/log.h"
69 #include "magick/magick.h"
70 #include "magick/memory_.h"
71 #include "magick/monitor.h"
72 #include "magick/monitor-private.h"
73 #include "magick/montage.h"
74 #include "magick/nt-base-private.h"
75 #include "magick/option.h"
76 #include "magick/paint.h"
77 #include "magick/pixel.h"
78 #include "magick/pixel-private.h"
79 #include "magick/property.h"
80 #include "magick/quantum.h"
81 #include "magick/resize.h"
82 #include "magick/resource_.h"
83 #include "magick/shear.h"
84 #include "magick/segment.h"
85 #include "magick/statistic.h"
86 #include "magick/string_.h"
87 #include "magick/string-private.h"
88 #include "magick/timer-private.h"
89 #include "magick/transform.h"
90 #include "magick/threshold.h"
91 #include "magick/utility.h"
92 #include "magick/utility-private.h"
93 #include "magick/version.h"
94 #include "magick/visual-effects.h"
95 #include "magick/widget.h"
96 #include "magick/xwindow-private.h"
97
98 #if defined(MAGICKCORE_X11_DELEGATE)
99 /*
100 Define declarations.
101 */
102 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
103
104 /*
105 Constant declarations.
106 */
107 static const unsigned char
108 HighlightBitmap[8] =
109 {
110 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
111 },
112 OpaqueBitmap[8] =
113 {
114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
115 },
116 ShadowBitmap[8] =
117 {
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
119 };
120
121 /*
122 Help widget declarations.
123 */
124 static const char
125 ImageAnnotateHelp[] =
126 {
127 "In annotate mode, the Command widget has these options:\n"
128 "\n"
129 " Font Name\n"
130 " fixed\n"
131 " variable\n"
132 " 5x8\n"
133 " 6x10\n"
134 " 7x13bold\n"
135 " 8x13bold\n"
136 " 9x15bold\n"
137 " 10x20\n"
138 " 12x24\n"
139 " Browser...\n"
140 " Font Color\n"
141 " black\n"
142 " blue\n"
143 " cyan\n"
144 " green\n"
145 " gray\n"
146 " red\n"
147 " magenta\n"
148 " yellow\n"
149 " white\n"
150 " transparent\n"
151 " Browser...\n"
152 " Font Color\n"
153 " black\n"
154 " blue\n"
155 " cyan\n"
156 " green\n"
157 " gray\n"
158 " red\n"
159 " magenta\n"
160 " yellow\n"
161 " white\n"
162 " transparent\n"
163 " Browser...\n"
164 " Rotate Text\n"
165 " -90\n"
166 " -45\n"
167 " -30\n"
168 " 0\n"
169 " 30\n"
170 " 45\n"
171 " 90\n"
172 " 180\n"
173 " Dialog...\n"
174 " Help\n"
175 " Dismiss\n"
176 "\n"
177 "Choose a font name from the Font Name sub-menu. Additional\n"
178 "font names can be specified with the font browser. You can\n"
179 "change the menu names by setting the X resources font1\n"
180 "through font9.\n"
181 "\n"
182 "Choose a font color from the Font Color sub-menu.\n"
183 "Additional font colors can be specified with the color\n"
184 "browser. You can change the menu colors by setting the X\n"
185 "resources pen1 through pen9.\n"
186 "\n"
187 "If you select the color browser and press Grab, you can\n"
188 "choose the font color by moving the pointer to the desired\n"
189 "color on the screen and press any button.\n"
190 "\n"
191 "If you choose to rotate the text, choose Rotate Text from the\n"
192 "menu and select an angle. Typically you will only want to\n"
193 "rotate one line of text at a time. Depending on the angle you\n"
194 "choose, subsequent lines may end up overwriting each other.\n"
195 "\n"
196 "Choosing a font and its color is optional. The default font\n"
197 "is fixed and the default color is black. However, you must\n"
198 "choose a location to begin entering text and press button 1.\n"
199 "An underscore character will appear at the location of the\n"
200 "pointer. The cursor changes to a pencil to indicate you are\n"
201 "in text mode. To exit immediately, press Dismiss.\n"
202 "\n"
203 "In text mode, any key presses will display the character at\n"
204 "the location of the underscore and advance the underscore\n"
205 "cursor. Enter your text and once completed press Apply to\n"
206 "finish your image annotation. To correct errors press BACK\n"
207 "SPACE. To delete an entire line of text, press DELETE. Any\n"
208 "text that exceeds the boundaries of the image window is\n"
209 "automagically continued onto the next line.\n"
210 "\n"
211 "The actual color you request for the font is saved in the\n"
212 "image. However, the color that appears in your image window\n"
213 "may be different. For example, on a monochrome screen the\n"
214 "text will appear black or white even if you choose the color\n"
215 "red as the font color. However, the image saved to a file\n"
216 "with -write is written with red lettering. To assure the\n"
217 "correct color text in the final image, any PseudoClass image\n"
218 "is promoted to DirectClass (see miff(5)). To force a\n"
219 "PseudoClass image to remain PseudoClass, use -colors.\n"
220 },
221 ImageChopHelp[] =
222 {
223 "In chop mode, the Command widget has these options:\n"
224 "\n"
225 " Direction\n"
226 " horizontal\n"
227 " vertical\n"
228 " Help\n"
229 " Dismiss\n"
230 "\n"
231 "If the you choose the horizontal direction (this the\n"
232 "default), the area of the image between the two horizontal\n"
233 "endpoints of the chop line is removed. Otherwise, the area\n"
234 "of the image between the two vertical endpoints of the chop\n"
235 "line is removed.\n"
236 "\n"
237 "Select a location within the image window to begin your chop,\n"
238 "press and hold any button. Next, move the pointer to\n"
239 "another location in the image. As you move a line will\n"
240 "connect the initial location and the pointer. When you\n"
241 "release the button, the area within the image to chop is\n"
242 "determined by which direction you choose from the Command\n"
243 "widget.\n"
244 "\n"
245 "To cancel the image chopping, move the pointer back to the\n"
246 "starting point of the line and release the button.\n"
247 },
248 ImageColorEditHelp[] =
249 {
250 "In color edit mode, the Command widget has these options:\n"
251 "\n"
252 " Method\n"
253 " point\n"
254 " replace\n"
255 " floodfill\n"
256 " filltoborder\n"
257 " reset\n"
258 " Pixel Color\n"
259 " black\n"
260 " blue\n"
261 " cyan\n"
262 " green\n"
263 " gray\n"
264 " red\n"
265 " magenta\n"
266 " yellow\n"
267 " white\n"
268 " Browser...\n"
269 " Border Color\n"
270 " black\n"
271 " blue\n"
272 " cyan\n"
273 " green\n"
274 " gray\n"
275 " red\n"
276 " magenta\n"
277 " yellow\n"
278 " white\n"
279 " Browser...\n"
280 " Fuzz\n"
281 " 0%\n"
282 " 2%\n"
283 " 5%\n"
284 " 10%\n"
285 " 15%\n"
286 " Dialog...\n"
287 " Undo\n"
288 " Help\n"
289 " Dismiss\n"
290 "\n"
291 "Choose a color editing method from the Method sub-menu\n"
292 "of the Command widget. The point method recolors any pixel\n"
293 "selected with the pointer until the button is released. The\n"
294 "replace method recolors any pixel that matches the color of\n"
295 "the pixel you select with a button press. Floodfill recolors\n"
296 "any pixel that matches the color of the pixel you select with\n"
297 "a button press and is a neighbor. Whereas filltoborder recolors\n"
298 "any neighbor pixel that is not the border color. Finally reset\n"
299 "changes the entire image to the designated color.\n"
300 "\n"
301 "Next, choose a pixel color from the Pixel Color sub-menu.\n"
302 "Additional pixel colors can be specified with the color\n"
303 "browser. You can change the menu colors by setting the X\n"
304 "resources pen1 through pen9.\n"
305 "\n"
306 "Now press button 1 to select a pixel within the image window\n"
307 "to change its color. Additional pixels may be recolored as\n"
308 "prescribed by the method you choose.\n"
309 "\n"
310 "If the Magnify widget is mapped, it can be helpful in positioning\n"
311 "your pointer within the image (refer to button 2).\n"
312 "\n"
313 "The actual color you request for the pixels is saved in the\n"
314 "image. However, the color that appears in your image window\n"
315 "may be different. For example, on a monochrome screen the\n"
316 "pixel will appear black or white even if you choose the\n"
317 "color red as the pixel color. However, the image saved to a\n"
318 "file with -write is written with red pixels. To assure the\n"
319 "correct color text in the final image, any PseudoClass image\n"
320 "is promoted to DirectClass (see miff(5)). To force a\n"
321 "PseudoClass image to remain PseudoClass, use -colors.\n"
322 },
323 ImageCompositeHelp[] =
324 {
325 "First a widget window is displayed requesting you to enter an\n"
326 "image name. Press Composite, Grab or type a file name.\n"
327 "Press Cancel if you choose not to create a composite image.\n"
328 "When you choose Grab, move the pointer to the desired window\n"
329 "and press any button.\n"
330 "\n"
331 "If the Composite image does not have any matte information,\n"
332 "you are informed and the file browser is displayed again.\n"
333 "Enter the name of a mask image. The image is typically\n"
334 "grayscale and the same size as the composite image. If the\n"
335 "image is not grayscale, it is converted to grayscale and the\n"
336 "resulting intensities are used as matte information.\n"
337 "\n"
338 "A small window appears showing the location of the cursor in\n"
339 "the image window. You are now in composite mode. To exit\n"
340 "immediately, press Dismiss. In composite mode, the Command\n"
341 "widget has these options:\n"
342 "\n"
343 " Operators\n"
344 " Over\n"
345 " In\n"
346 " Out\n"
347 " Atop\n"
348 " Xor\n"
349 " Plus\n"
350 " Minus\n"
351 " Add\n"
352 " Subtract\n"
353 " Difference\n"
354 " Multiply\n"
355 " Bumpmap\n"
356 " Copy\n"
357 " CopyRed\n"
358 " CopyGreen\n"
359 " CopyBlue\n"
360 " CopyOpacity\n"
361 " Clear\n"
362 " Dissolve\n"
363 " Displace\n"
364 " Help\n"
365 " Dismiss\n"
366 "\n"
367 "Choose a composite operation from the Operators sub-menu of\n"
368 "the Command widget. How each operator behaves is described\n"
369 "below. Image window is the image currently displayed on\n"
370 "your X server and image is the image obtained with the File\n"
371 "Browser widget.\n"
372 "\n"
373 "Over The result is the union of the two image shapes,\n"
374 " with image obscuring image window in the region of\n"
375 " overlap.\n"
376 "\n"
377 "In The result is simply image cut by the shape of\n"
378 " image window. None of the image data of image\n"
379 " window is in the result.\n"
380 "\n"
381 "Out The resulting image is image with the shape of\n"
382 " image window cut out.\n"
383 "\n"
384 "Atop The result is the same shape as image image window,\n"
385 " with image obscuring image window where the image\n"
386 " shapes overlap. Note this differs from over\n"
387 " because the portion of image outside image window's\n"
388 " shape does not appear in the result.\n"
389 "\n"
390 "Xor The result is the image data from both image and\n"
391 " image window that is outside the overlap region.\n"
392 " The overlap region is blank.\n"
393 "\n"
394 "Plus The result is just the sum of the image data.\n"
395 " Output values are cropped to QuantumRange (no overflow).\n"
396 "\n"
397 "Minus The result of image - image window, with underflow\n"
398 " cropped to zero.\n"
399 "\n"
400 "Add The result of image + image window, with overflow\n"
401 " wrapping around (mod 256).\n"
402 "\n"
403 "Subtract The result of image - image window, with underflow\n"
404 " wrapping around (mod 256). The add and subtract\n"
405 " operators can be used to perform reversible\n"
406 " transformations.\n"
407 "\n"
408 "Difference\n"
409 " The result of abs(image - image window). This\n"
410 " useful for comparing two very similar images.\n"
411 "\n"
412 "Multiply\n"
413 " The result of image * image window. This\n"
414 " useful for the creation of drop-shadows.\n"
415 "\n"
416 "Bumpmap The result of surface normals from image * image\n"
417 " window.\n"
418 "\n"
419 "Copy The resulting image is image window replaced with\n"
420 " image. Here the matte information is ignored.\n"
421 "\n"
422 "CopyRed The red layer of the image window is replace with\n"
423 " the red layer of the image. The other layers are\n"
424 " untouched.\n"
425 "\n"
426 "CopyGreen\n"
427 " The green layer of the image window is replace with\n"
428 " the green layer of the image. The other layers are\n"
429 " untouched.\n"
430 "\n"
431 "CopyBlue The blue layer of the image window is replace with\n"
432 " the blue layer of the image. The other layers are\n"
433 " untouched.\n"
434 "\n"
435 "CopyOpacity\n"
436 " The matte layer of the image window is replace with\n"
437 " the matte layer of the image. The other layers are\n"
438 " untouched.\n"
439 "\n"
440 "The image compositor requires a matte, or alpha channel in\n"
441 "the image for some operations. This extra channel usually\n"
442 "defines a mask which represents a sort of a cookie-cutter\n"
443 "for the image. This the case when matte is opaque (full\n"
444 "coverage) for pixels inside the shape, zero outside, and\n"
445 "between 0 and QuantumRange on the boundary. If image does not\n"
446 "have a matte channel, it is initialized with 0 for any pixel\n"
447 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
448 "\n"
449 "If you choose Dissolve, the composite operator becomes Over. The\n"
450 "image matte channel percent transparency is initialized to factor.\n"
451 "The image window is initialized to (100-factor). Where factor is the\n"
452 "value you specify in the Dialog widget.\n"
453 "\n"
454 "Displace shifts the image pixels as defined by a displacement\n"
455 "map. With this option, image is used as a displacement map.\n"
456 "Black, within the displacement map, is a maximum positive\n"
457 "displacement. White is a maximum negative displacement and\n"
458 "middle gray is neutral. The displacement is scaled to determine\n"
459 "the pixel shift. By default, the displacement applies in both the\n"
460 "horizontal and vertical directions. However, if you specify a mask,\n"
461 "image is the horizontal X displacement and mask the vertical Y\n"
462 "displacement.\n"
463 "\n"
464 "Note that matte information for image window is not retained\n"
465 "for colormapped X server visuals (e.g. StaticColor,\n"
466 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
467 "behavior may require a TrueColor or DirectColor visual or a\n"
468 "Standard Colormap.\n"
469 "\n"
470 "Choosing a composite operator is optional. The default\n"
471 "operator is replace. However, you must choose a location to\n"
472 "composite your image and press button 1. Press and hold the\n"
473 "button before releasing and an outline of the image will\n"
474 "appear to help you identify your location.\n"
475 "\n"
476 "The actual colors of the composite image is saved. However,\n"
477 "the color that appears in image window may be different.\n"
478 "For example, on a monochrome screen image window will appear\n"
479 "black or white even though your composited image may have\n"
480 "many colors. If the image is saved to a file it is written\n"
481 "with the correct colors. To assure the correct colors are\n"
482 "saved in the final image, any PseudoClass image is promoted\n"
483 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
484 "to remain PseudoClass, use -colors.\n"
485 },
486 ImageCutHelp[] =
487 {
488 "In cut mode, the Command widget has these options:\n"
489 "\n"
490 " Help\n"
491 " Dismiss\n"
492 "\n"
493 "To define a cut region, press button 1 and drag. The\n"
494 "cut region is defined by a highlighted rectangle that\n"
495 "expands or contracts as it follows the pointer. Once you\n"
496 "are satisfied with the cut region, release the button.\n"
497 "You are now in rectify mode. In rectify mode, the Command\n"
498 "widget has these options:\n"
499 "\n"
500 " Cut\n"
501 " Help\n"
502 " Dismiss\n"
503 "\n"
504 "You can make adjustments by moving the pointer to one of the\n"
505 "cut rectangle corners, pressing a button, and dragging.\n"
506 "Finally, press Cut to commit your copy region. To\n"
507 "exit without cutting the image, press Dismiss.\n"
508 },
509 ImageCopyHelp[] =
510 {
511 "In copy mode, the Command widget has these options:\n"
512 "\n"
513 " Help\n"
514 " Dismiss\n"
515 "\n"
516 "To define a copy region, press button 1 and drag. The\n"
517 "copy region is defined by a highlighted rectangle that\n"
518 "expands or contracts as it follows the pointer. Once you\n"
519 "are satisfied with the copy region, release the button.\n"
520 "You are now in rectify mode. In rectify mode, the Command\n"
521 "widget has these options:\n"
522 "\n"
523 " Copy\n"
524 " Help\n"
525 " Dismiss\n"
526 "\n"
527 "You can make adjustments by moving the pointer to one of the\n"
528 "copy rectangle corners, pressing a button, and dragging.\n"
529 "Finally, press Copy to commit your copy region. To\n"
530 "exit without copying the image, press Dismiss.\n"
531 },
532 ImageCropHelp[] =
533 {
534 "In crop mode, the Command widget has these options:\n"
535 "\n"
536 " Help\n"
537 " Dismiss\n"
538 "\n"
539 "To define a cropping region, press button 1 and drag. The\n"
540 "cropping region is defined by a highlighted rectangle that\n"
541 "expands or contracts as it follows the pointer. Once you\n"
542 "are satisfied with the cropping region, release the button.\n"
543 "You are now in rectify mode. In rectify mode, the Command\n"
544 "widget has these options:\n"
545 "\n"
546 " Crop\n"
547 " Help\n"
548 " Dismiss\n"
549 "\n"
550 "You can make adjustments by moving the pointer to one of the\n"
551 "cropping rectangle corners, pressing a button, and dragging.\n"
552 "Finally, press Crop to commit your cropping region. To\n"
553 "exit without cropping the image, press Dismiss.\n"
554 },
555 ImageDrawHelp[] =
556 {
557 "The cursor changes to a crosshair to indicate you are in\n"
558 "draw mode. To exit immediately, press Dismiss. In draw mode,\n"
559 "the Command widget has these options:\n"
560 "\n"
561 " Element\n"
562 " point\n"
563 " line\n"
564 " rectangle\n"
565 " fill rectangle\n"
566 " circle\n"
567 " fill circle\n"
568 " ellipse\n"
569 " fill ellipse\n"
570 " polygon\n"
571 " fill polygon\n"
572 " Color\n"
573 " black\n"
574 " blue\n"
575 " cyan\n"
576 " green\n"
577 " gray\n"
578 " red\n"
579 " magenta\n"
580 " yellow\n"
581 " white\n"
582 " transparent\n"
583 " Browser...\n"
584 " Stipple\n"
585 " Brick\n"
586 " Diagonal\n"
587 " Scales\n"
588 " Vertical\n"
589 " Wavy\n"
590 " Translucent\n"
591 " Opaque\n"
592 " Open...\n"
593 " Width\n"
594 " 1\n"
595 " 2\n"
596 " 4\n"
597 " 8\n"
598 " 16\n"
599 " Dialog...\n"
600 " Undo\n"
601 " Help\n"
602 " Dismiss\n"
603 "\n"
604 "Choose a drawing primitive from the Element sub-menu.\n"
605 "\n"
606 "Choose a color from the Color sub-menu. Additional\n"
607 "colors can be specified with the color browser.\n"
608 "\n"
609 "If you choose the color browser and press Grab, you can\n"
610 "select the color by moving the pointer to the desired\n"
611 "color on the screen and press any button. The transparent\n"
612 "color updates the image matte channel and is useful for\n"
613 "image compositing.\n"
614 "\n"
615 "Choose a stipple, if appropriate, from the Stipple sub-menu.\n"
616 "Additional stipples can be specified with the file browser.\n"
617 "Stipples obtained from the file browser must be on disk in the\n"
618 "X11 bitmap format.\n"
619 "\n"
620 "Choose a width, if appropriate, from the Width sub-menu. To\n"
621 "choose a specific width select the Dialog widget.\n"
622 "\n"
623 "Choose a point in the Image window and press button 1 and\n"
624 "hold. Next, move the pointer to another location in the\n"
625 "image. As you move, a line connects the initial location and\n"
626 "the pointer. When you release the button, the image is\n"
627 "updated with the primitive you just drew. For polygons, the\n"
628 "image is updated when you press and release the button without\n"
629 "moving the pointer.\n"
630 "\n"
631 "To cancel image drawing, move the pointer back to the\n"
632 "starting point of the line and release the button.\n"
633 },
634 DisplayHelp[] =
635 {
636 "BUTTONS\n"
637 " The effects of each button press is described below. Three\n"
638 " buttons are required. If you have a two button mouse,\n"
639 " button 1 and 3 are returned. Press ALT and button 3 to\n"
640 " simulate button 2.\n"
641 "\n"
642 " 1 Press this button to map or unmap the Command widget.\n"
643 "\n"
644 " 2 Press and drag to define a region of the image to\n"
645 " magnify.\n"
646 "\n"
647 " 3 Press and drag to choose from a select set of commands.\n"
648 " This button behaves differently if the image being\n"
649 " displayed is a visual image directory. Here, choose a\n"
650 " particular tile of the directory and press this button and\n"
651 " drag to select a command from a pop-up menu. Choose from\n"
652 " these menu items:\n"
653 "\n"
654 " Open\n"
655 " Next\n"
656 " Former\n"
657 " Delete\n"
658 " Update\n"
659 "\n"
660 " If you choose Open, the image represented by the tile is\n"
661 " displayed. To return to the visual image directory, choose\n"
662 " Next from the Command widget. Next and Former moves to the\n"
663 " next or former image respectively. Choose Delete to delete\n"
664 " a particular image tile. Finally, choose Update to\n"
665 " synchronize all the image tiles with their respective\n"
666 " images.\n"
667 "\n"
668 "COMMAND WIDGET\n"
669 " The Command widget lists a number of sub-menus and commands.\n"
670 " They are\n"
671 "\n"
672 " File\n"
673 " Open...\n"
674 " Next\n"
675 " Former\n"
676 " Select...\n"
677 " Save...\n"
678 " Print...\n"
679 " Delete...\n"
680 " New...\n"
681 " Visual Directory...\n"
682 " Quit\n"
683 " Edit\n"
684 " Undo\n"
685 " Redo\n"
686 " Cut\n"
687 " Copy\n"
688 " Paste\n"
689 " View\n"
690 " Half Size\n"
691 " Original Size\n"
692 " Double Size\n"
693 " Resize...\n"
694 " Apply\n"
695 " Refresh\n"
696 " Restore\n"
697 " Transform\n"
698 " Crop\n"
699 " Chop\n"
700 " Flop\n"
701 " Flip\n"
702 " Rotate Right\n"
703 " Rotate Left\n"
704 " Rotate...\n"
705 " Shear...\n"
706 " Roll...\n"
707 " Trim Edges\n"
708 " Enhance\n"
709 " Brightness...\n"
710 " Saturation...\n"
711 " Hue...\n"
712 " Gamma...\n"
713 " Sharpen...\n"
714 " Dull\n"
715 " Contrast Stretch...\n"
716 " Sigmoidal Contrast...\n"
717 " Normalize\n"
718 " Equalize\n"
719 " Negate\n"
720 " Grayscale\n"
721 " Map...\n"
722 " Quantize...\n"
723 " Effects\n"
724 " Despeckle\n"
725 " Emboss\n"
726 " Reduce Noise\n"
727 " Add Noise\n"
728 " Sharpen...\n"
729 " Blur...\n"
730 " Threshold...\n"
731 " Edge Detect...\n"
732 " Spread...\n"
733 " Shade...\n"
734 " Painting...\n"
735 " Segment...\n"
736 " F/X\n"
737 " Solarize...\n"
738 " Sepia Tone...\n"
739 " Swirl...\n"
740 " Implode...\n"
741 " Vignette...\n"
742 " Wave...\n"
743 " Oil Painting...\n"
744 " Charcoal Drawing...\n"
745 " Image Edit\n"
746 " Annotate...\n"
747 " Draw...\n"
748 " Color...\n"
749 " Matte...\n"
750 " Composite...\n"
751 " Add Border...\n"
752 " Add Frame...\n"
753 " Comment...\n"
754 " Launch...\n"
755 " Region of Interest...\n"
756 " Miscellany\n"
757 " Image Info\n"
758 " Zoom Image\n"
759 " Show Preview...\n"
760 " Show Histogram\n"
761 " Show Matte\n"
762 " Background...\n"
763 " Slide Show\n"
764 " Preferences...\n"
765 " Help\n"
766 " Overview\n"
767 " Browse Documentation\n"
768 " About Display\n"
769 "\n"
770 " Menu items with a indented triangle have a sub-menu. They\n"
771 " are represented above as the indented items. To access a\n"
772 " sub-menu item, move the pointer to the appropriate menu and\n"
773 " press a button and drag. When you find the desired sub-menu\n"
774 " item, release the button and the command is executed. Move\n"
775 " the pointer away from the sub-menu if you decide not to\n"
776 " execute a particular command.\n"
777 "\n"
778 "KEYBOARD ACCELERATORS\n"
779 " Accelerators are one or two key presses that effect a\n"
780 " particular command. The keyboard accelerators that\n"
781 " display(1) understands is:\n"
782 "\n"
783 " Ctl+O Press to open an image from a file.\n"
784 "\n"
785 " space Press to display the next image.\n"
786 "\n"
787 " If the image is a multi-paged document such as a Postscript\n"
788 " document, you can skip ahead several pages by preceding\n"
789 " this command with a number. For example to display the\n"
790 " third page beyond the current page, press 3<space>.\n"
791 "\n"
792 " backspace Press to display the former image.\n"
793 "\n"
794 " If the image is a multi-paged document such as a Postscript\n"
795 " document, you can skip behind several pages by preceding\n"
796 " this command with a number. For example to display the\n"
797 " third page preceding the current page, press 3<backspace>.\n"
798 "\n"
799 " Ctl+S Press to write the image to a file.\n"
800 "\n"
801 " Ctl+P Press to print the image to a Postscript printer.\n"
802 "\n"
803 " Ctl+D Press to delete an image file.\n"
804 "\n"
805 " Ctl+N Press to create a blank canvas.\n"
806 "\n"
807 " Ctl+Q Press to discard all images and exit program.\n"
808 "\n"
809 " Ctl+Z Press to undo last image transformation.\n"
810 "\n"
811 " Ctl+R Press to redo last image transformation.\n"
812 "\n"
813 " Ctl+X Press to cut a region of the image.\n"
814 "\n"
815 " Ctl+C Press to copy a region of the image.\n"
816 "\n"
817 " Ctl+V Press to paste a region to the image.\n"
818 "\n"
819 " < Press to half the image size.\n"
820 "\n"
821 " - Press to return to the original image size.\n"
822 "\n"
823 " > Press to double the image size.\n"
824 "\n"
825 " % Press to resize the image to a width and height you\n"
826 " specify.\n"
827 "\n"
828 "Cmd-A Press to make any image transformations permanent."
829 "\n"
830 " By default, any image size transformations are applied\n"
831 " to the original image to create the image displayed on\n"
832 " the X server. However, the transformations are not\n"
833 " permanent (i.e. the original image does not change\n"
834 " size only the X image does). For example, if you\n"
835 " press > the X image will appear to double in size,\n"
836 " but the original image will in fact remain the same size.\n"
837 " To force the original image to double in size, press >\n"
838 " followed by Cmd-A.\n"
839 "\n"
840 " @ Press to refresh the image window.\n"
841 "\n"
842 " C Press to cut out a rectangular region of the image.\n"
843 "\n"
844 " [ Press to chop the image.\n"
845 "\n"
846 " H Press to flop image in the horizontal direction.\n"
847 "\n"
848 " V Press to flip image in the vertical direction.\n"
849 "\n"
850 " / Press to rotate the image 90 degrees clockwise.\n"
851 "\n"
852 " \\ Press to rotate the image 90 degrees counter-clockwise.\n"
853 "\n"
854 " * Press to rotate the image the number of degrees you\n"
855 " specify.\n"
856 "\n"
857 " S Press to shear the image the number of degrees you\n"
858 " specify.\n"
859 "\n"
860 " R Press to roll the image.\n"
861 "\n"
862 " T Press to trim the image edges.\n"
863 "\n"
864 " Shft-H Press to vary the image hue.\n"
865 "\n"
866 " Shft-S Press to vary the color saturation.\n"
867 "\n"
868 " Shft-L Press to vary the color brightness.\n"
869 "\n"
870 " Shft-G Press to gamma correct the image.\n"
871 "\n"
872 " Shft-C Press to sharpen the image contrast.\n"
873 "\n"
874 " Shft-Z Press to dull the image contrast.\n"
875 "\n"
876 " = Press to perform histogram equalization on the image.\n"
877 "\n"
878 " Shft-N Press to perform histogram normalization on the image.\n"
879 "\n"
880 " Shft-~ Press to negate the colors of the image.\n"
881 "\n"
882 " . Press to convert the image colors to gray.\n"
883 "\n"
884 " Shft-# Press to set the maximum number of unique colors in the\n"
885 " image.\n"
886 "\n"
887 " F2 Press to reduce the speckles in an image.\n"
888 "\n"
889 " F3 Press to eliminate peak noise from an image.\n"
890 "\n"
891 " F4 Press to add noise to an image.\n"
892 "\n"
893 " F5 Press to sharpen an image.\n"
894 "\n"
895 " F6 Press to delete an image file.\n"
896 "\n"
897 " F7 Press to threshold the image.\n"
898 "\n"
899 " F8 Press to detect edges within an image.\n"
900 "\n"
901 " F9 Press to emboss an image.\n"
902 "\n"
903 " F10 Press to displace pixels by a random amount.\n"
904 "\n"
905 " F11 Press to negate all pixels above the threshold level.\n"
906 "\n"
907 " F12 Press to shade the image using a distant light source.\n"
908 "\n"
909 " F13 Press to lighten or darken image edges to create a 3-D effect.\n"
910 "\n"
911 " F14 Press to segment the image by color.\n"
912 "\n"
913 " Meta-S Press to swirl image pixels about the center.\n"
914 "\n"
915 " Meta-I Press to implode image pixels about the center.\n"
916 "\n"
917 " Meta-W Press to alter an image along a sine wave.\n"
918 "\n"
919 " Meta-P Press to simulate an oil painting.\n"
920 "\n"
921 " Meta-C Press to simulate a charcoal drawing.\n"
922 "\n"
923 " Alt-A Press to annotate the image with text.\n"
924 "\n"
925 " Alt-D Press to draw on an image.\n"
926 "\n"
927 " Alt-P Press to edit an image pixel color.\n"
928 "\n"
929 " Alt-M Press to edit the image matte information.\n"
930 "\n"
931 " Alt-V Press to composite the image with another.\n"
932 "\n"
933 " Alt-B Press to add a border to the image.\n"
934 "\n"
935 " Alt-F Press to add an ornamental border to the image.\n"
936 "\n"
937 " Alt-Shft-!\n"
938 " Press to add an image comment.\n"
939 "\n"
940 " Ctl-A Press to apply image processing techniques to a region\n"
941 " of interest.\n"
942 "\n"
943 " Shft-? Press to display information about the image.\n"
944 "\n"
945 " Shft-+ Press to map the zoom image window.\n"
946 "\n"
947 " Shft-P Press to preview an image enhancement, effect, or f/x.\n"
948 "\n"
949 " F1 Press to display helpful information about display(1).\n"
950 "\n"
951 " Find Press to browse documentation about ImageMagick.\n"
952 "\n"
953 " 1-9 Press to change the level of magnification.\n"
954 "\n"
955 " Use the arrow keys to move the image one pixel up, down,\n"
956 " left, or right within the magnify window. Be sure to first\n"
957 " map the magnify window by pressing button 2.\n"
958 "\n"
959 " Press ALT and one of the arrow keys to trim off one pixel\n"
960 " from any side of the image.\n"
961 },
962 ImageMatteEditHelp[] =
963 {
964 "Matte information within an image is useful for some\n"
965 "operations such as image compositing (See IMAGE\n"
966 "COMPOSITING). This extra channel usually defines a mask\n"
967 "which represents a sort of a cookie-cutter for the image.\n"
968 "This the case when matte is opaque (full coverage) for\n"
969 "pixels inside the shape, zero outside, and between 0 and\n"
970 "QuantumRange on the boundary.\n"
971 "\n"
972 "A small window appears showing the location of the cursor in\n"
973 "the image window. You are now in matte edit mode. To exit\n"
974 "immediately, press Dismiss. In matte edit mode, the Command\n"
975 "widget has these options:\n"
976 "\n"
977 " Method\n"
978 " point\n"
979 " replace\n"
980 " floodfill\n"
981 " filltoborder\n"
982 " reset\n"
983 " Border Color\n"
984 " black\n"
985 " blue\n"
986 " cyan\n"
987 " green\n"
988 " gray\n"
989 " red\n"
990 " magenta\n"
991 " yellow\n"
992 " white\n"
993 " Browser...\n"
994 " Fuzz\n"
995 " 0%\n"
996 " 2%\n"
997 " 5%\n"
998 " 10%\n"
999 " 15%\n"
1000 " Dialog...\n"
1001 " Matte\n"
1002 " Opaque\n"
1003 " Transparent\n"
1004 " Dialog...\n"
1005 " Undo\n"
1006 " Help\n"
1007 " Dismiss\n"
1008 "\n"
1009 "Choose a matte editing method from the Method sub-menu of\n"
1010 "the Command widget. The point method changes the matte value\n"
1011 "of any pixel selected with the pointer until the button is\n"
1012 "is released. The replace method changes the matte value of\n"
1013 "any pixel that matches the color of the pixel you select with\n"
1014 "a button press. Floodfill changes the matte value of any pixel\n"
1015 "that matches the color of the pixel you select with a button\n"
1016 "press and is a neighbor. Whereas filltoborder changes the matte\n"
1017 "value any neighbor pixel that is not the border color. Finally\n"
1018 "reset changes the entire image to the designated matte value.\n"
1019 "\n"
1020 "Choose Matte Value and pick Opaque or Transarent. For other values\n"
1021 "select the Dialog entry. Here a dialog appears requesting a matte\n"
1022 "value. The value you select is assigned as the opacity value of the\n"
1023 "selected pixel or pixels.\n"
1024 "\n"
1025 "Now, press any button to select a pixel within the image\n"
1026 "window to change its matte value.\n"
1027 "\n"
1028 "If the Magnify widget is mapped, it can be helpful in positioning\n"
1029 "your pointer within the image (refer to button 2).\n"
1030 "\n"
1031 "Matte information is only valid in a DirectClass image.\n"
1032 "Therefore, any PseudoClass image is promoted to DirectClass\n"
1033 "(see miff(5)). Note that matte information for PseudoClass\n"
1034 "is not retained for colormapped X server visuals (e.g.\n"
1035 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you\n"
1036 "immediately save your image to a file (refer to Write).\n"
1037 "Correct matte editing behavior may require a TrueColor or\n"
1038 "DirectColor visual or a Standard Colormap.\n"
1039 },
1040 ImagePanHelp[] =
1041 {
1042 "When an image exceeds the width or height of the X server\n"
1043 "screen, display maps a small panning icon. The rectangle\n"
1044 "within the panning icon shows the area that is currently\n"
1045 "displayed in the image window. To pan about the image,\n"
1046 "press any button and drag the pointer within the panning\n"
1047 "icon. The pan rectangle moves with the pointer and the\n"
1048 "image window is updated to reflect the location of the\n"
1049 "rectangle within the panning icon. When you have selected\n"
1050 "the area of the image you wish to view, release the button.\n"
1051 "\n"
1052 "Use the arrow keys to pan the image one pixel up, down,\n"
1053 "left, or right within the image window.\n"
1054 "\n"
1055 "The panning icon is withdrawn if the image becomes smaller\n"
1056 "than the dimensions of the X server screen.\n"
1057 },
1058 ImagePasteHelp[] =
1059 {
1060 "A small window appears showing the location of the cursor in\n"
1061 "the image window. You are now in paste mode. To exit\n"
1062 "immediately, press Dismiss. In paste mode, the Command\n"
1063 "widget has these options:\n"
1064 "\n"
1065 " Operators\n"
1066 " over\n"
1067 " in\n"
1068 " out\n"
1069 " atop\n"
1070 " xor\n"
1071 " plus\n"
1072 " minus\n"
1073 " add\n"
1074 " subtract\n"
1075 " difference\n"
1076 " replace\n"
1077 " Help\n"
1078 " Dismiss\n"
1079 "\n"
1080 "Choose a composite operation from the Operators sub-menu of\n"
1081 "the Command widget. How each operator behaves is described\n"
1082 "below. Image window is the image currently displayed on\n"
1083 "your X server and image is the image obtained with the File\n"
1084 "Browser widget.\n"
1085 "\n"
1086 "Over The result is the union of the two image shapes,\n"
1087 " with image obscuring image window in the region of\n"
1088 " overlap.\n"
1089 "\n"
1090 "In The result is simply image cut by the shape of\n"
1091 " image window. None of the image data of image\n"
1092 " window is in the result.\n"
1093 "\n"
1094 "Out The resulting image is image with the shape of\n"
1095 " image window cut out.\n"
1096 "\n"
1097 "Atop The result is the same shape as image image window,\n"
1098 " with image obscuring image window where the image\n"
1099 " shapes overlap. Note this differs from over\n"
1100 " because the portion of image outside image window's\n"
1101 " shape does not appear in the result.\n"
1102 "\n"
1103 "Xor The result is the image data from both image and\n"
1104 " image window that is outside the overlap region.\n"
1105 " The overlap region is blank.\n"
1106 "\n"
1107 "Plus The result is just the sum of the image data.\n"
1108 " Output values are cropped to QuantumRange (no overflow).\n"
1109 " This operation is independent of the matte\n"
1110 " channels.\n"
1111 "\n"
1112 "Minus The result of image - image window, with underflow\n"
1113 " cropped to zero.\n"
1114 "\n"
1115 "Add The result of image + image window, with overflow\n"
1116 " wrapping around (mod 256).\n"
1117 "\n"
1118 "Subtract The result of image - image window, with underflow\n"
1119 " wrapping around (mod 256). The add and subtract\n"
1120 " operators can be used to perform reversible\n"
1121 " transformations.\n"
1122 "\n"
1123 "Difference\n"
1124 " The result of abs(image - image window). This\n"
1125 " useful for comparing two very similar images.\n"
1126 "\n"
1127 "Copy The resulting image is image window replaced with\n"
1128 " image. Here the matte information is ignored.\n"
1129 "\n"
1130 "CopyRed The red layer of the image window is replace with\n"
1131 " the red layer of the image. The other layers are\n"
1132 " untouched.\n"
1133 "\n"
1134 "CopyGreen\n"
1135 " The green layer of the image window is replace with\n"
1136 " the green layer of the image. The other layers are\n"
1137 " untouched.\n"
1138 "\n"
1139 "CopyBlue The blue layer of the image window is replace with\n"
1140 " the blue layer of the image. The other layers are\n"
1141 " untouched.\n"
1142 "\n"
1143 "CopyOpacity\n"
1144 " The matte layer of the image window is replace with\n"
1145 " the matte layer of the image. The other layers are\n"
1146 " untouched.\n"
1147 "\n"
1148 "The image compositor requires a matte, or alpha channel in\n"
1149 "the image for some operations. This extra channel usually\n"
1150 "defines a mask which represents a sort of a cookie-cutter\n"
1151 "for the image. This the case when matte is opaque (full\n"
1152 "coverage) for pixels inside the shape, zero outside, and\n"
1153 "between 0 and QuantumRange on the boundary. If image does not\n"
1154 "have a matte channel, it is initialized with 0 for any pixel\n"
1155 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
1156 "\n"
1157 "Note that matte information for image window is not retained\n"
1158 "for colormapped X server visuals (e.g. StaticColor,\n"
1159 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
1160 "behavior may require a TrueColor or DirectColor visual or a\n"
1161 "Standard Colormap.\n"
1162 "\n"
1163 "Choosing a composite operator is optional. The default\n"
1164 "operator is replace. However, you must choose a location to\n"
1165 "paste your image and press button 1. Press and hold the\n"
1166 "button before releasing and an outline of the image will\n"
1167 "appear to help you identify your location.\n"
1168 "\n"
1169 "The actual colors of the pasted image is saved. However,\n"
1170 "the color that appears in image window may be different.\n"
1171 "For example, on a monochrome screen image window will appear\n"
1172 "black or white even though your pasted image may have\n"
1173 "many colors. If the image is saved to a file it is written\n"
1174 "with the correct colors. To assure the correct colors are\n"
1175 "saved in the final image, any PseudoClass image is promoted\n"
1176 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
1177 "to remain PseudoClass, use -colors.\n"
1178 },
1179 ImageROIHelp[] =
1180 {
1181 "In region of interest mode, the Command widget has these\n"
1182 "options:\n"
1183 "\n"
1184 " Help\n"
1185 " Dismiss\n"
1186 "\n"
1187 "To define a region of interest, press button 1 and drag.\n"
1188 "The region of interest is defined by a highlighted rectangle\n"
1189 "that expands or contracts as it follows the pointer. Once\n"
1190 "you are satisfied with the region of interest, release the\n"
1191 "button. You are now in apply mode. In apply mode the\n"
1192 "Command widget has these options:\n"
1193 "\n"
1194 " File\n"
1195 " Save...\n"
1196 " Print...\n"
1197 " Edit\n"
1198 " Undo\n"
1199 " Redo\n"
1200 " Transform\n"
1201 " Flop\n"
1202 " Flip\n"
1203 " Rotate Right\n"
1204 " Rotate Left\n"
1205 " Enhance\n"
1206 " Hue...\n"
1207 " Saturation...\n"
1208 " Brightness...\n"
1209 " Gamma...\n"
1210 " Spiff\n"
1211 " Dull\n"
1212 " Contrast Stretch\n"
1213 " Sigmoidal Contrast...\n"
1214 " Normalize\n"
1215 " Equalize\n"
1216 " Negate\n"
1217 " Grayscale\n"
1218 " Map...\n"
1219 " Quantize...\n"
1220 " Effects\n"
1221 " Despeckle\n"
1222 " Emboss\n"
1223 " Reduce Noise\n"
1224 " Sharpen...\n"
1225 " Blur...\n"
1226 " Threshold...\n"
1227 " Edge Detect...\n"
1228 " Spread...\n"
1229 " Shade...\n"
1230 " Raise...\n"
1231 " Segment...\n"
1232 " F/X\n"
1233 " Solarize...\n"
1234 " Sepia Tone...\n"
1235 " Swirl...\n"
1236 " Implode...\n"
1237 " Vignette...\n"
1238 " Wave...\n"
1239 " Oil Painting...\n"
1240 " Charcoal Drawing...\n"
1241 " Miscellany\n"
1242 " Image Info\n"
1243 " Zoom Image\n"
1244 " Show Preview...\n"
1245 " Show Histogram\n"
1246 " Show Matte\n"
1247 " Help\n"
1248 " Dismiss\n"
1249 "\n"
1250 "You can make adjustments to the region of interest by moving\n"
1251 "the pointer to one of the rectangle corners, pressing a\n"
1252 "button, and dragging. Finally, choose an image processing\n"
1253 "technique from the Command widget. You can choose more than\n"
1254 "one image processing technique to apply to an area.\n"
1255 "Alternatively, you can move the region of interest before\n"
1256 "applying another image processing technique. To exit, press\n"
1257 "Dismiss.\n"
1258 },
1259 ImageRotateHelp[] =
1260 {
1261 "In rotate mode, the Command widget has these options:\n"
1262 "\n"
1263 " Pixel Color\n"
1264 " black\n"
1265 " blue\n"
1266 " cyan\n"
1267 " green\n"
1268 " gray\n"
1269 " red\n"
1270 " magenta\n"
1271 " yellow\n"
1272 " white\n"
1273 " Browser...\n"
1274 " Direction\n"
1275 " horizontal\n"
1276 " vertical\n"
1277 " Help\n"
1278 " Dismiss\n"
1279 "\n"
1280 "Choose a background color from the Pixel Color sub-menu.\n"
1281 "Additional background colors can be specified with the color\n"
1282 "browser. You can change the menu colors by setting the X\n"
1283 "resources pen1 through pen9.\n"
1284 "\n"
1285 "If you choose the color browser and press Grab, you can\n"
1286 "select the background color by moving the pointer to the\n"
1287 "desired color on the screen and press any button.\n"
1288 "\n"
1289 "Choose a point in the image window and press this button and\n"
1290 "hold. Next, move the pointer to another location in the\n"
1291 "image. As you move a line connects the initial location and\n"
1292 "the pointer. When you release the button, the degree of\n"
1293 "image rotation is determined by the slope of the line you\n"
1294 "just drew. The slope is relative to the direction you\n"
1295 "choose from the Direction sub-menu of the Command widget.\n"
1296 "\n"
1297 "To cancel the image rotation, move the pointer back to the\n"
1298 "starting point of the line and release the button.\n"
1299 };
1300
1301 /*
1302 Enumeration declarations.
1303 */
1304 typedef enum
1305 {
1306 CopyMode,
1307 CropMode,
1308 CutMode
1309 } ClipboardMode;
1310
1311 typedef enum
1312 {
1313 OpenCommand,
1314 NextCommand,
1315 FormerCommand,
1316 SelectCommand,
1317 SaveCommand,
1318 PrintCommand,
1319 DeleteCommand,
1320 NewCommand,
1321 VisualDirectoryCommand,
1322 QuitCommand,
1323 UndoCommand,
1324 RedoCommand,
1325 CutCommand,
1326 CopyCommand,
1327 PasteCommand,
1328 HalfSizeCommand,
1329 OriginalSizeCommand,
1330 DoubleSizeCommand,
1331 ResizeCommand,
1332 ApplyCommand,
1333 RefreshCommand,
1334 RestoreCommand,
1335 CropCommand,
1336 ChopCommand,
1337 FlopCommand,
1338 FlipCommand,
1339 RotateRightCommand,
1340 RotateLeftCommand,
1341 RotateCommand,
1342 ShearCommand,
1343 RollCommand,
1344 TrimCommand,
1345 HueCommand,
1346 SaturationCommand,
1347 BrightnessCommand,
1348 GammaCommand,
1349 SpiffCommand,
1350 DullCommand,
1351 ContrastStretchCommand,
1352 SigmoidalContrastCommand,
1353 NormalizeCommand,
1354 EqualizeCommand,
1355 NegateCommand,
1356 GrayscaleCommand,
1357 MapCommand,
1358 QuantizeCommand,
1359 DespeckleCommand,
1360 EmbossCommand,
1361 ReduceNoiseCommand,
1362 AddNoiseCommand,
1363 SharpenCommand,
1364 BlurCommand,
1365 ThresholdCommand,
1366 EdgeDetectCommand,
1367 SpreadCommand,
1368 ShadeCommand,
1369 RaiseCommand,
1370 SegmentCommand,
1371 SolarizeCommand,
1372 SepiaToneCommand,
1373 SwirlCommand,
1374 ImplodeCommand,
1375 VignetteCommand,
1376 WaveCommand,
1377 OilPaintCommand,
1378 CharcoalDrawCommand,
1379 AnnotateCommand,
1380 DrawCommand,
1381 ColorCommand,
1382 MatteCommand,
1383 CompositeCommand,
1384 AddBorderCommand,
1385 AddFrameCommand,
1386 CommentCommand,
1387 LaunchCommand,
1388 RegionofInterestCommand,
1389 ROIHelpCommand,
1390 ROIDismissCommand,
1391 InfoCommand,
1392 ZoomCommand,
1393 ShowPreviewCommand,
1394 ShowHistogramCommand,
1395 ShowMatteCommand,
1396 BackgroundCommand,
1397 SlideShowCommand,
1398 PreferencesCommand,
1399 HelpCommand,
1400 BrowseDocumentationCommand,
1401 VersionCommand,
1402 SaveToUndoBufferCommand,
1403 FreeBuffersCommand,
1404 NullCommand
1405 } CommandType;
1406
1407 typedef enum
1408 {
1409 AnnotateNameCommand,
1410 AnnotateFontColorCommand,
1411 AnnotateBackgroundColorCommand,
1412 AnnotateRotateCommand,
1413 AnnotateHelpCommand,
1414 AnnotateDismissCommand,
1415 TextHelpCommand,
1416 TextApplyCommand,
1417 ChopDirectionCommand,
1418 ChopHelpCommand,
1419 ChopDismissCommand,
1420 HorizontalChopCommand,
1421 VerticalChopCommand,
1422 ColorEditMethodCommand,
1423 ColorEditColorCommand,
1424 ColorEditBorderCommand,
1425 ColorEditFuzzCommand,
1426 ColorEditUndoCommand,
1427 ColorEditHelpCommand,
1428 ColorEditDismissCommand,
1429 CompositeOperatorsCommand,
1430 CompositeDissolveCommand,
1431 CompositeDisplaceCommand,
1432 CompositeHelpCommand,
1433 CompositeDismissCommand,
1434 CropHelpCommand,
1435 CropDismissCommand,
1436 RectifyCopyCommand,
1437 RectifyHelpCommand,
1438 RectifyDismissCommand,
1439 DrawElementCommand,
1440 DrawColorCommand,
1441 DrawStippleCommand,
1442 DrawWidthCommand,
1443 DrawUndoCommand,
1444 DrawHelpCommand,
1445 DrawDismissCommand,
1446 MatteEditMethod,
1447 MatteEditBorderCommand,
1448 MatteEditFuzzCommand,
1449 MatteEditValueCommand,
1450 MatteEditUndoCommand,
1451 MatteEditHelpCommand,
1452 MatteEditDismissCommand,
1453 PasteOperatorsCommand,
1454 PasteHelpCommand,
1455 PasteDismissCommand,
1456 RotateColorCommand,
1457 RotateDirectionCommand,
1458 RotateCropCommand,
1459 RotateSharpenCommand,
1460 RotateHelpCommand,
1461 RotateDismissCommand,
1462 HorizontalRotateCommand,
1463 VerticalRotateCommand,
1464 TileLoadCommand,
1465 TileNextCommand,
1466 TileFormerCommand,
1467 TileDeleteCommand,
1468 TileUpdateCommand
1469 } ModeType;
1470
1471 /*
1472 Stipples.
1473 */
1474 #define BricksWidth 20
1475 #define BricksHeight 20
1476 #define DiagonalWidth 16
1477 #define DiagonalHeight 16
1478 #define HighlightWidth 8
1479 #define HighlightHeight 8
1480 #define OpaqueWidth 8
1481 #define OpaqueHeight 8
1482 #define ScalesWidth 16
1483 #define ScalesHeight 16
1484 #define ShadowWidth 8
1485 #define ShadowHeight 8
1486 #define VerticalWidth 16
1487 #define VerticalHeight 16
1488 #define WavyWidth 16
1489 #define WavyHeight 16
1490
1491 /*
1492 Constant declaration.
1493 */
1494 static const int
1495 RoiDelta = 8;
1496
1497 static const unsigned char
1498 BricksBitmap[] =
1499 {
1500 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1501 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1502 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1503 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1504 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1505 },
1506 DiagonalBitmap[] =
1507 {
1508 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1509 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1510 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1511 },
1512 ScalesBitmap[] =
1513 {
1514 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1515 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1516 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1517 },
1518 VerticalBitmap[] =
1519 {
1520 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1521 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1522 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1523 },
1524 WavyBitmap[] =
1525 {
1526 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1527 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1528 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1529 };
1530
1531 /*
1532 Function prototypes.
1533 */
1534 static CommandType
1535 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1536 const MagickStatusType,KeySym,Image **);
1537
1538 static Image
1539 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1540 Image **),
1541 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1542 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1543 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1544
1545 static MagickBooleanType
1546 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1547 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1548 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1549 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1550 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1551 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1552 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1553 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1554 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1555 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1556 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1557 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1558 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1559 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1560 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1561
1562 static void
1563 XDrawPanRectangle(Display *,XWindows *),
1564 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
1565 XMagnifyImage(Display *,XWindows *,XEvent *),
1566 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1567 XPanImage(Display *,XWindows *,XEvent *),
1568 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1569 const KeySym),
1570 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1571 XScreenEvent(Display *,XWindows *,XEvent *),
1572 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1573
1574 /*
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1576 % %
1577 % %
1578 % %
1579 % D i s p l a y I m a g e s %
1580 % %
1581 % %
1582 % %
1583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584 %
1585 % DisplayImages() displays an image sequence to any X window screen. It
1586 % returns a value other than 0 if successful. Check the exception member
1587 % of image to determine the reason for any failure.
1588 %
1589 % The format of the DisplayImages method is:
1590 %
1591 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1592 % Image *images)
1593 %
1594 % A description of each parameter follows:
1595 %
1596 % o image_info: the image info.
1597 %
1598 % o image: the image.
1599 %
1600 */
DisplayImages(const ImageInfo * image_info,Image * images)1601 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1602 Image *images)
1603 {
1604 char
1605 *argv[1];
1606
1607 Display
1608 *display;
1609
1610 Image
1611 *image;
1612
1613 ssize_t
1614 i;
1615
1616 size_t
1617 state;
1618
1619 XrmDatabase
1620 resource_database;
1621
1622 XResourceInfo
1623 resource_info;
1624
1625 assert(image_info != (const ImageInfo *) NULL);
1626 assert(image_info->signature == MagickCoreSignature);
1627 assert(images != (Image *) NULL);
1628 assert(images->signature == MagickCoreSignature);
1629 if (images->debug != MagickFalse)
1630 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1631 display=XOpenDisplay(image_info->server_name);
1632 if (display == (Display *) NULL)
1633 {
1634 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1635 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1636 image_info->server_name));
1637 return(MagickFalse);
1638 }
1639 if (images->exception.severity != UndefinedException)
1640 CatchException(&images->exception);
1641 (void) XSetErrorHandler(XError);
1642 resource_database=XGetResourceDatabase(display,GetClientName());
1643 (void) memset(&resource_info,0,sizeof(resource_info));
1644 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1645 if (image_info->page != (char *) NULL)
1646 resource_info.image_geometry=AcquireString(image_info->page);
1647 resource_info.immutable=MagickTrue;
1648 argv[0]=AcquireString(GetClientName());
1649 state=DefaultState;
1650 for (i=0; (state & ExitState) == 0; i++)
1651 {
1652 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1653 break;
1654 image=GetImageFromList(images,i % GetImageListLength(images));
1655 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1656 }
1657 (void) SetErrorHandler((ErrorHandler) NULL);
1658 (void) SetWarningHandler((WarningHandler) NULL);
1659 argv[0]=DestroyString(argv[0]);
1660 XDestroyResourceInfo(&resource_info);
1661 if (images->exception.severity != UndefinedException)
1662 return(MagickFalse);
1663 return(MagickTrue);
1664 }
1665
1666 /*
1667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668 % %
1669 % %
1670 % %
1671 % R e m o t e D i s p l a y C o m m a n d %
1672 % %
1673 % %
1674 % %
1675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676 %
1677 % RemoteDisplayCommand() encourages a remote display program to display the
1678 % specified image filename.
1679 %
1680 % The format of the RemoteDisplayCommand method is:
1681 %
1682 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1683 % const char *window,const char *filename,ExceptionInfo *exception)
1684 %
1685 % A description of each parameter follows:
1686 %
1687 % o image_info: the image info.
1688 %
1689 % o window: Specifies the name or id of an X window.
1690 %
1691 % o filename: the name of the image filename to display.
1692 %
1693 % o exception: return any errors or warnings in this structure.
1694 %
1695 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)1696 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1697 const char *window,const char *filename,ExceptionInfo *exception)
1698 {
1699 Display
1700 *display;
1701
1702 MagickStatusType
1703 status;
1704
1705 assert(image_info != (const ImageInfo *) NULL);
1706 assert(image_info->signature == MagickCoreSignature);
1707 assert(filename != (char *) NULL);
1708 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1709 display=XOpenDisplay(image_info->server_name);
1710 if (display == (Display *) NULL)
1711 {
1712 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1713 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1714 return(MagickFalse);
1715 }
1716 (void) XSetErrorHandler(XError);
1717 status=XRemoteCommand(display,window,filename);
1718 (void) XCloseDisplay(display);
1719 return(status != 0 ? MagickTrue : MagickFalse);
1720 }
1721
1722 /*
1723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724 % %
1725 % %
1726 % %
1727 + X A n n o t a t e E d i t I m a g e %
1728 % %
1729 % %
1730 % %
1731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732 %
1733 % XAnnotateEditImage() annotates the image with text.
1734 %
1735 % The format of the XAnnotateEditImage method is:
1736 %
1737 % MagickBooleanType XAnnotateEditImage(Display *display,
1738 % XResourceInfo *resource_info,XWindows *windows,Image *image)
1739 %
1740 % A description of each parameter follows:
1741 %
1742 % o display: Specifies a connection to an X server; returned from
1743 % XOpenDisplay.
1744 %
1745 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1746 %
1747 % o windows: Specifies a pointer to a XWindows structure.
1748 %
1749 % o image: the image; returned from ReadImage.
1750 %
1751 */
1752
XAnnotateEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)1753 static MagickBooleanType XAnnotateEditImage(Display *display,
1754 XResourceInfo *resource_info,XWindows *windows,Image *image)
1755 {
1756 const char
1757 *const AnnotateMenu[] =
1758 {
1759 "Font Name",
1760 "Font Color",
1761 "Box Color",
1762 "Rotate Text",
1763 "Help",
1764 "Dismiss",
1765 (char *) NULL
1766 },
1767 *const TextMenu[] =
1768 {
1769 "Help",
1770 "Apply",
1771 (char *) NULL
1772 };
1773
1774 static const ModeType
1775 AnnotateCommands[] =
1776 {
1777 AnnotateNameCommand,
1778 AnnotateFontColorCommand,
1779 AnnotateBackgroundColorCommand,
1780 AnnotateRotateCommand,
1781 AnnotateHelpCommand,
1782 AnnotateDismissCommand
1783 },
1784 TextCommands[] =
1785 {
1786 TextHelpCommand,
1787 TextApplyCommand
1788 };
1789
1790 static MagickBooleanType
1791 transparent_box = MagickTrue,
1792 transparent_pen = MagickFalse;
1793
1794 static MagickRealType
1795 degrees = 0.0;
1796
1797 static unsigned int
1798 box_id = MaxNumberPens-2,
1799 font_id = 0,
1800 pen_id = 0;
1801
1802 char
1803 command[MaxTextExtent],
1804 text[MaxTextExtent];
1805
1806 const char
1807 *ColorMenu[MaxNumberPens+1];
1808
1809 Cursor
1810 cursor;
1811
1812 GC
1813 annotate_context;
1814
1815 int
1816 id,
1817 pen_number,
1818 status,
1819 x,
1820 y;
1821
1822 KeySym
1823 key_symbol;
1824
1825 char
1826 *p;
1827
1828 ssize_t
1829 i;
1830
1831 unsigned int
1832 height,
1833 width;
1834
1835 size_t
1836 state;
1837
1838 XAnnotateInfo
1839 *annotate_info,
1840 *previous_info;
1841
1842 XColor
1843 color;
1844
1845 XFontStruct
1846 *font_info;
1847
1848 XEvent
1849 event,
1850 text_event;
1851
1852 /*
1853 Map Command widget.
1854 */
1855 (void) CloneString(&windows->command.name,"Annotate");
1856 windows->command.data=4;
1857 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1858 (void) XMapRaised(display,windows->command.id);
1859 XClientMessage(display,windows->image.id,windows->im_protocols,
1860 windows->im_update_widget,CurrentTime);
1861 /*
1862 Track pointer until button 1 is pressed.
1863 */
1864 XQueryPosition(display,windows->image.id,&x,&y);
1865 (void) XSelectInput(display,windows->image.id,
1866 windows->image.attributes.event_mask | PointerMotionMask);
1867 cursor=XCreateFontCursor(display,XC_left_side);
1868 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1869 state=DefaultState;
1870 do
1871 {
1872 if (windows->info.mapped != MagickFalse)
1873 {
1874 /*
1875 Display pointer position.
1876 */
1877 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
1878 x+windows->image.x,y+windows->image.y);
1879 XInfoWidget(display,windows,text);
1880 }
1881 /*
1882 Wait for next event.
1883 */
1884 XScreenEvent(display,windows,&event);
1885 if (event.xany.window == windows->command.id)
1886 {
1887 /*
1888 Select a command from the Command widget.
1889 */
1890 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1891 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1892 if (id < 0)
1893 continue;
1894 switch (AnnotateCommands[id])
1895 {
1896 case AnnotateNameCommand:
1897 {
1898 const char
1899 *FontMenu[MaxNumberFonts];
1900
1901 int
1902 font_number;
1903
1904 /*
1905 Initialize menu selections.
1906 */
1907 for (i=0; i < MaxNumberFonts; i++)
1908 FontMenu[i]=resource_info->font_name[i];
1909 FontMenu[MaxNumberFonts-2]="Browser...";
1910 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1911 /*
1912 Select a font name from the pop-up menu.
1913 */
1914 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1915 (const char **) FontMenu,command);
1916 if (font_number < 0)
1917 break;
1918 if (font_number == (MaxNumberFonts-2))
1919 {
1920 static char
1921 font_name[MaxTextExtent] = "fixed";
1922
1923 /*
1924 Select a font name from a browser.
1925 */
1926 resource_info->font_name[font_number]=font_name;
1927 XFontBrowserWidget(display,windows,"Select",font_name);
1928 if (*font_name == '\0')
1929 break;
1930 }
1931 /*
1932 Initialize font info.
1933 */
1934 font_info=XLoadQueryFont(display,resource_info->font_name[
1935 font_number]);
1936 if (font_info == (XFontStruct *) NULL)
1937 {
1938 XNoticeWidget(display,windows,"Unable to load font:",
1939 resource_info->font_name[font_number]);
1940 break;
1941 }
1942 font_id=(unsigned int) font_number;
1943 (void) XFreeFont(display,font_info);
1944 break;
1945 }
1946 case AnnotateFontColorCommand:
1947 {
1948 /*
1949 Initialize menu selections.
1950 */
1951 for (i=0; i < (int) (MaxNumberPens-2); i++)
1952 ColorMenu[i]=resource_info->pen_colors[i];
1953 ColorMenu[MaxNumberPens-2]="transparent";
1954 ColorMenu[MaxNumberPens-1]="Browser...";
1955 ColorMenu[MaxNumberPens]=(const char *) NULL;
1956 /*
1957 Select a pen color from the pop-up menu.
1958 */
1959 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
1960 (const char **) ColorMenu,command);
1961 if (pen_number < 0)
1962 break;
1963 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
1964 MagickFalse;
1965 if (transparent_pen != MagickFalse)
1966 break;
1967 if (pen_number == (MaxNumberPens-1))
1968 {
1969 static char
1970 color_name[MaxTextExtent] = "gray";
1971
1972 /*
1973 Select a pen color from a dialog.
1974 */
1975 resource_info->pen_colors[pen_number]=color_name;
1976 XColorBrowserWidget(display,windows,"Select",color_name);
1977 if (*color_name == '\0')
1978 break;
1979 }
1980 /*
1981 Set pen color.
1982 */
1983 (void) XParseColor(display,windows->map_info->colormap,
1984 resource_info->pen_colors[pen_number],&color);
1985 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
1986 (unsigned int) MaxColors,&color);
1987 windows->pixel_info->pen_colors[pen_number]=color;
1988 pen_id=(unsigned int) pen_number;
1989 break;
1990 }
1991 case AnnotateBackgroundColorCommand:
1992 {
1993 /*
1994 Initialize menu selections.
1995 */
1996 for (i=0; i < (int) (MaxNumberPens-2); i++)
1997 ColorMenu[i]=resource_info->pen_colors[i];
1998 ColorMenu[MaxNumberPens-2]="transparent";
1999 ColorMenu[MaxNumberPens-1]="Browser...";
2000 ColorMenu[MaxNumberPens]=(const char *) NULL;
2001 /*
2002 Select a pen color from the pop-up menu.
2003 */
2004 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2005 (const char **) ColorMenu,command);
2006 if (pen_number < 0)
2007 break;
2008 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2009 MagickFalse;
2010 if (transparent_box != MagickFalse)
2011 break;
2012 if (pen_number == (MaxNumberPens-1))
2013 {
2014 static char
2015 color_name[MaxTextExtent] = "gray";
2016
2017 /*
2018 Select a pen color from a dialog.
2019 */
2020 resource_info->pen_colors[pen_number]=color_name;
2021 XColorBrowserWidget(display,windows,"Select",color_name);
2022 if (*color_name == '\0')
2023 break;
2024 }
2025 /*
2026 Set pen color.
2027 */
2028 (void) XParseColor(display,windows->map_info->colormap,
2029 resource_info->pen_colors[pen_number],&color);
2030 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2031 (unsigned int) MaxColors,&color);
2032 windows->pixel_info->pen_colors[pen_number]=color;
2033 box_id=(unsigned int) pen_number;
2034 break;
2035 }
2036 case AnnotateRotateCommand:
2037 {
2038 int
2039 entry;
2040
2041 const char
2042 *const RotateMenu[] =
2043 {
2044 "-90",
2045 "-45",
2046 "-30",
2047 "0",
2048 "30",
2049 "45",
2050 "90",
2051 "180",
2052 "Dialog...",
2053 (char *) NULL,
2054 };
2055
2056 static char
2057 angle[MaxTextExtent] = "30.0";
2058
2059 /*
2060 Select a command from the pop-up menu.
2061 */
2062 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2063 command);
2064 if (entry < 0)
2065 break;
2066 if (entry != 8)
2067 {
2068 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
2069 break;
2070 }
2071 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2072 angle);
2073 if (*angle == '\0')
2074 break;
2075 degrees=StringToDouble(angle,(char **) NULL);
2076 break;
2077 }
2078 case AnnotateHelpCommand:
2079 {
2080 XTextViewHelp(display,resource_info,windows,MagickFalse,
2081 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2082 break;
2083 }
2084 case AnnotateDismissCommand:
2085 {
2086 /*
2087 Prematurely exit.
2088 */
2089 state|=EscapeState;
2090 state|=ExitState;
2091 break;
2092 }
2093 default:
2094 break;
2095 }
2096 continue;
2097 }
2098 switch (event.type)
2099 {
2100 case ButtonPress:
2101 {
2102 if (event.xbutton.button != Button1)
2103 break;
2104 if (event.xbutton.window != windows->image.id)
2105 break;
2106 /*
2107 Change to text entering mode.
2108 */
2109 x=event.xbutton.x;
2110 y=event.xbutton.y;
2111 state|=ExitState;
2112 break;
2113 }
2114 case ButtonRelease:
2115 break;
2116 case Expose:
2117 break;
2118 case KeyPress:
2119 {
2120 if (event.xkey.window != windows->image.id)
2121 break;
2122 /*
2123 Respond to a user key press.
2124 */
2125 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2126 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2127 switch ((int) key_symbol)
2128 {
2129 case XK_Escape:
2130 case XK_F20:
2131 {
2132 /*
2133 Prematurely exit.
2134 */
2135 state|=EscapeState;
2136 state|=ExitState;
2137 break;
2138 }
2139 case XK_F1:
2140 case XK_Help:
2141 {
2142 XTextViewHelp(display,resource_info,windows,MagickFalse,
2143 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2144 break;
2145 }
2146 default:
2147 {
2148 (void) XBell(display,0);
2149 break;
2150 }
2151 }
2152 break;
2153 }
2154 case MotionNotify:
2155 {
2156 /*
2157 Map and unmap Info widget as cursor crosses its boundaries.
2158 */
2159 x=event.xmotion.x;
2160 y=event.xmotion.y;
2161 if (windows->info.mapped != MagickFalse)
2162 {
2163 if ((x < (int) (windows->info.x+windows->info.width)) &&
2164 (y < (int) (windows->info.y+windows->info.height)))
2165 (void) XWithdrawWindow(display,windows->info.id,
2166 windows->info.screen);
2167 }
2168 else
2169 if ((x > (int) (windows->info.x+windows->info.width)) ||
2170 (y > (int) (windows->info.y+windows->info.height)))
2171 (void) XMapWindow(display,windows->info.id);
2172 break;
2173 }
2174 default:
2175 break;
2176 }
2177 } while ((state & ExitState) == 0);
2178 (void) XSelectInput(display,windows->image.id,
2179 windows->image.attributes.event_mask);
2180 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2181 if ((state & EscapeState) != 0)
2182 return(MagickTrue);
2183 /*
2184 Set font info and check boundary conditions.
2185 */
2186 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2187 if (font_info == (XFontStruct *) NULL)
2188 {
2189 XNoticeWidget(display,windows,"Unable to load font:",
2190 resource_info->font_name[font_id]);
2191 font_info=windows->font_info;
2192 }
2193 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2194 x=(int) windows->image.width-font_info->max_bounds.width;
2195 if (y < (int) (font_info->ascent+font_info->descent))
2196 y=(int) font_info->ascent+font_info->descent;
2197 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2198 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2199 return(MagickFalse);
2200 /*
2201 Initialize annotate structure.
2202 */
2203 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2204 if (annotate_info == (XAnnotateInfo *) NULL)
2205 return(MagickFalse);
2206 XGetAnnotateInfo(annotate_info);
2207 annotate_info->x=x;
2208 annotate_info->y=y;
2209 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2210 annotate_info->stencil=OpaqueStencil;
2211 else
2212 if (transparent_box == MagickFalse)
2213 annotate_info->stencil=BackgroundStencil;
2214 else
2215 annotate_info->stencil=ForegroundStencil;
2216 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2217 annotate_info->degrees=degrees;
2218 annotate_info->font_info=font_info;
2219 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2220 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2221 sizeof(*annotate_info->text));
2222 if (annotate_info->text == (char *) NULL)
2223 return(MagickFalse);
2224 /*
2225 Create cursor and set graphic context.
2226 */
2227 cursor=XCreateFontCursor(display,XC_pencil);
2228 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2229 annotate_context=windows->image.annotate_context;
2230 (void) XSetFont(display,annotate_context,font_info->fid);
2231 (void) XSetBackground(display,annotate_context,
2232 windows->pixel_info->pen_colors[box_id].pixel);
2233 (void) XSetForeground(display,annotate_context,
2234 windows->pixel_info->pen_colors[pen_id].pixel);
2235 /*
2236 Begin annotating the image with text.
2237 */
2238 (void) CloneString(&windows->command.name,"Text");
2239 windows->command.data=0;
2240 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2241 state=DefaultState;
2242 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2243 text_event.xexpose.width=(int) font_info->max_bounds.width;
2244 text_event.xexpose.height=font_info->max_bounds.ascent+
2245 font_info->max_bounds.descent;
2246 p=annotate_info->text;
2247 do
2248 {
2249 /*
2250 Display text cursor.
2251 */
2252 *p='\0';
2253 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2254 /*
2255 Wait for next event.
2256 */
2257 XScreenEvent(display,windows,&event);
2258 if (event.xany.window == windows->command.id)
2259 {
2260 /*
2261 Select a command from the Command widget.
2262 */
2263 (void) XSetBackground(display,annotate_context,
2264 windows->pixel_info->background_color.pixel);
2265 (void) XSetForeground(display,annotate_context,
2266 windows->pixel_info->foreground_color.pixel);
2267 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2268 (void) XSetBackground(display,annotate_context,
2269 windows->pixel_info->pen_colors[box_id].pixel);
2270 (void) XSetForeground(display,annotate_context,
2271 windows->pixel_info->pen_colors[pen_id].pixel);
2272 if (id < 0)
2273 continue;
2274 switch (TextCommands[id])
2275 {
2276 case TextHelpCommand:
2277 {
2278 XTextViewHelp(display,resource_info,windows,MagickFalse,
2279 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2280 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2281 break;
2282 }
2283 case TextApplyCommand:
2284 {
2285 /*
2286 Finished annotating.
2287 */
2288 annotate_info->width=(unsigned int) XTextWidth(font_info,
2289 annotate_info->text,(int) strlen(annotate_info->text));
2290 XRefreshWindow(display,&windows->image,&text_event);
2291 state|=ExitState;
2292 break;
2293 }
2294 default:
2295 break;
2296 }
2297 continue;
2298 }
2299 /*
2300 Erase text cursor.
2301 */
2302 text_event.xexpose.x=x;
2303 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2304 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2305 (unsigned int) text_event.xexpose.width,(unsigned int)
2306 text_event.xexpose.height,MagickFalse);
2307 XRefreshWindow(display,&windows->image,&text_event);
2308 switch (event.type)
2309 {
2310 case ButtonPress:
2311 {
2312 if (event.xbutton.window != windows->image.id)
2313 break;
2314 if (event.xbutton.button == Button2)
2315 {
2316 /*
2317 Request primary selection.
2318 */
2319 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2320 windows->image.id,CurrentTime);
2321 break;
2322 }
2323 break;
2324 }
2325 case Expose:
2326 {
2327 if (event.xexpose.count == 0)
2328 {
2329 XAnnotateInfo
2330 *text_info;
2331
2332 /*
2333 Refresh Image window.
2334 */
2335 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2336 text_info=annotate_info;
2337 while (text_info != (XAnnotateInfo *) NULL)
2338 {
2339 if (annotate_info->stencil == ForegroundStencil)
2340 (void) XDrawString(display,windows->image.id,annotate_context,
2341 text_info->x,text_info->y,text_info->text,
2342 (int) strlen(text_info->text));
2343 else
2344 (void) XDrawImageString(display,windows->image.id,
2345 annotate_context,text_info->x,text_info->y,text_info->text,
2346 (int) strlen(text_info->text));
2347 text_info=text_info->previous;
2348 }
2349 (void) XDrawString(display,windows->image.id,annotate_context,
2350 x,y,"_",1);
2351 }
2352 break;
2353 }
2354 case KeyPress:
2355 {
2356 int
2357 length;
2358
2359 if (event.xkey.window != windows->image.id)
2360 break;
2361 /*
2362 Respond to a user key press.
2363 */
2364 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2365 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2366 *(command+length)='\0';
2367 if (((event.xkey.state & ControlMask) != 0) ||
2368 ((event.xkey.state & Mod1Mask) != 0))
2369 state|=ModifierState;
2370 if ((state & ModifierState) != 0)
2371 switch ((int) key_symbol)
2372 {
2373 case XK_u:
2374 case XK_U:
2375 {
2376 key_symbol=DeleteCommand;
2377 break;
2378 }
2379 default:
2380 break;
2381 }
2382 switch ((int) key_symbol)
2383 {
2384 case XK_BackSpace:
2385 {
2386 /*
2387 Erase one character.
2388 */
2389 if (p == annotate_info->text)
2390 {
2391 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2392 break;
2393 else
2394 {
2395 /*
2396 Go to end of the previous line of text.
2397 */
2398 annotate_info=annotate_info->previous;
2399 p=annotate_info->text;
2400 x=annotate_info->x+annotate_info->width;
2401 y=annotate_info->y;
2402 if (annotate_info->width != 0)
2403 p+=strlen(annotate_info->text);
2404 break;
2405 }
2406 }
2407 p--;
2408 x-=XTextWidth(font_info,p,1);
2409 text_event.xexpose.x=x;
2410 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2411 XRefreshWindow(display,&windows->image,&text_event);
2412 break;
2413 }
2414 case XK_bracketleft:
2415 {
2416 key_symbol=XK_Escape;
2417 break;
2418 }
2419 case DeleteCommand:
2420 {
2421 /*
2422 Erase the entire line of text.
2423 */
2424 while (p != annotate_info->text)
2425 {
2426 p--;
2427 x-=XTextWidth(font_info,p,1);
2428 text_event.xexpose.x=x;
2429 XRefreshWindow(display,&windows->image,&text_event);
2430 }
2431 break;
2432 }
2433 case XK_Escape:
2434 case XK_F20:
2435 {
2436 /*
2437 Finished annotating.
2438 */
2439 annotate_info->width=(unsigned int) XTextWidth(font_info,
2440 annotate_info->text,(int) strlen(annotate_info->text));
2441 XRefreshWindow(display,&windows->image,&text_event);
2442 state|=ExitState;
2443 break;
2444 }
2445 default:
2446 {
2447 /*
2448 Draw a single character on the Image window.
2449 */
2450 if ((state & ModifierState) != 0)
2451 break;
2452 if (*command == '\0')
2453 break;
2454 *p=(*command);
2455 if (annotate_info->stencil == ForegroundStencil)
2456 (void) XDrawString(display,windows->image.id,annotate_context,
2457 x,y,p,1);
2458 else
2459 (void) XDrawImageString(display,windows->image.id,
2460 annotate_context,x,y,p,1);
2461 x+=XTextWidth(font_info,p,1);
2462 p++;
2463 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2464 break;
2465 }
2466 case XK_Return:
2467 case XK_KP_Enter:
2468 {
2469 /*
2470 Advance to the next line of text.
2471 */
2472 *p='\0';
2473 annotate_info->width=(unsigned int) XTextWidth(font_info,
2474 annotate_info->text,(int) strlen(annotate_info->text));
2475 if (annotate_info->next != (XAnnotateInfo *) NULL)
2476 {
2477 /*
2478 Line of text already exists.
2479 */
2480 annotate_info=annotate_info->next;
2481 x=annotate_info->x;
2482 y=annotate_info->y;
2483 p=annotate_info->text;
2484 break;
2485 }
2486 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2487 sizeof(*annotate_info->next));
2488 if (annotate_info->next == (XAnnotateInfo *) NULL)
2489 return(MagickFalse);
2490 *annotate_info->next=(*annotate_info);
2491 annotate_info->next->previous=annotate_info;
2492 annotate_info=annotate_info->next;
2493 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2494 windows->image.width/MagickMax((ssize_t)
2495 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2496 if (annotate_info->text == (char *) NULL)
2497 return(MagickFalse);
2498 annotate_info->y+=annotate_info->height;
2499 if (annotate_info->y > (int) windows->image.height)
2500 annotate_info->y=(int) annotate_info->height;
2501 annotate_info->next=(XAnnotateInfo *) NULL;
2502 x=annotate_info->x;
2503 y=annotate_info->y;
2504 p=annotate_info->text;
2505 break;
2506 }
2507 }
2508 break;
2509 }
2510 case KeyRelease:
2511 {
2512 /*
2513 Respond to a user key release.
2514 */
2515 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2516 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2517 state&=(~ModifierState);
2518 break;
2519 }
2520 case SelectionNotify:
2521 {
2522 Atom
2523 type;
2524
2525 int
2526 format;
2527
2528 unsigned char
2529 *data;
2530
2531 unsigned long
2532 after,
2533 length;
2534
2535 /*
2536 Obtain response from primary selection.
2537 */
2538 if (event.xselection.property == (Atom) None)
2539 break;
2540 status=XGetWindowProperty(display,event.xselection.requestor,
2541 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2542 &type,&format,&length,&after,&data);
2543 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2544 (length == 0))
2545 break;
2546 /*
2547 Annotate Image window with primary selection.
2548 */
2549 for (i=0; i < (ssize_t) length; i++)
2550 {
2551 if ((char) data[i] != '\n')
2552 {
2553 /*
2554 Draw a single character on the Image window.
2555 */
2556 *p=(char) data[i];
2557 (void) XDrawString(display,windows->image.id,annotate_context,
2558 x,y,p,1);
2559 x+=XTextWidth(font_info,p,1);
2560 p++;
2561 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2562 continue;
2563 }
2564 /*
2565 Advance to the next line of text.
2566 */
2567 *p='\0';
2568 annotate_info->width=(unsigned int) XTextWidth(font_info,
2569 annotate_info->text,(int) strlen(annotate_info->text));
2570 if (annotate_info->next != (XAnnotateInfo *) NULL)
2571 {
2572 /*
2573 Line of text already exists.
2574 */
2575 annotate_info=annotate_info->next;
2576 x=annotate_info->x;
2577 y=annotate_info->y;
2578 p=annotate_info->text;
2579 continue;
2580 }
2581 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2582 sizeof(*annotate_info->next));
2583 if (annotate_info->next == (XAnnotateInfo *) NULL)
2584 return(MagickFalse);
2585 *annotate_info->next=(*annotate_info);
2586 annotate_info->next->previous=annotate_info;
2587 annotate_info=annotate_info->next;
2588 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2589 windows->image.width/MagickMax((ssize_t)
2590 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2591 if (annotate_info->text == (char *) NULL)
2592 return(MagickFalse);
2593 annotate_info->y+=annotate_info->height;
2594 if (annotate_info->y > (int) windows->image.height)
2595 annotate_info->y=(int) annotate_info->height;
2596 annotate_info->next=(XAnnotateInfo *) NULL;
2597 x=annotate_info->x;
2598 y=annotate_info->y;
2599 p=annotate_info->text;
2600 }
2601 (void) XFree((void *) data);
2602 break;
2603 }
2604 default:
2605 break;
2606 }
2607 } while ((state & ExitState) == 0);
2608 (void) XFreeCursor(display,cursor);
2609 /*
2610 Annotation is relative to image configuration.
2611 */
2612 width=(unsigned int) image->columns;
2613 height=(unsigned int) image->rows;
2614 x=0;
2615 y=0;
2616 if (windows->image.crop_geometry != (char *) NULL)
2617 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2618 /*
2619 Initialize annotated image.
2620 */
2621 XSetCursorState(display,windows,MagickTrue);
2622 XCheckRefreshWindows(display,windows);
2623 while (annotate_info != (XAnnotateInfo *) NULL)
2624 {
2625 if (annotate_info->width == 0)
2626 {
2627 /*
2628 No text on this line-- go to the next line of text.
2629 */
2630 previous_info=annotate_info->previous;
2631 annotate_info->text=(char *)
2632 RelinquishMagickMemory(annotate_info->text);
2633 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2634 annotate_info=previous_info;
2635 continue;
2636 }
2637 /*
2638 Determine pixel index for box and pen color.
2639 */
2640 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2641 if (windows->pixel_info->colors != 0)
2642 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2643 if (windows->pixel_info->pixels[i] ==
2644 windows->pixel_info->pen_colors[box_id].pixel)
2645 {
2646 windows->pixel_info->box_index=(unsigned short) i;
2647 break;
2648 }
2649 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2650 if (windows->pixel_info->colors != 0)
2651 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2652 if (windows->pixel_info->pixels[i] ==
2653 windows->pixel_info->pen_colors[pen_id].pixel)
2654 {
2655 windows->pixel_info->pen_index=(unsigned short) i;
2656 break;
2657 }
2658 /*
2659 Define the annotate geometry string.
2660 */
2661 annotate_info->x=(int)
2662 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2663 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2664 windows->image.y)/windows->image.ximage->height;
2665 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
2666 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2667 height*annotate_info->height/windows->image.ximage->height,
2668 annotate_info->x+x,annotate_info->y+y);
2669 /*
2670 Annotate image with text.
2671 */
2672 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2673 if (status == 0)
2674 return(MagickFalse);
2675 /*
2676 Free up memory.
2677 */
2678 previous_info=annotate_info->previous;
2679 annotate_info->text=DestroyString(annotate_info->text);
2680 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2681 annotate_info=previous_info;
2682 }
2683 (void) XSetForeground(display,annotate_context,
2684 windows->pixel_info->foreground_color.pixel);
2685 (void) XSetBackground(display,annotate_context,
2686 windows->pixel_info->background_color.pixel);
2687 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2688 XSetCursorState(display,windows,MagickFalse);
2689 (void) XFreeFont(display,font_info);
2690 /*
2691 Update image configuration.
2692 */
2693 XConfigureImageColormap(display,resource_info,windows,image);
2694 (void) XConfigureImage(display,resource_info,windows,image);
2695 return(MagickTrue);
2696 }
2697
2698 /*
2699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700 % %
2701 % %
2702 % %
2703 + X B a c k g r o u n d I m a g e %
2704 % %
2705 % %
2706 % %
2707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708 %
2709 % XBackgroundImage() displays the image in the background of a window.
2710 %
2711 % The format of the XBackgroundImage method is:
2712 %
2713 % MagickBooleanType XBackgroundImage(Display *display,
2714 % XResourceInfo *resource_info,XWindows *windows,Image **image)
2715 %
2716 % A description of each parameter follows:
2717 %
2718 % o display: Specifies a connection to an X server; returned from
2719 % XOpenDisplay.
2720 %
2721 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2722 %
2723 % o windows: Specifies a pointer to a XWindows structure.
2724 %
2725 % o image: the image.
2726 %
2727 */
XBackgroundImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)2728 static MagickBooleanType XBackgroundImage(Display *display,
2729 XResourceInfo *resource_info,XWindows *windows,Image **image)
2730 {
2731 #define BackgroundImageTag "Background/Image"
2732
2733 int
2734 status;
2735
2736 static char
2737 window_id[MaxTextExtent] = "root";
2738
2739 XResourceInfo
2740 background_resources;
2741
2742 /*
2743 Put image in background.
2744 */
2745 status=XDialogWidget(display,windows,"Background",
2746 "Enter window id (id 0x00 selects window with pointer):",window_id);
2747 if (*window_id == '\0')
2748 return(MagickFalse);
2749 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2750 XInfoWidget(display,windows,BackgroundImageTag);
2751 XSetCursorState(display,windows,MagickTrue);
2752 XCheckRefreshWindows(display,windows);
2753 background_resources=(*resource_info);
2754 background_resources.window_id=window_id;
2755 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2756 status=XDisplayBackgroundImage(display,&background_resources,*image);
2757 if (status != MagickFalse)
2758 XClientMessage(display,windows->image.id,windows->im_protocols,
2759 windows->im_retain_colors,CurrentTime);
2760 XSetCursorState(display,windows,MagickFalse);
2761 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2762 return(MagickTrue);
2763 }
2764
2765 /*
2766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767 % %
2768 % %
2769 % %
2770 + X C h o p I m a g e %
2771 % %
2772 % %
2773 % %
2774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775 %
2776 % XChopImage() chops the X image.
2777 %
2778 % The format of the XChopImage method is:
2779 %
2780 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2781 % XWindows *windows,Image **image)
2782 %
2783 % A description of each parameter follows:
2784 %
2785 % o display: Specifies a connection to an X server; returned from
2786 % XOpenDisplay.
2787 %
2788 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2789 %
2790 % o windows: Specifies a pointer to a XWindows structure.
2791 %
2792 % o image: the image.
2793 %
2794 */
XChopImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)2795 static MagickBooleanType XChopImage(Display *display,
2796 XResourceInfo *resource_info,XWindows *windows,Image **image)
2797 {
2798 const char
2799 *const ChopMenu[] =
2800 {
2801 "Direction",
2802 "Help",
2803 "Dismiss",
2804 (char *) NULL
2805 };
2806
2807 static ModeType
2808 direction = HorizontalChopCommand;
2809
2810 static const ModeType
2811 ChopCommands[] =
2812 {
2813 ChopDirectionCommand,
2814 ChopHelpCommand,
2815 ChopDismissCommand
2816 },
2817 DirectionCommands[] =
2818 {
2819 HorizontalChopCommand,
2820 VerticalChopCommand
2821 };
2822
2823 char
2824 text[MaxTextExtent];
2825
2826 Image
2827 *chop_image;
2828
2829 int
2830 id,
2831 x,
2832 y;
2833
2834 MagickRealType
2835 scale_factor;
2836
2837 RectangleInfo
2838 chop_info;
2839
2840 unsigned int
2841 distance,
2842 height,
2843 width;
2844
2845 size_t
2846 state;
2847
2848 XEvent
2849 event;
2850
2851 XSegment
2852 segment_info;
2853
2854 /*
2855 Map Command widget.
2856 */
2857 (void) CloneString(&windows->command.name,"Chop");
2858 windows->command.data=1;
2859 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2860 (void) XMapRaised(display,windows->command.id);
2861 XClientMessage(display,windows->image.id,windows->im_protocols,
2862 windows->im_update_widget,CurrentTime);
2863 /*
2864 Track pointer until button 1 is pressed.
2865 */
2866 XQueryPosition(display,windows->image.id,&x,&y);
2867 (void) XSelectInput(display,windows->image.id,
2868 windows->image.attributes.event_mask | PointerMotionMask);
2869 state=DefaultState;
2870 (void) memset(&segment_info,0,sizeof(segment_info));
2871 do
2872 {
2873 if (windows->info.mapped != MagickFalse)
2874 {
2875 /*
2876 Display pointer position.
2877 */
2878 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
2879 x+windows->image.x,y+windows->image.y);
2880 XInfoWidget(display,windows,text);
2881 }
2882 /*
2883 Wait for next event.
2884 */
2885 XScreenEvent(display,windows,&event);
2886 if (event.xany.window == windows->command.id)
2887 {
2888 /*
2889 Select a command from the Command widget.
2890 */
2891 id=XCommandWidget(display,windows,ChopMenu,&event);
2892 if (id < 0)
2893 continue;
2894 switch (ChopCommands[id])
2895 {
2896 case ChopDirectionCommand:
2897 {
2898 char
2899 command[MaxTextExtent];
2900
2901 const char
2902 *const Directions[] =
2903 {
2904 "horizontal",
2905 "vertical",
2906 (char *) NULL,
2907 };
2908
2909 /*
2910 Select a command from the pop-up menu.
2911 */
2912 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2913 if (id >= 0)
2914 direction=DirectionCommands[id];
2915 break;
2916 }
2917 case ChopHelpCommand:
2918 {
2919 XTextViewHelp(display,resource_info,windows,MagickFalse,
2920 "Help Viewer - Image Chop",ImageChopHelp);
2921 break;
2922 }
2923 case ChopDismissCommand:
2924 {
2925 /*
2926 Prematurely exit.
2927 */
2928 state|=EscapeState;
2929 state|=ExitState;
2930 break;
2931 }
2932 default:
2933 break;
2934 }
2935 continue;
2936 }
2937 switch (event.type)
2938 {
2939 case ButtonPress:
2940 {
2941 if (event.xbutton.button != Button1)
2942 break;
2943 if (event.xbutton.window != windows->image.id)
2944 break;
2945 /*
2946 User has committed to start point of chopping line.
2947 */
2948 segment_info.x1=(short int) event.xbutton.x;
2949 segment_info.x2=(short int) event.xbutton.x;
2950 segment_info.y1=(short int) event.xbutton.y;
2951 segment_info.y2=(short int) event.xbutton.y;
2952 state|=ExitState;
2953 break;
2954 }
2955 case ButtonRelease:
2956 break;
2957 case Expose:
2958 break;
2959 case KeyPress:
2960 {
2961 char
2962 command[MaxTextExtent];
2963
2964 KeySym
2965 key_symbol;
2966
2967 if (event.xkey.window != windows->image.id)
2968 break;
2969 /*
2970 Respond to a user key press.
2971 */
2972 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2973 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2974 switch ((int) key_symbol)
2975 {
2976 case XK_Escape:
2977 case XK_F20:
2978 {
2979 /*
2980 Prematurely exit.
2981 */
2982 state|=EscapeState;
2983 state|=ExitState;
2984 break;
2985 }
2986 case XK_F1:
2987 case XK_Help:
2988 {
2989 (void) XSetFunction(display,windows->image.highlight_context,
2990 GXcopy);
2991 XTextViewHelp(display,resource_info,windows,MagickFalse,
2992 "Help Viewer - Image Chop",ImageChopHelp);
2993 (void) XSetFunction(display,windows->image.highlight_context,
2994 GXinvert);
2995 break;
2996 }
2997 default:
2998 {
2999 (void) XBell(display,0);
3000 break;
3001 }
3002 }
3003 break;
3004 }
3005 case MotionNotify:
3006 {
3007 /*
3008 Map and unmap Info widget as text cursor crosses its boundaries.
3009 */
3010 x=event.xmotion.x;
3011 y=event.xmotion.y;
3012 if (windows->info.mapped != MagickFalse)
3013 {
3014 if ((x < (int) (windows->info.x+windows->info.width)) &&
3015 (y < (int) (windows->info.y+windows->info.height)))
3016 (void) XWithdrawWindow(display,windows->info.id,
3017 windows->info.screen);
3018 }
3019 else
3020 if ((x > (int) (windows->info.x+windows->info.width)) ||
3021 (y > (int) (windows->info.y+windows->info.height)))
3022 (void) XMapWindow(display,windows->info.id);
3023 }
3024 }
3025 } while ((state & ExitState) == 0);
3026 (void) XSelectInput(display,windows->image.id,
3027 windows->image.attributes.event_mask);
3028 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3029 if ((state & EscapeState) != 0)
3030 return(MagickTrue);
3031 /*
3032 Draw line as pointer moves until the mouse button is released.
3033 */
3034 chop_info.width=0;
3035 chop_info.height=0;
3036 chop_info.x=0;
3037 chop_info.y=0;
3038 distance=0;
3039 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3040 state=DefaultState;
3041 do
3042 {
3043 if (distance > 9)
3044 {
3045 /*
3046 Display info and draw chopping line.
3047 */
3048 if (windows->info.mapped == MagickFalse)
3049 (void) XMapWindow(display,windows->info.id);
3050 (void) FormatLocaleString(text,MaxTextExtent,
3051 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3052 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3053 XInfoWidget(display,windows,text);
3054 XHighlightLine(display,windows->image.id,
3055 windows->image.highlight_context,&segment_info);
3056 }
3057 else
3058 if (windows->info.mapped != MagickFalse)
3059 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3060 /*
3061 Wait for next event.
3062 */
3063 XScreenEvent(display,windows,&event);
3064 if (distance > 9)
3065 XHighlightLine(display,windows->image.id,
3066 windows->image.highlight_context,&segment_info);
3067 switch (event.type)
3068 {
3069 case ButtonPress:
3070 {
3071 segment_info.x2=(short int) event.xmotion.x;
3072 segment_info.y2=(short int) event.xmotion.y;
3073 break;
3074 }
3075 case ButtonRelease:
3076 {
3077 /*
3078 User has committed to chopping line.
3079 */
3080 segment_info.x2=(short int) event.xbutton.x;
3081 segment_info.y2=(short int) event.xbutton.y;
3082 state|=ExitState;
3083 break;
3084 }
3085 case Expose:
3086 break;
3087 case MotionNotify:
3088 {
3089 segment_info.x2=(short int) event.xmotion.x;
3090 segment_info.y2=(short int) event.xmotion.y;
3091 }
3092 default:
3093 break;
3094 }
3095 /*
3096 Check boundary conditions.
3097 */
3098 if (segment_info.x2 < 0)
3099 segment_info.x2=0;
3100 else
3101 if (segment_info.x2 > windows->image.ximage->width)
3102 segment_info.x2=windows->image.ximage->width;
3103 if (segment_info.y2 < 0)
3104 segment_info.y2=0;
3105 else
3106 if (segment_info.y2 > windows->image.ximage->height)
3107 segment_info.y2=windows->image.ximage->height;
3108 distance=(unsigned int)
3109 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3110 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3111 /*
3112 Compute chopping geometry.
3113 */
3114 if (direction == HorizontalChopCommand)
3115 {
3116 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3117 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3118 chop_info.height=0;
3119 chop_info.y=0;
3120 if (segment_info.x1 > (int) segment_info.x2)
3121 {
3122 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3123 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3124 }
3125 }
3126 else
3127 {
3128 chop_info.width=0;
3129 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3130 chop_info.x=0;
3131 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3132 if (segment_info.y1 > segment_info.y2)
3133 {
3134 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3135 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3136 }
3137 }
3138 } while ((state & ExitState) == 0);
3139 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3140 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3141 if (distance <= 9)
3142 return(MagickTrue);
3143 /*
3144 Image chopping is relative to image configuration.
3145 */
3146 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3147 XSetCursorState(display,windows,MagickTrue);
3148 XCheckRefreshWindows(display,windows);
3149 windows->image.window_changes.width=windows->image.ximage->width-
3150 (unsigned int) chop_info.width;
3151 windows->image.window_changes.height=windows->image.ximage->height-
3152 (unsigned int) chop_info.height;
3153 width=(unsigned int) (*image)->columns;
3154 height=(unsigned int) (*image)->rows;
3155 x=0;
3156 y=0;
3157 if (windows->image.crop_geometry != (char *) NULL)
3158 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3159 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3160 chop_info.x+=x;
3161 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3162 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3163 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3164 chop_info.y+=y;
3165 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3166 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3167 /*
3168 Chop image.
3169 */
3170 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3171 XSetCursorState(display,windows,MagickFalse);
3172 if (chop_image == (Image *) NULL)
3173 return(MagickFalse);
3174 *image=DestroyImage(*image);
3175 *image=chop_image;
3176 /*
3177 Update image configuration.
3178 */
3179 XConfigureImageColormap(display,resource_info,windows,*image);
3180 (void) XConfigureImage(display,resource_info,windows,*image);
3181 return(MagickTrue);
3182 }
3183
3184 /*
3185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3186 % %
3187 % %
3188 % %
3189 + X C o l o r E d i t I m a g e %
3190 % %
3191 % %
3192 % %
3193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3194 %
3195 % XColorEditImage() allows the user to interactively change the color of one
3196 % pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3197 %
3198 % The format of the XColorEditImage method is:
3199 %
3200 % MagickBooleanType XColorEditImage(Display *display,
3201 % XResourceInfo *resource_info,XWindows *windows,Image **image)
3202 %
3203 % A description of each parameter follows:
3204 %
3205 % o display: Specifies a connection to an X server; returned from
3206 % XOpenDisplay.
3207 %
3208 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3209 %
3210 % o windows: Specifies a pointer to a XWindows structure.
3211 %
3212 % o image: the image; returned from ReadImage.
3213 %
3214 */
3215
3216
XColorEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)3217 static MagickBooleanType XColorEditImage(Display *display,
3218 XResourceInfo *resource_info,XWindows *windows,Image **image)
3219 {
3220 const char
3221 *const ColorEditMenu[] =
3222 {
3223 "Method",
3224 "Pixel Color",
3225 "Border Color",
3226 "Fuzz",
3227 "Undo",
3228 "Help",
3229 "Dismiss",
3230 (char *) NULL
3231 };
3232
3233 static const ModeType
3234 ColorEditCommands[] =
3235 {
3236 ColorEditMethodCommand,
3237 ColorEditColorCommand,
3238 ColorEditBorderCommand,
3239 ColorEditFuzzCommand,
3240 ColorEditUndoCommand,
3241 ColorEditHelpCommand,
3242 ColorEditDismissCommand
3243 };
3244
3245 static PaintMethod
3246 method = PointMethod;
3247
3248 static unsigned int
3249 pen_id = 0;
3250
3251 static XColor
3252 border_color = { 0, 0, 0, 0, 0, 0 };
3253
3254 char
3255 command[MaxTextExtent],
3256 text[MaxTextExtent];
3257
3258 Cursor
3259 cursor;
3260
3261 ExceptionInfo
3262 *exception;
3263
3264 int
3265 entry,
3266 id,
3267 x,
3268 x_offset,
3269 y,
3270 y_offset;
3271
3272 PixelPacket
3273 *q;
3274
3275 ssize_t
3276 i;
3277
3278 unsigned int
3279 height,
3280 width;
3281
3282 size_t
3283 state;
3284
3285 XColor
3286 color;
3287
3288 XEvent
3289 event;
3290
3291 /*
3292 Map Command widget.
3293 */
3294 (void) CloneString(&windows->command.name,"Color Edit");
3295 windows->command.data=4;
3296 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3297 (void) XMapRaised(display,windows->command.id);
3298 XClientMessage(display,windows->image.id,windows->im_protocols,
3299 windows->im_update_widget,CurrentTime);
3300 /*
3301 Make cursor.
3302 */
3303 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3304 resource_info->background_color,resource_info->foreground_color);
3305 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3306 /*
3307 Track pointer until button 1 is pressed.
3308 */
3309 XQueryPosition(display,windows->image.id,&x,&y);
3310 (void) XSelectInput(display,windows->image.id,
3311 windows->image.attributes.event_mask | PointerMotionMask);
3312 state=DefaultState;
3313 do
3314 {
3315 if (windows->info.mapped != MagickFalse)
3316 {
3317 /*
3318 Display pointer position.
3319 */
3320 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
3321 x+windows->image.x,y+windows->image.y);
3322 XInfoWidget(display,windows,text);
3323 }
3324 /*
3325 Wait for next event.
3326 */
3327 XScreenEvent(display,windows,&event);
3328 if (event.xany.window == windows->command.id)
3329 {
3330 /*
3331 Select a command from the Command widget.
3332 */
3333 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3334 if (id < 0)
3335 {
3336 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3337 continue;
3338 }
3339 switch (ColorEditCommands[id])
3340 {
3341 case ColorEditMethodCommand:
3342 {
3343 char
3344 **methods;
3345
3346 /*
3347 Select a method from the pop-up menu.
3348 */
3349 methods=(char **) GetCommandOptions(MagickMethodOptions);
3350 if (methods == (char **) NULL)
3351 break;
3352 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3353 (const char **) methods,command);
3354 if (entry >= 0)
3355 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3356 MagickFalse,methods[entry]);
3357 methods=DestroyStringList(methods);
3358 break;
3359 }
3360 case ColorEditColorCommand:
3361 {
3362 const char
3363 *ColorMenu[MaxNumberPens];
3364
3365 int
3366 pen_number;
3367
3368 /*
3369 Initialize menu selections.
3370 */
3371 for (i=0; i < (int) (MaxNumberPens-2); i++)
3372 ColorMenu[i]=resource_info->pen_colors[i];
3373 ColorMenu[MaxNumberPens-2]="Browser...";
3374 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3375 /*
3376 Select a pen color from the pop-up menu.
3377 */
3378 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3379 (const char **) ColorMenu,command);
3380 if (pen_number < 0)
3381 break;
3382 if (pen_number == (MaxNumberPens-2))
3383 {
3384 static char
3385 color_name[MaxTextExtent] = "gray";
3386
3387 /*
3388 Select a pen color from a dialog.
3389 */
3390 resource_info->pen_colors[pen_number]=color_name;
3391 XColorBrowserWidget(display,windows,"Select",color_name);
3392 if (*color_name == '\0')
3393 break;
3394 }
3395 /*
3396 Set pen color.
3397 */
3398 (void) XParseColor(display,windows->map_info->colormap,
3399 resource_info->pen_colors[pen_number],&color);
3400 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3401 (unsigned int) MaxColors,&color);
3402 windows->pixel_info->pen_colors[pen_number]=color;
3403 pen_id=(unsigned int) pen_number;
3404 break;
3405 }
3406 case ColorEditBorderCommand:
3407 {
3408 const char
3409 *ColorMenu[MaxNumberPens];
3410
3411 int
3412 pen_number;
3413
3414 /*
3415 Initialize menu selections.
3416 */
3417 for (i=0; i < (int) (MaxNumberPens-2); i++)
3418 ColorMenu[i]=resource_info->pen_colors[i];
3419 ColorMenu[MaxNumberPens-2]="Browser...";
3420 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3421 /*
3422 Select a pen color from the pop-up menu.
3423 */
3424 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3425 (const char **) ColorMenu,command);
3426 if (pen_number < 0)
3427 break;
3428 if (pen_number == (MaxNumberPens-2))
3429 {
3430 static char
3431 color_name[MaxTextExtent] = "gray";
3432
3433 /*
3434 Select a pen color from a dialog.
3435 */
3436 resource_info->pen_colors[pen_number]=color_name;
3437 XColorBrowserWidget(display,windows,"Select",color_name);
3438 if (*color_name == '\0')
3439 break;
3440 }
3441 /*
3442 Set border color.
3443 */
3444 (void) XParseColor(display,windows->map_info->colormap,
3445 resource_info->pen_colors[pen_number],&border_color);
3446 break;
3447 }
3448 case ColorEditFuzzCommand:
3449 {
3450 static char
3451 fuzz[MaxTextExtent];
3452
3453 static const char
3454 *FuzzMenu[] =
3455 {
3456 "0%",
3457 "2%",
3458 "5%",
3459 "10%",
3460 "15%",
3461 "Dialog...",
3462 (char *) NULL,
3463 };
3464
3465 /*
3466 Select a command from the pop-up menu.
3467 */
3468 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3469 command);
3470 if (entry < 0)
3471 break;
3472 if (entry != 5)
3473 {
3474 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
3475 QuantumRange+1.0);
3476 break;
3477 }
3478 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3479 (void) XDialogWidget(display,windows,"Ok",
3480 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3481 if (*fuzz == '\0')
3482 break;
3483 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
3484 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3485 1.0);
3486 break;
3487 }
3488 case ColorEditUndoCommand:
3489 {
3490 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3491 image);
3492 break;
3493 }
3494 case ColorEditHelpCommand:
3495 default:
3496 {
3497 XTextViewHelp(display,resource_info,windows,MagickFalse,
3498 "Help Viewer - Image Annotation",ImageColorEditHelp);
3499 break;
3500 }
3501 case ColorEditDismissCommand:
3502 {
3503 /*
3504 Prematurely exit.
3505 */
3506 state|=EscapeState;
3507 state|=ExitState;
3508 break;
3509 }
3510 }
3511 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3512 continue;
3513 }
3514 switch (event.type)
3515 {
3516 case ButtonPress:
3517 {
3518 if (event.xbutton.button != Button1)
3519 break;
3520 if ((event.xbutton.window != windows->image.id) &&
3521 (event.xbutton.window != windows->magnify.id))
3522 break;
3523 /*
3524 exit loop.
3525 */
3526 x=event.xbutton.x;
3527 y=event.xbutton.y;
3528 (void) XMagickCommand(display,resource_info,windows,
3529 SaveToUndoBufferCommand,image);
3530 state|=UpdateConfigurationState;
3531 break;
3532 }
3533 case ButtonRelease:
3534 {
3535 if (event.xbutton.button != Button1)
3536 break;
3537 if ((event.xbutton.window != windows->image.id) &&
3538 (event.xbutton.window != windows->magnify.id))
3539 break;
3540 /*
3541 Update colormap information.
3542 */
3543 x=event.xbutton.x;
3544 y=event.xbutton.y;
3545 XConfigureImageColormap(display,resource_info,windows,*image);
3546 (void) XConfigureImage(display,resource_info,windows,*image);
3547 XInfoWidget(display,windows,text);
3548 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3549 state&=(~UpdateConfigurationState);
3550 break;
3551 }
3552 case Expose:
3553 break;
3554 case KeyPress:
3555 {
3556 KeySym
3557 key_symbol;
3558
3559 if (event.xkey.window == windows->magnify.id)
3560 {
3561 Window
3562 window;
3563
3564 window=windows->magnify.id;
3565 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3566 }
3567 if (event.xkey.window != windows->image.id)
3568 break;
3569 /*
3570 Respond to a user key press.
3571 */
3572 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3573 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3574 switch ((int) key_symbol)
3575 {
3576 case XK_Escape:
3577 case XK_F20:
3578 {
3579 /*
3580 Prematurely exit.
3581 */
3582 state|=ExitState;
3583 break;
3584 }
3585 case XK_F1:
3586 case XK_Help:
3587 {
3588 XTextViewHelp(display,resource_info,windows,MagickFalse,
3589 "Help Viewer - Image Annotation",ImageColorEditHelp);
3590 break;
3591 }
3592 default:
3593 {
3594 (void) XBell(display,0);
3595 break;
3596 }
3597 }
3598 break;
3599 }
3600 case MotionNotify:
3601 {
3602 /*
3603 Map and unmap Info widget as cursor crosses its boundaries.
3604 */
3605 x=event.xmotion.x;
3606 y=event.xmotion.y;
3607 if (windows->info.mapped != MagickFalse)
3608 {
3609 if ((x < (int) (windows->info.x+windows->info.width)) &&
3610 (y < (int) (windows->info.y+windows->info.height)))
3611 (void) XWithdrawWindow(display,windows->info.id,
3612 windows->info.screen);
3613 }
3614 else
3615 if ((x > (int) (windows->info.x+windows->info.width)) ||
3616 (y > (int) (windows->info.y+windows->info.height)))
3617 (void) XMapWindow(display,windows->info.id);
3618 break;
3619 }
3620 default:
3621 break;
3622 }
3623 if (event.xany.window == windows->magnify.id)
3624 {
3625 x=windows->magnify.x-windows->image.x;
3626 y=windows->magnify.y-windows->image.y;
3627 }
3628 x_offset=x;
3629 y_offset=y;
3630 if ((state & UpdateConfigurationState) != 0)
3631 {
3632 CacheView
3633 *image_view;
3634
3635 int
3636 x,
3637 y;
3638
3639 /*
3640 Pixel edit is relative to image configuration.
3641 */
3642 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3643 MagickTrue);
3644 color=windows->pixel_info->pen_colors[pen_id];
3645 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3646 width=(unsigned int) (*image)->columns;
3647 height=(unsigned int) (*image)->rows;
3648 x=0;
3649 y=0;
3650 if (windows->image.crop_geometry != (char *) NULL)
3651 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3652 &width,&height);
3653 x_offset=(int)
3654 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3655 y_offset=(int)
3656 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3657 if ((x_offset < 0) || (y_offset < 0))
3658 continue;
3659 if ((x_offset >= (int) (*image)->columns) ||
3660 (y_offset >= (int) (*image)->rows))
3661 continue;
3662 exception=(&(*image)->exception);
3663 image_view=AcquireAuthenticCacheView(*image,exception);
3664 switch (method)
3665 {
3666 case PointMethod:
3667 default:
3668 {
3669 /*
3670 Update color information using point algorithm.
3671 */
3672 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3673 return(MagickFalse);
3674 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3675 (ssize_t)y_offset,1,1,exception);
3676 if (q == (PixelPacket *) NULL)
3677 break;
3678 q->red=ScaleShortToQuantum(color.red);
3679 q->green=ScaleShortToQuantum(color.green);
3680 q->blue=ScaleShortToQuantum(color.blue);
3681 (void) SyncCacheViewAuthenticPixels(image_view,
3682 &(*image)->exception);
3683 break;
3684 }
3685 case ReplaceMethod:
3686 {
3687 PixelPacket
3688 target;
3689
3690 /*
3691 Update color information using replace algorithm.
3692 */
3693 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
3694 (ssize_t) y_offset,&target,&(*image)->exception);
3695 if ((*image)->storage_class == DirectClass)
3696 {
3697 for (y=0; y < (int) (*image)->rows; y++)
3698 {
3699 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3700 (*image)->columns,1,exception);
3701 if (q == (PixelPacket *) NULL)
3702 break;
3703 for (x=0; x < (int) (*image)->columns; x++)
3704 {
3705 if (IsColorSimilar(*image,q,&target) != MagickFalse)
3706 {
3707 q->red=ScaleShortToQuantum(color.red);
3708 q->green=ScaleShortToQuantum(color.green);
3709 q->blue=ScaleShortToQuantum(color.blue);
3710 }
3711 q++;
3712 }
3713 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3714 break;
3715 }
3716 }
3717 else
3718 {
3719 for (i=0; i < (ssize_t) (*image)->colors; i++)
3720 if (IsColorSimilar(*image,(*image)->colormap+i,&target) != MagickFalse)
3721 {
3722 (*image)->colormap[i].red=ScaleShortToQuantum(color.red);
3723 (*image)->colormap[i].green=ScaleShortToQuantum(
3724 color.green);
3725 (*image)->colormap[i].blue=ScaleShortToQuantum(
3726 color.blue);
3727 }
3728 (void) SyncImage(*image);
3729 }
3730 break;
3731 }
3732 case FloodfillMethod:
3733 case FillToBorderMethod:
3734 {
3735 DrawInfo
3736 *draw_info;
3737
3738 MagickPixelPacket
3739 target;
3740
3741 /*
3742 Update color information using floodfill algorithm.
3743 */
3744 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3745 (ssize_t) y_offset,&target,exception);
3746 if (method == FillToBorderMethod)
3747 {
3748 target.red=(MagickRealType)
3749 ScaleShortToQuantum(border_color.red);
3750 target.green=(MagickRealType)
3751 ScaleShortToQuantum(border_color.green);
3752 target.blue=(MagickRealType)
3753 ScaleShortToQuantum(border_color.blue);
3754 }
3755 draw_info=CloneDrawInfo(resource_info->image_info,
3756 (DrawInfo *) NULL);
3757 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3758 &draw_info->fill,exception);
3759 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
3760 (ssize_t) x_offset,(ssize_t) y_offset,
3761 method == FloodfillMethod ? MagickFalse : MagickTrue);
3762 draw_info=DestroyDrawInfo(draw_info);
3763 break;
3764 }
3765 case ResetMethod:
3766 {
3767 /*
3768 Update color information using reset algorithm.
3769 */
3770 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3771 return(MagickFalse);
3772 for (y=0; y < (int) (*image)->rows; y++)
3773 {
3774 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3775 (*image)->columns,1,exception);
3776 if (q == (PixelPacket *) NULL)
3777 break;
3778 for (x=0; x < (int) (*image)->columns; x++)
3779 {
3780 q->red=ScaleShortToQuantum(color.red);
3781 q->green=ScaleShortToQuantum(color.green);
3782 q->blue=ScaleShortToQuantum(color.blue);
3783 q++;
3784 }
3785 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3786 break;
3787 }
3788 break;
3789 }
3790 }
3791 image_view=DestroyCacheView(image_view);
3792 state&=(~UpdateConfigurationState);
3793 }
3794 } while ((state & ExitState) == 0);
3795 (void) XSelectInput(display,windows->image.id,
3796 windows->image.attributes.event_mask);
3797 XSetCursorState(display,windows,MagickFalse);
3798 (void) XFreeCursor(display,cursor);
3799 return(MagickTrue);
3800 }
3801
3802 /*
3803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3804 % %
3805 % %
3806 % %
3807 + X C o m p o s i t e I m a g e %
3808 % %
3809 % %
3810 % %
3811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3812 %
3813 % XCompositeImage() requests an image name from the user, reads the image and
3814 % composites it with the X window image at a location the user chooses with
3815 % the pointer.
3816 %
3817 % The format of the XCompositeImage method is:
3818 %
3819 % MagickBooleanType XCompositeImage(Display *display,
3820 % XResourceInfo *resource_info,XWindows *windows,Image *image)
3821 %
3822 % A description of each parameter follows:
3823 %
3824 % o display: Specifies a connection to an X server; returned from
3825 % XOpenDisplay.
3826 %
3827 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3828 %
3829 % o windows: Specifies a pointer to a XWindows structure.
3830 %
3831 % o image: the image; returned from ReadImage.
3832 %
3833 */
XCompositeImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)3834 static MagickBooleanType XCompositeImage(Display *display,
3835 XResourceInfo *resource_info,XWindows *windows,Image *image)
3836 {
3837 const char
3838 *const CompositeMenu[] =
3839 {
3840 "Operators",
3841 "Dissolve",
3842 "Displace",
3843 "Help",
3844 "Dismiss",
3845 (char *) NULL
3846 };
3847
3848 static char
3849 displacement_geometry[MaxTextExtent] = "30x30",
3850 filename[MaxTextExtent] = "\0";
3851
3852 static CompositeOperator
3853 compose = CopyCompositeOp;
3854
3855 static const ModeType
3856 CompositeCommands[] =
3857 {
3858 CompositeOperatorsCommand,
3859 CompositeDissolveCommand,
3860 CompositeDisplaceCommand,
3861 CompositeHelpCommand,
3862 CompositeDismissCommand
3863 };
3864
3865 char
3866 text[MaxTextExtent];
3867
3868 Cursor
3869 cursor;
3870
3871 Image
3872 *composite_image;
3873
3874 int
3875 entry,
3876 id,
3877 x,
3878 y;
3879
3880 MagickRealType
3881 blend,
3882 scale_factor;
3883
3884 RectangleInfo
3885 highlight_info,
3886 composite_info;
3887
3888 unsigned int
3889 height,
3890 width;
3891
3892 size_t
3893 state;
3894
3895 XEvent
3896 event;
3897
3898 /*
3899 Request image file name from user.
3900 */
3901 XFileBrowserWidget(display,windows,"Composite",filename);
3902 if (*filename == '\0')
3903 return(MagickTrue);
3904 /*
3905 Read image.
3906 */
3907 XSetCursorState(display,windows,MagickTrue);
3908 XCheckRefreshWindows(display,windows);
3909 (void) CopyMagickString(resource_info->image_info->filename,filename,
3910 MaxTextExtent);
3911 composite_image=ReadImage(resource_info->image_info,&image->exception);
3912 CatchException(&image->exception);
3913 XSetCursorState(display,windows,MagickFalse);
3914 if (composite_image == (Image *) NULL)
3915 return(MagickFalse);
3916 /*
3917 Map Command widget.
3918 */
3919 (void) CloneString(&windows->command.name,"Composite");
3920 windows->command.data=1;
3921 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3922 (void) XMapRaised(display,windows->command.id);
3923 XClientMessage(display,windows->image.id,windows->im_protocols,
3924 windows->im_update_widget,CurrentTime);
3925 /*
3926 Track pointer until button 1 is pressed.
3927 */
3928 XQueryPosition(display,windows->image.id,&x,&y);
3929 (void) XSelectInput(display,windows->image.id,
3930 windows->image.attributes.event_mask | PointerMotionMask);
3931 composite_info.x=(ssize_t) windows->image.x+x;
3932 composite_info.y=(ssize_t) windows->image.y+y;
3933 composite_info.width=0;
3934 composite_info.height=0;
3935 cursor=XCreateFontCursor(display,XC_ul_angle);
3936 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3937 blend=0.0;
3938 state=DefaultState;
3939 do
3940 {
3941 if (windows->info.mapped != MagickFalse)
3942 {
3943 /*
3944 Display pointer position.
3945 */
3946 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
3947 (long) composite_info.x,(long) composite_info.y);
3948 XInfoWidget(display,windows,text);
3949 }
3950 highlight_info=composite_info;
3951 highlight_info.x=composite_info.x-windows->image.x;
3952 highlight_info.y=composite_info.y-windows->image.y;
3953 XHighlightRectangle(display,windows->image.id,
3954 windows->image.highlight_context,&highlight_info);
3955 /*
3956 Wait for next event.
3957 */
3958 XScreenEvent(display,windows,&event);
3959 XHighlightRectangle(display,windows->image.id,
3960 windows->image.highlight_context,&highlight_info);
3961 if (event.xany.window == windows->command.id)
3962 {
3963 /*
3964 Select a command from the Command widget.
3965 */
3966 id=XCommandWidget(display,windows,CompositeMenu,&event);
3967 if (id < 0)
3968 continue;
3969 switch (CompositeCommands[id])
3970 {
3971 case CompositeOperatorsCommand:
3972 {
3973 char
3974 command[MaxTextExtent],
3975 **operators;
3976
3977 /*
3978 Select a command from the pop-up menu.
3979 */
3980 operators=GetCommandOptions(MagickComposeOptions);
3981 if (operators == (char **) NULL)
3982 break;
3983 entry=XMenuWidget(display,windows,CompositeMenu[id],
3984 (const char **) operators,command);
3985 if (entry >= 0)
3986 compose=(CompositeOperator) ParseCommandOption(
3987 MagickComposeOptions,MagickFalse,operators[entry]);
3988 operators=DestroyStringList(operators);
3989 break;
3990 }
3991 case CompositeDissolveCommand:
3992 {
3993 static char
3994 factor[MaxTextExtent] = "20.0";
3995
3996 /*
3997 Dissolve the two images a given percent.
3998 */
3999 (void) XSetFunction(display,windows->image.highlight_context,
4000 GXcopy);
4001 (void) XDialogWidget(display,windows,"Dissolve",
4002 "Enter the blend factor (0.0 - 99.9%):",factor);
4003 (void) XSetFunction(display,windows->image.highlight_context,
4004 GXinvert);
4005 if (*factor == '\0')
4006 break;
4007 blend=StringToDouble(factor,(char **) NULL);
4008 compose=DissolveCompositeOp;
4009 break;
4010 }
4011 case CompositeDisplaceCommand:
4012 {
4013 /*
4014 Get horizontal and vertical scale displacement geometry.
4015 */
4016 (void) XSetFunction(display,windows->image.highlight_context,
4017 GXcopy);
4018 (void) XDialogWidget(display,windows,"Displace",
4019 "Enter the horizontal and vertical scale:",displacement_geometry);
4020 (void) XSetFunction(display,windows->image.highlight_context,
4021 GXinvert);
4022 if (*displacement_geometry == '\0')
4023 break;
4024 compose=DisplaceCompositeOp;
4025 break;
4026 }
4027 case CompositeHelpCommand:
4028 {
4029 (void) XSetFunction(display,windows->image.highlight_context,
4030 GXcopy);
4031 XTextViewHelp(display,resource_info,windows,MagickFalse,
4032 "Help Viewer - Image Composite",ImageCompositeHelp);
4033 (void) XSetFunction(display,windows->image.highlight_context,
4034 GXinvert);
4035 break;
4036 }
4037 case CompositeDismissCommand:
4038 {
4039 /*
4040 Prematurely exit.
4041 */
4042 state|=EscapeState;
4043 state|=ExitState;
4044 break;
4045 }
4046 default:
4047 break;
4048 }
4049 continue;
4050 }
4051 switch (event.type)
4052 {
4053 case ButtonPress:
4054 {
4055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(X11Event,GetMagickModule(),
4057 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4058 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4059 if (event.xbutton.button != Button1)
4060 break;
4061 if (event.xbutton.window != windows->image.id)
4062 break;
4063 /*
4064 Change cursor.
4065 */
4066 composite_info.width=composite_image->columns;
4067 composite_info.height=composite_image->rows;
4068 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4069 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4070 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4071 break;
4072 }
4073 case ButtonRelease:
4074 {
4075 if (image->debug != MagickFalse)
4076 (void) LogMagickEvent(X11Event,GetMagickModule(),
4077 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4078 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4079 if (event.xbutton.button != Button1)
4080 break;
4081 if (event.xbutton.window != windows->image.id)
4082 break;
4083 if ((composite_info.width != 0) && (composite_info.height != 0))
4084 {
4085 /*
4086 User has selected the location of the composite image.
4087 */
4088 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4089 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4090 state|=ExitState;
4091 }
4092 break;
4093 }
4094 case Expose:
4095 break;
4096 case KeyPress:
4097 {
4098 char
4099 command[MaxTextExtent];
4100
4101 KeySym
4102 key_symbol;
4103
4104 int
4105 length;
4106
4107 if (event.xkey.window != windows->image.id)
4108 break;
4109 /*
4110 Respond to a user key press.
4111 */
4112 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4113 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4114 *(command+length)='\0';
4115 if (image->debug != MagickFalse)
4116 (void) LogMagickEvent(X11Event,GetMagickModule(),
4117 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4118 switch ((int) key_symbol)
4119 {
4120 case XK_Escape:
4121 case XK_F20:
4122 {
4123 /*
4124 Prematurely exit.
4125 */
4126 composite_image=DestroyImage(composite_image);
4127 state|=EscapeState;
4128 state|=ExitState;
4129 break;
4130 }
4131 case XK_F1:
4132 case XK_Help:
4133 {
4134 (void) XSetFunction(display,windows->image.highlight_context,
4135 GXcopy);
4136 XTextViewHelp(display,resource_info,windows,MagickFalse,
4137 "Help Viewer - Image Composite",ImageCompositeHelp);
4138 (void) XSetFunction(display,windows->image.highlight_context,
4139 GXinvert);
4140 break;
4141 }
4142 default:
4143 {
4144 (void) XBell(display,0);
4145 break;
4146 }
4147 }
4148 break;
4149 }
4150 case MotionNotify:
4151 {
4152 /*
4153 Map and unmap Info widget as text cursor crosses its boundaries.
4154 */
4155 x=event.xmotion.x;
4156 y=event.xmotion.y;
4157 if (windows->info.mapped != MagickFalse)
4158 {
4159 if ((x < (int) (windows->info.x+windows->info.width)) &&
4160 (y < (int) (windows->info.y+windows->info.height)))
4161 (void) XWithdrawWindow(display,windows->info.id,
4162 windows->info.screen);
4163 }
4164 else
4165 if ((x > (int) (windows->info.x+windows->info.width)) ||
4166 (y > (int) (windows->info.y+windows->info.height)))
4167 (void) XMapWindow(display,windows->info.id);
4168 composite_info.x=(ssize_t) windows->image.x+x;
4169 composite_info.y=(ssize_t) windows->image.y+y;
4170 break;
4171 }
4172 default:
4173 {
4174 if (image->debug != MagickFalse)
4175 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4176 event.type);
4177 break;
4178 }
4179 }
4180 } while ((state & ExitState) == 0);
4181 (void) XSelectInput(display,windows->image.id,
4182 windows->image.attributes.event_mask);
4183 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4184 XSetCursorState(display,windows,MagickFalse);
4185 (void) XFreeCursor(display,cursor);
4186 if ((state & EscapeState) != 0)
4187 return(MagickTrue);
4188 /*
4189 Image compositing is relative to image configuration.
4190 */
4191 XSetCursorState(display,windows,MagickTrue);
4192 XCheckRefreshWindows(display,windows);
4193 width=(unsigned int) image->columns;
4194 height=(unsigned int) image->rows;
4195 x=0;
4196 y=0;
4197 if (windows->image.crop_geometry != (char *) NULL)
4198 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4199 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4200 composite_info.x+=x;
4201 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4202 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4203 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4204 composite_info.y+=y;
4205 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4206 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4207 if ((composite_info.width != composite_image->columns) ||
4208 (composite_info.height != composite_image->rows))
4209 {
4210 Image
4211 *resize_image;
4212
4213 /*
4214 Scale composite image.
4215 */
4216 resize_image=ResizeImage(composite_image,composite_info.width,
4217 composite_info.height,composite_image->filter,composite_image->blur,
4218 &image->exception);
4219 composite_image=DestroyImage(composite_image);
4220 if (resize_image == (Image *) NULL)
4221 {
4222 XSetCursorState(display,windows,MagickFalse);
4223 return(MagickFalse);
4224 }
4225 composite_image=resize_image;
4226 }
4227 if (compose == DisplaceCompositeOp)
4228 (void) SetImageArtifact(composite_image,"compose:args",
4229 displacement_geometry);
4230 if (blend != 0.0)
4231 {
4232 CacheView
4233 *image_view;
4234
4235 ExceptionInfo
4236 *exception;
4237
4238 int
4239 y;
4240
4241 Quantum
4242 opacity;
4243
4244 int
4245 x;
4246
4247 PixelPacket
4248 *q;
4249
4250 /*
4251 Create mattes for blending.
4252 */
4253 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
4254 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4255 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
4256 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4257 return(MagickFalse);
4258 image->matte=MagickTrue;
4259 exception=(&image->exception);
4260 image_view=AcquireAuthenticCacheView(image,exception);
4261 for (y=0; y < (int) image->rows; y++)
4262 {
4263 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4264 exception);
4265 if (q == (PixelPacket *) NULL)
4266 break;
4267 for (x=0; x < (int) image->columns; x++)
4268 {
4269 q->opacity=opacity;
4270 q++;
4271 }
4272 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4273 break;
4274 }
4275 image_view=DestroyCacheView(image_view);
4276 }
4277 /*
4278 Composite image with X Image window.
4279 */
4280 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4281 composite_info.y);
4282 composite_image=DestroyImage(composite_image);
4283 XSetCursorState(display,windows,MagickFalse);
4284 /*
4285 Update image configuration.
4286 */
4287 XConfigureImageColormap(display,resource_info,windows,image);
4288 (void) XConfigureImage(display,resource_info,windows,image);
4289 return(MagickTrue);
4290 }
4291
4292 /*
4293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4294 % %
4295 % %
4296 % %
4297 + X C o n f i g u r e I m a g e %
4298 % %
4299 % %
4300 % %
4301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4302 %
4303 % XConfigureImage() creates a new X image. It also notifies the window
4304 % manager of the new image size and configures the transient widows.
4305 %
4306 % The format of the XConfigureImage method is:
4307 %
4308 % MagickBooleanType XConfigureImage(Display *display,
4309 % XResourceInfo *resource_info,XWindows *windows,Image *image)
4310 %
4311 % A description of each parameter follows:
4312 %
4313 % o display: Specifies a connection to an X server; returned from
4314 % XOpenDisplay.
4315 %
4316 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4317 %
4318 % o windows: Specifies a pointer to a XWindows structure.
4319 %
4320 % o image: the image.
4321 %
4322 %
4323 */
XConfigureImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)4324 static MagickBooleanType XConfigureImage(Display *display,
4325 XResourceInfo *resource_info,XWindows *windows,Image *image)
4326 {
4327 char
4328 geometry[MaxTextExtent];
4329
4330 MagickStatusType
4331 status;
4332
4333 size_t
4334 mask,
4335 height,
4336 width;
4337
4338 ssize_t
4339 x,
4340 y;
4341
4342 XSizeHints
4343 *size_hints;
4344
4345 XWindowChanges
4346 window_changes;
4347
4348 /*
4349 Dismiss if window dimensions are zero.
4350 */
4351 width=(unsigned int) windows->image.window_changes.width;
4352 height=(unsigned int) windows->image.window_changes.height;
4353 if (image->debug != MagickFalse)
4354 (void) LogMagickEvent(X11Event,GetMagickModule(),
4355 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4356 windows->image.ximage->height,(double) width,(double) height);
4357 if ((width*height) == 0)
4358 return(MagickTrue);
4359 x=0;
4360 y=0;
4361 /*
4362 Resize image to fit Image window dimensions.
4363 */
4364 XSetCursorState(display,windows,MagickTrue);
4365 (void) XFlush(display);
4366 if (((int) width != windows->image.ximage->width) ||
4367 ((int) height != windows->image.ximage->height))
4368 image->taint=MagickTrue;
4369 windows->magnify.x=(int)
4370 width*windows->magnify.x/windows->image.ximage->width;
4371 windows->magnify.y=(int)
4372 height*windows->magnify.y/windows->image.ximage->height;
4373 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4374 windows->image.y=(int)
4375 (height*windows->image.y/windows->image.ximage->height);
4376 status=XMakeImage(display,resource_info,&windows->image,image,
4377 (unsigned int) width,(unsigned int) height);
4378 if (status == MagickFalse)
4379 XNoticeWidget(display,windows,"Unable to configure X image:",
4380 windows->image.name);
4381 /*
4382 Notify window manager of the new configuration.
4383 */
4384 if (resource_info->image_geometry != (char *) NULL)
4385 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
4386 resource_info->image_geometry);
4387 else
4388 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4389 XDisplayWidth(display,windows->image.screen),
4390 XDisplayHeight(display,windows->image.screen));
4391 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4392 window_changes.width=(int) width;
4393 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4394 window_changes.width=XDisplayWidth(display,windows->image.screen);
4395 window_changes.height=(int) height;
4396 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4397 window_changes.height=XDisplayHeight(display,windows->image.screen);
4398 mask=(size_t) (CWWidth | CWHeight);
4399 if (resource_info->backdrop)
4400 {
4401 mask|=CWX | CWY;
4402 window_changes.x=(int)
4403 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4404 window_changes.y=(int)
4405 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4406 }
4407 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4408 (unsigned int) mask,&window_changes);
4409 (void) XClearWindow(display,windows->image.id);
4410 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4411 /*
4412 Update Magnify window configuration.
4413 */
4414 if (windows->magnify.mapped != MagickFalse)
4415 XMakeMagnifyImage(display,windows);
4416 windows->pan.crop_geometry=windows->image.crop_geometry;
4417 XBestIconSize(display,&windows->pan,image);
4418 while (((windows->pan.width << 1) < MaxIconSize) &&
4419 ((windows->pan.height << 1) < MaxIconSize))
4420 {
4421 windows->pan.width<<=1;
4422 windows->pan.height<<=1;
4423 }
4424 if (windows->pan.geometry != (char *) NULL)
4425 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4426 &windows->pan.width,&windows->pan.height);
4427 window_changes.width=(int) windows->pan.width;
4428 window_changes.height=(int) windows->pan.height;
4429 size_hints=XAllocSizeHints();
4430 if (size_hints != (XSizeHints *) NULL)
4431 {
4432 /*
4433 Set new size hints.
4434 */
4435 size_hints->flags=PSize | PMinSize | PMaxSize;
4436 size_hints->width=window_changes.width;
4437 size_hints->height=window_changes.height;
4438 size_hints->min_width=size_hints->width;
4439 size_hints->min_height=size_hints->height;
4440 size_hints->max_width=size_hints->width;
4441 size_hints->max_height=size_hints->height;
4442 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4443 (void) XFree((void *) size_hints);
4444 }
4445 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4446 (unsigned int) (CWWidth | CWHeight),&window_changes);
4447 /*
4448 Update icon window configuration.
4449 */
4450 windows->icon.crop_geometry=windows->image.crop_geometry;
4451 XBestIconSize(display,&windows->icon,image);
4452 window_changes.width=(int) windows->icon.width;
4453 window_changes.height=(int) windows->icon.height;
4454 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4455 (unsigned int) (CWWidth | CWHeight),&window_changes);
4456 XSetCursorState(display,windows,MagickFalse);
4457 return(status != 0 ? MagickTrue : MagickFalse);
4458 }
4459
4460 /*
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462 % %
4463 % %
4464 % %
4465 + X C r o p I m a g e %
4466 % %
4467 % %
4468 % %
4469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4470 %
4471 % XCropImage() allows the user to select a region of the image and crop, copy,
4472 % or cut it. For copy or cut, the image can subsequently be composited onto
4473 % the image with XPasteImage.
4474 %
4475 % The format of the XCropImage method is:
4476 %
4477 % MagickBooleanType XCropImage(Display *display,
4478 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4479 % const ClipboardMode mode)
4480 %
4481 % A description of each parameter follows:
4482 %
4483 % o display: Specifies a connection to an X server; returned from
4484 % XOpenDisplay.
4485 %
4486 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4487 %
4488 % o windows: Specifies a pointer to a XWindows structure.
4489 %
4490 % o image: the image; returned from ReadImage.
4491 %
4492 % o mode: This unsigned value specified whether the image should be
4493 % cropped, copied, or cut.
4494 %
4495 */
XCropImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,const ClipboardMode mode)4496 static MagickBooleanType XCropImage(Display *display,
4497 XResourceInfo *resource_info,XWindows *windows,Image *image,
4498 const ClipboardMode mode)
4499 {
4500 static const char
4501 *CropModeMenu[] =
4502 {
4503 "Help",
4504 "Dismiss",
4505 (char *) NULL
4506 },
4507 *RectifyModeMenu[] =
4508 {
4509 "Crop",
4510 "Help",
4511 "Dismiss",
4512 (char *) NULL
4513 };
4514
4515 static const ModeType
4516 CropCommands[] =
4517 {
4518 CropHelpCommand,
4519 CropDismissCommand
4520 },
4521 RectifyCommands[] =
4522 {
4523 RectifyCopyCommand,
4524 RectifyHelpCommand,
4525 RectifyDismissCommand
4526 };
4527
4528 CacheView
4529 *image_view;
4530
4531 char
4532 command[MaxTextExtent],
4533 text[MaxTextExtent];
4534
4535 Cursor
4536 cursor;
4537
4538 ExceptionInfo
4539 *exception;
4540
4541 int
4542 id,
4543 x,
4544 y;
4545
4546 KeySym
4547 key_symbol;
4548
4549 Image
4550 *crop_image;
4551
4552 MagickRealType
4553 scale_factor;
4554
4555 RectangleInfo
4556 crop_info,
4557 highlight_info;
4558
4559 PixelPacket
4560 *q;
4561
4562 unsigned int
4563 height,
4564 width;
4565
4566 size_t
4567 state;
4568
4569 XEvent
4570 event;
4571
4572 /*
4573 Map Command widget.
4574 */
4575 switch (mode)
4576 {
4577 case CopyMode:
4578 {
4579 (void) CloneString(&windows->command.name,"Copy");
4580 break;
4581 }
4582 case CropMode:
4583 {
4584 (void) CloneString(&windows->command.name,"Crop");
4585 break;
4586 }
4587 case CutMode:
4588 {
4589 (void) CloneString(&windows->command.name,"Cut");
4590 break;
4591 }
4592 }
4593 RectifyModeMenu[0]=windows->command.name;
4594 windows->command.data=0;
4595 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4596 (void) XMapRaised(display,windows->command.id);
4597 XClientMessage(display,windows->image.id,windows->im_protocols,
4598 windows->im_update_widget,CurrentTime);
4599 /*
4600 Track pointer until button 1 is pressed.
4601 */
4602 XQueryPosition(display,windows->image.id,&x,&y);
4603 (void) XSelectInput(display,windows->image.id,
4604 windows->image.attributes.event_mask | PointerMotionMask);
4605 crop_info.x=(ssize_t) windows->image.x+x;
4606 crop_info.y=(ssize_t) windows->image.y+y;
4607 crop_info.width=0;
4608 crop_info.height=0;
4609 cursor=XCreateFontCursor(display,XC_fleur);
4610 state=DefaultState;
4611 do
4612 {
4613 if (windows->info.mapped != MagickFalse)
4614 {
4615 /*
4616 Display pointer position.
4617 */
4618 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
4619 (long) crop_info.x,(long) crop_info.y);
4620 XInfoWidget(display,windows,text);
4621 }
4622 /*
4623 Wait for next event.
4624 */
4625 XScreenEvent(display,windows,&event);
4626 if (event.xany.window == windows->command.id)
4627 {
4628 /*
4629 Select a command from the Command widget.
4630 */
4631 id=XCommandWidget(display,windows,CropModeMenu,&event);
4632 if (id < 0)
4633 continue;
4634 switch (CropCommands[id])
4635 {
4636 case CropHelpCommand:
4637 {
4638 switch (mode)
4639 {
4640 case CopyMode:
4641 {
4642 XTextViewHelp(display,resource_info,windows,MagickFalse,
4643 "Help Viewer - Image Copy",ImageCopyHelp);
4644 break;
4645 }
4646 case CropMode:
4647 {
4648 XTextViewHelp(display,resource_info,windows,MagickFalse,
4649 "Help Viewer - Image Crop",ImageCropHelp);
4650 break;
4651 }
4652 case CutMode:
4653 {
4654 XTextViewHelp(display,resource_info,windows,MagickFalse,
4655 "Help Viewer - Image Cut",ImageCutHelp);
4656 break;
4657 }
4658 }
4659 break;
4660 }
4661 case CropDismissCommand:
4662 {
4663 /*
4664 Prematurely exit.
4665 */
4666 state|=EscapeState;
4667 state|=ExitState;
4668 break;
4669 }
4670 default:
4671 break;
4672 }
4673 continue;
4674 }
4675 switch (event.type)
4676 {
4677 case ButtonPress:
4678 {
4679 if (event.xbutton.button != Button1)
4680 break;
4681 if (event.xbutton.window != windows->image.id)
4682 break;
4683 /*
4684 Note first corner of cropping rectangle-- exit loop.
4685 */
4686 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4687 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4688 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4689 state|=ExitState;
4690 break;
4691 }
4692 case ButtonRelease:
4693 break;
4694 case Expose:
4695 break;
4696 case KeyPress:
4697 {
4698 if (event.xkey.window != windows->image.id)
4699 break;
4700 /*
4701 Respond to a user key press.
4702 */
4703 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4704 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4705 switch ((int) key_symbol)
4706 {
4707 case XK_Escape:
4708 case XK_F20:
4709 {
4710 /*
4711 Prematurely exit.
4712 */
4713 state|=EscapeState;
4714 state|=ExitState;
4715 break;
4716 }
4717 case XK_F1:
4718 case XK_Help:
4719 {
4720 switch (mode)
4721 {
4722 case CopyMode:
4723 {
4724 XTextViewHelp(display,resource_info,windows,MagickFalse,
4725 "Help Viewer - Image Copy",ImageCopyHelp);
4726 break;
4727 }
4728 case CropMode:
4729 {
4730 XTextViewHelp(display,resource_info,windows,MagickFalse,
4731 "Help Viewer - Image Crop",ImageCropHelp);
4732 break;
4733 }
4734 case CutMode:
4735 {
4736 XTextViewHelp(display,resource_info,windows,MagickFalse,
4737 "Help Viewer - Image Cut",ImageCutHelp);
4738 break;
4739 }
4740 }
4741 break;
4742 }
4743 default:
4744 {
4745 (void) XBell(display,0);
4746 break;
4747 }
4748 }
4749 break;
4750 }
4751 case MotionNotify:
4752 {
4753 if (event.xmotion.window != windows->image.id)
4754 break;
4755 /*
4756 Map and unmap Info widget as text cursor crosses its boundaries.
4757 */
4758 x=event.xmotion.x;
4759 y=event.xmotion.y;
4760 if (windows->info.mapped != MagickFalse)
4761 {
4762 if ((x < (int) (windows->info.x+windows->info.width)) &&
4763 (y < (int) (windows->info.y+windows->info.height)))
4764 (void) XWithdrawWindow(display,windows->info.id,
4765 windows->info.screen);
4766 }
4767 else
4768 if ((x > (int) (windows->info.x+windows->info.width)) ||
4769 (y > (int) (windows->info.y+windows->info.height)))
4770 (void) XMapWindow(display,windows->info.id);
4771 crop_info.x=(ssize_t) windows->image.x+x;
4772 crop_info.y=(ssize_t) windows->image.y+y;
4773 break;
4774 }
4775 default:
4776 break;
4777 }
4778 } while ((state & ExitState) == 0);
4779 (void) XSelectInput(display,windows->image.id,
4780 windows->image.attributes.event_mask);
4781 if ((state & EscapeState) != 0)
4782 {
4783 /*
4784 User want to exit without cropping.
4785 */
4786 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4787 (void) XFreeCursor(display,cursor);
4788 return(MagickTrue);
4789 }
4790 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4791 do
4792 {
4793 /*
4794 Size rectangle as pointer moves until the mouse button is released.
4795 */
4796 x=(int) crop_info.x;
4797 y=(int) crop_info.y;
4798 crop_info.width=0;
4799 crop_info.height=0;
4800 state=DefaultState;
4801 do
4802 {
4803 highlight_info=crop_info;
4804 highlight_info.x=crop_info.x-windows->image.x;
4805 highlight_info.y=crop_info.y-windows->image.y;
4806 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4807 {
4808 /*
4809 Display info and draw cropping rectangle.
4810 */
4811 if (windows->info.mapped == MagickFalse)
4812 (void) XMapWindow(display,windows->info.id);
4813 (void) FormatLocaleString(text,MaxTextExtent,
4814 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4815 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4816 XInfoWidget(display,windows,text);
4817 XHighlightRectangle(display,windows->image.id,
4818 windows->image.highlight_context,&highlight_info);
4819 }
4820 else
4821 if (windows->info.mapped != MagickFalse)
4822 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4823 /*
4824 Wait for next event.
4825 */
4826 XScreenEvent(display,windows,&event);
4827 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4828 XHighlightRectangle(display,windows->image.id,
4829 windows->image.highlight_context,&highlight_info);
4830 switch (event.type)
4831 {
4832 case ButtonPress:
4833 {
4834 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4835 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4836 break;
4837 }
4838 case ButtonRelease:
4839 {
4840 /*
4841 User has committed to cropping rectangle.
4842 */
4843 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4844 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4845 XSetCursorState(display,windows,MagickFalse);
4846 state|=ExitState;
4847 windows->command.data=0;
4848 (void) XCommandWidget(display,windows,RectifyModeMenu,
4849 (XEvent *) NULL);
4850 break;
4851 }
4852 case Expose:
4853 break;
4854 case MotionNotify:
4855 {
4856 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4857 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4858 }
4859 default:
4860 break;
4861 }
4862 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4863 ((state & ExitState) != 0))
4864 {
4865 /*
4866 Check boundary conditions.
4867 */
4868 if (crop_info.x < 0)
4869 crop_info.x=0;
4870 else
4871 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4872 crop_info.x=(ssize_t) windows->image.ximage->width;
4873 if ((int) crop_info.x < x)
4874 crop_info.width=(unsigned int) (x-crop_info.x);
4875 else
4876 {
4877 crop_info.width=(unsigned int) (crop_info.x-x);
4878 crop_info.x=(ssize_t) x;
4879 }
4880 if (crop_info.y < 0)
4881 crop_info.y=0;
4882 else
4883 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4884 crop_info.y=(ssize_t) windows->image.ximage->height;
4885 if ((int) crop_info.y < y)
4886 crop_info.height=(unsigned int) (y-crop_info.y);
4887 else
4888 {
4889 crop_info.height=(unsigned int) (crop_info.y-y);
4890 crop_info.y=(ssize_t) y;
4891 }
4892 }
4893 } while ((state & ExitState) == 0);
4894 /*
4895 Wait for user to grab a corner of the rectangle or press return.
4896 */
4897 state=DefaultState;
4898 (void) XMapWindow(display,windows->info.id);
4899 do
4900 {
4901 if (windows->info.mapped != MagickFalse)
4902 {
4903 /*
4904 Display pointer position.
4905 */
4906 (void) FormatLocaleString(text,MaxTextExtent,
4907 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4908 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4909 XInfoWidget(display,windows,text);
4910 }
4911 highlight_info=crop_info;
4912 highlight_info.x=crop_info.x-windows->image.x;
4913 highlight_info.y=crop_info.y-windows->image.y;
4914 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4915 {
4916 state|=EscapeState;
4917 state|=ExitState;
4918 break;
4919 }
4920 XHighlightRectangle(display,windows->image.id,
4921 windows->image.highlight_context,&highlight_info);
4922 XScreenEvent(display,windows,&event);
4923 if (event.xany.window == windows->command.id)
4924 {
4925 /*
4926 Select a command from the Command widget.
4927 */
4928 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4929 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4930 (void) XSetFunction(display,windows->image.highlight_context,
4931 GXinvert);
4932 XHighlightRectangle(display,windows->image.id,
4933 windows->image.highlight_context,&highlight_info);
4934 if (id >= 0)
4935 switch (RectifyCommands[id])
4936 {
4937 case RectifyCopyCommand:
4938 {
4939 state|=ExitState;
4940 break;
4941 }
4942 case RectifyHelpCommand:
4943 {
4944 (void) XSetFunction(display,windows->image.highlight_context,
4945 GXcopy);
4946 switch (mode)
4947 {
4948 case CopyMode:
4949 {
4950 XTextViewHelp(display,resource_info,windows,MagickFalse,
4951 "Help Viewer - Image Copy",ImageCopyHelp);
4952 break;
4953 }
4954 case CropMode:
4955 {
4956 XTextViewHelp(display,resource_info,windows,MagickFalse,
4957 "Help Viewer - Image Crop",ImageCropHelp);
4958 break;
4959 }
4960 case CutMode:
4961 {
4962 XTextViewHelp(display,resource_info,windows,MagickFalse,
4963 "Help Viewer - Image Cut",ImageCutHelp);
4964 break;
4965 }
4966 }
4967 (void) XSetFunction(display,windows->image.highlight_context,
4968 GXinvert);
4969 break;
4970 }
4971 case RectifyDismissCommand:
4972 {
4973 /*
4974 Prematurely exit.
4975 */
4976 state|=EscapeState;
4977 state|=ExitState;
4978 break;
4979 }
4980 default:
4981 break;
4982 }
4983 continue;
4984 }
4985 XHighlightRectangle(display,windows->image.id,
4986 windows->image.highlight_context,&highlight_info);
4987 switch (event.type)
4988 {
4989 case ButtonPress:
4990 {
4991 if (event.xbutton.button != Button1)
4992 break;
4993 if (event.xbutton.window != windows->image.id)
4994 break;
4995 x=windows->image.x+event.xbutton.x;
4996 y=windows->image.y+event.xbutton.y;
4997 if ((x < (int) (crop_info.x+RoiDelta)) &&
4998 (x > (int) (crop_info.x-RoiDelta)) &&
4999 (y < (int) (crop_info.y+RoiDelta)) &&
5000 (y > (int) (crop_info.y-RoiDelta)))
5001 {
5002 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5003 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5004 state|=UpdateConfigurationState;
5005 break;
5006 }
5007 if ((x < (int) (crop_info.x+RoiDelta)) &&
5008 (x > (int) (crop_info.x-RoiDelta)) &&
5009 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5010 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5011 {
5012 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5013 state|=UpdateConfigurationState;
5014 break;
5015 }
5016 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5017 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5018 (y < (int) (crop_info.y+RoiDelta)) &&
5019 (y > (int) (crop_info.y-RoiDelta)))
5020 {
5021 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5022 state|=UpdateConfigurationState;
5023 break;
5024 }
5025 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5026 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5027 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5028 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5029 {
5030 state|=UpdateConfigurationState;
5031 break;
5032 }
5033 }
5034 case ButtonRelease:
5035 {
5036 if (event.xbutton.window == windows->pan.id)
5037 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5038 (highlight_info.y != crop_info.y-windows->image.y))
5039 XHighlightRectangle(display,windows->image.id,
5040 windows->image.highlight_context,&highlight_info);
5041 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5042 event.xbutton.time);
5043 break;
5044 }
5045 case Expose:
5046 {
5047 if (event.xexpose.window == windows->image.id)
5048 if (event.xexpose.count == 0)
5049 {
5050 event.xexpose.x=(int) highlight_info.x;
5051 event.xexpose.y=(int) highlight_info.y;
5052 event.xexpose.width=(int) highlight_info.width;
5053 event.xexpose.height=(int) highlight_info.height;
5054 XRefreshWindow(display,&windows->image,&event);
5055 }
5056 if (event.xexpose.window == windows->info.id)
5057 if (event.xexpose.count == 0)
5058 XInfoWidget(display,windows,text);
5059 break;
5060 }
5061 case KeyPress:
5062 {
5063 if (event.xkey.window != windows->image.id)
5064 break;
5065 /*
5066 Respond to a user key press.
5067 */
5068 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5069 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5070 switch ((int) key_symbol)
5071 {
5072 case XK_Escape:
5073 case XK_F20:
5074 state|=EscapeState;
5075 case XK_Return:
5076 {
5077 state|=ExitState;
5078 break;
5079 }
5080 case XK_Home:
5081 case XK_KP_Home:
5082 {
5083 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/
5084 2L);
5085 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/
5086 2L);
5087 break;
5088 }
5089 case XK_Left:
5090 case XK_KP_Left:
5091 {
5092 crop_info.x--;
5093 break;
5094 }
5095 case XK_Up:
5096 case XK_KP_Up:
5097 case XK_Next:
5098 {
5099 crop_info.y--;
5100 break;
5101 }
5102 case XK_Right:
5103 case XK_KP_Right:
5104 {
5105 crop_info.x++;
5106 break;
5107 }
5108 case XK_Prior:
5109 case XK_Down:
5110 case XK_KP_Down:
5111 {
5112 crop_info.y++;
5113 break;
5114 }
5115 case XK_F1:
5116 case XK_Help:
5117 {
5118 (void) XSetFunction(display,windows->image.highlight_context,
5119 GXcopy);
5120 switch (mode)
5121 {
5122 case CopyMode:
5123 {
5124 XTextViewHelp(display,resource_info,windows,MagickFalse,
5125 "Help Viewer - Image Copy",ImageCopyHelp);
5126 break;
5127 }
5128 case CropMode:
5129 {
5130 XTextViewHelp(display,resource_info,windows,MagickFalse,
5131 "Help Viewer - Image Cropg",ImageCropHelp);
5132 break;
5133 }
5134 case CutMode:
5135 {
5136 XTextViewHelp(display,resource_info,windows,MagickFalse,
5137 "Help Viewer - Image Cutg",ImageCutHelp);
5138 break;
5139 }
5140 }
5141 (void) XSetFunction(display,windows->image.highlight_context,
5142 GXinvert);
5143 break;
5144 }
5145 default:
5146 {
5147 (void) XBell(display,0);
5148 break;
5149 }
5150 }
5151 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5152 event.xkey.time);
5153 break;
5154 }
5155 case KeyRelease:
5156 break;
5157 case MotionNotify:
5158 {
5159 if (event.xmotion.window != windows->image.id)
5160 break;
5161 /*
5162 Map and unmap Info widget as text cursor crosses its boundaries.
5163 */
5164 x=event.xmotion.x;
5165 y=event.xmotion.y;
5166 if (windows->info.mapped != MagickFalse)
5167 {
5168 if ((x < (int) (windows->info.x+windows->info.width)) &&
5169 (y < (int) (windows->info.y+windows->info.height)))
5170 (void) XWithdrawWindow(display,windows->info.id,
5171 windows->info.screen);
5172 }
5173 else
5174 if ((x > (int) (windows->info.x+windows->info.width)) ||
5175 (y > (int) (windows->info.y+windows->info.height)))
5176 (void) XMapWindow(display,windows->info.id);
5177 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5178 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5179 break;
5180 }
5181 case SelectionRequest:
5182 {
5183 XSelectionEvent
5184 notify;
5185
5186 XSelectionRequestEvent
5187 *request;
5188
5189 /*
5190 Set primary selection.
5191 */
5192 (void) FormatLocaleString(text,MaxTextExtent,
5193 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5194 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5195 request=(&(event.xselectionrequest));
5196 (void) XChangeProperty(request->display,request->requestor,
5197 request->property,request->target,8,PropModeReplace,
5198 (unsigned char *) text,(int) strlen(text));
5199 notify.type=SelectionNotify;
5200 notify.display=request->display;
5201 notify.requestor=request->requestor;
5202 notify.selection=request->selection;
5203 notify.target=request->target;
5204 notify.time=request->time;
5205 if (request->property == None)
5206 notify.property=request->target;
5207 else
5208 notify.property=request->property;
5209 (void) XSendEvent(request->display,request->requestor,False,0,
5210 (XEvent *) ¬ify);
5211 }
5212 default:
5213 break;
5214 }
5215 if ((state & UpdateConfigurationState) != 0)
5216 {
5217 (void) XPutBackEvent(display,&event);
5218 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5219 break;
5220 }
5221 } while ((state & ExitState) == 0);
5222 } while ((state & ExitState) == 0);
5223 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5224 XSetCursorState(display,windows,MagickFalse);
5225 if ((state & EscapeState) != 0)
5226 return(MagickTrue);
5227 if (mode == CropMode)
5228 if (((int) crop_info.width != windows->image.ximage->width) ||
5229 ((int) crop_info.height != windows->image.ximage->height))
5230 {
5231 /*
5232 Reconfigure Image window as defined by cropping rectangle.
5233 */
5234 XSetCropGeometry(display,windows,&crop_info,image);
5235 windows->image.window_changes.width=(int) crop_info.width;
5236 windows->image.window_changes.height=(int) crop_info.height;
5237 (void) XConfigureImage(display,resource_info,windows,image);
5238 return(MagickTrue);
5239 }
5240 /*
5241 Copy image before applying image transforms.
5242 */
5243 XSetCursorState(display,windows,MagickTrue);
5244 XCheckRefreshWindows(display,windows);
5245 width=(unsigned int) image->columns;
5246 height=(unsigned int) image->rows;
5247 x=0;
5248 y=0;
5249 if (windows->image.crop_geometry != (char *) NULL)
5250 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5251 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5252 crop_info.x+=x;
5253 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5254 crop_info.x+=image->page.x;
5255 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5256 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5257 crop_info.y+=y;
5258 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5259 crop_info.y+=image->page.y;
5260 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5261 crop_image=CropImage(image,&crop_info,&image->exception);
5262 XSetCursorState(display,windows,MagickFalse);
5263 if (crop_image == (Image *) NULL)
5264 return(MagickFalse);
5265 if (resource_info->copy_image != (Image *) NULL)
5266 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5267 resource_info->copy_image=crop_image;
5268 if (mode == CopyMode)
5269 {
5270 (void) XConfigureImage(display,resource_info,windows,image);
5271 return(MagickTrue);
5272 }
5273 /*
5274 Cut image.
5275 */
5276 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
5277 return(MagickFalse);
5278 image->matte=MagickTrue;
5279 exception=(&image->exception);
5280 image_view=AcquireAuthenticCacheView(image,exception);
5281 for (y=0; y < (int) crop_info.height; y++)
5282 {
5283 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5284 crop_info.width,1,exception);
5285 if (q == (PixelPacket *) NULL)
5286 break;
5287 for (x=0; x < (int) crop_info.width; x++)
5288 {
5289 q->opacity=(Quantum) TransparentOpacity;
5290 q++;
5291 }
5292 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5293 break;
5294 }
5295 image_view=DestroyCacheView(image_view);
5296 /*
5297 Update image configuration.
5298 */
5299 XConfigureImageColormap(display,resource_info,windows,image);
5300 (void) XConfigureImage(display,resource_info,windows,image);
5301 return(MagickTrue);
5302 }
5303
5304 /*
5305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5306 % %
5307 % %
5308 % %
5309 + X D r a w I m a g e %
5310 % %
5311 % %
5312 % %
5313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5314 %
5315 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5316 % the image.
5317 %
5318 % The format of the XDrawEditImage method is:
5319 %
5320 % MagickBooleanType XDrawEditImage(Display *display,
5321 % XResourceInfo *resource_info,XWindows *windows,Image **image)
5322 %
5323 % A description of each parameter follows:
5324 %
5325 % o display: Specifies a connection to an X server; returned from
5326 % XOpenDisplay.
5327 %
5328 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5329 %
5330 % o windows: Specifies a pointer to a XWindows structure.
5331 %
5332 % o image: the image.
5333 %
5334 */
XDrawEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)5335 static MagickBooleanType XDrawEditImage(Display *display,
5336 XResourceInfo *resource_info,XWindows *windows,Image **image)
5337 {
5338 const char
5339 *const DrawMenu[] =
5340 {
5341 "Element",
5342 "Color",
5343 "Stipple",
5344 "Width",
5345 "Undo",
5346 "Help",
5347 "Dismiss",
5348 (char *) NULL
5349 };
5350
5351 static ElementType
5352 element = PointElement;
5353
5354 static const ModeType
5355 DrawCommands[] =
5356 {
5357 DrawElementCommand,
5358 DrawColorCommand,
5359 DrawStippleCommand,
5360 DrawWidthCommand,
5361 DrawUndoCommand,
5362 DrawHelpCommand,
5363 DrawDismissCommand
5364 };
5365
5366 static Pixmap
5367 stipple = (Pixmap) NULL;
5368
5369 static unsigned int
5370 pen_id = 0,
5371 line_width = 1;
5372
5373 char
5374 command[MaxTextExtent],
5375 text[MaxTextExtent];
5376
5377 Cursor
5378 cursor;
5379
5380 int
5381 entry,
5382 id,
5383 number_coordinates,
5384 x,
5385 y;
5386
5387 MagickRealType
5388 degrees;
5389
5390 MagickStatusType
5391 status;
5392
5393 RectangleInfo
5394 rectangle_info;
5395
5396 int
5397 i;
5398
5399 unsigned int
5400 distance,
5401 height,
5402 max_coordinates,
5403 width;
5404
5405 size_t
5406 state;
5407
5408 Window
5409 root_window;
5410
5411 XDrawInfo
5412 draw_info;
5413
5414 XEvent
5415 event;
5416
5417 XPoint
5418 *coordinate_info;
5419
5420 XSegment
5421 line_info;
5422
5423 /*
5424 Allocate polygon info.
5425 */
5426 max_coordinates=2048;
5427 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5428 sizeof(*coordinate_info));
5429 if (coordinate_info == (XPoint *) NULL)
5430 {
5431 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5432 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5433 return(MagickFalse);
5434 }
5435 /*
5436 Map Command widget.
5437 */
5438 (void) CloneString(&windows->command.name,"Draw");
5439 windows->command.data=4;
5440 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5441 (void) XMapRaised(display,windows->command.id);
5442 XClientMessage(display,windows->image.id,windows->im_protocols,
5443 windows->im_update_widget,CurrentTime);
5444 /*
5445 Wait for first button press.
5446 */
5447 root_window=XRootWindow(display,XDefaultScreen(display));
5448 draw_info.stencil=OpaqueStencil;
5449 status=MagickTrue;
5450 cursor=XCreateFontCursor(display,XC_tcross);
5451 for ( ; ; )
5452 {
5453 XQueryPosition(display,windows->image.id,&x,&y);
5454 (void) XSelectInput(display,windows->image.id,
5455 windows->image.attributes.event_mask | PointerMotionMask);
5456 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5457 state=DefaultState;
5458 do
5459 {
5460 if (windows->info.mapped != MagickFalse)
5461 {
5462 /*
5463 Display pointer position.
5464 */
5465 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
5466 x+windows->image.x,y+windows->image.y);
5467 XInfoWidget(display,windows,text);
5468 }
5469 /*
5470 Wait for next event.
5471 */
5472 XScreenEvent(display,windows,&event);
5473 if (event.xany.window == windows->command.id)
5474 {
5475 /*
5476 Select a command from the Command widget.
5477 */
5478 id=XCommandWidget(display,windows,DrawMenu,&event);
5479 if (id < 0)
5480 continue;
5481 switch (DrawCommands[id])
5482 {
5483 case DrawElementCommand:
5484 {
5485 const char
5486 *const Elements[] =
5487 {
5488 "point",
5489 "line",
5490 "rectangle",
5491 "fill rectangle",
5492 "circle",
5493 "fill circle",
5494 "ellipse",
5495 "fill ellipse",
5496 "polygon",
5497 "fill polygon",
5498 (char *) NULL,
5499 };
5500
5501 /*
5502 Select a command from the pop-up menu.
5503 */
5504 element=(ElementType) (XMenuWidget(display,windows,
5505 DrawMenu[id],Elements,command)+1);
5506 break;
5507 }
5508 case DrawColorCommand:
5509 {
5510 const char
5511 *ColorMenu[MaxNumberPens+1];
5512
5513 int
5514 pen_number;
5515
5516 MagickBooleanType
5517 transparent;
5518
5519 XColor
5520 color;
5521
5522 /*
5523 Initialize menu selections.
5524 */
5525 for (i=0; i < (int) (MaxNumberPens-2); i++)
5526 ColorMenu[i]=resource_info->pen_colors[i];
5527 ColorMenu[MaxNumberPens-2]="transparent";
5528 ColorMenu[MaxNumberPens-1]="Browser...";
5529 ColorMenu[MaxNumberPens]=(char *) NULL;
5530 /*
5531 Select a pen color from the pop-up menu.
5532 */
5533 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5534 (const char **) ColorMenu,command);
5535 if (pen_number < 0)
5536 break;
5537 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5538 MagickFalse;
5539 if (transparent != MagickFalse)
5540 {
5541 draw_info.stencil=TransparentStencil;
5542 break;
5543 }
5544 if (pen_number == (MaxNumberPens-1))
5545 {
5546 static char
5547 color_name[MaxTextExtent] = "gray";
5548
5549 /*
5550 Select a pen color from a dialog.
5551 */
5552 resource_info->pen_colors[pen_number]=color_name;
5553 XColorBrowserWidget(display,windows,"Select",color_name);
5554 if (*color_name == '\0')
5555 break;
5556 }
5557 /*
5558 Set pen color.
5559 */
5560 (void) XParseColor(display,windows->map_info->colormap,
5561 resource_info->pen_colors[pen_number],&color);
5562 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5563 (unsigned int) MaxColors,&color);
5564 windows->pixel_info->pen_colors[pen_number]=color;
5565 pen_id=(unsigned int) pen_number;
5566 draw_info.stencil=OpaqueStencil;
5567 break;
5568 }
5569 case DrawStippleCommand:
5570 {
5571 const char
5572 *StipplesMenu[] =
5573 {
5574 "Brick",
5575 "Diagonal",
5576 "Scales",
5577 "Vertical",
5578 "Wavy",
5579 "Translucent",
5580 "Opaque",
5581 (char *) NULL,
5582 (char *) NULL,
5583 };
5584
5585 Image
5586 *stipple_image;
5587
5588 ImageInfo
5589 *image_info;
5590
5591 int
5592 status;
5593
5594 static char
5595 filename[MaxTextExtent] = "\0";
5596
5597 /*
5598 Select a command from the pop-up menu.
5599 */
5600 StipplesMenu[7]="Open...";
5601 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5602 command);
5603 if (entry < 0)
5604 break;
5605 if (stipple != (Pixmap) NULL)
5606 (void) XFreePixmap(display,stipple);
5607 stipple=(Pixmap) NULL;
5608 if (entry != 7)
5609 {
5610 switch (entry)
5611 {
5612 case 0:
5613 {
5614 stipple=XCreateBitmapFromData(display,root_window,
5615 (char *) BricksBitmap,BricksWidth,BricksHeight);
5616 break;
5617 }
5618 case 1:
5619 {
5620 stipple=XCreateBitmapFromData(display,root_window,
5621 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5622 break;
5623 }
5624 case 2:
5625 {
5626 stipple=XCreateBitmapFromData(display,root_window,
5627 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5628 break;
5629 }
5630 case 3:
5631 {
5632 stipple=XCreateBitmapFromData(display,root_window,
5633 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5634 break;
5635 }
5636 case 4:
5637 {
5638 stipple=XCreateBitmapFromData(display,root_window,
5639 (char *) WavyBitmap,WavyWidth,WavyHeight);
5640 break;
5641 }
5642 case 5:
5643 {
5644 stipple=XCreateBitmapFromData(display,root_window,
5645 (char *) HighlightBitmap,HighlightWidth,
5646 HighlightHeight);
5647 break;
5648 }
5649 case 6:
5650 default:
5651 {
5652 stipple=XCreateBitmapFromData(display,root_window,
5653 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5654 break;
5655 }
5656 }
5657 break;
5658 }
5659 XFileBrowserWidget(display,windows,"Stipple",filename);
5660 if (*filename == '\0')
5661 break;
5662 /*
5663 Read image.
5664 */
5665 XSetCursorState(display,windows,MagickTrue);
5666 XCheckRefreshWindows(display,windows);
5667 image_info=AcquireImageInfo();
5668 (void) CopyMagickString(image_info->filename,filename,
5669 MaxTextExtent);
5670 stipple_image=ReadImage(image_info,&(*image)->exception);
5671 CatchException(&(*image)->exception);
5672 XSetCursorState(display,windows,MagickFalse);
5673 if (stipple_image == (Image *) NULL)
5674 break;
5675 (void) AcquireUniqueFileResource(filename);
5676 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
5677 "xbm:%s",filename);
5678 (void) WriteImage(image_info,stipple_image);
5679 stipple_image=DestroyImage(stipple_image);
5680 image_info=DestroyImageInfo(image_info);
5681 status=XReadBitmapFile(display,root_window,filename,&width,
5682 &height,&stipple,&x,&y);
5683 (void) RelinquishUniqueFileResource(filename);
5684 if ((status != BitmapSuccess) != 0)
5685 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5686 filename);
5687 break;
5688 }
5689 case DrawWidthCommand:
5690 {
5691 const char
5692 *const WidthsMenu[] =
5693 {
5694 "1",
5695 "2",
5696 "4",
5697 "8",
5698 "16",
5699 "Dialog...",
5700 (char *) NULL,
5701 };
5702
5703 static char
5704 width[MaxTextExtent] = "0";
5705
5706 /*
5707 Select a command from the pop-up menu.
5708 */
5709 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5710 command);
5711 if (entry < 0)
5712 break;
5713 if (entry != 5)
5714 {
5715 line_width=(unsigned int) StringToUnsignedLong(
5716 WidthsMenu[entry]);
5717 break;
5718 }
5719 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5720 width);
5721 if (*width == '\0')
5722 break;
5723 line_width=(unsigned int) StringToUnsignedLong(width);
5724 break;
5725 }
5726 case DrawUndoCommand:
5727 {
5728 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5729 image);
5730 break;
5731 }
5732 case DrawHelpCommand:
5733 {
5734 XTextViewHelp(display,resource_info,windows,MagickFalse,
5735 "Help Viewer - Image Rotation",ImageDrawHelp);
5736 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5737 break;
5738 }
5739 case DrawDismissCommand:
5740 {
5741 /*
5742 Prematurely exit.
5743 */
5744 state|=EscapeState;
5745 state|=ExitState;
5746 break;
5747 }
5748 default:
5749 break;
5750 }
5751 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5752 continue;
5753 }
5754 switch (event.type)
5755 {
5756 case ButtonPress:
5757 {
5758 if (event.xbutton.button != Button1)
5759 break;
5760 if (event.xbutton.window != windows->image.id)
5761 break;
5762 /*
5763 exit loop.
5764 */
5765 x=event.xbutton.x;
5766 y=event.xbutton.y;
5767 state|=ExitState;
5768 break;
5769 }
5770 case ButtonRelease:
5771 break;
5772 case Expose:
5773 break;
5774 case KeyPress:
5775 {
5776 KeySym
5777 key_symbol;
5778
5779 if (event.xkey.window != windows->image.id)
5780 break;
5781 /*
5782 Respond to a user key press.
5783 */
5784 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5785 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5786 switch ((int) key_symbol)
5787 {
5788 case XK_Escape:
5789 case XK_F20:
5790 {
5791 /*
5792 Prematurely exit.
5793 */
5794 state|=EscapeState;
5795 state|=ExitState;
5796 break;
5797 }
5798 case XK_F1:
5799 case XK_Help:
5800 {
5801 XTextViewHelp(display,resource_info,windows,MagickFalse,
5802 "Help Viewer - Image Rotation",ImageDrawHelp);
5803 break;
5804 }
5805 default:
5806 {
5807 (void) XBell(display,0);
5808 break;
5809 }
5810 }
5811 break;
5812 }
5813 case MotionNotify:
5814 {
5815 /*
5816 Map and unmap Info widget as text cursor crosses its boundaries.
5817 */
5818 x=event.xmotion.x;
5819 y=event.xmotion.y;
5820 if (windows->info.mapped != MagickFalse)
5821 {
5822 if ((x < (int) (windows->info.x+windows->info.width)) &&
5823 (y < (int) (windows->info.y+windows->info.height)))
5824 (void) XWithdrawWindow(display,windows->info.id,
5825 windows->info.screen);
5826 }
5827 else
5828 if ((x > (int) (windows->info.x+windows->info.width)) ||
5829 (y > (int) (windows->info.y+windows->info.height)))
5830 (void) XMapWindow(display,windows->info.id);
5831 break;
5832 }
5833 }
5834 } while ((state & ExitState) == 0);
5835 (void) XSelectInput(display,windows->image.id,
5836 windows->image.attributes.event_mask);
5837 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5838 if ((state & EscapeState) != 0)
5839 break;
5840 /*
5841 Draw element as pointer moves until the button is released.
5842 */
5843 distance=0;
5844 degrees=0.0;
5845 line_info.x1=x;
5846 line_info.y1=y;
5847 line_info.x2=x;
5848 line_info.y2=y;
5849 rectangle_info.x=(ssize_t) x;
5850 rectangle_info.y=(ssize_t) y;
5851 rectangle_info.width=0;
5852 rectangle_info.height=0;
5853 number_coordinates=1;
5854 coordinate_info->x=x;
5855 coordinate_info->y=y;
5856 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5857 state=DefaultState;
5858 do
5859 {
5860 switch (element)
5861 {
5862 case PointElement:
5863 default:
5864 {
5865 if (number_coordinates > 1)
5866 {
5867 (void) XDrawLines(display,windows->image.id,
5868 windows->image.highlight_context,coordinate_info,
5869 number_coordinates,CoordModeOrigin);
5870 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
5871 coordinate_info[number_coordinates-1].x,
5872 coordinate_info[number_coordinates-1].y);
5873 XInfoWidget(display,windows,text);
5874 }
5875 break;
5876 }
5877 case LineElement:
5878 {
5879 if (distance > 9)
5880 {
5881 /*
5882 Display angle of the line.
5883 */
5884 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5885 line_info.y1),(double) (line_info.x2-line_info.x1)));
5886 (void) FormatLocaleString(text,MaxTextExtent," %g",
5887 (double) degrees);
5888 XInfoWidget(display,windows,text);
5889 XHighlightLine(display,windows->image.id,
5890 windows->image.highlight_context,&line_info);
5891 }
5892 else
5893 if (windows->info.mapped != MagickFalse)
5894 (void) XWithdrawWindow(display,windows->info.id,
5895 windows->info.screen);
5896 break;
5897 }
5898 case RectangleElement:
5899 case FillRectangleElement:
5900 {
5901 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5902 {
5903 /*
5904 Display info and draw drawing rectangle.
5905 */
5906 (void) FormatLocaleString(text,MaxTextExtent,
5907 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5908 (double) rectangle_info.height,(double) rectangle_info.x,
5909 (double) rectangle_info.y);
5910 XInfoWidget(display,windows,text);
5911 XHighlightRectangle(display,windows->image.id,
5912 windows->image.highlight_context,&rectangle_info);
5913 }
5914 else
5915 if (windows->info.mapped != MagickFalse)
5916 (void) XWithdrawWindow(display,windows->info.id,
5917 windows->info.screen);
5918 break;
5919 }
5920 case CircleElement:
5921 case FillCircleElement:
5922 case EllipseElement:
5923 case FillEllipseElement:
5924 {
5925 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5926 {
5927 /*
5928 Display info and draw drawing rectangle.
5929 */
5930 (void) FormatLocaleString(text,MaxTextExtent,
5931 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5932 (double) rectangle_info.height,(double) rectangle_info.x,
5933 (double) rectangle_info.y);
5934 XInfoWidget(display,windows,text);
5935 XHighlightEllipse(display,windows->image.id,
5936 windows->image.highlight_context,&rectangle_info);
5937 }
5938 else
5939 if (windows->info.mapped != MagickFalse)
5940 (void) XWithdrawWindow(display,windows->info.id,
5941 windows->info.screen);
5942 break;
5943 }
5944 case PolygonElement:
5945 case FillPolygonElement:
5946 {
5947 if (number_coordinates > 1)
5948 (void) XDrawLines(display,windows->image.id,
5949 windows->image.highlight_context,coordinate_info,
5950 number_coordinates,CoordModeOrigin);
5951 if (distance > 9)
5952 {
5953 /*
5954 Display angle of the line.
5955 */
5956 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5957 line_info.y1),(double) (line_info.x2-line_info.x1)));
5958 (void) FormatLocaleString(text,MaxTextExtent," %g",
5959 (double) degrees);
5960 XInfoWidget(display,windows,text);
5961 XHighlightLine(display,windows->image.id,
5962 windows->image.highlight_context,&line_info);
5963 }
5964 else
5965 if (windows->info.mapped != MagickFalse)
5966 (void) XWithdrawWindow(display,windows->info.id,
5967 windows->info.screen);
5968 break;
5969 }
5970 }
5971 /*
5972 Wait for next event.
5973 */
5974 XScreenEvent(display,windows,&event);
5975 switch (element)
5976 {
5977 case PointElement:
5978 default:
5979 {
5980 if (number_coordinates > 1)
5981 (void) XDrawLines(display,windows->image.id,
5982 windows->image.highlight_context,coordinate_info,
5983 number_coordinates,CoordModeOrigin);
5984 break;
5985 }
5986 case LineElement:
5987 {
5988 if (distance > 9)
5989 XHighlightLine(display,windows->image.id,
5990 windows->image.highlight_context,&line_info);
5991 break;
5992 }
5993 case RectangleElement:
5994 case FillRectangleElement:
5995 {
5996 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5997 XHighlightRectangle(display,windows->image.id,
5998 windows->image.highlight_context,&rectangle_info);
5999 break;
6000 }
6001 case CircleElement:
6002 case FillCircleElement:
6003 case EllipseElement:
6004 case FillEllipseElement:
6005 {
6006 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6007 XHighlightEllipse(display,windows->image.id,
6008 windows->image.highlight_context,&rectangle_info);
6009 break;
6010 }
6011 case PolygonElement:
6012 case FillPolygonElement:
6013 {
6014 if (number_coordinates > 1)
6015 (void) XDrawLines(display,windows->image.id,
6016 windows->image.highlight_context,coordinate_info,
6017 number_coordinates,CoordModeOrigin);
6018 if (distance > 9)
6019 XHighlightLine(display,windows->image.id,
6020 windows->image.highlight_context,&line_info);
6021 break;
6022 }
6023 }
6024 switch (event.type)
6025 {
6026 case ButtonPress:
6027 break;
6028 case ButtonRelease:
6029 {
6030 /*
6031 User has committed to element.
6032 */
6033 line_info.x2=event.xbutton.x;
6034 line_info.y2=event.xbutton.y;
6035 rectangle_info.x=(ssize_t) event.xbutton.x;
6036 rectangle_info.y=(ssize_t) event.xbutton.y;
6037 coordinate_info[number_coordinates].x=event.xbutton.x;
6038 coordinate_info[number_coordinates].y=event.xbutton.y;
6039 if (((element != PolygonElement) &&
6040 (element != FillPolygonElement)) || (distance <= 9))
6041 {
6042 state|=ExitState;
6043 break;
6044 }
6045 number_coordinates++;
6046 if (number_coordinates < (int) max_coordinates)
6047 {
6048 line_info.x1=event.xbutton.x;
6049 line_info.y1=event.xbutton.y;
6050 break;
6051 }
6052 max_coordinates<<=1;
6053 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6054 max_coordinates,sizeof(*coordinate_info));
6055 if (coordinate_info == (XPoint *) NULL)
6056 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6057 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6058 break;
6059 }
6060 case Expose:
6061 break;
6062 case MotionNotify:
6063 {
6064 if (event.xmotion.window != windows->image.id)
6065 break;
6066 if (element != PointElement)
6067 {
6068 line_info.x2=event.xmotion.x;
6069 line_info.y2=event.xmotion.y;
6070 rectangle_info.x=(ssize_t) event.xmotion.x;
6071 rectangle_info.y=(ssize_t) event.xmotion.y;
6072 break;
6073 }
6074 coordinate_info[number_coordinates].x=event.xbutton.x;
6075 coordinate_info[number_coordinates].y=event.xbutton.y;
6076 number_coordinates++;
6077 if (number_coordinates < (int) max_coordinates)
6078 break;
6079 max_coordinates<<=1;
6080 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6081 max_coordinates,sizeof(*coordinate_info));
6082 if (coordinate_info == (XPoint *) NULL)
6083 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6084 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6085 break;
6086 }
6087 default:
6088 break;
6089 }
6090 /*
6091 Check boundary conditions.
6092 */
6093 if (line_info.x2 < 0)
6094 line_info.x2=0;
6095 else
6096 if (line_info.x2 > (int) windows->image.width)
6097 line_info.x2=(short) windows->image.width;
6098 if (line_info.y2 < 0)
6099 line_info.y2=0;
6100 else
6101 if (line_info.y2 > (int) windows->image.height)
6102 line_info.y2=(short) windows->image.height;
6103 distance=(unsigned int)
6104 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6105 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6106 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6107 ((state & ExitState) != 0))
6108 {
6109 if (rectangle_info.x < 0)
6110 rectangle_info.x=0;
6111 else
6112 if (rectangle_info.x > (ssize_t) windows->image.width)
6113 rectangle_info.x=(ssize_t) windows->image.width;
6114 if ((int) rectangle_info.x < x)
6115 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6116 else
6117 {
6118 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6119 rectangle_info.x=(ssize_t) x;
6120 }
6121 if (rectangle_info.y < 0)
6122 rectangle_info.y=0;
6123 else
6124 if (rectangle_info.y > (ssize_t) windows->image.height)
6125 rectangle_info.y=(ssize_t) windows->image.height;
6126 if ((int) rectangle_info.y < y)
6127 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6128 else
6129 {
6130 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6131 rectangle_info.y=(ssize_t) y;
6132 }
6133 }
6134 } while ((state & ExitState) == 0);
6135 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6136 if ((element == PointElement) || (element == PolygonElement) ||
6137 (element == FillPolygonElement))
6138 {
6139 /*
6140 Determine polygon bounding box.
6141 */
6142 rectangle_info.x=(ssize_t) coordinate_info->x;
6143 rectangle_info.y=(ssize_t) coordinate_info->y;
6144 x=coordinate_info->x;
6145 y=coordinate_info->y;
6146 for (i=1; i < number_coordinates; i++)
6147 {
6148 if (coordinate_info[i].x > x)
6149 x=coordinate_info[i].x;
6150 if (coordinate_info[i].y > y)
6151 y=coordinate_info[i].y;
6152 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6153 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6154 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6155 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6156 }
6157 rectangle_info.width=(size_t) (x-rectangle_info.x);
6158 rectangle_info.height=(size_t) (y-rectangle_info.y);
6159 for (i=0; i < number_coordinates; i++)
6160 {
6161 coordinate_info[i].x-=rectangle_info.x;
6162 coordinate_info[i].y-=rectangle_info.y;
6163 }
6164 }
6165 else
6166 if (distance <= 9)
6167 continue;
6168 else
6169 if ((element == RectangleElement) ||
6170 (element == CircleElement) || (element == EllipseElement))
6171 {
6172 rectangle_info.width--;
6173 rectangle_info.height--;
6174 }
6175 /*
6176 Drawing is relative to image configuration.
6177 */
6178 draw_info.x=(int) rectangle_info.x;
6179 draw_info.y=(int) rectangle_info.y;
6180 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6181 image);
6182 width=(unsigned int) (*image)->columns;
6183 height=(unsigned int) (*image)->rows;
6184 x=0;
6185 y=0;
6186 if (windows->image.crop_geometry != (char *) NULL)
6187 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6188 draw_info.x+=windows->image.x-(line_width/2);
6189 if (draw_info.x < 0)
6190 draw_info.x=0;
6191 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6192 draw_info.y+=windows->image.y-(line_width/2);
6193 if (draw_info.y < 0)
6194 draw_info.y=0;
6195 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6196 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6197 if (draw_info.width > (unsigned int) (*image)->columns)
6198 draw_info.width=(unsigned int) (*image)->columns;
6199 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6200 if (draw_info.height > (unsigned int) (*image)->rows)
6201 draw_info.height=(unsigned int) (*image)->rows;
6202 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6203 width*draw_info.width/windows->image.ximage->width,
6204 height*draw_info.height/windows->image.ximage->height,
6205 draw_info.x+x,draw_info.y+y);
6206 /*
6207 Initialize drawing attributes.
6208 */
6209 draw_info.degrees=0.0;
6210 draw_info.element=element;
6211 draw_info.stipple=stipple;
6212 draw_info.line_width=line_width;
6213 draw_info.line_info=line_info;
6214 if (line_info.x1 > (int) (line_width/2))
6215 draw_info.line_info.x1=(short) line_width/2;
6216 if (line_info.y1 > (int) (line_width/2))
6217 draw_info.line_info.y1=(short) line_width/2;
6218 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6219 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6220 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6221 {
6222 draw_info.line_info.x2=(-draw_info.line_info.x2);
6223 draw_info.line_info.y2=(-draw_info.line_info.y2);
6224 }
6225 if (draw_info.line_info.x2 < 0)
6226 {
6227 draw_info.line_info.x2=(-draw_info.line_info.x2);
6228 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6229 }
6230 if (draw_info.line_info.y2 < 0)
6231 {
6232 draw_info.line_info.y2=(-draw_info.line_info.y2);
6233 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6234 }
6235 draw_info.rectangle_info=rectangle_info;
6236 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6237 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6238 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6239 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6240 draw_info.number_coordinates=(unsigned int) number_coordinates;
6241 draw_info.coordinate_info=coordinate_info;
6242 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6243 /*
6244 Draw element on image.
6245 */
6246 XSetCursorState(display,windows,MagickTrue);
6247 XCheckRefreshWindows(display,windows);
6248 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6249 XSetCursorState(display,windows,MagickFalse);
6250 /*
6251 Update image colormap and return to image drawing.
6252 */
6253 XConfigureImageColormap(display,resource_info,windows,*image);
6254 (void) XConfigureImage(display,resource_info,windows,*image);
6255 }
6256 XSetCursorState(display,windows,MagickFalse);
6257 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6258 return(status != 0 ? MagickTrue : MagickFalse);
6259 }
6260
6261 /*
6262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6263 % %
6264 % %
6265 % %
6266 + X D r a w P a n R e c t a n g l e %
6267 % %
6268 % %
6269 % %
6270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6271 %
6272 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6273 % displays a zoom image and the rectangle shows which portion of the image is
6274 % displayed in the Image window.
6275 %
6276 % The format of the XDrawPanRectangle method is:
6277 %
6278 % XDrawPanRectangle(Display *display,XWindows *windows)
6279 %
6280 % A description of each parameter follows:
6281 %
6282 % o display: Specifies a connection to an X server; returned from
6283 % XOpenDisplay.
6284 %
6285 % o windows: Specifies a pointer to a XWindows structure.
6286 %
6287 */
XDrawPanRectangle(Display * display,XWindows * windows)6288 static void XDrawPanRectangle(Display *display,XWindows *windows)
6289 {
6290 MagickRealType
6291 scale_factor;
6292
6293 RectangleInfo
6294 highlight_info;
6295
6296 /*
6297 Determine dimensions of the panning rectangle.
6298 */
6299 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6300 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6301 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6302 scale_factor=(MagickRealType)
6303 windows->pan.height/windows->image.ximage->height;
6304 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6305 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6306 /*
6307 Display the panning rectangle.
6308 */
6309 (void) XClearWindow(display,windows->pan.id);
6310 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6311 &highlight_info);
6312 }
6313
6314 /*
6315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6316 % %
6317 % %
6318 % %
6319 + X I m a g e C a c h e %
6320 % %
6321 % %
6322 % %
6323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6324 %
6325 % XImageCache() handles the creation, manipulation, and destruction of the
6326 % image cache (undo and redo buffers).
6327 %
6328 % The format of the XImageCache method is:
6329 %
6330 % void XImageCache(Display *display,XResourceInfo *resource_info,
6331 % XWindows *windows,const CommandType command,Image **image)
6332 %
6333 % A description of each parameter follows:
6334 %
6335 % o display: Specifies a connection to an X server; returned from
6336 % XOpenDisplay.
6337 %
6338 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6339 %
6340 % o windows: Specifies a pointer to a XWindows structure.
6341 %
6342 % o command: Specifies a command to perform.
6343 %
6344 % o image: the image; XImageCache may transform the image and return a new
6345 % image pointer.
6346 %
6347 */
XImageCache(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image)6348 static void XImageCache(Display *display,XResourceInfo *resource_info,
6349 XWindows *windows,const CommandType command,Image **image)
6350 {
6351 Image
6352 *cache_image;
6353
6354 static Image
6355 *redo_image = (Image *) NULL,
6356 *undo_image = (Image *) NULL;
6357
6358 switch (command)
6359 {
6360 case FreeBuffersCommand:
6361 {
6362 /*
6363 Free memory from the undo and redo cache.
6364 */
6365 while (undo_image != (Image *) NULL)
6366 {
6367 cache_image=undo_image;
6368 undo_image=GetPreviousImageInList(undo_image);
6369 cache_image->list=DestroyImage(cache_image->list);
6370 cache_image=DestroyImage(cache_image);
6371 }
6372 undo_image=NewImageList();
6373 if (redo_image != (Image *) NULL)
6374 redo_image=DestroyImage(redo_image);
6375 redo_image=NewImageList();
6376 return;
6377 }
6378 case UndoCommand:
6379 {
6380 char
6381 image_geometry[MaxTextExtent];
6382
6383 /*
6384 Undo the last image transformation.
6385 */
6386 if (undo_image == (Image *) NULL)
6387 {
6388 (void) XBell(display,0);
6389 return;
6390 }
6391 cache_image=undo_image;
6392 undo_image=GetPreviousImageInList(undo_image);
6393 windows->image.window_changes.width=(int) cache_image->columns;
6394 windows->image.window_changes.height=(int) cache_image->rows;
6395 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
6396 windows->image.ximage->width,windows->image.ximage->height);
6397 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
6398 if (windows->image.crop_geometry != (char *) NULL)
6399 windows->image.crop_geometry=(char *)
6400 RelinquishMagickMemory(windows->image.crop_geometry);
6401 windows->image.crop_geometry=cache_image->geometry;
6402 if (redo_image != (Image *) NULL)
6403 redo_image=DestroyImage(redo_image);
6404 redo_image=(*image);
6405 *image=cache_image->list;
6406 cache_image=DestroyImage(cache_image);
6407 if (windows->image.orphan != MagickFalse)
6408 return;
6409 XConfigureImageColormap(display,resource_info,windows,*image);
6410 (void) XConfigureImage(display,resource_info,windows,*image);
6411 return;
6412 }
6413 case CutCommand:
6414 case PasteCommand:
6415 case ApplyCommand:
6416 case HalfSizeCommand:
6417 case OriginalSizeCommand:
6418 case DoubleSizeCommand:
6419 case ResizeCommand:
6420 case TrimCommand:
6421 case CropCommand:
6422 case ChopCommand:
6423 case FlipCommand:
6424 case FlopCommand:
6425 case RotateRightCommand:
6426 case RotateLeftCommand:
6427 case RotateCommand:
6428 case ShearCommand:
6429 case RollCommand:
6430 case NegateCommand:
6431 case ContrastStretchCommand:
6432 case SigmoidalContrastCommand:
6433 case NormalizeCommand:
6434 case EqualizeCommand:
6435 case HueCommand:
6436 case SaturationCommand:
6437 case BrightnessCommand:
6438 case GammaCommand:
6439 case SpiffCommand:
6440 case DullCommand:
6441 case GrayscaleCommand:
6442 case MapCommand:
6443 case QuantizeCommand:
6444 case DespeckleCommand:
6445 case EmbossCommand:
6446 case ReduceNoiseCommand:
6447 case AddNoiseCommand:
6448 case SharpenCommand:
6449 case BlurCommand:
6450 case ThresholdCommand:
6451 case EdgeDetectCommand:
6452 case SpreadCommand:
6453 case ShadeCommand:
6454 case RaiseCommand:
6455 case SegmentCommand:
6456 case SolarizeCommand:
6457 case SepiaToneCommand:
6458 case SwirlCommand:
6459 case ImplodeCommand:
6460 case VignetteCommand:
6461 case WaveCommand:
6462 case OilPaintCommand:
6463 case CharcoalDrawCommand:
6464 case AnnotateCommand:
6465 case AddBorderCommand:
6466 case AddFrameCommand:
6467 case CompositeCommand:
6468 case CommentCommand:
6469 case LaunchCommand:
6470 case RegionofInterestCommand:
6471 case SaveToUndoBufferCommand:
6472 case RedoCommand:
6473 {
6474 Image
6475 *previous_image;
6476
6477 ssize_t
6478 bytes;
6479
6480 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6481 if (undo_image != (Image *) NULL)
6482 {
6483 /*
6484 Ensure the undo cache has enough memory available.
6485 */
6486 previous_image=undo_image;
6487 while (previous_image != (Image *) NULL)
6488 {
6489 bytes+=previous_image->list->columns*previous_image->list->rows*
6490 sizeof(PixelPacket);
6491 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6492 {
6493 previous_image=GetPreviousImageInList(previous_image);
6494 continue;
6495 }
6496 bytes-=previous_image->list->columns*previous_image->list->rows*
6497 sizeof(PixelPacket);
6498 if (previous_image == undo_image)
6499 undo_image=NewImageList();
6500 else
6501 previous_image->next->previous=NewImageList();
6502 break;
6503 }
6504 while (previous_image != (Image *) NULL)
6505 {
6506 /*
6507 Delete any excess memory from undo cache.
6508 */
6509 cache_image=previous_image;
6510 previous_image=GetPreviousImageInList(previous_image);
6511 cache_image->list=DestroyImage(cache_image->list);
6512 cache_image=DestroyImage(cache_image);
6513 }
6514 }
6515 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6516 break;
6517 /*
6518 Save image before transformations are applied.
6519 */
6520 cache_image=AcquireImage((ImageInfo *) NULL);
6521 if (cache_image == (Image *) NULL)
6522 break;
6523 XSetCursorState(display,windows,MagickTrue);
6524 XCheckRefreshWindows(display,windows);
6525 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6526 XSetCursorState(display,windows,MagickFalse);
6527 if (cache_image->list == (Image *) NULL)
6528 {
6529 cache_image=DestroyImage(cache_image);
6530 break;
6531 }
6532 cache_image->columns=(size_t) windows->image.ximage->width;
6533 cache_image->rows=(size_t) windows->image.ximage->height;
6534 cache_image->geometry=windows->image.crop_geometry;
6535 if (windows->image.crop_geometry != (char *) NULL)
6536 {
6537 cache_image->geometry=AcquireString((char *) NULL);
6538 (void) CopyMagickString(cache_image->geometry,
6539 windows->image.crop_geometry,MaxTextExtent);
6540 }
6541 if (undo_image == (Image *) NULL)
6542 {
6543 undo_image=cache_image;
6544 break;
6545 }
6546 undo_image->next=cache_image;
6547 undo_image->next->previous=undo_image;
6548 undo_image=undo_image->next;
6549 break;
6550 }
6551 default:
6552 break;
6553 }
6554 if (command == RedoCommand)
6555 {
6556 /*
6557 Redo the last image transformation.
6558 */
6559 if (redo_image == (Image *) NULL)
6560 {
6561 (void) XBell(display,0);
6562 return;
6563 }
6564 windows->image.window_changes.width=(int) redo_image->columns;
6565 windows->image.window_changes.height=(int) redo_image->rows;
6566 if (windows->image.crop_geometry != (char *) NULL)
6567 windows->image.crop_geometry=(char *)
6568 RelinquishMagickMemory(windows->image.crop_geometry);
6569 windows->image.crop_geometry=redo_image->geometry;
6570 *image=DestroyImage(*image);
6571 *image=redo_image;
6572 redo_image=NewImageList();
6573 if (windows->image.orphan != MagickFalse)
6574 return;
6575 XConfigureImageColormap(display,resource_info,windows,*image);
6576 (void) XConfigureImage(display,resource_info,windows,*image);
6577 return;
6578 }
6579 if (command != InfoCommand)
6580 return;
6581 /*
6582 Display image info.
6583 */
6584 XSetCursorState(display,windows,MagickTrue);
6585 XCheckRefreshWindows(display,windows);
6586 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6587 XSetCursorState(display,windows,MagickFalse);
6588 }
6589
6590 /*
6591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6592 % %
6593 % %
6594 % %
6595 + X I m a g e W i n d o w C o m m a n d %
6596 % %
6597 % %
6598 % %
6599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6600 %
6601 % XImageWindowCommand() makes a transform to the image or Image window as
6602 % specified by a user menu button or keyboard command.
6603 %
6604 % The format of the XMagickCommand method is:
6605 %
6606 % CommandType XImageWindowCommand(Display *display,
6607 % XResourceInfo *resource_info,XWindows *windows,
6608 % const MagickStatusType state,KeySym key_symbol,Image **image)
6609 %
6610 % A description of each parameter follows:
6611 %
6612 % o nexus: Method XImageWindowCommand returns an image when the
6613 % user chooses 'Open Image' from the command menu. Otherwise a null
6614 % image is returned.
6615 %
6616 % o display: Specifies a connection to an X server; returned from
6617 % XOpenDisplay.
6618 %
6619 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6620 %
6621 % o windows: Specifies a pointer to a XWindows structure.
6622 %
6623 % o state: key mask.
6624 %
6625 % o key_symbol: Specifies a command to perform.
6626 %
6627 % o image: the image; XImageWIndowCommand
6628 % may transform the image and return a new image pointer.
6629 %
6630 */
XImageWindowCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickStatusType state,KeySym key_symbol,Image ** image)6631 static CommandType XImageWindowCommand(Display *display,
6632 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6633 KeySym key_symbol,Image **image)
6634 {
6635 static char
6636 delta[MaxTextExtent] = "";
6637
6638 static const char
6639 Digits[] = "01234567890";
6640
6641 static KeySym
6642 last_symbol = XK_0;
6643
6644 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6645 {
6646 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6647 {
6648 *delta='\0';
6649 resource_info->quantum=1;
6650 }
6651 last_symbol=key_symbol;
6652 delta[strlen(delta)+1]='\0';
6653 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6654 resource_info->quantum=StringToLong(delta);
6655 return(NullCommand);
6656 }
6657 last_symbol=key_symbol;
6658 if (resource_info->immutable)
6659 {
6660 /*
6661 Virtual image window has a restricted command set.
6662 */
6663 switch (key_symbol)
6664 {
6665 case XK_question:
6666 return(InfoCommand);
6667 case XK_p:
6668 case XK_Print:
6669 return(PrintCommand);
6670 case XK_space:
6671 return(NextCommand);
6672 case XK_q:
6673 case XK_Escape:
6674 return(QuitCommand);
6675 default:
6676 break;
6677 }
6678 return(NullCommand);
6679 }
6680 switch ((int) key_symbol)
6681 {
6682 case XK_o:
6683 {
6684 if ((state & ControlMask) == 0)
6685 break;
6686 return(OpenCommand);
6687 }
6688 case XK_space:
6689 return(NextCommand);
6690 case XK_BackSpace:
6691 return(FormerCommand);
6692 case XK_s:
6693 {
6694 if ((state & Mod1Mask) != 0)
6695 return(SwirlCommand);
6696 if ((state & ControlMask) == 0)
6697 return(ShearCommand);
6698 return(SaveCommand);
6699 }
6700 case XK_p:
6701 case XK_Print:
6702 {
6703 if ((state & Mod1Mask) != 0)
6704 return(OilPaintCommand);
6705 if ((state & Mod4Mask) != 0)
6706 return(ColorCommand);
6707 if ((state & ControlMask) == 0)
6708 return(NullCommand);
6709 return(PrintCommand);
6710 }
6711 case XK_d:
6712 {
6713 if ((state & Mod4Mask) != 0)
6714 return(DrawCommand);
6715 if ((state & ControlMask) == 0)
6716 return(NullCommand);
6717 return(DeleteCommand);
6718 }
6719 case XK_Select:
6720 {
6721 if ((state & ControlMask) == 0)
6722 return(NullCommand);
6723 return(SelectCommand);
6724 }
6725 case XK_n:
6726 {
6727 if ((state & ControlMask) == 0)
6728 return(NullCommand);
6729 return(NewCommand);
6730 }
6731 case XK_q:
6732 case XK_Escape:
6733 return(QuitCommand);
6734 case XK_z:
6735 case XK_Undo:
6736 {
6737 if ((state & ControlMask) == 0)
6738 return(NullCommand);
6739 return(UndoCommand);
6740 }
6741 case XK_r:
6742 case XK_Redo:
6743 {
6744 if ((state & ControlMask) == 0)
6745 return(RollCommand);
6746 return(RedoCommand);
6747 }
6748 case XK_x:
6749 {
6750 if ((state & ControlMask) == 0)
6751 return(NullCommand);
6752 return(CutCommand);
6753 }
6754 case XK_c:
6755 {
6756 if ((state & Mod1Mask) != 0)
6757 return(CharcoalDrawCommand);
6758 if ((state & ControlMask) == 0)
6759 return(CropCommand);
6760 return(CopyCommand);
6761 }
6762 case XK_v:
6763 case XK_Insert:
6764 {
6765 if ((state & Mod4Mask) != 0)
6766 return(CompositeCommand);
6767 if ((state & ControlMask) == 0)
6768 return(FlipCommand);
6769 return(PasteCommand);
6770 }
6771 case XK_less:
6772 return(HalfSizeCommand);
6773 case XK_minus:
6774 return(OriginalSizeCommand);
6775 case XK_greater:
6776 return(DoubleSizeCommand);
6777 case XK_percent:
6778 return(ResizeCommand);
6779 case XK_at:
6780 return(RefreshCommand);
6781 case XK_bracketleft:
6782 return(ChopCommand);
6783 case XK_h:
6784 return(FlopCommand);
6785 case XK_slash:
6786 return(RotateRightCommand);
6787 case XK_backslash:
6788 return(RotateLeftCommand);
6789 case XK_asterisk:
6790 return(RotateCommand);
6791 case XK_t:
6792 return(TrimCommand);
6793 case XK_H:
6794 return(HueCommand);
6795 case XK_S:
6796 return(SaturationCommand);
6797 case XK_L:
6798 return(BrightnessCommand);
6799 case XK_G:
6800 return(GammaCommand);
6801 case XK_C:
6802 return(SpiffCommand);
6803 case XK_Z:
6804 return(DullCommand);
6805 case XK_N:
6806 return(NormalizeCommand);
6807 case XK_equal:
6808 return(EqualizeCommand);
6809 case XK_asciitilde:
6810 return(NegateCommand);
6811 case XK_period:
6812 return(GrayscaleCommand);
6813 case XK_numbersign:
6814 return(QuantizeCommand);
6815 case XK_F2:
6816 return(DespeckleCommand);
6817 case XK_F3:
6818 return(EmbossCommand);
6819 case XK_F4:
6820 return(ReduceNoiseCommand);
6821 case XK_F5:
6822 return(AddNoiseCommand);
6823 case XK_F6:
6824 return(SharpenCommand);
6825 case XK_F7:
6826 return(BlurCommand);
6827 case XK_F8:
6828 return(ThresholdCommand);
6829 case XK_F9:
6830 return(EdgeDetectCommand);
6831 case XK_F10:
6832 return(SpreadCommand);
6833 case XK_F11:
6834 return(ShadeCommand);
6835 case XK_F12:
6836 return(RaiseCommand);
6837 case XK_F13:
6838 return(SegmentCommand);
6839 case XK_i:
6840 {
6841 if ((state & Mod1Mask) == 0)
6842 return(NullCommand);
6843 return(ImplodeCommand);
6844 }
6845 case XK_w:
6846 {
6847 if ((state & Mod1Mask) == 0)
6848 return(NullCommand);
6849 return(WaveCommand);
6850 }
6851 case XK_m:
6852 {
6853 if ((state & Mod4Mask) == 0)
6854 return(NullCommand);
6855 return(MatteCommand);
6856 }
6857 case XK_b:
6858 {
6859 if ((state & Mod4Mask) == 0)
6860 return(NullCommand);
6861 return(AddBorderCommand);
6862 }
6863 case XK_f:
6864 {
6865 if ((state & Mod4Mask) == 0)
6866 return(NullCommand);
6867 return(AddFrameCommand);
6868 }
6869 case XK_exclam:
6870 {
6871 if ((state & Mod4Mask) == 0)
6872 return(NullCommand);
6873 return(CommentCommand);
6874 }
6875 case XK_a:
6876 {
6877 if ((state & Mod1Mask) != 0)
6878 return(ApplyCommand);
6879 if ((state & Mod4Mask) != 0)
6880 return(AnnotateCommand);
6881 if ((state & ControlMask) == 0)
6882 return(NullCommand);
6883 return(RegionofInterestCommand);
6884 }
6885 case XK_question:
6886 return(InfoCommand);
6887 case XK_plus:
6888 return(ZoomCommand);
6889 case XK_P:
6890 {
6891 if ((state & ShiftMask) == 0)
6892 return(NullCommand);
6893 return(ShowPreviewCommand);
6894 }
6895 case XK_Execute:
6896 return(LaunchCommand);
6897 case XK_F1:
6898 return(HelpCommand);
6899 case XK_Find:
6900 return(BrowseDocumentationCommand);
6901 case XK_Menu:
6902 {
6903 (void) XMapRaised(display,windows->command.id);
6904 return(NullCommand);
6905 }
6906 case XK_Next:
6907 case XK_Prior:
6908 case XK_Home:
6909 case XK_KP_Home:
6910 {
6911 XTranslateImage(display,windows,*image,key_symbol);
6912 return(NullCommand);
6913 }
6914 case XK_Up:
6915 case XK_KP_Up:
6916 case XK_Down:
6917 case XK_KP_Down:
6918 case XK_Left:
6919 case XK_KP_Left:
6920 case XK_Right:
6921 case XK_KP_Right:
6922 {
6923 if ((state & Mod1Mask) != 0)
6924 {
6925 RectangleInfo
6926 crop_info;
6927
6928 /*
6929 Trim one pixel from edge of image.
6930 */
6931 crop_info.x=0;
6932 crop_info.y=0;
6933 crop_info.width=(size_t) windows->image.ximage->width;
6934 crop_info.height=(size_t) windows->image.ximage->height;
6935 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6936 {
6937 if (resource_info->quantum >= (int) crop_info.height)
6938 resource_info->quantum=(int) crop_info.height-1;
6939 crop_info.height-=resource_info->quantum;
6940 }
6941 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6942 {
6943 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6944 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6945 crop_info.y+=resource_info->quantum;
6946 crop_info.height-=resource_info->quantum;
6947 }
6948 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6949 {
6950 if (resource_info->quantum >= (int) crop_info.width)
6951 resource_info->quantum=(int) crop_info.width-1;
6952 crop_info.width-=resource_info->quantum;
6953 }
6954 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6955 {
6956 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6957 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6958 crop_info.x+=resource_info->quantum;
6959 crop_info.width-=resource_info->quantum;
6960 }
6961 if ((int) (windows->image.x+windows->image.width) >
6962 (int) crop_info.width)
6963 windows->image.x=(int) (crop_info.width-windows->image.width);
6964 if ((int) (windows->image.y+windows->image.height) >
6965 (int) crop_info.height)
6966 windows->image.y=(int) (crop_info.height-windows->image.height);
6967 XSetCropGeometry(display,windows,&crop_info,*image);
6968 windows->image.window_changes.width=(int) crop_info.width;
6969 windows->image.window_changes.height=(int) crop_info.height;
6970 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
6971 (void) XConfigureImage(display,resource_info,windows,*image);
6972 return(NullCommand);
6973 }
6974 XTranslateImage(display,windows,*image,key_symbol);
6975 return(NullCommand);
6976 }
6977 default:
6978 return(NullCommand);
6979 }
6980 return(NullCommand);
6981 }
6982
6983 /*
6984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6985 % %
6986 % %
6987 % %
6988 + X M a g i c k C o m m a n d %
6989 % %
6990 % %
6991 % %
6992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6993 %
6994 % XMagickCommand() makes a transform to the image or Image window as
6995 % specified by a user menu button or keyboard command.
6996 %
6997 % The format of the XMagickCommand method is:
6998 %
6999 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7000 % XWindows *windows,const CommandType command,Image **image)
7001 %
7002 % A description of each parameter follows:
7003 %
7004 % o nexus: Method XMagickCommand returns an image when the
7005 % user chooses 'Load Image' from the command menu. Otherwise a null
7006 % image is returned.
7007 %
7008 % o display: Specifies a connection to an X server; returned from
7009 % XOpenDisplay.
7010 %
7011 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7012 %
7013 % o windows: Specifies a pointer to a XWindows structure.
7014 %
7015 % o command: Specifies a command to perform.
7016 %
7017 % o image: the image; XMagickCommand
7018 % may transform the image and return a new image pointer.
7019 %
7020 */
XMagickCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image)7021 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7022 XWindows *windows,const CommandType command,Image **image)
7023 {
7024 char
7025 filename[MaxTextExtent],
7026 geometry[MaxTextExtent],
7027 modulate_factors[MaxTextExtent];
7028
7029 GeometryInfo
7030 geometry_info;
7031
7032 Image
7033 *nexus;
7034
7035 ImageInfo
7036 *image_info;
7037
7038 int
7039 x,
7040 y;
7041
7042 MagickStatusType
7043 flags,
7044 status;
7045
7046 QuantizeInfo
7047 quantize_info;
7048
7049 RectangleInfo
7050 page_geometry;
7051
7052 int
7053 i;
7054
7055 static char
7056 color[MaxTextExtent] = "gray";
7057
7058 unsigned int
7059 height,
7060 width;
7061
7062 /*
7063 Process user command.
7064 */
7065 XCheckRefreshWindows(display,windows);
7066 XImageCache(display,resource_info,windows,command,image);
7067 nexus=NewImageList();
7068 windows->image.window_changes.width=windows->image.ximage->width;
7069 windows->image.window_changes.height=windows->image.ximage->height;
7070 image_info=CloneImageInfo(resource_info->image_info);
7071 SetGeometryInfo(&geometry_info);
7072 GetQuantizeInfo(&quantize_info);
7073 switch (command)
7074 {
7075 case OpenCommand:
7076 {
7077 /*
7078 Load image.
7079 */
7080 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7081 break;
7082 }
7083 case NextCommand:
7084 {
7085 /*
7086 Display next image.
7087 */
7088 for (i=0; i < resource_info->quantum; i++)
7089 XClientMessage(display,windows->image.id,windows->im_protocols,
7090 windows->im_next_image,CurrentTime);
7091 break;
7092 }
7093 case FormerCommand:
7094 {
7095 /*
7096 Display former image.
7097 */
7098 for (i=0; i < resource_info->quantum; i++)
7099 XClientMessage(display,windows->image.id,windows->im_protocols,
7100 windows->im_former_image,CurrentTime);
7101 break;
7102 }
7103 case SelectCommand:
7104 {
7105 int
7106 status;
7107
7108 /*
7109 Select image.
7110 */
7111 if (*resource_info->home_directory == '\0')
7112 (void) CopyMagickString(resource_info->home_directory,".",
7113 MaxTextExtent);
7114 status=chdir(resource_info->home_directory);
7115 if (status == -1)
7116 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7117 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7118 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7119 break;
7120 }
7121 case SaveCommand:
7122 {
7123 /*
7124 Save image.
7125 */
7126 status=XSaveImage(display,resource_info,windows,*image);
7127 if (status == MagickFalse)
7128 {
7129 char
7130 message[MaxTextExtent];
7131
7132 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7133 (*image)->exception.reason != (char *) NULL ?
7134 (*image)->exception.reason : "",
7135 (*image)->exception.description != (char *) NULL ?
7136 (*image)->exception.description : "");
7137 XNoticeWidget(display,windows,"Unable to save file:",message);
7138 break;
7139 }
7140 break;
7141 }
7142 case PrintCommand:
7143 {
7144 /*
7145 Print image.
7146 */
7147 status=XPrintImage(display,resource_info,windows,*image);
7148 if (status == MagickFalse)
7149 {
7150 char
7151 message[MaxTextExtent];
7152
7153 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7154 (*image)->exception.reason != (char *) NULL ?
7155 (*image)->exception.reason : "",
7156 (*image)->exception.description != (char *) NULL ?
7157 (*image)->exception.description : "");
7158 XNoticeWidget(display,windows,"Unable to print file:",message);
7159 break;
7160 }
7161 break;
7162 }
7163 case DeleteCommand:
7164 {
7165 static char
7166 filename[MaxTextExtent] = "\0";
7167
7168 /*
7169 Delete image file.
7170 */
7171 XFileBrowserWidget(display,windows,"Delete",filename);
7172 if (*filename == '\0')
7173 break;
7174 status=ShredFile(filename);
7175 if (status != MagickFalse)
7176 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7177 break;
7178 }
7179 case NewCommand:
7180 {
7181 int
7182 status;
7183
7184 static char
7185 color[MaxTextExtent] = "gray",
7186 geometry[MaxTextExtent] = "640x480";
7187
7188 static const char
7189 *format = "gradient";
7190
7191 /*
7192 Query user for canvas geometry.
7193 */
7194 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7195 geometry);
7196 if (*geometry == '\0')
7197 break;
7198 if (status == 0)
7199 format="xc";
7200 XColorBrowserWidget(display,windows,"Select",color);
7201 if (*color == '\0')
7202 break;
7203 /*
7204 Create canvas.
7205 */
7206 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
7207 "%s:%s",format,color);
7208 (void) CloneString(&image_info->size,geometry);
7209 nexus=ReadImage(image_info,&(*image)->exception);
7210 CatchException(&(*image)->exception);
7211 XClientMessage(display,windows->image.id,windows->im_protocols,
7212 windows->im_next_image,CurrentTime);
7213 break;
7214 }
7215 case VisualDirectoryCommand:
7216 {
7217 /*
7218 Visual Image directory.
7219 */
7220 nexus=XVisualDirectoryImage(display,resource_info,windows);
7221 break;
7222 }
7223 case QuitCommand:
7224 {
7225 /*
7226 exit program.
7227 */
7228 if (resource_info->confirm_exit == MagickFalse)
7229 XClientMessage(display,windows->image.id,windows->im_protocols,
7230 windows->im_exit,CurrentTime);
7231 else
7232 {
7233 int
7234 status;
7235
7236 /*
7237 Confirm program exit.
7238 */
7239 status=XConfirmWidget(display,windows,"Do you really want to exit",
7240 resource_info->client_name);
7241 if (status > 0)
7242 XClientMessage(display,windows->image.id,windows->im_protocols,
7243 windows->im_exit,CurrentTime);
7244 }
7245 break;
7246 }
7247 case CutCommand:
7248 {
7249 /*
7250 Cut image.
7251 */
7252 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7253 break;
7254 }
7255 case CopyCommand:
7256 {
7257 /*
7258 Copy image.
7259 */
7260 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7261 break;
7262 }
7263 case PasteCommand:
7264 {
7265 /*
7266 Paste image.
7267 */
7268 status=XPasteImage(display,resource_info,windows,*image);
7269 if (status == MagickFalse)
7270 {
7271 XNoticeWidget(display,windows,"Unable to paste X image",
7272 (*image)->filename);
7273 break;
7274 }
7275 break;
7276 }
7277 case HalfSizeCommand:
7278 {
7279 /*
7280 Half image size.
7281 */
7282 windows->image.window_changes.width=windows->image.ximage->width/2;
7283 windows->image.window_changes.height=windows->image.ximage->height/2;
7284 (void) XConfigureImage(display,resource_info,windows,*image);
7285 break;
7286 }
7287 case OriginalSizeCommand:
7288 {
7289 /*
7290 Original image size.
7291 */
7292 windows->image.window_changes.width=(int) (*image)->columns;
7293 windows->image.window_changes.height=(int) (*image)->rows;
7294 (void) XConfigureImage(display,resource_info,windows,*image);
7295 break;
7296 }
7297 case DoubleSizeCommand:
7298 {
7299 /*
7300 Double the image size.
7301 */
7302 windows->image.window_changes.width=windows->image.ximage->width << 1;
7303 windows->image.window_changes.height=windows->image.ximage->height << 1;
7304 (void) XConfigureImage(display,resource_info,windows,*image);
7305 break;
7306 }
7307 case ResizeCommand:
7308 {
7309 int
7310 status;
7311
7312 size_t
7313 height,
7314 width;
7315
7316 ssize_t
7317 x,
7318 y;
7319
7320 /*
7321 Resize image.
7322 */
7323 width=(size_t) windows->image.ximage->width;
7324 height=(size_t) windows->image.ximage->height;
7325 x=0;
7326 y=0;
7327 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7328 (double) width,(double) height);
7329 status=XDialogWidget(display,windows,"Resize",
7330 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7331 if (*geometry == '\0')
7332 break;
7333 if (status == 0)
7334 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7335 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7336 windows->image.window_changes.width=(int) width;
7337 windows->image.window_changes.height=(int) height;
7338 (void) XConfigureImage(display,resource_info,windows,*image);
7339 break;
7340 }
7341 case ApplyCommand:
7342 {
7343 char
7344 image_geometry[MaxTextExtent];
7345
7346 if ((windows->image.crop_geometry == (char *) NULL) &&
7347 ((int) (*image)->columns == windows->image.ximage->width) &&
7348 ((int) (*image)->rows == windows->image.ximage->height))
7349 break;
7350 /*
7351 Apply size transforms to image.
7352 */
7353 XSetCursorState(display,windows,MagickTrue);
7354 XCheckRefreshWindows(display,windows);
7355 /*
7356 Crop and/or scale displayed image.
7357 */
7358 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
7359 windows->image.ximage->width,windows->image.ximage->height);
7360 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7361 if (windows->image.crop_geometry != (char *) NULL)
7362 windows->image.crop_geometry=(char *)
7363 RelinquishMagickMemory(windows->image.crop_geometry);
7364 windows->image.x=0;
7365 windows->image.y=0;
7366 XConfigureImageColormap(display,resource_info,windows,*image);
7367 (void) XConfigureImage(display,resource_info,windows,*image);
7368 break;
7369 }
7370 case RefreshCommand:
7371 {
7372 (void) XConfigureImage(display,resource_info,windows,*image);
7373 break;
7374 }
7375 case RestoreCommand:
7376 {
7377 /*
7378 Restore Image window to its original size.
7379 */
7380 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7381 (windows->image.height == (unsigned int) (*image)->rows) &&
7382 (windows->image.crop_geometry == (char *) NULL))
7383 {
7384 (void) XBell(display,0);
7385 break;
7386 }
7387 windows->image.window_changes.width=(int) (*image)->columns;
7388 windows->image.window_changes.height=(int) (*image)->rows;
7389 if (windows->image.crop_geometry != (char *) NULL)
7390 {
7391 windows->image.crop_geometry=(char *)
7392 RelinquishMagickMemory(windows->image.crop_geometry);
7393 windows->image.crop_geometry=(char *) NULL;
7394 windows->image.x=0;
7395 windows->image.y=0;
7396 }
7397 XConfigureImageColormap(display,resource_info,windows,*image);
7398 (void) XConfigureImage(display,resource_info,windows,*image);
7399 break;
7400 }
7401 case CropCommand:
7402 {
7403 /*
7404 Crop image.
7405 */
7406 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7407 break;
7408 }
7409 case ChopCommand:
7410 {
7411 /*
7412 Chop image.
7413 */
7414 status=XChopImage(display,resource_info,windows,image);
7415 if (status == MagickFalse)
7416 {
7417 XNoticeWidget(display,windows,"Unable to cut X image",
7418 (*image)->filename);
7419 break;
7420 }
7421 break;
7422 }
7423 case FlopCommand:
7424 {
7425 Image
7426 *flop_image;
7427
7428 /*
7429 Flop image scanlines.
7430 */
7431 XSetCursorState(display,windows,MagickTrue);
7432 XCheckRefreshWindows(display,windows);
7433 flop_image=FlopImage(*image,&(*image)->exception);
7434 if (flop_image != (Image *) NULL)
7435 {
7436 *image=DestroyImage(*image);
7437 *image=flop_image;
7438 }
7439 CatchException(&(*image)->exception);
7440 XSetCursorState(display,windows,MagickFalse);
7441 if (windows->image.crop_geometry != (char *) NULL)
7442 {
7443 /*
7444 Flop crop geometry.
7445 */
7446 width=(unsigned int) (*image)->columns;
7447 height=(unsigned int) (*image)->rows;
7448 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7449 &width,&height);
7450 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7451 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7452 }
7453 if (windows->image.orphan != MagickFalse)
7454 break;
7455 (void) XConfigureImage(display,resource_info,windows,*image);
7456 break;
7457 }
7458 case FlipCommand:
7459 {
7460 Image
7461 *flip_image;
7462
7463 /*
7464 Flip image scanlines.
7465 */
7466 XSetCursorState(display,windows,MagickTrue);
7467 XCheckRefreshWindows(display,windows);
7468 flip_image=FlipImage(*image,&(*image)->exception);
7469 if (flip_image != (Image *) NULL)
7470 {
7471 *image=DestroyImage(*image);
7472 *image=flip_image;
7473 }
7474 CatchException(&(*image)->exception);
7475 XSetCursorState(display,windows,MagickFalse);
7476 if (windows->image.crop_geometry != (char *) NULL)
7477 {
7478 /*
7479 Flip crop geometry.
7480 */
7481 width=(unsigned int) (*image)->columns;
7482 height=(unsigned int) (*image)->rows;
7483 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7484 &width,&height);
7485 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7486 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7487 }
7488 if (windows->image.orphan != MagickFalse)
7489 break;
7490 (void) XConfigureImage(display,resource_info,windows,*image);
7491 break;
7492 }
7493 case RotateRightCommand:
7494 {
7495 /*
7496 Rotate image 90 degrees clockwise.
7497 */
7498 status=XRotateImage(display,resource_info,windows,90.0,image);
7499 if (status == MagickFalse)
7500 {
7501 XNoticeWidget(display,windows,"Unable to rotate X image",
7502 (*image)->filename);
7503 break;
7504 }
7505 break;
7506 }
7507 case RotateLeftCommand:
7508 {
7509 /*
7510 Rotate image 90 degrees counter-clockwise.
7511 */
7512 status=XRotateImage(display,resource_info,windows,-90.0,image);
7513 if (status == MagickFalse)
7514 {
7515 XNoticeWidget(display,windows,"Unable to rotate X image",
7516 (*image)->filename);
7517 break;
7518 }
7519 break;
7520 }
7521 case RotateCommand:
7522 {
7523 /*
7524 Rotate image.
7525 */
7526 status=XRotateImage(display,resource_info,windows,0.0,image);
7527 if (status == MagickFalse)
7528 {
7529 XNoticeWidget(display,windows,"Unable to rotate X image",
7530 (*image)->filename);
7531 break;
7532 }
7533 break;
7534 }
7535 case ShearCommand:
7536 {
7537 Image
7538 *shear_image;
7539
7540 static char
7541 geometry[MaxTextExtent] = "45.0x45.0";
7542
7543 /*
7544 Query user for shear color and geometry.
7545 */
7546 XColorBrowserWidget(display,windows,"Select",color);
7547 if (*color == '\0')
7548 break;
7549 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7550 geometry);
7551 if (*geometry == '\0')
7552 break;
7553 /*
7554 Shear image.
7555 */
7556 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7557 XSetCursorState(display,windows,MagickTrue);
7558 XCheckRefreshWindows(display,windows);
7559 (void) QueryColorDatabase(color,&(*image)->background_color,
7560 &(*image)->exception);
7561 flags=ParseGeometry(geometry,&geometry_info);
7562 if ((flags & SigmaValue) == 0)
7563 geometry_info.sigma=geometry_info.rho;
7564 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7565 &(*image)->exception);
7566 if (shear_image != (Image *) NULL)
7567 {
7568 *image=DestroyImage(*image);
7569 *image=shear_image;
7570 }
7571 CatchException(&(*image)->exception);
7572 XSetCursorState(display,windows,MagickFalse);
7573 if (windows->image.orphan != MagickFalse)
7574 break;
7575 windows->image.window_changes.width=(int) (*image)->columns;
7576 windows->image.window_changes.height=(int) (*image)->rows;
7577 XConfigureImageColormap(display,resource_info,windows,*image);
7578 (void) XConfigureImage(display,resource_info,windows,*image);
7579 break;
7580 }
7581 case RollCommand:
7582 {
7583 Image
7584 *roll_image;
7585
7586 static char
7587 geometry[MaxTextExtent] = "+2+2";
7588
7589 /*
7590 Query user for the roll geometry.
7591 */
7592 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7593 geometry);
7594 if (*geometry == '\0')
7595 break;
7596 /*
7597 Roll image.
7598 */
7599 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7600 XSetCursorState(display,windows,MagickTrue);
7601 XCheckRefreshWindows(display,windows);
7602 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7603 &(*image)->exception);
7604 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7605 &(*image)->exception);
7606 if (roll_image != (Image *) NULL)
7607 {
7608 *image=DestroyImage(*image);
7609 *image=roll_image;
7610 }
7611 CatchException(&(*image)->exception);
7612 XSetCursorState(display,windows,MagickFalse);
7613 if (windows->image.orphan != MagickFalse)
7614 break;
7615 windows->image.window_changes.width=(int) (*image)->columns;
7616 windows->image.window_changes.height=(int) (*image)->rows;
7617 XConfigureImageColormap(display,resource_info,windows,*image);
7618 (void) XConfigureImage(display,resource_info,windows,*image);
7619 break;
7620 }
7621 case TrimCommand:
7622 {
7623 static char
7624 fuzz[MaxTextExtent];
7625
7626 /*
7627 Query user for the fuzz factor.
7628 */
7629 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
7630 (*image)->fuzz/(QuantumRange+1.0));
7631 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7632 if (*fuzz == '\0')
7633 break;
7634 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7635 /*
7636 Trim image.
7637 */
7638 status=XTrimImage(display,resource_info,windows,*image);
7639 if (status == MagickFalse)
7640 {
7641 XNoticeWidget(display,windows,"Unable to trim X image",
7642 (*image)->filename);
7643 break;
7644 }
7645 break;
7646 }
7647 case HueCommand:
7648 {
7649 static char
7650 hue_percent[MaxTextExtent] = "110";
7651
7652 /*
7653 Query user for percent hue change.
7654 */
7655 (void) XDialogWidget(display,windows,"Apply",
7656 "Enter percent change in image hue (0-200):",hue_percent);
7657 if (*hue_percent == '\0')
7658 break;
7659 /*
7660 Vary the image hue.
7661 */
7662 XSetCursorState(display,windows,MagickTrue);
7663 XCheckRefreshWindows(display,windows);
7664 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7665 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7666 MaxTextExtent);
7667 (void) ModulateImage(*image,modulate_factors);
7668 XSetCursorState(display,windows,MagickFalse);
7669 if (windows->image.orphan != MagickFalse)
7670 break;
7671 XConfigureImageColormap(display,resource_info,windows,*image);
7672 (void) XConfigureImage(display,resource_info,windows,*image);
7673 break;
7674 }
7675 case SaturationCommand:
7676 {
7677 static char
7678 saturation_percent[MaxTextExtent] = "110";
7679
7680 /*
7681 Query user for percent saturation change.
7682 */
7683 (void) XDialogWidget(display,windows,"Apply",
7684 "Enter percent change in color saturation (0-200):",saturation_percent);
7685 if (*saturation_percent == '\0')
7686 break;
7687 /*
7688 Vary color saturation.
7689 */
7690 XSetCursorState(display,windows,MagickTrue);
7691 XCheckRefreshWindows(display,windows);
7692 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7693 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7694 MaxTextExtent);
7695 (void) ModulateImage(*image,modulate_factors);
7696 XSetCursorState(display,windows,MagickFalse);
7697 if (windows->image.orphan != MagickFalse)
7698 break;
7699 XConfigureImageColormap(display,resource_info,windows,*image);
7700 (void) XConfigureImage(display,resource_info,windows,*image);
7701 break;
7702 }
7703 case BrightnessCommand:
7704 {
7705 static char
7706 brightness_percent[MaxTextExtent] = "110";
7707
7708 /*
7709 Query user for percent brightness change.
7710 */
7711 (void) XDialogWidget(display,windows,"Apply",
7712 "Enter percent change in color brightness (0-200):",brightness_percent);
7713 if (*brightness_percent == '\0')
7714 break;
7715 /*
7716 Vary the color brightness.
7717 */
7718 XSetCursorState(display,windows,MagickTrue);
7719 XCheckRefreshWindows(display,windows);
7720 (void) CopyMagickString(modulate_factors,brightness_percent,
7721 MaxTextExtent);
7722 (void) ModulateImage(*image,modulate_factors);
7723 XSetCursorState(display,windows,MagickFalse);
7724 if (windows->image.orphan != MagickFalse)
7725 break;
7726 XConfigureImageColormap(display,resource_info,windows,*image);
7727 (void) XConfigureImage(display,resource_info,windows,*image);
7728 break;
7729 }
7730 case GammaCommand:
7731 {
7732 static char
7733 factor[MaxTextExtent] = "1.6";
7734
7735 /*
7736 Query user for gamma value.
7737 */
7738 (void) XDialogWidget(display,windows,"Gamma",
7739 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7740 if (*factor == '\0')
7741 break;
7742 /*
7743 Gamma correct image.
7744 */
7745 XSetCursorState(display,windows,MagickTrue);
7746 XCheckRefreshWindows(display,windows);
7747 (void) GammaImage(*image,factor);
7748 XSetCursorState(display,windows,MagickFalse);
7749 if (windows->image.orphan != MagickFalse)
7750 break;
7751 XConfigureImageColormap(display,resource_info,windows,*image);
7752 (void) XConfigureImage(display,resource_info,windows,*image);
7753 break;
7754 }
7755 case SpiffCommand:
7756 {
7757 /*
7758 Sharpen the image contrast.
7759 */
7760 XSetCursorState(display,windows,MagickTrue);
7761 XCheckRefreshWindows(display,windows);
7762 (void) ContrastImage(*image,MagickTrue);
7763 XSetCursorState(display,windows,MagickFalse);
7764 if (windows->image.orphan != MagickFalse)
7765 break;
7766 XConfigureImageColormap(display,resource_info,windows,*image);
7767 (void) XConfigureImage(display,resource_info,windows,*image);
7768 break;
7769 }
7770 case DullCommand:
7771 {
7772 /*
7773 Dull the image contrast.
7774 */
7775 XSetCursorState(display,windows,MagickTrue);
7776 XCheckRefreshWindows(display,windows);
7777 (void) ContrastImage(*image,MagickFalse);
7778 XSetCursorState(display,windows,MagickFalse);
7779 if (windows->image.orphan != MagickFalse)
7780 break;
7781 XConfigureImageColormap(display,resource_info,windows,*image);
7782 (void) XConfigureImage(display,resource_info,windows,*image);
7783 break;
7784 }
7785 case ContrastStretchCommand:
7786 {
7787 double
7788 black_point,
7789 white_point;
7790
7791 static char
7792 levels[MaxTextExtent] = "1%";
7793
7794 /*
7795 Query user for gamma value.
7796 */
7797 (void) XDialogWidget(display,windows,"Contrast Stretch",
7798 "Enter black and white points:",levels);
7799 if (*levels == '\0')
7800 break;
7801 /*
7802 Contrast stretch image.
7803 */
7804 XSetCursorState(display,windows,MagickTrue);
7805 XCheckRefreshWindows(display,windows);
7806 flags=ParseGeometry(levels,&geometry_info);
7807 black_point=geometry_info.rho;
7808 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7809 if ((flags & PercentValue) != 0)
7810 {
7811 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7812 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7813 }
7814 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7815 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7816 white_point);
7817 XSetCursorState(display,windows,MagickFalse);
7818 if (windows->image.orphan != MagickFalse)
7819 break;
7820 XConfigureImageColormap(display,resource_info,windows,*image);
7821 (void) XConfigureImage(display,resource_info,windows,*image);
7822 break;
7823 }
7824 case SigmoidalContrastCommand:
7825 {
7826 static char
7827 levels[MaxTextExtent] = "3x50%";
7828
7829 /*
7830 Query user for gamma value.
7831 */
7832 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7833 "Enter contrast and midpoint:",levels);
7834 if (*levels == '\0')
7835 break;
7836 /*
7837 Contrast stretch image.
7838 */
7839 XSetCursorState(display,windows,MagickTrue);
7840 XCheckRefreshWindows(display,windows);
7841 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
7842 XSetCursorState(display,windows,MagickFalse);
7843 if (windows->image.orphan != MagickFalse)
7844 break;
7845 XConfigureImageColormap(display,resource_info,windows,*image);
7846 (void) XConfigureImage(display,resource_info,windows,*image);
7847 break;
7848 }
7849 case NormalizeCommand:
7850 {
7851 /*
7852 Perform histogram normalization on the image.
7853 */
7854 XSetCursorState(display,windows,MagickTrue);
7855 XCheckRefreshWindows(display,windows);
7856 (void) NormalizeImage(*image);
7857 XSetCursorState(display,windows,MagickFalse);
7858 if (windows->image.orphan != MagickFalse)
7859 break;
7860 XConfigureImageColormap(display,resource_info,windows,*image);
7861 (void) XConfigureImage(display,resource_info,windows,*image);
7862 break;
7863 }
7864 case EqualizeCommand:
7865 {
7866 /*
7867 Perform histogram equalization on the image.
7868 */
7869 XSetCursorState(display,windows,MagickTrue);
7870 XCheckRefreshWindows(display,windows);
7871 (void) EqualizeImage(*image);
7872 XSetCursorState(display,windows,MagickFalse);
7873 if (windows->image.orphan != MagickFalse)
7874 break;
7875 XConfigureImageColormap(display,resource_info,windows,*image);
7876 (void) XConfigureImage(display,resource_info,windows,*image);
7877 break;
7878 }
7879 case NegateCommand:
7880 {
7881 /*
7882 Negate colors in image.
7883 */
7884 XSetCursorState(display,windows,MagickTrue);
7885 XCheckRefreshWindows(display,windows);
7886 (void) NegateImage(*image,MagickFalse);
7887 XSetCursorState(display,windows,MagickFalse);
7888 if (windows->image.orphan != MagickFalse)
7889 break;
7890 XConfigureImageColormap(display,resource_info,windows,*image);
7891 (void) XConfigureImage(display,resource_info,windows,*image);
7892 break;
7893 }
7894 case GrayscaleCommand:
7895 {
7896 /*
7897 Convert image to grayscale.
7898 */
7899 XSetCursorState(display,windows,MagickTrue);
7900 XCheckRefreshWindows(display,windows);
7901 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7902 GrayscaleType : GrayscaleMatteType);
7903 XSetCursorState(display,windows,MagickFalse);
7904 if (windows->image.orphan != MagickFalse)
7905 break;
7906 XConfigureImageColormap(display,resource_info,windows,*image);
7907 (void) XConfigureImage(display,resource_info,windows,*image);
7908 break;
7909 }
7910 case MapCommand:
7911 {
7912 Image
7913 *affinity_image;
7914
7915 static char
7916 filename[MaxTextExtent] = "\0";
7917
7918 /*
7919 Request image file name from user.
7920 */
7921 XFileBrowserWidget(display,windows,"Map",filename);
7922 if (*filename == '\0')
7923 break;
7924 /*
7925 Map image.
7926 */
7927 XSetCursorState(display,windows,MagickTrue);
7928 XCheckRefreshWindows(display,windows);
7929 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7930 affinity_image=ReadImage(image_info,&(*image)->exception);
7931 if (affinity_image != (Image *) NULL)
7932 {
7933 (void) RemapImage(&quantize_info,*image,affinity_image);
7934 affinity_image=DestroyImage(affinity_image);
7935 }
7936 CatchException(&(*image)->exception);
7937 XSetCursorState(display,windows,MagickFalse);
7938 if (windows->image.orphan != MagickFalse)
7939 break;
7940 XConfigureImageColormap(display,resource_info,windows,*image);
7941 (void) XConfigureImage(display,resource_info,windows,*image);
7942 break;
7943 }
7944 case QuantizeCommand:
7945 {
7946 int
7947 status;
7948
7949 static char
7950 colors[MaxTextExtent] = "256";
7951
7952 /*
7953 Query user for maximum number of colors.
7954 */
7955 status=XDialogWidget(display,windows,"Quantize",
7956 "Maximum number of colors:",colors);
7957 if (*colors == '\0')
7958 break;
7959 /*
7960 Color reduce the image.
7961 */
7962 XSetCursorState(display,windows,MagickTrue);
7963 XCheckRefreshWindows(display,windows);
7964 quantize_info.number_colors=StringToUnsignedLong(colors);
7965 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7966 (void) QuantizeImage(&quantize_info,*image);
7967 XSetCursorState(display,windows,MagickFalse);
7968 if (windows->image.orphan != MagickFalse)
7969 break;
7970 XConfigureImageColormap(display,resource_info,windows,*image);
7971 (void) XConfigureImage(display,resource_info,windows,*image);
7972 break;
7973 }
7974 case DespeckleCommand:
7975 {
7976 Image
7977 *despeckle_image;
7978
7979 /*
7980 Despeckle image.
7981 */
7982 XSetCursorState(display,windows,MagickTrue);
7983 XCheckRefreshWindows(display,windows);
7984 despeckle_image=DespeckleImage(*image,&(*image)->exception);
7985 if (despeckle_image != (Image *) NULL)
7986 {
7987 *image=DestroyImage(*image);
7988 *image=despeckle_image;
7989 }
7990 CatchException(&(*image)->exception);
7991 XSetCursorState(display,windows,MagickFalse);
7992 if (windows->image.orphan != MagickFalse)
7993 break;
7994 XConfigureImageColormap(display,resource_info,windows,*image);
7995 (void) XConfigureImage(display,resource_info,windows,*image);
7996 break;
7997 }
7998 case EmbossCommand:
7999 {
8000 Image
8001 *emboss_image;
8002
8003 static char
8004 radius[MaxTextExtent] = "0.0x1.0";
8005
8006 /*
8007 Query user for emboss radius.
8008 */
8009 (void) XDialogWidget(display,windows,"Emboss",
8010 "Enter the emboss radius and standard deviation:",radius);
8011 if (*radius == '\0')
8012 break;
8013 /*
8014 Reduce noise in the image.
8015 */
8016 XSetCursorState(display,windows,MagickTrue);
8017 XCheckRefreshWindows(display,windows);
8018 flags=ParseGeometry(radius,&geometry_info);
8019 if ((flags & SigmaValue) == 0)
8020 geometry_info.sigma=1.0;
8021 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8022 &(*image)->exception);
8023 if (emboss_image != (Image *) NULL)
8024 {
8025 *image=DestroyImage(*image);
8026 *image=emboss_image;
8027 }
8028 CatchException(&(*image)->exception);
8029 XSetCursorState(display,windows,MagickFalse);
8030 if (windows->image.orphan != MagickFalse)
8031 break;
8032 XConfigureImageColormap(display,resource_info,windows,*image);
8033 (void) XConfigureImage(display,resource_info,windows,*image);
8034 break;
8035 }
8036 case ReduceNoiseCommand:
8037 {
8038 Image
8039 *noise_image;
8040
8041 static char
8042 radius[MaxTextExtent] = "0";
8043
8044 /*
8045 Query user for noise radius.
8046 */
8047 (void) XDialogWidget(display,windows,"Reduce Noise",
8048 "Enter the noise radius:",radius);
8049 if (*radius == '\0')
8050 break;
8051 /*
8052 Reduce noise in the image.
8053 */
8054 XSetCursorState(display,windows,MagickTrue);
8055 XCheckRefreshWindows(display,windows);
8056 flags=ParseGeometry(radius,&geometry_info);
8057 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8058 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
8059 if (noise_image != (Image *) NULL)
8060 {
8061 *image=DestroyImage(*image);
8062 *image=noise_image;
8063 }
8064 CatchException(&(*image)->exception);
8065 XSetCursorState(display,windows,MagickFalse);
8066 if (windows->image.orphan != MagickFalse)
8067 break;
8068 XConfigureImageColormap(display,resource_info,windows,*image);
8069 (void) XConfigureImage(display,resource_info,windows,*image);
8070 break;
8071 }
8072 case AddNoiseCommand:
8073 {
8074 char
8075 **noises;
8076
8077 Image
8078 *noise_image;
8079
8080 static char
8081 noise_type[MaxTextExtent] = "Gaussian";
8082
8083 /*
8084 Add noise to the image.
8085 */
8086 noises=GetCommandOptions(MagickNoiseOptions);
8087 if (noises == (char **) NULL)
8088 break;
8089 XListBrowserWidget(display,windows,&windows->widget,
8090 (const char **) noises,"Add Noise",
8091 "Select a type of noise to add to your image:",noise_type);
8092 noises=DestroyStringList(noises);
8093 if (*noise_type == '\0')
8094 break;
8095 XSetCursorState(display,windows,MagickTrue);
8096 XCheckRefreshWindows(display,windows);
8097 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8098 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8099 if (noise_image != (Image *) NULL)
8100 {
8101 *image=DestroyImage(*image);
8102 *image=noise_image;
8103 }
8104 CatchException(&(*image)->exception);
8105 XSetCursorState(display,windows,MagickFalse);
8106 if (windows->image.orphan != MagickFalse)
8107 break;
8108 XConfigureImageColormap(display,resource_info,windows,*image);
8109 (void) XConfigureImage(display,resource_info,windows,*image);
8110 break;
8111 }
8112 case SharpenCommand:
8113 {
8114 Image
8115 *sharp_image;
8116
8117 static char
8118 radius[MaxTextExtent] = "0.0x1.0";
8119
8120 /*
8121 Query user for sharpen radius.
8122 */
8123 (void) XDialogWidget(display,windows,"Sharpen",
8124 "Enter the sharpen radius and standard deviation:",radius);
8125 if (*radius == '\0')
8126 break;
8127 /*
8128 Sharpen image scanlines.
8129 */
8130 XSetCursorState(display,windows,MagickTrue);
8131 XCheckRefreshWindows(display,windows);
8132 flags=ParseGeometry(radius,&geometry_info);
8133 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8134 &(*image)->exception);
8135 if (sharp_image != (Image *) NULL)
8136 {
8137 *image=DestroyImage(*image);
8138 *image=sharp_image;
8139 }
8140 CatchException(&(*image)->exception);
8141 XSetCursorState(display,windows,MagickFalse);
8142 if (windows->image.orphan != MagickFalse)
8143 break;
8144 XConfigureImageColormap(display,resource_info,windows,*image);
8145 (void) XConfigureImage(display,resource_info,windows,*image);
8146 break;
8147 }
8148 case BlurCommand:
8149 {
8150 Image
8151 *blur_image;
8152
8153 static char
8154 radius[MaxTextExtent] = "0.0x1.0";
8155
8156 /*
8157 Query user for blur radius.
8158 */
8159 (void) XDialogWidget(display,windows,"Blur",
8160 "Enter the blur radius and standard deviation:",radius);
8161 if (*radius == '\0')
8162 break;
8163 /*
8164 Blur an image.
8165 */
8166 XSetCursorState(display,windows,MagickTrue);
8167 XCheckRefreshWindows(display,windows);
8168 flags=ParseGeometry(radius,&geometry_info);
8169 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8170 &(*image)->exception);
8171 if (blur_image != (Image *) NULL)
8172 {
8173 *image=DestroyImage(*image);
8174 *image=blur_image;
8175 }
8176 CatchException(&(*image)->exception);
8177 XSetCursorState(display,windows,MagickFalse);
8178 if (windows->image.orphan != MagickFalse)
8179 break;
8180 XConfigureImageColormap(display,resource_info,windows,*image);
8181 (void) XConfigureImage(display,resource_info,windows,*image);
8182 break;
8183 }
8184 case ThresholdCommand:
8185 {
8186 double
8187 threshold;
8188
8189 static char
8190 factor[MaxTextExtent] = "128";
8191
8192 /*
8193 Query user for threshold value.
8194 */
8195 (void) XDialogWidget(display,windows,"Threshold",
8196 "Enter threshold value:",factor);
8197 if (*factor == '\0')
8198 break;
8199 /*
8200 Gamma correct image.
8201 */
8202 XSetCursorState(display,windows,MagickTrue);
8203 XCheckRefreshWindows(display,windows);
8204 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8205 (void) BilevelImage(*image,threshold);
8206 XSetCursorState(display,windows,MagickFalse);
8207 if (windows->image.orphan != MagickFalse)
8208 break;
8209 XConfigureImageColormap(display,resource_info,windows,*image);
8210 (void) XConfigureImage(display,resource_info,windows,*image);
8211 break;
8212 }
8213 case EdgeDetectCommand:
8214 {
8215 Image
8216 *edge_image;
8217
8218 static char
8219 radius[MaxTextExtent] = "0";
8220
8221 /*
8222 Query user for edge factor.
8223 */
8224 (void) XDialogWidget(display,windows,"Detect Edges",
8225 "Enter the edge detect radius:",radius);
8226 if (*radius == '\0')
8227 break;
8228 /*
8229 Detect edge in image.
8230 */
8231 XSetCursorState(display,windows,MagickTrue);
8232 XCheckRefreshWindows(display,windows);
8233 flags=ParseGeometry(radius,&geometry_info);
8234 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8235 if (edge_image != (Image *) NULL)
8236 {
8237 *image=DestroyImage(*image);
8238 *image=edge_image;
8239 }
8240 CatchException(&(*image)->exception);
8241 XSetCursorState(display,windows,MagickFalse);
8242 if (windows->image.orphan != MagickFalse)
8243 break;
8244 XConfigureImageColormap(display,resource_info,windows,*image);
8245 (void) XConfigureImage(display,resource_info,windows,*image);
8246 break;
8247 }
8248 case SpreadCommand:
8249 {
8250 Image
8251 *spread_image;
8252
8253 static char
8254 amount[MaxTextExtent] = "2";
8255
8256 /*
8257 Query user for spread amount.
8258 */
8259 (void) XDialogWidget(display,windows,"Spread",
8260 "Enter the displacement amount:",amount);
8261 if (*amount == '\0')
8262 break;
8263 /*
8264 Displace image pixels by a random amount.
8265 */
8266 XSetCursorState(display,windows,MagickTrue);
8267 XCheckRefreshWindows(display,windows);
8268 flags=ParseGeometry(amount,&geometry_info);
8269 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8270 if (spread_image != (Image *) NULL)
8271 {
8272 *image=DestroyImage(*image);
8273 *image=spread_image;
8274 }
8275 CatchException(&(*image)->exception);
8276 XSetCursorState(display,windows,MagickFalse);
8277 if (windows->image.orphan != MagickFalse)
8278 break;
8279 XConfigureImageColormap(display,resource_info,windows,*image);
8280 (void) XConfigureImage(display,resource_info,windows,*image);
8281 break;
8282 }
8283 case ShadeCommand:
8284 {
8285 Image
8286 *shade_image;
8287
8288 int
8289 status;
8290
8291 static char
8292 geometry[MaxTextExtent] = "30x30";
8293
8294 /*
8295 Query user for the shade geometry.
8296 */
8297 status=XDialogWidget(display,windows,"Shade",
8298 "Enter the azimuth and elevation of the light source:",geometry);
8299 if (*geometry == '\0')
8300 break;
8301 /*
8302 Shade image pixels.
8303 */
8304 XSetCursorState(display,windows,MagickTrue);
8305 XCheckRefreshWindows(display,windows);
8306 flags=ParseGeometry(geometry,&geometry_info);
8307 if ((flags & SigmaValue) == 0)
8308 geometry_info.sigma=1.0;
8309 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8310 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8311 if (shade_image != (Image *) NULL)
8312 {
8313 *image=DestroyImage(*image);
8314 *image=shade_image;
8315 }
8316 CatchException(&(*image)->exception);
8317 XSetCursorState(display,windows,MagickFalse);
8318 if (windows->image.orphan != MagickFalse)
8319 break;
8320 XConfigureImageColormap(display,resource_info,windows,*image);
8321 (void) XConfigureImage(display,resource_info,windows,*image);
8322 break;
8323 }
8324 case RaiseCommand:
8325 {
8326 static char
8327 bevel_width[MaxTextExtent] = "10";
8328
8329 /*
8330 Query user for bevel width.
8331 */
8332 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8333 if (*bevel_width == '\0')
8334 break;
8335 /*
8336 Raise an image.
8337 */
8338 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8339 XSetCursorState(display,windows,MagickTrue);
8340 XCheckRefreshWindows(display,windows);
8341 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8342 &(*image)->exception);
8343 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8344 XSetCursorState(display,windows,MagickFalse);
8345 if (windows->image.orphan != MagickFalse)
8346 break;
8347 XConfigureImageColormap(display,resource_info,windows,*image);
8348 (void) XConfigureImage(display,resource_info,windows,*image);
8349 break;
8350 }
8351 case SegmentCommand:
8352 {
8353 static char
8354 threshold[MaxTextExtent] = "1.0x1.5";
8355
8356 /*
8357 Query user for smoothing threshold.
8358 */
8359 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8360 threshold);
8361 if (*threshold == '\0')
8362 break;
8363 /*
8364 Segment an image.
8365 */
8366 XSetCursorState(display,windows,MagickTrue);
8367 XCheckRefreshWindows(display,windows);
8368 flags=ParseGeometry(threshold,&geometry_info);
8369 if ((flags & SigmaValue) == 0)
8370 geometry_info.sigma=1.0;
8371 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8372 geometry_info.sigma);
8373 XSetCursorState(display,windows,MagickFalse);
8374 if (windows->image.orphan != MagickFalse)
8375 break;
8376 XConfigureImageColormap(display,resource_info,windows,*image);
8377 (void) XConfigureImage(display,resource_info,windows,*image);
8378 break;
8379 }
8380 case SepiaToneCommand:
8381 {
8382 double
8383 threshold;
8384
8385 Image
8386 *sepia_image;
8387
8388 static char
8389 factor[MaxTextExtent] = "80%";
8390
8391 /*
8392 Query user for sepia-tone factor.
8393 */
8394 (void) XDialogWidget(display,windows,"Sepia Tone",
8395 "Enter the sepia tone factor (0 - 99.9%):",factor);
8396 if (*factor == '\0')
8397 break;
8398 /*
8399 Sepia tone image pixels.
8400 */
8401 XSetCursorState(display,windows,MagickTrue);
8402 XCheckRefreshWindows(display,windows);
8403 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8404 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8405 if (sepia_image != (Image *) NULL)
8406 {
8407 *image=DestroyImage(*image);
8408 *image=sepia_image;
8409 }
8410 CatchException(&(*image)->exception);
8411 XSetCursorState(display,windows,MagickFalse);
8412 if (windows->image.orphan != MagickFalse)
8413 break;
8414 XConfigureImageColormap(display,resource_info,windows,*image);
8415 (void) XConfigureImage(display,resource_info,windows,*image);
8416 break;
8417 }
8418 case SolarizeCommand:
8419 {
8420 double
8421 threshold;
8422
8423 static char
8424 factor[MaxTextExtent] = "60%";
8425
8426 /*
8427 Query user for solarize factor.
8428 */
8429 (void) XDialogWidget(display,windows,"Solarize",
8430 "Enter the solarize factor (0 - 99.9%):",factor);
8431 if (*factor == '\0')
8432 break;
8433 /*
8434 Solarize image pixels.
8435 */
8436 XSetCursorState(display,windows,MagickTrue);
8437 XCheckRefreshWindows(display,windows);
8438 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8439 (void) SolarizeImage(*image,threshold);
8440 XSetCursorState(display,windows,MagickFalse);
8441 if (windows->image.orphan != MagickFalse)
8442 break;
8443 XConfigureImageColormap(display,resource_info,windows,*image);
8444 (void) XConfigureImage(display,resource_info,windows,*image);
8445 break;
8446 }
8447 case SwirlCommand:
8448 {
8449 Image
8450 *swirl_image;
8451
8452 static char
8453 degrees[MaxTextExtent] = "60";
8454
8455 /*
8456 Query user for swirl angle.
8457 */
8458 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8459 degrees);
8460 if (*degrees == '\0')
8461 break;
8462 /*
8463 Swirl image pixels about the center.
8464 */
8465 XSetCursorState(display,windows,MagickTrue);
8466 XCheckRefreshWindows(display,windows);
8467 flags=ParseGeometry(degrees,&geometry_info);
8468 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8469 if (swirl_image != (Image *) NULL)
8470 {
8471 *image=DestroyImage(*image);
8472 *image=swirl_image;
8473 }
8474 CatchException(&(*image)->exception);
8475 XSetCursorState(display,windows,MagickFalse);
8476 if (windows->image.orphan != MagickFalse)
8477 break;
8478 XConfigureImageColormap(display,resource_info,windows,*image);
8479 (void) XConfigureImage(display,resource_info,windows,*image);
8480 break;
8481 }
8482 case ImplodeCommand:
8483 {
8484 Image
8485 *implode_image;
8486
8487 static char
8488 factor[MaxTextExtent] = "0.3";
8489
8490 /*
8491 Query user for implode factor.
8492 */
8493 (void) XDialogWidget(display,windows,"Implode",
8494 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8495 if (*factor == '\0')
8496 break;
8497 /*
8498 Implode image pixels about the center.
8499 */
8500 XSetCursorState(display,windows,MagickTrue);
8501 XCheckRefreshWindows(display,windows);
8502 flags=ParseGeometry(factor,&geometry_info);
8503 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8504 if (implode_image != (Image *) NULL)
8505 {
8506 *image=DestroyImage(*image);
8507 *image=implode_image;
8508 }
8509 CatchException(&(*image)->exception);
8510 XSetCursorState(display,windows,MagickFalse);
8511 if (windows->image.orphan != MagickFalse)
8512 break;
8513 XConfigureImageColormap(display,resource_info,windows,*image);
8514 (void) XConfigureImage(display,resource_info,windows,*image);
8515 break;
8516 }
8517 case VignetteCommand:
8518 {
8519 Image
8520 *vignette_image;
8521
8522 static char
8523 geometry[MaxTextExtent] = "0x20";
8524
8525 /*
8526 Query user for the vignette geometry.
8527 */
8528 (void) XDialogWidget(display,windows,"Vignette",
8529 "Enter the radius, sigma, and x and y offsets:",geometry);
8530 if (*geometry == '\0')
8531 break;
8532 /*
8533 Soften the edges of the image in vignette style
8534 */
8535 XSetCursorState(display,windows,MagickTrue);
8536 XCheckRefreshWindows(display,windows);
8537 flags=ParseGeometry(geometry,&geometry_info);
8538 if ((flags & SigmaValue) == 0)
8539 geometry_info.sigma=1.0;
8540 if ((flags & XiValue) == 0)
8541 geometry_info.xi=0.1*(*image)->columns;
8542 if ((flags & PsiValue) == 0)
8543 geometry_info.psi=0.1*(*image)->rows;
8544 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8545 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8546 0.5),&(*image)->exception);
8547 if (vignette_image != (Image *) NULL)
8548 {
8549 *image=DestroyImage(*image);
8550 *image=vignette_image;
8551 }
8552 CatchException(&(*image)->exception);
8553 XSetCursorState(display,windows,MagickFalse);
8554 if (windows->image.orphan != MagickFalse)
8555 break;
8556 XConfigureImageColormap(display,resource_info,windows,*image);
8557 (void) XConfigureImage(display,resource_info,windows,*image);
8558 break;
8559 }
8560 case WaveCommand:
8561 {
8562 Image
8563 *wave_image;
8564
8565 static char
8566 geometry[MaxTextExtent] = "25x150";
8567
8568 /*
8569 Query user for the wave geometry.
8570 */
8571 (void) XDialogWidget(display,windows,"Wave",
8572 "Enter the amplitude and length of the wave:",geometry);
8573 if (*geometry == '\0')
8574 break;
8575 /*
8576 Alter an image along a sine wave.
8577 */
8578 XSetCursorState(display,windows,MagickTrue);
8579 XCheckRefreshWindows(display,windows);
8580 flags=ParseGeometry(geometry,&geometry_info);
8581 if ((flags & SigmaValue) == 0)
8582 geometry_info.sigma=1.0;
8583 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8584 &(*image)->exception);
8585 if (wave_image != (Image *) NULL)
8586 {
8587 *image=DestroyImage(*image);
8588 *image=wave_image;
8589 }
8590 CatchException(&(*image)->exception);
8591 XSetCursorState(display,windows,MagickFalse);
8592 if (windows->image.orphan != MagickFalse)
8593 break;
8594 XConfigureImageColormap(display,resource_info,windows,*image);
8595 (void) XConfigureImage(display,resource_info,windows,*image);
8596 break;
8597 }
8598 case OilPaintCommand:
8599 {
8600 Image
8601 *paint_image;
8602
8603 static char
8604 radius[MaxTextExtent] = "0";
8605
8606 /*
8607 Query user for circular neighborhood radius.
8608 */
8609 (void) XDialogWidget(display,windows,"Oil Paint",
8610 "Enter the mask radius:",radius);
8611 if (*radius == '\0')
8612 break;
8613 /*
8614 OilPaint image scanlines.
8615 */
8616 XSetCursorState(display,windows,MagickTrue);
8617 XCheckRefreshWindows(display,windows);
8618 flags=ParseGeometry(radius,&geometry_info);
8619 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8620 if (paint_image != (Image *) NULL)
8621 {
8622 *image=DestroyImage(*image);
8623 *image=paint_image;
8624 }
8625 CatchException(&(*image)->exception);
8626 XSetCursorState(display,windows,MagickFalse);
8627 if (windows->image.orphan != MagickFalse)
8628 break;
8629 XConfigureImageColormap(display,resource_info,windows,*image);
8630 (void) XConfigureImage(display,resource_info,windows,*image);
8631 break;
8632 }
8633 case CharcoalDrawCommand:
8634 {
8635 Image
8636 *charcoal_image;
8637
8638 static char
8639 radius[MaxTextExtent] = "0x1";
8640
8641 /*
8642 Query user for charcoal radius.
8643 */
8644 (void) XDialogWidget(display,windows,"Charcoal Draw",
8645 "Enter the charcoal radius and sigma:",radius);
8646 if (*radius == '\0')
8647 break;
8648 /*
8649 Charcoal the image.
8650 */
8651 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8652 XSetCursorState(display,windows,MagickTrue);
8653 XCheckRefreshWindows(display,windows);
8654 flags=ParseGeometry(radius,&geometry_info);
8655 if ((flags & SigmaValue) == 0)
8656 geometry_info.sigma=geometry_info.rho;
8657 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8658 &(*image)->exception);
8659 if (charcoal_image != (Image *) NULL)
8660 {
8661 *image=DestroyImage(*image);
8662 *image=charcoal_image;
8663 }
8664 CatchException(&(*image)->exception);
8665 XSetCursorState(display,windows,MagickFalse);
8666 if (windows->image.orphan != MagickFalse)
8667 break;
8668 XConfigureImageColormap(display,resource_info,windows,*image);
8669 (void) XConfigureImage(display,resource_info,windows,*image);
8670 break;
8671 }
8672 case AnnotateCommand:
8673 {
8674 /*
8675 Annotate the image with text.
8676 */
8677 status=XAnnotateEditImage(display,resource_info,windows,*image);
8678 if (status == MagickFalse)
8679 {
8680 XNoticeWidget(display,windows,"Unable to annotate X image",
8681 (*image)->filename);
8682 break;
8683 }
8684 break;
8685 }
8686 case DrawCommand:
8687 {
8688 /*
8689 Draw image.
8690 */
8691 status=XDrawEditImage(display,resource_info,windows,image);
8692 if (status == MagickFalse)
8693 {
8694 XNoticeWidget(display,windows,"Unable to draw on the X image",
8695 (*image)->filename);
8696 break;
8697 }
8698 break;
8699 }
8700 case ColorCommand:
8701 {
8702 /*
8703 Color edit.
8704 */
8705 status=XColorEditImage(display,resource_info,windows,image);
8706 if (status == MagickFalse)
8707 {
8708 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8709 (*image)->filename);
8710 break;
8711 }
8712 break;
8713 }
8714 case MatteCommand:
8715 {
8716 /*
8717 Matte edit.
8718 */
8719 status=XMatteEditImage(display,resource_info,windows,image);
8720 if (status == MagickFalse)
8721 {
8722 XNoticeWidget(display,windows,"Unable to matte edit X image",
8723 (*image)->filename);
8724 break;
8725 }
8726 break;
8727 }
8728 case CompositeCommand:
8729 {
8730 /*
8731 Composite image.
8732 */
8733 status=XCompositeImage(display,resource_info,windows,*image);
8734 if (status == MagickFalse)
8735 {
8736 XNoticeWidget(display,windows,"Unable to composite X image",
8737 (*image)->filename);
8738 break;
8739 }
8740 break;
8741 }
8742 case AddBorderCommand:
8743 {
8744 Image
8745 *border_image;
8746
8747 static char
8748 geometry[MaxTextExtent] = "6x6";
8749
8750 /*
8751 Query user for border color and geometry.
8752 */
8753 XColorBrowserWidget(display,windows,"Select",color);
8754 if (*color == '\0')
8755 break;
8756 (void) XDialogWidget(display,windows,"Add Border",
8757 "Enter border geometry:",geometry);
8758 if (*geometry == '\0')
8759 break;
8760 /*
8761 Add a border to the image.
8762 */
8763 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8764 XSetCursorState(display,windows,MagickTrue);
8765 XCheckRefreshWindows(display,windows);
8766 (void) QueryColorDatabase(color,&(*image)->border_color,
8767 &(*image)->exception);
8768 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8769 &(*image)->exception);
8770 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8771 if (border_image != (Image *) NULL)
8772 {
8773 *image=DestroyImage(*image);
8774 *image=border_image;
8775 }
8776 CatchException(&(*image)->exception);
8777 XSetCursorState(display,windows,MagickFalse);
8778 if (windows->image.orphan != MagickFalse)
8779 break;
8780 windows->image.window_changes.width=(int) (*image)->columns;
8781 windows->image.window_changes.height=(int) (*image)->rows;
8782 XConfigureImageColormap(display,resource_info,windows,*image);
8783 (void) XConfigureImage(display,resource_info,windows,*image);
8784 break;
8785 }
8786 case AddFrameCommand:
8787 {
8788 FrameInfo
8789 frame_info;
8790
8791 Image
8792 *frame_image;
8793
8794 static char
8795 geometry[MaxTextExtent] = "6x6";
8796
8797 /*
8798 Query user for frame color and geometry.
8799 */
8800 XColorBrowserWidget(display,windows,"Select",color);
8801 if (*color == '\0')
8802 break;
8803 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8804 geometry);
8805 if (*geometry == '\0')
8806 break;
8807 /*
8808 Surround image with an ornamental border.
8809 */
8810 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8811 XSetCursorState(display,windows,MagickTrue);
8812 XCheckRefreshWindows(display,windows);
8813 (void) QueryColorDatabase(color,&(*image)->matte_color,
8814 &(*image)->exception);
8815 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8816 &(*image)->exception);
8817 frame_info.width=page_geometry.width;
8818 frame_info.height=page_geometry.height;
8819 frame_info.outer_bevel=page_geometry.x;
8820 frame_info.inner_bevel=page_geometry.y;
8821 frame_info.x=(ssize_t) frame_info.width;
8822 frame_info.y=(ssize_t) frame_info.height;
8823 frame_info.width=(*image)->columns+2*frame_info.width;
8824 frame_info.height=(*image)->rows+2*frame_info.height;
8825 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8826 if (frame_image != (Image *) NULL)
8827 {
8828 *image=DestroyImage(*image);
8829 *image=frame_image;
8830 }
8831 CatchException(&(*image)->exception);
8832 XSetCursorState(display,windows,MagickFalse);
8833 if (windows->image.orphan != MagickFalse)
8834 break;
8835 windows->image.window_changes.width=(int) (*image)->columns;
8836 windows->image.window_changes.height=(int) (*image)->rows;
8837 XConfigureImageColormap(display,resource_info,windows,*image);
8838 (void) XConfigureImage(display,resource_info,windows,*image);
8839 break;
8840 }
8841 case CommentCommand:
8842 {
8843 const char
8844 *value;
8845
8846 FILE
8847 *file;
8848
8849 int
8850 unique_file;
8851
8852 /*
8853 Edit image comment.
8854 */
8855 unique_file=AcquireUniqueFileResource(image_info->filename);
8856 if (unique_file == -1)
8857 XNoticeWidget(display,windows,"Unable to edit image comment",
8858 image_info->filename);
8859 value=GetImageProperty(*image,"comment");
8860 if (value == (char *) NULL)
8861 unique_file=close(unique_file)-1;
8862 else
8863 {
8864 const char
8865 *p;
8866
8867 file=fdopen(unique_file,"w");
8868 if (file == (FILE *) NULL)
8869 {
8870 XNoticeWidget(display,windows,"Unable to edit image comment",
8871 image_info->filename);
8872 break;
8873 }
8874 for (p=value; *p != '\0'; p++)
8875 (void) fputc((int) *p,file);
8876 (void) fputc('\n',file);
8877 (void) fclose(file);
8878 }
8879 XSetCursorState(display,windows,MagickTrue);
8880 XCheckRefreshWindows(display,windows);
8881 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8882 &(*image)->exception);
8883 if (status == MagickFalse)
8884 XNoticeWidget(display,windows,"Unable to edit image comment",
8885 (char *) NULL);
8886 else
8887 {
8888 char
8889 *comment;
8890
8891 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8892 if (comment != (char *) NULL)
8893 {
8894 (void) SetImageProperty(*image,"comment",comment);
8895 (*image)->taint=MagickTrue;
8896 }
8897 }
8898 (void) RelinquishUniqueFileResource(image_info->filename);
8899 XSetCursorState(display,windows,MagickFalse);
8900 break;
8901 }
8902 case LaunchCommand:
8903 {
8904 /*
8905 Launch program.
8906 */
8907 XSetCursorState(display,windows,MagickTrue);
8908 XCheckRefreshWindows(display,windows);
8909 (void) AcquireUniqueFilename(filename);
8910 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
8911 filename);
8912 status=WriteImage(image_info,*image);
8913 if (status == MagickFalse)
8914 XNoticeWidget(display,windows,"Unable to launch image editor",
8915 (char *) NULL);
8916 else
8917 {
8918 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8919 CatchException(&(*image)->exception);
8920 XClientMessage(display,windows->image.id,windows->im_protocols,
8921 windows->im_next_image,CurrentTime);
8922 }
8923 (void) RelinquishUniqueFileResource(filename);
8924 XSetCursorState(display,windows,MagickFalse);
8925 break;
8926 }
8927 case RegionofInterestCommand:
8928 {
8929 /*
8930 Apply an image processing technique to a region of interest.
8931 */
8932 (void) XROIImage(display,resource_info,windows,image);
8933 break;
8934 }
8935 case InfoCommand:
8936 break;
8937 case ZoomCommand:
8938 {
8939 /*
8940 Zoom image.
8941 */
8942 if (windows->magnify.mapped != MagickFalse)
8943 (void) XRaiseWindow(display,windows->magnify.id);
8944 else
8945 {
8946 /*
8947 Make magnify image.
8948 */
8949 XSetCursorState(display,windows,MagickTrue);
8950 (void) XMapRaised(display,windows->magnify.id);
8951 XSetCursorState(display,windows,MagickFalse);
8952 }
8953 break;
8954 }
8955 case ShowPreviewCommand:
8956 {
8957 char
8958 **previews;
8959
8960 Image
8961 *preview_image;
8962
8963 static char
8964 preview_type[MaxTextExtent] = "Gamma";
8965
8966 /*
8967 Select preview type from menu.
8968 */
8969 previews=GetCommandOptions(MagickPreviewOptions);
8970 if (previews == (char **) NULL)
8971 break;
8972 XListBrowserWidget(display,windows,&windows->widget,
8973 (const char **) previews,"Preview",
8974 "Select an enhancement, effect, or F/X:",preview_type);
8975 previews=DestroyStringList(previews);
8976 if (*preview_type == '\0')
8977 break;
8978 /*
8979 Show image preview.
8980 */
8981 XSetCursorState(display,windows,MagickTrue);
8982 XCheckRefreshWindows(display,windows);
8983 image_info->preview_type=(PreviewType)
8984 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
8985 image_info->group=(ssize_t) windows->image.id;
8986 (void) DeleteImageProperty(*image,"label");
8987 (void) SetImageProperty(*image,"label","Preview");
8988 (void) AcquireUniqueFilename(filename);
8989 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
8990 filename);
8991 status=WriteImage(image_info,*image);
8992 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
8993 preview_image=ReadImage(image_info,&(*image)->exception);
8994 (void) RelinquishUniqueFileResource(filename);
8995 if (preview_image == (Image *) NULL)
8996 break;
8997 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
8998 filename);
8999 status=WriteImage(image_info,preview_image);
9000 preview_image=DestroyImage(preview_image);
9001 if (status == MagickFalse)
9002 XNoticeWidget(display,windows,"Unable to show image preview",
9003 (*image)->filename);
9004 XDelay(display,1500);
9005 XSetCursorState(display,windows,MagickFalse);
9006 break;
9007 }
9008 case ShowHistogramCommand:
9009 {
9010 Image
9011 *histogram_image;
9012
9013 /*
9014 Show image histogram.
9015 */
9016 XSetCursorState(display,windows,MagickTrue);
9017 XCheckRefreshWindows(display,windows);
9018 image_info->group=(ssize_t) windows->image.id;
9019 (void) DeleteImageProperty(*image,"label");
9020 (void) SetImageProperty(*image,"label","Histogram");
9021 (void) AcquireUniqueFilename(filename);
9022 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
9023 filename);
9024 status=WriteImage(image_info,*image);
9025 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9026 histogram_image=ReadImage(image_info,&(*image)->exception);
9027 (void) RelinquishUniqueFileResource(filename);
9028 if (histogram_image == (Image *) NULL)
9029 break;
9030 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
9031 "show:%s",filename);
9032 status=WriteImage(image_info,histogram_image);
9033 histogram_image=DestroyImage(histogram_image);
9034 if (status == MagickFalse)
9035 XNoticeWidget(display,windows,"Unable to show histogram",
9036 (*image)->filename);
9037 XDelay(display,1500);
9038 XSetCursorState(display,windows,MagickFalse);
9039 break;
9040 }
9041 case ShowMatteCommand:
9042 {
9043 Image
9044 *matte_image;
9045
9046 if ((*image)->matte == MagickFalse)
9047 {
9048 XNoticeWidget(display,windows,
9049 "Image does not have any matte information",(*image)->filename);
9050 break;
9051 }
9052 /*
9053 Show image matte.
9054 */
9055 XSetCursorState(display,windows,MagickTrue);
9056 XCheckRefreshWindows(display,windows);
9057 image_info->group=(ssize_t) windows->image.id;
9058 (void) DeleteImageProperty(*image,"label");
9059 (void) SetImageProperty(*image,"label","Matte");
9060 (void) AcquireUniqueFilename(filename);
9061 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
9062 filename);
9063 status=WriteImage(image_info,*image);
9064 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9065 matte_image=ReadImage(image_info,&(*image)->exception);
9066 (void) RelinquishUniqueFileResource(filename);
9067 if (matte_image == (Image *) NULL)
9068 break;
9069 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
9070 filename);
9071 status=WriteImage(image_info,matte_image);
9072 matte_image=DestroyImage(matte_image);
9073 if (status == MagickFalse)
9074 XNoticeWidget(display,windows,"Unable to show matte",
9075 (*image)->filename);
9076 XDelay(display,1500);
9077 XSetCursorState(display,windows,MagickFalse);
9078 break;
9079 }
9080 case BackgroundCommand:
9081 {
9082 /*
9083 Background image.
9084 */
9085 status=XBackgroundImage(display,resource_info,windows,image);
9086 if (status == MagickFalse)
9087 break;
9088 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9089 if (nexus != (Image *) NULL)
9090 XClientMessage(display,windows->image.id,windows->im_protocols,
9091 windows->im_next_image,CurrentTime);
9092 break;
9093 }
9094 case SlideShowCommand:
9095 {
9096 static char
9097 delay[MaxTextExtent] = "5";
9098
9099 /*
9100 Display next image after pausing.
9101 */
9102 (void) XDialogWidget(display,windows,"Slide Show",
9103 "Pause how many 1/100ths of a second between images:",delay);
9104 if (*delay == '\0')
9105 break;
9106 resource_info->delay=StringToUnsignedLong(delay);
9107 XClientMessage(display,windows->image.id,windows->im_protocols,
9108 windows->im_next_image,CurrentTime);
9109 break;
9110 }
9111 case PreferencesCommand:
9112 {
9113 /*
9114 Set user preferences.
9115 */
9116 status=XPreferencesWidget(display,resource_info,windows);
9117 if (status == MagickFalse)
9118 break;
9119 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9120 if (nexus != (Image *) NULL)
9121 XClientMessage(display,windows->image.id,windows->im_protocols,
9122 windows->im_next_image,CurrentTime);
9123 break;
9124 }
9125 case HelpCommand:
9126 {
9127 /*
9128 User requested help.
9129 */
9130 XTextViewHelp(display,resource_info,windows,MagickFalse,
9131 "Help Viewer - Display",DisplayHelp);
9132 break;
9133 }
9134 case BrowseDocumentationCommand:
9135 {
9136 Atom
9137 mozilla_atom;
9138
9139 Window
9140 mozilla_window,
9141 root_window;
9142
9143 /*
9144 Browse the ImageMagick documentation.
9145 */
9146 root_window=XRootWindow(display,XDefaultScreen(display));
9147 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9148 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9149 if (mozilla_window != (Window) NULL)
9150 {
9151 char
9152 command[MaxTextExtent];
9153
9154 /*
9155 Display documentation using Netscape remote control.
9156 */
9157 (void) FormatLocaleString(command,MaxTextExtent,
9158 "openurl(%s,new-tab)",MagickAuthoritativeURL);
9159 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9160 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9161 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9162 XSetCursorState(display,windows,MagickFalse);
9163 break;
9164 }
9165 XSetCursorState(display,windows,MagickTrue);
9166 XCheckRefreshWindows(display,windows);
9167 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9168 &(*image)->exception);
9169 if (status == MagickFalse)
9170 XNoticeWidget(display,windows,"Unable to browse documentation",
9171 (char *) NULL);
9172 XDelay(display,1500);
9173 XSetCursorState(display,windows,MagickFalse);
9174 break;
9175 }
9176 case VersionCommand:
9177 {
9178 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9179 GetMagickCopyright());
9180 break;
9181 }
9182 case SaveToUndoBufferCommand:
9183 break;
9184 default:
9185 {
9186 (void) XBell(display,0);
9187 break;
9188 }
9189 }
9190 image_info=DestroyImageInfo(image_info);
9191 return(nexus);
9192 }
9193
9194 /*
9195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9196 % %
9197 % %
9198 % %
9199 + X M a g n i f y I m a g e %
9200 % %
9201 % %
9202 % %
9203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9204 %
9205 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9206 % The magnified portion is displayed in a separate window.
9207 %
9208 % The format of the XMagnifyImage method is:
9209 %
9210 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9211 %
9212 % A description of each parameter follows:
9213 %
9214 % o display: Specifies a connection to an X server; returned from
9215 % XOpenDisplay.
9216 %
9217 % o windows: Specifies a pointer to a XWindows structure.
9218 %
9219 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9220 % the entire image is refreshed.
9221 %
9222 */
XMagnifyImage(Display * display,XWindows * windows,XEvent * event)9223 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9224 {
9225 char
9226 text[MaxTextExtent];
9227
9228 int
9229 x,
9230 y;
9231
9232 size_t
9233 state;
9234
9235 /*
9236 Update magnified image until the mouse button is released.
9237 */
9238 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9239 state=DefaultState;
9240 x=event->xbutton.x;
9241 y=event->xbutton.y;
9242 windows->magnify.x=(int) windows->image.x+x;
9243 windows->magnify.y=(int) windows->image.y+y;
9244 do
9245 {
9246 /*
9247 Map and unmap Info widget as text cursor crosses its boundaries.
9248 */
9249 if (windows->info.mapped != MagickFalse)
9250 {
9251 if ((x < (int) (windows->info.x+windows->info.width)) &&
9252 (y < (int) (windows->info.y+windows->info.height)))
9253 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9254 }
9255 else
9256 if ((x > (int) (windows->info.x+windows->info.width)) ||
9257 (y > (int) (windows->info.y+windows->info.height)))
9258 (void) XMapWindow(display,windows->info.id);
9259 if (windows->info.mapped != MagickFalse)
9260 {
9261 /*
9262 Display pointer position.
9263 */
9264 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9265 windows->magnify.x,windows->magnify.y);
9266 XInfoWidget(display,windows,text);
9267 }
9268 /*
9269 Wait for next event.
9270 */
9271 XScreenEvent(display,windows,event);
9272 switch (event->type)
9273 {
9274 case ButtonPress:
9275 break;
9276 case ButtonRelease:
9277 {
9278 /*
9279 User has finished magnifying image.
9280 */
9281 x=event->xbutton.x;
9282 y=event->xbutton.y;
9283 state|=ExitState;
9284 break;
9285 }
9286 case Expose:
9287 break;
9288 case MotionNotify:
9289 {
9290 x=event->xmotion.x;
9291 y=event->xmotion.y;
9292 break;
9293 }
9294 default:
9295 break;
9296 }
9297 /*
9298 Check boundary conditions.
9299 */
9300 if (x < 0)
9301 x=0;
9302 else
9303 if (x >= (int) windows->image.width)
9304 x=(int) windows->image.width-1;
9305 if (y < 0)
9306 y=0;
9307 else
9308 if (y >= (int) windows->image.height)
9309 y=(int) windows->image.height-1;
9310 } while ((state & ExitState) == 0);
9311 /*
9312 Display magnified image.
9313 */
9314 XSetCursorState(display,windows,MagickFalse);
9315 }
9316
9317 /*
9318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9319 % %
9320 % %
9321 % %
9322 + X M a g n i f y W i n d o w C o m m a n d %
9323 % %
9324 % %
9325 % %
9326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9327 %
9328 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9329 % pixel as specified by the key symbol.
9330 %
9331 % The format of the XMagnifyWindowCommand method is:
9332 %
9333 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9334 % const MagickStatusType state,const KeySym key_symbol)
9335 %
9336 % A description of each parameter follows:
9337 %
9338 % o display: Specifies a connection to an X server; returned from
9339 % XOpenDisplay.
9340 %
9341 % o windows: Specifies a pointer to a XWindows structure.
9342 %
9343 % o state: key mask.
9344 %
9345 % o key_symbol: Specifies a KeySym which indicates which side of the image
9346 % to trim.
9347 %
9348 */
XMagnifyWindowCommand(Display * display,XWindows * windows,const MagickStatusType state,const KeySym key_symbol)9349 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9350 const MagickStatusType state,const KeySym key_symbol)
9351 {
9352 unsigned int
9353 quantum;
9354
9355 /*
9356 User specified a magnify factor or position.
9357 */
9358 quantum=1;
9359 if ((state & Mod1Mask) != 0)
9360 quantum=10;
9361 switch ((int) key_symbol)
9362 {
9363 case QuitCommand:
9364 {
9365 (void) XWithdrawWindow(display,windows->magnify.id,
9366 windows->magnify.screen);
9367 break;
9368 }
9369 case XK_Home:
9370 case XK_KP_Home:
9371 {
9372 windows->magnify.x=(int) windows->image.width/2;
9373 windows->magnify.y=(int) windows->image.height/2;
9374 break;
9375 }
9376 case XK_Left:
9377 case XK_KP_Left:
9378 {
9379 if (windows->magnify.x > 0)
9380 windows->magnify.x-=quantum;
9381 break;
9382 }
9383 case XK_Up:
9384 case XK_KP_Up:
9385 {
9386 if (windows->magnify.y > 0)
9387 windows->magnify.y-=quantum;
9388 break;
9389 }
9390 case XK_Right:
9391 case XK_KP_Right:
9392 {
9393 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9394 windows->magnify.x+=quantum;
9395 break;
9396 }
9397 case XK_Down:
9398 case XK_KP_Down:
9399 {
9400 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9401 windows->magnify.y+=quantum;
9402 break;
9403 }
9404 case XK_0:
9405 case XK_1:
9406 case XK_2:
9407 case XK_3:
9408 case XK_4:
9409 case XK_5:
9410 case XK_6:
9411 case XK_7:
9412 case XK_8:
9413 case XK_9:
9414 {
9415 windows->magnify.data=(key_symbol-XK_0);
9416 break;
9417 }
9418 case XK_KP_0:
9419 case XK_KP_1:
9420 case XK_KP_2:
9421 case XK_KP_3:
9422 case XK_KP_4:
9423 case XK_KP_5:
9424 case XK_KP_6:
9425 case XK_KP_7:
9426 case XK_KP_8:
9427 case XK_KP_9:
9428 {
9429 windows->magnify.data=(key_symbol-XK_KP_0);
9430 break;
9431 }
9432 default:
9433 break;
9434 }
9435 XMakeMagnifyImage(display,windows);
9436 }
9437
9438 /*
9439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9440 % %
9441 % %
9442 % %
9443 + X M a k e P a n I m a g e %
9444 % %
9445 % %
9446 % %
9447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9448 %
9449 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9450 % icon window.
9451 %
9452 % The format of the XMakePanImage method is:
9453 %
9454 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9455 % XWindows *windows,Image *image)
9456 %
9457 % A description of each parameter follows:
9458 %
9459 % o display: Specifies a connection to an X server; returned from
9460 % XOpenDisplay.
9461 %
9462 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9463 %
9464 % o windows: Specifies a pointer to a XWindows structure.
9465 %
9466 % o image: the image.
9467 %
9468 */
XMakePanImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)9469 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9470 XWindows *windows,Image *image)
9471 {
9472 MagickStatusType
9473 status;
9474
9475 /*
9476 Create and display image for panning icon.
9477 */
9478 XSetCursorState(display,windows,MagickTrue);
9479 XCheckRefreshWindows(display,windows);
9480 windows->pan.x=(int) windows->image.x;
9481 windows->pan.y=(int) windows->image.y;
9482 status=XMakeImage(display,resource_info,&windows->pan,image,
9483 windows->pan.width,windows->pan.height);
9484 if (status == MagickFalse)
9485 ThrowXWindowFatalException(XServerFatalError,image->exception.reason,
9486 image->exception.description);
9487 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9488 windows->pan.pixmap);
9489 (void) XClearWindow(display,windows->pan.id);
9490 XDrawPanRectangle(display,windows);
9491 XSetCursorState(display,windows,MagickFalse);
9492 }
9493
9494 /*
9495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9496 % %
9497 % %
9498 % %
9499 + X M a t t a E d i t I m a g e %
9500 % %
9501 % %
9502 % %
9503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9504 %
9505 % XMatteEditImage() allows the user to interactively change the Matte channel
9506 % of an image. If the image is PseudoClass it is promoted to DirectClass
9507 % before the matte information is stored.
9508 %
9509 % The format of the XMatteEditImage method is:
9510 %
9511 % MagickBooleanType XMatteEditImage(Display *display,
9512 % XResourceInfo *resource_info,XWindows *windows,Image **image)
9513 %
9514 % A description of each parameter follows:
9515 %
9516 % o display: Specifies a connection to an X server; returned from
9517 % XOpenDisplay.
9518 %
9519 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9520 %
9521 % o windows: Specifies a pointer to a XWindows structure.
9522 %
9523 % o image: the image; returned from ReadImage.
9524 %
9525 */
XMatteEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)9526 static MagickBooleanType XMatteEditImage(Display *display,
9527 XResourceInfo *resource_info,XWindows *windows,Image **image)
9528 {
9529 const char
9530 *const MatteEditMenu[] =
9531 {
9532 "Method",
9533 "Border Color",
9534 "Fuzz",
9535 "Matte Value",
9536 "Undo",
9537 "Help",
9538 "Dismiss",
9539 (char *) NULL
9540 };
9541
9542 static char
9543 matte[MaxTextExtent] = "0";
9544
9545 static const ModeType
9546 MatteEditCommands[] =
9547 {
9548 MatteEditMethod,
9549 MatteEditBorderCommand,
9550 MatteEditFuzzCommand,
9551 MatteEditValueCommand,
9552 MatteEditUndoCommand,
9553 MatteEditHelpCommand,
9554 MatteEditDismissCommand
9555 };
9556
9557 static PaintMethod
9558 method = PointMethod;
9559
9560 static XColor
9561 border_color = { 0, 0, 0, 0, 0, 0 };
9562
9563 char
9564 command[MaxTextExtent],
9565 text[MaxTextExtent];
9566
9567 Cursor
9568 cursor;
9569
9570 int
9571 entry,
9572 id,
9573 x,
9574 x_offset,
9575 y,
9576 y_offset;
9577
9578 int
9579 i;
9580
9581 PixelPacket
9582 *q;
9583
9584 unsigned int
9585 height,
9586 width;
9587
9588 size_t
9589 state;
9590
9591 XEvent
9592 event;
9593
9594 /*
9595 Map Command widget.
9596 */
9597 (void) CloneString(&windows->command.name,"Matte Edit");
9598 windows->command.data=4;
9599 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9600 (void) XMapRaised(display,windows->command.id);
9601 XClientMessage(display,windows->image.id,windows->im_protocols,
9602 windows->im_update_widget,CurrentTime);
9603 /*
9604 Make cursor.
9605 */
9606 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9607 resource_info->background_color,resource_info->foreground_color);
9608 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9609 /*
9610 Track pointer until button 1 is pressed.
9611 */
9612 XQueryPosition(display,windows->image.id,&x,&y);
9613 (void) XSelectInput(display,windows->image.id,
9614 windows->image.attributes.event_mask | PointerMotionMask);
9615 state=DefaultState;
9616 do
9617 {
9618 if (windows->info.mapped != MagickFalse)
9619 {
9620 /*
9621 Display pointer position.
9622 */
9623 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9624 x+windows->image.x,y+windows->image.y);
9625 XInfoWidget(display,windows,text);
9626 }
9627 /*
9628 Wait for next event.
9629 */
9630 XScreenEvent(display,windows,&event);
9631 if (event.xany.window == windows->command.id)
9632 {
9633 /*
9634 Select a command from the Command widget.
9635 */
9636 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9637 if (id < 0)
9638 {
9639 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9640 continue;
9641 }
9642 switch (MatteEditCommands[id])
9643 {
9644 case MatteEditMethod:
9645 {
9646 char
9647 **methods;
9648
9649 /*
9650 Select a method from the pop-up menu.
9651 */
9652 methods=GetCommandOptions(MagickMethodOptions);
9653 if (methods == (char **) NULL)
9654 break;
9655 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9656 (const char **) methods,command);
9657 if (entry >= 0)
9658 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9659 MagickFalse,methods[entry]);
9660 methods=DestroyStringList(methods);
9661 break;
9662 }
9663 case MatteEditBorderCommand:
9664 {
9665 const char
9666 *ColorMenu[MaxNumberPens];
9667
9668 int
9669 pen_number;
9670
9671 /*
9672 Initialize menu selections.
9673 */
9674 for (i=0; i < (int) (MaxNumberPens-2); i++)
9675 ColorMenu[i]=resource_info->pen_colors[i];
9676 ColorMenu[MaxNumberPens-2]="Browser...";
9677 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9678 /*
9679 Select a pen color from the pop-up menu.
9680 */
9681 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9682 (const char **) ColorMenu,command);
9683 if (pen_number < 0)
9684 break;
9685 if (pen_number == (MaxNumberPens-2))
9686 {
9687 static char
9688 color_name[MaxTextExtent] = "gray";
9689
9690 /*
9691 Select a pen color from a dialog.
9692 */
9693 resource_info->pen_colors[pen_number]=color_name;
9694 XColorBrowserWidget(display,windows,"Select",color_name);
9695 if (*color_name == '\0')
9696 break;
9697 }
9698 /*
9699 Set border color.
9700 */
9701 (void) XParseColor(display,windows->map_info->colormap,
9702 resource_info->pen_colors[pen_number],&border_color);
9703 break;
9704 }
9705 case MatteEditFuzzCommand:
9706 {
9707 const char
9708 *const FuzzMenu[] =
9709 {
9710 "0%",
9711 "2%",
9712 "5%",
9713 "10%",
9714 "15%",
9715 "Dialog...",
9716 (char *) NULL,
9717 };
9718
9719 static char
9720 fuzz[MaxTextExtent];
9721
9722 /*
9723 Select a command from the pop-up menu.
9724 */
9725 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9726 command);
9727 if (entry < 0)
9728 break;
9729 if (entry != 5)
9730 {
9731 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9732 QuantumRange+1.0);
9733 break;
9734 }
9735 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9736 (void) XDialogWidget(display,windows,"Ok",
9737 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9738 if (*fuzz == '\0')
9739 break;
9740 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9741 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9742 1.0);
9743 break;
9744 }
9745 case MatteEditValueCommand:
9746 {
9747 const char
9748 *const MatteMenu[] =
9749 {
9750 "Opaque",
9751 "Transparent",
9752 "Dialog...",
9753 (char *) NULL,
9754 };
9755
9756 static char
9757 message[MaxTextExtent];
9758
9759 /*
9760 Select a command from the pop-up menu.
9761 */
9762 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9763 command);
9764 if (entry < 0)
9765 break;
9766 if (entry != 2)
9767 {
9768 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9769 OpaqueOpacity);
9770 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9771 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
9772 (Quantum) TransparentOpacity);
9773 break;
9774 }
9775 (void) FormatLocaleString(message,MaxTextExtent,
9776 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9777 QuantumRange);
9778 (void) XDialogWidget(display,windows,"Matte",message,matte);
9779 if (*matte == '\0')
9780 break;
9781 break;
9782 }
9783 case MatteEditUndoCommand:
9784 {
9785 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9786 image);
9787 break;
9788 }
9789 case MatteEditHelpCommand:
9790 {
9791 XTextViewHelp(display,resource_info,windows,MagickFalse,
9792 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9793 break;
9794 }
9795 case MatteEditDismissCommand:
9796 {
9797 /*
9798 Prematurely exit.
9799 */
9800 state|=EscapeState;
9801 state|=ExitState;
9802 break;
9803 }
9804 default:
9805 break;
9806 }
9807 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9808 continue;
9809 }
9810 switch (event.type)
9811 {
9812 case ButtonPress:
9813 {
9814 if (event.xbutton.button != Button1)
9815 break;
9816 if ((event.xbutton.window != windows->image.id) &&
9817 (event.xbutton.window != windows->magnify.id))
9818 break;
9819 /*
9820 Update matte data.
9821 */
9822 x=event.xbutton.x;
9823 y=event.xbutton.y;
9824 (void) XMagickCommand(display,resource_info,windows,
9825 SaveToUndoBufferCommand,image);
9826 state|=UpdateConfigurationState;
9827 break;
9828 }
9829 case ButtonRelease:
9830 {
9831 if (event.xbutton.button != Button1)
9832 break;
9833 if ((event.xbutton.window != windows->image.id) &&
9834 (event.xbutton.window != windows->magnify.id))
9835 break;
9836 /*
9837 Update colormap information.
9838 */
9839 x=event.xbutton.x;
9840 y=event.xbutton.y;
9841 XConfigureImageColormap(display,resource_info,windows,*image);
9842 (void) XConfigureImage(display,resource_info,windows,*image);
9843 XInfoWidget(display,windows,text);
9844 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9845 state&=(~UpdateConfigurationState);
9846 break;
9847 }
9848 case Expose:
9849 break;
9850 case KeyPress:
9851 {
9852 char
9853 command[MaxTextExtent];
9854
9855 KeySym
9856 key_symbol;
9857
9858 if (event.xkey.window == windows->magnify.id)
9859 {
9860 Window
9861 window;
9862
9863 window=windows->magnify.id;
9864 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9865 }
9866 if (event.xkey.window != windows->image.id)
9867 break;
9868 /*
9869 Respond to a user key press.
9870 */
9871 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9872 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9873 switch ((int) key_symbol)
9874 {
9875 case XK_Escape:
9876 case XK_F20:
9877 {
9878 /*
9879 Prematurely exit.
9880 */
9881 state|=ExitState;
9882 break;
9883 }
9884 case XK_F1:
9885 case XK_Help:
9886 {
9887 XTextViewHelp(display,resource_info,windows,MagickFalse,
9888 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9889 break;
9890 }
9891 default:
9892 {
9893 (void) XBell(display,0);
9894 break;
9895 }
9896 }
9897 break;
9898 }
9899 case MotionNotify:
9900 {
9901 /*
9902 Map and unmap Info widget as cursor crosses its boundaries.
9903 */
9904 x=event.xmotion.x;
9905 y=event.xmotion.y;
9906 if (windows->info.mapped != MagickFalse)
9907 {
9908 if ((x < (int) (windows->info.x+windows->info.width)) &&
9909 (y < (int) (windows->info.y+windows->info.height)))
9910 (void) XWithdrawWindow(display,windows->info.id,
9911 windows->info.screen);
9912 }
9913 else
9914 if ((x > (int) (windows->info.x+windows->info.width)) ||
9915 (y > (int) (windows->info.y+windows->info.height)))
9916 (void) XMapWindow(display,windows->info.id);
9917 break;
9918 }
9919 default:
9920 break;
9921 }
9922 if (event.xany.window == windows->magnify.id)
9923 {
9924 x=windows->magnify.x-windows->image.x;
9925 y=windows->magnify.y-windows->image.y;
9926 }
9927 x_offset=x;
9928 y_offset=y;
9929 if ((state & UpdateConfigurationState) != 0)
9930 {
9931 CacheView
9932 *image_view;
9933
9934 ExceptionInfo
9935 *exception;
9936
9937 int
9938 x,
9939 y;
9940
9941 /*
9942 Matte edit is relative to image configuration.
9943 */
9944 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9945 MagickTrue);
9946 XPutPixel(windows->image.ximage,x_offset,y_offset,
9947 windows->pixel_info->background_color.pixel);
9948 width=(unsigned int) (*image)->columns;
9949 height=(unsigned int) (*image)->rows;
9950 x=0;
9951 y=0;
9952 if (windows->image.crop_geometry != (char *) NULL)
9953 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9954 &width,&height);
9955 x_offset=(int)
9956 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9957 y_offset=(int)
9958 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9959 if ((x_offset < 0) || (y_offset < 0))
9960 continue;
9961 if ((x_offset >= (int) (*image)->columns) ||
9962 (y_offset >= (int) (*image)->rows))
9963 continue;
9964 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9965 return(MagickFalse);
9966 (*image)->matte=MagickTrue;
9967 exception=(&(*image)->exception);
9968 image_view=AcquireAuthenticCacheView(*image,exception);
9969 switch (method)
9970 {
9971 case PointMethod:
9972 default:
9973 {
9974 /*
9975 Update matte information using point algorithm.
9976 */
9977 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
9978 (ssize_t) y_offset,1,1,exception);
9979 if (q == (PixelPacket *) NULL)
9980 break;
9981 q->opacity=(Quantum) StringToLong(matte);
9982 (void) SyncCacheViewAuthenticPixels(image_view,exception);
9983 break;
9984 }
9985 case ReplaceMethod:
9986 {
9987 PixelPacket
9988 target;
9989
9990 /*
9991 Update matte information using replace algorithm.
9992 */
9993 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
9994 (ssize_t) y_offset,&target,exception);
9995 for (y=0; y < (int) (*image)->rows; y++)
9996 {
9997 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
9998 (*image)->columns,1,&(*image)->exception);
9999 if (q == (PixelPacket *) NULL)
10000 break;
10001 for (x=0; x < (int) (*image)->columns; x++)
10002 {
10003 if (IsColorSimilar(*image,q,&target))
10004 q->opacity=(Quantum) StringToLong(matte);
10005 q++;
10006 }
10007 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10008 break;
10009 }
10010 break;
10011 }
10012 case FloodfillMethod:
10013 case FillToBorderMethod:
10014 {
10015 DrawInfo
10016 *draw_info;
10017
10018 MagickPixelPacket
10019 target;
10020
10021 /*
10022 Update matte information using floodfill algorithm.
10023 */
10024 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10025 (ssize_t) y_offset,&target,exception);
10026 if (method == FillToBorderMethod)
10027 {
10028 target.red=(MagickRealType)
10029 ScaleShortToQuantum(border_color.red);
10030 target.green=(MagickRealType)
10031 ScaleShortToQuantum(border_color.green);
10032 target.blue=(MagickRealType)
10033 ScaleShortToQuantum(border_color.blue);
10034 }
10035 draw_info=CloneDrawInfo(resource_info->image_info,
10036 (DrawInfo *) NULL);
10037 draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte,
10038 (char **) NULL));
10039 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10040 (ssize_t) x_offset,(ssize_t) y_offset,
10041 method == FloodfillMethod ? MagickFalse : MagickTrue);
10042 draw_info=DestroyDrawInfo(draw_info);
10043 break;
10044 }
10045 case ResetMethod:
10046 {
10047 /*
10048 Update matte information using reset algorithm.
10049 */
10050 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10051 return(MagickFalse);
10052 for (y=0; y < (int) (*image)->rows; y++)
10053 {
10054 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10055 (*image)->columns,1,exception);
10056 if (q == (PixelPacket *) NULL)
10057 break;
10058 for (x=0; x < (int) (*image)->columns; x++)
10059 {
10060 q->opacity=(Quantum) StringToLong(matte);
10061 q++;
10062 }
10063 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10064 break;
10065 }
10066 if (StringToLong(matte) == OpaqueOpacity)
10067 (*image)->matte=MagickFalse;
10068 break;
10069 }
10070 }
10071 image_view=DestroyCacheView(image_view);
10072 state&=(~UpdateConfigurationState);
10073 }
10074 } while ((state & ExitState) == 0);
10075 (void) XSelectInput(display,windows->image.id,
10076 windows->image.attributes.event_mask);
10077 XSetCursorState(display,windows,MagickFalse);
10078 (void) XFreeCursor(display,cursor);
10079 return(MagickTrue);
10080 }
10081
10082 /*
10083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10084 % %
10085 % %
10086 % %
10087 + X O p e n I m a g e %
10088 % %
10089 % %
10090 % %
10091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10092 %
10093 % XOpenImage() loads an image from a file.
10094 %
10095 % The format of the XOpenImage method is:
10096 %
10097 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10098 % XWindows *windows,const unsigned int command)
10099 %
10100 % A description of each parameter follows:
10101 %
10102 % o display: Specifies a connection to an X server; returned from
10103 % XOpenDisplay.
10104 %
10105 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10106 %
10107 % o windows: Specifies a pointer to a XWindows structure.
10108 %
10109 % o command: A value other than zero indicates that the file is selected
10110 % from the command line argument list.
10111 %
10112 */
XOpenImage(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickBooleanType command)10113 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10114 XWindows *windows,const MagickBooleanType command)
10115 {
10116 const MagickInfo
10117 *magick_info;
10118
10119 ExceptionInfo
10120 *exception;
10121
10122 Image
10123 *nexus;
10124
10125 ImageInfo
10126 *image_info;
10127
10128 static char
10129 filename[MaxTextExtent] = "\0";
10130
10131 /*
10132 Request file name from user.
10133 */
10134 if (command == MagickFalse)
10135 XFileBrowserWidget(display,windows,"Open",filename);
10136 else
10137 {
10138 char
10139 **filelist,
10140 **files;
10141
10142 int
10143 count,
10144 status;
10145
10146 int
10147 i,
10148 j;
10149
10150 /*
10151 Select next image from the command line.
10152 */
10153 status=XGetCommand(display,windows->image.id,&files,&count);
10154 if (status == 0)
10155 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10156 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10157 if (filelist == (char **) NULL)
10158 {
10159 (void) XFreeStringList(files);
10160 ThrowXWindowException(ResourceLimitError,
10161 "MemoryAllocationFailed","...");
10162 return((Image *) NULL);
10163 }
10164 j=0;
10165 for (i=1; i < count; i++)
10166 if (*files[i] != '-')
10167 filelist[j++]=files[i];
10168 filelist[j]=(char *) NULL;
10169 XListBrowserWidget(display,windows,&windows->widget,
10170 (const char **) filelist,"Load","Select Image to Load:",filename);
10171 filelist=(char **) RelinquishMagickMemory(filelist);
10172 (void) XFreeStringList(files);
10173 }
10174 if (*filename == '\0')
10175 return((Image *) NULL);
10176 image_info=CloneImageInfo(resource_info->image_info);
10177 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10178 (void *) NULL);
10179 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10180 exception=AcquireExceptionInfo();
10181 (void) SetImageInfo(image_info,0,exception);
10182 if (LocaleCompare(image_info->magick,"X") == 0)
10183 {
10184 char
10185 seconds[MaxTextExtent];
10186
10187 /*
10188 User may want to delay the X server screen grab.
10189 */
10190 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10191 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10192 seconds);
10193 if (*seconds == '\0')
10194 return((Image *) NULL);
10195 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10196 }
10197 magick_info=GetMagickInfo(image_info->magick,exception);
10198 if ((magick_info != (const MagickInfo *) NULL) &&
10199 (magick_info->raw != MagickFalse))
10200 {
10201 char
10202 geometry[MaxTextExtent];
10203
10204 /*
10205 Request image size from the user.
10206 */
10207 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10208 if (image_info->size != (char *) NULL)
10209 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10210 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10211 geometry);
10212 (void) CloneString(&image_info->size,geometry);
10213 }
10214 /*
10215 Load the image.
10216 */
10217 XSetCursorState(display,windows,MagickTrue);
10218 XCheckRefreshWindows(display,windows);
10219 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10220 nexus=ReadImage(image_info,exception);
10221 CatchException(exception);
10222 XSetCursorState(display,windows,MagickFalse);
10223 if (nexus != (Image *) NULL)
10224 XClientMessage(display,windows->image.id,windows->im_protocols,
10225 windows->im_next_image,CurrentTime);
10226 else
10227 {
10228 char
10229 *text,
10230 **textlist;
10231
10232 /*
10233 Unknown image format.
10234 */
10235 text=FileToString(filename,~0UL,exception);
10236 if (text == (char *) NULL)
10237 return((Image *) NULL);
10238 textlist=StringToList(text);
10239 if (textlist != (char **) NULL)
10240 {
10241 char
10242 title[MaxTextExtent];
10243
10244 int
10245 i;
10246
10247 (void) FormatLocaleString(title,MaxTextExtent,
10248 "Unknown format: %s",filename);
10249 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10250 (const char **) textlist);
10251 for (i=0; textlist[i] != (char *) NULL; i++)
10252 textlist[i]=DestroyString(textlist[i]);
10253 textlist=(char **) RelinquishMagickMemory(textlist);
10254 }
10255 text=DestroyString(text);
10256 }
10257 exception=DestroyExceptionInfo(exception);
10258 image_info=DestroyImageInfo(image_info);
10259 return(nexus);
10260 }
10261
10262 /*
10263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10264 % %
10265 % %
10266 % %
10267 + X P a n I m a g e %
10268 % %
10269 % %
10270 % %
10271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10272 %
10273 % XPanImage() pans the image until the mouse button is released.
10274 %
10275 % The format of the XPanImage method is:
10276 %
10277 % void XPanImage(Display *display,XWindows *windows,XEvent *event)
10278 %
10279 % A description of each parameter follows:
10280 %
10281 % o display: Specifies a connection to an X server; returned from
10282 % XOpenDisplay.
10283 %
10284 % o windows: Specifies a pointer to a XWindows structure.
10285 %
10286 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10287 % the entire image is refreshed.
10288 %
10289 */
XPanImage(Display * display,XWindows * windows,XEvent * event)10290 static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10291 {
10292 char
10293 text[MaxTextExtent];
10294
10295 Cursor
10296 cursor;
10297
10298 MagickRealType
10299 x_factor,
10300 y_factor;
10301
10302 RectangleInfo
10303 pan_info;
10304
10305 size_t
10306 state;
10307
10308 /*
10309 Define cursor.
10310 */
10311 if ((windows->image.ximage->width > (int) windows->image.width) &&
10312 (windows->image.ximage->height > (int) windows->image.height))
10313 cursor=XCreateFontCursor(display,XC_fleur);
10314 else
10315 if (windows->image.ximage->width > (int) windows->image.width)
10316 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10317 else
10318 if (windows->image.ximage->height > (int) windows->image.height)
10319 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10320 else
10321 cursor=XCreateFontCursor(display,XC_arrow);
10322 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10323 /*
10324 Pan image as pointer moves until the mouse button is released.
10325 */
10326 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10327 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10328 pan_info.width=windows->pan.width*windows->image.width/
10329 windows->image.ximage->width;
10330 pan_info.height=windows->pan.height*windows->image.height/
10331 windows->image.ximage->height;
10332 pan_info.x=0;
10333 pan_info.y=0;
10334 state=UpdateConfigurationState;
10335 do
10336 {
10337 switch (event->type)
10338 {
10339 case ButtonPress:
10340 {
10341 /*
10342 User choose an initial pan location.
10343 */
10344 pan_info.x=(ssize_t) event->xbutton.x;
10345 pan_info.y=(ssize_t) event->xbutton.y;
10346 state|=UpdateConfigurationState;
10347 break;
10348 }
10349 case ButtonRelease:
10350 {
10351 /*
10352 User has finished panning the image.
10353 */
10354 pan_info.x=(ssize_t) event->xbutton.x;
10355 pan_info.y=(ssize_t) event->xbutton.y;
10356 state|=UpdateConfigurationState | ExitState;
10357 break;
10358 }
10359 case MotionNotify:
10360 {
10361 pan_info.x=(ssize_t) event->xmotion.x;
10362 pan_info.y=(ssize_t) event->xmotion.y;
10363 state|=UpdateConfigurationState;
10364 }
10365 default:
10366 break;
10367 }
10368 if ((state & UpdateConfigurationState) != 0)
10369 {
10370 /*
10371 Check boundary conditions.
10372 */
10373 if (pan_info.x < (ssize_t) (pan_info.width/2))
10374 pan_info.x=0;
10375 else
10376 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10377 if (pan_info.x < 0)
10378 pan_info.x=0;
10379 else
10380 if ((int) (pan_info.x+windows->image.width) >
10381 windows->image.ximage->width)
10382 pan_info.x=(ssize_t)
10383 (windows->image.ximage->width-windows->image.width);
10384 if (pan_info.y < (ssize_t) (pan_info.height/2))
10385 pan_info.y=0;
10386 else
10387 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10388 if (pan_info.y < 0)
10389 pan_info.y=0;
10390 else
10391 if ((int) (pan_info.y+windows->image.height) >
10392 windows->image.ximage->height)
10393 pan_info.y=(ssize_t)
10394 (windows->image.ximage->height-windows->image.height);
10395 if ((windows->image.x != (int) pan_info.x) ||
10396 (windows->image.y != (int) pan_info.y))
10397 {
10398 /*
10399 Display image pan offset.
10400 */
10401 windows->image.x=(int) pan_info.x;
10402 windows->image.y=(int) pan_info.y;
10403 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
10404 windows->image.width,windows->image.height,windows->image.x,
10405 windows->image.y);
10406 XInfoWidget(display,windows,text);
10407 /*
10408 Refresh Image window.
10409 */
10410 XDrawPanRectangle(display,windows);
10411 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10412 }
10413 state&=(~UpdateConfigurationState);
10414 }
10415 /*
10416 Wait for next event.
10417 */
10418 if ((state & ExitState) == 0)
10419 XScreenEvent(display,windows,event);
10420 } while ((state & ExitState) == 0);
10421 /*
10422 Restore cursor.
10423 */
10424 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10425 (void) XFreeCursor(display,cursor);
10426 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10427 }
10428
10429 /*
10430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10431 % %
10432 % %
10433 % %
10434 + X P a s t e I m a g e %
10435 % %
10436 % %
10437 % %
10438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10439 %
10440 % XPasteImage() pastes an image previously saved with XCropImage in the X
10441 % window image at a location the user chooses with the pointer.
10442 %
10443 % The format of the XPasteImage method is:
10444 %
10445 % MagickBooleanType XPasteImage(Display *display,
10446 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10447 %
10448 % A description of each parameter follows:
10449 %
10450 % o display: Specifies a connection to an X server; returned from
10451 % XOpenDisplay.
10452 %
10453 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10454 %
10455 % o windows: Specifies a pointer to a XWindows structure.
10456 %
10457 % o image: the image; returned from ReadImage.
10458 %
10459 */
XPasteImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)10460 static MagickBooleanType XPasteImage(Display *display,
10461 XResourceInfo *resource_info,XWindows *windows,Image *image)
10462 {
10463 const char
10464 *const PasteMenu[] =
10465 {
10466 "Operator",
10467 "Help",
10468 "Dismiss",
10469 (char *) NULL
10470 };
10471
10472 static const ModeType
10473 PasteCommands[] =
10474 {
10475 PasteOperatorsCommand,
10476 PasteHelpCommand,
10477 PasteDismissCommand
10478 };
10479
10480 static CompositeOperator
10481 compose = CopyCompositeOp;
10482
10483 char
10484 text[MaxTextExtent];
10485
10486 Cursor
10487 cursor;
10488
10489 Image
10490 *paste_image;
10491
10492 int
10493 entry,
10494 id,
10495 x,
10496 y;
10497
10498 MagickRealType
10499 scale_factor;
10500
10501 RectangleInfo
10502 highlight_info,
10503 paste_info;
10504
10505 unsigned int
10506 height,
10507 width;
10508
10509 size_t
10510 state;
10511
10512 XEvent
10513 event;
10514
10515 /*
10516 Copy image.
10517 */
10518 if (resource_info->copy_image == (Image *) NULL)
10519 return(MagickFalse);
10520 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10521 &image->exception);
10522 if (paste_image == (Image *) NULL)
10523 return(MagickFalse);
10524 /*
10525 Map Command widget.
10526 */
10527 (void) CloneString(&windows->command.name,"Paste");
10528 windows->command.data=1;
10529 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10530 (void) XMapRaised(display,windows->command.id);
10531 XClientMessage(display,windows->image.id,windows->im_protocols,
10532 windows->im_update_widget,CurrentTime);
10533 /*
10534 Track pointer until button 1 is pressed.
10535 */
10536 XSetCursorState(display,windows,MagickFalse);
10537 XQueryPosition(display,windows->image.id,&x,&y);
10538 (void) XSelectInput(display,windows->image.id,
10539 windows->image.attributes.event_mask | PointerMotionMask);
10540 paste_info.x=(ssize_t) windows->image.x+x;
10541 paste_info.y=(ssize_t) windows->image.y+y;
10542 paste_info.width=0;
10543 paste_info.height=0;
10544 cursor=XCreateFontCursor(display,XC_ul_angle);
10545 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10546 state=DefaultState;
10547 do
10548 {
10549 if (windows->info.mapped != MagickFalse)
10550 {
10551 /*
10552 Display pointer position.
10553 */
10554 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
10555 (long) paste_info.x,(long) paste_info.y);
10556 XInfoWidget(display,windows,text);
10557 }
10558 highlight_info=paste_info;
10559 highlight_info.x=paste_info.x-windows->image.x;
10560 highlight_info.y=paste_info.y-windows->image.y;
10561 XHighlightRectangle(display,windows->image.id,
10562 windows->image.highlight_context,&highlight_info);
10563 /*
10564 Wait for next event.
10565 */
10566 XScreenEvent(display,windows,&event);
10567 XHighlightRectangle(display,windows->image.id,
10568 windows->image.highlight_context,&highlight_info);
10569 if (event.xany.window == windows->command.id)
10570 {
10571 /*
10572 Select a command from the Command widget.
10573 */
10574 id=XCommandWidget(display,windows,PasteMenu,&event);
10575 if (id < 0)
10576 continue;
10577 switch (PasteCommands[id])
10578 {
10579 case PasteOperatorsCommand:
10580 {
10581 char
10582 command[MaxTextExtent],
10583 **operators;
10584
10585 /*
10586 Select a command from the pop-up menu.
10587 */
10588 operators=GetCommandOptions(MagickComposeOptions);
10589 if (operators == (char **) NULL)
10590 break;
10591 entry=XMenuWidget(display,windows,PasteMenu[id],
10592 (const char **) operators,command);
10593 if (entry >= 0)
10594 compose=(CompositeOperator) ParseCommandOption(
10595 MagickComposeOptions,MagickFalse,operators[entry]);
10596 operators=DestroyStringList(operators);
10597 break;
10598 }
10599 case PasteHelpCommand:
10600 {
10601 XTextViewHelp(display,resource_info,windows,MagickFalse,
10602 "Help Viewer - Image Composite",ImagePasteHelp);
10603 break;
10604 }
10605 case PasteDismissCommand:
10606 {
10607 /*
10608 Prematurely exit.
10609 */
10610 state|=EscapeState;
10611 state|=ExitState;
10612 break;
10613 }
10614 default:
10615 break;
10616 }
10617 continue;
10618 }
10619 switch (event.type)
10620 {
10621 case ButtonPress:
10622 {
10623 if (image->debug != MagickFalse)
10624 (void) LogMagickEvent(X11Event,GetMagickModule(),
10625 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10626 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10627 if (event.xbutton.button != Button1)
10628 break;
10629 if (event.xbutton.window != windows->image.id)
10630 break;
10631 /*
10632 Paste rectangle is relative to image configuration.
10633 */
10634 width=(unsigned int) image->columns;
10635 height=(unsigned int) image->rows;
10636 x=0;
10637 y=0;
10638 if (windows->image.crop_geometry != (char *) NULL)
10639 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10640 &width,&height);
10641 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10642 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10643 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10644 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10645 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10646 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10647 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10648 break;
10649 }
10650 case ButtonRelease:
10651 {
10652 if (image->debug != MagickFalse)
10653 (void) LogMagickEvent(X11Event,GetMagickModule(),
10654 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10655 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10656 if (event.xbutton.button != Button1)
10657 break;
10658 if (event.xbutton.window != windows->image.id)
10659 break;
10660 if ((paste_info.width != 0) && (paste_info.height != 0))
10661 {
10662 /*
10663 User has selected the location of the paste image.
10664 */
10665 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10666 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10667 state|=ExitState;
10668 }
10669 break;
10670 }
10671 case Expose:
10672 break;
10673 case KeyPress:
10674 {
10675 char
10676 command[MaxTextExtent];
10677
10678 KeySym
10679 key_symbol;
10680
10681 int
10682 length;
10683
10684 if (event.xkey.window != windows->image.id)
10685 break;
10686 /*
10687 Respond to a user key press.
10688 */
10689 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10690 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10691 *(command+length)='\0';
10692 if (image->debug != MagickFalse)
10693 (void) LogMagickEvent(X11Event,GetMagickModule(),
10694 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10695 switch ((int) key_symbol)
10696 {
10697 case XK_Escape:
10698 case XK_F20:
10699 {
10700 /*
10701 Prematurely exit.
10702 */
10703 paste_image=DestroyImage(paste_image);
10704 state|=EscapeState;
10705 state|=ExitState;
10706 break;
10707 }
10708 case XK_F1:
10709 case XK_Help:
10710 {
10711 (void) XSetFunction(display,windows->image.highlight_context,
10712 GXcopy);
10713 XTextViewHelp(display,resource_info,windows,MagickFalse,
10714 "Help Viewer - Image Composite",ImagePasteHelp);
10715 (void) XSetFunction(display,windows->image.highlight_context,
10716 GXinvert);
10717 break;
10718 }
10719 default:
10720 {
10721 (void) XBell(display,0);
10722 break;
10723 }
10724 }
10725 break;
10726 }
10727 case MotionNotify:
10728 {
10729 /*
10730 Map and unmap Info widget as text cursor crosses its boundaries.
10731 */
10732 x=event.xmotion.x;
10733 y=event.xmotion.y;
10734 if (windows->info.mapped != MagickFalse)
10735 {
10736 if ((x < (int) (windows->info.x+windows->info.width)) &&
10737 (y < (int) (windows->info.y+windows->info.height)))
10738 (void) XWithdrawWindow(display,windows->info.id,
10739 windows->info.screen);
10740 }
10741 else
10742 if ((x > (int) (windows->info.x+windows->info.width)) ||
10743 (y > (int) (windows->info.y+windows->info.height)))
10744 (void) XMapWindow(display,windows->info.id);
10745 paste_info.x=(ssize_t) windows->image.x+x;
10746 paste_info.y=(ssize_t) windows->image.y+y;
10747 break;
10748 }
10749 default:
10750 {
10751 if (image->debug != MagickFalse)
10752 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10753 event.type);
10754 break;
10755 }
10756 }
10757 } while ((state & ExitState) == 0);
10758 (void) XSelectInput(display,windows->image.id,
10759 windows->image.attributes.event_mask);
10760 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10761 XSetCursorState(display,windows,MagickFalse);
10762 (void) XFreeCursor(display,cursor);
10763 if ((state & EscapeState) != 0)
10764 return(MagickTrue);
10765 /*
10766 Image pasting is relative to image configuration.
10767 */
10768 XSetCursorState(display,windows,MagickTrue);
10769 XCheckRefreshWindows(display,windows);
10770 width=(unsigned int) image->columns;
10771 height=(unsigned int) image->rows;
10772 x=0;
10773 y=0;
10774 if (windows->image.crop_geometry != (char *) NULL)
10775 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10776 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10777 paste_info.x+=x;
10778 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10779 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10780 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10781 paste_info.y+=y;
10782 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10783 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10784 /*
10785 Paste image with X Image window.
10786 */
10787 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10788 paste_image=DestroyImage(paste_image);
10789 XSetCursorState(display,windows,MagickFalse);
10790 /*
10791 Update image colormap.
10792 */
10793 XConfigureImageColormap(display,resource_info,windows,image);
10794 (void) XConfigureImage(display,resource_info,windows,image);
10795 return(MagickTrue);
10796 }
10797
10798 /*
10799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10800 % %
10801 % %
10802 % %
10803 + X P r i n t I m a g e %
10804 % %
10805 % %
10806 % %
10807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10808 %
10809 % XPrintImage() prints an image to a Postscript printer.
10810 %
10811 % The format of the XPrintImage method is:
10812 %
10813 % MagickBooleanType XPrintImage(Display *display,
10814 % XResourceInfo *resource_info,XWindows *windows,Image *image)
10815 %
10816 % A description of each parameter follows:
10817 %
10818 % o display: Specifies a connection to an X server; returned from
10819 % XOpenDisplay.
10820 %
10821 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10822 %
10823 % o windows: Specifies a pointer to a XWindows structure.
10824 %
10825 % o image: the image.
10826 %
10827 */
XPrintImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)10828 static MagickBooleanType XPrintImage(Display *display,
10829 XResourceInfo *resource_info,XWindows *windows,Image *image)
10830 {
10831 char
10832 filename[MaxTextExtent],
10833 geometry[MaxTextExtent];
10834
10835 const char
10836 *const PageSizes[] =
10837 {
10838 "Letter",
10839 "Tabloid",
10840 "Ledger",
10841 "Legal",
10842 "Statement",
10843 "Executive",
10844 "A3",
10845 "A4",
10846 "A5",
10847 "B4",
10848 "B5",
10849 "Folio",
10850 "Quarto",
10851 "10x14",
10852 (char *) NULL
10853 };
10854
10855 Image
10856 *print_image;
10857
10858 ImageInfo
10859 *image_info;
10860
10861 MagickStatusType
10862 status;
10863
10864 /*
10865 Request Postscript page geometry from user.
10866 */
10867 image_info=CloneImageInfo(resource_info->image_info);
10868 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
10869 if (image_info->page != (char *) NULL)
10870 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10871 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10872 "Select Postscript Page Geometry:",geometry);
10873 if (*geometry == '\0')
10874 return(MagickTrue);
10875 image_info->page=GetPageGeometry(geometry);
10876 /*
10877 Apply image transforms.
10878 */
10879 XSetCursorState(display,windows,MagickTrue);
10880 XCheckRefreshWindows(display,windows);
10881 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10882 if (print_image == (Image *) NULL)
10883 return(MagickFalse);
10884 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
10885 windows->image.ximage->width,windows->image.ximage->height);
10886 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10887 /*
10888 Print image.
10889 */
10890 (void) AcquireUniqueFilename(filename);
10891 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
10892 filename);
10893 status=WriteImage(image_info,print_image);
10894 (void) RelinquishUniqueFileResource(filename);
10895 print_image=DestroyImage(print_image);
10896 image_info=DestroyImageInfo(image_info);
10897 XSetCursorState(display,windows,MagickFalse);
10898 return(status != 0 ? MagickTrue : MagickFalse);
10899 }
10900
10901 /*
10902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10903 % %
10904 % %
10905 % %
10906 + X R O I I m a g e %
10907 % %
10908 % %
10909 % %
10910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10911 %
10912 % XROIImage() applies an image processing technique to a region of interest.
10913 %
10914 % The format of the XROIImage method is:
10915 %
10916 % MagickBooleanType XROIImage(Display *display,
10917 % XResourceInfo *resource_info,XWindows *windows,Image **image)
10918 %
10919 % A description of each parameter follows:
10920 %
10921 % o display: Specifies a connection to an X server; returned from
10922 % XOpenDisplay.
10923 %
10924 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10925 %
10926 % o windows: Specifies a pointer to a XWindows structure.
10927 %
10928 % o image: the image; returned from ReadImage.
10929 %
10930 */
XROIImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image)10931 static MagickBooleanType XROIImage(Display *display,
10932 XResourceInfo *resource_info,XWindows *windows,Image **image)
10933 {
10934 #define ApplyMenus 7
10935
10936 const char
10937 *const ROIMenu[] =
10938 {
10939 "Help",
10940 "Dismiss",
10941 (char *) NULL
10942 },
10943 *const ApplyMenu[] =
10944 {
10945 "File",
10946 "Edit",
10947 "Transform",
10948 "Enhance",
10949 "Effects",
10950 "F/X",
10951 "Miscellany",
10952 "Help",
10953 "Dismiss",
10954 (char *) NULL
10955 },
10956 *const FileMenu[] =
10957 {
10958 "Save...",
10959 "Print...",
10960 (char *) NULL
10961 },
10962 *const EditMenu[] =
10963 {
10964 "Undo",
10965 "Redo",
10966 (char *) NULL
10967 },
10968 *const TransformMenu[] =
10969 {
10970 "Flop",
10971 "Flip",
10972 "Rotate Right",
10973 "Rotate Left",
10974 (char *) NULL
10975 },
10976 *const EnhanceMenu[] =
10977 {
10978 "Hue...",
10979 "Saturation...",
10980 "Brightness...",
10981 "Gamma...",
10982 "Spiff",
10983 "Dull",
10984 "Contrast Stretch...",
10985 "Sigmoidal Contrast...",
10986 "Normalize",
10987 "Equalize",
10988 "Negate",
10989 "Grayscale",
10990 "Map...",
10991 "Quantize...",
10992 (char *) NULL
10993 },
10994 *const EffectsMenu[] =
10995 {
10996 "Despeckle",
10997 "Emboss",
10998 "Reduce Noise",
10999 "Add Noise",
11000 "Sharpen...",
11001 "Blur...",
11002 "Threshold...",
11003 "Edge Detect...",
11004 "Spread...",
11005 "Shade...",
11006 "Raise...",
11007 "Segment...",
11008 (char *) NULL
11009 },
11010 *const FXMenu[] =
11011 {
11012 "Solarize...",
11013 "Sepia Tone...",
11014 "Swirl...",
11015 "Implode...",
11016 "Vignette...",
11017 "Wave...",
11018 "Oil Paint...",
11019 "Charcoal Draw...",
11020 (char *) NULL
11021 },
11022 *const MiscellanyMenu[] =
11023 {
11024 "Image Info",
11025 "Zoom Image",
11026 "Show Preview...",
11027 "Show Histogram",
11028 "Show Matte",
11029 (char *) NULL
11030 };
11031
11032 const char
11033 *const *Menus[ApplyMenus] =
11034 {
11035 FileMenu,
11036 EditMenu,
11037 TransformMenu,
11038 EnhanceMenu,
11039 EffectsMenu,
11040 FXMenu,
11041 MiscellanyMenu
11042 };
11043
11044 static const CommandType
11045 ApplyCommands[] =
11046 {
11047 NullCommand,
11048 NullCommand,
11049 NullCommand,
11050 NullCommand,
11051 NullCommand,
11052 NullCommand,
11053 NullCommand,
11054 HelpCommand,
11055 QuitCommand
11056 },
11057 FileCommands[] =
11058 {
11059 SaveCommand,
11060 PrintCommand
11061 },
11062 EditCommands[] =
11063 {
11064 UndoCommand,
11065 RedoCommand
11066 },
11067 TransformCommands[] =
11068 {
11069 FlopCommand,
11070 FlipCommand,
11071 RotateRightCommand,
11072 RotateLeftCommand
11073 },
11074 EnhanceCommands[] =
11075 {
11076 HueCommand,
11077 SaturationCommand,
11078 BrightnessCommand,
11079 GammaCommand,
11080 SpiffCommand,
11081 DullCommand,
11082 ContrastStretchCommand,
11083 SigmoidalContrastCommand,
11084 NormalizeCommand,
11085 EqualizeCommand,
11086 NegateCommand,
11087 GrayscaleCommand,
11088 MapCommand,
11089 QuantizeCommand
11090 },
11091 EffectsCommands[] =
11092 {
11093 DespeckleCommand,
11094 EmbossCommand,
11095 ReduceNoiseCommand,
11096 AddNoiseCommand,
11097 SharpenCommand,
11098 BlurCommand,
11099 EdgeDetectCommand,
11100 SpreadCommand,
11101 ShadeCommand,
11102 RaiseCommand,
11103 SegmentCommand
11104 },
11105 FXCommands[] =
11106 {
11107 SolarizeCommand,
11108 SepiaToneCommand,
11109 SwirlCommand,
11110 ImplodeCommand,
11111 VignetteCommand,
11112 WaveCommand,
11113 OilPaintCommand,
11114 CharcoalDrawCommand
11115 },
11116 MiscellanyCommands[] =
11117 {
11118 InfoCommand,
11119 ZoomCommand,
11120 ShowPreviewCommand,
11121 ShowHistogramCommand,
11122 ShowMatteCommand
11123 },
11124 ROICommands[] =
11125 {
11126 ROIHelpCommand,
11127 ROIDismissCommand
11128 };
11129
11130 static const CommandType
11131 *Commands[ApplyMenus] =
11132 {
11133 FileCommands,
11134 EditCommands,
11135 TransformCommands,
11136 EnhanceCommands,
11137 EffectsCommands,
11138 FXCommands,
11139 MiscellanyCommands
11140 };
11141
11142 char
11143 command[MaxTextExtent],
11144 text[MaxTextExtent];
11145
11146 CommandType
11147 command_type;
11148
11149 Cursor
11150 cursor;
11151
11152 Image
11153 *roi_image;
11154
11155 int
11156 entry,
11157 id,
11158 x,
11159 y;
11160
11161 MagickRealType
11162 scale_factor;
11163
11164 MagickProgressMonitor
11165 progress_monitor;
11166
11167 RectangleInfo
11168 crop_info,
11169 highlight_info,
11170 roi_info;
11171
11172 unsigned int
11173 height,
11174 width;
11175
11176 size_t
11177 state;
11178
11179 XEvent
11180 event;
11181
11182 /*
11183 Map Command widget.
11184 */
11185 (void) CloneString(&windows->command.name,"ROI");
11186 windows->command.data=0;
11187 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11188 (void) XMapRaised(display,windows->command.id);
11189 XClientMessage(display,windows->image.id,windows->im_protocols,
11190 windows->im_update_widget,CurrentTime);
11191 /*
11192 Track pointer until button 1 is pressed.
11193 */
11194 XQueryPosition(display,windows->image.id,&x,&y);
11195 (void) XSelectInput(display,windows->image.id,
11196 windows->image.attributes.event_mask | PointerMotionMask);
11197 crop_info.width=0;
11198 crop_info.height=0;
11199 crop_info.x=0;
11200 crop_info.y=0;
11201 roi_info.x=(ssize_t) windows->image.x+x;
11202 roi_info.y=(ssize_t) windows->image.y+y;
11203 roi_info.width=0;
11204 roi_info.height=0;
11205 cursor=XCreateFontCursor(display,XC_fleur);
11206 state=DefaultState;
11207 do
11208 {
11209 if (windows->info.mapped != MagickFalse)
11210 {
11211 /*
11212 Display pointer position.
11213 */
11214 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
11215 (long) roi_info.x,(long) roi_info.y);
11216 XInfoWidget(display,windows,text);
11217 }
11218 /*
11219 Wait for next event.
11220 */
11221 XScreenEvent(display,windows,&event);
11222 if (event.xany.window == windows->command.id)
11223 {
11224 /*
11225 Select a command from the Command widget.
11226 */
11227 id=XCommandWidget(display,windows,ROIMenu,&event);
11228 if (id < 0)
11229 continue;
11230 switch (ROICommands[id])
11231 {
11232 case ROIHelpCommand:
11233 {
11234 XTextViewHelp(display,resource_info,windows,MagickFalse,
11235 "Help Viewer - Region of Interest",ImageROIHelp);
11236 break;
11237 }
11238 case ROIDismissCommand:
11239 {
11240 /*
11241 Prematurely exit.
11242 */
11243 state|=EscapeState;
11244 state|=ExitState;
11245 break;
11246 }
11247 default:
11248 break;
11249 }
11250 continue;
11251 }
11252 switch (event.type)
11253 {
11254 case ButtonPress:
11255 {
11256 if (event.xbutton.button != Button1)
11257 break;
11258 if (event.xbutton.window != windows->image.id)
11259 break;
11260 /*
11261 Note first corner of region of interest rectangle-- exit loop.
11262 */
11263 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11264 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11265 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11266 state|=ExitState;
11267 break;
11268 }
11269 case ButtonRelease:
11270 break;
11271 case Expose:
11272 break;
11273 case KeyPress:
11274 {
11275 KeySym
11276 key_symbol;
11277
11278 if (event.xkey.window != windows->image.id)
11279 break;
11280 /*
11281 Respond to a user key press.
11282 */
11283 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11284 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11285 switch ((int) key_symbol)
11286 {
11287 case XK_Escape:
11288 case XK_F20:
11289 {
11290 /*
11291 Prematurely exit.
11292 */
11293 state|=EscapeState;
11294 state|=ExitState;
11295 break;
11296 }
11297 case XK_F1:
11298 case XK_Help:
11299 {
11300 XTextViewHelp(display,resource_info,windows,MagickFalse,
11301 "Help Viewer - Region of Interest",ImageROIHelp);
11302 break;
11303 }
11304 default:
11305 {
11306 (void) XBell(display,0);
11307 break;
11308 }
11309 }
11310 break;
11311 }
11312 case MotionNotify:
11313 {
11314 /*
11315 Map and unmap Info widget as text cursor crosses its boundaries.
11316 */
11317 x=event.xmotion.x;
11318 y=event.xmotion.y;
11319 if (windows->info.mapped != MagickFalse)
11320 {
11321 if ((x < (int) (windows->info.x+windows->info.width)) &&
11322 (y < (int) (windows->info.y+windows->info.height)))
11323 (void) XWithdrawWindow(display,windows->info.id,
11324 windows->info.screen);
11325 }
11326 else
11327 if ((x > (int) (windows->info.x+windows->info.width)) ||
11328 (y > (int) (windows->info.y+windows->info.height)))
11329 (void) XMapWindow(display,windows->info.id);
11330 roi_info.x=(ssize_t) windows->image.x+x;
11331 roi_info.y=(ssize_t) windows->image.y+y;
11332 break;
11333 }
11334 default:
11335 break;
11336 }
11337 } while ((state & ExitState) == 0);
11338 (void) XSelectInput(display,windows->image.id,
11339 windows->image.attributes.event_mask);
11340 if ((state & EscapeState) != 0)
11341 {
11342 /*
11343 User want to exit without region of interest.
11344 */
11345 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11346 (void) XFreeCursor(display,cursor);
11347 return(MagickTrue);
11348 }
11349 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11350 do
11351 {
11352 /*
11353 Size rectangle as pointer moves until the mouse button is released.
11354 */
11355 x=(int) roi_info.x;
11356 y=(int) roi_info.y;
11357 roi_info.width=0;
11358 roi_info.height=0;
11359 state=DefaultState;
11360 do
11361 {
11362 highlight_info=roi_info;
11363 highlight_info.x=roi_info.x-windows->image.x;
11364 highlight_info.y=roi_info.y-windows->image.y;
11365 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11366 {
11367 /*
11368 Display info and draw region of interest rectangle.
11369 */
11370 if (windows->info.mapped == MagickFalse)
11371 (void) XMapWindow(display,windows->info.id);
11372 (void) FormatLocaleString(text,MaxTextExtent,
11373 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11374 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11375 XInfoWidget(display,windows,text);
11376 XHighlightRectangle(display,windows->image.id,
11377 windows->image.highlight_context,&highlight_info);
11378 }
11379 else
11380 if (windows->info.mapped != MagickFalse)
11381 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11382 /*
11383 Wait for next event.
11384 */
11385 XScreenEvent(display,windows,&event);
11386 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11387 XHighlightRectangle(display,windows->image.id,
11388 windows->image.highlight_context,&highlight_info);
11389 switch (event.type)
11390 {
11391 case ButtonPress:
11392 {
11393 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11394 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11395 break;
11396 }
11397 case ButtonRelease:
11398 {
11399 /*
11400 User has committed to region of interest rectangle.
11401 */
11402 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11403 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11404 XSetCursorState(display,windows,MagickFalse);
11405 state|=ExitState;
11406 if (LocaleCompare(windows->command.name,"Apply") == 0)
11407 break;
11408 (void) CloneString(&windows->command.name,"Apply");
11409 windows->command.data=ApplyMenus;
11410 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11411 break;
11412 }
11413 case Expose:
11414 break;
11415 case MotionNotify:
11416 {
11417 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11418 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11419 }
11420 default:
11421 break;
11422 }
11423 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11424 ((state & ExitState) != 0))
11425 {
11426 /*
11427 Check boundary conditions.
11428 */
11429 if (roi_info.x < 0)
11430 roi_info.x=0;
11431 else
11432 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11433 roi_info.x=(ssize_t) windows->image.ximage->width;
11434 if ((int) roi_info.x < x)
11435 roi_info.width=(unsigned int) (x-roi_info.x);
11436 else
11437 {
11438 roi_info.width=(unsigned int) (roi_info.x-x);
11439 roi_info.x=(ssize_t) x;
11440 }
11441 if (roi_info.y < 0)
11442 roi_info.y=0;
11443 else
11444 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11445 roi_info.y=(ssize_t) windows->image.ximage->height;
11446 if ((int) roi_info.y < y)
11447 roi_info.height=(unsigned int) (y-roi_info.y);
11448 else
11449 {
11450 roi_info.height=(unsigned int) (roi_info.y-y);
11451 roi_info.y=(ssize_t) y;
11452 }
11453 }
11454 } while ((state & ExitState) == 0);
11455 /*
11456 Wait for user to grab a corner of the rectangle or press return.
11457 */
11458 state=DefaultState;
11459 command_type=NullCommand;
11460 (void) XMapWindow(display,windows->info.id);
11461 do
11462 {
11463 if (windows->info.mapped != MagickFalse)
11464 {
11465 /*
11466 Display pointer position.
11467 */
11468 (void) FormatLocaleString(text,MaxTextExtent,
11469 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11470 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11471 XInfoWidget(display,windows,text);
11472 }
11473 highlight_info=roi_info;
11474 highlight_info.x=roi_info.x-windows->image.x;
11475 highlight_info.y=roi_info.y-windows->image.y;
11476 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11477 {
11478 state|=EscapeState;
11479 state|=ExitState;
11480 break;
11481 }
11482 if ((state & UpdateRegionState) != 0)
11483 {
11484 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11485 switch (command_type)
11486 {
11487 case UndoCommand:
11488 case RedoCommand:
11489 {
11490 (void) XMagickCommand(display,resource_info,windows,command_type,
11491 image);
11492 break;
11493 }
11494 default:
11495 {
11496 /*
11497 Region of interest is relative to image configuration.
11498 */
11499 progress_monitor=SetImageProgressMonitor(*image,
11500 (MagickProgressMonitor) NULL,(*image)->client_data);
11501 crop_info=roi_info;
11502 width=(unsigned int) (*image)->columns;
11503 height=(unsigned int) (*image)->rows;
11504 x=0;
11505 y=0;
11506 if (windows->image.crop_geometry != (char *) NULL)
11507 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11508 &width,&height);
11509 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11510 crop_info.x+=x;
11511 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11512 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11513 scale_factor=(MagickRealType)
11514 height/windows->image.ximage->height;
11515 crop_info.y+=y;
11516 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11517 crop_info.height=(unsigned int)
11518 (scale_factor*crop_info.height+0.5);
11519 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11520 (void) SetImageProgressMonitor(*image,progress_monitor,
11521 (*image)->client_data);
11522 if (roi_image == (Image *) NULL)
11523 continue;
11524 /*
11525 Apply image processing technique to the region of interest.
11526 */
11527 windows->image.orphan=MagickTrue;
11528 (void) XMagickCommand(display,resource_info,windows,command_type,
11529 &roi_image);
11530 progress_monitor=SetImageProgressMonitor(*image,
11531 (MagickProgressMonitor) NULL,(*image)->client_data);
11532 (void) XMagickCommand(display,resource_info,windows,
11533 SaveToUndoBufferCommand,image);
11534 windows->image.orphan=MagickFalse;
11535 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11536 crop_info.x,crop_info.y);
11537 roi_image=DestroyImage(roi_image);
11538 (void) SetImageProgressMonitor(*image,progress_monitor,
11539 (*image)->client_data);
11540 break;
11541 }
11542 }
11543 if (command_type != InfoCommand)
11544 {
11545 XConfigureImageColormap(display,resource_info,windows,*image);
11546 (void) XConfigureImage(display,resource_info,windows,*image);
11547 }
11548 XCheckRefreshWindows(display,windows);
11549 XInfoWidget(display,windows,text);
11550 (void) XSetFunction(display,windows->image.highlight_context,
11551 GXinvert);
11552 state&=(~UpdateRegionState);
11553 }
11554 XHighlightRectangle(display,windows->image.id,
11555 windows->image.highlight_context,&highlight_info);
11556 XScreenEvent(display,windows,&event);
11557 if (event.xany.window == windows->command.id)
11558 {
11559 /*
11560 Select a command from the Command widget.
11561 */
11562 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11563 command_type=NullCommand;
11564 id=XCommandWidget(display,windows,ApplyMenu,&event);
11565 if (id >= 0)
11566 {
11567 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11568 command_type=ApplyCommands[id];
11569 if (id < ApplyMenus)
11570 {
11571 /*
11572 Select a command from a pop-up menu.
11573 */
11574 entry=XMenuWidget(display,windows,ApplyMenu[id],
11575 (const char **) Menus[id],command);
11576 if (entry >= 0)
11577 {
11578 (void) CopyMagickString(command,Menus[id][entry],
11579 MaxTextExtent);
11580 command_type=Commands[id][entry];
11581 }
11582 }
11583 }
11584 (void) XSetFunction(display,windows->image.highlight_context,
11585 GXinvert);
11586 XHighlightRectangle(display,windows->image.id,
11587 windows->image.highlight_context,&highlight_info);
11588 if (command_type == HelpCommand)
11589 {
11590 (void) XSetFunction(display,windows->image.highlight_context,
11591 GXcopy);
11592 XTextViewHelp(display,resource_info,windows,MagickFalse,
11593 "Help Viewer - Region of Interest",ImageROIHelp);
11594 (void) XSetFunction(display,windows->image.highlight_context,
11595 GXinvert);
11596 continue;
11597 }
11598 if (command_type == QuitCommand)
11599 {
11600 /*
11601 exit.
11602 */
11603 state|=EscapeState;
11604 state|=ExitState;
11605 continue;
11606 }
11607 if (command_type != NullCommand)
11608 state|=UpdateRegionState;
11609 continue;
11610 }
11611 XHighlightRectangle(display,windows->image.id,
11612 windows->image.highlight_context,&highlight_info);
11613 switch (event.type)
11614 {
11615 case ButtonPress:
11616 {
11617 x=windows->image.x;
11618 y=windows->image.y;
11619 if (event.xbutton.button != Button1)
11620 break;
11621 if (event.xbutton.window != windows->image.id)
11622 break;
11623 x=windows->image.x+event.xbutton.x;
11624 y=windows->image.y+event.xbutton.y;
11625 if ((x < (int) (roi_info.x+RoiDelta)) &&
11626 (x > (int) (roi_info.x-RoiDelta)) &&
11627 (y < (int) (roi_info.y+RoiDelta)) &&
11628 (y > (int) (roi_info.y-RoiDelta)))
11629 {
11630 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11631 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11632 state|=UpdateConfigurationState;
11633 break;
11634 }
11635 if ((x < (int) (roi_info.x+RoiDelta)) &&
11636 (x > (int) (roi_info.x-RoiDelta)) &&
11637 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11638 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11639 {
11640 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11641 state|=UpdateConfigurationState;
11642 break;
11643 }
11644 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11645 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11646 (y < (int) (roi_info.y+RoiDelta)) &&
11647 (y > (int) (roi_info.y-RoiDelta)))
11648 {
11649 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11650 state|=UpdateConfigurationState;
11651 break;
11652 }
11653 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11654 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11655 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11656 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11657 {
11658 state|=UpdateConfigurationState;
11659 break;
11660 }
11661 }
11662 case ButtonRelease:
11663 {
11664 if (event.xbutton.window == windows->pan.id)
11665 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11666 (highlight_info.y != crop_info.y-windows->image.y))
11667 XHighlightRectangle(display,windows->image.id,
11668 windows->image.highlight_context,&highlight_info);
11669 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11670 event.xbutton.time);
11671 break;
11672 }
11673 case Expose:
11674 {
11675 if (event.xexpose.window == windows->image.id)
11676 if (event.xexpose.count == 0)
11677 {
11678 event.xexpose.x=(int) highlight_info.x;
11679 event.xexpose.y=(int) highlight_info.y;
11680 event.xexpose.width=(int) highlight_info.width;
11681 event.xexpose.height=(int) highlight_info.height;
11682 XRefreshWindow(display,&windows->image,&event);
11683 }
11684 if (event.xexpose.window == windows->info.id)
11685 if (event.xexpose.count == 0)
11686 XInfoWidget(display,windows,text);
11687 break;
11688 }
11689 case KeyPress:
11690 {
11691 KeySym
11692 key_symbol;
11693
11694 if (event.xkey.window != windows->image.id)
11695 break;
11696 /*
11697 Respond to a user key press.
11698 */
11699 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11700 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11701 switch ((int) key_symbol)
11702 {
11703 case XK_Shift_L:
11704 case XK_Shift_R:
11705 break;
11706 case XK_Escape:
11707 case XK_F20:
11708 state|=EscapeState;
11709 case XK_Return:
11710 {
11711 state|=ExitState;
11712 break;
11713 }
11714 case XK_Home:
11715 case XK_KP_Home:
11716 {
11717 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11718 roi_info.y=(ssize_t) (windows->image.height/2L-
11719 roi_info.height/2L);
11720 break;
11721 }
11722 case XK_Left:
11723 case XK_KP_Left:
11724 {
11725 roi_info.x--;
11726 break;
11727 }
11728 case XK_Up:
11729 case XK_KP_Up:
11730 case XK_Next:
11731 {
11732 roi_info.y--;
11733 break;
11734 }
11735 case XK_Right:
11736 case XK_KP_Right:
11737 {
11738 roi_info.x++;
11739 break;
11740 }
11741 case XK_Prior:
11742 case XK_Down:
11743 case XK_KP_Down:
11744 {
11745 roi_info.y++;
11746 break;
11747 }
11748 case XK_F1:
11749 case XK_Help:
11750 {
11751 (void) XSetFunction(display,windows->image.highlight_context,
11752 GXcopy);
11753 XTextViewHelp(display,resource_info,windows,MagickFalse,
11754 "Help Viewer - Region of Interest",ImageROIHelp);
11755 (void) XSetFunction(display,windows->image.highlight_context,
11756 GXinvert);
11757 break;
11758 }
11759 default:
11760 {
11761 command_type=XImageWindowCommand(display,resource_info,windows,
11762 event.xkey.state,key_symbol,image);
11763 if (command_type != NullCommand)
11764 state|=UpdateRegionState;
11765 break;
11766 }
11767 }
11768 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11769 event.xkey.time);
11770 break;
11771 }
11772 case KeyRelease:
11773 break;
11774 case MotionNotify:
11775 {
11776 if (event.xbutton.window != windows->image.id)
11777 break;
11778 /*
11779 Map and unmap Info widget as text cursor crosses its boundaries.
11780 */
11781 x=event.xmotion.x;
11782 y=event.xmotion.y;
11783 if (windows->info.mapped != MagickFalse)
11784 {
11785 if ((x < (int) (windows->info.x+windows->info.width)) &&
11786 (y < (int) (windows->info.y+windows->info.height)))
11787 (void) XWithdrawWindow(display,windows->info.id,
11788 windows->info.screen);
11789 }
11790 else
11791 if ((x > (int) (windows->info.x+windows->info.width)) ||
11792 (y > (int) (windows->info.y+windows->info.height)))
11793 (void) XMapWindow(display,windows->info.id);
11794 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11795 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11796 break;
11797 }
11798 case SelectionRequest:
11799 {
11800 XSelectionEvent
11801 notify;
11802
11803 XSelectionRequestEvent
11804 *request;
11805
11806 /*
11807 Set primary selection.
11808 */
11809 (void) FormatLocaleString(text,MaxTextExtent,
11810 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11811 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11812 request=(&(event.xselectionrequest));
11813 (void) XChangeProperty(request->display,request->requestor,
11814 request->property,request->target,8,PropModeReplace,
11815 (unsigned char *) text,(int) strlen(text));
11816 notify.type=SelectionNotify;
11817 notify.display=request->display;
11818 notify.requestor=request->requestor;
11819 notify.selection=request->selection;
11820 notify.target=request->target;
11821 notify.time=request->time;
11822 if (request->property == None)
11823 notify.property=request->target;
11824 else
11825 notify.property=request->property;
11826 (void) XSendEvent(request->display,request->requestor,False,0,
11827 (XEvent *) ¬ify);
11828 }
11829 default:
11830 break;
11831 }
11832 if ((state & UpdateConfigurationState) != 0)
11833 {
11834 (void) XPutBackEvent(display,&event);
11835 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11836 break;
11837 }
11838 } while ((state & ExitState) == 0);
11839 } while ((state & ExitState) == 0);
11840 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11841 XSetCursorState(display,windows,MagickFalse);
11842 if ((state & EscapeState) != 0)
11843 return(MagickTrue);
11844 return(MagickTrue);
11845 }
11846
11847 /*
11848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11849 % %
11850 % %
11851 % %
11852 + X R o t a t e I m a g e %
11853 % %
11854 % %
11855 % %
11856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11857 %
11858 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11859 % rotation angle is computed from the slope of a line drawn by the user.
11860 %
11861 % The format of the XRotateImage method is:
11862 %
11863 % MagickBooleanType XRotateImage(Display *display,
11864 % XResourceInfo *resource_info,XWindows *windows,double degrees,
11865 % Image **image)
11866 %
11867 % A description of each parameter follows:
11868 %
11869 % o display: Specifies a connection to an X server; returned from
11870 % XOpenDisplay.
11871 %
11872 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11873 %
11874 % o windows: Specifies a pointer to a XWindows structure.
11875 %
11876 % o degrees: Specifies the number of degrees to rotate the image.
11877 %
11878 % o image: the image.
11879 %
11880 */
XRotateImage(Display * display,XResourceInfo * resource_info,XWindows * windows,double degrees,Image ** image)11881 static MagickBooleanType XRotateImage(Display *display,
11882 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11883 {
11884 const char
11885 *const RotateMenu[] =
11886 {
11887 "Pixel Color",
11888 "Direction",
11889 "Help",
11890 "Dismiss",
11891 (char *) NULL
11892 };
11893
11894 static ModeType
11895 direction = HorizontalRotateCommand;
11896
11897 static const ModeType
11898 DirectionCommands[] =
11899 {
11900 HorizontalRotateCommand,
11901 VerticalRotateCommand
11902 },
11903 RotateCommands[] =
11904 {
11905 RotateColorCommand,
11906 RotateDirectionCommand,
11907 RotateHelpCommand,
11908 RotateDismissCommand
11909 };
11910
11911 static unsigned int
11912 pen_id = 0;
11913
11914 char
11915 command[MaxTextExtent],
11916 text[MaxTextExtent];
11917
11918 Image
11919 *rotate_image;
11920
11921 int
11922 id,
11923 x,
11924 y;
11925
11926 MagickRealType
11927 normalized_degrees;
11928
11929 int
11930 i;
11931
11932 unsigned int
11933 height,
11934 rotations,
11935 width;
11936
11937 if (degrees == 0.0)
11938 {
11939 unsigned int
11940 distance;
11941
11942 size_t
11943 state;
11944
11945 XEvent
11946 event;
11947
11948 XSegment
11949 rotate_info;
11950
11951 /*
11952 Map Command widget.
11953 */
11954 (void) CloneString(&windows->command.name,"Rotate");
11955 windows->command.data=2;
11956 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11957 (void) XMapRaised(display,windows->command.id);
11958 XClientMessage(display,windows->image.id,windows->im_protocols,
11959 windows->im_update_widget,CurrentTime);
11960 /*
11961 Wait for first button press.
11962 */
11963 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11964 XQueryPosition(display,windows->image.id,&x,&y);
11965 rotate_info.x1=x;
11966 rotate_info.y1=y;
11967 rotate_info.x2=x;
11968 rotate_info.y2=y;
11969 state=DefaultState;
11970 do
11971 {
11972 XHighlightLine(display,windows->image.id,
11973 windows->image.highlight_context,&rotate_info);
11974 /*
11975 Wait for next event.
11976 */
11977 XScreenEvent(display,windows,&event);
11978 XHighlightLine(display,windows->image.id,
11979 windows->image.highlight_context,&rotate_info);
11980 if (event.xany.window == windows->command.id)
11981 {
11982 /*
11983 Select a command from the Command widget.
11984 */
11985 id=XCommandWidget(display,windows,RotateMenu,&event);
11986 if (id < 0)
11987 continue;
11988 (void) XSetFunction(display,windows->image.highlight_context,
11989 GXcopy);
11990 switch (RotateCommands[id])
11991 {
11992 case RotateColorCommand:
11993 {
11994 const char
11995 *ColorMenu[MaxNumberPens];
11996
11997 int
11998 pen_number;
11999
12000 XColor
12001 color;
12002
12003 /*
12004 Initialize menu selections.
12005 */
12006 for (i=0; i < (int) (MaxNumberPens-2); i++)
12007 ColorMenu[i]=resource_info->pen_colors[i];
12008 ColorMenu[MaxNumberPens-2]="Browser...";
12009 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12010 /*
12011 Select a pen color from the pop-up menu.
12012 */
12013 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12014 (const char **) ColorMenu,command);
12015 if (pen_number < 0)
12016 break;
12017 if (pen_number == (MaxNumberPens-2))
12018 {
12019 static char
12020 color_name[MaxTextExtent] = "gray";
12021
12022 /*
12023 Select a pen color from a dialog.
12024 */
12025 resource_info->pen_colors[pen_number]=color_name;
12026 XColorBrowserWidget(display,windows,"Select",color_name);
12027 if (*color_name == '\0')
12028 break;
12029 }
12030 /*
12031 Set pen color.
12032 */
12033 (void) XParseColor(display,windows->map_info->colormap,
12034 resource_info->pen_colors[pen_number],&color);
12035 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12036 (unsigned int) MaxColors,&color);
12037 windows->pixel_info->pen_colors[pen_number]=color;
12038 pen_id=(unsigned int) pen_number;
12039 break;
12040 }
12041 case RotateDirectionCommand:
12042 {
12043 const char
12044 *const Directions[] =
12045 {
12046 "horizontal",
12047 "vertical",
12048 (char *) NULL,
12049 };
12050
12051 /*
12052 Select a command from the pop-up menu.
12053 */
12054 id=XMenuWidget(display,windows,RotateMenu[id],
12055 Directions,command);
12056 if (id >= 0)
12057 direction=DirectionCommands[id];
12058 break;
12059 }
12060 case RotateHelpCommand:
12061 {
12062 XTextViewHelp(display,resource_info,windows,MagickFalse,
12063 "Help Viewer - Image Rotation",ImageRotateHelp);
12064 break;
12065 }
12066 case RotateDismissCommand:
12067 {
12068 /*
12069 Prematurely exit.
12070 */
12071 state|=EscapeState;
12072 state|=ExitState;
12073 break;
12074 }
12075 default:
12076 break;
12077 }
12078 (void) XSetFunction(display,windows->image.highlight_context,
12079 GXinvert);
12080 continue;
12081 }
12082 switch (event.type)
12083 {
12084 case ButtonPress:
12085 {
12086 if (event.xbutton.button != Button1)
12087 break;
12088 if (event.xbutton.window != windows->image.id)
12089 break;
12090 /*
12091 exit loop.
12092 */
12093 (void) XSetFunction(display,windows->image.highlight_context,
12094 GXcopy);
12095 rotate_info.x1=event.xbutton.x;
12096 rotate_info.y1=event.xbutton.y;
12097 state|=ExitState;
12098 break;
12099 }
12100 case ButtonRelease:
12101 break;
12102 case Expose:
12103 break;
12104 case KeyPress:
12105 {
12106 char
12107 command[MaxTextExtent];
12108
12109 KeySym
12110 key_symbol;
12111
12112 if (event.xkey.window != windows->image.id)
12113 break;
12114 /*
12115 Respond to a user key press.
12116 */
12117 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12118 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12119 switch ((int) key_symbol)
12120 {
12121 case XK_Escape:
12122 case XK_F20:
12123 {
12124 /*
12125 Prematurely exit.
12126 */
12127 state|=EscapeState;
12128 state|=ExitState;
12129 break;
12130 }
12131 case XK_F1:
12132 case XK_Help:
12133 {
12134 (void) XSetFunction(display,windows->image.highlight_context,
12135 GXcopy);
12136 XTextViewHelp(display,resource_info,windows,MagickFalse,
12137 "Help Viewer - Image Rotation",ImageRotateHelp);
12138 (void) XSetFunction(display,windows->image.highlight_context,
12139 GXinvert);
12140 break;
12141 }
12142 default:
12143 {
12144 (void) XBell(display,0);
12145 break;
12146 }
12147 }
12148 break;
12149 }
12150 case MotionNotify:
12151 {
12152 rotate_info.x1=event.xmotion.x;
12153 rotate_info.y1=event.xmotion.y;
12154 }
12155 }
12156 rotate_info.x2=rotate_info.x1;
12157 rotate_info.y2=rotate_info.y1;
12158 if (direction == HorizontalRotateCommand)
12159 rotate_info.x2+=32;
12160 else
12161 rotate_info.y2-=32;
12162 } while ((state & ExitState) == 0);
12163 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12164 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12165 if ((state & EscapeState) != 0)
12166 return(MagickTrue);
12167 /*
12168 Draw line as pointer moves until the mouse button is released.
12169 */
12170 distance=0;
12171 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12172 state=DefaultState;
12173 do
12174 {
12175 if (distance > 9)
12176 {
12177 /*
12178 Display info and draw rotation line.
12179 */
12180 if (windows->info.mapped == MagickFalse)
12181 (void) XMapWindow(display,windows->info.id);
12182 (void) FormatLocaleString(text,MaxTextExtent," %g",
12183 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12184 XInfoWidget(display,windows,text);
12185 XHighlightLine(display,windows->image.id,
12186 windows->image.highlight_context,&rotate_info);
12187 }
12188 else
12189 if (windows->info.mapped != MagickFalse)
12190 (void) XWithdrawWindow(display,windows->info.id,
12191 windows->info.screen);
12192 /*
12193 Wait for next event.
12194 */
12195 XScreenEvent(display,windows,&event);
12196 if (distance > 9)
12197 XHighlightLine(display,windows->image.id,
12198 windows->image.highlight_context,&rotate_info);
12199 switch (event.type)
12200 {
12201 case ButtonPress:
12202 break;
12203 case ButtonRelease:
12204 {
12205 /*
12206 User has committed to rotation line.
12207 */
12208 rotate_info.x2=event.xbutton.x;
12209 rotate_info.y2=event.xbutton.y;
12210 state|=ExitState;
12211 break;
12212 }
12213 case Expose:
12214 break;
12215 case MotionNotify:
12216 {
12217 rotate_info.x2=event.xmotion.x;
12218 rotate_info.y2=event.xmotion.y;
12219 }
12220 default:
12221 break;
12222 }
12223 /*
12224 Check boundary conditions.
12225 */
12226 if (rotate_info.x2 < 0)
12227 rotate_info.x2=0;
12228 else
12229 if (rotate_info.x2 > (int) windows->image.width)
12230 rotate_info.x2=(short) windows->image.width;
12231 if (rotate_info.y2 < 0)
12232 rotate_info.y2=0;
12233 else
12234 if (rotate_info.y2 > (int) windows->image.height)
12235 rotate_info.y2=(short) windows->image.height;
12236 /*
12237 Compute rotation angle from the slope of the line.
12238 */
12239 degrees=0.0;
12240 distance=(unsigned int)
12241 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12242 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12243 if (distance > 9)
12244 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12245 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12246 } while ((state & ExitState) == 0);
12247 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12248 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12249 if (distance <= 9)
12250 return(MagickTrue);
12251 }
12252 if (direction == VerticalRotateCommand)
12253 degrees-=90.0;
12254 if (degrees == 0.0)
12255 return(MagickTrue);
12256 /*
12257 Rotate image.
12258 */
12259 normalized_degrees=degrees;
12260 while (normalized_degrees < -45.0)
12261 normalized_degrees+=360.0;
12262 for (rotations=0; normalized_degrees > 45.0; rotations++)
12263 normalized_degrees-=90.0;
12264 if (normalized_degrees != 0.0)
12265 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12266 XSetCursorState(display,windows,MagickTrue);
12267 XCheckRefreshWindows(display,windows);
12268 (*image)->background_color.red=ScaleShortToQuantum(
12269 windows->pixel_info->pen_colors[pen_id].red);
12270 (*image)->background_color.green=ScaleShortToQuantum(
12271 windows->pixel_info->pen_colors[pen_id].green);
12272 (*image)->background_color.blue=ScaleShortToQuantum(
12273 windows->pixel_info->pen_colors[pen_id].blue);
12274 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12275 XSetCursorState(display,windows,MagickFalse);
12276 if (rotate_image == (Image *) NULL)
12277 return(MagickFalse);
12278 *image=DestroyImage(*image);
12279 *image=rotate_image;
12280 if (windows->image.crop_geometry != (char *) NULL)
12281 {
12282 /*
12283 Rotate crop geometry.
12284 */
12285 width=(unsigned int) (*image)->columns;
12286 height=(unsigned int) (*image)->rows;
12287 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12288 switch (rotations % 4)
12289 {
12290 default:
12291 case 0:
12292 break;
12293 case 1:
12294 {
12295 /*
12296 Rotate 90 degrees.
12297 */
12298 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12299 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12300 (int) height-y,x);
12301 break;
12302 }
12303 case 2:
12304 {
12305 /*
12306 Rotate 180 degrees.
12307 */
12308 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12309 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12310 break;
12311 }
12312 case 3:
12313 {
12314 /*
12315 Rotate 270 degrees.
12316 */
12317 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12318 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12319 break;
12320 }
12321 }
12322 }
12323 if (windows->image.orphan != MagickFalse)
12324 return(MagickTrue);
12325 if (normalized_degrees != 0.0)
12326 {
12327 /*
12328 Update image colormap.
12329 */
12330 windows->image.window_changes.width=(int) (*image)->columns;
12331 windows->image.window_changes.height=(int) (*image)->rows;
12332 if (windows->image.crop_geometry != (char *) NULL)
12333 {
12334 /*
12335 Obtain dimensions of image from crop geometry.
12336 */
12337 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12338 &width,&height);
12339 windows->image.window_changes.width=(int) width;
12340 windows->image.window_changes.height=(int) height;
12341 }
12342 XConfigureImageColormap(display,resource_info,windows,*image);
12343 }
12344 else
12345 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12346 {
12347 windows->image.window_changes.width=windows->image.ximage->height;
12348 windows->image.window_changes.height=windows->image.ximage->width;
12349 }
12350 /*
12351 Update image configuration.
12352 */
12353 (void) XConfigureImage(display,resource_info,windows,*image);
12354 return(MagickTrue);
12355 }
12356
12357 /*
12358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12359 % %
12360 % %
12361 % %
12362 + X S a v e I m a g e %
12363 % %
12364 % %
12365 % %
12366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12367 %
12368 % XSaveImage() saves an image to a file.
12369 %
12370 % The format of the XSaveImage method is:
12371 %
12372 % MagickBooleanType XSaveImage(Display *display,
12373 % XResourceInfo *resource_info,XWindows *windows,Image *image)
12374 %
12375 % A description of each parameter follows:
12376 %
12377 % o display: Specifies a connection to an X server; returned from
12378 % XOpenDisplay.
12379 %
12380 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12381 %
12382 % o windows: Specifies a pointer to a XWindows structure.
12383 %
12384 % o image: the image.
12385 %
12386 */
XSaveImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)12387 static MagickBooleanType XSaveImage(Display *display,
12388 XResourceInfo *resource_info,XWindows *windows,Image *image)
12389 {
12390 char
12391 filename[MaxTextExtent],
12392 geometry[MaxTextExtent];
12393
12394 Image
12395 *save_image;
12396
12397 ImageInfo
12398 *image_info;
12399
12400 MagickStatusType
12401 status;
12402
12403 /*
12404 Request file name from user.
12405 */
12406 if (resource_info->write_filename != (char *) NULL)
12407 (void) CopyMagickString(filename,resource_info->write_filename,
12408 MaxTextExtent);
12409 else
12410 {
12411 char
12412 path[MaxTextExtent];
12413
12414 int
12415 status;
12416
12417 GetPathComponent(image->filename,HeadPath,path);
12418 GetPathComponent(image->filename,TailPath,filename);
12419 if (*path != '\0')
12420 {
12421 status=chdir(path);
12422 if (status == -1)
12423 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12424 FileOpenError,"UnableToOpenFile","%s",path);
12425 }
12426 }
12427 XFileBrowserWidget(display,windows,"Save",filename);
12428 if (*filename == '\0')
12429 return(MagickTrue);
12430 if (IsPathAccessible(filename) != MagickFalse)
12431 {
12432 int
12433 status;
12434
12435 /*
12436 File exists-- seek user's permission before overwriting.
12437 */
12438 status=XConfirmWidget(display,windows,"Overwrite",filename);
12439 if (status <= 0)
12440 return(MagickTrue);
12441 }
12442 image_info=CloneImageInfo(resource_info->image_info);
12443 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12444 (void) SetImageInfo(image_info,1,&image->exception);
12445 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12446 (LocaleCompare(image_info->magick,"JPG") == 0))
12447 {
12448 char
12449 quality[MaxTextExtent];
12450
12451 int
12452 status;
12453
12454 /*
12455 Request JPEG quality from user.
12456 */
12457 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
12458 image->quality);
12459 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12460 quality);
12461 if (*quality == '\0')
12462 return(MagickTrue);
12463 image->quality=StringToUnsignedLong(quality);
12464 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12465 }
12466 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12467 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12468 (LocaleCompare(image_info->magick,"PS") == 0) ||
12469 (LocaleCompare(image_info->magick,"PS2") == 0))
12470 {
12471 char
12472 geometry[MaxTextExtent];
12473
12474 const char
12475 *const PageSizes[] =
12476 {
12477 "Letter",
12478 "Tabloid",
12479 "Ledger",
12480 "Legal",
12481 "Statement",
12482 "Executive",
12483 "A3",
12484 "A4",
12485 "A5",
12486 "B4",
12487 "B5",
12488 "Folio",
12489 "Quarto",
12490 "10x14",
12491 (char *) NULL
12492 };
12493
12494 /*
12495 Request page geometry from user.
12496 */
12497 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12498 if (LocaleCompare(image_info->magick,"PDF") == 0)
12499 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12500 if (image_info->page != (char *) NULL)
12501 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12502 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12503 "Select page geometry:",geometry);
12504 if (*geometry != '\0')
12505 image_info->page=GetPageGeometry(geometry);
12506 }
12507 /*
12508 Apply image transforms.
12509 */
12510 XSetCursorState(display,windows,MagickTrue);
12511 XCheckRefreshWindows(display,windows);
12512 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12513 if (save_image == (Image *) NULL)
12514 return(MagickFalse);
12515 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
12516 windows->image.ximage->width,windows->image.ximage->height);
12517 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12518 /*
12519 Write image.
12520 */
12521 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12522 status=WriteImage(image_info,save_image);
12523 if (status != MagickFalse)
12524 image->taint=MagickFalse;
12525 save_image=DestroyImage(save_image);
12526 image_info=DestroyImageInfo(image_info);
12527 XSetCursorState(display,windows,MagickFalse);
12528 return(status != 0 ? MagickTrue : MagickFalse);
12529 }
12530
12531 /*
12532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12533 % %
12534 % %
12535 % %
12536 + X S c r e e n E v e n t %
12537 % %
12538 % %
12539 % %
12540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12541 %
12542 % XScreenEvent() handles global events associated with the Pan and Magnify
12543 % windows.
12544 %
12545 % The format of the XScreenEvent function is:
12546 %
12547 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12548 %
12549 % A description of each parameter follows:
12550 %
12551 % o display: Specifies a pointer to the Display structure; returned from
12552 % XOpenDisplay.
12553 %
12554 % o windows: Specifies a pointer to a XWindows structure.
12555 %
12556 % o event: Specifies a pointer to a X11 XEvent structure.
12557 %
12558 %
12559 */
12560
12561 #if defined(__cplusplus) || defined(c_plusplus)
12562 extern "C" {
12563 #endif
12564
XPredicate(Display * magick_unused (display),XEvent * event,char * data)12565 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12566 {
12567 XWindows
12568 *windows;
12569
12570 magick_unreferenced(display);
12571
12572 windows=(XWindows *) data;
12573 if ((event->type == ClientMessage) &&
12574 (event->xclient.window == windows->image.id))
12575 return(MagickFalse);
12576 return(MagickTrue);
12577 }
12578
12579 #if defined(__cplusplus) || defined(c_plusplus)
12580 }
12581 #endif
12582
XScreenEvent(Display * display,XWindows * windows,XEvent * event)12583 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12584 {
12585 int
12586 x,
12587 y;
12588
12589 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12590 if (event->xany.window == windows->command.id)
12591 return;
12592 switch (event->type)
12593 {
12594 case ButtonPress:
12595 case ButtonRelease:
12596 {
12597 if ((event->xbutton.button == Button3) &&
12598 (event->xbutton.state & Mod1Mask))
12599 {
12600 /*
12601 Convert Alt-Button3 to Button2.
12602 */
12603 event->xbutton.button=Button2;
12604 event->xbutton.state&=(~Mod1Mask);
12605 }
12606 if (event->xbutton.window == windows->backdrop.id)
12607 {
12608 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12609 event->xbutton.time);
12610 break;
12611 }
12612 if (event->xbutton.window == windows->pan.id)
12613 {
12614 XPanImage(display,windows,event);
12615 break;
12616 }
12617 if (event->xbutton.window == windows->image.id)
12618 if (event->xbutton.button == Button2)
12619 {
12620 /*
12621 Update magnified image.
12622 */
12623 x=event->xbutton.x;
12624 y=event->xbutton.y;
12625 if (x < 0)
12626 x=0;
12627 else
12628 if (x >= (int) windows->image.width)
12629 x=(int) (windows->image.width-1);
12630 windows->magnify.x=(int) windows->image.x+x;
12631 if (y < 0)
12632 y=0;
12633 else
12634 if (y >= (int) windows->image.height)
12635 y=(int) (windows->image.height-1);
12636 windows->magnify.y=windows->image.y+y;
12637 if (windows->magnify.mapped == MagickFalse)
12638 (void) XMapRaised(display,windows->magnify.id);
12639 XMakeMagnifyImage(display,windows);
12640 if (event->type == ButtonRelease)
12641 (void) XWithdrawWindow(display,windows->info.id,
12642 windows->info.screen);
12643 break;
12644 }
12645 break;
12646 }
12647 case ClientMessage:
12648 {
12649 /*
12650 If client window delete message, exit.
12651 */
12652 if (event->xclient.message_type != windows->wm_protocols)
12653 break;
12654 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12655 break;
12656 if (event->xclient.window == windows->magnify.id)
12657 {
12658 (void) XWithdrawWindow(display,windows->magnify.id,
12659 windows->magnify.screen);
12660 break;
12661 }
12662 break;
12663 }
12664 case ConfigureNotify:
12665 {
12666 if (event->xconfigure.window == windows->magnify.id)
12667 {
12668 unsigned int
12669 magnify;
12670
12671 /*
12672 Magnify window has a new configuration.
12673 */
12674 windows->magnify.width=(unsigned int) event->xconfigure.width;
12675 windows->magnify.height=(unsigned int) event->xconfigure.height;
12676 if (windows->magnify.mapped == MagickFalse)
12677 break;
12678 magnify=1;
12679 while ((int) magnify <= event->xconfigure.width)
12680 magnify<<=1;
12681 while ((int) magnify <= event->xconfigure.height)
12682 magnify<<=1;
12683 magnify>>=1;
12684 if (((int) magnify != event->xconfigure.width) ||
12685 ((int) magnify != event->xconfigure.height))
12686 {
12687 XWindowChanges
12688 window_changes;
12689
12690 window_changes.width=(int) magnify;
12691 window_changes.height=(int) magnify;
12692 (void) XReconfigureWMWindow(display,windows->magnify.id,
12693 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12694 &window_changes);
12695 break;
12696 }
12697 XMakeMagnifyImage(display,windows);
12698 break;
12699 }
12700 break;
12701 }
12702 case Expose:
12703 {
12704 if (event->xexpose.window == windows->image.id)
12705 {
12706 XRefreshWindow(display,&windows->image,event);
12707 break;
12708 }
12709 if (event->xexpose.window == windows->pan.id)
12710 if (event->xexpose.count == 0)
12711 {
12712 XDrawPanRectangle(display,windows);
12713 break;
12714 }
12715 if (event->xexpose.window == windows->magnify.id)
12716 if (event->xexpose.count == 0)
12717 {
12718 XMakeMagnifyImage(display,windows);
12719 break;
12720 }
12721 break;
12722 }
12723 case KeyPress:
12724 {
12725 char
12726 command[MaxTextExtent];
12727
12728 KeySym
12729 key_symbol;
12730
12731 if (event->xkey.window != windows->magnify.id)
12732 break;
12733 /*
12734 Respond to a user key press.
12735 */
12736 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12737 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12738 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12739 break;
12740 }
12741 case MapNotify:
12742 {
12743 if (event->xmap.window == windows->magnify.id)
12744 {
12745 windows->magnify.mapped=MagickTrue;
12746 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12747 break;
12748 }
12749 if (event->xmap.window == windows->info.id)
12750 {
12751 windows->info.mapped=MagickTrue;
12752 break;
12753 }
12754 break;
12755 }
12756 case MotionNotify:
12757 {
12758 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12759 if (event->xmotion.window == windows->image.id)
12760 if (windows->magnify.mapped != MagickFalse)
12761 {
12762 /*
12763 Update magnified image.
12764 */
12765 x=event->xmotion.x;
12766 y=event->xmotion.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 XMakeMagnifyImage(display,windows);
12780 }
12781 break;
12782 }
12783 case UnmapNotify:
12784 {
12785 if (event->xunmap.window == windows->magnify.id)
12786 {
12787 windows->magnify.mapped=MagickFalse;
12788 break;
12789 }
12790 if (event->xunmap.window == windows->info.id)
12791 {
12792 windows->info.mapped=MagickFalse;
12793 break;
12794 }
12795 break;
12796 }
12797 default:
12798 break;
12799 }
12800 }
12801
12802 /*
12803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12804 % %
12805 % %
12806 % %
12807 + X S e t C r o p G e o m e t r y %
12808 % %
12809 % %
12810 % %
12811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12812 %
12813 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12814 % and translates it to a cropping geometry relative to the image.
12815 %
12816 % The format of the XSetCropGeometry method is:
12817 %
12818 % void XSetCropGeometry(Display *display,XWindows *windows,
12819 % RectangleInfo *crop_info,Image *image)
12820 %
12821 % A description of each parameter follows:
12822 %
12823 % o display: Specifies a connection to an X server; returned from
12824 % XOpenDisplay.
12825 %
12826 % o windows: Specifies a pointer to a XWindows structure.
12827 %
12828 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12829 % Image window to crop.
12830 %
12831 % o image: the image.
12832 %
12833 */
XSetCropGeometry(Display * display,XWindows * windows,RectangleInfo * crop_info,Image * image)12834 static void XSetCropGeometry(Display *display,XWindows *windows,
12835 RectangleInfo *crop_info,Image *image)
12836 {
12837 char
12838 text[MaxTextExtent];
12839
12840 int
12841 x,
12842 y;
12843
12844 MagickRealType
12845 scale_factor;
12846
12847 unsigned int
12848 height,
12849 width;
12850
12851 if (windows->info.mapped != MagickFalse)
12852 {
12853 /*
12854 Display info on cropping rectangle.
12855 */
12856 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12857 (double) crop_info->width,(double) crop_info->height,(double)
12858 crop_info->x,(double) crop_info->y);
12859 XInfoWidget(display,windows,text);
12860 }
12861 /*
12862 Cropping geometry is relative to any previous crop geometry.
12863 */
12864 x=0;
12865 y=0;
12866 width=(unsigned int) image->columns;
12867 height=(unsigned int) image->rows;
12868 if (windows->image.crop_geometry != (char *) NULL)
12869 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12870 else
12871 windows->image.crop_geometry=AcquireString((char *) NULL);
12872 /*
12873 Define the crop geometry string from the cropping rectangle.
12874 */
12875 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12876 if (crop_info->x > 0)
12877 x+=(int) (scale_factor*crop_info->x+0.5);
12878 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12879 if (width == 0)
12880 width=1;
12881 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12882 if (crop_info->y > 0)
12883 y+=(int) (scale_factor*crop_info->y+0.5);
12884 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12885 if (height == 0)
12886 height=1;
12887 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12888 "%ux%u%+d%+d",width,height,x,y);
12889 }
12890
12891 /*
12892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12893 % %
12894 % %
12895 % %
12896 + X T i l e I m a g e %
12897 % %
12898 % %
12899 % %
12900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12901 %
12902 % XTileImage() loads or deletes a selected tile from a visual image directory.
12903 % The load or delete command is chosen from a menu.
12904 %
12905 % The format of the XTileImage method is:
12906 %
12907 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
12908 % XWindows *windows,Image *image,XEvent *event)
12909 %
12910 % A description of each parameter follows:
12911 %
12912 % o tile_image: XTileImage reads or deletes the tile image
12913 % and returns it. A null image is returned if an error occurs.
12914 %
12915 % o display: Specifies a connection to an X server; returned from
12916 % XOpenDisplay.
12917 %
12918 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12919 %
12920 % o windows: Specifies a pointer to a XWindows structure.
12921 %
12922 % o image: the image; returned from ReadImage.
12923 %
12924 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
12925 % the entire image is refreshed.
12926 %
12927 */
XTileImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,XEvent * event)12928 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12929 XWindows *windows,Image *image,XEvent *event)
12930 {
12931 const char
12932 *const VerbMenu[] =
12933 {
12934 "Load",
12935 "Next",
12936 "Former",
12937 "Delete",
12938 "Update",
12939 (char *) NULL,
12940 };
12941
12942 static const ModeType
12943 TileCommands[] =
12944 {
12945 TileLoadCommand,
12946 TileNextCommand,
12947 TileFormerCommand,
12948 TileDeleteCommand,
12949 TileUpdateCommand
12950 };
12951
12952 char
12953 command[MaxTextExtent],
12954 filename[MaxTextExtent];
12955
12956 Image
12957 *tile_image;
12958
12959 int
12960 id,
12961 status,
12962 tile,
12963 x,
12964 y;
12965
12966 MagickRealType
12967 scale_factor;
12968
12969 char
12970 *p,
12971 *q;
12972
12973 int
12974 i;
12975
12976 unsigned int
12977 height,
12978 width;
12979
12980 /*
12981 Tile image is relative to montage image configuration.
12982 */
12983 x=0;
12984 y=0;
12985 width=(unsigned int) image->columns;
12986 height=(unsigned int) image->rows;
12987 if (windows->image.crop_geometry != (char *) NULL)
12988 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12989 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12990 event->xbutton.x+=windows->image.x;
12991 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
12992 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12993 event->xbutton.y+=windows->image.y;
12994 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
12995 /*
12996 Determine size and location of each tile in the visual image directory.
12997 */
12998 width=(unsigned int) image->columns;
12999 height=(unsigned int) image->rows;
13000 x=0;
13001 y=0;
13002 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13003 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13004 (event->xbutton.x-x)/width;
13005 if (tile < 0)
13006 {
13007 /*
13008 Button press is outside any tile.
13009 */
13010 (void) XBell(display,0);
13011 return((Image *) NULL);
13012 }
13013 /*
13014 Determine file name from the tile directory.
13015 */
13016 p=image->directory;
13017 for (i=tile; (i != 0) && (*p != '\0'); )
13018 {
13019 if (*p == '\xff')
13020 i--;
13021 p++;
13022 }
13023 if (*p == '\0')
13024 {
13025 /*
13026 Button press is outside any tile.
13027 */
13028 (void) XBell(display,0);
13029 return((Image *) NULL);
13030 }
13031 /*
13032 Select a command from the pop-up menu.
13033 */
13034 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13035 if (id < 0)
13036 return((Image *) NULL);
13037 q=p;
13038 while ((*q != '\xff') && (*q != '\0'))
13039 q++;
13040 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13041 /*
13042 Perform command for the selected tile.
13043 */
13044 XSetCursorState(display,windows,MagickTrue);
13045 XCheckRefreshWindows(display,windows);
13046 tile_image=NewImageList();
13047 switch (TileCommands[id])
13048 {
13049 case TileLoadCommand:
13050 {
13051 /*
13052 Load tile image.
13053 */
13054 XCheckRefreshWindows(display,windows);
13055 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13056 MaxTextExtent);
13057 (void) CopyMagickString(resource_info->image_info->filename,filename,
13058 MaxTextExtent);
13059 tile_image=ReadImage(resource_info->image_info,&image->exception);
13060 CatchException(&image->exception);
13061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13062 break;
13063 }
13064 case TileNextCommand:
13065 {
13066 /*
13067 Display next image.
13068 */
13069 XClientMessage(display,windows->image.id,windows->im_protocols,
13070 windows->im_next_image,CurrentTime);
13071 break;
13072 }
13073 case TileFormerCommand:
13074 {
13075 /*
13076 Display former image.
13077 */
13078 XClientMessage(display,windows->image.id,windows->im_protocols,
13079 windows->im_former_image,CurrentTime);
13080 break;
13081 }
13082 case TileDeleteCommand:
13083 {
13084 /*
13085 Delete tile image.
13086 */
13087 if (IsPathAccessible(filename) == MagickFalse)
13088 {
13089 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13090 break;
13091 }
13092 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13093 if (status <= 0)
13094 break;
13095 status=ShredFile(filename);
13096 if (status != MagickFalse)
13097 {
13098 XNoticeWidget(display,windows,"Unable to delete image file:",
13099 filename);
13100 break;
13101 }
13102 }
13103 case TileUpdateCommand:
13104 {
13105 ExceptionInfo
13106 *exception;
13107
13108 int
13109 x_offset,
13110 y_offset;
13111
13112 PixelPacket
13113 pixel;
13114
13115 int
13116 j;
13117
13118 PixelPacket
13119 *s;
13120
13121 /*
13122 Ensure all the images exist.
13123 */
13124 tile=0;
13125 for (p=image->directory; *p != '\0'; p++)
13126 {
13127 CacheView
13128 *image_view;
13129
13130 q=p;
13131 while ((*q != '\xff') && (*q != '\0'))
13132 q++;
13133 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13134 p=q;
13135 if (IsPathAccessible(filename) != MagickFalse)
13136 {
13137 tile++;
13138 continue;
13139 }
13140 /*
13141 Overwrite tile with background color.
13142 */
13143 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13144 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13145 exception=(&image->exception);
13146 image_view=AcquireAuthenticCacheView(image,exception);
13147 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13148 for (i=0; i < (int) height; i++)
13149 {
13150 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13151 y_offset+i,width,1,exception);
13152 if (s == (PixelPacket *) NULL)
13153 break;
13154 for (j=0; j < (int) width; j++)
13155 *s++=pixel;
13156 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13157 break;
13158 }
13159 image_view=DestroyCacheView(image_view);
13160 tile++;
13161 }
13162 windows->image.window_changes.width=(int) image->columns;
13163 windows->image.window_changes.height=(int) image->rows;
13164 XConfigureImageColormap(display,resource_info,windows,image);
13165 (void) XConfigureImage(display,resource_info,windows,image);
13166 break;
13167 }
13168 default:
13169 break;
13170 }
13171 XSetCursorState(display,windows,MagickFalse);
13172 return(tile_image);
13173 }
13174
13175 /*
13176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13177 % %
13178 % %
13179 % %
13180 + X T r a n s l a t e I m a g e %
13181 % %
13182 % %
13183 % %
13184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13185 %
13186 % XTranslateImage() translates the image within an Image window by one pixel
13187 % as specified by the key symbol. If the image has a `montage string the
13188 % translation is respect to the width and height contained within the string.
13189 %
13190 % The format of the XTranslateImage method is:
13191 %
13192 % void XTranslateImage(Display *display,XWindows *windows,
13193 % Image *image,const KeySym key_symbol)
13194 %
13195 % A description of each parameter follows:
13196 %
13197 % o display: Specifies a connection to an X server; returned from
13198 % XOpenDisplay.
13199 %
13200 % o windows: Specifies a pointer to a XWindows structure.
13201 %
13202 % o image: the image.
13203 %
13204 % o key_symbol: Specifies a KeySym which indicates which side of the image
13205 % to trim.
13206 %
13207 */
XTranslateImage(Display * display,XWindows * windows,Image * image,const KeySym key_symbol)13208 static void XTranslateImage(Display *display,XWindows *windows,
13209 Image *image,const KeySym key_symbol)
13210 {
13211 char
13212 text[MaxTextExtent];
13213
13214 int
13215 x,
13216 y;
13217
13218 unsigned int
13219 x_offset,
13220 y_offset;
13221
13222 /*
13223 User specified a pan position offset.
13224 */
13225 x_offset=windows->image.width;
13226 y_offset=windows->image.height;
13227 if (image->montage != (char *) NULL)
13228 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13229 switch ((int) key_symbol)
13230 {
13231 case XK_Home:
13232 case XK_KP_Home:
13233 {
13234 windows->image.x=(int) windows->image.width/2;
13235 windows->image.y=(int) windows->image.height/2;
13236 break;
13237 }
13238 case XK_Left:
13239 case XK_KP_Left:
13240 {
13241 windows->image.x-=x_offset;
13242 break;
13243 }
13244 case XK_Next:
13245 case XK_Up:
13246 case XK_KP_Up:
13247 {
13248 windows->image.y-=y_offset;
13249 break;
13250 }
13251 case XK_Right:
13252 case XK_KP_Right:
13253 {
13254 windows->image.x+=x_offset;
13255 break;
13256 }
13257 case XK_Prior:
13258 case XK_Down:
13259 case XK_KP_Down:
13260 {
13261 windows->image.y+=y_offset;
13262 break;
13263 }
13264 default:
13265 return;
13266 }
13267 /*
13268 Check boundary conditions.
13269 */
13270 if (windows->image.x < 0)
13271 windows->image.x=0;
13272 else
13273 if ((int) (windows->image.x+windows->image.width) >
13274 windows->image.ximage->width)
13275 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13276 if (windows->image.y < 0)
13277 windows->image.y=0;
13278 else
13279 if ((int) (windows->image.y+windows->image.height) >
13280 windows->image.ximage->height)
13281 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13282 /*
13283 Refresh Image window.
13284 */
13285 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
13286 windows->image.width,windows->image.height,windows->image.x,
13287 windows->image.y);
13288 XInfoWidget(display,windows,text);
13289 XCheckRefreshWindows(display,windows);
13290 XDrawPanRectangle(display,windows);
13291 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13292 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13293 }
13294
13295 /*
13296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13297 % %
13298 % %
13299 % %
13300 + X T r i m I m a g e %
13301 % %
13302 % %
13303 % %
13304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13305 %
13306 % XTrimImage() trims the edges from the Image window.
13307 %
13308 % The format of the XTrimImage method is:
13309 %
13310 % MagickBooleanType XTrimImage(Display *display,
13311 % XResourceInfo *resource_info,XWindows *windows,Image *image)
13312 %
13313 % A description of each parameter follows:
13314 %
13315 % o display: Specifies a connection to an X server; returned from
13316 % XOpenDisplay.
13317 %
13318 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13319 %
13320 % o windows: Specifies a pointer to a XWindows structure.
13321 %
13322 % o image: the image.
13323 %
13324 */
XTrimImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image)13325 static MagickBooleanType XTrimImage(Display *display,
13326 XResourceInfo *resource_info,XWindows *windows,Image *image)
13327 {
13328 RectangleInfo
13329 trim_info;
13330
13331 int
13332 x,
13333 y;
13334
13335 size_t
13336 background,
13337 pixel;
13338
13339 /*
13340 Trim edges from image.
13341 */
13342 XSetCursorState(display,windows,MagickTrue);
13343 XCheckRefreshWindows(display,windows);
13344 /*
13345 Crop the left edge.
13346 */
13347 background=XGetPixel(windows->image.ximage,0,0);
13348 trim_info.width=(size_t) windows->image.ximage->width;
13349 for (x=0; x < windows->image.ximage->width; x++)
13350 {
13351 for (y=0; y < windows->image.ximage->height; y++)
13352 {
13353 pixel=XGetPixel(windows->image.ximage,x,y);
13354 if (pixel != background)
13355 break;
13356 }
13357 if (y < windows->image.ximage->height)
13358 break;
13359 }
13360 trim_info.x=(ssize_t) x;
13361 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13362 {
13363 XSetCursorState(display,windows,MagickFalse);
13364 return(MagickFalse);
13365 }
13366 /*
13367 Crop the right edge.
13368 */
13369 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13370 for (x=windows->image.ximage->width-1; x != 0; x--)
13371 {
13372 for (y=0; y < windows->image.ximage->height; y++)
13373 {
13374 pixel=XGetPixel(windows->image.ximage,x,y);
13375 if (pixel != background)
13376 break;
13377 }
13378 if (y < windows->image.ximage->height)
13379 break;
13380 }
13381 trim_info.width=(size_t) (x-trim_info.x+1);
13382 /*
13383 Crop the top edge.
13384 */
13385 background=XGetPixel(windows->image.ximage,0,0);
13386 trim_info.height=(size_t) windows->image.ximage->height;
13387 for (y=0; y < windows->image.ximage->height; y++)
13388 {
13389 for (x=0; x < windows->image.ximage->width; x++)
13390 {
13391 pixel=XGetPixel(windows->image.ximage,x,y);
13392 if (pixel != background)
13393 break;
13394 }
13395 if (x < windows->image.ximage->width)
13396 break;
13397 }
13398 trim_info.y=(ssize_t) y;
13399 /*
13400 Crop the bottom edge.
13401 */
13402 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13403 for (y=windows->image.ximage->height-1; y != 0; y--)
13404 {
13405 for (x=0; x < windows->image.ximage->width; x++)
13406 {
13407 pixel=XGetPixel(windows->image.ximage,x,y);
13408 if (pixel != background)
13409 break;
13410 }
13411 if (x < windows->image.ximage->width)
13412 break;
13413 }
13414 trim_info.height=(size_t) y-trim_info.y+1;
13415 if (((unsigned int) trim_info.width != windows->image.width) ||
13416 ((unsigned int) trim_info.height != windows->image.height))
13417 {
13418 /*
13419 Reconfigure Image window as defined by the trimming rectangle.
13420 */
13421 XSetCropGeometry(display,windows,&trim_info,image);
13422 windows->image.window_changes.width=(int) trim_info.width;
13423 windows->image.window_changes.height=(int) trim_info.height;
13424 (void) XConfigureImage(display,resource_info,windows,image);
13425 }
13426 XSetCursorState(display,windows,MagickFalse);
13427 return(MagickTrue);
13428 }
13429
13430 /*
13431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13432 % %
13433 % %
13434 % %
13435 + X V i s u a l D i r e c t o r y I m a g e %
13436 % %
13437 % %
13438 % %
13439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13440 %
13441 % XVisualDirectoryImage() creates a Visual Image Directory.
13442 %
13443 % The format of the XVisualDirectoryImage method is:
13444 %
13445 % Image *XVisualDirectoryImage(Display *display,
13446 % XResourceInfo *resource_info,XWindows *windows)
13447 %
13448 % A description of each parameter follows:
13449 %
13450 % o nexus: Method XVisualDirectoryImage returns a visual image
13451 % directory if it can be created successfully. Otherwise a null image
13452 % is returned.
13453 %
13454 % o display: Specifies a connection to an X server; returned from
13455 % XOpenDisplay.
13456 %
13457 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13458 %
13459 % o windows: Specifies a pointer to a XWindows structure.
13460 %
13461 */
XVisualDirectoryImage(Display * display,XResourceInfo * resource_info,XWindows * windows)13462 static Image *XVisualDirectoryImage(Display *display,
13463 XResourceInfo *resource_info,XWindows *windows)
13464 {
13465 #define TileImageTag "Scale/Image"
13466 #define XClientName "montage"
13467
13468 char
13469 **filelist;
13470
13471 ExceptionInfo
13472 *exception;
13473
13474 Image
13475 *images,
13476 *montage_image,
13477 *next_image,
13478 *thumbnail_image;
13479
13480 ImageInfo
13481 *read_info;
13482
13483 int
13484 number_files;
13485
13486 MagickBooleanType
13487 backdrop;
13488
13489 MagickStatusType
13490 status;
13491
13492 MontageInfo
13493 *montage_info;
13494
13495 RectangleInfo
13496 geometry;
13497
13498 int
13499 i;
13500
13501 static char
13502 filename[MaxTextExtent] = "\0",
13503 filenames[MaxTextExtent] = "*";
13504
13505 XResourceInfo
13506 background_resources;
13507
13508 /*
13509 Request file name from user.
13510 */
13511 XFileBrowserWidget(display,windows,"Directory",filenames);
13512 if (*filenames == '\0')
13513 return((Image *) NULL);
13514 /*
13515 Expand the filenames.
13516 */
13517 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13518 if (filelist == (char **) NULL)
13519 {
13520 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13521 filenames);
13522 return((Image *) NULL);
13523 }
13524 number_files=1;
13525 filelist[0]=filenames;
13526 status=ExpandFilenames(&number_files,&filelist);
13527 if ((status == MagickFalse) || (number_files == 0))
13528 {
13529 if (number_files == 0)
13530 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13531 else
13532 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13533 filenames);
13534 return((Image *) NULL);
13535 }
13536 /*
13537 Set image background resources.
13538 */
13539 background_resources=(*resource_info);
13540 background_resources.window_id=AcquireString("");
13541 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
13542 "0x%lx",windows->image.id);
13543 background_resources.backdrop=MagickTrue;
13544 /*
13545 Read each image and convert them to a tile.
13546 */
13547 backdrop=(windows->visual_info->klass == TrueColor) ||
13548 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13549 read_info=CloneImageInfo(resource_info->image_info);
13550 (void) SetImageOption(read_info,"jpeg:size","120x120");
13551 (void) CloneString(&read_info->size,DefaultTileGeometry);
13552 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13553 (void *) NULL);
13554 images=NewImageList();
13555 exception=AcquireExceptionInfo();
13556 XSetCursorState(display,windows,MagickTrue);
13557 XCheckRefreshWindows(display,windows);
13558 for (i=0; i < (int) number_files; i++)
13559 {
13560 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13561 filelist[i]=DestroyString(filelist[i]);
13562 *read_info->magick='\0';
13563 next_image=ReadImage(read_info,exception);
13564 CatchException(exception);
13565 if (next_image != (Image *) NULL)
13566 {
13567 (void) DeleteImageProperty(next_image,"label");
13568 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13569 read_info,next_image,DefaultTileLabel));
13570 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13571 exception);
13572 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13573 geometry.height,exception);
13574 if (thumbnail_image != (Image *) NULL)
13575 {
13576 next_image=DestroyImage(next_image);
13577 next_image=thumbnail_image;
13578 }
13579 if (backdrop)
13580 {
13581 (void) XDisplayBackgroundImage(display,&background_resources,
13582 next_image);
13583 XSetCursorState(display,windows,MagickTrue);
13584 }
13585 AppendImageToList(&images,next_image);
13586 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13587 {
13588 MagickBooleanType
13589 proceed;
13590
13591 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13592 (MagickSizeType) number_files);
13593 if (proceed == MagickFalse)
13594 break;
13595 }
13596 }
13597 }
13598 exception=DestroyExceptionInfo(exception);
13599 filelist=(char **) RelinquishMagickMemory(filelist);
13600 if (images == (Image *) NULL)
13601 {
13602 read_info=DestroyImageInfo(read_info);
13603 XSetCursorState(display,windows,MagickFalse);
13604 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13605 return((Image *) NULL);
13606 }
13607 /*
13608 Create the Visual Image Directory.
13609 */
13610 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13611 montage_info->pointsize=10;
13612 if (resource_info->font != (char *) NULL)
13613 (void) CloneString(&montage_info->font,resource_info->font);
13614 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13615 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13616 images),&images->exception);
13617 images=DestroyImageList(images);
13618 montage_info=DestroyMontageInfo(montage_info);
13619 read_info=DestroyImageInfo(read_info);
13620 XSetCursorState(display,windows,MagickFalse);
13621 if (montage_image == (Image *) NULL)
13622 return(montage_image);
13623 XClientMessage(display,windows->image.id,windows->im_protocols,
13624 windows->im_next_image,CurrentTime);
13625 return(montage_image);
13626 }
13627
13628 /*
13629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13630 % %
13631 % %
13632 % %
13633 % X D i s p l a y B a c k g r o u n d I m a g e %
13634 % %
13635 % %
13636 % %
13637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13638 %
13639 % XDisplayBackgroundImage() displays an image in the background of a window.
13640 %
13641 % The format of the XDisplayBackgroundImage method is:
13642 %
13643 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13644 % XResourceInfo *resource_info,Image *image)
13645 %
13646 % A description of each parameter follows:
13647 %
13648 % o display: Specifies a connection to an X server; returned from
13649 % XOpenDisplay.
13650 %
13651 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13652 %
13653 % o image: the image.
13654 %
13655 */
XDisplayBackgroundImage(Display * display,XResourceInfo * resource_info,Image * image)13656 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13657 XResourceInfo *resource_info,Image *image)
13658 {
13659 char
13660 geometry[MaxTextExtent],
13661 visual_type[MaxTextExtent];
13662
13663 int
13664 height,
13665 status,
13666 width;
13667
13668 RectangleInfo
13669 geometry_info;
13670
13671 static XPixelInfo
13672 pixel;
13673
13674 static XStandardColormap
13675 *map_info;
13676
13677 static XVisualInfo
13678 *visual_info = (XVisualInfo *) NULL;
13679
13680 static XWindowInfo
13681 window_info;
13682
13683 size_t
13684 delay;
13685
13686 Window
13687 root_window;
13688
13689 XGCValues
13690 context_values;
13691
13692 XResourceInfo
13693 resources;
13694
13695 XWindowAttributes
13696 window_attributes;
13697
13698 /*
13699 Determine target window.
13700 */
13701 assert(image != (Image *) NULL);
13702 assert(image->signature == MagickCoreSignature);
13703 if (image->debug != MagickFalse)
13704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13705 resources=(*resource_info);
13706 window_info.id=(Window) NULL;
13707 root_window=XRootWindow(display,XDefaultScreen(display));
13708 if (LocaleCompare(resources.window_id,"root") == 0)
13709 window_info.id=root_window;
13710 else
13711 {
13712 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13713 window_info.id=XWindowByID(display,root_window,
13714 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13715 if (window_info.id == (Window) NULL)
13716 window_info.id=XWindowByName(display,root_window,resources.window_id);
13717 }
13718 if (window_info.id == (Window) NULL)
13719 {
13720 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13721 resources.window_id);
13722 }
13723 /*
13724 Determine window visual id.
13725 */
13726 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13727 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13728 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13729 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13730 if (status != 0)
13731 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
13732 XVisualIDFromVisual(window_attributes.visual));
13733 if (visual_info == (XVisualInfo *) NULL)
13734 {
13735 /*
13736 Allocate standard colormap.
13737 */
13738 map_info=XAllocStandardColormap();
13739 if (map_info == (XStandardColormap *) NULL)
13740 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13741 image->filename);
13742 map_info->colormap=(Colormap) NULL;
13743 pixel.pixels=(unsigned long *) NULL;
13744 /*
13745 Initialize visual info.
13746 */
13747 resources.map_type=(char *) NULL;
13748 resources.visual_type=visual_type;
13749 visual_info=XBestVisualInfo(display,map_info,&resources);
13750 if (visual_info == (XVisualInfo *) NULL)
13751 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13752 resources.visual_type);
13753 /*
13754 Initialize window info.
13755 */
13756 window_info.ximage=(XImage *) NULL;
13757 window_info.matte_image=(XImage *) NULL;
13758 window_info.pixmap=(Pixmap) NULL;
13759 window_info.matte_pixmap=(Pixmap) NULL;
13760 }
13761 /*
13762 Free previous root colors.
13763 */
13764 if (window_info.id == root_window)
13765 (void) XDestroyWindowColors(display,root_window);
13766 /*
13767 Initialize Standard Colormap.
13768 */
13769 resources.colormap=SharedColormap;
13770 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13771 /*
13772 Graphic context superclass.
13773 */
13774 context_values.background=pixel.foreground_color.pixel;
13775 context_values.foreground=pixel.background_color.pixel;
13776 pixel.annotate_context=XCreateGC(display,window_info.id,
13777 (size_t) (GCBackground | GCForeground),&context_values);
13778 if (pixel.annotate_context == (GC) NULL)
13779 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13780 image->filename);
13781 /*
13782 Initialize Image window attributes.
13783 */
13784 window_info.name=AcquireString("\0");
13785 window_info.icon_name=AcquireString("\0");
13786 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13787 &resources,&window_info);
13788 /*
13789 Create the X image.
13790 */
13791 window_info.width=(unsigned int) image->columns;
13792 window_info.height=(unsigned int) image->rows;
13793 if ((image->columns != window_info.width) ||
13794 (image->rows != window_info.height))
13795 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13796 image->filename);
13797 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
13798 window_attributes.width,window_attributes.height);
13799 geometry_info.width=window_info.width;
13800 geometry_info.height=window_info.height;
13801 geometry_info.x=(ssize_t) window_info.x;
13802 geometry_info.y=(ssize_t) window_info.y;
13803 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13804 &geometry_info.width,&geometry_info.height);
13805 window_info.width=(unsigned int) geometry_info.width;
13806 window_info.height=(unsigned int) geometry_info.height;
13807 window_info.x=(int) geometry_info.x;
13808 window_info.y=(int) geometry_info.y;
13809 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13810 window_info.height);
13811 if (status == MagickFalse)
13812 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13813 image->filename);
13814 window_info.x=0;
13815 window_info.y=0;
13816 if (image->debug != MagickFalse)
13817 {
13818 (void) LogMagickEvent(X11Event,GetMagickModule(),
13819 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13820 (double) image->columns,(double) image->rows);
13821 if (image->colors != 0)
13822 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13823 image->colors);
13824 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13825 }
13826 /*
13827 Adjust image dimensions as specified by backdrop or geometry options.
13828 */
13829 width=(int) window_info.width;
13830 height=(int) window_info.height;
13831 if (resources.backdrop != MagickFalse)
13832 {
13833 /*
13834 Center image on window.
13835 */
13836 window_info.x=(window_attributes.width/2)-(window_info.ximage->width/2);
13837 window_info.y=(window_attributes.height/2)-(window_info.ximage->height/2);
13838 width=window_attributes.width;
13839 height=window_attributes.height;
13840 }
13841 if ((resources.image_geometry != (char *) NULL) &&
13842 (*resources.image_geometry != '\0'))
13843 {
13844 char
13845 default_geometry[MaxTextExtent];
13846
13847 int
13848 flags,
13849 gravity;
13850
13851 XSizeHints
13852 *size_hints;
13853
13854 /*
13855 User specified geometry.
13856 */
13857 size_hints=XAllocSizeHints();
13858 if (size_hints == (XSizeHints *) NULL)
13859 ThrowXWindowFatalException(ResourceLimitFatalError,
13860 "MemoryAllocationFailed",image->filename);
13861 size_hints->flags=0L;
13862 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
13863 width,height);
13864 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13865 default_geometry,window_info.border_width,size_hints,&window_info.x,
13866 &window_info.y,&width,&height,&gravity);
13867 if (flags & (XValue | YValue))
13868 {
13869 width=window_attributes.width;
13870 height=window_attributes.height;
13871 }
13872 (void) XFree((void *) size_hints);
13873 }
13874 /*
13875 Create the X pixmap.
13876 */
13877 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13878 (unsigned int) height,window_info.depth);
13879 if (window_info.pixmap == (Pixmap) NULL)
13880 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13881 image->filename);
13882 /*
13883 Display pixmap on the window.
13884 */
13885 if (((unsigned int) width > window_info.width) ||
13886 ((unsigned int) height > window_info.height))
13887 (void) XFillRectangle(display,window_info.pixmap,
13888 window_info.annotate_context,0,0,(unsigned int) width,
13889 (unsigned int) height);
13890 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13891 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13892 window_info.width,(unsigned int) window_info.height);
13893 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13894 (void) XClearWindow(display,window_info.id);
13895 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13896 XDelay(display,delay == 0UL ? 10UL : delay);
13897 (void) XSync(display,MagickFalse);
13898 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13899 }
13900
13901 /*
13902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13903 % %
13904 % %
13905 % %
13906 + X D i s p l a y I m a g e %
13907 % %
13908 % %
13909 % %
13910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13911 %
13912 % XDisplayImage() displays an image via X11. A new image is created and
13913 % returned if the user interactively transforms the displayed image.
13914 %
13915 % The format of the XDisplayImage method is:
13916 %
13917 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13918 % char **argv,int argc,Image **image,size_t *state)
13919 %
13920 % A description of each parameter follows:
13921 %
13922 % o nexus: Method XDisplayImage returns an image when the
13923 % user chooses 'Open Image' from the command menu or picks a tile
13924 % from the image directory. Otherwise a null image is returned.
13925 %
13926 % o display: Specifies a connection to an X server; returned from
13927 % XOpenDisplay.
13928 %
13929 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13930 %
13931 % o argv: Specifies the application's argument list.
13932 %
13933 % o argc: Specifies the number of arguments.
13934 %
13935 % o image: Specifies an address to an address of an Image structure;
13936 %
13937 */
XDisplayImage(Display * display,XResourceInfo * resource_info,char ** argv,int argc,Image ** image,size_t * state)13938 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13939 char **argv,int argc,Image **image,size_t *state)
13940 {
13941 #define MagnifySize 256 /* must be a power of 2 */
13942 #define MagickMenus 10
13943 #define MagickTitle "Commands"
13944
13945 const char
13946 *const CommandMenu[] =
13947 {
13948 "File",
13949 "Edit",
13950 "View",
13951 "Transform",
13952 "Enhance",
13953 "Effects",
13954 "F/X",
13955 "Image Edit",
13956 "Miscellany",
13957 "Help",
13958 (char *) NULL
13959 },
13960 *const FileMenu[] =
13961 {
13962 "Open...",
13963 "Next",
13964 "Former",
13965 "Select...",
13966 "Save...",
13967 "Print...",
13968 "Delete...",
13969 "New...",
13970 "Visual Directory...",
13971 "Quit",
13972 (char *) NULL
13973 },
13974 *const EditMenu[] =
13975 {
13976 "Undo",
13977 "Redo",
13978 "Cut",
13979 "Copy",
13980 "Paste",
13981 (char *) NULL
13982 },
13983 *const ViewMenu[] =
13984 {
13985 "Half Size",
13986 "Original Size",
13987 "Double Size",
13988 "Resize...",
13989 "Apply",
13990 "Refresh",
13991 "Restore",
13992 (char *) NULL
13993 },
13994 *const TransformMenu[] =
13995 {
13996 "Crop",
13997 "Chop",
13998 "Flop",
13999 "Flip",
14000 "Rotate Right",
14001 "Rotate Left",
14002 "Rotate...",
14003 "Shear...",
14004 "Roll...",
14005 "Trim Edges",
14006 (char *) NULL
14007 },
14008 *const EnhanceMenu[] =
14009 {
14010 "Hue...",
14011 "Saturation...",
14012 "Brightness...",
14013 "Gamma...",
14014 "Spiff",
14015 "Dull",
14016 "Contrast Stretch...",
14017 "Sigmoidal Contrast...",
14018 "Normalize",
14019 "Equalize",
14020 "Negate",
14021 "Grayscale",
14022 "Map...",
14023 "Quantize...",
14024 (char *) NULL
14025 },
14026 *const EffectsMenu[] =
14027 {
14028 "Despeckle",
14029 "Emboss",
14030 "Reduce Noise",
14031 "Add Noise...",
14032 "Sharpen...",
14033 "Blur...",
14034 "Threshold...",
14035 "Edge Detect...",
14036 "Spread...",
14037 "Shade...",
14038 "Raise...",
14039 "Segment...",
14040 (char *) NULL
14041 },
14042 *const FXMenu[] =
14043 {
14044 "Solarize...",
14045 "Sepia Tone...",
14046 "Swirl...",
14047 "Implode...",
14048 "Vignette...",
14049 "Wave...",
14050 "Oil Paint...",
14051 "Charcoal Draw...",
14052 (char *) NULL
14053 },
14054 *const ImageEditMenu[] =
14055 {
14056 "Annotate...",
14057 "Draw...",
14058 "Color...",
14059 "Matte...",
14060 "Composite...",
14061 "Add Border...",
14062 "Add Frame...",
14063 "Comment...",
14064 "Launch...",
14065 "Region of Interest...",
14066 (char *) NULL
14067 },
14068 *const MiscellanyMenu[] =
14069 {
14070 "Image Info",
14071 "Zoom Image",
14072 "Show Preview...",
14073 "Show Histogram",
14074 "Show Matte",
14075 "Background...",
14076 "Slide Show...",
14077 "Preferences...",
14078 (char *) NULL
14079 },
14080 *const HelpMenu[] =
14081 {
14082 "Overview",
14083 "Browse Documentation",
14084 "About Display",
14085 (char *) NULL
14086 },
14087 *const ShortCutsMenu[] =
14088 {
14089 "Next",
14090 "Former",
14091 "Open...",
14092 "Save...",
14093 "Print...",
14094 "Undo",
14095 "Restore",
14096 "Image Info",
14097 "Quit",
14098 (char *) NULL
14099 },
14100 *const VirtualMenu[] =
14101 {
14102 "Image Info",
14103 "Print",
14104 "Next",
14105 "Quit",
14106 (char *) NULL
14107 };
14108
14109 const char
14110 *const *Menus[MagickMenus] =
14111 {
14112 FileMenu,
14113 EditMenu,
14114 ViewMenu,
14115 TransformMenu,
14116 EnhanceMenu,
14117 EffectsMenu,
14118 FXMenu,
14119 ImageEditMenu,
14120 MiscellanyMenu,
14121 HelpMenu
14122 };
14123
14124 static CommandType
14125 CommandMenus[] =
14126 {
14127 NullCommand,
14128 NullCommand,
14129 NullCommand,
14130 NullCommand,
14131 NullCommand,
14132 NullCommand,
14133 NullCommand,
14134 NullCommand,
14135 NullCommand,
14136 NullCommand,
14137 },
14138 FileCommands[] =
14139 {
14140 OpenCommand,
14141 NextCommand,
14142 FormerCommand,
14143 SelectCommand,
14144 SaveCommand,
14145 PrintCommand,
14146 DeleteCommand,
14147 NewCommand,
14148 VisualDirectoryCommand,
14149 QuitCommand
14150 },
14151 EditCommands[] =
14152 {
14153 UndoCommand,
14154 RedoCommand,
14155 CutCommand,
14156 CopyCommand,
14157 PasteCommand
14158 },
14159 ViewCommands[] =
14160 {
14161 HalfSizeCommand,
14162 OriginalSizeCommand,
14163 DoubleSizeCommand,
14164 ResizeCommand,
14165 ApplyCommand,
14166 RefreshCommand,
14167 RestoreCommand
14168 },
14169 TransformCommands[] =
14170 {
14171 CropCommand,
14172 ChopCommand,
14173 FlopCommand,
14174 FlipCommand,
14175 RotateRightCommand,
14176 RotateLeftCommand,
14177 RotateCommand,
14178 ShearCommand,
14179 RollCommand,
14180 TrimCommand
14181 },
14182 EnhanceCommands[] =
14183 {
14184 HueCommand,
14185 SaturationCommand,
14186 BrightnessCommand,
14187 GammaCommand,
14188 SpiffCommand,
14189 DullCommand,
14190 ContrastStretchCommand,
14191 SigmoidalContrastCommand,
14192 NormalizeCommand,
14193 EqualizeCommand,
14194 NegateCommand,
14195 GrayscaleCommand,
14196 MapCommand,
14197 QuantizeCommand
14198 },
14199 EffectsCommands[] =
14200 {
14201 DespeckleCommand,
14202 EmbossCommand,
14203 ReduceNoiseCommand,
14204 AddNoiseCommand,
14205 SharpenCommand,
14206 BlurCommand,
14207 ThresholdCommand,
14208 EdgeDetectCommand,
14209 SpreadCommand,
14210 ShadeCommand,
14211 RaiseCommand,
14212 SegmentCommand
14213 },
14214 FXCommands[] =
14215 {
14216 SolarizeCommand,
14217 SepiaToneCommand,
14218 SwirlCommand,
14219 ImplodeCommand,
14220 VignetteCommand,
14221 WaveCommand,
14222 OilPaintCommand,
14223 CharcoalDrawCommand
14224 },
14225 ImageEditCommands[] =
14226 {
14227 AnnotateCommand,
14228 DrawCommand,
14229 ColorCommand,
14230 MatteCommand,
14231 CompositeCommand,
14232 AddBorderCommand,
14233 AddFrameCommand,
14234 CommentCommand,
14235 LaunchCommand,
14236 RegionofInterestCommand
14237 },
14238 MiscellanyCommands[] =
14239 {
14240 InfoCommand,
14241 ZoomCommand,
14242 ShowPreviewCommand,
14243 ShowHistogramCommand,
14244 ShowMatteCommand,
14245 BackgroundCommand,
14246 SlideShowCommand,
14247 PreferencesCommand
14248 },
14249 HelpCommands[] =
14250 {
14251 HelpCommand,
14252 BrowseDocumentationCommand,
14253 VersionCommand
14254 },
14255 ShortCutsCommands[] =
14256 {
14257 NextCommand,
14258 FormerCommand,
14259 OpenCommand,
14260 SaveCommand,
14261 PrintCommand,
14262 UndoCommand,
14263 RestoreCommand,
14264 InfoCommand,
14265 QuitCommand
14266 },
14267 VirtualCommands[] =
14268 {
14269 InfoCommand,
14270 PrintCommand,
14271 NextCommand,
14272 QuitCommand
14273 };
14274
14275 static CommandType
14276 *Commands[MagickMenus] =
14277 {
14278 FileCommands,
14279 EditCommands,
14280 ViewCommands,
14281 TransformCommands,
14282 EnhanceCommands,
14283 EffectsCommands,
14284 FXCommands,
14285 ImageEditCommands,
14286 MiscellanyCommands,
14287 HelpCommands
14288 };
14289
14290 char
14291 command[MaxTextExtent],
14292 *directory,
14293 geometry[MaxTextExtent],
14294 resource_name[MaxTextExtent];
14295
14296 CommandType
14297 command_type;
14298
14299 Image
14300 *display_image,
14301 *nexus;
14302
14303 int
14304 entry,
14305 id;
14306
14307 KeySym
14308 key_symbol;
14309
14310 MagickStatusType
14311 context_mask,
14312 status;
14313
14314 RectangleInfo
14315 geometry_info;
14316
14317 int
14318 i;
14319
14320 static char
14321 working_directory[MaxTextExtent];
14322
14323 static XPoint
14324 vid_info;
14325
14326 static XWindowInfo
14327 *magick_windows[MaxXWindows];
14328
14329 static unsigned int
14330 number_windows;
14331
14332 struct stat
14333 attributes;
14334
14335 time_t
14336 timer,
14337 timestamp,
14338 update_time;
14339
14340 unsigned int
14341 height,
14342 width;
14343
14344 size_t
14345 delay;
14346
14347 WarningHandler
14348 warning_handler;
14349
14350 Window
14351 root_window;
14352
14353 XClassHint
14354 *class_hints;
14355
14356 XEvent
14357 event;
14358
14359 XFontStruct
14360 *font_info;
14361
14362 XGCValues
14363 context_values;
14364
14365 XPixelInfo
14366 *icon_pixel,
14367 *pixel;
14368
14369 XResourceInfo
14370 *icon_resources;
14371
14372 XStandardColormap
14373 *icon_map,
14374 *map_info;
14375
14376 XVisualInfo
14377 *icon_visual,
14378 *visual_info;
14379
14380 XWindowChanges
14381 window_changes;
14382
14383 XWindows
14384 *windows;
14385
14386 XWMHints
14387 *manager_hints;
14388
14389 assert(image != (Image **) NULL);
14390 assert((*image)->signature == MagickCoreSignature);
14391 if ((*image)->debug != MagickFalse)
14392 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14393 display_image=(*image);
14394 warning_handler=(WarningHandler) NULL;
14395 windows=XSetWindows((XWindows *) ~0);
14396 if (windows != (XWindows *) NULL)
14397 {
14398 int
14399 status;
14400
14401 if (*working_directory == '\0')
14402 (void) CopyMagickString(working_directory,".",MaxTextExtent);
14403 status=chdir(working_directory);
14404 if (status == -1)
14405 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14406 FileOpenError,"UnableToOpenFile","%s",working_directory);
14407 warning_handler=resource_info->display_warnings ?
14408 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14409 warning_handler=resource_info->display_warnings ?
14410 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14411 }
14412 else
14413 {
14414 /*
14415 Allocate windows structure.
14416 */
14417 resource_info->colors=display_image->colors;
14418 windows=XSetWindows(XInitializeWindows(display,resource_info));
14419 if (windows == (XWindows *) NULL)
14420 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14421 (*image)->filename);
14422 /*
14423 Initialize window id's.
14424 */
14425 number_windows=0;
14426 magick_windows[number_windows++]=(&windows->icon);
14427 magick_windows[number_windows++]=(&windows->backdrop);
14428 magick_windows[number_windows++]=(&windows->image);
14429 magick_windows[number_windows++]=(&windows->info);
14430 magick_windows[number_windows++]=(&windows->command);
14431 magick_windows[number_windows++]=(&windows->widget);
14432 magick_windows[number_windows++]=(&windows->popup);
14433 magick_windows[number_windows++]=(&windows->magnify);
14434 magick_windows[number_windows++]=(&windows->pan);
14435 for (i=0; i < (int) number_windows; i++)
14436 magick_windows[i]->id=(Window) NULL;
14437 vid_info.x=0;
14438 vid_info.y=0;
14439 }
14440 /*
14441 Initialize font info.
14442 */
14443 if (windows->font_info != (XFontStruct *) NULL)
14444 (void) XFreeFont(display,windows->font_info);
14445 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14446 if (windows->font_info == (XFontStruct *) NULL)
14447 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14448 resource_info->font);
14449 /*
14450 Initialize Standard Colormap.
14451 */
14452 map_info=windows->map_info;
14453 icon_map=windows->icon_map;
14454 visual_info=windows->visual_info;
14455 icon_visual=windows->icon_visual;
14456 pixel=windows->pixel_info;
14457 icon_pixel=windows->icon_pixel;
14458 font_info=windows->font_info;
14459 icon_resources=windows->icon_resources;
14460 class_hints=windows->class_hints;
14461 manager_hints=windows->manager_hints;
14462 root_window=XRootWindow(display,visual_info->screen);
14463 nexus=NewImageList();
14464 if (display_image->debug != MagickFalse)
14465 {
14466 (void) LogMagickEvent(X11Event,GetMagickModule(),
14467 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14468 (double) display_image->scene,(double) display_image->columns,
14469 (double) display_image->rows);
14470 if (display_image->colors != 0)
14471 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14472 display_image->colors);
14473 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14474 display_image->magick);
14475 }
14476 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14477 map_info,pixel);
14478 display_image->taint=MagickFalse;
14479 /*
14480 Initialize graphic context.
14481 */
14482 windows->context.id=(Window) NULL;
14483 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14484 resource_info,&windows->context);
14485 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14486 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14487 class_hints->res_class[0]=(char) LocaleUppercase((int)
14488 class_hints->res_class[0]);
14489 manager_hints->flags=InputHint | StateHint;
14490 manager_hints->input=MagickFalse;
14491 manager_hints->initial_state=WithdrawnState;
14492 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14493 &windows->context);
14494 if (display_image->debug != MagickFalse)
14495 (void) LogMagickEvent(X11Event,GetMagickModule(),
14496 "Window id: 0x%lx (context)",windows->context.id);
14497 context_values.background=pixel->background_color.pixel;
14498 context_values.font=font_info->fid;
14499 context_values.foreground=pixel->foreground_color.pixel;
14500 context_values.graphics_exposures=MagickFalse;
14501 context_mask=(MagickStatusType)
14502 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14503 if (pixel->annotate_context != (GC) NULL)
14504 (void) XFreeGC(display,pixel->annotate_context);
14505 pixel->annotate_context=XCreateGC(display,windows->context.id,
14506 context_mask,&context_values);
14507 if (pixel->annotate_context == (GC) NULL)
14508 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14509 display_image->filename);
14510 context_values.background=pixel->depth_color.pixel;
14511 if (pixel->widget_context != (GC) NULL)
14512 (void) XFreeGC(display,pixel->widget_context);
14513 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14514 &context_values);
14515 if (pixel->widget_context == (GC) NULL)
14516 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14517 display_image->filename);
14518 context_values.background=pixel->foreground_color.pixel;
14519 context_values.foreground=pixel->background_color.pixel;
14520 context_values.plane_mask=context_values.background ^
14521 context_values.foreground;
14522 if (pixel->highlight_context != (GC) NULL)
14523 (void) XFreeGC(display,pixel->highlight_context);
14524 pixel->highlight_context=XCreateGC(display,windows->context.id,
14525 (size_t) (context_mask | GCPlaneMask),&context_values);
14526 if (pixel->highlight_context == (GC) NULL)
14527 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14528 display_image->filename);
14529 (void) XDestroyWindow(display,windows->context.id);
14530 /*
14531 Initialize icon window.
14532 */
14533 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14534 icon_resources,&windows->icon);
14535 windows->icon.geometry=resource_info->icon_geometry;
14536 XBestIconSize(display,&windows->icon,display_image);
14537 windows->icon.attributes.colormap=XDefaultColormap(display,
14538 icon_visual->screen);
14539 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14540 manager_hints->flags=InputHint | StateHint;
14541 manager_hints->input=MagickFalse;
14542 manager_hints->initial_state=IconicState;
14543 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14544 &windows->icon);
14545 if (display_image->debug != MagickFalse)
14546 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14547 windows->icon.id);
14548 /*
14549 Initialize graphic context for icon window.
14550 */
14551 if (icon_pixel->annotate_context != (GC) NULL)
14552 (void) XFreeGC(display,icon_pixel->annotate_context);
14553 context_values.background=icon_pixel->background_color.pixel;
14554 context_values.foreground=icon_pixel->foreground_color.pixel;
14555 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14556 (size_t) (GCBackground | GCForeground),&context_values);
14557 if (icon_pixel->annotate_context == (GC) NULL)
14558 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14559 display_image->filename);
14560 windows->icon.annotate_context=icon_pixel->annotate_context;
14561 /*
14562 Initialize Image window.
14563 */
14564 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14565 &windows->image);
14566 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14567 if (resource_info->use_shared_memory == MagickFalse)
14568 windows->image.shared_memory=MagickFalse;
14569 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14570 {
14571 char
14572 *title;
14573
14574 title=InterpretImageProperties(resource_info->image_info,display_image,
14575 resource_info->title);
14576 (void) CloneString(&windows->image.name,title);
14577 (void) CloneString(&windows->image.icon_name,title);
14578 title=DestroyString(title);
14579 }
14580 else
14581 {
14582 char
14583 filename[MaxTextExtent],
14584 window_name[MaxTextExtent];
14585
14586 /*
14587 Window name is the base of the filename.
14588 */
14589 GetPathComponent(display_image->magick_filename,TailPath,filename);
14590 if (display_image->scene == 0)
14591 (void) FormatLocaleString(window_name,MaxTextExtent,"%s: %s",
14592 MagickPackageName,filename);
14593 else
14594 (void) FormatLocaleString(window_name,MaxTextExtent,
14595 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14596 (double) display_image->scene,(double) GetImageListLength(
14597 display_image));
14598 (void) CloneString(&windows->image.name,window_name);
14599 (void) CloneString(&windows->image.icon_name,filename);
14600 }
14601 if (resource_info->immutable)
14602 windows->image.immutable=MagickTrue;
14603 windows->image.use_pixmap=resource_info->use_pixmap;
14604 windows->image.geometry=resource_info->image_geometry;
14605 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14606 XDisplayWidth(display,visual_info->screen),
14607 XDisplayHeight(display,visual_info->screen));
14608 geometry_info.width=display_image->columns;
14609 geometry_info.height=display_image->rows;
14610 geometry_info.x=0;
14611 geometry_info.y=0;
14612 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14613 &geometry_info.width,&geometry_info.height);
14614 windows->image.width=(unsigned int) geometry_info.width;
14615 windows->image.height=(unsigned int) geometry_info.height;
14616 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14617 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14618 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14619 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14620 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14621 resource_info,&windows->backdrop);
14622 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14623 {
14624 /*
14625 Initialize backdrop window.
14626 */
14627 windows->backdrop.x=0;
14628 windows->backdrop.y=0;
14629 (void) CloneString(&windows->backdrop.name,"Backdrop");
14630 windows->backdrop.flags=(size_t) (USSize | USPosition);
14631 windows->backdrop.width=(unsigned int)
14632 XDisplayWidth(display,visual_info->screen);
14633 windows->backdrop.height=(unsigned int)
14634 XDisplayHeight(display,visual_info->screen);
14635 windows->backdrop.border_width=0;
14636 windows->backdrop.immutable=MagickTrue;
14637 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14638 ButtonReleaseMask;
14639 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14640 StructureNotifyMask;
14641 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14642 manager_hints->icon_window=windows->icon.id;
14643 manager_hints->input=MagickTrue;
14644 manager_hints->initial_state=resource_info->iconic ? IconicState :
14645 NormalState;
14646 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14647 &windows->backdrop);
14648 if (display_image->debug != MagickFalse)
14649 (void) LogMagickEvent(X11Event,GetMagickModule(),
14650 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14651 (void) XMapWindow(display,windows->backdrop.id);
14652 (void) XClearWindow(display,windows->backdrop.id);
14653 if (windows->image.id != (Window) NULL)
14654 {
14655 (void) XDestroyWindow(display,windows->image.id);
14656 windows->image.id=(Window) NULL;
14657 }
14658 /*
14659 Position image in the center the backdrop.
14660 */
14661 windows->image.flags|=USPosition;
14662 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14663 (windows->image.width/2);
14664 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14665 (windows->image.height/2);
14666 }
14667 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14668 manager_hints->icon_window=windows->icon.id;
14669 manager_hints->input=MagickTrue;
14670 manager_hints->initial_state=resource_info->iconic ? IconicState :
14671 NormalState;
14672 if (windows->group_leader.id != (Window) NULL)
14673 {
14674 /*
14675 Follow the leader.
14676 */
14677 manager_hints->flags|=WindowGroupHint;
14678 manager_hints->window_group=windows->group_leader.id;
14679 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14680 if (display_image->debug != MagickFalse)
14681 (void) LogMagickEvent(X11Event,GetMagickModule(),
14682 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14683 }
14684 XMakeWindow(display,
14685 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14686 argv,argc,class_hints,manager_hints,&windows->image);
14687 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14688 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14689 if (windows->group_leader.id != (Window) NULL)
14690 (void) XSetTransientForHint(display,windows->image.id,
14691 windows->group_leader.id);
14692 if (display_image->debug != MagickFalse)
14693 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14694 windows->image.id);
14695 /*
14696 Initialize Info widget.
14697 */
14698 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14699 &windows->info);
14700 (void) CloneString(&windows->info.name,"Info");
14701 (void) CloneString(&windows->info.icon_name,"Info");
14702 windows->info.border_width=1;
14703 windows->info.x=2;
14704 windows->info.y=2;
14705 windows->info.flags|=PPosition;
14706 windows->info.attributes.win_gravity=UnmapGravity;
14707 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14708 StructureNotifyMask;
14709 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14710 manager_hints->input=MagickFalse;
14711 manager_hints->initial_state=NormalState;
14712 manager_hints->window_group=windows->image.id;
14713 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14714 &windows->info);
14715 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14716 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14717 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14718 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14719 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14720 if (windows->image.mapped != MagickFalse)
14721 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14722 if (display_image->debug != MagickFalse)
14723 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14724 windows->info.id);
14725 /*
14726 Initialize Command widget.
14727 */
14728 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14729 resource_info,&windows->command);
14730 windows->command.data=MagickMenus;
14731 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14732 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
14733 resource_info->client_name);
14734 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14735 resource_name,"geometry",(char *) NULL);
14736 (void) CloneString(&windows->command.name,MagickTitle);
14737 windows->command.border_width=0;
14738 windows->command.flags|=PPosition;
14739 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14740 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14741 OwnerGrabButtonMask | StructureNotifyMask;
14742 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14743 manager_hints->input=MagickTrue;
14744 manager_hints->initial_state=NormalState;
14745 manager_hints->window_group=windows->image.id;
14746 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14747 &windows->command);
14748 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14749 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14750 HighlightHeight);
14751 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14752 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14753 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14754 if (windows->command.mapped != MagickFalse)
14755 (void) XMapRaised(display,windows->command.id);
14756 if (display_image->debug != MagickFalse)
14757 (void) LogMagickEvent(X11Event,GetMagickModule(),
14758 "Window id: 0x%lx (command)",windows->command.id);
14759 /*
14760 Initialize Widget window.
14761 */
14762 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14763 resource_info,&windows->widget);
14764 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
14765 resource_info->client_name);
14766 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14767 resource_name,"geometry",(char *) NULL);
14768 windows->widget.border_width=0;
14769 windows->widget.flags|=PPosition;
14770 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14771 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14772 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14773 StructureNotifyMask;
14774 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14775 manager_hints->input=MagickTrue;
14776 manager_hints->initial_state=NormalState;
14777 manager_hints->window_group=windows->image.id;
14778 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14779 &windows->widget);
14780 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14781 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14782 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14783 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14784 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14785 if (display_image->debug != MagickFalse)
14786 (void) LogMagickEvent(X11Event,GetMagickModule(),
14787 "Window id: 0x%lx (widget)",windows->widget.id);
14788 /*
14789 Initialize popup window.
14790 */
14791 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14792 resource_info,&windows->popup);
14793 windows->popup.border_width=0;
14794 windows->popup.flags|=PPosition;
14795 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14796 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14797 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14798 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14799 manager_hints->input=MagickTrue;
14800 manager_hints->initial_state=NormalState;
14801 manager_hints->window_group=windows->image.id;
14802 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14803 &windows->popup);
14804 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14805 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14806 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14807 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14808 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14809 if (display_image->debug != MagickFalse)
14810 (void) LogMagickEvent(X11Event,GetMagickModule(),
14811 "Window id: 0x%lx (pop up)",windows->popup.id);
14812 /*
14813 Initialize Magnify window and cursor.
14814 */
14815 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14816 resource_info,&windows->magnify);
14817 if (resource_info->use_shared_memory == MagickFalse)
14818 windows->magnify.shared_memory=MagickFalse;
14819 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
14820 resource_info->client_name);
14821 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14822 resource_name,"geometry",(char *) NULL);
14823 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14824 resource_info->magnify);
14825 if (windows->magnify.cursor != (Cursor) NULL)
14826 (void) XFreeCursor(display,windows->magnify.cursor);
14827 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14828 map_info->colormap,resource_info->background_color,
14829 resource_info->foreground_color);
14830 if (windows->magnify.cursor == (Cursor) NULL)
14831 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14832 display_image->filename);
14833 windows->magnify.width=MagnifySize;
14834 windows->magnify.height=MagnifySize;
14835 windows->magnify.flags|=PPosition;
14836 windows->magnify.min_width=MagnifySize;
14837 windows->magnify.min_height=MagnifySize;
14838 windows->magnify.width_inc=MagnifySize;
14839 windows->magnify.height_inc=MagnifySize;
14840 windows->magnify.data=resource_info->magnify;
14841 windows->magnify.attributes.cursor=windows->magnify.cursor;
14842 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14843 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14844 StructureNotifyMask;
14845 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14846 manager_hints->input=MagickTrue;
14847 manager_hints->initial_state=NormalState;
14848 manager_hints->window_group=windows->image.id;
14849 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14850 &windows->magnify);
14851 if (display_image->debug != MagickFalse)
14852 (void) LogMagickEvent(X11Event,GetMagickModule(),
14853 "Window id: 0x%lx (magnify)",windows->magnify.id);
14854 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14855 /*
14856 Initialize panning window.
14857 */
14858 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14859 resource_info,&windows->pan);
14860 (void) CloneString(&windows->pan.name,"Pan Icon");
14861 windows->pan.width=windows->icon.width;
14862 windows->pan.height=windows->icon.height;
14863 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
14864 resource_info->client_name);
14865 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14866 resource_name,"geometry",(char *) NULL);
14867 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14868 &windows->pan.width,&windows->pan.height);
14869 windows->pan.flags|=PPosition;
14870 windows->pan.immutable=MagickTrue;
14871 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14872 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14873 StructureNotifyMask;
14874 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14875 manager_hints->input=MagickFalse;
14876 manager_hints->initial_state=NormalState;
14877 manager_hints->window_group=windows->image.id;
14878 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14879 &windows->pan);
14880 if (display_image->debug != MagickFalse)
14881 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14882 windows->pan.id);
14883 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14884 if (windows->info.mapped != MagickFalse)
14885 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14886 if ((windows->image.mapped == MagickFalse) ||
14887 (windows->backdrop.id != (Window) NULL))
14888 (void) XMapWindow(display,windows->image.id);
14889 /*
14890 Set our progress monitor and warning handlers.
14891 */
14892 if (warning_handler == (WarningHandler) NULL)
14893 {
14894 warning_handler=resource_info->display_warnings ?
14895 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14896 warning_handler=resource_info->display_warnings ?
14897 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14898 }
14899 /*
14900 Initialize Image and Magnify X images.
14901 */
14902 windows->image.x=0;
14903 windows->image.y=0;
14904 windows->magnify.shape=MagickFalse;
14905 width=(unsigned int) display_image->columns;
14906 height=(unsigned int) display_image->rows;
14907 if ((display_image->columns != width) || (display_image->rows != height))
14908 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14909 display_image->filename);
14910 status=XMakeImage(display,resource_info,&windows->image,display_image,
14911 width,height);
14912 if (status == MagickFalse)
14913 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14914 display_image->filename);
14915 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14916 windows->magnify.width,windows->magnify.height);
14917 if (status == MagickFalse)
14918 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14919 display_image->filename);
14920 if (windows->magnify.mapped != MagickFalse)
14921 (void) XMapRaised(display,windows->magnify.id);
14922 if (windows->pan.mapped != MagickFalse)
14923 (void) XMapRaised(display,windows->pan.id);
14924 windows->image.window_changes.width=(int) display_image->columns;
14925 windows->image.window_changes.height=(int) display_image->rows;
14926 (void) XConfigureImage(display,resource_info,windows,display_image);
14927 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14928 (void) XSync(display,MagickFalse);
14929 /*
14930 Respond to events.
14931 */
14932 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14933 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
14934 update_time=0;
14935 if (resource_info->update != MagickFalse)
14936 {
14937 MagickBooleanType
14938 status;
14939
14940 /*
14941 Determine when file data was last modified.
14942 */
14943 status=GetPathAttributes(display_image->filename,&attributes);
14944 if (status != MagickFalse)
14945 update_time=attributes.st_mtime;
14946 }
14947 *state&=(~FormerImageState);
14948 *state&=(~MontageImageState);
14949 *state&=(~NextImageState);
14950 do
14951 {
14952 /*
14953 Handle a window event.
14954 */
14955 if (windows->image.mapped != MagickFalse)
14956 if ((display_image->delay != 0) || (resource_info->update != 0))
14957 {
14958 if (timer < GetMagickTime())
14959 {
14960 if (resource_info->update == MagickFalse)
14961 *state|=NextImageState | ExitState;
14962 else
14963 {
14964 MagickBooleanType
14965 status;
14966
14967 /*
14968 Determine if image file was modified.
14969 */
14970 status=GetPathAttributes(display_image->filename,&attributes);
14971 if (status != MagickFalse)
14972 if (update_time != attributes.st_mtime)
14973 {
14974 /*
14975 Redisplay image.
14976 */
14977 (void) FormatLocaleString(
14978 resource_info->image_info->filename,MaxTextExtent,
14979 "%s:%s",display_image->magick,
14980 display_image->filename);
14981 nexus=ReadImage(resource_info->image_info,
14982 &display_image->exception);
14983 if (nexus != (Image *) NULL)
14984 *state|=NextImageState | ExitState;
14985 }
14986 delay=display_image->delay/MagickMax(
14987 display_image->ticks_per_second,1L);
14988 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
14989 }
14990 }
14991 if (XEventsQueued(display,QueuedAfterFlush) == 0)
14992 {
14993 /*
14994 Do not block if delay > 0.
14995 */
14996 XDelay(display,SuspendTime << 2);
14997 continue;
14998 }
14999 }
15000 timestamp=GetMagickTime();
15001 (void) XNextEvent(display,&event);
15002 if (windows->image.stasis == MagickFalse)
15003 windows->image.stasis=(GetMagickTime()-timestamp) > 0 ?
15004 MagickTrue : MagickFalse;
15005 if (windows->magnify.stasis == MagickFalse)
15006 windows->magnify.stasis=(GetMagickTime()-timestamp) > 0 ?
15007 MagickTrue : MagickFalse;
15008 if (event.xany.window == windows->command.id)
15009 {
15010 /*
15011 Select a command from the Command widget.
15012 */
15013 id=XCommandWidget(display,windows,CommandMenu,&event);
15014 if (id < 0)
15015 continue;
15016 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15017 command_type=CommandMenus[id];
15018 if (id < MagickMenus)
15019 {
15020 /*
15021 Select a command from a pop-up menu.
15022 */
15023 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15024 command);
15025 if (entry < 0)
15026 continue;
15027 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15028 command_type=Commands[id][entry];
15029 }
15030 if (command_type != NullCommand)
15031 nexus=XMagickCommand(display,resource_info,windows,command_type,
15032 &display_image);
15033 continue;
15034 }
15035 switch (event.type)
15036 {
15037 case ButtonPress:
15038 {
15039 if (display_image->debug != MagickFalse)
15040 (void) LogMagickEvent(X11Event,GetMagickModule(),
15041 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15042 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15043 if ((event.xbutton.button == Button3) &&
15044 (event.xbutton.state & Mod1Mask))
15045 {
15046 /*
15047 Convert Alt-Button3 to Button2.
15048 */
15049 event.xbutton.button=Button2;
15050 event.xbutton.state&=(~Mod1Mask);
15051 }
15052 if (event.xbutton.window == windows->backdrop.id)
15053 {
15054 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15055 event.xbutton.time);
15056 break;
15057 }
15058 if (event.xbutton.window == windows->image.id)
15059 {
15060 switch (event.xbutton.button)
15061 {
15062 case Button1:
15063 {
15064 if (resource_info->immutable)
15065 {
15066 /*
15067 Select a command from the Virtual menu.
15068 */
15069 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15070 command);
15071 if (entry >= 0)
15072 nexus=XMagickCommand(display,resource_info,windows,
15073 VirtualCommands[entry],&display_image);
15074 break;
15075 }
15076 /*
15077 Map/unmap Command widget.
15078 */
15079 if (windows->command.mapped != MagickFalse)
15080 (void) XWithdrawWindow(display,windows->command.id,
15081 windows->command.screen);
15082 else
15083 {
15084 (void) XCommandWidget(display,windows,CommandMenu,
15085 (XEvent *) NULL);
15086 (void) XMapRaised(display,windows->command.id);
15087 }
15088 break;
15089 }
15090 case Button2:
15091 {
15092 /*
15093 User pressed the image magnify button.
15094 */
15095 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15096 &display_image);
15097 XMagnifyImage(display,windows,&event);
15098 break;
15099 }
15100 case Button3:
15101 {
15102 if (resource_info->immutable)
15103 {
15104 /*
15105 Select a command from the Virtual menu.
15106 */
15107 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15108 command);
15109 if (entry >= 0)
15110 nexus=XMagickCommand(display,resource_info,windows,
15111 VirtualCommands[entry],&display_image);
15112 break;
15113 }
15114 if (display_image->montage != (char *) NULL)
15115 {
15116 /*
15117 Open or delete a tile from a visual image directory.
15118 */
15119 nexus=XTileImage(display,resource_info,windows,
15120 display_image,&event);
15121 if (nexus != (Image *) NULL)
15122 *state|=MontageImageState | NextImageState | ExitState;
15123 vid_info.x=(short int) windows->image.x;
15124 vid_info.y=(short int) windows->image.y;
15125 break;
15126 }
15127 /*
15128 Select a command from the Short Cuts menu.
15129 */
15130 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15131 command);
15132 if (entry >= 0)
15133 nexus=XMagickCommand(display,resource_info,windows,
15134 ShortCutsCommands[entry],&display_image);
15135 break;
15136 }
15137 case Button4:
15138 {
15139 /*
15140 Wheel up.
15141 */
15142 XTranslateImage(display,windows,*image,XK_Up);
15143 break;
15144 }
15145 case Button5:
15146 {
15147 /*
15148 Wheel down.
15149 */
15150 XTranslateImage(display,windows,*image,XK_Down);
15151 break;
15152 }
15153 default:
15154 break;
15155 }
15156 break;
15157 }
15158 if (event.xbutton.window == windows->magnify.id)
15159 {
15160 const char
15161 *const MagnifyMenu[] =
15162 {
15163 "2",
15164 "4",
15165 "5",
15166 "6",
15167 "7",
15168 "8",
15169 "9",
15170 "3",
15171 (char *) NULL,
15172 };
15173
15174 int
15175 factor;
15176
15177 static KeySym
15178 MagnifyCommands[] =
15179 {
15180 XK_2,
15181 XK_4,
15182 XK_5,
15183 XK_6,
15184 XK_7,
15185 XK_8,
15186 XK_9,
15187 XK_3
15188 };
15189
15190 /*
15191 Select a magnify factor from the pop-up menu.
15192 */
15193 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15194 if (factor >= 0)
15195 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15196 break;
15197 }
15198 if (event.xbutton.window == windows->pan.id)
15199 {
15200 switch (event.xbutton.button)
15201 {
15202 case Button4:
15203 {
15204 /*
15205 Wheel up.
15206 */
15207 XTranslateImage(display,windows,*image,XK_Up);
15208 break;
15209 }
15210 case Button5:
15211 {
15212 /*
15213 Wheel down.
15214 */
15215 XTranslateImage(display,windows,*image,XK_Down);
15216 break;
15217 }
15218 default:
15219 {
15220 XPanImage(display,windows,&event);
15221 break;
15222 }
15223 }
15224 break;
15225 }
15226 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15227 1L);
15228 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15229 break;
15230 }
15231 case ButtonRelease:
15232 {
15233 if (display_image->debug != MagickFalse)
15234 (void) LogMagickEvent(X11Event,GetMagickModule(),
15235 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15236 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15237 break;
15238 }
15239 case ClientMessage:
15240 {
15241 if (display_image->debug != MagickFalse)
15242 (void) LogMagickEvent(X11Event,GetMagickModule(),
15243 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15244 event.xclient.message_type,event.xclient.format,(unsigned long)
15245 event.xclient.data.l[0]);
15246 if (event.xclient.message_type == windows->im_protocols)
15247 {
15248 if (*event.xclient.data.l == (long) windows->im_update_widget)
15249 {
15250 (void) CloneString(&windows->command.name,MagickTitle);
15251 windows->command.data=MagickMenus;
15252 (void) XCommandWidget(display,windows,CommandMenu,
15253 (XEvent *) NULL);
15254 break;
15255 }
15256 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15257 {
15258 /*
15259 Update graphic context and window colormap.
15260 */
15261 for (i=0; i < (int) number_windows; i++)
15262 {
15263 if (magick_windows[i]->id == windows->icon.id)
15264 continue;
15265 context_values.background=pixel->background_color.pixel;
15266 context_values.foreground=pixel->foreground_color.pixel;
15267 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15268 context_mask,&context_values);
15269 (void) XChangeGC(display,magick_windows[i]->widget_context,
15270 context_mask,&context_values);
15271 context_values.background=pixel->foreground_color.pixel;
15272 context_values.foreground=pixel->background_color.pixel;
15273 context_values.plane_mask=context_values.background ^
15274 context_values.foreground;
15275 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15276 (size_t) (context_mask | GCPlaneMask),
15277 &context_values);
15278 magick_windows[i]->attributes.background_pixel=
15279 pixel->background_color.pixel;
15280 magick_windows[i]->attributes.border_pixel=
15281 pixel->border_color.pixel;
15282 magick_windows[i]->attributes.colormap=map_info->colormap;
15283 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15284 (unsigned long) magick_windows[i]->mask,
15285 &magick_windows[i]->attributes);
15286 }
15287 if (windows->pan.mapped != MagickFalse)
15288 {
15289 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15290 windows->pan.pixmap);
15291 (void) XClearWindow(display,windows->pan.id);
15292 XDrawPanRectangle(display,windows);
15293 }
15294 if (windows->backdrop.id != (Window) NULL)
15295 (void) XInstallColormap(display,map_info->colormap);
15296 break;
15297 }
15298 if (*event.xclient.data.l == (long) windows->im_former_image)
15299 {
15300 *state|=FormerImageState | ExitState;
15301 break;
15302 }
15303 if (*event.xclient.data.l == (long) windows->im_next_image)
15304 {
15305 *state|=NextImageState | ExitState;
15306 break;
15307 }
15308 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15309 {
15310 *state|=RetainColorsState;
15311 break;
15312 }
15313 if (*event.xclient.data.l == (long) windows->im_exit)
15314 {
15315 *state|=ExitState;
15316 break;
15317 }
15318 break;
15319 }
15320 if (event.xclient.message_type == windows->dnd_protocols)
15321 {
15322 Atom
15323 selection,
15324 type;
15325
15326 int
15327 format,
15328 status;
15329
15330 unsigned char
15331 *data;
15332
15333 unsigned long
15334 after,
15335 length;
15336
15337 /*
15338 Display image named by the Drag-and-Drop selection.
15339 */
15340 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15341 break;
15342 selection=XInternAtom(display,"DndSelection",MagickFalse);
15343 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15344 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15345 &length,&after,&data);
15346 if ((status != Success) || (length == 0))
15347 break;
15348 if (*event.xclient.data.l == 2)
15349 {
15350 /*
15351 Offix DND.
15352 */
15353 (void) CopyMagickString(resource_info->image_info->filename,
15354 (char *) data,MaxTextExtent);
15355 }
15356 else
15357 {
15358 /*
15359 XDND.
15360 */
15361 if (strncmp((char *) data, "file:", 5) != 0)
15362 {
15363 (void) XFree((void *) data);
15364 break;
15365 }
15366 (void) CopyMagickString(resource_info->image_info->filename,
15367 ((char *) data)+5,MaxTextExtent);
15368 }
15369 nexus=ReadImage(resource_info->image_info,
15370 &display_image->exception);
15371 CatchException(&display_image->exception);
15372 if (nexus != (Image *) NULL)
15373 *state|=NextImageState | ExitState;
15374 (void) XFree((void *) data);
15375 break;
15376 }
15377 /*
15378 If client window delete message, exit.
15379 */
15380 if (event.xclient.message_type != windows->wm_protocols)
15381 break;
15382 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15383 break;
15384 (void) XWithdrawWindow(display,event.xclient.window,
15385 visual_info->screen);
15386 if (event.xclient.window == windows->image.id)
15387 {
15388 *state|=ExitState;
15389 break;
15390 }
15391 if (event.xclient.window == windows->pan.id)
15392 {
15393 /*
15394 Restore original image size when pan window is deleted.
15395 */
15396 windows->image.window_changes.width=windows->image.ximage->width;
15397 windows->image.window_changes.height=windows->image.ximage->height;
15398 (void) XConfigureImage(display,resource_info,windows,
15399 display_image);
15400 }
15401 break;
15402 }
15403 case ConfigureNotify:
15404 {
15405 if (display_image->debug != MagickFalse)
15406 (void) LogMagickEvent(X11Event,GetMagickModule(),
15407 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15408 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15409 event.xconfigure.y,event.xconfigure.send_event);
15410 if (event.xconfigure.window == windows->image.id)
15411 {
15412 /*
15413 Image window has a new configuration.
15414 */
15415 if (event.xconfigure.send_event != 0)
15416 {
15417 XWindowChanges
15418 window_changes;
15419
15420 /*
15421 Position the transient windows relative of the Image window.
15422 */
15423 if (windows->command.geometry == (char *) NULL)
15424 if (windows->command.mapped == MagickFalse)
15425 {
15426 windows->command.x=event.xconfigure.x-
15427 windows->command.width-25;
15428 windows->command.y=event.xconfigure.y;
15429 XConstrainWindowPosition(display,&windows->command);
15430 window_changes.x=windows->command.x;
15431 window_changes.y=windows->command.y;
15432 (void) XReconfigureWMWindow(display,windows->command.id,
15433 windows->command.screen,(unsigned int) (CWX | CWY),
15434 &window_changes);
15435 }
15436 if (windows->widget.geometry == (char *) NULL)
15437 if (windows->widget.mapped == MagickFalse)
15438 {
15439 windows->widget.x=event.xconfigure.x+
15440 event.xconfigure.width/10;
15441 windows->widget.y=event.xconfigure.y+
15442 event.xconfigure.height/10;
15443 XConstrainWindowPosition(display,&windows->widget);
15444 window_changes.x=windows->widget.x;
15445 window_changes.y=windows->widget.y;
15446 (void) XReconfigureWMWindow(display,windows->widget.id,
15447 windows->widget.screen,(unsigned int) (CWX | CWY),
15448 &window_changes);
15449 }
15450 if (windows->magnify.geometry == (char *) NULL)
15451 if (windows->magnify.mapped == MagickFalse)
15452 {
15453 windows->magnify.x=event.xconfigure.x+
15454 event.xconfigure.width+25;
15455 windows->magnify.y=event.xconfigure.y;
15456 XConstrainWindowPosition(display,&windows->magnify);
15457 window_changes.x=windows->magnify.x;
15458 window_changes.y=windows->magnify.y;
15459 (void) XReconfigureWMWindow(display,windows->magnify.id,
15460 windows->magnify.screen,(unsigned int) (CWX | CWY),
15461 &window_changes);
15462 }
15463 if (windows->pan.geometry == (char *) NULL)
15464 if (windows->pan.mapped == MagickFalse)
15465 {
15466 windows->pan.x=event.xconfigure.x+
15467 event.xconfigure.width+25;
15468 windows->pan.y=event.xconfigure.y+
15469 windows->magnify.height+50;
15470 XConstrainWindowPosition(display,&windows->pan);
15471 window_changes.x=windows->pan.x;
15472 window_changes.y=windows->pan.y;
15473 (void) XReconfigureWMWindow(display,windows->pan.id,
15474 windows->pan.screen,(unsigned int) (CWX | CWY),
15475 &window_changes);
15476 }
15477 }
15478 if ((event.xconfigure.width == (int) windows->image.width) &&
15479 (event.xconfigure.height == (int) windows->image.height))
15480 break;
15481 windows->image.width=(unsigned int) event.xconfigure.width;
15482 windows->image.height=(unsigned int) event.xconfigure.height;
15483 windows->image.x=0;
15484 windows->image.y=0;
15485 if (display_image->montage != (char *) NULL)
15486 {
15487 windows->image.x=vid_info.x;
15488 windows->image.y=vid_info.y;
15489 }
15490 if ((windows->image.mapped != MagickFalse) &&
15491 (windows->image.stasis != MagickFalse))
15492 {
15493 /*
15494 Update image window configuration.
15495 */
15496 windows->image.window_changes.width=event.xconfigure.width;
15497 windows->image.window_changes.height=event.xconfigure.height;
15498 (void) XConfigureImage(display,resource_info,windows,
15499 display_image);
15500 }
15501 /*
15502 Update pan window configuration.
15503 */
15504 if ((event.xconfigure.width < windows->image.ximage->width) ||
15505 (event.xconfigure.height < windows->image.ximage->height))
15506 {
15507 (void) XMapRaised(display,windows->pan.id);
15508 XDrawPanRectangle(display,windows);
15509 }
15510 else
15511 if (windows->pan.mapped != MagickFalse)
15512 (void) XWithdrawWindow(display,windows->pan.id,
15513 windows->pan.screen);
15514 break;
15515 }
15516 if (event.xconfigure.window == windows->magnify.id)
15517 {
15518 unsigned int
15519 magnify;
15520
15521 /*
15522 Magnify window has a new configuration.
15523 */
15524 windows->magnify.width=(unsigned int) event.xconfigure.width;
15525 windows->magnify.height=(unsigned int) event.xconfigure.height;
15526 if (windows->magnify.mapped == MagickFalse)
15527 break;
15528 magnify=1;
15529 while ((int) magnify <= event.xconfigure.width)
15530 magnify<<=1;
15531 while ((int) magnify <= event.xconfigure.height)
15532 magnify<<=1;
15533 magnify>>=1;
15534 if (((int) magnify != event.xconfigure.width) ||
15535 ((int) magnify != event.xconfigure.height))
15536 {
15537 window_changes.width=(int) magnify;
15538 window_changes.height=(int) magnify;
15539 (void) XReconfigureWMWindow(display,windows->magnify.id,
15540 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15541 &window_changes);
15542 break;
15543 }
15544 if ((windows->magnify.mapped != MagickFalse) &&
15545 (windows->magnify.stasis != MagickFalse))
15546 {
15547 status=XMakeImage(display,resource_info,&windows->magnify,
15548 display_image,windows->magnify.width,windows->magnify.height);
15549 XMakeMagnifyImage(display,windows);
15550 }
15551 break;
15552 }
15553 if ((windows->magnify.mapped != MagickFalse) &&
15554 (event.xconfigure.window == windows->pan.id))
15555 {
15556 /*
15557 Pan icon window has a new configuration.
15558 */
15559 if (event.xconfigure.send_event != 0)
15560 {
15561 windows->pan.x=event.xconfigure.x;
15562 windows->pan.y=event.xconfigure.y;
15563 }
15564 windows->pan.width=(unsigned int) event.xconfigure.width;
15565 windows->pan.height=(unsigned int) event.xconfigure.height;
15566 break;
15567 }
15568 if (event.xconfigure.window == windows->icon.id)
15569 {
15570 /*
15571 Icon window has a new configuration.
15572 */
15573 windows->icon.width=(unsigned int) event.xconfigure.width;
15574 windows->icon.height=(unsigned int) event.xconfigure.height;
15575 break;
15576 }
15577 break;
15578 }
15579 case DestroyNotify:
15580 {
15581 /*
15582 Group leader has exited.
15583 */
15584 if (display_image->debug != MagickFalse)
15585 (void) LogMagickEvent(X11Event,GetMagickModule(),
15586 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15587 if (event.xdestroywindow.window == windows->group_leader.id)
15588 {
15589 *state|=ExitState;
15590 break;
15591 }
15592 break;
15593 }
15594 case EnterNotify:
15595 {
15596 /*
15597 Selectively install colormap.
15598 */
15599 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15600 if (event.xcrossing.mode != NotifyUngrab)
15601 XInstallColormap(display,map_info->colormap);
15602 break;
15603 }
15604 case Expose:
15605 {
15606 if (display_image->debug != MagickFalse)
15607 (void) LogMagickEvent(X11Event,GetMagickModule(),
15608 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15609 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15610 event.xexpose.y);
15611 /*
15612 Refresh windows that are now exposed.
15613 */
15614 if ((event.xexpose.window == windows->image.id) &&
15615 (windows->image.mapped != MagickFalse))
15616 {
15617 XRefreshWindow(display,&windows->image,&event);
15618 delay=display_image->delay/MagickMax(
15619 display_image->ticks_per_second,1L);
15620 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15621 break;
15622 }
15623 if ((event.xexpose.window == windows->magnify.id) &&
15624 (windows->magnify.mapped != MagickFalse))
15625 {
15626 XMakeMagnifyImage(display,windows);
15627 break;
15628 }
15629 if (event.xexpose.window == windows->pan.id)
15630 {
15631 XDrawPanRectangle(display,windows);
15632 break;
15633 }
15634 if (event.xexpose.window == windows->icon.id)
15635 {
15636 XRefreshWindow(display,&windows->icon,&event);
15637 break;
15638 }
15639 break;
15640 }
15641 case KeyPress:
15642 {
15643 int
15644 length;
15645
15646 /*
15647 Respond to a user key press.
15648 */
15649 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15650 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15651 *(command+length)='\0';
15652 if (display_image->debug != MagickFalse)
15653 (void) LogMagickEvent(X11Event,GetMagickModule(),
15654 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15655 key_symbol,command);
15656 if (event.xkey.window == windows->image.id)
15657 {
15658 command_type=XImageWindowCommand(display,resource_info,windows,
15659 event.xkey.state,key_symbol,&display_image);
15660 if (command_type != NullCommand)
15661 nexus=XMagickCommand(display,resource_info,windows,command_type,
15662 &display_image);
15663 }
15664 if (event.xkey.window == windows->magnify.id)
15665 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15666 if (event.xkey.window == windows->pan.id)
15667 {
15668 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15669 (void) XWithdrawWindow(display,windows->pan.id,
15670 windows->pan.screen);
15671 else
15672 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15673 XTextViewHelp(display,resource_info,windows,MagickFalse,
15674 "Help Viewer - Image Pan",ImagePanHelp);
15675 else
15676 XTranslateImage(display,windows,*image,key_symbol);
15677 }
15678 delay=display_image->delay/MagickMax(
15679 display_image->ticks_per_second,1L);
15680 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15681 break;
15682 }
15683 case KeyRelease:
15684 {
15685 /*
15686 Respond to a user key release.
15687 */
15688 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15689 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15690 if (display_image->debug != MagickFalse)
15691 (void) LogMagickEvent(X11Event,GetMagickModule(),
15692 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15693 break;
15694 }
15695 case LeaveNotify:
15696 {
15697 /*
15698 Selectively uninstall colormap.
15699 */
15700 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15701 if (event.xcrossing.mode != NotifyUngrab)
15702 XUninstallColormap(display,map_info->colormap);
15703 break;
15704 }
15705 case MapNotify:
15706 {
15707 if (display_image->debug != MagickFalse)
15708 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15709 event.xmap.window);
15710 if (event.xmap.window == windows->backdrop.id)
15711 {
15712 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15713 CurrentTime);
15714 windows->backdrop.mapped=MagickTrue;
15715 break;
15716 }
15717 if (event.xmap.window == windows->image.id)
15718 {
15719 if (windows->backdrop.id != (Window) NULL)
15720 (void) XInstallColormap(display,map_info->colormap);
15721 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15722 {
15723 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15724 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15725 }
15726 if (((int) windows->image.width < windows->image.ximage->width) ||
15727 ((int) windows->image.height < windows->image.ximage->height))
15728 (void) XMapRaised(display,windows->pan.id);
15729 windows->image.mapped=MagickTrue;
15730 break;
15731 }
15732 if (event.xmap.window == windows->magnify.id)
15733 {
15734 XMakeMagnifyImage(display,windows);
15735 windows->magnify.mapped=MagickTrue;
15736 (void) XWithdrawWindow(display,windows->info.id,
15737 windows->info.screen);
15738 break;
15739 }
15740 if (event.xmap.window == windows->pan.id)
15741 {
15742 XMakePanImage(display,resource_info,windows,display_image);
15743 windows->pan.mapped=MagickTrue;
15744 break;
15745 }
15746 if (event.xmap.window == windows->info.id)
15747 {
15748 windows->info.mapped=MagickTrue;
15749 break;
15750 }
15751 if (event.xmap.window == windows->icon.id)
15752 {
15753 MagickBooleanType
15754 taint;
15755
15756 /*
15757 Create an icon image.
15758 */
15759 taint=display_image->taint;
15760 XMakeStandardColormap(display,icon_visual,icon_resources,
15761 display_image,icon_map,icon_pixel);
15762 (void) XMakeImage(display,icon_resources,&windows->icon,
15763 display_image,windows->icon.width,windows->icon.height);
15764 display_image->taint=taint;
15765 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15766 windows->icon.pixmap);
15767 (void) XClearWindow(display,windows->icon.id);
15768 (void) XWithdrawWindow(display,windows->info.id,
15769 windows->info.screen);
15770 windows->icon.mapped=MagickTrue;
15771 break;
15772 }
15773 if (event.xmap.window == windows->command.id)
15774 {
15775 windows->command.mapped=MagickTrue;
15776 break;
15777 }
15778 if (event.xmap.window == windows->popup.id)
15779 {
15780 windows->popup.mapped=MagickTrue;
15781 break;
15782 }
15783 if (event.xmap.window == windows->widget.id)
15784 {
15785 windows->widget.mapped=MagickTrue;
15786 break;
15787 }
15788 break;
15789 }
15790 case MappingNotify:
15791 {
15792 (void) XRefreshKeyboardMapping(&event.xmapping);
15793 break;
15794 }
15795 case NoExpose:
15796 break;
15797 case PropertyNotify:
15798 {
15799 Atom
15800 type;
15801
15802 int
15803 format,
15804 status;
15805
15806 unsigned char
15807 *data;
15808
15809 unsigned long
15810 after,
15811 length;
15812
15813 if (display_image->debug != MagickFalse)
15814 (void) LogMagickEvent(X11Event,GetMagickModule(),
15815 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15816 event.xproperty.atom,event.xproperty.state);
15817 if (event.xproperty.atom != windows->im_remote_command)
15818 break;
15819 /*
15820 Display image named by the remote command protocol.
15821 */
15822 status=XGetWindowProperty(display,event.xproperty.window,
15823 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15824 AnyPropertyType,&type,&format,&length,&after,&data);
15825 if ((status != Success) || (length == 0))
15826 break;
15827 if (LocaleCompare((char *) data,"-quit") == 0)
15828 {
15829 XClientMessage(display,windows->image.id,windows->im_protocols,
15830 windows->im_exit,CurrentTime);
15831 (void) XFree((void *) data);
15832 break;
15833 }
15834 (void) CopyMagickString(resource_info->image_info->filename,
15835 (char *) data,MaxTextExtent);
15836 (void) XFree((void *) data);
15837 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15838 CatchException(&display_image->exception);
15839 if (nexus != (Image *) NULL)
15840 *state|=NextImageState | ExitState;
15841 break;
15842 }
15843 case ReparentNotify:
15844 {
15845 if (display_image->debug != MagickFalse)
15846 (void) LogMagickEvent(X11Event,GetMagickModule(),
15847 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15848 event.xreparent.window);
15849 break;
15850 }
15851 case UnmapNotify:
15852 {
15853 if (display_image->debug != MagickFalse)
15854 (void) LogMagickEvent(X11Event,GetMagickModule(),
15855 "Unmap Notify: 0x%lx",event.xunmap.window);
15856 if (event.xunmap.window == windows->backdrop.id)
15857 {
15858 windows->backdrop.mapped=MagickFalse;
15859 break;
15860 }
15861 if (event.xunmap.window == windows->image.id)
15862 {
15863 windows->image.mapped=MagickFalse;
15864 break;
15865 }
15866 if (event.xunmap.window == windows->magnify.id)
15867 {
15868 windows->magnify.mapped=MagickFalse;
15869 break;
15870 }
15871 if (event.xunmap.window == windows->pan.id)
15872 {
15873 windows->pan.mapped=MagickFalse;
15874 break;
15875 }
15876 if (event.xunmap.window == windows->info.id)
15877 {
15878 windows->info.mapped=MagickFalse;
15879 break;
15880 }
15881 if (event.xunmap.window == windows->icon.id)
15882 {
15883 if (map_info->colormap == icon_map->colormap)
15884 XConfigureImageColormap(display,resource_info,windows,
15885 display_image);
15886 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15887 icon_pixel);
15888 windows->icon.mapped=MagickFalse;
15889 break;
15890 }
15891 if (event.xunmap.window == windows->command.id)
15892 {
15893 windows->command.mapped=MagickFalse;
15894 break;
15895 }
15896 if (event.xunmap.window == windows->popup.id)
15897 {
15898 if (windows->backdrop.id != (Window) NULL)
15899 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15900 CurrentTime);
15901 windows->popup.mapped=MagickFalse;
15902 break;
15903 }
15904 if (event.xunmap.window == windows->widget.id)
15905 {
15906 if (windows->backdrop.id != (Window) NULL)
15907 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15908 CurrentTime);
15909 windows->widget.mapped=MagickFalse;
15910 break;
15911 }
15912 break;
15913 }
15914 default:
15915 {
15916 if (display_image->debug != MagickFalse)
15917 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15918 event.type);
15919 break;
15920 }
15921 }
15922 } while (!(*state & ExitState));
15923 if ((*state & ExitState) == 0)
15924 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15925 &display_image);
15926 else
15927 if (resource_info->confirm_edit != MagickFalse)
15928 {
15929 /*
15930 Query user if image has changed.
15931 */
15932 if ((resource_info->immutable == MagickFalse) &&
15933 (display_image->taint != MagickFalse))
15934 {
15935 int
15936 status;
15937
15938 status=XConfirmWidget(display,windows,"Your image changed.",
15939 "Do you want to save it");
15940 if (status == 0)
15941 *state&=(~ExitState);
15942 else
15943 if (status > 0)
15944 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15945 &display_image);
15946 }
15947 }
15948 if ((windows->visual_info->klass == GrayScale) ||
15949 (windows->visual_info->klass == PseudoColor) ||
15950 (windows->visual_info->klass == DirectColor))
15951 {
15952 /*
15953 Withdraw pan and Magnify window.
15954 */
15955 if (windows->info.mapped != MagickFalse)
15956 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15957 if (windows->magnify.mapped != MagickFalse)
15958 (void) XWithdrawWindow(display,windows->magnify.id,
15959 windows->magnify.screen);
15960 if (windows->command.mapped != MagickFalse)
15961 (void) XWithdrawWindow(display,windows->command.id,
15962 windows->command.screen);
15963 }
15964 if (windows->pan.mapped != MagickFalse)
15965 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15966 if (resource_info->backdrop == MagickFalse)
15967 if (windows->backdrop.mapped)
15968 {
15969 (void) XWithdrawWindow(display,windows->backdrop.id,
15970 windows->backdrop.screen);
15971 (void) XDestroyWindow(display,windows->backdrop.id);
15972 windows->backdrop.id=(Window) NULL;
15973 (void) XWithdrawWindow(display,windows->image.id,
15974 windows->image.screen);
15975 (void) XDestroyWindow(display,windows->image.id);
15976 windows->image.id=(Window) NULL;
15977 }
15978 XSetCursorState(display,windows,MagickTrue);
15979 XCheckRefreshWindows(display,windows);
15980 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
15981 *state&=(~ExitState);
15982 if (*state & ExitState)
15983 {
15984 /*
15985 Free Standard Colormap.
15986 */
15987 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
15988 if (resource_info->map_type == (char *) NULL)
15989 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
15990 /*
15991 Free X resources.
15992 */
15993 if (resource_info->copy_image != (Image *) NULL)
15994 resource_info->copy_image=DestroyImage(resource_info->copy_image);
15995 DestroyXResources();
15996 }
15997 (void) XSync(display,MagickFalse);
15998 /*
15999 Restore our progress monitor and warning handlers.
16000 */
16001 (void) SetErrorHandler(warning_handler);
16002 (void) SetWarningHandler(warning_handler);
16003 /*
16004 Change to home directory.
16005 */
16006 directory=getcwd(working_directory,MaxTextExtent);
16007 (void) directory;
16008 {
16009 int
16010 status;
16011
16012 if (*resource_info->home_directory == '\0')
16013 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent);
16014 status=chdir(resource_info->home_directory);
16015 if (status == -1)
16016 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
16017 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
16018 }
16019 *image=display_image;
16020 return(nexus);
16021 }
16022 #else
16023
16024 /*
16025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16026 % %
16027 % %
16028 % %
16029 + D i s p l a y I m a g e s %
16030 % %
16031 % %
16032 % %
16033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16034 %
16035 % DisplayImages() displays an image sequence to any X window screen. It
16036 % returns a value other than 0 if successful. Check the exception member
16037 % of image to determine the reason for any failure.
16038 %
16039 % The format of the DisplayImages method is:
16040 %
16041 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16042 % Image *images)
16043 %
16044 % A description of each parameter follows:
16045 %
16046 % o image_info: the image info.
16047 %
16048 % o image: the image.
16049 %
16050 */
DisplayImages(const ImageInfo * image_info,Image * image)16051 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16052 Image *image)
16053 {
16054 assert(image_info != (const ImageInfo *) NULL);
16055 assert(image_info->signature == MagickCoreSignature);
16056 assert(image != (Image *) NULL);
16057 assert(image->signature == MagickCoreSignature);
16058 (void) image_info;
16059 if (image->debug != MagickFalse)
16060 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16061 (void) ThrowMagickException(&image->exception,GetMagickModule(),
16062 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
16063 image->filename);
16064 return(MagickFalse);
16065 }
16066
16067 /*
16068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16069 % %
16070 % %
16071 % %
16072 + R e m o t e D i s p l a y C o m m a n d %
16073 % %
16074 % %
16075 % %
16076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16077 %
16078 % RemoteDisplayCommand() encourages a remote display program to display the
16079 % specified image filename.
16080 %
16081 % The format of the RemoteDisplayCommand method is:
16082 %
16083 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16084 % const char *window,const char *filename,ExceptionInfo *exception)
16085 %
16086 % A description of each parameter follows:
16087 %
16088 % o image_info: the image info.
16089 %
16090 % o window: Specifies the name or id of an X window.
16091 %
16092 % o filename: the name of the image filename to display.
16093 %
16094 % o exception: return any errors or warnings in this structure.
16095 %
16096 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)16097 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16098 const char *window,const char *filename,ExceptionInfo *exception)
16099 {
16100 assert(image_info != (const ImageInfo *) NULL);
16101 assert(image_info->signature == MagickCoreSignature);
16102 assert(filename != (char *) NULL);
16103 (void) window;
16104 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16105 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16106 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16107 return(MagickFalse);
16108 }
16109 #endif
16110