MagickCore 6.9.13
Loading...
Searching...
No Matches
display.c
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 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/license/ %
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/locale-private.h"
69#include "magick/log.h"
70#include "magick/magick.h"
71#include "magick/memory_.h"
72#include "magick/monitor.h"
73#include "magick/monitor-private.h"
74#include "magick/montage.h"
75#include "magick/nt-base-private.h"
76#include "magick/option.h"
77#include "magick/paint.h"
78#include "magick/pixel.h"
79#include "magick/pixel-private.h"
80#include "magick/property.h"
81#include "magick/quantum.h"
82#include "magick/resize.h"
83#include "magick/resource_.h"
84#include "magick/shear.h"
85#include "magick/segment.h"
86#include "magick/statistic.h"
87#include "magick/string_.h"
88#include "magick/string-private.h"
89#include "magick/timer-private.h"
90#include "magick/transform.h"
91#include "magick/threshold.h"
92#include "magick/utility.h"
93#include "magick/utility-private.h"
94#include "magick/version.h"
95#include "magick/visual-effects.h"
96#include "magick/widget.h"
97#include "magick/xwindow-private.h"
98
99#if defined(MAGICKCORE_X11_DELEGATE)
100/*
101 Define declarations.
102*/
103#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
104
105/*
106 Constant declarations.
107*/
108static const unsigned char
109 HighlightBitmap[8] =
110 {
111 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
112 },
113 OpaqueBitmap[8] =
114 {
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
116 },
117 ShadowBitmap[8] =
118 {
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
120 };
121
122/*
123 Help widget declarations.
124*/
125static const char
126 ImageAnnotateHelp[] =
127 {
128 "In annotate mode, the Command widget has these options:\n"
129 "\n"
130 " Font Name\n"
131 " fixed\n"
132 " variable\n"
133 " 5x8\n"
134 " 6x10\n"
135 " 7x13bold\n"
136 " 8x13bold\n"
137 " 9x15bold\n"
138 " 10x20\n"
139 " 12x24\n"
140 " Browser...\n"
141 " Font Color\n"
142 " black\n"
143 " blue\n"
144 " cyan\n"
145 " green\n"
146 " gray\n"
147 " red\n"
148 " magenta\n"
149 " yellow\n"
150 " white\n"
151 " transparent\n"
152 " Browser...\n"
153 " Font Color\n"
154 " black\n"
155 " blue\n"
156 " cyan\n"
157 " green\n"
158 " gray\n"
159 " red\n"
160 " magenta\n"
161 " yellow\n"
162 " white\n"
163 " transparent\n"
164 " Browser...\n"
165 " Rotate Text\n"
166 " -90\n"
167 " -45\n"
168 " -30\n"
169 " 0\n"
170 " 30\n"
171 " 45\n"
172 " 90\n"
173 " 180\n"
174 " Dialog...\n"
175 " Help\n"
176 " Dismiss\n"
177 "\n"
178 "Choose a font name from the Font Name sub-menu. Additional\n"
179 "font names can be specified with the font browser. You can\n"
180 "change the menu names by setting the X resources font1\n"
181 "through font9.\n"
182 "\n"
183 "Choose a font color from the Font Color sub-menu.\n"
184 "Additional font colors can be specified with the color\n"
185 "browser. You can change the menu colors by setting the X\n"
186 "resources pen1 through pen9.\n"
187 "\n"
188 "If you select the color browser and press Grab, you can\n"
189 "choose the font color by moving the pointer to the desired\n"
190 "color on the screen and press any button.\n"
191 "\n"
192 "If you choose to rotate the text, choose Rotate Text from the\n"
193 "menu and select an angle. Typically you will only want to\n"
194 "rotate one line of text at a time. Depending on the angle you\n"
195 "choose, subsequent lines may end up overwriting each other.\n"
196 "\n"
197 "Choosing a font and its color is optional. The default font\n"
198 "is fixed and the default color is black. However, you must\n"
199 "choose a location to begin entering text and press button 1.\n"
200 "An underscore character will appear at the location of the\n"
201 "pointer. The cursor changes to a pencil to indicate you are\n"
202 "in text mode. To exit immediately, press Dismiss.\n"
203 "\n"
204 "In text mode, any key presses will display the character at\n"
205 "the location of the underscore and advance the underscore\n"
206 "cursor. Enter your text and once completed press Apply to\n"
207 "finish your image annotation. To correct errors press BACK\n"
208 "SPACE. To delete an entire line of text, press DELETE. Any\n"
209 "text that exceeds the boundaries of the image window is\n"
210 "automagically continued onto the next line.\n"
211 "\n"
212 "The actual color you request for the font is saved in the\n"
213 "image. However, the color that appears in your image window\n"
214 "may be different. For example, on a monochrome screen the\n"
215 "text will appear black or white even if you choose the color\n"
216 "red as the font color. However, the image saved to a file\n"
217 "with -write is written with red lettering. To assure the\n"
218 "correct color text in the final image, any PseudoClass image\n"
219 "is promoted to DirectClass (see miff(5)). To force a\n"
220 "PseudoClass image to remain PseudoClass, use -colors.\n"
221 },
222 ImageChopHelp[] =
223 {
224 "In chop mode, the Command widget has these options:\n"
225 "\n"
226 " Direction\n"
227 " horizontal\n"
228 " vertical\n"
229 " Help\n"
230 " Dismiss\n"
231 "\n"
232 "If the you choose the horizontal direction (this the\n"
233 "default), the area of the image between the two horizontal\n"
234 "endpoints of the chop line is removed. Otherwise, the area\n"
235 "of the image between the two vertical endpoints of the chop\n"
236 "line is removed.\n"
237 "\n"
238 "Select a location within the image window to begin your chop,\n"
239 "press and hold any button. Next, move the pointer to\n"
240 "another location in the image. As you move a line will\n"
241 "connect the initial location and the pointer. When you\n"
242 "release the button, the area within the image to chop is\n"
243 "determined by which direction you choose from the Command\n"
244 "widget.\n"
245 "\n"
246 "To cancel the image chopping, move the pointer back to the\n"
247 "starting point of the line and release the button.\n"
248 },
249 ImageColorEditHelp[] =
250 {
251 "In color edit mode, the Command widget has these options:\n"
252 "\n"
253 " Method\n"
254 " point\n"
255 " replace\n"
256 " floodfill\n"
257 " filltoborder\n"
258 " reset\n"
259 " Pixel Color\n"
260 " black\n"
261 " blue\n"
262 " cyan\n"
263 " green\n"
264 " gray\n"
265 " red\n"
266 " magenta\n"
267 " yellow\n"
268 " white\n"
269 " Browser...\n"
270 " Border Color\n"
271 " black\n"
272 " blue\n"
273 " cyan\n"
274 " green\n"
275 " gray\n"
276 " red\n"
277 " magenta\n"
278 " yellow\n"
279 " white\n"
280 " Browser...\n"
281 " Fuzz\n"
282 " 0%\n"
283 " 2%\n"
284 " 5%\n"
285 " 10%\n"
286 " 15%\n"
287 " Dialog...\n"
288 " Undo\n"
289 " Help\n"
290 " Dismiss\n"
291 "\n"
292 "Choose a color editing method from the Method sub-menu\n"
293 "of the Command widget. The point method recolors any pixel\n"
294 "selected with the pointer until the button is released. The\n"
295 "replace method recolors any pixel that matches the color of\n"
296 "the pixel you select with a button press. Floodfill recolors\n"
297 "any pixel that matches the color of the pixel you select with\n"
298 "a button press and is a neighbor. Whereas filltoborder recolors\n"
299 "any neighbor pixel that is not the border color. Finally reset\n"
300 "changes the entire image to the designated color.\n"
301 "\n"
302 "Next, choose a pixel color from the Pixel Color sub-menu.\n"
303 "Additional pixel colors can be specified with the color\n"
304 "browser. You can change the menu colors by setting the X\n"
305 "resources pen1 through pen9.\n"
306 "\n"
307 "Now press button 1 to select a pixel within the image window\n"
308 "to change its color. Additional pixels may be recolored as\n"
309 "prescribed by the method you choose.\n"
310 "\n"
311 "If the Magnify widget is mapped, it can be helpful in positioning\n"
312 "your pointer within the image (refer to button 2).\n"
313 "\n"
314 "The actual color you request for the pixels is saved in the\n"
315 "image. However, the color that appears in your image window\n"
316 "may be different. For example, on a monochrome screen the\n"
317 "pixel will appear black or white even if you choose the\n"
318 "color red as the pixel color. However, the image saved to a\n"
319 "file with -write is written with red pixels. To assure the\n"
320 "correct color text in the final image, any PseudoClass image\n"
321 "is promoted to DirectClass (see miff(5)). To force a\n"
322 "PseudoClass image to remain PseudoClass, use -colors.\n"
323 },
324 ImageCompositeHelp[] =
325 {
326 "First a widget window is displayed requesting you to enter an\n"
327 "image name. Press Composite, Grab or type a file name.\n"
328 "Press Cancel if you choose not to create a composite image.\n"
329 "When you choose Grab, move the pointer to the desired window\n"
330 "and press any button.\n"
331 "\n"
332 "If the Composite image does not have any matte information,\n"
333 "you are informed and the file browser is displayed again.\n"
334 "Enter the name of a mask image. The image is typically\n"
335 "grayscale and the same size as the composite image. If the\n"
336 "image is not grayscale, it is converted to grayscale and the\n"
337 "resulting intensities are used as matte information.\n"
338 "\n"
339 "A small window appears showing the location of the cursor in\n"
340 "the image window. You are now in composite mode. To exit\n"
341 "immediately, press Dismiss. In composite mode, the Command\n"
342 "widget has these options:\n"
343 "\n"
344 " Operators\n"
345 " Over\n"
346 " In\n"
347 " Out\n"
348 " Atop\n"
349 " Xor\n"
350 " Plus\n"
351 " Minus\n"
352 " Add\n"
353 " Subtract\n"
354 " Difference\n"
355 " Multiply\n"
356 " Bumpmap\n"
357 " Copy\n"
358 " CopyRed\n"
359 " CopyGreen\n"
360 " CopyBlue\n"
361 " CopyOpacity\n"
362 " Clear\n"
363 " Dissolve\n"
364 " Displace\n"
365 " Help\n"
366 " Dismiss\n"
367 "\n"
368 "Choose a composite operation from the Operators sub-menu of\n"
369 "the Command widget. How each operator behaves is described\n"
370 "below. Image window is the image currently displayed on\n"
371 "your X server and image is the image obtained with the File\n"
372 "Browser widget.\n"
373 "\n"
374 "Over The result is the union of the two image shapes,\n"
375 " with image obscuring image window in the region of\n"
376 " overlap.\n"
377 "\n"
378 "In The result is simply image cut by the shape of\n"
379 " image window. None of the image data of image\n"
380 " window is in the result.\n"
381 "\n"
382 "Out The resulting image is image with the shape of\n"
383 " image window cut out.\n"
384 "\n"
385 "Atop The result is the same shape as the image window,\n"
386 " with image obscuring image window where the image\n"
387 " shapes overlap. Note this differs from over\n"
388 " because the portion of image outside image window's\n"
389 " shape does not appear in the result.\n"
390 "\n"
391 "Xor The result is the image data from both image and\n"
392 " image window that is outside the overlap region.\n"
393 " The overlap region is blank.\n"
394 "\n"
395 "Plus The result is just the sum of the image data.\n"
396 " Output values are cropped to QuantumRange (no overflow).\n"
397 "\n"
398 "Minus The result of image - image window, with underflow\n"
399 " cropped to zero.\n"
400 "\n"
401 "Add The result of image + image window, with overflow\n"
402 " wrapping around (mod 256).\n"
403 "\n"
404 "Subtract The result of image - image window, with underflow\n"
405 " wrapping around (mod 256). The add and subtract\n"
406 " operators can be used to perform reversible\n"
407 " transformations.\n"
408 "\n"
409 "Difference\n"
410 " The result of abs(image - image window). This\n"
411 " useful for comparing two very similar images.\n"
412 "\n"
413 "Multiply\n"
414 " The result of image * image window. This\n"
415 " useful for the creation of drop-shadows.\n"
416 "\n"
417 "Bumpmap The result of surface normals from image * image\n"
418 " window.\n"
419 "\n"
420 "Copy The resulting image is image window replaced with\n"
421 " image. Here the matte information is ignored.\n"
422 "\n"
423 "CopyRed The red layer of the image window is replace with\n"
424 " the red layer of the image. The other layers are\n"
425 " untouched.\n"
426 "\n"
427 "CopyGreen\n"
428 " The green layer of the image window is replace with\n"
429 " the green layer of the image. The other layers are\n"
430 " untouched.\n"
431 "\n"
432 "CopyBlue The blue layer of the image window is replace with\n"
433 " the blue layer of the image. The other layers are\n"
434 " untouched.\n"
435 "\n"
436 "CopyOpacity\n"
437 " The matte layer of the image window is replace with\n"
438 " the matte layer of the image. The other layers are\n"
439 " untouched.\n"
440 "\n"
441 "The image compositor requires a matte, or alpha channel in\n"
442 "the image for some operations. This extra channel usually\n"
443 "defines a mask which represents a sort of a cookie-cutter\n"
444 "for the image. This the case when matte is opaque (full\n"
445 "coverage) for pixels inside the shape, zero outside, and\n"
446 "between 0 and QuantumRange on the boundary. If image does not\n"
447 "have a matte channel, it is initialized with 0 for any pixel\n"
448 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
449 "\n"
450 "If you choose Dissolve, the composite operator becomes Over. The\n"
451 "image matte channel percent transparency is initialized to factor.\n"
452 "The image window is initialized to (100-factor). Where factor is the\n"
453 "value you specify in the Dialog widget.\n"
454 "\n"
455 "Displace shifts the image pixels as defined by a displacement\n"
456 "map. With this option, image is used as a displacement map.\n"
457 "Black, within the displacement map, is a maximum positive\n"
458 "displacement. White is a maximum negative displacement and\n"
459 "middle gray is neutral. The displacement is scaled to determine\n"
460 "the pixel shift. By default, the displacement applies in both the\n"
461 "horizontal and vertical directions. However, if you specify a mask,\n"
462 "image is the horizontal X displacement and mask the vertical Y\n"
463 "displacement.\n"
464 "\n"
465 "Note that matte information for image window is not retained\n"
466 "for colormapped X server visuals (e.g. StaticColor,\n"
467 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
468 "behavior may require a TrueColor or DirectColor visual or a\n"
469 "Standard Colormap.\n"
470 "\n"
471 "Choosing a composite operator is optional. The default\n"
472 "operator is replace. However, you must choose a location to\n"
473 "composite your image and press button 1. Press and hold the\n"
474 "button before releasing and an outline of the image will\n"
475 "appear to help you identify your location.\n"
476 "\n"
477 "The actual colors of the composite image is saved. However,\n"
478 "the color that appears in image window may be different.\n"
479 "For example, on a monochrome screen image window will appear\n"
480 "black or white even though your composited image may have\n"
481 "many colors. If the image is saved to a file it is written\n"
482 "with the correct colors. To assure the correct colors are\n"
483 "saved in the final image, any PseudoClass image is promoted\n"
484 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
485 "to remain PseudoClass, use -colors.\n"
486 },
487 ImageCutHelp[] =
488 {
489 "In cut mode, the Command widget has these options:\n"
490 "\n"
491 " Help\n"
492 " Dismiss\n"
493 "\n"
494 "To define a cut region, press button 1 and drag. The\n"
495 "cut region is defined by a highlighted rectangle that\n"
496 "expands or contracts as it follows the pointer. Once you\n"
497 "are satisfied with the cut region, release the button.\n"
498 "You are now in rectify mode. In rectify mode, the Command\n"
499 "widget has these options:\n"
500 "\n"
501 " Cut\n"
502 " Help\n"
503 " Dismiss\n"
504 "\n"
505 "You can make adjustments by moving the pointer to one of the\n"
506 "cut rectangle corners, pressing a button, and dragging.\n"
507 "Finally, press Cut to commit your copy region. To\n"
508 "exit without cutting the image, press Dismiss.\n"
509 },
510 ImageCopyHelp[] =
511 {
512 "In copy mode, the Command widget has these options:\n"
513 "\n"
514 " Help\n"
515 " Dismiss\n"
516 "\n"
517 "To define a copy region, press button 1 and drag. The\n"
518 "copy region is defined by a highlighted rectangle that\n"
519 "expands or contracts as it follows the pointer. Once you\n"
520 "are satisfied with the copy region, release the button.\n"
521 "You are now in rectify mode. In rectify mode, the Command\n"
522 "widget has these options:\n"
523 "\n"
524 " Copy\n"
525 " Help\n"
526 " Dismiss\n"
527 "\n"
528 "You can make adjustments by moving the pointer to one of the\n"
529 "copy rectangle corners, pressing a button, and dragging.\n"
530 "Finally, press Copy to commit your copy region. To\n"
531 "exit without copying the image, press Dismiss.\n"
532 },
533 ImageCropHelp[] =
534 {
535 "In crop mode, the Command widget has these options:\n"
536 "\n"
537 " Help\n"
538 " Dismiss\n"
539 "\n"
540 "To define a cropping region, press button 1 and drag. The\n"
541 "cropping region is defined by a highlighted rectangle that\n"
542 "expands or contracts as it follows the pointer. Once you\n"
543 "are satisfied with the cropping region, release the button.\n"
544 "You are now in rectify mode. In rectify mode, the Command\n"
545 "widget has these options:\n"
546 "\n"
547 " Crop\n"
548 " Help\n"
549 " Dismiss\n"
550 "\n"
551 "You can make adjustments by moving the pointer to one of the\n"
552 "cropping rectangle corners, pressing a button, and dragging.\n"
553 "Finally, press Crop to commit your cropping region. To\n"
554 "exit without cropping the image, press Dismiss.\n"
555 },
556 ImageDrawHelp[] =
557 {
558 "The cursor changes to a crosshair to indicate you are in\n"
559 "draw mode. To exit immediately, press Dismiss. In draw mode,\n"
560 "the Command widget has these options:\n"
561 "\n"
562 " Element\n"
563 " point\n"
564 " line\n"
565 " rectangle\n"
566 " fill rectangle\n"
567 " circle\n"
568 " fill circle\n"
569 " ellipse\n"
570 " fill ellipse\n"
571 " polygon\n"
572 " fill polygon\n"
573 " Color\n"
574 " black\n"
575 " blue\n"
576 " cyan\n"
577 " green\n"
578 " gray\n"
579 " red\n"
580 " magenta\n"
581 " yellow\n"
582 " white\n"
583 " transparent\n"
584 " Browser...\n"
585 " Stipple\n"
586 " Brick\n"
587 " Diagonal\n"
588 " Scales\n"
589 " Vertical\n"
590 " Wavy\n"
591 " Translucent\n"
592 " Opaque\n"
593 " Open...\n"
594 " Width\n"
595 " 1\n"
596 " 2\n"
597 " 4\n"
598 " 8\n"
599 " 16\n"
600 " Dialog...\n"
601 " Undo\n"
602 " Help\n"
603 " Dismiss\n"
604 "\n"
605 "Choose a drawing primitive from the Element sub-menu.\n"
606 "\n"
607 "Choose a color from the Color sub-menu. Additional\n"
608 "colors can be specified with the color browser.\n"
609 "\n"
610 "If you choose the color browser and press Grab, you can\n"
611 "select the color by moving the pointer to the desired\n"
612 "color on the screen and press any button. The transparent\n"
613 "color updates the image matte channel and is useful for\n"
614 "image compositing.\n"
615 "\n"
616 "Choose a stipple, if appropriate, from the Stipple sub-menu.\n"
617 "Additional stipples can be specified with the file browser.\n"
618 "Stipples obtained from the file browser must be on disk in the\n"
619 "X11 bitmap format.\n"
620 "\n"
621 "Choose a width, if appropriate, from the Width sub-menu. To\n"
622 "choose a specific width select the Dialog widget.\n"
623 "\n"
624 "Choose a point in the Image window and press button 1 and\n"
625 "hold. Next, move the pointer to another location in the\n"
626 "image. As you move, a line connects the initial location and\n"
627 "the pointer. When you release the button, the image is\n"
628 "updated with the primitive you just drew. For polygons, the\n"
629 "image is updated when you press and release the button without\n"
630 "moving the pointer.\n"
631 "\n"
632 "To cancel image drawing, move the pointer back to the\n"
633 "starting point of the line and release the button.\n"
634 },
635 DisplayHelp[] =
636 {
637 "BUTTONS\n"
638 " The effects of each button press is described below. Three\n"
639 " buttons are required. If you have a two button mouse,\n"
640 " button 1 and 3 are returned. Press ALT and button 3 to\n"
641 " simulate button 2.\n"
642 "\n"
643 " 1 Press this button to map or unmap the Command widget.\n"
644 "\n"
645 " 2 Press and drag to define a region of the image to\n"
646 " magnify.\n"
647 "\n"
648 " 3 Press and drag to choose from a select set of commands.\n"
649 " This button behaves differently if the image being\n"
650 " displayed is a visual image directory. Here, choose a\n"
651 " particular tile of the directory and press this button and\n"
652 " drag to select a command from a pop-up menu. Choose from\n"
653 " these menu items:\n"
654 "\n"
655 " Open\n"
656 " Next\n"
657 " Former\n"
658 " Delete\n"
659 " Update\n"
660 "\n"
661 " If you choose Open, the image represented by the tile is\n"
662 " displayed. To return to the visual image directory, choose\n"
663 " Next from the Command widget. Next and Former moves to the\n"
664 " next or former image respectively. Choose Delete to delete\n"
665 " a particular image tile. Finally, choose Update to\n"
666 " synchronize all the image tiles with their respective\n"
667 " images.\n"
668 "\n"
669 "COMMAND WIDGET\n"
670 " The Command widget lists a number of sub-menus and commands.\n"
671 " They are\n"
672 "\n"
673 " File\n"
674 " Open...\n"
675 " Next\n"
676 " Former\n"
677 " Select...\n"
678 " Save...\n"
679 " Print...\n"
680 " Delete...\n"
681 " New...\n"
682 " Visual Directory...\n"
683 " Quit\n"
684 " Edit\n"
685 " Undo\n"
686 " Redo\n"
687 " Cut\n"
688 " Copy\n"
689 " Paste\n"
690 " View\n"
691 " Half Size\n"
692 " Original Size\n"
693 " Double Size\n"
694 " Resize...\n"
695 " Apply\n"
696 " Refresh\n"
697 " Restore\n"
698 " Transform\n"
699 " Crop\n"
700 " Chop\n"
701 " Flop\n"
702 " Flip\n"
703 " Rotate Right\n"
704 " Rotate Left\n"
705 " Rotate...\n"
706 " Shear...\n"
707 " Roll...\n"
708 " Trim Edges\n"
709 " Enhance\n"
710 " Brightness...\n"
711 " Saturation...\n"
712 " Hue...\n"
713 " Gamma...\n"
714 " Sharpen...\n"
715 " Dull\n"
716 " Contrast Stretch...\n"
717 " Sigmoidal Contrast...\n"
718 " Normalize\n"
719 " Equalize\n"
720 " Negate\n"
721 " Grayscale\n"
722 " Map...\n"
723 " Quantize...\n"
724 " Effects\n"
725 " Despeckle\n"
726 " Emboss\n"
727 " Reduce Noise\n"
728 " Add Noise\n"
729 " Sharpen...\n"
730 " Blur...\n"
731 " Threshold...\n"
732 " Edge Detect...\n"
733 " Spread...\n"
734 " Shade...\n"
735 " Painting...\n"
736 " Segment...\n"
737 " F/X\n"
738 " Solarize...\n"
739 " Sepia Tone...\n"
740 " Swirl...\n"
741 " Implode...\n"
742 " Vignette...\n"
743 " Wave...\n"
744 " Oil Painting...\n"
745 " Charcoal Drawing...\n"
746 " Image Edit\n"
747 " Annotate...\n"
748 " Draw...\n"
749 " Color...\n"
750 " Matte...\n"
751 " Composite...\n"
752 " Add Border...\n"
753 " Add Frame...\n"
754 " Comment...\n"
755 " Launch...\n"
756 " Region of Interest...\n"
757 " Miscellany\n"
758 " Image Info\n"
759 " Zoom Image\n"
760 " Show Preview...\n"
761 " Show Histogram\n"
762 " Show Matte\n"
763 " Background...\n"
764 " Slide Show\n"
765 " Preferences...\n"
766 " Help\n"
767 " Overview\n"
768 " Browse Documentation\n"
769 " About Display\n"
770 "\n"
771 " Menu items with a indented triangle have a sub-menu. They\n"
772 " are represented above as the indented items. To access a\n"
773 " sub-menu item, move the pointer to the appropriate menu and\n"
774 " press a button and drag. When you find the desired sub-menu\n"
775 " item, release the button and the command is executed. Move\n"
776 " the pointer away from the sub-menu if you decide not to\n"
777 " execute a particular command.\n"
778 "\n"
779 "KEYBOARD ACCELERATORS\n"
780 " Accelerators are one or two key presses that effect a\n"
781 " particular command. The keyboard accelerators that\n"
782 " display(1) understands is:\n"
783 "\n"
784 " Ctl+O Press to open an image from a file.\n"
785 "\n"
786 " space Press to display the next image.\n"
787 "\n"
788 " If the image is a multi-paged document such as a Postscript\n"
789 " document, you can skip ahead several pages by preceding\n"
790 " this command with a number. For example to display the\n"
791 " third page beyond the current page, press 3<space>.\n"
792 "\n"
793 " backspace Press to display the former image.\n"
794 "\n"
795 " If the image is a multi-paged document such as a Postscript\n"
796 " document, you can skip behind several pages by preceding\n"
797 " this command with a number. For example to display the\n"
798 " third page preceding the current page, press 3<backspace>.\n"
799 "\n"
800 " Ctl+S Press to write the image to a file.\n"
801 "\n"
802 " Ctl+P Press to print the image to a Postscript printer.\n"
803 "\n"
804 " Ctl+D Press to delete an image file.\n"
805 "\n"
806 " Ctl+N Press to create a blank canvas.\n"
807 "\n"
808 " Ctl+Q Press to discard all images and exit program.\n"
809 "\n"
810 " Ctl+Z Press to undo last image transformation.\n"
811 "\n"
812 " Ctl+R Press to redo last image transformation.\n"
813 "\n"
814 " Ctl+X Press to cut a region of the image.\n"
815 "\n"
816 " Ctl+C Press to copy a region of the image.\n"
817 "\n"
818 " Ctl+V Press to paste a region to the image.\n"
819 "\n"
820 " < Press to half the image size.\n"
821 "\n"
822 " - Press to return to the original image size.\n"
823 "\n"
824 " > Press to double the image size.\n"
825 "\n"
826 " % Press to resize the image to a width and height you\n"
827 " specify.\n"
828 "\n"
829 "Cmd-A Press to make any image transformations permanent."
830 "\n"
831 " By default, any image size transformations are applied\n"
832 " to the original image to create the image displayed on\n"
833 " the X server. However, the transformations are not\n"
834 " permanent (i.e. the original image does not change\n"
835 " size only the X image does). For example, if you\n"
836 " press > the X image will appear to double in size,\n"
837 " but the original image will in fact remain the same size.\n"
838 " To force the original image to double in size, press >\n"
839 " followed by Cmd-A.\n"
840 "\n"
841 " @ Press to refresh the image window.\n"
842 "\n"
843 " C Press to cut out a rectangular region of the image.\n"
844 "\n"
845 " [ Press to chop the image.\n"
846 "\n"
847 " H Press to flop image in the horizontal direction.\n"
848 "\n"
849 " V Press to flip image in the vertical direction.\n"
850 "\n"
851 " / Press to rotate the image 90 degrees clockwise.\n"
852 "\n"
853 " \\ Press to rotate the image 90 degrees counter-clockwise.\n"
854 "\n"
855 " * Press to rotate the image the number of degrees you\n"
856 " specify.\n"
857 "\n"
858 " S Press to shear the image the number of degrees you\n"
859 " specify.\n"
860 "\n"
861 " R Press to roll the image.\n"
862 "\n"
863 " T Press to trim the image edges.\n"
864 "\n"
865 " Shft-H Press to vary the image hue.\n"
866 "\n"
867 " Shft-S Press to vary the color saturation.\n"
868 "\n"
869 " Shft-L Press to vary the color brightness.\n"
870 "\n"
871 " Shft-G Press to gamma correct the image.\n"
872 "\n"
873 " Shft-C Press to sharpen the image contrast.\n"
874 "\n"
875 " Shft-Z Press to dull the image contrast.\n"
876 "\n"
877 " = Press to perform histogram equalization on the image.\n"
878 "\n"
879 " Shft-N Press to perform histogram normalization on the image.\n"
880 "\n"
881 " Shft-~ Press to negate the colors of the image.\n"
882 "\n"
883 " . Press to convert the image colors to gray.\n"
884 "\n"
885 " Shft-# Press to set the maximum number of unique colors in the\n"
886 " image.\n"
887 "\n"
888 " F2 Press to reduce the speckles in an image.\n"
889 "\n"
890 " F3 Press to eliminate peak noise from an image.\n"
891 "\n"
892 " F4 Press to add noise to an image.\n"
893 "\n"
894 " F5 Press to sharpen an image.\n"
895 "\n"
896 " F6 Press to delete an image file.\n"
897 "\n"
898 " F7 Press to threshold the image.\n"
899 "\n"
900 " F8 Press to detect edges within an image.\n"
901 "\n"
902 " F9 Press to emboss an image.\n"
903 "\n"
904 " F10 Press to displace pixels by a random amount.\n"
905 "\n"
906 " F11 Press to negate all pixels above the threshold level.\n"
907 "\n"
908 " F12 Press to shade the image using a distant light source.\n"
909 "\n"
910 " F13 Press to lighten or darken image edges to create a 3-D effect.\n"
911 "\n"
912 " F14 Press to segment the image by color.\n"
913 "\n"
914 " Meta-S Press to swirl image pixels about the center.\n"
915 "\n"
916 " Meta-I Press to implode image pixels about the center.\n"
917 "\n"
918 " Meta-W Press to alter an image along a sine wave.\n"
919 "\n"
920 " Meta-P Press to simulate an oil painting.\n"
921 "\n"
922 " Meta-C Press to simulate a charcoal drawing.\n"
923 "\n"
924 " Alt-A Press to annotate the image with text.\n"
925 "\n"
926 " Alt-D Press to draw on an image.\n"
927 "\n"
928 " Alt-P Press to edit an image pixel color.\n"
929 "\n"
930 " Alt-M Press to edit the image matte information.\n"
931 "\n"
932 " Alt-V Press to composite the image with another.\n"
933 "\n"
934 " Alt-B Press to add a border to the image.\n"
935 "\n"
936 " Alt-F Press to add an ornamental border to the image.\n"
937 "\n"
938 " Alt-Shft-!\n"
939 " Press to add an image comment.\n"
940 "\n"
941 " Ctl-A Press to apply image processing techniques to a region\n"
942 " of interest.\n"
943 "\n"
944 " Shft-? Press to display information about the image.\n"
945 "\n"
946 " Shft-+ Press to map the zoom image window.\n"
947 "\n"
948 " Shft-P Press to preview an image enhancement, effect, or f/x.\n"
949 "\n"
950 " F1 Press to display helpful information about display(1).\n"
951 "\n"
952 " Find Press to browse documentation about ImageMagick.\n"
953 "\n"
954 " 1-9 Press to change the level of magnification.\n"
955 "\n"
956 " Use the arrow keys to move the image one pixel up, down,\n"
957 " left, or right within the magnify window. Be sure to first\n"
958 " map the magnify window by pressing button 2.\n"
959 "\n"
960 " Press ALT and one of the arrow keys to trim off one pixel\n"
961 " from any side of the image.\n"
962 },
963 ImageMatteEditHelp[] =
964 {
965 "Matte information within an image is useful for some\n"
966 "operations such as image compositing (See IMAGE\n"
967 "COMPOSITING). This extra channel usually defines a mask\n"
968 "which represents a sort of a cookie-cutter for the image.\n"
969 "This the case when matte is opaque (full coverage) for\n"
970 "pixels inside the shape, zero outside, and between 0 and\n"
971 "QuantumRange on the boundary.\n"
972 "\n"
973 "A small window appears showing the location of the cursor in\n"
974 "the image window. You are now in matte edit mode. To exit\n"
975 "immediately, press Dismiss. In matte edit mode, the Command\n"
976 "widget has these options:\n"
977 "\n"
978 " Method\n"
979 " point\n"
980 " replace\n"
981 " floodfill\n"
982 " filltoborder\n"
983 " reset\n"
984 " Border Color\n"
985 " black\n"
986 " blue\n"
987 " cyan\n"
988 " green\n"
989 " gray\n"
990 " red\n"
991 " magenta\n"
992 " yellow\n"
993 " white\n"
994 " Browser...\n"
995 " Fuzz\n"
996 " 0%\n"
997 " 2%\n"
998 " 5%\n"
999 " 10%\n"
1000 " 15%\n"
1001 " Dialog...\n"
1002 " Matte\n"
1003 " Opaque\n"
1004 " Transparent\n"
1005 " Dialog...\n"
1006 " Undo\n"
1007 " Help\n"
1008 " Dismiss\n"
1009 "\n"
1010 "Choose a matte editing method from the Method sub-menu of\n"
1011 "the Command widget. The point method changes the matte value\n"
1012 "of any pixel selected with the pointer until the button is\n"
1013 "is released. The replace method changes the matte value of\n"
1014 "any pixel that matches the color of the pixel you select with\n"
1015 "a button press. Floodfill changes the matte value of any pixel\n"
1016 "that matches the color of the pixel you select with a button\n"
1017 "press and is a neighbor. Whereas filltoborder changes the matte\n"
1018 "value any neighbor pixel that is not the border color. Finally\n"
1019 "reset changes the entire image to the designated matte value.\n"
1020 "\n"
1021 "Choose Matte Value and pick Opaque or Transparent. For other values\n"
1022 "select the Dialog entry. Here a dialog appears requesting a matte\n"
1023 "value. The value you select is assigned as the opacity value of the\n"
1024 "selected pixel or pixels.\n"
1025 "\n"
1026 "Now, press any button to select a pixel within the image\n"
1027 "window to change its matte value.\n"
1028 "\n"
1029 "If the Magnify widget is mapped, it can be helpful in positioning\n"
1030 "your pointer within the image (refer to button 2).\n"
1031 "\n"
1032 "Matte information is only valid in a DirectClass image.\n"
1033 "Therefore, any PseudoClass image is promoted to DirectClass\n"
1034 "(see miff(5)). Note that matte information for PseudoClass\n"
1035 "is not retained for colormapped X server visuals (e.g.\n"
1036 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you\n"
1037 "immediately save your image to a file (refer to Write).\n"
1038 "Correct matte editing behavior may require a TrueColor or\n"
1039 "DirectColor visual or a Standard Colormap.\n"
1040 },
1041 ImagePanHelp[] =
1042 {
1043 "When an image exceeds the width or height of the X server\n"
1044 "screen, display maps a small panning icon. The rectangle\n"
1045 "within the panning icon shows the area that is currently\n"
1046 "displayed in the image window. To pan about the image,\n"
1047 "press any button and drag the pointer within the panning\n"
1048 "icon. The pan rectangle moves with the pointer and the\n"
1049 "image window is updated to reflect the location of the\n"
1050 "rectangle within the panning icon. When you have selected\n"
1051 "the area of the image you wish to view, release the button.\n"
1052 "\n"
1053 "Use the arrow keys to pan the image one pixel up, down,\n"
1054 "left, or right within the image window.\n"
1055 "\n"
1056 "The panning icon is withdrawn if the image becomes smaller\n"
1057 "than the dimensions of the X server screen.\n"
1058 },
1059 ImagePasteHelp[] =
1060 {
1061 "A small window appears showing the location of the cursor in\n"
1062 "the image window. You are now in paste mode. To exit\n"
1063 "immediately, press Dismiss. In paste mode, the Command\n"
1064 "widget has these options:\n"
1065 "\n"
1066 " Operators\n"
1067 " over\n"
1068 " in\n"
1069 " out\n"
1070 " atop\n"
1071 " xor\n"
1072 " plus\n"
1073 " minus\n"
1074 " add\n"
1075 " subtract\n"
1076 " difference\n"
1077 " replace\n"
1078 " Help\n"
1079 " Dismiss\n"
1080 "\n"
1081 "Choose a composite operation from the Operators sub-menu of\n"
1082 "the Command widget. How each operator behaves is described\n"
1083 "below. Image window is the image currently displayed on\n"
1084 "your X server and image is the image obtained with the File\n"
1085 "Browser widget.\n"
1086 "\n"
1087 "Over The result is the union of the two image shapes,\n"
1088 " with image obscuring image window in the region of\n"
1089 " overlap.\n"
1090 "\n"
1091 "In The result is simply image cut by the shape of\n"
1092 " image window. None of the image data of image\n"
1093 " window is in the result.\n"
1094 "\n"
1095 "Out The resulting image is image with the shape of\n"
1096 " image window cut out.\n"
1097 "\n"
1098 "Atop The result is the same shape as the image window,\n"
1099 " with image obscuring image window where the image\n"
1100 " shapes overlap. Note this differs from over\n"
1101 " because the portion of image outside image window's\n"
1102 " shape does not appear in the result.\n"
1103 "\n"
1104 "Xor The result is the image data from both image and\n"
1105 " image window that is outside the overlap region.\n"
1106 " The overlap region is blank.\n"
1107 "\n"
1108 "Plus The result is just the sum of the image data.\n"
1109 " Output values are cropped to QuantumRange (no overflow).\n"
1110 " This operation is independent of the matte\n"
1111 " channels.\n"
1112 "\n"
1113 "Minus The result of image - image window, with underflow\n"
1114 " cropped to zero.\n"
1115 "\n"
1116 "Add The result of image + image window, with overflow\n"
1117 " wrapping around (mod 256).\n"
1118 "\n"
1119 "Subtract The result of image - image window, with underflow\n"
1120 " wrapping around (mod 256). The add and subtract\n"
1121 " operators can be used to perform reversible\n"
1122 " transformations.\n"
1123 "\n"
1124 "Difference\n"
1125 " The result of abs(image - image window). This\n"
1126 " useful for comparing two very similar images.\n"
1127 "\n"
1128 "Copy The resulting image is image window replaced with\n"
1129 " image. Here the matte information is ignored.\n"
1130 "\n"
1131 "CopyRed The red layer of the image window is replace with\n"
1132 " the red layer of the image. The other layers are\n"
1133 " untouched.\n"
1134 "\n"
1135 "CopyGreen\n"
1136 " The green layer of the image window is replace with\n"
1137 " the green layer of the image. The other layers are\n"
1138 " untouched.\n"
1139 "\n"
1140 "CopyBlue The blue layer of the image window is replace with\n"
1141 " the blue layer of the image. The other layers are\n"
1142 " untouched.\n"
1143 "\n"
1144 "CopyOpacity\n"
1145 " The matte layer of the image window is replace with\n"
1146 " the matte layer of the image. The other layers are\n"
1147 " untouched.\n"
1148 "\n"
1149 "The image compositor requires a matte, or alpha channel in\n"
1150 "the image for some operations. This extra channel usually\n"
1151 "defines a mask which represents a sort of a cookie-cutter\n"
1152 "for the image. This the case when matte is opaque (full\n"
1153 "coverage) for pixels inside the shape, zero outside, and\n"
1154 "between 0 and QuantumRange on the boundary. If image does not\n"
1155 "have a matte channel, it is initialized with 0 for any pixel\n"
1156 "matching in color to pixel location (0,0), otherwise QuantumRange.\n"
1157 "\n"
1158 "Note that matte information for image window is not retained\n"
1159 "for colormapped X server visuals (e.g. StaticColor,\n"
1160 "StaticColor, GrayScale, PseudoColor). Correct compositing\n"
1161 "behavior may require a TrueColor or DirectColor visual or a\n"
1162 "Standard Colormap.\n"
1163 "\n"
1164 "Choosing a composite operator is optional. The default\n"
1165 "operator is replace. However, you must choose a location to\n"
1166 "paste your image and press button 1. Press and hold the\n"
1167 "button before releasing and an outline of the image will\n"
1168 "appear to help you identify your location.\n"
1169 "\n"
1170 "The actual colors of the pasted image is saved. However,\n"
1171 "the color that appears in image window may be different.\n"
1172 "For example, on a monochrome screen image window will appear\n"
1173 "black or white even though your pasted image may have\n"
1174 "many colors. If the image is saved to a file it is written\n"
1175 "with the correct colors. To assure the correct colors are\n"
1176 "saved in the final image, any PseudoClass image is promoted\n"
1177 "to DirectClass (see miff(5)). To force a PseudoClass image\n"
1178 "to remain PseudoClass, use -colors.\n"
1179 },
1180 ImageROIHelp[] =
1181 {
1182 "In region of interest mode, the Command widget has these\n"
1183 "options:\n"
1184 "\n"
1185 " Help\n"
1186 " Dismiss\n"
1187 "\n"
1188 "To define a region of interest, press button 1 and drag.\n"
1189 "The region of interest is defined by a highlighted rectangle\n"
1190 "that expands or contracts as it follows the pointer. Once\n"
1191 "you are satisfied with the region of interest, release the\n"
1192 "button. You are now in apply mode. In apply mode the\n"
1193 "Command widget has these options:\n"
1194 "\n"
1195 " File\n"
1196 " Save...\n"
1197 " Print...\n"
1198 " Edit\n"
1199 " Undo\n"
1200 " Redo\n"
1201 " Transform\n"
1202 " Flop\n"
1203 " Flip\n"
1204 " Rotate Right\n"
1205 " Rotate Left\n"
1206 " Enhance\n"
1207 " Hue...\n"
1208 " Saturation...\n"
1209 " Brightness...\n"
1210 " Gamma...\n"
1211 " Spiff\n"
1212 " Dull\n"
1213 " Contrast Stretch\n"
1214 " Sigmoidal Contrast...\n"
1215 " Normalize\n"
1216 " Equalize\n"
1217 " Negate\n"
1218 " Grayscale\n"
1219 " Map...\n"
1220 " Quantize...\n"
1221 " Effects\n"
1222 " Despeckle\n"
1223 " Emboss\n"
1224 " Reduce Noise\n"
1225 " Sharpen...\n"
1226 " Blur...\n"
1227 " Threshold...\n"
1228 " Edge Detect...\n"
1229 " Spread...\n"
1230 " Shade...\n"
1231 " Raise...\n"
1232 " Segment...\n"
1233 " F/X\n"
1234 " Solarize...\n"
1235 " Sepia Tone...\n"
1236 " Swirl...\n"
1237 " Implode...\n"
1238 " Vignette...\n"
1239 " Wave...\n"
1240 " Oil Painting...\n"
1241 " Charcoal Drawing...\n"
1242 " Miscellany\n"
1243 " Image Info\n"
1244 " Zoom Image\n"
1245 " Show Preview...\n"
1246 " Show Histogram\n"
1247 " Show Matte\n"
1248 " Help\n"
1249 " Dismiss\n"
1250 "\n"
1251 "You can make adjustments to the region of interest by moving\n"
1252 "the pointer to one of the rectangle corners, pressing a\n"
1253 "button, and dragging. Finally, choose an image processing\n"
1254 "technique from the Command widget. You can choose more than\n"
1255 "one image processing technique to apply to an area.\n"
1256 "Alternatively, you can move the region of interest before\n"
1257 "applying another image processing technique. To exit, press\n"
1258 "Dismiss.\n"
1259 },
1260 ImageRotateHelp[] =
1261 {
1262 "In rotate mode, the Command widget has these options:\n"
1263 "\n"
1264 " Pixel Color\n"
1265 " black\n"
1266 " blue\n"
1267 " cyan\n"
1268 " green\n"
1269 " gray\n"
1270 " red\n"
1271 " magenta\n"
1272 " yellow\n"
1273 " white\n"
1274 " Browser...\n"
1275 " Direction\n"
1276 " horizontal\n"
1277 " vertical\n"
1278 " Help\n"
1279 " Dismiss\n"
1280 "\n"
1281 "Choose a background color from the Pixel Color sub-menu.\n"
1282 "Additional background colors can be specified with the color\n"
1283 "browser. You can change the menu colors by setting the X\n"
1284 "resources pen1 through pen9.\n"
1285 "\n"
1286 "If you choose the color browser and press Grab, you can\n"
1287 "select the background color by moving the pointer to the\n"
1288 "desired color on the screen and press any button.\n"
1289 "\n"
1290 "Choose a point in the image window and press this button and\n"
1291 "hold. Next, move the pointer to another location in the\n"
1292 "image. As you move a line connects the initial location and\n"
1293 "the pointer. When you release the button, the degree of\n"
1294 "image rotation is determined by the slope of the line you\n"
1295 "just drew. The slope is relative to the direction you\n"
1296 "choose from the Direction sub-menu of the Command widget.\n"
1297 "\n"
1298 "To cancel the image rotation, move the pointer back to the\n"
1299 "starting point of the line and release the button.\n"
1300 };
1301
1302/*
1303 Enumeration declarations.
1304*/
1305typedef enum
1306{
1307 CopyMode,
1308 CropMode,
1309 CutMode
1310} ClipboardMode;
1311
1312typedef enum
1313{
1314 OpenCommand,
1315 NextCommand,
1316 FormerCommand,
1317 SelectCommand,
1318 SaveCommand,
1319 PrintCommand,
1320 DeleteCommand,
1321 NewCommand,
1322 VisualDirectoryCommand,
1323 QuitCommand,
1324 UndoCommand,
1325 RedoCommand,
1326 CutCommand,
1327 CopyCommand,
1328 PasteCommand,
1329 HalfSizeCommand,
1330 OriginalSizeCommand,
1331 DoubleSizeCommand,
1332 ResizeCommand,
1333 ApplyCommand,
1334 RefreshCommand,
1335 RestoreCommand,
1336 CropCommand,
1337 ChopCommand,
1338 FlopCommand,
1339 FlipCommand,
1340 RotateRightCommand,
1341 RotateLeftCommand,
1342 RotateCommand,
1343 ShearCommand,
1344 RollCommand,
1345 TrimCommand,
1346 HueCommand,
1347 SaturationCommand,
1348 BrightnessCommand,
1349 GammaCommand,
1350 SpiffCommand,
1351 DullCommand,
1352 ContrastStretchCommand,
1353 SigmoidalContrastCommand,
1354 NormalizeCommand,
1355 EqualizeCommand,
1356 NegateCommand,
1357 GrayscaleCommand,
1358 MapCommand,
1359 QuantizeCommand,
1360 DespeckleCommand,
1361 EmbossCommand,
1362 ReduceNoiseCommand,
1363 AddNoiseCommand,
1364 SharpenCommand,
1365 BlurCommand,
1366 ThresholdCommand,
1367 EdgeDetectCommand,
1368 SpreadCommand,
1369 ShadeCommand,
1370 RaiseCommand,
1371 SegmentCommand,
1372 SolarizeCommand,
1373 SepiaToneCommand,
1374 SwirlCommand,
1375 ImplodeCommand,
1376 VignetteCommand,
1377 WaveCommand,
1378 OilPaintCommand,
1379 CharcoalDrawCommand,
1380 AnnotateCommand,
1381 DrawCommand,
1382 ColorCommand,
1383 MatteCommand,
1384 CompositeCommand,
1385 AddBorderCommand,
1386 AddFrameCommand,
1387 CommentCommand,
1388 LaunchCommand,
1389 RegionOfInterestCommand,
1390 ROIHelpCommand,
1391 ROIDismissCommand,
1392 InfoCommand,
1393 ZoomCommand,
1394 ShowPreviewCommand,
1395 ShowHistogramCommand,
1396 ShowMatteCommand,
1397 BackgroundCommand,
1398 SlideShowCommand,
1399 PreferencesCommand,
1400 HelpCommand,
1401 BrowseDocumentationCommand,
1402 VersionCommand,
1403 SaveToUndoBufferCommand,
1404 FreeBuffersCommand,
1405 NullCommand
1406} DisplayCommand;
1407
1408typedef enum
1409{
1410 AnnotateNameCommand,
1411 AnnotateFontColorCommand,
1412 AnnotateBackgroundColorCommand,
1413 AnnotateRotateCommand,
1414 AnnotateHelpCommand,
1415 AnnotateDismissCommand,
1416 TextHelpCommand,
1417 TextApplyCommand,
1418 ChopDirectionCommand,
1419 ChopHelpCommand,
1420 ChopDismissCommand,
1421 HorizontalChopCommand,
1422 VerticalChopCommand,
1423 ColorEditMethodCommand,
1424 ColorEditColorCommand,
1425 ColorEditBorderCommand,
1426 ColorEditFuzzCommand,
1427 ColorEditUndoCommand,
1428 ColorEditHelpCommand,
1429 ColorEditDismissCommand,
1430 CompositeOperatorsCommand,
1431 CompositeDissolveCommand,
1432 CompositeDisplaceCommand,
1433 CompositeHelpCommand,
1434 CompositeDismissCommand,
1435 CropHelpCommand,
1436 CropDismissCommand,
1437 RectifyCopyCommand,
1438 RectifyHelpCommand,
1439 RectifyDismissCommand,
1440 DrawElementCommand,
1441 DrawColorCommand,
1442 DrawStippleCommand,
1443 DrawWidthCommand,
1444 DrawUndoCommand,
1445 DrawHelpCommand,
1446 DrawDismissCommand,
1447 MatteEditMethod,
1448 MatteEditBorderCommand,
1449 MatteEditFuzzCommand,
1450 MatteEditValueCommand,
1451 MatteEditUndoCommand,
1452 MatteEditHelpCommand,
1453 MatteEditDismissCommand,
1454 PasteOperatorsCommand,
1455 PasteHelpCommand,
1456 PasteDismissCommand,
1457 RotateColorCommand,
1458 RotateDirectionCommand,
1459 RotateCropCommand,
1460 RotateSharpenCommand,
1461 RotateHelpCommand,
1462 RotateDismissCommand,
1463 HorizontalRotateCommand,
1464 VerticalRotateCommand,
1465 TileLoadCommand,
1466 TileNextCommand,
1467 TileFormerCommand,
1468 TileDeleteCommand,
1469 TileUpdateCommand
1470} ModeType;
1471
1472/*
1473 Stipples.
1474*/
1475#define BricksWidth 20
1476#define BricksHeight 20
1477#define DiagonalWidth 16
1478#define DiagonalHeight 16
1479#define HighlightWidth 8
1480#define HighlightHeight 8
1481#define OpaqueWidth 8
1482#define OpaqueHeight 8
1483#define ScalesWidth 16
1484#define ScalesHeight 16
1485#define ShadowWidth 8
1486#define ShadowHeight 8
1487#define VerticalWidth 16
1488#define VerticalHeight 16
1489#define WavyWidth 16
1490#define WavyHeight 16
1491
1492/*
1493 Constant declaration.
1494*/
1495static const int
1496 RoiDelta = 8;
1497
1498static const unsigned char
1499 BricksBitmap[] =
1500 {
1501 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1502 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1503 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1504 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1505 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1506 },
1507 DiagonalBitmap[] =
1508 {
1509 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1510 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1511 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1512 },
1513 ScalesBitmap[] =
1514 {
1515 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1516 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1517 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1518 },
1519 VerticalBitmap[] =
1520 {
1521 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1522 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1523 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1524 },
1525 WavyBitmap[] =
1526 {
1527 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1528 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1529 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1530 };
1531
1532/*
1533 Function prototypes.
1534*/
1535static DisplayCommand
1536 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1537 const MagickStatusType,KeySym,Image **);
1538
1539static Image
1540 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const DisplayCommand,
1541 Image **),
1542 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1543 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
1544 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
1545
1546static MagickBooleanType
1547 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
1548 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1549 XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
1550 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
1551 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
1552 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1553 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
1554 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
1555 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
1556 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
1557 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
1558 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
1559 XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
1560 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
1561 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
1562
1563static void
1564 XDrawPanRectangle(Display *,XWindows *),
1565 XImageCache(Display *,XResourceInfo *,XWindows *,const DisplayCommand,Image **),
1566 XMagnifyImage(Display *,XWindows *,XEvent *),
1567 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
1568 XPanImage(Display *,XWindows *,XEvent *),
1569 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1570 const KeySym),
1571 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1572 XScreenEvent(Display *,XWindows *,XEvent *),
1573 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1574
1575/*
1576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577% %
1578% %
1579% %
1580% D i s p l a y I m a g e s %
1581% %
1582% %
1583% %
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585%
1586% DisplayImages() displays an image sequence to any X window screen. It
1587% returns a value other than 0 if successful. Check the exception member
1588% of image to determine the reason for any failure.
1589%
1590% The format of the DisplayImages method is:
1591%
1592% MagickBooleanType DisplayImages(const ImageInfo *image_info,
1593% Image *images)
1594%
1595% A description of each parameter follows:
1596%
1597% o image_info: the image info.
1598%
1599% o image: the image.
1600%
1601*/
1602MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1603 Image *images)
1604{
1605 char
1606 *argv[1];
1607
1608 Display
1609 *display;
1610
1611 Image
1612 *image;
1613
1614 size_t
1615 state;
1616
1617 ssize_t
1618 i;
1619
1620 XrmDatabase
1621 resource_database;
1622
1623 XResourceInfo
1624 resource_info;
1625
1626 assert(image_info != (const ImageInfo *) NULL);
1627 assert(image_info->signature == MagickCoreSignature);
1628 assert(images != (Image *) NULL);
1629 assert(images->signature == MagickCoreSignature);
1630 if (IsEventLogging() != MagickFalse)
1631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1632 display=XOpenDisplay(image_info->server_name);
1633 if (display == (Display *) NULL)
1634 {
1635 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1636 XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
1637 image_info->server_name));
1638 return(MagickFalse);
1639 }
1640 if (images->exception.severity != UndefinedException)
1641 CatchException(&images->exception);
1642 (void) XSetErrorHandler(XError);
1643 resource_database=XGetResourceDatabase(display,GetClientName());
1644 (void) memset(&resource_info,0,sizeof(resource_info));
1645 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1646 if (image_info->page != (char *) NULL)
1647 resource_info.image_geometry=AcquireString(image_info->page);
1648 resource_info.immutable=MagickTrue;
1649 argv[0]=AcquireString(GetClientName());
1650 state=DefaultState;
1651 for (i=0; (state & ExitState) == 0; i++)
1652 {
1653 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1654 break;
1655 image=GetImageFromList(images,i % GetImageListLength(images));
1656 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
1657 }
1658 (void) SetErrorHandler((ErrorHandler) NULL);
1659 (void) SetWarningHandler((WarningHandler) NULL);
1660 argv[0]=DestroyString(argv[0]);
1661 XDestroyResourceInfo(&resource_info);
1662 if (images->exception.severity != UndefinedException)
1663 return(MagickFalse);
1664 return(MagickTrue);
1665}
1666
1667/*
1668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669% %
1670% %
1671% %
1672% R e m o t e D i s p l a y C o m m a n d %
1673% %
1674% %
1675% %
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677%
1678% RemoteDisplayCommand() encourages a remote display program to display the
1679% specified image filename.
1680%
1681% The format of the RemoteDisplayCommand method is:
1682%
1683% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1684% const char *window,const char *filename,ExceptionInfo *exception)
1685%
1686% A description of each parameter follows:
1687%
1688% o image_info: the image info.
1689%
1690% o window: Specifies the name or id of an X window.
1691%
1692% o filename: the name of the image filename to display.
1693%
1694% o exception: return any errors or warnings in this structure.
1695%
1696*/
1697MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1698 const char *window,const char *filename,ExceptionInfo *exception)
1699{
1700 Display
1701 *display;
1702
1703 MagickStatusType
1704 status;
1705
1706 assert(image_info != (const ImageInfo *) NULL);
1707 assert(image_info->signature == MagickCoreSignature);
1708 assert(filename != (char *) NULL);
1709 if (IsEventLogging() != MagickFalse)
1710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1711 display=XOpenDisplay(image_info->server_name);
1712 if (display == (Display *) NULL)
1713 {
1714 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1715 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1716 return(MagickFalse);
1717 }
1718 (void) XSetErrorHandler(XError);
1719 status=XRemoteCommand(display,window,filename);
1720 (void) XCloseDisplay(display);
1721 return(status != 0 ? MagickTrue : MagickFalse);
1722}
1723
1724/*
1725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726% %
1727% %
1728% %
1729+ X A n n o t a t e E d i t I m a g e %
1730% %
1731% %
1732% %
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734%
1735% XAnnotateEditImage() annotates the image with text.
1736%
1737% The format of the XAnnotateEditImage method is:
1738%
1739% MagickBooleanType XAnnotateEditImage(Display *display,
1740% XResourceInfo *resource_info,XWindows *windows,Image *image)
1741%
1742% A description of each parameter follows:
1743%
1744% o display: Specifies a connection to an X server; returned from
1745% XOpenDisplay.
1746%
1747% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1748%
1749% o windows: Specifies a pointer to a XWindows structure.
1750%
1751% o image: the image; returned from ReadImage.
1752%
1753*/
1754
1755static MagickBooleanType XAnnotateEditImage(Display *display,
1756 XResourceInfo *resource_info,XWindows *windows,Image *image)
1757{
1758 const char
1759 *const AnnotateMenu[] =
1760 {
1761 "Font Name",
1762 "Font Color",
1763 "Box Color",
1764 "Rotate Text",
1765 "Help",
1766 "Dismiss",
1767 (char *) NULL
1768 },
1769 *const TextMenu[] =
1770 {
1771 "Help",
1772 "Apply",
1773 (char *) NULL
1774 };
1775
1776 static const ModeType
1777 AnnotateCommands[] =
1778 {
1779 AnnotateNameCommand,
1780 AnnotateFontColorCommand,
1781 AnnotateBackgroundColorCommand,
1782 AnnotateRotateCommand,
1783 AnnotateHelpCommand,
1784 AnnotateDismissCommand
1785 },
1786 TextCommands[] =
1787 {
1788 TextHelpCommand,
1789 TextApplyCommand
1790 };
1791
1792 static MagickBooleanType
1793 transparent_box = MagickTrue,
1794 transparent_pen = MagickFalse;
1795
1796 static MagickRealType
1797 degrees = 0.0;
1798
1799 static unsigned int
1800 box_id = MaxNumberPens-2,
1801 font_id = 0,
1802 pen_id = 0;
1803
1804 char
1805 command[MaxTextExtent],
1806 *p,
1807 text[MaxTextExtent];
1808
1809 const char
1810 *ColorMenu[MaxNumberPens+1];
1811
1812 Cursor
1813 cursor;
1814
1815 GC
1816 annotate_context;
1817
1818 int
1819 id,
1820 pen_number,
1821 status,
1822 x,
1823 y;
1824
1825 KeySym
1826 key_symbol;
1827
1828 size_t
1829 state;
1830
1831 ssize_t
1832 i;
1833
1834 unsigned int
1835 height,
1836 width;
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+=(ptrdiff_t) 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 magick_fallthrough;
2466 }
2467 case XK_Return:
2468 case XK_KP_Enter:
2469 {
2470 /*
2471 Advance to the next line of text.
2472 */
2473 *p='\0';
2474 annotate_info->width=(unsigned int) XTextWidth(font_info,
2475 annotate_info->text,(int) strlen(annotate_info->text));
2476 if (annotate_info->next != (XAnnotateInfo *) NULL)
2477 {
2478 /*
2479 Line of text already exists.
2480 */
2481 annotate_info=annotate_info->next;
2482 x=annotate_info->x;
2483 y=annotate_info->y;
2484 p=annotate_info->text;
2485 break;
2486 }
2487 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2488 sizeof(*annotate_info->next));
2489 if (annotate_info->next == (XAnnotateInfo *) NULL)
2490 return(MagickFalse);
2491 *annotate_info->next=(*annotate_info);
2492 annotate_info->next->previous=annotate_info;
2493 annotate_info=annotate_info->next;
2494 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2495 windows->image.width/MagickMax((ssize_t)
2496 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2497 if (annotate_info->text == (char *) NULL)
2498 return(MagickFalse);
2499 annotate_info->y+=annotate_info->height;
2500 if (annotate_info->y > (int) windows->image.height)
2501 annotate_info->y=(int) annotate_info->height;
2502 annotate_info->next=(XAnnotateInfo *) NULL;
2503 x=annotate_info->x;
2504 y=annotate_info->y;
2505 p=annotate_info->text;
2506 break;
2507 }
2508 }
2509 break;
2510 }
2511 case KeyRelease:
2512 {
2513 /*
2514 Respond to a user key release.
2515 */
2516 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2517 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2518 state&=(~ModifierState);
2519 break;
2520 }
2521 case SelectionNotify:
2522 {
2523 Atom
2524 type;
2525
2526 int
2527 format;
2528
2529 unsigned char
2530 *data;
2531
2532 unsigned long
2533 after,
2534 length;
2535
2536 /*
2537 Obtain response from primary selection.
2538 */
2539 if (event.xselection.property == (Atom) None)
2540 break;
2541 status=XGetWindowProperty(display,event.xselection.requestor,
2542 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
2543 &type,&format,&length,&after,&data);
2544 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2545 (length == 0))
2546 break;
2547 /*
2548 Annotate Image window with primary selection.
2549 */
2550 for (i=0; i < (ssize_t) length; i++)
2551 {
2552 if ((char) data[i] != '\n')
2553 {
2554 /*
2555 Draw a single character on the Image window.
2556 */
2557 *p=(char) data[i];
2558 (void) XDrawString(display,windows->image.id,annotate_context,
2559 x,y,p,1);
2560 x+=XTextWidth(font_info,p,1);
2561 p++;
2562 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2563 continue;
2564 }
2565 /*
2566 Advance to the next line of text.
2567 */
2568 *p='\0';
2569 annotate_info->width=(unsigned int) XTextWidth(font_info,
2570 annotate_info->text,(int) strlen(annotate_info->text));
2571 if (annotate_info->next != (XAnnotateInfo *) NULL)
2572 {
2573 /*
2574 Line of text already exists.
2575 */
2576 annotate_info=annotate_info->next;
2577 x=annotate_info->x;
2578 y=annotate_info->y;
2579 p=annotate_info->text;
2580 continue;
2581 }
2582 annotate_info->next=(XAnnotateInfo *) AcquireQuantumMemory(1,
2583 sizeof(*annotate_info->next));
2584 if (annotate_info->next == (XAnnotateInfo *) NULL)
2585 return(MagickFalse);
2586 *annotate_info->next=(*annotate_info);
2587 annotate_info->next->previous=annotate_info;
2588 annotate_info=annotate_info->next;
2589 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2590 windows->image.width/MagickMax((ssize_t)
2591 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2592 if (annotate_info->text == (char *) NULL)
2593 return(MagickFalse);
2594 annotate_info->y+=annotate_info->height;
2595 if (annotate_info->y > (int) windows->image.height)
2596 annotate_info->y=(int) annotate_info->height;
2597 annotate_info->next=(XAnnotateInfo *) NULL;
2598 x=annotate_info->x;
2599 y=annotate_info->y;
2600 p=annotate_info->text;
2601 }
2602 (void) XFree((void *) data);
2603 break;
2604 }
2605 default:
2606 break;
2607 }
2608 } while ((state & ExitState) == 0);
2609 (void) XFreeCursor(display,cursor);
2610 /*
2611 Annotation is relative to image configuration.
2612 */
2613 width=(unsigned int) image->columns;
2614 height=(unsigned int) image->rows;
2615 x=0;
2616 y=0;
2617 if (windows->image.crop_geometry != (char *) NULL)
2618 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2619 /*
2620 Initialize annotated image.
2621 */
2622 XSetCursorState(display,windows,MagickTrue);
2623 XCheckRefreshWindows(display,windows);
2624 while (annotate_info != (XAnnotateInfo *) NULL)
2625 {
2626 if (annotate_info->width == 0)
2627 {
2628 /*
2629 No text on this line-- go to the next line of text.
2630 */
2631 previous_info=annotate_info->previous;
2632 annotate_info->text=(char *)
2633 RelinquishMagickMemory(annotate_info->text);
2634 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2635 annotate_info=previous_info;
2636 continue;
2637 }
2638 /*
2639 Determine pixel index for box and pen color.
2640 */
2641 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2642 if (windows->pixel_info->colors != 0)
2643 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2644 if (windows->pixel_info->pixels[i] ==
2645 windows->pixel_info->pen_colors[box_id].pixel)
2646 {
2647 windows->pixel_info->box_index=(unsigned short) i;
2648 break;
2649 }
2650 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2651 if (windows->pixel_info->colors != 0)
2652 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2653 if (windows->pixel_info->pixels[i] ==
2654 windows->pixel_info->pen_colors[pen_id].pixel)
2655 {
2656 windows->pixel_info->pen_index=(unsigned short) i;
2657 break;
2658 }
2659 /*
2660 Define the annotate geometry string.
2661 */
2662 annotate_info->x=(int)
2663 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2664 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2665 windows->image.y)/windows->image.ximage->height;
2666 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
2667 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2668 height*annotate_info->height/windows->image.ximage->height,
2669 annotate_info->x+x,annotate_info->y+y);
2670 /*
2671 Annotate image with text.
2672 */
2673 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
2674 if (status == 0)
2675 return(MagickFalse);
2676 /*
2677 Free up memory.
2678 */
2679 previous_info=annotate_info->previous;
2680 annotate_info->text=DestroyString(annotate_info->text);
2681 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2682 annotate_info=previous_info;
2683 }
2684 (void) XSetForeground(display,annotate_context,
2685 windows->pixel_info->foreground_color.pixel);
2686 (void) XSetBackground(display,annotate_context,
2687 windows->pixel_info->background_color.pixel);
2688 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2689 XSetCursorState(display,windows,MagickFalse);
2690 (void) XFreeFont(display,font_info);
2691 /*
2692 Update image configuration.
2693 */
2694 XConfigureImageColormap(display,resource_info,windows,image);
2695 (void) XConfigureImage(display,resource_info,windows,image);
2696 return(MagickTrue);
2697}
2698
2699/*
2700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2701% %
2702% %
2703% %
2704+ X B a c k g r o u n d I m a g e %
2705% %
2706% %
2707% %
2708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709%
2710% XBackgroundImage() displays the image in the background of a window.
2711%
2712% The format of the XBackgroundImage method is:
2713%
2714% MagickBooleanType XBackgroundImage(Display *display,
2715% XResourceInfo *resource_info,XWindows *windows,Image **image)
2716%
2717% A description of each parameter follows:
2718%
2719% o display: Specifies a connection to an X server; returned from
2720% XOpenDisplay.
2721%
2722% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2723%
2724% o windows: Specifies a pointer to a XWindows structure.
2725%
2726% o image: the image.
2727%
2728*/
2729static MagickBooleanType XBackgroundImage(Display *display,
2730 XResourceInfo *resource_info,XWindows *windows,Image **image)
2731{
2732#define BackgroundImageTag "Background/Image"
2733
2734 int
2735 status;
2736
2737 static char
2738 window_id[MaxTextExtent] = "root";
2739
2740 XResourceInfo
2741 background_resources;
2742
2743 /*
2744 Put image in background.
2745 */
2746 status=XDialogWidget(display,windows,"Background",
2747 "Enter window id (id 0x00 selects window with pointer):",window_id);
2748 if (*window_id == '\0')
2749 return(MagickFalse);
2750 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
2751 XInfoWidget(display,windows,BackgroundImageTag);
2752 XSetCursorState(display,windows,MagickTrue);
2753 XCheckRefreshWindows(display,windows);
2754 background_resources=(*resource_info);
2755 background_resources.window_id=window_id;
2756 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2757 status=XDisplayBackgroundImage(display,&background_resources,*image);
2758 if (status != MagickFalse)
2759 XClientMessage(display,windows->image.id,windows->im_protocols,
2760 windows->im_retain_colors,CurrentTime);
2761 XSetCursorState(display,windows,MagickFalse);
2762 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
2763 return(MagickTrue);
2764}
2765
2766/*
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768% %
2769% %
2770% %
2771+ X C h o p I m a g e %
2772% %
2773% %
2774% %
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776%
2777% XChopImage() chops the X image.
2778%
2779% The format of the XChopImage method is:
2780%
2781% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2782% XWindows *windows,Image **image)
2783%
2784% A description of each parameter follows:
2785%
2786% o display: Specifies a connection to an X server; returned from
2787% XOpenDisplay.
2788%
2789% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2790%
2791% o windows: Specifies a pointer to a XWindows structure.
2792%
2793% o image: the image.
2794%
2795*/
2796static MagickBooleanType XChopImage(Display *display,
2797 XResourceInfo *resource_info,XWindows *windows,Image **image)
2798{
2799 const char
2800 *const ChopMenu[] =
2801 {
2802 "Direction",
2803 "Help",
2804 "Dismiss",
2805 (char *) NULL
2806 };
2807
2808 static ModeType
2809 direction = HorizontalChopCommand;
2810
2811 static const ModeType
2812 ChopCommands[] =
2813 {
2814 ChopDirectionCommand,
2815 ChopHelpCommand,
2816 ChopDismissCommand
2817 },
2818 DirectionCommands[] =
2819 {
2820 HorizontalChopCommand,
2821 VerticalChopCommand
2822 };
2823
2824 char
2825 text[MaxTextExtent];
2826
2827 Image
2828 *chop_image;
2829
2830 int
2831 id,
2832 x,
2833 y;
2834
2835 MagickRealType
2836 scale_factor;
2837
2838 RectangleInfo
2839 chop_info;
2840
2841 unsigned int
2842 distance,
2843 height,
2844 width;
2845
2846 size_t
2847 state;
2848
2849 XEvent
2850 event;
2851
2852 XSegment
2853 segment_info;
2854
2855 /*
2856 Map Command widget.
2857 */
2858 (void) CloneString(&windows->command.name,"Chop");
2859 windows->command.data=1;
2860 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2861 (void) XMapRaised(display,windows->command.id);
2862 XClientMessage(display,windows->image.id,windows->im_protocols,
2863 windows->im_update_widget,CurrentTime);
2864 /*
2865 Track pointer until button 1 is pressed.
2866 */
2867 XQueryPosition(display,windows->image.id,&x,&y);
2868 (void) XSelectInput(display,windows->image.id,
2869 windows->image.attributes.event_mask | PointerMotionMask);
2870 state=DefaultState;
2871 (void) memset(&segment_info,0,sizeof(segment_info));
2872 do
2873 {
2874 if (windows->info.mapped != MagickFalse)
2875 {
2876 /*
2877 Display pointer position.
2878 */
2879 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
2880 x+windows->image.x,y+windows->image.y);
2881 XInfoWidget(display,windows,text);
2882 }
2883 /*
2884 Wait for next event.
2885 */
2886 XScreenEvent(display,windows,&event);
2887 if (event.xany.window == windows->command.id)
2888 {
2889 /*
2890 Select a command from the Command widget.
2891 */
2892 id=XCommandWidget(display,windows,ChopMenu,&event);
2893 if (id < 0)
2894 continue;
2895 switch (ChopCommands[id])
2896 {
2897 case ChopDirectionCommand:
2898 {
2899 char
2900 command[MaxTextExtent];
2901
2902 const char
2903 *const Directions[] =
2904 {
2905 "horizontal",
2906 "vertical",
2907 (char *) NULL,
2908 };
2909
2910 /*
2911 Select a command from the pop-up menu.
2912 */
2913 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2914 if (id >= 0)
2915 direction=DirectionCommands[id];
2916 break;
2917 }
2918 case ChopHelpCommand:
2919 {
2920 XTextViewHelp(display,resource_info,windows,MagickFalse,
2921 "Help Viewer - Image Chop",ImageChopHelp);
2922 break;
2923 }
2924 case ChopDismissCommand:
2925 {
2926 /*
2927 Prematurely exit.
2928 */
2929 state|=EscapeState;
2930 state|=ExitState;
2931 break;
2932 }
2933 default:
2934 break;
2935 }
2936 continue;
2937 }
2938 switch (event.type)
2939 {
2940 case ButtonPress:
2941 {
2942 if (event.xbutton.button != Button1)
2943 break;
2944 if (event.xbutton.window != windows->image.id)
2945 break;
2946 /*
2947 User has committed to start point of chopping line.
2948 */
2949 segment_info.x1=(short int) event.xbutton.x;
2950 segment_info.x2=(short int) event.xbutton.x;
2951 segment_info.y1=(short int) event.xbutton.y;
2952 segment_info.y2=(short int) event.xbutton.y;
2953 state|=ExitState;
2954 break;
2955 }
2956 case ButtonRelease:
2957 break;
2958 case Expose:
2959 break;
2960 case KeyPress:
2961 {
2962 char
2963 command[MaxTextExtent];
2964
2965 KeySym
2966 key_symbol;
2967
2968 if (event.xkey.window != windows->image.id)
2969 break;
2970 /*
2971 Respond to a user key press.
2972 */
2973 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2974 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2975 switch ((int) key_symbol)
2976 {
2977 case XK_Escape:
2978 case XK_F20:
2979 {
2980 /*
2981 Prematurely exit.
2982 */
2983 state|=EscapeState;
2984 state|=ExitState;
2985 break;
2986 }
2987 case XK_F1:
2988 case XK_Help:
2989 {
2990 (void) XSetFunction(display,windows->image.highlight_context,
2991 GXcopy);
2992 XTextViewHelp(display,resource_info,windows,MagickFalse,
2993 "Help Viewer - Image Chop",ImageChopHelp);
2994 (void) XSetFunction(display,windows->image.highlight_context,
2995 GXinvert);
2996 break;
2997 }
2998 default:
2999 {
3000 (void) XBell(display,0);
3001 break;
3002 }
3003 }
3004 break;
3005 }
3006 case MotionNotify:
3007 {
3008 /*
3009 Map and unmap Info widget as text cursor crosses its boundaries.
3010 */
3011 x=event.xmotion.x;
3012 y=event.xmotion.y;
3013 if (windows->info.mapped != MagickFalse)
3014 {
3015 if ((x < (int) (windows->info.x+windows->info.width)) &&
3016 (y < (int) (windows->info.y+windows->info.height)))
3017 (void) XWithdrawWindow(display,windows->info.id,
3018 windows->info.screen);
3019 }
3020 else
3021 if ((x > (int) (windows->info.x+windows->info.width)) ||
3022 (y > (int) (windows->info.y+windows->info.height)))
3023 (void) XMapWindow(display,windows->info.id);
3024 }
3025 }
3026 } while ((state & ExitState) == 0);
3027 (void) XSelectInput(display,windows->image.id,
3028 windows->image.attributes.event_mask);
3029 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3030 if ((state & EscapeState) != 0)
3031 return(MagickTrue);
3032 /*
3033 Draw line as pointer moves until the mouse button is released.
3034 */
3035 chop_info.width=0;
3036 chop_info.height=0;
3037 chop_info.x=0;
3038 chop_info.y=0;
3039 distance=0;
3040 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3041 state=DefaultState;
3042 do
3043 {
3044 if (distance > 9)
3045 {
3046 /*
3047 Display info and draw chopping line.
3048 */
3049 if (windows->info.mapped == MagickFalse)
3050 (void) XMapWindow(display,windows->info.id);
3051 (void) FormatLocaleString(text,MaxTextExtent,
3052 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3053 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3054 XInfoWidget(display,windows,text);
3055 XHighlightLine(display,windows->image.id,
3056 windows->image.highlight_context,&segment_info);
3057 }
3058 else
3059 if (windows->info.mapped != MagickFalse)
3060 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3061 /*
3062 Wait for next event.
3063 */
3064 XScreenEvent(display,windows,&event);
3065 if (distance > 9)
3066 XHighlightLine(display,windows->image.id,
3067 windows->image.highlight_context,&segment_info);
3068 switch (event.type)
3069 {
3070 case ButtonPress:
3071 {
3072 segment_info.x2=(short int) event.xmotion.x;
3073 segment_info.y2=(short int) event.xmotion.y;
3074 break;
3075 }
3076 case ButtonRelease:
3077 {
3078 /*
3079 User has committed to chopping line.
3080 */
3081 segment_info.x2=(short int) event.xbutton.x;
3082 segment_info.y2=(short int) event.xbutton.y;
3083 state|=ExitState;
3084 break;
3085 }
3086 case Expose:
3087 break;
3088 case MotionNotify:
3089 {
3090 segment_info.x2=(short int) event.xmotion.x;
3091 segment_info.y2=(short int) event.xmotion.y;
3092 }
3093 default:
3094 break;
3095 }
3096 /*
3097 Check boundary conditions.
3098 */
3099 if (segment_info.x2 < 0)
3100 segment_info.x2=0;
3101 else
3102 if (segment_info.x2 > windows->image.ximage->width)
3103 segment_info.x2=windows->image.ximage->width;
3104 if (segment_info.y2 < 0)
3105 segment_info.y2=0;
3106 else
3107 if (segment_info.y2 > windows->image.ximage->height)
3108 segment_info.y2=windows->image.ximage->height;
3109 distance=(unsigned int)
3110 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3111 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3112 /*
3113 Compute chopping geometry.
3114 */
3115 if (direction == HorizontalChopCommand)
3116 {
3117 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3118 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3119 chop_info.height=0;
3120 chop_info.y=0;
3121 if (segment_info.x1 > (int) segment_info.x2)
3122 {
3123 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3124 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3125 }
3126 }
3127 else
3128 {
3129 chop_info.width=0;
3130 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3131 chop_info.x=0;
3132 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3133 if (segment_info.y1 > segment_info.y2)
3134 {
3135 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3136 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3137 }
3138 }
3139 } while ((state & ExitState) == 0);
3140 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3141 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3142 if (distance <= 9)
3143 return(MagickTrue);
3144 /*
3145 Image chopping is relative to image configuration.
3146 */
3147 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
3148 XSetCursorState(display,windows,MagickTrue);
3149 XCheckRefreshWindows(display,windows);
3150 windows->image.window_changes.width=windows->image.ximage->width-
3151 (unsigned int) chop_info.width;
3152 windows->image.window_changes.height=windows->image.ximage->height-
3153 (unsigned int) chop_info.height;
3154 width=(unsigned int) (*image)->columns;
3155 height=(unsigned int) (*image)->rows;
3156 x=0;
3157 y=0;
3158 if (windows->image.crop_geometry != (char *) NULL)
3159 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3160 scale_factor=(MagickRealType) width/windows->image.ximage->width;
3161 chop_info.x+=x;
3162 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3163 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3164 scale_factor=(MagickRealType) height/windows->image.ximage->height;
3165 chop_info.y+=y;
3166 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3167 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3168 /*
3169 Chop image.
3170 */
3171 chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
3172 XSetCursorState(display,windows,MagickFalse);
3173 if (chop_image == (Image *) NULL)
3174 return(MagickFalse);
3175 *image=DestroyImage(*image);
3176 *image=chop_image;
3177 /*
3178 Update image configuration.
3179 */
3180 XConfigureImageColormap(display,resource_info,windows,*image);
3181 (void) XConfigureImage(display,resource_info,windows,*image);
3182 return(MagickTrue);
3183}
3184
3185/*
3186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3187% %
3188% %
3189% %
3190+ X C o l o r E d i t I m a g e %
3191% %
3192% %
3193% %
3194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3195%
3196% XColorEditImage() allows the user to interactively change the color of one
3197% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3198%
3199% The format of the XColorEditImage method is:
3200%
3201% MagickBooleanType XColorEditImage(Display *display,
3202% XResourceInfo *resource_info,XWindows *windows,Image **image)
3203%
3204% A description of each parameter follows:
3205%
3206% o display: Specifies a connection to an X server; returned from
3207% XOpenDisplay.
3208%
3209% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3210%
3211% o windows: Specifies a pointer to a XWindows structure.
3212%
3213% o image: the image; returned from ReadImage.
3214%
3215*/
3216
3217
3218static MagickBooleanType XColorEditImage(Display *display,
3219 XResourceInfo *resource_info,XWindows *windows,Image **image)
3220{
3221 const char
3222 *const ColorEditMenu[] =
3223 {
3224 "Method",
3225 "Pixel Color",
3226 "Border Color",
3227 "Fuzz",
3228 "Undo",
3229 "Help",
3230 "Dismiss",
3231 (char *) NULL
3232 };
3233
3234 static const ModeType
3235 ColorEditCommands[] =
3236 {
3237 ColorEditMethodCommand,
3238 ColorEditColorCommand,
3239 ColorEditBorderCommand,
3240 ColorEditFuzzCommand,
3241 ColorEditUndoCommand,
3242 ColorEditHelpCommand,
3243 ColorEditDismissCommand
3244 };
3245
3246 static PaintMethod
3247 method = PointMethod;
3248
3249 static unsigned int
3250 pen_id = 0;
3251
3252 static XColor
3253 border_color = { 0, 0, 0, 0, 0, 0 };
3254
3255 char
3256 command[MaxTextExtent] = "",
3257 text[MaxTextExtent] = "";
3258
3259 Cursor
3260 cursor;
3261
3262 ExceptionInfo
3263 *exception;
3264
3265 int
3266 entry,
3267 id,
3268 x,
3269 x_offset,
3270 y,
3271 y_offset;
3272
3273 PixelPacket
3274 *q;
3275
3276 size_t
3277 state;
3278
3279 ssize_t
3280 i;
3281
3282 unsigned int
3283 height,
3284 width;
3285
3286 XColor
3287 color;
3288
3289 XEvent
3290 event;
3291
3292 /*
3293 Map Command widget.
3294 */
3295 (void) CloneString(&windows->command.name,"Color Edit");
3296 windows->command.data=4;
3297 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3298 (void) XMapRaised(display,windows->command.id);
3299 XClientMessage(display,windows->image.id,windows->im_protocols,
3300 windows->im_update_widget,CurrentTime);
3301 /*
3302 Make cursor.
3303 */
3304 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3305 resource_info->background_color,resource_info->foreground_color);
3306 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3307 /*
3308 Track pointer until button 1 is pressed.
3309 */
3310 XQueryPosition(display,windows->image.id,&x,&y);
3311 (void) XSelectInput(display,windows->image.id,
3312 windows->image.attributes.event_mask | PointerMotionMask);
3313 state=DefaultState;
3314 do
3315 {
3316 if (windows->info.mapped != MagickFalse)
3317 {
3318 /*
3319 Display pointer position.
3320 */
3321 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
3322 x+windows->image.x,y+windows->image.y);
3323 XInfoWidget(display,windows,text);
3324 }
3325 /*
3326 Wait for next event.
3327 */
3328 XScreenEvent(display,windows,&event);
3329 if (event.xany.window == windows->command.id)
3330 {
3331 /*
3332 Select a command from the Command widget.
3333 */
3334 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3335 if (id < 0)
3336 {
3337 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3338 continue;
3339 }
3340 switch (ColorEditCommands[id])
3341 {
3342 case ColorEditMethodCommand:
3343 {
3344 char
3345 **methods;
3346
3347 /*
3348 Select a method from the pop-up menu.
3349 */
3350 methods=(char **) GetCommandOptions(MagickMethodOptions);
3351 if (methods == (char **) NULL)
3352 break;
3353 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3354 (const char **) methods,command);
3355 if (entry >= 0)
3356 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3357 MagickFalse,methods[entry]);
3358 methods=DestroyStringList(methods);
3359 break;
3360 }
3361 case ColorEditColorCommand:
3362 {
3363 const char
3364 *ColorMenu[MaxNumberPens];
3365
3366 int
3367 pen_number;
3368
3369 /*
3370 Initialize menu selections.
3371 */
3372 for (i=0; i < (int) (MaxNumberPens-2); i++)
3373 ColorMenu[i]=resource_info->pen_colors[i];
3374 ColorMenu[MaxNumberPens-2]="Browser...";
3375 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3376 /*
3377 Select a pen color from the pop-up menu.
3378 */
3379 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3380 (const char **) ColorMenu,command);
3381 if (pen_number < 0)
3382 break;
3383 if (pen_number == (MaxNumberPens-2))
3384 {
3385 static char
3386 color_name[MaxTextExtent] = "gray";
3387
3388 /*
3389 Select a pen color from a dialog.
3390 */
3391 resource_info->pen_colors[pen_number]=color_name;
3392 XColorBrowserWidget(display,windows,"Select",color_name);
3393 if (*color_name == '\0')
3394 break;
3395 }
3396 /*
3397 Set pen color.
3398 */
3399 (void) XParseColor(display,windows->map_info->colormap,
3400 resource_info->pen_colors[pen_number],&color);
3401 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3402 (unsigned int) MaxColors,&color);
3403 windows->pixel_info->pen_colors[pen_number]=color;
3404 pen_id=(unsigned int) pen_number;
3405 break;
3406 }
3407 case ColorEditBorderCommand:
3408 {
3409 const char
3410 *ColorMenu[MaxNumberPens];
3411
3412 int
3413 pen_number;
3414
3415 /*
3416 Initialize menu selections.
3417 */
3418 for (i=0; i < (int) (MaxNumberPens-2); i++)
3419 ColorMenu[i]=resource_info->pen_colors[i];
3420 ColorMenu[MaxNumberPens-2]="Browser...";
3421 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3422 /*
3423 Select a pen color from the pop-up menu.
3424 */
3425 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3426 (const char **) ColorMenu,command);
3427 if (pen_number < 0)
3428 break;
3429 if (pen_number == (MaxNumberPens-2))
3430 {
3431 static char
3432 color_name[MaxTextExtent] = "gray";
3433
3434 /*
3435 Select a pen color from a dialog.
3436 */
3437 resource_info->pen_colors[pen_number]=color_name;
3438 XColorBrowserWidget(display,windows,"Select",color_name);
3439 if (*color_name == '\0')
3440 break;
3441 }
3442 /*
3443 Set border color.
3444 */
3445 (void) XParseColor(display,windows->map_info->colormap,
3446 resource_info->pen_colors[pen_number],&border_color);
3447 break;
3448 }
3449 case ColorEditFuzzCommand:
3450 {
3451 static char
3452 fuzz[MaxTextExtent];
3453
3454 static const char
3455 *FuzzMenu[] =
3456 {
3457 "0%",
3458 "2%",
3459 "5%",
3460 "10%",
3461 "15%",
3462 "Dialog...",
3463 (char *) NULL,
3464 };
3465
3466 /*
3467 Select a command from the pop-up menu.
3468 */
3469 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3470 command);
3471 if (entry < 0)
3472 break;
3473 if (entry != 5)
3474 {
3475 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
3476 QuantumRange+1.0);
3477 break;
3478 }
3479 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3480 (void) XDialogWidget(display,windows,"Ok",
3481 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3482 if (*fuzz == '\0')
3483 break;
3484 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
3485 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3486 1.0);
3487 break;
3488 }
3489 case ColorEditUndoCommand:
3490 {
3491 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3492 image);
3493 break;
3494 }
3495 case ColorEditHelpCommand:
3496 default:
3497 {
3498 XTextViewHelp(display,resource_info,windows,MagickFalse,
3499 "Help Viewer - Image Annotation",ImageColorEditHelp);
3500 break;
3501 }
3502 case ColorEditDismissCommand:
3503 {
3504 /*
3505 Prematurely exit.
3506 */
3507 state|=EscapeState;
3508 state|=ExitState;
3509 break;
3510 }
3511 }
3512 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3513 continue;
3514 }
3515 switch (event.type)
3516 {
3517 case ButtonPress:
3518 {
3519 if (event.xbutton.button != Button1)
3520 break;
3521 if ((event.xbutton.window != windows->image.id) &&
3522 (event.xbutton.window != windows->magnify.id))
3523 break;
3524 /*
3525 exit loop.
3526 */
3527 x=event.xbutton.x;
3528 y=event.xbutton.y;
3529 (void) XMagickCommand(display,resource_info,windows,
3530 SaveToUndoBufferCommand,image);
3531 state|=UpdateConfigurationState;
3532 break;
3533 }
3534 case ButtonRelease:
3535 {
3536 if (event.xbutton.button != Button1)
3537 break;
3538 if ((event.xbutton.window != windows->image.id) &&
3539 (event.xbutton.window != windows->magnify.id))
3540 break;
3541 /*
3542 Update colormap information.
3543 */
3544 x=event.xbutton.x;
3545 y=event.xbutton.y;
3546 XConfigureImageColormap(display,resource_info,windows,*image);
3547 (void) XConfigureImage(display,resource_info,windows,*image);
3548 XInfoWidget(display,windows,text);
3549 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3550 state&=(~UpdateConfigurationState);
3551 break;
3552 }
3553 case Expose:
3554 break;
3555 case KeyPress:
3556 {
3557 KeySym
3558 key_symbol;
3559
3560 if (event.xkey.window == windows->magnify.id)
3561 {
3562 Window
3563 window;
3564
3565 window=windows->magnify.id;
3566 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3567 }
3568 if (event.xkey.window != windows->image.id)
3569 break;
3570 /*
3571 Respond to a user key press.
3572 */
3573 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3574 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3575 switch ((int) key_symbol)
3576 {
3577 case XK_Escape:
3578 case XK_F20:
3579 {
3580 /*
3581 Prematurely exit.
3582 */
3583 state|=ExitState;
3584 break;
3585 }
3586 case XK_F1:
3587 case XK_Help:
3588 {
3589 XTextViewHelp(display,resource_info,windows,MagickFalse,
3590 "Help Viewer - Image Annotation",ImageColorEditHelp);
3591 break;
3592 }
3593 default:
3594 {
3595 (void) XBell(display,0);
3596 break;
3597 }
3598 }
3599 break;
3600 }
3601 case MotionNotify:
3602 {
3603 /*
3604 Map and unmap Info widget as cursor crosses its boundaries.
3605 */
3606 x=event.xmotion.x;
3607 y=event.xmotion.y;
3608 if (windows->info.mapped != MagickFalse)
3609 {
3610 if ((x < (int) (windows->info.x+windows->info.width)) &&
3611 (y < (int) (windows->info.y+windows->info.height)))
3612 (void) XWithdrawWindow(display,windows->info.id,
3613 windows->info.screen);
3614 }
3615 else
3616 if ((x > (int) (windows->info.x+windows->info.width)) ||
3617 (y > (int) (windows->info.y+windows->info.height)))
3618 (void) XMapWindow(display,windows->info.id);
3619 break;
3620 }
3621 default:
3622 break;
3623 }
3624 if (event.xany.window == windows->magnify.id)
3625 {
3626 x=windows->magnify.x-windows->image.x;
3627 y=windows->magnify.y-windows->image.y;
3628 }
3629 x_offset=x;
3630 y_offset=y;
3631 if ((state & UpdateConfigurationState) != 0)
3632 {
3633 CacheView
3634 *image_view;
3635
3636 int
3637 x,
3638 y;
3639
3640 /*
3641 Pixel edit is relative to image configuration.
3642 */
3643 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3644 MagickTrue);
3645 color=windows->pixel_info->pen_colors[pen_id];
3646 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3647 width=(unsigned int) (*image)->columns;
3648 height=(unsigned int) (*image)->rows;
3649 x=0;
3650 y=0;
3651 if (windows->image.crop_geometry != (char *) NULL)
3652 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3653 &width,&height);
3654 x_offset=(int)
3655 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3656 y_offset=(int)
3657 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3658 if ((x_offset < 0) || (y_offset < 0))
3659 continue;
3660 if ((x_offset >= (int) (*image)->columns) ||
3661 (y_offset >= (int) (*image)->rows))
3662 continue;
3663 exception=(&(*image)->exception);
3664 image_view=AcquireAuthenticCacheView(*image,exception);
3665 switch (method)
3666 {
3667 case PointMethod:
3668 default:
3669 {
3670 /*
3671 Update color information using point algorithm.
3672 */
3673 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3674 return(MagickFalse);
3675 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3676 (ssize_t)y_offset,1,1,exception);
3677 if (q == (PixelPacket *) NULL)
3678 break;
3679 q->red=ScaleShortToQuantum(color.red);
3680 q->green=ScaleShortToQuantum(color.green);
3681 q->blue=ScaleShortToQuantum(color.blue);
3682 (void) SyncCacheViewAuthenticPixels(image_view,
3683 &(*image)->exception);
3684 break;
3685 }
3686 case ReplaceMethod:
3687 {
3688 PixelPacket
3689 target;
3690
3691 /*
3692 Update color information using replace algorithm.
3693 */
3694 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
3695 (ssize_t) y_offset,&target,&(*image)->exception);
3696 if ((*image)->storage_class == DirectClass)
3697 {
3698 for (y=0; y < (int) (*image)->rows; y++)
3699 {
3700 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3701 (*image)->columns,1,exception);
3702 if (q == (PixelPacket *) NULL)
3703 break;
3704 for (x=0; x < (int) (*image)->columns; x++)
3705 {
3706 if (IsColorSimilar(*image,q,&target) != MagickFalse)
3707 {
3708 q->red=ScaleShortToQuantum(color.red);
3709 q->green=ScaleShortToQuantum(color.green);
3710 q->blue=ScaleShortToQuantum(color.blue);
3711 }
3712 q++;
3713 }
3714 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3715 break;
3716 }
3717 }
3718 else
3719 {
3720 for (i=0; i < (ssize_t) (*image)->colors; i++)
3721 if (IsColorSimilar(*image,(*image)->colormap+i,&target) != MagickFalse)
3722 {
3723 (*image)->colormap[i].red=ScaleShortToQuantum(color.red);
3724 (*image)->colormap[i].green=ScaleShortToQuantum(
3725 color.green);
3726 (*image)->colormap[i].blue=ScaleShortToQuantum(
3727 color.blue);
3728 }
3729 (void) SyncImage(*image);
3730 }
3731 break;
3732 }
3733 case FloodfillMethod:
3734 case FillToBorderMethod:
3735 {
3736 DrawInfo
3737 *draw_info;
3738
3739 MagickPixelPacket
3740 target;
3741
3742 /*
3743 Update color information using floodfill algorithm.
3744 */
3745 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
3746 (ssize_t) y_offset,&target,exception);
3747 if (method == FillToBorderMethod)
3748 {
3749 target.red=(MagickRealType)
3750 ScaleShortToQuantum(border_color.red);
3751 target.green=(MagickRealType)
3752 ScaleShortToQuantum(border_color.green);
3753 target.blue=(MagickRealType)
3754 ScaleShortToQuantum(border_color.blue);
3755 }
3756 draw_info=CloneDrawInfo(resource_info->image_info,
3757 (DrawInfo *) NULL);
3758 (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
3759 &draw_info->fill,exception);
3760 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
3761 (ssize_t) x_offset,(ssize_t) y_offset,
3762 method == FloodfillMethod ? MagickFalse : MagickTrue);
3763 draw_info=DestroyDrawInfo(draw_info);
3764 break;
3765 }
3766 case ResetMethod:
3767 {
3768 /*
3769 Update color information using reset algorithm.
3770 */
3771 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
3772 return(MagickFalse);
3773 for (y=0; y < (int) (*image)->rows; y++)
3774 {
3775 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3776 (*image)->columns,1,exception);
3777 if (q == (PixelPacket *) NULL)
3778 break;
3779 for (x=0; x < (int) (*image)->columns; x++)
3780 {
3781 q->red=ScaleShortToQuantum(color.red);
3782 q->green=ScaleShortToQuantum(color.green);
3783 q->blue=ScaleShortToQuantum(color.blue);
3784 q++;
3785 }
3786 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3787 break;
3788 }
3789 break;
3790 }
3791 }
3792 image_view=DestroyCacheView(image_view);
3793 state&=(~UpdateConfigurationState);
3794 }
3795 } while ((state & ExitState) == 0);
3796 (void) XSelectInput(display,windows->image.id,
3797 windows->image.attributes.event_mask);
3798 XSetCursorState(display,windows,MagickFalse);
3799 (void) XFreeCursor(display,cursor);
3800 return(MagickTrue);
3801}
3802
3803/*
3804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3805% %
3806% %
3807% %
3808+ X C o m p o s i t e I m a g e %
3809% %
3810% %
3811% %
3812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3813%
3814% XCompositeImage() requests an image name from the user, reads the image and
3815% composites it with the X window image at a location the user chooses with
3816% the pointer.
3817%
3818% The format of the XCompositeImage method is:
3819%
3820% MagickBooleanType XCompositeImage(Display *display,
3821% XResourceInfo *resource_info,XWindows *windows,Image *image)
3822%
3823% A description of each parameter follows:
3824%
3825% o display: Specifies a connection to an X server; returned from
3826% XOpenDisplay.
3827%
3828% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3829%
3830% o windows: Specifies a pointer to a XWindows structure.
3831%
3832% o image: the image; returned from ReadImage.
3833%
3834*/
3835static MagickBooleanType XCompositeImage(Display *display,
3836 XResourceInfo *resource_info,XWindows *windows,Image *image)
3837{
3838 const char
3839 *const CompositeMenu[] =
3840 {
3841 "Operators",
3842 "Dissolve",
3843 "Displace",
3844 "Help",
3845 "Dismiss",
3846 (char *) NULL
3847 };
3848
3849 static char
3850 displacement_geometry[MaxTextExtent] = "30x30",
3851 filename[MaxTextExtent] = "\0";
3852
3853 static CompositeOperator
3854 compose = CopyCompositeOp;
3855
3856 static const ModeType
3857 CompositeCommands[] =
3858 {
3859 CompositeOperatorsCommand,
3860 CompositeDissolveCommand,
3861 CompositeDisplaceCommand,
3862 CompositeHelpCommand,
3863 CompositeDismissCommand
3864 };
3865
3866 char
3867 text[MaxTextExtent];
3868
3869 Cursor
3870 cursor;
3871
3872 Image
3873 *composite_image;
3874
3875 int
3876 entry,
3877 id,
3878 x,
3879 y;
3880
3881 MagickRealType
3882 blend,
3883 scale_factor;
3884
3885 RectangleInfo
3886 highlight_info,
3887 composite_info;
3888
3889 unsigned int
3890 height,
3891 width;
3892
3893 size_t
3894 state;
3895
3896 XEvent
3897 event;
3898
3899 /*
3900 Request image file name from user.
3901 */
3902 XFileBrowserWidget(display,windows,"Composite",filename);
3903 if (*filename == '\0')
3904 return(MagickTrue);
3905 /*
3906 Read image.
3907 */
3908 XSetCursorState(display,windows,MagickTrue);
3909 XCheckRefreshWindows(display,windows);
3910 (void) CopyMagickString(resource_info->image_info->filename,filename,
3911 MaxTextExtent);
3912 composite_image=ReadImage(resource_info->image_info,&image->exception);
3913 CatchException(&image->exception);
3914 XSetCursorState(display,windows,MagickFalse);
3915 if (composite_image == (Image *) NULL)
3916 return(MagickFalse);
3917 /*
3918 Map Command widget.
3919 */
3920 (void) CloneString(&windows->command.name,"Composite");
3921 windows->command.data=1;
3922 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3923 (void) XMapRaised(display,windows->command.id);
3924 XClientMessage(display,windows->image.id,windows->im_protocols,
3925 windows->im_update_widget,CurrentTime);
3926 /*
3927 Track pointer until button 1 is pressed.
3928 */
3929 XQueryPosition(display,windows->image.id,&x,&y);
3930 (void) XSelectInput(display,windows->image.id,
3931 windows->image.attributes.event_mask | PointerMotionMask);
3932 composite_info.x=(ssize_t) windows->image.x+x;
3933 composite_info.y=(ssize_t) windows->image.y+y;
3934 composite_info.width=0;
3935 composite_info.height=0;
3936 cursor=XCreateFontCursor(display,XC_ul_angle);
3937 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3938 blend=0.0;
3939 state=DefaultState;
3940 do
3941 {
3942 if (windows->info.mapped != MagickFalse)
3943 {
3944 /*
3945 Display pointer position.
3946 */
3947 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
3948 (long) composite_info.x,(long) composite_info.y);
3949 XInfoWidget(display,windows,text);
3950 }
3951 highlight_info=composite_info;
3952 highlight_info.x=composite_info.x-windows->image.x;
3953 highlight_info.y=composite_info.y-windows->image.y;
3954 XHighlightRectangle(display,windows->image.id,
3955 windows->image.highlight_context,&highlight_info);
3956 /*
3957 Wait for next event.
3958 */
3959 XScreenEvent(display,windows,&event);
3960 XHighlightRectangle(display,windows->image.id,
3961 windows->image.highlight_context,&highlight_info);
3962 if (event.xany.window == windows->command.id)
3963 {
3964 /*
3965 Select a command from the Command widget.
3966 */
3967 id=XCommandWidget(display,windows,CompositeMenu,&event);
3968 if (id < 0)
3969 continue;
3970 switch (CompositeCommands[id])
3971 {
3972 case CompositeOperatorsCommand:
3973 {
3974 char
3975 command[MaxTextExtent],
3976 **operators;
3977
3978 /*
3979 Select a command from the pop-up menu.
3980 */
3981 operators=GetCommandOptions(MagickComposeOptions);
3982 if (operators == (char **) NULL)
3983 break;
3984 entry=XMenuWidget(display,windows,CompositeMenu[id],
3985 (const char **) operators,command);
3986 if (entry >= 0)
3987 compose=(CompositeOperator) ParseCommandOption(
3988 MagickComposeOptions,MagickFalse,operators[entry]);
3989 operators=DestroyStringList(operators);
3990 break;
3991 }
3992 case CompositeDissolveCommand:
3993 {
3994 static char
3995 factor[MaxTextExtent] = "20.0";
3996
3997 /*
3998 Dissolve the two images a given percent.
3999 */
4000 (void) XSetFunction(display,windows->image.highlight_context,
4001 GXcopy);
4002 (void) XDialogWidget(display,windows,"Dissolve",
4003 "Enter the blend factor (0.0 - 99.9%):",factor);
4004 (void) XSetFunction(display,windows->image.highlight_context,
4005 GXinvert);
4006 if (*factor == '\0')
4007 break;
4008 blend=StringToDouble(factor,(char **) NULL);
4009 compose=DissolveCompositeOp;
4010 break;
4011 }
4012 case CompositeDisplaceCommand:
4013 {
4014 /*
4015 Get horizontal and vertical scale displacement geometry.
4016 */
4017 (void) XSetFunction(display,windows->image.highlight_context,
4018 GXcopy);
4019 (void) XDialogWidget(display,windows,"Displace",
4020 "Enter the horizontal and vertical scale:",displacement_geometry);
4021 (void) XSetFunction(display,windows->image.highlight_context,
4022 GXinvert);
4023 if (*displacement_geometry == '\0')
4024 break;
4025 compose=DisplaceCompositeOp;
4026 break;
4027 }
4028 case CompositeHelpCommand:
4029 {
4030 (void) XSetFunction(display,windows->image.highlight_context,
4031 GXcopy);
4032 XTextViewHelp(display,resource_info,windows,MagickFalse,
4033 "Help Viewer - Image Composite",ImageCompositeHelp);
4034 (void) XSetFunction(display,windows->image.highlight_context,
4035 GXinvert);
4036 break;
4037 }
4038 case CompositeDismissCommand:
4039 {
4040 /*
4041 Prematurely exit.
4042 */
4043 state|=EscapeState;
4044 state|=ExitState;
4045 break;
4046 }
4047 default:
4048 break;
4049 }
4050 continue;
4051 }
4052 switch (event.type)
4053 {
4054 case ButtonPress:
4055 {
4056 if (resource_info->debug != MagickFalse)
4057 (void) LogMagickEvent(X11Event,GetMagickModule(),
4058 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4059 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4060 if (event.xbutton.button != Button1)
4061 break;
4062 if (event.xbutton.window != windows->image.id)
4063 break;
4064 /*
4065 Change cursor.
4066 */
4067 composite_info.width=composite_image->columns;
4068 composite_info.height=composite_image->rows;
4069 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4070 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4071 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4072 break;
4073 }
4074 case ButtonRelease:
4075 {
4076 if (resource_info->debug != MagickFalse)
4077 (void) LogMagickEvent(X11Event,GetMagickModule(),
4078 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4079 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4080 if (event.xbutton.button != Button1)
4081 break;
4082 if (event.xbutton.window != windows->image.id)
4083 break;
4084 if ((composite_info.width != 0) && (composite_info.height != 0))
4085 {
4086 /*
4087 User has selected the location of the composite image.
4088 */
4089 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4090 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4091 state|=ExitState;
4092 }
4093 break;
4094 }
4095 case Expose:
4096 break;
4097 case KeyPress:
4098 {
4099 char
4100 command[MaxTextExtent];
4101
4102 KeySym
4103 key_symbol;
4104
4105 int
4106 length;
4107
4108 if (event.xkey.window != windows->image.id)
4109 break;
4110 /*
4111 Respond to a user key press.
4112 */
4113 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4114 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4115 *(command+length)='\0';
4116 if (resource_info->debug != MagickFalse)
4117 (void) LogMagickEvent(X11Event,GetMagickModule(),
4118 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4119 switch ((int) key_symbol)
4120 {
4121 case XK_Escape:
4122 case XK_F20:
4123 {
4124 /*
4125 Prematurely exit.
4126 */
4127 composite_image=DestroyImage(composite_image);
4128 state|=EscapeState;
4129 state|=ExitState;
4130 break;
4131 }
4132 case XK_F1:
4133 case XK_Help:
4134 {
4135 (void) XSetFunction(display,windows->image.highlight_context,
4136 GXcopy);
4137 XTextViewHelp(display,resource_info,windows,MagickFalse,
4138 "Help Viewer - Image Composite",ImageCompositeHelp);
4139 (void) XSetFunction(display,windows->image.highlight_context,
4140 GXinvert);
4141 break;
4142 }
4143 default:
4144 {
4145 (void) XBell(display,0);
4146 break;
4147 }
4148 }
4149 break;
4150 }
4151 case MotionNotify:
4152 {
4153 /*
4154 Map and unmap Info widget as text cursor crosses its boundaries.
4155 */
4156 x=event.xmotion.x;
4157 y=event.xmotion.y;
4158 if (windows->info.mapped != MagickFalse)
4159 {
4160 if ((x < (int) (windows->info.x+windows->info.width)) &&
4161 (y < (int) (windows->info.y+windows->info.height)))
4162 (void) XWithdrawWindow(display,windows->info.id,
4163 windows->info.screen);
4164 }
4165 else
4166 if ((x > (int) (windows->info.x+windows->info.width)) ||
4167 (y > (int) (windows->info.y+windows->info.height)))
4168 (void) XMapWindow(display,windows->info.id);
4169 composite_info.x=(ssize_t) windows->image.x+x;
4170 composite_info.y=(ssize_t) windows->image.y+y;
4171 break;
4172 }
4173 default:
4174 {
4175 if (resource_info->debug != MagickFalse)
4176 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4177 event.type);
4178 break;
4179 }
4180 }
4181 } while ((state & ExitState) == 0);
4182 (void) XSelectInput(display,windows->image.id,
4183 windows->image.attributes.event_mask);
4184 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4185 XSetCursorState(display,windows,MagickFalse);
4186 (void) XFreeCursor(display,cursor);
4187 if ((state & EscapeState) != 0)
4188 return(MagickTrue);
4189 /*
4190 Image compositing is relative to image configuration.
4191 */
4192 XSetCursorState(display,windows,MagickTrue);
4193 XCheckRefreshWindows(display,windows);
4194 width=(unsigned int) image->columns;
4195 height=(unsigned int) image->rows;
4196 x=0;
4197 y=0;
4198 if (windows->image.crop_geometry != (char *) NULL)
4199 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4200 scale_factor=(MagickRealType) width/windows->image.ximage->width;
4201 composite_info.x+=x;
4202 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4203 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4204 scale_factor=(MagickRealType) height/windows->image.ximage->height;
4205 composite_info.y+=y;
4206 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4207 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4208 if ((composite_info.width != composite_image->columns) ||
4209 (composite_info.height != composite_image->rows))
4210 {
4211 Image
4212 *resize_image;
4213
4214 /*
4215 Scale composite image.
4216 */
4217 resize_image=ResizeImage(composite_image,composite_info.width,
4218 composite_info.height,composite_image->filter,composite_image->blur,
4219 &image->exception);
4220 composite_image=DestroyImage(composite_image);
4221 if (resize_image == (Image *) NULL)
4222 {
4223 XSetCursorState(display,windows,MagickFalse);
4224 return(MagickFalse);
4225 }
4226 composite_image=resize_image;
4227 }
4228 if (compose == DisplaceCompositeOp)
4229 (void) SetImageArtifact(composite_image,"compose:args",
4230 displacement_geometry);
4231 if (blend != 0.0)
4232 {
4233 CacheView
4234 *image_view;
4235
4236 ExceptionInfo
4237 *exception;
4238
4239 int
4240 y;
4241
4242 Quantum
4243 opacity;
4244
4245 int
4246 x;
4247
4248 PixelPacket
4249 *q;
4250
4251 /*
4252 Create mattes for blending.
4253 */
4254 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
4255 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4256 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
4257 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4258 return(MagickFalse);
4259 image->matte=MagickTrue;
4260 exception=(&image->exception);
4261 image_view=AcquireAuthenticCacheView(image,exception);
4262 for (y=0; y < (int) image->rows; y++)
4263 {
4264 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4265 exception);
4266 if (q == (PixelPacket *) NULL)
4267 break;
4268 for (x=0; x < (int) image->columns; x++)
4269 {
4270 q->opacity=opacity;
4271 q++;
4272 }
4273 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4274 break;
4275 }
4276 image_view=DestroyCacheView(image_view);
4277 }
4278 /*
4279 Composite image with X Image window.
4280 */
4281 (void) CompositeImage(image,compose,composite_image,composite_info.x,
4282 composite_info.y);
4283 composite_image=DestroyImage(composite_image);
4284 XSetCursorState(display,windows,MagickFalse);
4285 /*
4286 Update image configuration.
4287 */
4288 XConfigureImageColormap(display,resource_info,windows,image);
4289 (void) XConfigureImage(display,resource_info,windows,image);
4290 return(MagickTrue);
4291}
4292
4293/*
4294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4295% %
4296% %
4297% %
4298+ X C o n f i g u r e I m a g e %
4299% %
4300% %
4301% %
4302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4303%
4304% XConfigureImage() creates a new X image. It also notifies the window
4305% manager of the new image size and configures the transient widows.
4306%
4307% The format of the XConfigureImage method is:
4308%
4309% MagickBooleanType XConfigureImage(Display *display,
4310% XResourceInfo *resource_info,XWindows *windows,Image *image)
4311%
4312% A description of each parameter follows:
4313%
4314% o display: Specifies a connection to an X server; returned from
4315% XOpenDisplay.
4316%
4317% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4318%
4319% o windows: Specifies a pointer to a XWindows structure.
4320%
4321% o image: the image.
4322%
4323%
4324*/
4325static MagickBooleanType XConfigureImage(Display *display,
4326 XResourceInfo *resource_info,XWindows *windows,Image *image)
4327{
4328 char
4329 geometry[MaxTextExtent];
4330
4331 MagickStatusType
4332 status;
4333
4334 size_t
4335 mask,
4336 height,
4337 width;
4338
4339 ssize_t
4340 x,
4341 y;
4342
4343 XSizeHints
4344 *size_hints;
4345
4346 XWindowChanges
4347 window_changes;
4348
4349 /*
4350 Dismiss if window dimensions are zero.
4351 */
4352 width=(unsigned int) windows->image.window_changes.width;
4353 height=(unsigned int) windows->image.window_changes.height;
4354 if (resource_info->debug != MagickFalse)
4355 (void) LogMagickEvent(X11Event,GetMagickModule(),
4356 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4357 windows->image.ximage->height,(double) width,(double) height);
4358 if ((width*height) == 0)
4359 return(MagickTrue);
4360 x=0;
4361 y=0;
4362 /*
4363 Resize image to fit Image window dimensions.
4364 */
4365 XSetCursorState(display,windows,MagickTrue);
4366 (void) XFlush(display);
4367 if (((int) width != windows->image.ximage->width) ||
4368 ((int) height != windows->image.ximage->height))
4369 image->taint=MagickTrue;
4370 windows->magnify.x=(int)
4371 width*windows->magnify.x/windows->image.ximage->width;
4372 windows->magnify.y=(int)
4373 height*windows->magnify.y/windows->image.ximage->height;
4374 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4375 windows->image.y=(int)
4376 (height*windows->image.y/windows->image.ximage->height);
4377 status=XMakeImage(display,resource_info,&windows->image,image,
4378 (unsigned int) width,(unsigned int) height);
4379 if (status == MagickFalse)
4380 XNoticeWidget(display,windows,"Unable to configure X image:",
4381 windows->image.name);
4382 /*
4383 Notify window manager of the new configuration.
4384 */
4385 if (resource_info->image_geometry != (char *) NULL)
4386 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
4387 resource_info->image_geometry);
4388 else
4389 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
4390 XDisplayWidth(display,windows->image.screen),
4391 XDisplayHeight(display,windows->image.screen));
4392 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4393 window_changes.width=(int) width;
4394 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4395 window_changes.width=XDisplayWidth(display,windows->image.screen);
4396 window_changes.height=(int) height;
4397 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4398 window_changes.height=XDisplayHeight(display,windows->image.screen);
4399 mask=(size_t) (CWWidth | CWHeight);
4400 if (resource_info->backdrop)
4401 {
4402 mask|=CWX | CWY;
4403 window_changes.x=(int)
4404 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4405 window_changes.y=(int)
4406 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4407 }
4408 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4409 (unsigned int) mask,&window_changes);
4410 (void) XClearWindow(display,windows->image.id);
4411 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4412 /*
4413 Update Magnify window configuration.
4414 */
4415 if (windows->magnify.mapped != MagickFalse)
4416 XMakeMagnifyImage(display,windows);
4417 windows->pan.crop_geometry=windows->image.crop_geometry;
4418 XBestIconSize(display,&windows->pan,image);
4419 while (((windows->pan.width << 1) < MaxIconSize) &&
4420 ((windows->pan.height << 1) < MaxIconSize))
4421 {
4422 windows->pan.width<<=1;
4423 windows->pan.height<<=1;
4424 }
4425 if (windows->pan.geometry != (char *) NULL)
4426 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4427 &windows->pan.width,&windows->pan.height);
4428 window_changes.width=(int) windows->pan.width;
4429 window_changes.height=(int) windows->pan.height;
4430 size_hints=XAllocSizeHints();
4431 if (size_hints != (XSizeHints *) NULL)
4432 {
4433 /*
4434 Set new size hints.
4435 */
4436 size_hints->flags=PSize | PMinSize | PMaxSize;
4437 size_hints->width=window_changes.width;
4438 size_hints->height=window_changes.height;
4439 size_hints->min_width=size_hints->width;
4440 size_hints->min_height=size_hints->height;
4441 size_hints->max_width=size_hints->width;
4442 size_hints->max_height=size_hints->height;
4443 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4444 (void) XFree((void *) size_hints);
4445 }
4446 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4447 (unsigned int) (CWWidth | CWHeight),&window_changes);
4448 /*
4449 Update icon window configuration.
4450 */
4451 windows->icon.crop_geometry=windows->image.crop_geometry;
4452 XBestIconSize(display,&windows->icon,image);
4453 window_changes.width=(int) windows->icon.width;
4454 window_changes.height=(int) windows->icon.height;
4455 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4456 (unsigned int) (CWWidth | CWHeight),&window_changes);
4457 XSetCursorState(display,windows,MagickFalse);
4458 return(status != 0 ? MagickTrue : MagickFalse);
4459}
4460
4461/*
4462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463% %
4464% %
4465% %
4466+ X C r o p I m a g e %
4467% %
4468% %
4469% %
4470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471%
4472% XCropImage() allows the user to select a region of the image and crop, copy,
4473% or cut it. For copy or cut, the image can subsequently be composited onto
4474% the image with XPasteImage.
4475%
4476% The format of the XCropImage method is:
4477%
4478% MagickBooleanType XCropImage(Display *display,
4479% XResourceInfo *resource_info,XWindows *windows,Image *image,
4480% const ClipboardMode mode)
4481%
4482% A description of each parameter follows:
4483%
4484% o display: Specifies a connection to an X server; returned from
4485% XOpenDisplay.
4486%
4487% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4488%
4489% o windows: Specifies a pointer to a XWindows structure.
4490%
4491% o image: the image; returned from ReadImage.
4492%
4493% o mode: This unsigned value specified whether the image should be
4494% cropped, copied, or cut.
4495%
4496*/
4497static MagickBooleanType XCropImage(Display *display,
4498 XResourceInfo *resource_info,XWindows *windows,Image *image,
4499 const ClipboardMode mode)
4500{
4501 static const char
4502 *CropModeMenu[] =
4503 {
4504 "Help",
4505 "Dismiss",
4506 (char *) NULL
4507 },
4508 *RectifyModeMenu[] =
4509 {
4510 "Crop",
4511 "Help",
4512 "Dismiss",
4513 (char *) NULL
4514 };
4515
4516 static const ModeType
4517 CropCommands[] =
4518 {
4519 CropHelpCommand,
4520 CropDismissCommand
4521 },
4522 RectifyCommands[] =
4523 {
4524 RectifyCopyCommand,
4525 RectifyHelpCommand,
4526 RectifyDismissCommand
4527 };
4528
4529 CacheView
4530 *image_view;
4531
4532 char
4533 command[MaxTextExtent],
4534 text[MaxTextExtent];
4535
4536 Cursor
4537 cursor;
4538
4539 ExceptionInfo
4540 *exception;
4541
4542 int
4543 id,
4544 x,
4545 y;
4546
4547 KeySym
4548 key_symbol;
4549
4550 Image
4551 *crop_image;
4552
4553 MagickRealType
4554 scale_factor;
4555
4556 RectangleInfo
4557 crop_info,
4558 highlight_info;
4559
4560 PixelPacket
4561 *q;
4562
4563 unsigned int
4564 height,
4565 width;
4566
4567 size_t
4568 state;
4569
4570 XEvent
4571 event;
4572
4573 /*
4574 Map Command widget.
4575 */
4576 switch (mode)
4577 {
4578 case CopyMode:
4579 {
4580 (void) CloneString(&windows->command.name,"Copy");
4581 break;
4582 }
4583 case CropMode:
4584 {
4585 (void) CloneString(&windows->command.name,"Crop");
4586 break;
4587 }
4588 case CutMode:
4589 {
4590 (void) CloneString(&windows->command.name,"Cut");
4591 break;
4592 }
4593 }
4594 RectifyModeMenu[0]=windows->command.name;
4595 windows->command.data=0;
4596 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4597 (void) XMapRaised(display,windows->command.id);
4598 XClientMessage(display,windows->image.id,windows->im_protocols,
4599 windows->im_update_widget,CurrentTime);
4600 /*
4601 Track pointer until button 1 is pressed.
4602 */
4603 XQueryPosition(display,windows->image.id,&x,&y);
4604 (void) XSelectInput(display,windows->image.id,
4605 windows->image.attributes.event_mask | PointerMotionMask);
4606 crop_info.x=(ssize_t) windows->image.x+x;
4607 crop_info.y=(ssize_t) windows->image.y+y;
4608 crop_info.width=0;
4609 crop_info.height=0;
4610 cursor=XCreateFontCursor(display,XC_fleur);
4611 state=DefaultState;
4612 do
4613 {
4614 if (windows->info.mapped != MagickFalse)
4615 {
4616 /*
4617 Display pointer position.
4618 */
4619 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
4620 (long) crop_info.x,(long) crop_info.y);
4621 XInfoWidget(display,windows,text);
4622 }
4623 /*
4624 Wait for next event.
4625 */
4626 XScreenEvent(display,windows,&event);
4627 if (event.xany.window == windows->command.id)
4628 {
4629 /*
4630 Select a command from the Command widget.
4631 */
4632 id=XCommandWidget(display,windows,CropModeMenu,&event);
4633 if (id < 0)
4634 continue;
4635 switch (CropCommands[id])
4636 {
4637 case CropHelpCommand:
4638 {
4639 switch (mode)
4640 {
4641 case CopyMode:
4642 {
4643 XTextViewHelp(display,resource_info,windows,MagickFalse,
4644 "Help Viewer - Image Copy",ImageCopyHelp);
4645 break;
4646 }
4647 case CropMode:
4648 {
4649 XTextViewHelp(display,resource_info,windows,MagickFalse,
4650 "Help Viewer - Image Crop",ImageCropHelp);
4651 break;
4652 }
4653 case CutMode:
4654 {
4655 XTextViewHelp(display,resource_info,windows,MagickFalse,
4656 "Help Viewer - Image Cut",ImageCutHelp);
4657 break;
4658 }
4659 }
4660 break;
4661 }
4662 case CropDismissCommand:
4663 {
4664 /*
4665 Prematurely exit.
4666 */
4667 state|=EscapeState;
4668 state|=ExitState;
4669 break;
4670 }
4671 default:
4672 break;
4673 }
4674 continue;
4675 }
4676 switch (event.type)
4677 {
4678 case ButtonPress:
4679 {
4680 if (event.xbutton.button != Button1)
4681 break;
4682 if (event.xbutton.window != windows->image.id)
4683 break;
4684 /*
4685 Note first corner of cropping rectangle-- exit loop.
4686 */
4687 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4688 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4689 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4690 state|=ExitState;
4691 break;
4692 }
4693 case ButtonRelease:
4694 break;
4695 case Expose:
4696 break;
4697 case KeyPress:
4698 {
4699 if (event.xkey.window != windows->image.id)
4700 break;
4701 /*
4702 Respond to a user key press.
4703 */
4704 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4705 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4706 switch ((int) key_symbol)
4707 {
4708 case XK_Escape:
4709 case XK_F20:
4710 {
4711 /*
4712 Prematurely exit.
4713 */
4714 state|=EscapeState;
4715 state|=ExitState;
4716 break;
4717 }
4718 case XK_F1:
4719 case XK_Help:
4720 {
4721 switch (mode)
4722 {
4723 case CopyMode:
4724 {
4725 XTextViewHelp(display,resource_info,windows,MagickFalse,
4726 "Help Viewer - Image Copy",ImageCopyHelp);
4727 break;
4728 }
4729 case CropMode:
4730 {
4731 XTextViewHelp(display,resource_info,windows,MagickFalse,
4732 "Help Viewer - Image Crop",ImageCropHelp);
4733 break;
4734 }
4735 case CutMode:
4736 {
4737 XTextViewHelp(display,resource_info,windows,MagickFalse,
4738 "Help Viewer - Image Cut",ImageCutHelp);
4739 break;
4740 }
4741 }
4742 break;
4743 }
4744 default:
4745 {
4746 (void) XBell(display,0);
4747 break;
4748 }
4749 }
4750 break;
4751 }
4752 case MotionNotify:
4753 {
4754 if (event.xmotion.window != windows->image.id)
4755 break;
4756 /*
4757 Map and unmap Info widget as text cursor crosses its boundaries.
4758 */
4759 x=event.xmotion.x;
4760 y=event.xmotion.y;
4761 if (windows->info.mapped != MagickFalse)
4762 {
4763 if ((x < (int) (windows->info.x+windows->info.width)) &&
4764 (y < (int) (windows->info.y+windows->info.height)))
4765 (void) XWithdrawWindow(display,windows->info.id,
4766 windows->info.screen);
4767 }
4768 else
4769 if ((x > (int) (windows->info.x+windows->info.width)) ||
4770 (y > (int) (windows->info.y+windows->info.height)))
4771 (void) XMapWindow(display,windows->info.id);
4772 crop_info.x=(ssize_t) windows->image.x+x;
4773 crop_info.y=(ssize_t) windows->image.y+y;
4774 break;
4775 }
4776 default:
4777 break;
4778 }
4779 } while ((state & ExitState) == 0);
4780 (void) XSelectInput(display,windows->image.id,
4781 windows->image.attributes.event_mask);
4782 if ((state & EscapeState) != 0)
4783 {
4784 /*
4785 User want to exit without cropping.
4786 */
4787 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4788 (void) XFreeCursor(display,cursor);
4789 return(MagickTrue);
4790 }
4791 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4792 do
4793 {
4794 /*
4795 Size rectangle as pointer moves until the mouse button is released.
4796 */
4797 x=(int) crop_info.x;
4798 y=(int) crop_info.y;
4799 crop_info.width=0;
4800 crop_info.height=0;
4801 state=DefaultState;
4802 do
4803 {
4804 highlight_info=crop_info;
4805 highlight_info.x=crop_info.x-windows->image.x;
4806 highlight_info.y=crop_info.y-windows->image.y;
4807 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4808 {
4809 /*
4810 Display info and draw cropping rectangle.
4811 */
4812 if (windows->info.mapped == MagickFalse)
4813 (void) XMapWindow(display,windows->info.id);
4814 (void) FormatLocaleString(text,MaxTextExtent,
4815 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4816 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4817 XInfoWidget(display,windows,text);
4818 XHighlightRectangle(display,windows->image.id,
4819 windows->image.highlight_context,&highlight_info);
4820 }
4821 else
4822 if (windows->info.mapped != MagickFalse)
4823 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4824 /*
4825 Wait for next event.
4826 */
4827 XScreenEvent(display,windows,&event);
4828 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4829 XHighlightRectangle(display,windows->image.id,
4830 windows->image.highlight_context,&highlight_info);
4831 switch (event.type)
4832 {
4833 case ButtonPress:
4834 {
4835 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4836 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4837 break;
4838 }
4839 case ButtonRelease:
4840 {
4841 /*
4842 User has committed to cropping rectangle.
4843 */
4844 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4845 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4846 XSetCursorState(display,windows,MagickFalse);
4847 state|=ExitState;
4848 windows->command.data=0;
4849 (void) XCommandWidget(display,windows,RectifyModeMenu,
4850 (XEvent *) NULL);
4851 break;
4852 }
4853 case Expose:
4854 break;
4855 case MotionNotify:
4856 {
4857 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4858 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4859 }
4860 default:
4861 break;
4862 }
4863 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4864 ((state & ExitState) != 0))
4865 {
4866 /*
4867 Check boundary conditions.
4868 */
4869 if (crop_info.x < 0)
4870 crop_info.x=0;
4871 else
4872 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4873 crop_info.x=(ssize_t) windows->image.ximage->width;
4874 if ((int) crop_info.x < x)
4875 crop_info.width=(unsigned int) (x-crop_info.x);
4876 else
4877 {
4878 crop_info.width=(unsigned int) (crop_info.x-x);
4879 crop_info.x=(ssize_t) x;
4880 }
4881 if (crop_info.y < 0)
4882 crop_info.y=0;
4883 else
4884 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4885 crop_info.y=(ssize_t) windows->image.ximage->height;
4886 if ((int) crop_info.y < y)
4887 crop_info.height=(unsigned int) (y-crop_info.y);
4888 else
4889 {
4890 crop_info.height=(unsigned int) (crop_info.y-y);
4891 crop_info.y=(ssize_t) y;
4892 }
4893 }
4894 } while ((state & ExitState) == 0);
4895 /*
4896 Wait for user to grab a corner of the rectangle or press return.
4897 */
4898 state=DefaultState;
4899 (void) XMapWindow(display,windows->info.id);
4900 do
4901 {
4902 if (windows->info.mapped != MagickFalse)
4903 {
4904 /*
4905 Display pointer position.
4906 */
4907 (void) FormatLocaleString(text,MaxTextExtent,
4908 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4909 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4910 XInfoWidget(display,windows,text);
4911 }
4912 highlight_info=crop_info;
4913 highlight_info.x=crop_info.x-windows->image.x;
4914 highlight_info.y=crop_info.y-windows->image.y;
4915 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4916 {
4917 state|=EscapeState;
4918 state|=ExitState;
4919 break;
4920 }
4921 XHighlightRectangle(display,windows->image.id,
4922 windows->image.highlight_context,&highlight_info);
4923 XScreenEvent(display,windows,&event);
4924 if (event.xany.window == windows->command.id)
4925 {
4926 /*
4927 Select a command from the Command widget.
4928 */
4929 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4930 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
4931 (void) XSetFunction(display,windows->image.highlight_context,
4932 GXinvert);
4933 XHighlightRectangle(display,windows->image.id,
4934 windows->image.highlight_context,&highlight_info);
4935 if (id >= 0)
4936 switch (RectifyCommands[id])
4937 {
4938 case RectifyCopyCommand:
4939 {
4940 state|=ExitState;
4941 break;
4942 }
4943 case RectifyHelpCommand:
4944 {
4945 (void) XSetFunction(display,windows->image.highlight_context,
4946 GXcopy);
4947 switch (mode)
4948 {
4949 case CopyMode:
4950 {
4951 XTextViewHelp(display,resource_info,windows,MagickFalse,
4952 "Help Viewer - Image Copy",ImageCopyHelp);
4953 break;
4954 }
4955 case CropMode:
4956 {
4957 XTextViewHelp(display,resource_info,windows,MagickFalse,
4958 "Help Viewer - Image Crop",ImageCropHelp);
4959 break;
4960 }
4961 case CutMode:
4962 {
4963 XTextViewHelp(display,resource_info,windows,MagickFalse,
4964 "Help Viewer - Image Cut",ImageCutHelp);
4965 break;
4966 }
4967 }
4968 (void) XSetFunction(display,windows->image.highlight_context,
4969 GXinvert);
4970 break;
4971 }
4972 case RectifyDismissCommand:
4973 {
4974 /*
4975 Prematurely exit.
4976 */
4977 state|=EscapeState;
4978 state|=ExitState;
4979 break;
4980 }
4981 default:
4982 break;
4983 }
4984 continue;
4985 }
4986 XHighlightRectangle(display,windows->image.id,
4987 windows->image.highlight_context,&highlight_info);
4988 switch (event.type)
4989 {
4990 case ButtonPress:
4991 {
4992 if (event.xbutton.button != Button1)
4993 break;
4994 if (event.xbutton.window != windows->image.id)
4995 break;
4996 x=windows->image.x+event.xbutton.x;
4997 y=windows->image.y+event.xbutton.y;
4998 if ((x < (int) (crop_info.x+RoiDelta)) &&
4999 (x > (int) (crop_info.x-RoiDelta)) &&
5000 (y < (int) (crop_info.y+RoiDelta)) &&
5001 (y > (int) (crop_info.y-RoiDelta)))
5002 {
5003 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5004 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5005 state|=UpdateConfigurationState;
5006 break;
5007 }
5008 if ((x < (int) (crop_info.x+RoiDelta)) &&
5009 (x > (int) (crop_info.x-RoiDelta)) &&
5010 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5011 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5012 {
5013 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5014 state|=UpdateConfigurationState;
5015 break;
5016 }
5017 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5018 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5019 (y < (int) (crop_info.y+RoiDelta)) &&
5020 (y > (int) (crop_info.y-RoiDelta)))
5021 {
5022 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5023 state|=UpdateConfigurationState;
5024 break;
5025 }
5026 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5027 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5028 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5029 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5030 {
5031 state|=UpdateConfigurationState;
5032 break;
5033 }
5034 magick_fallthrough;
5035 }
5036 case ButtonRelease:
5037 {
5038 if (event.xbutton.window == windows->pan.id)
5039 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5040 (highlight_info.y != crop_info.y-windows->image.y))
5041 XHighlightRectangle(display,windows->image.id,
5042 windows->image.highlight_context,&highlight_info);
5043 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5044 event.xbutton.time);
5045 break;
5046 }
5047 case Expose:
5048 {
5049 if (event.xexpose.window == windows->image.id)
5050 if (event.xexpose.count == 0)
5051 {
5052 event.xexpose.x=(int) highlight_info.x;
5053 event.xexpose.y=(int) highlight_info.y;
5054 event.xexpose.width=(int) highlight_info.width;
5055 event.xexpose.height=(int) highlight_info.height;
5056 XRefreshWindow(display,&windows->image,&event);
5057 }
5058 if (event.xexpose.window == windows->info.id)
5059 if (event.xexpose.count == 0)
5060 XInfoWidget(display,windows,text);
5061 break;
5062 }
5063 case KeyPress:
5064 {
5065 if (event.xkey.window != windows->image.id)
5066 break;
5067 /*
5068 Respond to a user key press.
5069 */
5070 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5071 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5072 switch ((int) key_symbol)
5073 {
5074 case XK_Escape:
5075 case XK_F20:
5076 {
5077 state|=EscapeState;
5078 magick_fallthrough;
5079 }
5080 case XK_Return:
5081 {
5082 state|=ExitState;
5083 break;
5084 }
5085 case XK_Home:
5086 case XK_KP_Home:
5087 {
5088 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/
5089 2L);
5090 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/
5091 2L);
5092 break;
5093 }
5094 case XK_Left:
5095 case XK_KP_Left:
5096 {
5097 crop_info.x--;
5098 break;
5099 }
5100 case XK_Up:
5101 case XK_KP_Up:
5102 case XK_Next:
5103 {
5104 crop_info.y--;
5105 break;
5106 }
5107 case XK_Right:
5108 case XK_KP_Right:
5109 {
5110 crop_info.x++;
5111 break;
5112 }
5113 case XK_Prior:
5114 case XK_Down:
5115 case XK_KP_Down:
5116 {
5117 crop_info.y++;
5118 break;
5119 }
5120 case XK_F1:
5121 case XK_Help:
5122 {
5123 (void) XSetFunction(display,windows->image.highlight_context,
5124 GXcopy);
5125 switch (mode)
5126 {
5127 case CopyMode:
5128 {
5129 XTextViewHelp(display,resource_info,windows,MagickFalse,
5130 "Help Viewer - Image Copy",ImageCopyHelp);
5131 break;
5132 }
5133 case CropMode:
5134 {
5135 XTextViewHelp(display,resource_info,windows,MagickFalse,
5136 "Help Viewer - Image Cropg",ImageCropHelp);
5137 break;
5138 }
5139 case CutMode:
5140 {
5141 XTextViewHelp(display,resource_info,windows,MagickFalse,
5142 "Help Viewer - Image Cutg",ImageCutHelp);
5143 break;
5144 }
5145 }
5146 (void) XSetFunction(display,windows->image.highlight_context,
5147 GXinvert);
5148 break;
5149 }
5150 default:
5151 {
5152 (void) XBell(display,0);
5153 break;
5154 }
5155 }
5156 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5157 event.xkey.time);
5158 break;
5159 }
5160 case KeyRelease:
5161 break;
5162 case MotionNotify:
5163 {
5164 if (event.xmotion.window != windows->image.id)
5165 break;
5166 /*
5167 Map and unmap Info widget as text cursor crosses its boundaries.
5168 */
5169 x=event.xmotion.x;
5170 y=event.xmotion.y;
5171 if (windows->info.mapped != MagickFalse)
5172 {
5173 if ((x < (int) (windows->info.x+windows->info.width)) &&
5174 (y < (int) (windows->info.y+windows->info.height)))
5175 (void) XWithdrawWindow(display,windows->info.id,
5176 windows->info.screen);
5177 }
5178 else
5179 if ((x > (int) (windows->info.x+windows->info.width)) ||
5180 (y > (int) (windows->info.y+windows->info.height)))
5181 (void) XMapWindow(display,windows->info.id);
5182 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5183 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5184 break;
5185 }
5186 case SelectionRequest:
5187 {
5188 XSelectionEvent
5189 notify;
5190
5191 XSelectionRequestEvent
5192 *request;
5193
5194 /*
5195 Set primary selection.
5196 */
5197 (void) FormatLocaleString(text,MaxTextExtent,
5198 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5199 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5200 request=(&(event.xselectionrequest));
5201 (void) XChangeProperty(request->display,request->requestor,
5202 request->property,request->target,8,PropModeReplace,
5203 (unsigned char *) text,(int) strlen(text));
5204 notify.type=SelectionNotify;
5205 notify.display=request->display;
5206 notify.requestor=request->requestor;
5207 notify.selection=request->selection;
5208 notify.target=request->target;
5209 notify.time=request->time;
5210 if (request->property == None)
5211 notify.property=request->target;
5212 else
5213 notify.property=request->property;
5214 (void) XSendEvent(request->display,request->requestor,False,0,
5215 (XEvent *) &notify);
5216 }
5217 default:
5218 break;
5219 }
5220 if ((state & UpdateConfigurationState) != 0)
5221 {
5222 (void) XPutBackEvent(display,&event);
5223 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5224 break;
5225 }
5226 } while ((state & ExitState) == 0);
5227 } while ((state & ExitState) == 0);
5228 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5229 XSetCursorState(display,windows,MagickFalse);
5230 if ((state & EscapeState) != 0)
5231 return(MagickTrue);
5232 if (mode == CropMode)
5233 if (((int) crop_info.width != windows->image.ximage->width) ||
5234 ((int) crop_info.height != windows->image.ximage->height))
5235 {
5236 /*
5237 Reconfigure Image window as defined by cropping rectangle.
5238 */
5239 XSetCropGeometry(display,windows,&crop_info,image);
5240 windows->image.window_changes.width=(int) crop_info.width;
5241 windows->image.window_changes.height=(int) crop_info.height;
5242 (void) XConfigureImage(display,resource_info,windows,image);
5243 return(MagickTrue);
5244 }
5245 /*
5246 Copy image before applying image transforms.
5247 */
5248 XSetCursorState(display,windows,MagickTrue);
5249 XCheckRefreshWindows(display,windows);
5250 width=(unsigned int) image->columns;
5251 height=(unsigned int) image->rows;
5252 x=0;
5253 y=0;
5254 if (windows->image.crop_geometry != (char *) NULL)
5255 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5256 scale_factor=(MagickRealType) width/windows->image.ximage->width;
5257 crop_info.x+=x;
5258 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5259 crop_info.x+=image->page.x;
5260 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5261 scale_factor=(MagickRealType) height/windows->image.ximage->height;
5262 crop_info.y+=y;
5263 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5264 crop_info.y+=image->page.y;
5265 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5266 crop_image=CropImage(image,&crop_info,&image->exception);
5267 XSetCursorState(display,windows,MagickFalse);
5268 if (crop_image == (Image *) NULL)
5269 return(MagickFalse);
5270 if (resource_info->copy_image != (Image *) NULL)
5271 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5272 resource_info->copy_image=crop_image;
5273 if (mode == CopyMode)
5274 {
5275 (void) XConfigureImage(display,resource_info,windows,image);
5276 return(MagickTrue);
5277 }
5278 /*
5279 Cut image.
5280 */
5281 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
5282 return(MagickFalse);
5283 image->matte=MagickTrue;
5284 exception=(&image->exception);
5285 image_view=AcquireAuthenticCacheView(image,exception);
5286 for (y=0; y < (int) crop_info.height; y++)
5287 {
5288 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5289 crop_info.width,1,exception);
5290 if (q == (PixelPacket *) NULL)
5291 break;
5292 for (x=0; x < (int) crop_info.width; x++)
5293 {
5294 q->opacity=(Quantum) TransparentOpacity;
5295 q++;
5296 }
5297 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5298 break;
5299 }
5300 image_view=DestroyCacheView(image_view);
5301 /*
5302 Update image configuration.
5303 */
5304 XConfigureImageColormap(display,resource_info,windows,image);
5305 (void) XConfigureImage(display,resource_info,windows,image);
5306 return(MagickTrue);
5307}
5308
5309/*
5310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5311% %
5312% %
5313% %
5314+ X D r a w I m a g e %
5315% %
5316% %
5317% %
5318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5319%
5320% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5321% the image.
5322%
5323% The format of the XDrawEditImage method is:
5324%
5325% MagickBooleanType XDrawEditImage(Display *display,
5326% XResourceInfo *resource_info,XWindows *windows,Image **image)
5327%
5328% A description of each parameter follows:
5329%
5330% o display: Specifies a connection to an X server; returned from
5331% XOpenDisplay.
5332%
5333% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5334%
5335% o windows: Specifies a pointer to a XWindows structure.
5336%
5337% o image: the image.
5338%
5339*/
5340static MagickBooleanType XDrawEditImage(Display *display,
5341 XResourceInfo *resource_info,XWindows *windows,Image **image)
5342{
5343 const char
5344 *const DrawMenu[] =
5345 {
5346 "Element",
5347 "Color",
5348 "Stipple",
5349 "Width",
5350 "Undo",
5351 "Help",
5352 "Dismiss",
5353 (char *) NULL
5354 };
5355
5356 static ElementType
5357 element = PointElement;
5358
5359 static const ModeType
5360 DrawCommands[] =
5361 {
5362 DrawElementCommand,
5363 DrawColorCommand,
5364 DrawStippleCommand,
5365 DrawWidthCommand,
5366 DrawUndoCommand,
5367 DrawHelpCommand,
5368 DrawDismissCommand
5369 };
5370
5371 static Pixmap
5372 stipple = (Pixmap) NULL;
5373
5374 static unsigned int
5375 pen_id = 0,
5376 line_width = 1;
5377
5378 char
5379 command[MaxTextExtent],
5380 text[MaxTextExtent];
5381
5382 Cursor
5383 cursor;
5384
5385 int
5386 entry,
5387 id,
5388 number_coordinates,
5389 x,
5390 y;
5391
5392 MagickRealType
5393 degrees;
5394
5395 MagickStatusType
5396 status;
5397
5398 RectangleInfo
5399 rectangle_info;
5400
5401 int
5402 i;
5403
5404 unsigned int
5405 distance,
5406 height,
5407 max_coordinates,
5408 width;
5409
5410 size_t
5411 state;
5412
5413 Window
5414 root_window;
5415
5416 XDrawInfo
5417 draw_info;
5418
5419 XEvent
5420 event;
5421
5422 XPoint
5423 *coordinate_info;
5424
5425 XSegment
5426 line_info;
5427
5428 /*
5429 Allocate polygon info.
5430 */
5431 max_coordinates=2048;
5432 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5433 sizeof(*coordinate_info));
5434 if (coordinate_info == (XPoint *) NULL)
5435 {
5436 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
5437 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5438 return(MagickFalse);
5439 }
5440 /*
5441 Map Command widget.
5442 */
5443 (void) CloneString(&windows->command.name,"Draw");
5444 windows->command.data=4;
5445 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5446 (void) XMapRaised(display,windows->command.id);
5447 XClientMessage(display,windows->image.id,windows->im_protocols,
5448 windows->im_update_widget,CurrentTime);
5449 /*
5450 Wait for first button press.
5451 */
5452 root_window=XRootWindow(display,XDefaultScreen(display));
5453 draw_info.stencil=OpaqueStencil;
5454 status=MagickTrue;
5455 cursor=XCreateFontCursor(display,XC_tcross);
5456 for ( ; ; )
5457 {
5458 XQueryPosition(display,windows->image.id,&x,&y);
5459 (void) XSelectInput(display,windows->image.id,
5460 windows->image.attributes.event_mask | PointerMotionMask);
5461 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5462 state=DefaultState;
5463 do
5464 {
5465 if (windows->info.mapped != MagickFalse)
5466 {
5467 /*
5468 Display pointer position.
5469 */
5470 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
5471 x+windows->image.x,y+windows->image.y);
5472 XInfoWidget(display,windows,text);
5473 }
5474 /*
5475 Wait for next event.
5476 */
5477 XScreenEvent(display,windows,&event);
5478 if (event.xany.window == windows->command.id)
5479 {
5480 /*
5481 Select a command from the Command widget.
5482 */
5483 id=XCommandWidget(display,windows,DrawMenu,&event);
5484 if (id < 0)
5485 continue;
5486 switch (DrawCommands[id])
5487 {
5488 case DrawElementCommand:
5489 {
5490 const char
5491 *const Elements[] =
5492 {
5493 "point",
5494 "line",
5495 "rectangle",
5496 "fill rectangle",
5497 "circle",
5498 "fill circle",
5499 "ellipse",
5500 "fill ellipse",
5501 "polygon",
5502 "fill polygon",
5503 (char *) NULL,
5504 };
5505
5506 /*
5507 Select a command from the pop-up menu.
5508 */
5509 element=(ElementType) (XMenuWidget(display,windows,
5510 DrawMenu[id],Elements,command)+1);
5511 break;
5512 }
5513 case DrawColorCommand:
5514 {
5515 const char
5516 *ColorMenu[MaxNumberPens+1];
5517
5518 int
5519 pen_number;
5520
5521 MagickBooleanType
5522 transparent;
5523
5524 XColor
5525 color;
5526
5527 /*
5528 Initialize menu selections.
5529 */
5530 for (i=0; i < (int) (MaxNumberPens-2); i++)
5531 ColorMenu[i]=resource_info->pen_colors[i];
5532 ColorMenu[MaxNumberPens-2]="transparent";
5533 ColorMenu[MaxNumberPens-1]="Browser...";
5534 ColorMenu[MaxNumberPens]=(char *) NULL;
5535 /*
5536 Select a pen color from the pop-up menu.
5537 */
5538 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5539 (const char **) ColorMenu,command);
5540 if (pen_number < 0)
5541 break;
5542 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5543 MagickFalse;
5544 if (transparent != MagickFalse)
5545 {
5546 draw_info.stencil=TransparentStencil;
5547 break;
5548 }
5549 if (pen_number == (MaxNumberPens-1))
5550 {
5551 static char
5552 color_name[MaxTextExtent] = "gray";
5553
5554 /*
5555 Select a pen color from a dialog.
5556 */
5557 resource_info->pen_colors[pen_number]=color_name;
5558 XColorBrowserWidget(display,windows,"Select",color_name);
5559 if (*color_name == '\0')
5560 break;
5561 }
5562 /*
5563 Set pen color.
5564 */
5565 (void) XParseColor(display,windows->map_info->colormap,
5566 resource_info->pen_colors[pen_number],&color);
5567 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5568 (unsigned int) MaxColors,&color);
5569 windows->pixel_info->pen_colors[pen_number]=color;
5570 pen_id=(unsigned int) pen_number;
5571 draw_info.stencil=OpaqueStencil;
5572 break;
5573 }
5574 case DrawStippleCommand:
5575 {
5576 const char
5577 *StipplesMenu[] =
5578 {
5579 "Brick",
5580 "Diagonal",
5581 "Scales",
5582 "Vertical",
5583 "Wavy",
5584 "Translucent",
5585 "Opaque",
5586 (char *) NULL,
5587 (char *) NULL,
5588 };
5589
5590 Image
5591 *stipple_image;
5592
5593 ImageInfo
5594 *image_info;
5595
5596 int
5597 status;
5598
5599 static char
5600 filename[MaxTextExtent] = "\0";
5601
5602 /*
5603 Select a command from the pop-up menu.
5604 */
5605 StipplesMenu[7]="Open...";
5606 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5607 command);
5608 if (entry < 0)
5609 break;
5610 if (stipple != (Pixmap) NULL)
5611 (void) XFreePixmap(display,stipple);
5612 stipple=(Pixmap) NULL;
5613 if (entry != 7)
5614 {
5615 switch (entry)
5616 {
5617 case 0:
5618 {
5619 stipple=XCreateBitmapFromData(display,root_window,
5620 (char *) BricksBitmap,BricksWidth,BricksHeight);
5621 break;
5622 }
5623 case 1:
5624 {
5625 stipple=XCreateBitmapFromData(display,root_window,
5626 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5627 break;
5628 }
5629 case 2:
5630 {
5631 stipple=XCreateBitmapFromData(display,root_window,
5632 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5633 break;
5634 }
5635 case 3:
5636 {
5637 stipple=XCreateBitmapFromData(display,root_window,
5638 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5639 break;
5640 }
5641 case 4:
5642 {
5643 stipple=XCreateBitmapFromData(display,root_window,
5644 (char *) WavyBitmap,WavyWidth,WavyHeight);
5645 break;
5646 }
5647 case 5:
5648 {
5649 stipple=XCreateBitmapFromData(display,root_window,
5650 (char *) HighlightBitmap,HighlightWidth,
5651 HighlightHeight);
5652 break;
5653 }
5654 case 6:
5655 default:
5656 {
5657 stipple=XCreateBitmapFromData(display,root_window,
5658 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5659 break;
5660 }
5661 }
5662 break;
5663 }
5664 XFileBrowserWidget(display,windows,"Stipple",filename);
5665 if (*filename == '\0')
5666 break;
5667 /*
5668 Read image.
5669 */
5670 XSetCursorState(display,windows,MagickTrue);
5671 XCheckRefreshWindows(display,windows);
5672 image_info=AcquireImageInfo();
5673 (void) CopyMagickString(image_info->filename,filename,
5674 MaxTextExtent);
5675 stipple_image=ReadImage(image_info,&(*image)->exception);
5676 CatchException(&(*image)->exception);
5677 XSetCursorState(display,windows,MagickFalse);
5678 if (stipple_image == (Image *) NULL)
5679 break;
5680 (void) AcquireUniqueFileResource(filename);
5681 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
5682 "xbm:%s",filename);
5683 (void) WriteImage(image_info,stipple_image);
5684 stipple_image=DestroyImage(stipple_image);
5685 image_info=DestroyImageInfo(image_info);
5686 status=XReadBitmapFile(display,root_window,filename,&width,
5687 &height,&stipple,&x,&y);
5688 (void) RelinquishUniqueFileResource(filename);
5689 if ((status != BitmapSuccess) != 0)
5690 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5691 filename);
5692 break;
5693 }
5694 case DrawWidthCommand:
5695 {
5696 const char
5697 *const WidthsMenu[] =
5698 {
5699 "1",
5700 "2",
5701 "4",
5702 "8",
5703 "16",
5704 "Dialog...",
5705 (char *) NULL,
5706 };
5707
5708 static char
5709 width[MaxTextExtent] = "0";
5710
5711 /*
5712 Select a command from the pop-up menu.
5713 */
5714 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5715 command);
5716 if (entry < 0)
5717 break;
5718 if (entry != 5)
5719 {
5720 line_width=(unsigned int) StringToUnsignedLong(
5721 WidthsMenu[entry]);
5722 break;
5723 }
5724 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5725 width);
5726 if (*width == '\0')
5727 break;
5728 line_width=(unsigned int) StringToUnsignedLong(width);
5729 break;
5730 }
5731 case DrawUndoCommand:
5732 {
5733 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5734 image);
5735 break;
5736 }
5737 case DrawHelpCommand:
5738 {
5739 XTextViewHelp(display,resource_info,windows,MagickFalse,
5740 "Help Viewer - Image Rotation",ImageDrawHelp);
5741 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5742 break;
5743 }
5744 case DrawDismissCommand:
5745 {
5746 /*
5747 Prematurely exit.
5748 */
5749 state|=EscapeState;
5750 state|=ExitState;
5751 break;
5752 }
5753 default:
5754 break;
5755 }
5756 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5757 continue;
5758 }
5759 switch (event.type)
5760 {
5761 case ButtonPress:
5762 {
5763 if (event.xbutton.button != Button1)
5764 break;
5765 if (event.xbutton.window != windows->image.id)
5766 break;
5767 /*
5768 exit loop.
5769 */
5770 x=event.xbutton.x;
5771 y=event.xbutton.y;
5772 state|=ExitState;
5773 break;
5774 }
5775 case ButtonRelease:
5776 break;
5777 case Expose:
5778 break;
5779 case KeyPress:
5780 {
5781 KeySym
5782 key_symbol;
5783
5784 if (event.xkey.window != windows->image.id)
5785 break;
5786 /*
5787 Respond to a user key press.
5788 */
5789 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5790 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5791 switch ((int) key_symbol)
5792 {
5793 case XK_Escape:
5794 case XK_F20:
5795 {
5796 /*
5797 Prematurely exit.
5798 */
5799 state|=EscapeState;
5800 state|=ExitState;
5801 break;
5802 }
5803 case XK_F1:
5804 case XK_Help:
5805 {
5806 XTextViewHelp(display,resource_info,windows,MagickFalse,
5807 "Help Viewer - Image Rotation",ImageDrawHelp);
5808 break;
5809 }
5810 default:
5811 {
5812 (void) XBell(display,0);
5813 break;
5814 }
5815 }
5816 break;
5817 }
5818 case MotionNotify:
5819 {
5820 /*
5821 Map and unmap Info widget as text cursor crosses its boundaries.
5822 */
5823 x=event.xmotion.x;
5824 y=event.xmotion.y;
5825 if (windows->info.mapped != MagickFalse)
5826 {
5827 if ((x < (int) (windows->info.x+windows->info.width)) &&
5828 (y < (int) (windows->info.y+windows->info.height)))
5829 (void) XWithdrawWindow(display,windows->info.id,
5830 windows->info.screen);
5831 }
5832 else
5833 if ((x > (int) (windows->info.x+windows->info.width)) ||
5834 (y > (int) (windows->info.y+windows->info.height)))
5835 (void) XMapWindow(display,windows->info.id);
5836 break;
5837 }
5838 }
5839 } while ((state & ExitState) == 0);
5840 (void) XSelectInput(display,windows->image.id,
5841 windows->image.attributes.event_mask);
5842 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5843 if ((state & EscapeState) != 0)
5844 break;
5845 /*
5846 Draw element as pointer moves until the button is released.
5847 */
5848 distance=0;
5849 degrees=0.0;
5850 line_info.x1=x;
5851 line_info.y1=y;
5852 line_info.x2=x;
5853 line_info.y2=y;
5854 rectangle_info.x=(ssize_t) x;
5855 rectangle_info.y=(ssize_t) y;
5856 rectangle_info.width=0;
5857 rectangle_info.height=0;
5858 number_coordinates=1;
5859 coordinate_info->x=x;
5860 coordinate_info->y=y;
5861 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5862 state=DefaultState;
5863 do
5864 {
5865 switch (element)
5866 {
5867 case PointElement:
5868 default:
5869 {
5870 if (number_coordinates > 1)
5871 {
5872 (void) XDrawLines(display,windows->image.id,
5873 windows->image.highlight_context,coordinate_info,
5874 number_coordinates,CoordModeOrigin);
5875 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
5876 coordinate_info[number_coordinates-1].x,
5877 coordinate_info[number_coordinates-1].y);
5878 XInfoWidget(display,windows,text);
5879 }
5880 break;
5881 }
5882 case LineElement:
5883 {
5884 if (distance > 9)
5885 {
5886 /*
5887 Display angle of the line.
5888 */
5889 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5890 line_info.y1),(double) (line_info.x2-line_info.x1)));
5891 (void) FormatLocaleString(text,MaxTextExtent," %g",
5892 (double) degrees);
5893 XInfoWidget(display,windows,text);
5894 XHighlightLine(display,windows->image.id,
5895 windows->image.highlight_context,&line_info);
5896 }
5897 else
5898 if (windows->info.mapped != MagickFalse)
5899 (void) XWithdrawWindow(display,windows->info.id,
5900 windows->info.screen);
5901 break;
5902 }
5903 case RectangleElement:
5904 case FillRectangleElement:
5905 {
5906 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5907 {
5908 /*
5909 Display info and draw drawing rectangle.
5910 */
5911 (void) FormatLocaleString(text,MaxTextExtent,
5912 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5913 (double) rectangle_info.height,(double) rectangle_info.x,
5914 (double) rectangle_info.y);
5915 XInfoWidget(display,windows,text);
5916 XHighlightRectangle(display,windows->image.id,
5917 windows->image.highlight_context,&rectangle_info);
5918 }
5919 else
5920 if (windows->info.mapped != MagickFalse)
5921 (void) XWithdrawWindow(display,windows->info.id,
5922 windows->info.screen);
5923 break;
5924 }
5925 case CircleElement:
5926 case FillCircleElement:
5927 case EllipseElement:
5928 case FillEllipseElement:
5929 {
5930 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5931 {
5932 /*
5933 Display info and draw drawing rectangle.
5934 */
5935 (void) FormatLocaleString(text,MaxTextExtent,
5936 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5937 (double) rectangle_info.height,(double) rectangle_info.x,
5938 (double) rectangle_info.y);
5939 XInfoWidget(display,windows,text);
5940 XHighlightEllipse(display,windows->image.id,
5941 windows->image.highlight_context,&rectangle_info);
5942 }
5943 else
5944 if (windows->info.mapped != MagickFalse)
5945 (void) XWithdrawWindow(display,windows->info.id,
5946 windows->info.screen);
5947 break;
5948 }
5949 case PolygonElement:
5950 case FillPolygonElement:
5951 {
5952 if (number_coordinates > 1)
5953 (void) XDrawLines(display,windows->image.id,
5954 windows->image.highlight_context,coordinate_info,
5955 number_coordinates,CoordModeOrigin);
5956 if (distance > 9)
5957 {
5958 /*
5959 Display angle of the line.
5960 */
5961 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5962 line_info.y1),(double) (line_info.x2-line_info.x1)));
5963 (void) FormatLocaleString(text,MaxTextExtent," %g",
5964 (double) degrees);
5965 XInfoWidget(display,windows,text);
5966 XHighlightLine(display,windows->image.id,
5967 windows->image.highlight_context,&line_info);
5968 }
5969 else
5970 if (windows->info.mapped != MagickFalse)
5971 (void) XWithdrawWindow(display,windows->info.id,
5972 windows->info.screen);
5973 break;
5974 }
5975 }
5976 /*
5977 Wait for next event.
5978 */
5979 XScreenEvent(display,windows,&event);
5980 switch (element)
5981 {
5982 case PointElement:
5983 default:
5984 {
5985 if (number_coordinates > 1)
5986 (void) XDrawLines(display,windows->image.id,
5987 windows->image.highlight_context,coordinate_info,
5988 number_coordinates,CoordModeOrigin);
5989 break;
5990 }
5991 case LineElement:
5992 {
5993 if (distance > 9)
5994 XHighlightLine(display,windows->image.id,
5995 windows->image.highlight_context,&line_info);
5996 break;
5997 }
5998 case RectangleElement:
5999 case FillRectangleElement:
6000 {
6001 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6002 XHighlightRectangle(display,windows->image.id,
6003 windows->image.highlight_context,&rectangle_info);
6004 break;
6005 }
6006 case CircleElement:
6007 case FillCircleElement:
6008 case EllipseElement:
6009 case FillEllipseElement:
6010 {
6011 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6012 XHighlightEllipse(display,windows->image.id,
6013 windows->image.highlight_context,&rectangle_info);
6014 break;
6015 }
6016 case PolygonElement:
6017 case FillPolygonElement:
6018 {
6019 if (number_coordinates > 1)
6020 (void) XDrawLines(display,windows->image.id,
6021 windows->image.highlight_context,coordinate_info,
6022 number_coordinates,CoordModeOrigin);
6023 if (distance > 9)
6024 XHighlightLine(display,windows->image.id,
6025 windows->image.highlight_context,&line_info);
6026 break;
6027 }
6028 }
6029 switch (event.type)
6030 {
6031 case ButtonPress:
6032 break;
6033 case ButtonRelease:
6034 {
6035 /*
6036 User has committed to element.
6037 */
6038 line_info.x2=event.xbutton.x;
6039 line_info.y2=event.xbutton.y;
6040 rectangle_info.x=(ssize_t) event.xbutton.x;
6041 rectangle_info.y=(ssize_t) event.xbutton.y;
6042 coordinate_info[number_coordinates].x=event.xbutton.x;
6043 coordinate_info[number_coordinates].y=event.xbutton.y;
6044 if (((element != PolygonElement) &&
6045 (element != FillPolygonElement)) || (distance <= 9))
6046 {
6047 state|=ExitState;
6048 break;
6049 }
6050 number_coordinates++;
6051 if (number_coordinates < (int) max_coordinates)
6052 {
6053 line_info.x1=event.xbutton.x;
6054 line_info.y1=event.xbutton.y;
6055 break;
6056 }
6057 max_coordinates<<=1;
6058 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6059 max_coordinates,sizeof(*coordinate_info));
6060 if (coordinate_info == (XPoint *) NULL)
6061 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6062 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6063 break;
6064 }
6065 case Expose:
6066 break;
6067 case MotionNotify:
6068 {
6069 if (event.xmotion.window != windows->image.id)
6070 break;
6071 if (element != PointElement)
6072 {
6073 line_info.x2=event.xmotion.x;
6074 line_info.y2=event.xmotion.y;
6075 rectangle_info.x=(ssize_t) event.xmotion.x;
6076 rectangle_info.y=(ssize_t) event.xmotion.y;
6077 break;
6078 }
6079 coordinate_info[number_coordinates].x=event.xbutton.x;
6080 coordinate_info[number_coordinates].y=event.xbutton.y;
6081 number_coordinates++;
6082 if (number_coordinates < (int) max_coordinates)
6083 break;
6084 max_coordinates<<=1;
6085 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6086 max_coordinates,sizeof(*coordinate_info));
6087 if (coordinate_info == (XPoint *) NULL)
6088 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
6089 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6090 break;
6091 }
6092 default:
6093 break;
6094 }
6095 /*
6096 Check boundary conditions.
6097 */
6098 if (line_info.x2 < 0)
6099 line_info.x2=0;
6100 else
6101 if (line_info.x2 > (int) windows->image.width)
6102 line_info.x2=(short) windows->image.width;
6103 if (line_info.y2 < 0)
6104 line_info.y2=0;
6105 else
6106 if (line_info.y2 > (int) windows->image.height)
6107 line_info.y2=(short) windows->image.height;
6108 distance=(unsigned int)
6109 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6110 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6111 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6112 ((state & ExitState) != 0))
6113 {
6114 if (rectangle_info.x < 0)
6115 rectangle_info.x=0;
6116 else
6117 if (rectangle_info.x > (ssize_t) windows->image.width)
6118 rectangle_info.x=(ssize_t) windows->image.width;
6119 if ((int) rectangle_info.x < x)
6120 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6121 else
6122 {
6123 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6124 rectangle_info.x=(ssize_t) x;
6125 }
6126 if (rectangle_info.y < 0)
6127 rectangle_info.y=0;
6128 else
6129 if (rectangle_info.y > (ssize_t) windows->image.height)
6130 rectangle_info.y=(ssize_t) windows->image.height;
6131 if ((int) rectangle_info.y < y)
6132 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6133 else
6134 {
6135 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6136 rectangle_info.y=(ssize_t) y;
6137 }
6138 }
6139 } while ((state & ExitState) == 0);
6140 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6141 if ((element == PointElement) || (element == PolygonElement) ||
6142 (element == FillPolygonElement))
6143 {
6144 /*
6145 Determine polygon bounding box.
6146 */
6147 rectangle_info.x=(ssize_t) coordinate_info->x;
6148 rectangle_info.y=(ssize_t) coordinate_info->y;
6149 x=coordinate_info->x;
6150 y=coordinate_info->y;
6151 for (i=1; i < number_coordinates; i++)
6152 {
6153 if (coordinate_info[i].x > x)
6154 x=coordinate_info[i].x;
6155 if (coordinate_info[i].y > y)
6156 y=coordinate_info[i].y;
6157 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6158 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6159 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6160 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6161 }
6162 rectangle_info.width=(size_t) (x-rectangle_info.x);
6163 rectangle_info.height=(size_t) (y-rectangle_info.y);
6164 for (i=0; i < number_coordinates; i++)
6165 {
6166 coordinate_info[i].x-=rectangle_info.x;
6167 coordinate_info[i].y-=rectangle_info.y;
6168 }
6169 }
6170 else
6171 if (distance <= 9)
6172 continue;
6173 else
6174 if ((element == RectangleElement) ||
6175 (element == CircleElement) || (element == EllipseElement))
6176 {
6177 rectangle_info.width--;
6178 rectangle_info.height--;
6179 }
6180 /*
6181 Drawing is relative to image configuration.
6182 */
6183 draw_info.x=(int) rectangle_info.x;
6184 draw_info.y=(int) rectangle_info.y;
6185 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6186 image);
6187 width=(unsigned int) (*image)->columns;
6188 height=(unsigned int) (*image)->rows;
6189 x=0;
6190 y=0;
6191 if (windows->image.crop_geometry != (char *) NULL)
6192 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6193 draw_info.x+=windows->image.x-(line_width/2);
6194 if (draw_info.x < 0)
6195 draw_info.x=0;
6196 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6197 draw_info.y+=windows->image.y-(line_width/2);
6198 if (draw_info.y < 0)
6199 draw_info.y=0;
6200 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6201 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6202 if (draw_info.width > (unsigned int) (*image)->columns)
6203 draw_info.width=(unsigned int) (*image)->columns;
6204 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6205 if (draw_info.height > (unsigned int) (*image)->rows)
6206 draw_info.height=(unsigned int) (*image)->rows;
6207 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
6208 width*draw_info.width/windows->image.ximage->width,
6209 height*draw_info.height/windows->image.ximage->height,
6210 draw_info.x+x,draw_info.y+y);
6211 /*
6212 Initialize drawing attributes.
6213 */
6214 draw_info.degrees=0.0;
6215 draw_info.element=element;
6216 draw_info.stipple=stipple;
6217 draw_info.line_width=line_width;
6218 draw_info.line_info=line_info;
6219 if (line_info.x1 > (int) (line_width/2))
6220 draw_info.line_info.x1=(short) line_width/2;
6221 if (line_info.y1 > (int) (line_width/2))
6222 draw_info.line_info.y1=(short) line_width/2;
6223 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6224 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6225 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6226 {
6227 draw_info.line_info.x2=(-draw_info.line_info.x2);
6228 draw_info.line_info.y2=(-draw_info.line_info.y2);
6229 }
6230 if (draw_info.line_info.x2 < 0)
6231 {
6232 draw_info.line_info.x2=(-draw_info.line_info.x2);
6233 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6234 }
6235 if (draw_info.line_info.y2 < 0)
6236 {
6237 draw_info.line_info.y2=(-draw_info.line_info.y2);
6238 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6239 }
6240 draw_info.rectangle_info=rectangle_info;
6241 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6242 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6243 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6244 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6245 draw_info.number_coordinates=(unsigned int) number_coordinates;
6246 draw_info.coordinate_info=coordinate_info;
6247 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6248 /*
6249 Draw element on image.
6250 */
6251 XSetCursorState(display,windows,MagickTrue);
6252 XCheckRefreshWindows(display,windows);
6253 status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
6254 XSetCursorState(display,windows,MagickFalse);
6255 /*
6256 Update image colormap and return to image drawing.
6257 */
6258 XConfigureImageColormap(display,resource_info,windows,*image);
6259 (void) XConfigureImage(display,resource_info,windows,*image);
6260 }
6261 XSetCursorState(display,windows,MagickFalse);
6262 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6263 return(status != 0 ? MagickTrue : MagickFalse);
6264}
6265
6266/*
6267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6268% %
6269% %
6270% %
6271+ X D r a w P a n R e c t a n g l e %
6272% %
6273% %
6274% %
6275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6276%
6277% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6278% displays a zoom image and the rectangle shows which portion of the image is
6279% displayed in the Image window.
6280%
6281% The format of the XDrawPanRectangle method is:
6282%
6283% XDrawPanRectangle(Display *display,XWindows *windows)
6284%
6285% A description of each parameter follows:
6286%
6287% o display: Specifies a connection to an X server; returned from
6288% XOpenDisplay.
6289%
6290% o windows: Specifies a pointer to a XWindows structure.
6291%
6292*/
6293static void XDrawPanRectangle(Display *display,XWindows *windows)
6294{
6295 MagickRealType
6296 scale_factor;
6297
6298 RectangleInfo
6299 highlight_info;
6300
6301 /*
6302 Determine dimensions of the panning rectangle.
6303 */
6304 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
6305 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6306 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6307 scale_factor=(MagickRealType)
6308 windows->pan.height/windows->image.ximage->height;
6309 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6310 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6311 /*
6312 Display the panning rectangle.
6313 */
6314 (void) XClearWindow(display,windows->pan.id);
6315 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6316 &highlight_info);
6317}
6318
6319/*
6320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6321% %
6322% %
6323% %
6324+ X I m a g e C a c h e %
6325% %
6326% %
6327% %
6328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6329%
6330% XImageCache() handles the creation, manipulation, and destruction of the
6331% image cache (undo and redo buffers).
6332%
6333% The format of the XImageCache method is:
6334%
6335% void XImageCache(Display *display,XResourceInfo *resource_info,
6336% XWindows *windows,const DisplayCommand command,Image **image)
6337%
6338% A description of each parameter follows:
6339%
6340% o display: Specifies a connection to an X server; returned from
6341% XOpenDisplay.
6342%
6343% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6344%
6345% o windows: Specifies a pointer to a XWindows structure.
6346%
6347% o command: Specifies a command to perform.
6348%
6349% o image: the image; XImageCache may transform the image and return a new
6350% image pointer.
6351%
6352*/
6353static void XImageCache(Display *display,XResourceInfo *resource_info,
6354 XWindows *windows,const DisplayCommand command,Image **image)
6355{
6356 Image
6357 *cache_image;
6358
6359 static Image
6360 *redo_image = (Image *) NULL,
6361 *undo_image = (Image *) NULL;
6362
6363 switch (command)
6364 {
6365 case FreeBuffersCommand:
6366 {
6367 /*
6368 Free memory from the undo and redo cache.
6369 */
6370 while (undo_image != (Image *) NULL)
6371 {
6372 cache_image=undo_image;
6373 undo_image=GetPreviousImageInList(undo_image);
6374 cache_image->list=DestroyImage(cache_image->list);
6375 cache_image=DestroyImage(cache_image);
6376 }
6377 undo_image=NewImageList();
6378 if (redo_image != (Image *) NULL)
6379 redo_image=DestroyImage(redo_image);
6380 redo_image=NewImageList();
6381 return;
6382 }
6383 case UndoCommand:
6384 {
6385 char
6386 image_geometry[MaxTextExtent];
6387
6388 /*
6389 Undo the last image transformation.
6390 */
6391 if (undo_image == (Image *) NULL)
6392 {
6393 (void) XBell(display,0);
6394 ThrowXWindowException(ImageError,"NoImagesWereFound",
6395 (*image)->filename);
6396 return;
6397 }
6398 cache_image=undo_image;
6399 undo_image=GetPreviousImageInList(undo_image);
6400 windows->image.window_changes.width=(int) cache_image->columns;
6401 windows->image.window_changes.height=(int) cache_image->rows;
6402 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
6403 windows->image.ximage->width,windows->image.ximage->height);
6404 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
6405 if (windows->image.crop_geometry != (char *) NULL)
6406 windows->image.crop_geometry=(char *)
6407 RelinquishMagickMemory(windows->image.crop_geometry);
6408 windows->image.crop_geometry=cache_image->geometry;
6409 if (redo_image != (Image *) NULL)
6410 redo_image=DestroyImage(redo_image);
6411 redo_image=(*image);
6412 *image=cache_image->list;
6413 cache_image=DestroyImage(cache_image);
6414 if (windows->image.orphan != MagickFalse)
6415 return;
6416 XConfigureImageColormap(display,resource_info,windows,*image);
6417 (void) XConfigureImage(display,resource_info,windows,*image);
6418 return;
6419 }
6420 case CutCommand:
6421 case PasteCommand:
6422 case ApplyCommand:
6423 case HalfSizeCommand:
6424 case OriginalSizeCommand:
6425 case DoubleSizeCommand:
6426 case ResizeCommand:
6427 case TrimCommand:
6428 case CropCommand:
6429 case ChopCommand:
6430 case FlipCommand:
6431 case FlopCommand:
6432 case RotateRightCommand:
6433 case RotateLeftCommand:
6434 case RotateCommand:
6435 case ShearCommand:
6436 case RollCommand:
6437 case NegateCommand:
6438 case ContrastStretchCommand:
6439 case SigmoidalContrastCommand:
6440 case NormalizeCommand:
6441 case EqualizeCommand:
6442 case HueCommand:
6443 case SaturationCommand:
6444 case BrightnessCommand:
6445 case GammaCommand:
6446 case SpiffCommand:
6447 case DullCommand:
6448 case GrayscaleCommand:
6449 case MapCommand:
6450 case QuantizeCommand:
6451 case DespeckleCommand:
6452 case EmbossCommand:
6453 case ReduceNoiseCommand:
6454 case AddNoiseCommand:
6455 case SharpenCommand:
6456 case BlurCommand:
6457 case ThresholdCommand:
6458 case EdgeDetectCommand:
6459 case SpreadCommand:
6460 case ShadeCommand:
6461 case RaiseCommand:
6462 case SegmentCommand:
6463 case SolarizeCommand:
6464 case SepiaToneCommand:
6465 case SwirlCommand:
6466 case ImplodeCommand:
6467 case VignetteCommand:
6468 case WaveCommand:
6469 case OilPaintCommand:
6470 case CharcoalDrawCommand:
6471 case AnnotateCommand:
6472 case AddBorderCommand:
6473 case AddFrameCommand:
6474 case CompositeCommand:
6475 case CommentCommand:
6476 case LaunchCommand:
6477 case RegionOfInterestCommand:
6478 case SaveToUndoBufferCommand:
6479 case RedoCommand:
6480 {
6481 Image
6482 *previous_image;
6483
6484 ssize_t
6485 bytes;
6486
6487 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
6488 if (undo_image != (Image *) NULL)
6489 {
6490 /*
6491 Ensure the undo cache has enough memory available.
6492 */
6493 previous_image=undo_image;
6494 while (previous_image != (Image *) NULL)
6495 {
6496 bytes+=previous_image->list->columns*previous_image->list->rows*
6497 sizeof(PixelPacket);
6498 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6499 {
6500 previous_image=GetPreviousImageInList(previous_image);
6501 continue;
6502 }
6503 bytes-=previous_image->list->columns*previous_image->list->rows*
6504 sizeof(PixelPacket);
6505 if (previous_image == undo_image)
6506 undo_image=NewImageList();
6507 else
6508 previous_image->next->previous=NewImageList();
6509 break;
6510 }
6511 while (previous_image != (Image *) NULL)
6512 {
6513 /*
6514 Delete any excess memory from undo cache.
6515 */
6516 cache_image=previous_image;
6517 previous_image=GetPreviousImageInList(previous_image);
6518 cache_image->list=DestroyImage(cache_image->list);
6519 cache_image=DestroyImage(cache_image);
6520 }
6521 }
6522 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6523 break;
6524 /*
6525 Save image before transformations are applied.
6526 */
6527 cache_image=AcquireImage((ImageInfo *) NULL);
6528 if (cache_image == (Image *) NULL)
6529 break;
6530 XSetCursorState(display,windows,MagickTrue);
6531 XCheckRefreshWindows(display,windows);
6532 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
6533 XSetCursorState(display,windows,MagickFalse);
6534 if (cache_image->list == (Image *) NULL)
6535 {
6536 cache_image=DestroyImage(cache_image);
6537 break;
6538 }
6539 cache_image->columns=(size_t) windows->image.ximage->width;
6540 cache_image->rows=(size_t) windows->image.ximage->height;
6541 cache_image->geometry=windows->image.crop_geometry;
6542 if (windows->image.crop_geometry != (char *) NULL)
6543 {
6544 cache_image->geometry=AcquireString((char *) NULL);
6545 (void) CopyMagickString(cache_image->geometry,
6546 windows->image.crop_geometry,MaxTextExtent);
6547 }
6548 if (undo_image == (Image *) NULL)
6549 {
6550 undo_image=cache_image;
6551 break;
6552 }
6553 undo_image->next=cache_image;
6554 undo_image->next->previous=undo_image;
6555 undo_image=undo_image->next;
6556 break;
6557 }
6558 default:
6559 break;
6560 }
6561 if (command == RedoCommand)
6562 {
6563 /*
6564 Redo the last image transformation.
6565 */
6566 if (redo_image == (Image *) NULL)
6567 {
6568 (void) XBell(display,0);
6569 return;
6570 }
6571 windows->image.window_changes.width=(int) redo_image->columns;
6572 windows->image.window_changes.height=(int) redo_image->rows;
6573 if (windows->image.crop_geometry != (char *) NULL)
6574 windows->image.crop_geometry=(char *)
6575 RelinquishMagickMemory(windows->image.crop_geometry);
6576 windows->image.crop_geometry=redo_image->geometry;
6577 *image=DestroyImage(*image);
6578 *image=redo_image;
6579 redo_image=NewImageList();
6580 if (windows->image.orphan != MagickFalse)
6581 return;
6582 XConfigureImageColormap(display,resource_info,windows,*image);
6583 (void) XConfigureImage(display,resource_info,windows,*image);
6584 return;
6585 }
6586 if (command != InfoCommand)
6587 return;
6588 /*
6589 Display image info.
6590 */
6591 XSetCursorState(display,windows,MagickTrue);
6592 XCheckRefreshWindows(display,windows);
6593 XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
6594 XSetCursorState(display,windows,MagickFalse);
6595}
6596
6597/*
6598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6599% %
6600% %
6601% %
6602+ X I m a g e W i n d o w C o m m a n d %
6603% %
6604% %
6605% %
6606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6607%
6608% XImageWindowCommand() makes a transform to the image or Image window as
6609% specified by a user menu button or keyboard command.
6610%
6611% The format of the XMagickCommand method is:
6612%
6613% DisplayCommand XImageWindowCommand(Display *display,
6614% XResourceInfo *resource_info,XWindows *windows,
6615% const MagickStatusType state,KeySym key_symbol,Image **image)
6616%
6617% A description of each parameter follows:
6618%
6619% o nexus: Method XImageWindowCommand returns an image when the
6620% user chooses 'Open Image' from the command menu. Otherwise a null
6621% image is returned.
6622%
6623% o display: Specifies a connection to an X server; returned from
6624% XOpenDisplay.
6625%
6626% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6627%
6628% o windows: Specifies a pointer to a XWindows structure.
6629%
6630% o state: key mask.
6631%
6632% o key_symbol: Specifies a command to perform.
6633%
6634% o image: the image; XImageWIndowCommand
6635% may transform the image and return a new image pointer.
6636%
6637*/
6638static DisplayCommand XImageWindowCommand(Display *display,
6639 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6640 KeySym key_symbol,Image **image)
6641{
6642 static char
6643 delta[MaxTextExtent+1] = "";
6644
6645 static const char
6646 Digits[] = "01234567890";
6647
6648 static KeySym
6649 last_symbol = XK_0;
6650
6651 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6652 {
6653 size_t
6654 length;
6655
6656 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6657 {
6658 *delta='\0';
6659 resource_info->quantum=1;
6660 }
6661 last_symbol=key_symbol;
6662 length=strlen(delta);
6663 if (length < MagickPathExtent)
6664 {
6665 delta[length]=Digits[key_symbol-XK_0];
6666 delta[length+1]='\0';
6667 }
6668 resource_info->quantum=StringToLong(delta);
6669 return(NullCommand);
6670 }
6671 last_symbol=key_symbol;
6672 if (resource_info->immutable)
6673 {
6674 /*
6675 Virtual image window has a restricted command set.
6676 */
6677 switch (key_symbol)
6678 {
6679 case XK_question:
6680 return(InfoCommand);
6681 case XK_p:
6682 case XK_Print:
6683 return(PrintCommand);
6684 case XK_space:
6685 return(NextCommand);
6686 case XK_q:
6687 case XK_Escape:
6688 return(QuitCommand);
6689 default:
6690 break;
6691 }
6692 return(NullCommand);
6693 }
6694 switch ((int) key_symbol)
6695 {
6696 case XK_o:
6697 {
6698 if ((state & ControlMask) == 0)
6699 break;
6700 return(OpenCommand);
6701 }
6702 case XK_space:
6703 return(NextCommand);
6704 case XK_BackSpace:
6705 return(FormerCommand);
6706 case XK_s:
6707 {
6708 if ((state & Mod1Mask) != 0)
6709 return(SwirlCommand);
6710 if ((state & ControlMask) == 0)
6711 return(ShearCommand);
6712 return(SaveCommand);
6713 }
6714 case XK_p:
6715 case XK_Print:
6716 {
6717 if ((state & Mod1Mask) != 0)
6718 return(OilPaintCommand);
6719 if ((state & Mod4Mask) != 0)
6720 return(ColorCommand);
6721 if ((state & ControlMask) == 0)
6722 return(NullCommand);
6723 return(PrintCommand);
6724 }
6725 case XK_d:
6726 {
6727 if ((state & Mod4Mask) != 0)
6728 return(DrawCommand);
6729 if ((state & ControlMask) == 0)
6730 return(NullCommand);
6731 return(DeleteCommand);
6732 }
6733 case XK_Select:
6734 {
6735 if ((state & ControlMask) == 0)
6736 return(NullCommand);
6737 return(SelectCommand);
6738 }
6739 case XK_n:
6740 {
6741 if ((state & ControlMask) == 0)
6742 return(NullCommand);
6743 return(NewCommand);
6744 }
6745 case XK_q:
6746 case XK_Escape:
6747 return(QuitCommand);
6748 case XK_z:
6749 case XK_Undo:
6750 {
6751 if ((state & ControlMask) == 0)
6752 return(NullCommand);
6753 return(UndoCommand);
6754 }
6755 case XK_r:
6756 case XK_Redo:
6757 {
6758 if ((state & ControlMask) == 0)
6759 return(RollCommand);
6760 return(RedoCommand);
6761 }
6762 case XK_x:
6763 {
6764 if ((state & ControlMask) == 0)
6765 return(NullCommand);
6766 return(CutCommand);
6767 }
6768 case XK_c:
6769 {
6770 if ((state & Mod1Mask) != 0)
6771 return(CharcoalDrawCommand);
6772 if ((state & ControlMask) == 0)
6773 return(CropCommand);
6774 return(CopyCommand);
6775 }
6776 case XK_v:
6777 case XK_Insert:
6778 {
6779 if ((state & Mod4Mask) != 0)
6780 return(CompositeCommand);
6781 if ((state & ControlMask) == 0)
6782 return(FlipCommand);
6783 return(PasteCommand);
6784 }
6785 case XK_less:
6786 return(HalfSizeCommand);
6787 case XK_minus:
6788 return(OriginalSizeCommand);
6789 case XK_greater:
6790 return(DoubleSizeCommand);
6791 case XK_percent:
6792 return(ResizeCommand);
6793 case XK_at:
6794 return(RefreshCommand);
6795 case XK_bracketleft:
6796 return(ChopCommand);
6797 case XK_h:
6798 return(FlopCommand);
6799 case XK_slash:
6800 return(RotateRightCommand);
6801 case XK_backslash:
6802 return(RotateLeftCommand);
6803 case XK_asterisk:
6804 return(RotateCommand);
6805 case XK_t:
6806 return(TrimCommand);
6807 case XK_H:
6808 return(HueCommand);
6809 case XK_S:
6810 return(SaturationCommand);
6811 case XK_L:
6812 return(BrightnessCommand);
6813 case XK_G:
6814 return(GammaCommand);
6815 case XK_C:
6816 return(SpiffCommand);
6817 case XK_Z:
6818 return(DullCommand);
6819 case XK_N:
6820 return(NormalizeCommand);
6821 case XK_equal:
6822 return(EqualizeCommand);
6823 case XK_asciitilde:
6824 return(NegateCommand);
6825 case XK_period:
6826 return(GrayscaleCommand);
6827 case XK_numbersign:
6828 return(QuantizeCommand);
6829 case XK_F2:
6830 return(DespeckleCommand);
6831 case XK_F3:
6832 return(EmbossCommand);
6833 case XK_F4:
6834 return(ReduceNoiseCommand);
6835 case XK_F5:
6836 return(AddNoiseCommand);
6837 case XK_F6:
6838 return(SharpenCommand);
6839 case XK_F7:
6840 return(BlurCommand);
6841 case XK_F8:
6842 return(ThresholdCommand);
6843 case XK_F9:
6844 return(EdgeDetectCommand);
6845 case XK_F10:
6846 return(SpreadCommand);
6847 case XK_F11:
6848 return(ShadeCommand);
6849 case XK_F12:
6850 return(RaiseCommand);
6851 case XK_F13:
6852 return(SegmentCommand);
6853 case XK_i:
6854 {
6855 if ((state & Mod1Mask) == 0)
6856 return(NullCommand);
6857 return(ImplodeCommand);
6858 }
6859 case XK_w:
6860 {
6861 if ((state & Mod1Mask) == 0)
6862 return(NullCommand);
6863 return(WaveCommand);
6864 }
6865 case XK_m:
6866 {
6867 if ((state & Mod4Mask) == 0)
6868 return(NullCommand);
6869 return(MatteCommand);
6870 }
6871 case XK_b:
6872 {
6873 if ((state & Mod4Mask) == 0)
6874 return(NullCommand);
6875 return(AddBorderCommand);
6876 }
6877 case XK_f:
6878 {
6879 if ((state & Mod4Mask) == 0)
6880 return(NullCommand);
6881 return(AddFrameCommand);
6882 }
6883 case XK_exclam:
6884 {
6885 if ((state & Mod4Mask) == 0)
6886 return(NullCommand);
6887 return(CommentCommand);
6888 }
6889 case XK_a:
6890 {
6891 if ((state & Mod1Mask) != 0)
6892 return(ApplyCommand);
6893 if ((state & Mod4Mask) != 0)
6894 return(AnnotateCommand);
6895 if ((state & ControlMask) == 0)
6896 return(NullCommand);
6897 return(RegionOfInterestCommand);
6898 }
6899 case XK_question:
6900 return(InfoCommand);
6901 case XK_plus:
6902 return(ZoomCommand);
6903 case XK_P:
6904 {
6905 if ((state & ShiftMask) == 0)
6906 return(NullCommand);
6907 return(ShowPreviewCommand);
6908 }
6909 case XK_Execute:
6910 return(LaunchCommand);
6911 case XK_F1:
6912 return(HelpCommand);
6913 case XK_Find:
6914 return(BrowseDocumentationCommand);
6915 case XK_Menu:
6916 {
6917 (void) XMapRaised(display,windows->command.id);
6918 return(NullCommand);
6919 }
6920 case XK_Next:
6921 case XK_Prior:
6922 case XK_Home:
6923 case XK_KP_Home:
6924 {
6925 XTranslateImage(display,windows,*image,key_symbol);
6926 return(NullCommand);
6927 }
6928 case XK_Up:
6929 case XK_KP_Up:
6930 case XK_Down:
6931 case XK_KP_Down:
6932 case XK_Left:
6933 case XK_KP_Left:
6934 case XK_Right:
6935 case XK_KP_Right:
6936 {
6937 if ((state & Mod1Mask) != 0)
6938 {
6939 RectangleInfo
6940 crop_info;
6941
6942 /*
6943 Trim one pixel from edge of image.
6944 */
6945 crop_info.x=0;
6946 crop_info.y=0;
6947 crop_info.width=(size_t) windows->image.ximage->width;
6948 crop_info.height=(size_t) windows->image.ximage->height;
6949 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
6950 {
6951 if (resource_info->quantum >= (int) crop_info.height)
6952 resource_info->quantum=(int) crop_info.height-1;
6953 crop_info.height-=resource_info->quantum;
6954 }
6955 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
6956 {
6957 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
6958 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
6959 crop_info.y+=resource_info->quantum;
6960 crop_info.height-=resource_info->quantum;
6961 }
6962 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
6963 {
6964 if (resource_info->quantum >= (int) crop_info.width)
6965 resource_info->quantum=(int) crop_info.width-1;
6966 crop_info.width-=resource_info->quantum;
6967 }
6968 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
6969 {
6970 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
6971 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
6972 crop_info.x+=resource_info->quantum;
6973 crop_info.width-=resource_info->quantum;
6974 }
6975 if ((int) (windows->image.x+windows->image.width) >
6976 (int) crop_info.width)
6977 windows->image.x=(int) (crop_info.width-windows->image.width);
6978 if ((int) (windows->image.y+windows->image.height) >
6979 (int) crop_info.height)
6980 windows->image.y=(int) (crop_info.height-windows->image.height);
6981 XSetCropGeometry(display,windows,&crop_info,*image);
6982 windows->image.window_changes.width=(int) crop_info.width;
6983 windows->image.window_changes.height=(int) crop_info.height;
6984 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
6985 (void) XConfigureImage(display,resource_info,windows,*image);
6986 return(NullCommand);
6987 }
6988 XTranslateImage(display,windows,*image,key_symbol);
6989 return(NullCommand);
6990 }
6991 default:
6992 return(NullCommand);
6993 }
6994 return(NullCommand);
6995}
6996
6997/*
6998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6999% %
7000% %
7001% %
7002+ X M a g i c k C o m m a n d %
7003% %
7004% %
7005% %
7006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7007%
7008% XMagickCommand() makes a transform to the image or Image window as
7009% specified by a user menu button or keyboard command.
7010%
7011% The format of the XMagickCommand method is:
7012%
7013% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7014% XWindows *windows,const DisplayCommand command,Image **image)
7015%
7016% A description of each parameter follows:
7017%
7018% o nexus: Method XMagickCommand returns an image when the
7019% user chooses 'Load Image' from the command menu. Otherwise a null
7020% image is returned.
7021%
7022% o display: Specifies a connection to an X server; returned from
7023% XOpenDisplay.
7024%
7025% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7026%
7027% o windows: Specifies a pointer to a XWindows structure.
7028%
7029% o command: Specifies a command to perform.
7030%
7031% o image: the image; XMagickCommand
7032% may transform the image and return a new image pointer.
7033%
7034*/
7035static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7036 XWindows *windows,const DisplayCommand command,Image **image)
7037{
7038 char
7039 filename[MaxTextExtent],
7040 geometry[MaxTextExtent],
7041 modulate_factors[MaxTextExtent];
7042
7043 GeometryInfo
7044 geometry_info;
7045
7046 Image
7047 *nexus;
7048
7049 ImageInfo
7050 *image_info;
7051
7052 int
7053 x,
7054 y;
7055
7056 MagickStatusType
7057 flags,
7058 status;
7059
7060 QuantizeInfo
7061 quantize_info;
7062
7063 RectangleInfo
7064 page_geometry;
7065
7066 int
7067 i;
7068
7069 static char
7070 color[MaxTextExtent] = "gray";
7071
7072 unsigned int
7073 height,
7074 width;
7075
7076 /*
7077 Process user command.
7078 */
7079 XCheckRefreshWindows(display,windows);
7080 XImageCache(display,resource_info,windows,command,image);
7081 nexus=NewImageList();
7082 windows->image.window_changes.width=windows->image.ximage->width;
7083 windows->image.window_changes.height=windows->image.ximage->height;
7084 image_info=CloneImageInfo(resource_info->image_info);
7085 SetGeometryInfo(&geometry_info);
7086 GetQuantizeInfo(&quantize_info);
7087 switch (command)
7088 {
7089 case OpenCommand:
7090 {
7091 /*
7092 Load image.
7093 */
7094 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7095 break;
7096 }
7097 case NextCommand:
7098 {
7099 /*
7100 Display next image.
7101 */
7102 for (i=0; i < resource_info->quantum; i++)
7103 XClientMessage(display,windows->image.id,windows->im_protocols,
7104 windows->im_next_image,CurrentTime);
7105 break;
7106 }
7107 case FormerCommand:
7108 {
7109 /*
7110 Display former image.
7111 */
7112 for (i=0; i < resource_info->quantum; i++)
7113 XClientMessage(display,windows->image.id,windows->im_protocols,
7114 windows->im_former_image,CurrentTime);
7115 break;
7116 }
7117 case SelectCommand:
7118 {
7119 int
7120 status;
7121
7122 /*
7123 Select image.
7124 */
7125 if (*resource_info->home_directory == '\0')
7126 (void) CopyMagickString(resource_info->home_directory,".",
7127 MaxTextExtent);
7128 status=chdir(resource_info->home_directory);
7129 if (status == -1)
7130 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
7131 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
7132 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7133 break;
7134 }
7135 case SaveCommand:
7136 {
7137 /*
7138 Save image.
7139 */
7140 status=XSaveImage(display,resource_info,windows,*image);
7141 if (status == MagickFalse)
7142 {
7143 char
7144 message[MaxTextExtent];
7145
7146 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7147 (*image)->exception.reason != (char *) NULL ?
7148 (*image)->exception.reason : "",
7149 (*image)->exception.description != (char *) NULL ?
7150 (*image)->exception.description : "");
7151 XNoticeWidget(display,windows,"Unable to save file:",message);
7152 break;
7153 }
7154 break;
7155 }
7156 case PrintCommand:
7157 {
7158 /*
7159 Print image.
7160 */
7161 status=XPrintImage(display,resource_info,windows,*image);
7162 if (status == MagickFalse)
7163 {
7164 char
7165 message[MaxTextExtent];
7166
7167 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7168 (*image)->exception.reason != (char *) NULL ?
7169 (*image)->exception.reason : "",
7170 (*image)->exception.description != (char *) NULL ?
7171 (*image)->exception.description : "");
7172 XNoticeWidget(display,windows,"Unable to print file:",message);
7173 break;
7174 }
7175 break;
7176 }
7177 case DeleteCommand:
7178 {
7179 static char
7180 filename[MaxTextExtent] = "\0";
7181
7182 /*
7183 Delete image file.
7184 */
7185 XFileBrowserWidget(display,windows,"Delete",filename);
7186 if (*filename == '\0')
7187 break;
7188 status=ShredFile(filename);
7189 status|=remove_utf8(filename);
7190 if (status != MagickFalse)
7191 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7192 break;
7193 }
7194 case NewCommand:
7195 {
7196 int
7197 status;
7198
7199 static char
7200 color[MaxTextExtent] = "gray",
7201 geometry[MaxTextExtent] = "640x480";
7202
7203 static const char
7204 *format = "gradient";
7205
7206 /*
7207 Query user for canvas geometry.
7208 */
7209 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7210 geometry);
7211 if (*geometry == '\0')
7212 break;
7213 if (status == 0)
7214 format="xc";
7215 XColorBrowserWidget(display,windows,"Select",color);
7216 if (*color == '\0')
7217 break;
7218 /*
7219 Create canvas.
7220 */
7221 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
7222 "%s:%s",format,color);
7223 (void) CloneString(&image_info->size,geometry);
7224 nexus=ReadImage(image_info,&(*image)->exception);
7225 CatchException(&(*image)->exception);
7226 XClientMessage(display,windows->image.id,windows->im_protocols,
7227 windows->im_next_image,CurrentTime);
7228 break;
7229 }
7230 case VisualDirectoryCommand:
7231 {
7232 /*
7233 Visual Image directory.
7234 */
7235 nexus=XVisualDirectoryImage(display,resource_info,windows);
7236 break;
7237 }
7238 case QuitCommand:
7239 {
7240 /*
7241 exit program.
7242 */
7243 if (resource_info->confirm_exit == MagickFalse)
7244 XClientMessage(display,windows->image.id,windows->im_protocols,
7245 windows->im_exit,CurrentTime);
7246 else
7247 {
7248 int
7249 status;
7250
7251 /*
7252 Confirm program exit.
7253 */
7254 status=XConfirmWidget(display,windows,"Do you really want to exit",
7255 resource_info->client_name);
7256 if (status > 0)
7257 XClientMessage(display,windows->image.id,windows->im_protocols,
7258 windows->im_exit,CurrentTime);
7259 }
7260 break;
7261 }
7262 case CutCommand:
7263 {
7264 /*
7265 Cut image.
7266 */
7267 (void) XCropImage(display,resource_info,windows,*image,CutMode);
7268 break;
7269 }
7270 case CopyCommand:
7271 {
7272 /*
7273 Copy image.
7274 */
7275 (void) XCropImage(display,resource_info,windows,*image,CopyMode);
7276 break;
7277 }
7278 case PasteCommand:
7279 {
7280 /*
7281 Paste image.
7282 */
7283 status=XPasteImage(display,resource_info,windows,*image);
7284 if (status == MagickFalse)
7285 {
7286 XNoticeWidget(display,windows,"Unable to paste X image",
7287 (*image)->filename);
7288 break;
7289 }
7290 break;
7291 }
7292 case HalfSizeCommand:
7293 {
7294 /*
7295 Half image size.
7296 */
7297 windows->image.window_changes.width=windows->image.ximage->width/2;
7298 windows->image.window_changes.height=windows->image.ximage->height/2;
7299 (void) XConfigureImage(display,resource_info,windows,*image);
7300 break;
7301 }
7302 case OriginalSizeCommand:
7303 {
7304 /*
7305 Original image size.
7306 */
7307 windows->image.window_changes.width=(int) (*image)->columns;
7308 windows->image.window_changes.height=(int) (*image)->rows;
7309 (void) XConfigureImage(display,resource_info,windows,*image);
7310 break;
7311 }
7312 case DoubleSizeCommand:
7313 {
7314 /*
7315 Double the image size.
7316 */
7317 windows->image.window_changes.width=windows->image.ximage->width << 1;
7318 windows->image.window_changes.height=windows->image.ximage->height << 1;
7319 (void) XConfigureImage(display,resource_info,windows,*image);
7320 break;
7321 }
7322 case ResizeCommand:
7323 {
7324 int
7325 status;
7326
7327 size_t
7328 height,
7329 width;
7330
7331 ssize_t
7332 x,
7333 y;
7334
7335 /*
7336 Resize image.
7337 */
7338 width=(size_t) windows->image.ximage->width;
7339 height=(size_t) windows->image.ximage->height;
7340 x=0;
7341 y=0;
7342 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
7343 (double) width,(double) height);
7344 status=XDialogWidget(display,windows,"Resize",
7345 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7346 if (*geometry == '\0')
7347 break;
7348 if (status == 0)
7349 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7350 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7351 windows->image.window_changes.width=(int) width;
7352 windows->image.window_changes.height=(int) height;
7353 (void) XConfigureImage(display,resource_info,windows,*image);
7354 break;
7355 }
7356 case ApplyCommand:
7357 {
7358 char
7359 image_geometry[MaxTextExtent];
7360
7361 if ((windows->image.crop_geometry == (char *) NULL) &&
7362 ((int) (*image)->columns == windows->image.ximage->width) &&
7363 ((int) (*image)->rows == windows->image.ximage->height))
7364 break;
7365 /*
7366 Apply size transforms to image.
7367 */
7368 XSetCursorState(display,windows,MagickTrue);
7369 XCheckRefreshWindows(display,windows);
7370 /*
7371 Crop and/or scale displayed image.
7372 */
7373 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
7374 windows->image.ximage->width,windows->image.ximage->height);
7375 (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
7376 if (windows->image.crop_geometry != (char *) NULL)
7377 windows->image.crop_geometry=(char *)
7378 RelinquishMagickMemory(windows->image.crop_geometry);
7379 windows->image.x=0;
7380 windows->image.y=0;
7381 XConfigureImageColormap(display,resource_info,windows,*image);
7382 (void) XConfigureImage(display,resource_info,windows,*image);
7383 break;
7384 }
7385 case RefreshCommand:
7386 {
7387 (void) XConfigureImage(display,resource_info,windows,*image);
7388 break;
7389 }
7390 case RestoreCommand:
7391 {
7392 /*
7393 Restore Image window to its original size.
7394 */
7395 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7396 (windows->image.height == (unsigned int) (*image)->rows) &&
7397 (windows->image.crop_geometry == (char *) NULL))
7398 {
7399 (void) XBell(display,0);
7400 break;
7401 }
7402 windows->image.window_changes.width=(int) (*image)->columns;
7403 windows->image.window_changes.height=(int) (*image)->rows;
7404 if (windows->image.crop_geometry != (char *) NULL)
7405 {
7406 windows->image.crop_geometry=(char *)
7407 RelinquishMagickMemory(windows->image.crop_geometry);
7408 windows->image.crop_geometry=(char *) NULL;
7409 windows->image.x=0;
7410 windows->image.y=0;
7411 }
7412 XConfigureImageColormap(display,resource_info,windows,*image);
7413 (void) XConfigureImage(display,resource_info,windows,*image);
7414 break;
7415 }
7416 case CropCommand:
7417 {
7418 /*
7419 Crop image.
7420 */
7421 (void) XCropImage(display,resource_info,windows,*image,CropMode);
7422 break;
7423 }
7424 case ChopCommand:
7425 {
7426 /*
7427 Chop image.
7428 */
7429 status=XChopImage(display,resource_info,windows,image);
7430 if (status == MagickFalse)
7431 {
7432 XNoticeWidget(display,windows,"Unable to cut X image",
7433 (*image)->filename);
7434 break;
7435 }
7436 break;
7437 }
7438 case FlopCommand:
7439 {
7440 Image
7441 *flop_image;
7442
7443 /*
7444 Flop image scanlines.
7445 */
7446 XSetCursorState(display,windows,MagickTrue);
7447 XCheckRefreshWindows(display,windows);
7448 flop_image=FlopImage(*image,&(*image)->exception);
7449 if (flop_image != (Image *) NULL)
7450 {
7451 *image=DestroyImage(*image);
7452 *image=flop_image;
7453 }
7454 CatchException(&(*image)->exception);
7455 XSetCursorState(display,windows,MagickFalse);
7456 if (windows->image.crop_geometry != (char *) NULL)
7457 {
7458 /*
7459 Flop crop geometry.
7460 */
7461 width=(unsigned int) (*image)->columns;
7462 height=(unsigned int) (*image)->rows;
7463 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7464 &width,&height);
7465 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7466 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7467 }
7468 if (windows->image.orphan != MagickFalse)
7469 break;
7470 (void) XConfigureImage(display,resource_info,windows,*image);
7471 break;
7472 }
7473 case FlipCommand:
7474 {
7475 Image
7476 *flip_image;
7477
7478 /*
7479 Flip image scanlines.
7480 */
7481 XSetCursorState(display,windows,MagickTrue);
7482 XCheckRefreshWindows(display,windows);
7483 flip_image=FlipImage(*image,&(*image)->exception);
7484 if (flip_image != (Image *) NULL)
7485 {
7486 *image=DestroyImage(*image);
7487 *image=flip_image;
7488 }
7489 CatchException(&(*image)->exception);
7490 XSetCursorState(display,windows,MagickFalse);
7491 if (windows->image.crop_geometry != (char *) NULL)
7492 {
7493 /*
7494 Flip crop geometry.
7495 */
7496 width=(unsigned int) (*image)->columns;
7497 height=(unsigned int) (*image)->rows;
7498 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7499 &width,&height);
7500 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
7501 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7502 }
7503 if (windows->image.orphan != MagickFalse)
7504 break;
7505 (void) XConfigureImage(display,resource_info,windows,*image);
7506 break;
7507 }
7508 case RotateRightCommand:
7509 {
7510 /*
7511 Rotate image 90 degrees clockwise.
7512 */
7513 status=XRotateImage(display,resource_info,windows,90.0,image);
7514 if (status == MagickFalse)
7515 {
7516 XNoticeWidget(display,windows,"Unable to rotate X image",
7517 (*image)->filename);
7518 break;
7519 }
7520 break;
7521 }
7522 case RotateLeftCommand:
7523 {
7524 /*
7525 Rotate image 90 degrees counter-clockwise.
7526 */
7527 status=XRotateImage(display,resource_info,windows,-90.0,image);
7528 if (status == MagickFalse)
7529 {
7530 XNoticeWidget(display,windows,"Unable to rotate X image",
7531 (*image)->filename);
7532 break;
7533 }
7534 break;
7535 }
7536 case RotateCommand:
7537 {
7538 /*
7539 Rotate image.
7540 */
7541 status=XRotateImage(display,resource_info,windows,0.0,image);
7542 if (status == MagickFalse)
7543 {
7544 XNoticeWidget(display,windows,"Unable to rotate X image",
7545 (*image)->filename);
7546 break;
7547 }
7548 break;
7549 }
7550 case ShearCommand:
7551 {
7552 Image
7553 *shear_image;
7554
7555 static char
7556 geometry[MaxTextExtent] = "45.0x45.0";
7557
7558 /*
7559 Query user for shear color and geometry.
7560 */
7561 XColorBrowserWidget(display,windows,"Select",color);
7562 if (*color == '\0')
7563 break;
7564 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7565 geometry);
7566 if (*geometry == '\0')
7567 break;
7568 /*
7569 Shear image.
7570 */
7571 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7572 XSetCursorState(display,windows,MagickTrue);
7573 XCheckRefreshWindows(display,windows);
7574 (void) QueryColorDatabase(color,&(*image)->background_color,
7575 &(*image)->exception);
7576 flags=ParseGeometry(geometry,&geometry_info);
7577 if ((flags & SigmaValue) == 0)
7578 geometry_info.sigma=geometry_info.rho;
7579 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7580 &(*image)->exception);
7581 if (shear_image != (Image *) NULL)
7582 {
7583 *image=DestroyImage(*image);
7584 *image=shear_image;
7585 }
7586 CatchException(&(*image)->exception);
7587 XSetCursorState(display,windows,MagickFalse);
7588 if (windows->image.orphan != MagickFalse)
7589 break;
7590 windows->image.window_changes.width=(int) (*image)->columns;
7591 windows->image.window_changes.height=(int) (*image)->rows;
7592 XConfigureImageColormap(display,resource_info,windows,*image);
7593 (void) XConfigureImage(display,resource_info,windows,*image);
7594 break;
7595 }
7596 case RollCommand:
7597 {
7598 Image
7599 *roll_image;
7600
7601 static char
7602 geometry[MaxTextExtent] = "+2+2";
7603
7604 /*
7605 Query user for the roll geometry.
7606 */
7607 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7608 geometry);
7609 if (*geometry == '\0')
7610 break;
7611 /*
7612 Roll image.
7613 */
7614 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
7615 XSetCursorState(display,windows,MagickTrue);
7616 XCheckRefreshWindows(display,windows);
7617 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7618 &(*image)->exception);
7619 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7620 &(*image)->exception);
7621 if (roll_image != (Image *) NULL)
7622 {
7623 *image=DestroyImage(*image);
7624 *image=roll_image;
7625 }
7626 CatchException(&(*image)->exception);
7627 XSetCursorState(display,windows,MagickFalse);
7628 if (windows->image.orphan != MagickFalse)
7629 break;
7630 windows->image.window_changes.width=(int) (*image)->columns;
7631 windows->image.window_changes.height=(int) (*image)->rows;
7632 XConfigureImageColormap(display,resource_info,windows,*image);
7633 (void) XConfigureImage(display,resource_info,windows,*image);
7634 break;
7635 }
7636 case TrimCommand:
7637 {
7638 static char
7639 fuzz[MaxTextExtent];
7640
7641 /*
7642 Query user for the fuzz factor.
7643 */
7644 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
7645 (*image)->fuzz/((double) QuantumRange+1.0));
7646 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7647 if (*fuzz == '\0')
7648 break;
7649 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7650 /*
7651 Trim image.
7652 */
7653 status=XTrimImage(display,resource_info,windows,*image);
7654 if (status == MagickFalse)
7655 {
7656 XNoticeWidget(display,windows,"Unable to trim X image",
7657 (*image)->filename);
7658 break;
7659 }
7660 break;
7661 }
7662 case HueCommand:
7663 {
7664 static char
7665 hue_percent[MaxTextExtent] = "110";
7666
7667 /*
7668 Query user for percent hue change.
7669 */
7670 (void) XDialogWidget(display,windows,"Apply",
7671 "Enter percent change in image hue (0-200):",hue_percent);
7672 if (*hue_percent == '\0')
7673 break;
7674 /*
7675 Vary the image hue.
7676 */
7677 XSetCursorState(display,windows,MagickTrue);
7678 XCheckRefreshWindows(display,windows);
7679 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7680 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7681 MaxTextExtent);
7682 (void) ModulateImage(*image,modulate_factors);
7683 XSetCursorState(display,windows,MagickFalse);
7684 if (windows->image.orphan != MagickFalse)
7685 break;
7686 XConfigureImageColormap(display,resource_info,windows,*image);
7687 (void) XConfigureImage(display,resource_info,windows,*image);
7688 break;
7689 }
7690 case SaturationCommand:
7691 {
7692 static char
7693 saturation_percent[MaxTextExtent] = "110";
7694
7695 /*
7696 Query user for percent saturation change.
7697 */
7698 (void) XDialogWidget(display,windows,"Apply",
7699 "Enter percent change in color saturation (0-200):",saturation_percent);
7700 if (*saturation_percent == '\0')
7701 break;
7702 /*
7703 Vary color saturation.
7704 */
7705 XSetCursorState(display,windows,MagickTrue);
7706 XCheckRefreshWindows(display,windows);
7707 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7708 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7709 MaxTextExtent);
7710 (void) ModulateImage(*image,modulate_factors);
7711 XSetCursorState(display,windows,MagickFalse);
7712 if (windows->image.orphan != MagickFalse)
7713 break;
7714 XConfigureImageColormap(display,resource_info,windows,*image);
7715 (void) XConfigureImage(display,resource_info,windows,*image);
7716 break;
7717 }
7718 case BrightnessCommand:
7719 {
7720 static char
7721 brightness_percent[MaxTextExtent] = "110";
7722
7723 /*
7724 Query user for percent brightness change.
7725 */
7726 (void) XDialogWidget(display,windows,"Apply",
7727 "Enter percent change in color brightness (0-200):",brightness_percent);
7728 if (*brightness_percent == '\0')
7729 break;
7730 /*
7731 Vary the color brightness.
7732 */
7733 XSetCursorState(display,windows,MagickTrue);
7734 XCheckRefreshWindows(display,windows);
7735 (void) CopyMagickString(modulate_factors,brightness_percent,
7736 MaxTextExtent);
7737 (void) ModulateImage(*image,modulate_factors);
7738 XSetCursorState(display,windows,MagickFalse);
7739 if (windows->image.orphan != MagickFalse)
7740 break;
7741 XConfigureImageColormap(display,resource_info,windows,*image);
7742 (void) XConfigureImage(display,resource_info,windows,*image);
7743 break;
7744 }
7745 case GammaCommand:
7746 {
7747 static char
7748 factor[MaxTextExtent] = "1.6";
7749
7750 /*
7751 Query user for gamma value.
7752 */
7753 (void) XDialogWidget(display,windows,"Gamma",
7754 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
7755 if (*factor == '\0')
7756 break;
7757 /*
7758 Gamma correct image.
7759 */
7760 XSetCursorState(display,windows,MagickTrue);
7761 XCheckRefreshWindows(display,windows);
7762 (void) GammaImage(*image,factor);
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 SpiffCommand:
7771 {
7772 /*
7773 Sharpen the image contrast.
7774 */
7775 XSetCursorState(display,windows,MagickTrue);
7776 XCheckRefreshWindows(display,windows);
7777 (void) ContrastImage(*image,MagickTrue);
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 DullCommand:
7786 {
7787 /*
7788 Dull the image contrast.
7789 */
7790 XSetCursorState(display,windows,MagickTrue);
7791 XCheckRefreshWindows(display,windows);
7792 (void) ContrastImage(*image,MagickFalse);
7793 XSetCursorState(display,windows,MagickFalse);
7794 if (windows->image.orphan != MagickFalse)
7795 break;
7796 XConfigureImageColormap(display,resource_info,windows,*image);
7797 (void) XConfigureImage(display,resource_info,windows,*image);
7798 break;
7799 }
7800 case ContrastStretchCommand:
7801 {
7802 double
7803 black_point,
7804 white_point;
7805
7806 static char
7807 levels[MaxTextExtent] = "1%";
7808
7809 /*
7810 Query user for gamma value.
7811 */
7812 (void) XDialogWidget(display,windows,"Contrast Stretch",
7813 "Enter black and white points:",levels);
7814 if (*levels == '\0')
7815 break;
7816 /*
7817 Contrast stretch image.
7818 */
7819 XSetCursorState(display,windows,MagickTrue);
7820 XCheckRefreshWindows(display,windows);
7821 flags=ParseGeometry(levels,&geometry_info);
7822 black_point=geometry_info.rho;
7823 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7824 if ((flags & PercentValue) != 0)
7825 {
7826 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7827 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7828 }
7829 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
7830 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
7831 white_point);
7832 XSetCursorState(display,windows,MagickFalse);
7833 if (windows->image.orphan != MagickFalse)
7834 break;
7835 XConfigureImageColormap(display,resource_info,windows,*image);
7836 (void) XConfigureImage(display,resource_info,windows,*image);
7837 break;
7838 }
7839 case SigmoidalContrastCommand:
7840 {
7841 static char
7842 levels[MaxTextExtent] = "3x50%";
7843
7844 /*
7845 Query user for gamma value.
7846 */
7847 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7848 "Enter contrast and midpoint:",levels);
7849 if (*levels == '\0')
7850 break;
7851 /*
7852 Contrast stretch image.
7853 */
7854 XSetCursorState(display,windows,MagickTrue);
7855 XCheckRefreshWindows(display,windows);
7856 (void) SigmoidalContrastImage(*image,MagickTrue,levels);
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 NormalizeCommand:
7865 {
7866 /*
7867 Perform histogram normalization on the image.
7868 */
7869 XSetCursorState(display,windows,MagickTrue);
7870 XCheckRefreshWindows(display,windows);
7871 (void) NormalizeImage(*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 EqualizeCommand:
7880 {
7881 /*
7882 Perform histogram equalization on the image.
7883 */
7884 XSetCursorState(display,windows,MagickTrue);
7885 XCheckRefreshWindows(display,windows);
7886 (void) EqualizeImage(*image);
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 NegateCommand:
7895 {
7896 /*
7897 Negate colors in image.
7898 */
7899 XSetCursorState(display,windows,MagickTrue);
7900 XCheckRefreshWindows(display,windows);
7901 (void) NegateImage(*image,MagickFalse);
7902 XSetCursorState(display,windows,MagickFalse);
7903 if (windows->image.orphan != MagickFalse)
7904 break;
7905 XConfigureImageColormap(display,resource_info,windows,*image);
7906 (void) XConfigureImage(display,resource_info,windows,*image);
7907 break;
7908 }
7909 case GrayscaleCommand:
7910 {
7911 /*
7912 Convert image to grayscale.
7913 */
7914 XSetCursorState(display,windows,MagickTrue);
7915 XCheckRefreshWindows(display,windows);
7916 (void) SetImageType(*image,(*image)->matte == MagickFalse ?
7917 GrayscaleType : GrayscaleMatteType);
7918 XSetCursorState(display,windows,MagickFalse);
7919 if (windows->image.orphan != MagickFalse)
7920 break;
7921 XConfigureImageColormap(display,resource_info,windows,*image);
7922 (void) XConfigureImage(display,resource_info,windows,*image);
7923 break;
7924 }
7925 case MapCommand:
7926 {
7927 Image
7928 *affinity_image;
7929
7930 static char
7931 filename[MaxTextExtent] = "\0";
7932
7933 /*
7934 Request image file name from user.
7935 */
7936 XFileBrowserWidget(display,windows,"Map",filename);
7937 if (*filename == '\0')
7938 break;
7939 /*
7940 Map image.
7941 */
7942 XSetCursorState(display,windows,MagickTrue);
7943 XCheckRefreshWindows(display,windows);
7944 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
7945 affinity_image=ReadImage(image_info,&(*image)->exception);
7946 if (affinity_image != (Image *) NULL)
7947 {
7948 (void) RemapImage(&quantize_info,*image,affinity_image);
7949 affinity_image=DestroyImage(affinity_image);
7950 }
7951 CatchException(&(*image)->exception);
7952 XSetCursorState(display,windows,MagickFalse);
7953 if (windows->image.orphan != MagickFalse)
7954 break;
7955 XConfigureImageColormap(display,resource_info,windows,*image);
7956 (void) XConfigureImage(display,resource_info,windows,*image);
7957 break;
7958 }
7959 case QuantizeCommand:
7960 {
7961 int
7962 status;
7963
7964 static char
7965 colors[MaxTextExtent] = "256";
7966
7967 /*
7968 Query user for maximum number of colors.
7969 */
7970 status=XDialogWidget(display,windows,"Quantize",
7971 "Maximum number of colors:",colors);
7972 if (*colors == '\0')
7973 break;
7974 /*
7975 Color reduce the image.
7976 */
7977 XSetCursorState(display,windows,MagickTrue);
7978 XCheckRefreshWindows(display,windows);
7979 quantize_info.number_colors=StringToUnsignedLong(colors);
7980 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
7981 (void) QuantizeImage(&quantize_info,*image);
7982 XSetCursorState(display,windows,MagickFalse);
7983 if (windows->image.orphan != MagickFalse)
7984 break;
7985 XConfigureImageColormap(display,resource_info,windows,*image);
7986 (void) XConfigureImage(display,resource_info,windows,*image);
7987 break;
7988 }
7989 case DespeckleCommand:
7990 {
7991 Image
7992 *despeckle_image;
7993
7994 /*
7995 Despeckle image.
7996 */
7997 XSetCursorState(display,windows,MagickTrue);
7998 XCheckRefreshWindows(display,windows);
7999 despeckle_image=DespeckleImage(*image,&(*image)->exception);
8000 if (despeckle_image != (Image *) NULL)
8001 {
8002 *image=DestroyImage(*image);
8003 *image=despeckle_image;
8004 }
8005 CatchException(&(*image)->exception);
8006 XSetCursorState(display,windows,MagickFalse);
8007 if (windows->image.orphan != MagickFalse)
8008 break;
8009 XConfigureImageColormap(display,resource_info,windows,*image);
8010 (void) XConfigureImage(display,resource_info,windows,*image);
8011 break;
8012 }
8013 case EmbossCommand:
8014 {
8015 Image
8016 *emboss_image;
8017
8018 static char
8019 radius[MaxTextExtent] = "0.0x1.0";
8020
8021 /*
8022 Query user for emboss radius.
8023 */
8024 (void) XDialogWidget(display,windows,"Emboss",
8025 "Enter the emboss radius and standard deviation:",radius);
8026 if (*radius == '\0')
8027 break;
8028 /*
8029 Reduce noise in the image.
8030 */
8031 XSetCursorState(display,windows,MagickTrue);
8032 XCheckRefreshWindows(display,windows);
8033 flags=ParseGeometry(radius,&geometry_info);
8034 if ((flags & SigmaValue) == 0)
8035 geometry_info.sigma=1.0;
8036 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8037 &(*image)->exception);
8038 if (emboss_image != (Image *) NULL)
8039 {
8040 *image=DestroyImage(*image);
8041 *image=emboss_image;
8042 }
8043 CatchException(&(*image)->exception);
8044 XSetCursorState(display,windows,MagickFalse);
8045 if (windows->image.orphan != MagickFalse)
8046 break;
8047 XConfigureImageColormap(display,resource_info,windows,*image);
8048 (void) XConfigureImage(display,resource_info,windows,*image);
8049 break;
8050 }
8051 case ReduceNoiseCommand:
8052 {
8053 Image
8054 *noise_image;
8055
8056 static char
8057 radius[MaxTextExtent] = "0";
8058
8059 /*
8060 Query user for noise radius.
8061 */
8062 (void) XDialogWidget(display,windows,"Reduce Noise",
8063 "Enter the noise radius:",radius);
8064 if (*radius == '\0')
8065 break;
8066 /*
8067 Reduce noise in the image.
8068 */
8069 XSetCursorState(display,windows,MagickTrue);
8070 XCheckRefreshWindows(display,windows);
8071 flags=ParseGeometry(radius,&geometry_info);
8072 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8073 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
8074 if (noise_image != (Image *) NULL)
8075 {
8076 *image=DestroyImage(*image);
8077 *image=noise_image;
8078 }
8079 CatchException(&(*image)->exception);
8080 XSetCursorState(display,windows,MagickFalse);
8081 if (windows->image.orphan != MagickFalse)
8082 break;
8083 XConfigureImageColormap(display,resource_info,windows,*image);
8084 (void) XConfigureImage(display,resource_info,windows,*image);
8085 break;
8086 }
8087 case AddNoiseCommand:
8088 {
8089 char
8090 **noises;
8091
8092 Image
8093 *noise_image;
8094
8095 static char
8096 noise_type[MaxTextExtent] = "Gaussian";
8097
8098 /*
8099 Add noise to the image.
8100 */
8101 noises=GetCommandOptions(MagickNoiseOptions);
8102 if (noises == (char **) NULL)
8103 break;
8104 XListBrowserWidget(display,windows,&windows->widget,
8105 (const char **) noises,"Add Noise",
8106 "Select a type of noise to add to your image:",noise_type);
8107 noises=DestroyStringList(noises);
8108 if (*noise_type == '\0')
8109 break;
8110 XSetCursorState(display,windows,MagickTrue);
8111 XCheckRefreshWindows(display,windows);
8112 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8113 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
8114 if (noise_image != (Image *) NULL)
8115 {
8116 *image=DestroyImage(*image);
8117 *image=noise_image;
8118 }
8119 CatchException(&(*image)->exception);
8120 XSetCursorState(display,windows,MagickFalse);
8121 if (windows->image.orphan != MagickFalse)
8122 break;
8123 XConfigureImageColormap(display,resource_info,windows,*image);
8124 (void) XConfigureImage(display,resource_info,windows,*image);
8125 break;
8126 }
8127 case SharpenCommand:
8128 {
8129 Image
8130 *sharp_image;
8131
8132 static char
8133 radius[MaxTextExtent] = "0.0x1.0";
8134
8135 /*
8136 Query user for sharpen radius.
8137 */
8138 (void) XDialogWidget(display,windows,"Sharpen",
8139 "Enter the sharpen radius and standard deviation:",radius);
8140 if (*radius == '\0')
8141 break;
8142 /*
8143 Sharpen image scanlines.
8144 */
8145 XSetCursorState(display,windows,MagickTrue);
8146 XCheckRefreshWindows(display,windows);
8147 flags=ParseGeometry(radius,&geometry_info);
8148 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8149 &(*image)->exception);
8150 if (sharp_image != (Image *) NULL)
8151 {
8152 *image=DestroyImage(*image);
8153 *image=sharp_image;
8154 }
8155 CatchException(&(*image)->exception);
8156 XSetCursorState(display,windows,MagickFalse);
8157 if (windows->image.orphan != MagickFalse)
8158 break;
8159 XConfigureImageColormap(display,resource_info,windows,*image);
8160 (void) XConfigureImage(display,resource_info,windows,*image);
8161 break;
8162 }
8163 case BlurCommand:
8164 {
8165 Image
8166 *blur_image;
8167
8168 static char
8169 radius[MaxTextExtent] = "0.0x1.0";
8170
8171 /*
8172 Query user for blur radius.
8173 */
8174 (void) XDialogWidget(display,windows,"Blur",
8175 "Enter the blur radius and standard deviation:",radius);
8176 if (*radius == '\0')
8177 break;
8178 /*
8179 Blur an image.
8180 */
8181 XSetCursorState(display,windows,MagickTrue);
8182 XCheckRefreshWindows(display,windows);
8183 flags=ParseGeometry(radius,&geometry_info);
8184 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8185 &(*image)->exception);
8186 if (blur_image != (Image *) NULL)
8187 {
8188 *image=DestroyImage(*image);
8189 *image=blur_image;
8190 }
8191 CatchException(&(*image)->exception);
8192 XSetCursorState(display,windows,MagickFalse);
8193 if (windows->image.orphan != MagickFalse)
8194 break;
8195 XConfigureImageColormap(display,resource_info,windows,*image);
8196 (void) XConfigureImage(display,resource_info,windows,*image);
8197 break;
8198 }
8199 case ThresholdCommand:
8200 {
8201 double
8202 threshold;
8203
8204 static char
8205 factor[MaxTextExtent] = "128";
8206
8207 /*
8208 Query user for threshold value.
8209 */
8210 (void) XDialogWidget(display,windows,"Threshold",
8211 "Enter threshold value:",factor);
8212 if (*factor == '\0')
8213 break;
8214 /*
8215 Gamma correct image.
8216 */
8217 XSetCursorState(display,windows,MagickTrue);
8218 XCheckRefreshWindows(display,windows);
8219 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8220 (void) BilevelImage(*image,threshold);
8221 XSetCursorState(display,windows,MagickFalse);
8222 if (windows->image.orphan != MagickFalse)
8223 break;
8224 XConfigureImageColormap(display,resource_info,windows,*image);
8225 (void) XConfigureImage(display,resource_info,windows,*image);
8226 break;
8227 }
8228 case EdgeDetectCommand:
8229 {
8230 Image
8231 *edge_image;
8232
8233 static char
8234 radius[MaxTextExtent] = "0";
8235
8236 /*
8237 Query user for edge factor.
8238 */
8239 (void) XDialogWidget(display,windows,"Detect Edges",
8240 "Enter the edge detect radius:",radius);
8241 if (*radius == '\0')
8242 break;
8243 /*
8244 Detect edge in image.
8245 */
8246 XSetCursorState(display,windows,MagickTrue);
8247 XCheckRefreshWindows(display,windows);
8248 flags=ParseGeometry(radius,&geometry_info);
8249 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8250 if (edge_image != (Image *) NULL)
8251 {
8252 *image=DestroyImage(*image);
8253 *image=edge_image;
8254 }
8255 CatchException(&(*image)->exception);
8256 XSetCursorState(display,windows,MagickFalse);
8257 if (windows->image.orphan != MagickFalse)
8258 break;
8259 XConfigureImageColormap(display,resource_info,windows,*image);
8260 (void) XConfigureImage(display,resource_info,windows,*image);
8261 break;
8262 }
8263 case SpreadCommand:
8264 {
8265 Image
8266 *spread_image;
8267
8268 static char
8269 amount[MaxTextExtent] = "2";
8270
8271 /*
8272 Query user for spread amount.
8273 */
8274 (void) XDialogWidget(display,windows,"Spread",
8275 "Enter the displacement amount:",amount);
8276 if (*amount == '\0')
8277 break;
8278 /*
8279 Displace image pixels by a random amount.
8280 */
8281 XSetCursorState(display,windows,MagickTrue);
8282 XCheckRefreshWindows(display,windows);
8283 flags=ParseGeometry(amount,&geometry_info);
8284 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
8285 if (spread_image != (Image *) NULL)
8286 {
8287 *image=DestroyImage(*image);
8288 *image=spread_image;
8289 }
8290 CatchException(&(*image)->exception);
8291 XSetCursorState(display,windows,MagickFalse);
8292 if (windows->image.orphan != MagickFalse)
8293 break;
8294 XConfigureImageColormap(display,resource_info,windows,*image);
8295 (void) XConfigureImage(display,resource_info,windows,*image);
8296 break;
8297 }
8298 case ShadeCommand:
8299 {
8300 Image
8301 *shade_image;
8302
8303 int
8304 status;
8305
8306 static char
8307 geometry[MaxTextExtent] = "30x30";
8308
8309 /*
8310 Query user for the shade geometry.
8311 */
8312 status=XDialogWidget(display,windows,"Shade",
8313 "Enter the azimuth and elevation of the light source:",geometry);
8314 if (*geometry == '\0')
8315 break;
8316 /*
8317 Shade image pixels.
8318 */
8319 XSetCursorState(display,windows,MagickTrue);
8320 XCheckRefreshWindows(display,windows);
8321 flags=ParseGeometry(geometry,&geometry_info);
8322 if ((flags & SigmaValue) == 0)
8323 geometry_info.sigma=1.0;
8324 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
8325 geometry_info.rho,geometry_info.sigma,&(*image)->exception);
8326 if (shade_image != (Image *) NULL)
8327 {
8328 *image=DestroyImage(*image);
8329 *image=shade_image;
8330 }
8331 CatchException(&(*image)->exception);
8332 XSetCursorState(display,windows,MagickFalse);
8333 if (windows->image.orphan != MagickFalse)
8334 break;
8335 XConfigureImageColormap(display,resource_info,windows,*image);
8336 (void) XConfigureImage(display,resource_info,windows,*image);
8337 break;
8338 }
8339 case RaiseCommand:
8340 {
8341 static char
8342 bevel_width[MaxTextExtent] = "10";
8343
8344 /*
8345 Query user for bevel width.
8346 */
8347 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8348 if (*bevel_width == '\0')
8349 break;
8350 /*
8351 Raise an image.
8352 */
8353 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8354 XSetCursorState(display,windows,MagickTrue);
8355 XCheckRefreshWindows(display,windows);
8356 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8357 &(*image)->exception);
8358 (void) RaiseImage(*image,&page_geometry,MagickTrue);
8359 XSetCursorState(display,windows,MagickFalse);
8360 if (windows->image.orphan != MagickFalse)
8361 break;
8362 XConfigureImageColormap(display,resource_info,windows,*image);
8363 (void) XConfigureImage(display,resource_info,windows,*image);
8364 break;
8365 }
8366 case SegmentCommand:
8367 {
8368 static char
8369 threshold[MaxTextExtent] = "1.0x1.5";
8370
8371 /*
8372 Query user for smoothing threshold.
8373 */
8374 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8375 threshold);
8376 if (*threshold == '\0')
8377 break;
8378 /*
8379 Segment an image.
8380 */
8381 XSetCursorState(display,windows,MagickTrue);
8382 XCheckRefreshWindows(display,windows);
8383 flags=ParseGeometry(threshold,&geometry_info);
8384 if ((flags & SigmaValue) == 0)
8385 geometry_info.sigma=1.0;
8386 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8387 geometry_info.sigma);
8388 XSetCursorState(display,windows,MagickFalse);
8389 if (windows->image.orphan != MagickFalse)
8390 break;
8391 XConfigureImageColormap(display,resource_info,windows,*image);
8392 (void) XConfigureImage(display,resource_info,windows,*image);
8393 break;
8394 }
8395 case SepiaToneCommand:
8396 {
8397 double
8398 threshold;
8399
8400 Image
8401 *sepia_image;
8402
8403 static char
8404 factor[MaxTextExtent] = "80%";
8405
8406 /*
8407 Query user for sepia-tone factor.
8408 */
8409 (void) XDialogWidget(display,windows,"Sepia Tone",
8410 "Enter the sepia tone factor (0 - 99.9%):",factor);
8411 if (*factor == '\0')
8412 break;
8413 /*
8414 Sepia tone image pixels.
8415 */
8416 XSetCursorState(display,windows,MagickTrue);
8417 XCheckRefreshWindows(display,windows);
8418 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8419 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
8420 if (sepia_image != (Image *) NULL)
8421 {
8422 *image=DestroyImage(*image);
8423 *image=sepia_image;
8424 }
8425 CatchException(&(*image)->exception);
8426 XSetCursorState(display,windows,MagickFalse);
8427 if (windows->image.orphan != MagickFalse)
8428 break;
8429 XConfigureImageColormap(display,resource_info,windows,*image);
8430 (void) XConfigureImage(display,resource_info,windows,*image);
8431 break;
8432 }
8433 case SolarizeCommand:
8434 {
8435 double
8436 threshold;
8437
8438 static char
8439 factor[MaxTextExtent] = "60%";
8440
8441 /*
8442 Query user for solarize factor.
8443 */
8444 (void) XDialogWidget(display,windows,"Solarize",
8445 "Enter the solarize factor (0 - 99.9%):",factor);
8446 if (*factor == '\0')
8447 break;
8448 /*
8449 Solarize image pixels.
8450 */
8451 XSetCursorState(display,windows,MagickTrue);
8452 XCheckRefreshWindows(display,windows);
8453 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8454 (void) SolarizeImage(*image,threshold);
8455 XSetCursorState(display,windows,MagickFalse);
8456 if (windows->image.orphan != MagickFalse)
8457 break;
8458 XConfigureImageColormap(display,resource_info,windows,*image);
8459 (void) XConfigureImage(display,resource_info,windows,*image);
8460 break;
8461 }
8462 case SwirlCommand:
8463 {
8464 Image
8465 *swirl_image;
8466
8467 static char
8468 degrees[MaxTextExtent] = "60";
8469
8470 /*
8471 Query user for swirl angle.
8472 */
8473 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8474 degrees);
8475 if (*degrees == '\0')
8476 break;
8477 /*
8478 Swirl image pixels about the center.
8479 */
8480 XSetCursorState(display,windows,MagickTrue);
8481 XCheckRefreshWindows(display,windows);
8482 flags=ParseGeometry(degrees,&geometry_info);
8483 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
8484 if (swirl_image != (Image *) NULL)
8485 {
8486 *image=DestroyImage(*image);
8487 *image=swirl_image;
8488 }
8489 CatchException(&(*image)->exception);
8490 XSetCursorState(display,windows,MagickFalse);
8491 if (windows->image.orphan != MagickFalse)
8492 break;
8493 XConfigureImageColormap(display,resource_info,windows,*image);
8494 (void) XConfigureImage(display,resource_info,windows,*image);
8495 break;
8496 }
8497 case ImplodeCommand:
8498 {
8499 Image
8500 *implode_image;
8501
8502 static char
8503 factor[MaxTextExtent] = "0.3";
8504
8505 /*
8506 Query user for implode factor.
8507 */
8508 (void) XDialogWidget(display,windows,"Implode",
8509 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8510 if (*factor == '\0')
8511 break;
8512 /*
8513 Implode image pixels about the center.
8514 */
8515 XSetCursorState(display,windows,MagickTrue);
8516 XCheckRefreshWindows(display,windows);
8517 flags=ParseGeometry(factor,&geometry_info);
8518 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
8519 if (implode_image != (Image *) NULL)
8520 {
8521 *image=DestroyImage(*image);
8522 *image=implode_image;
8523 }
8524 CatchException(&(*image)->exception);
8525 XSetCursorState(display,windows,MagickFalse);
8526 if (windows->image.orphan != MagickFalse)
8527 break;
8528 XConfigureImageColormap(display,resource_info,windows,*image);
8529 (void) XConfigureImage(display,resource_info,windows,*image);
8530 break;
8531 }
8532 case VignetteCommand:
8533 {
8534 Image
8535 *vignette_image;
8536
8537 static char
8538 geometry[MaxTextExtent] = "0x20";
8539
8540 /*
8541 Query user for the vignette geometry.
8542 */
8543 (void) XDialogWidget(display,windows,"Vignette",
8544 "Enter the radius, sigma, and x and y offsets:",geometry);
8545 if (*geometry == '\0')
8546 break;
8547 /*
8548 Soften the edges of the image in vignette style
8549 */
8550 XSetCursorState(display,windows,MagickTrue);
8551 XCheckRefreshWindows(display,windows);
8552 flags=ParseGeometry(geometry,&geometry_info);
8553 if ((flags & SigmaValue) == 0)
8554 geometry_info.sigma=1.0;
8555 if ((flags & XiValue) == 0)
8556 geometry_info.xi=0.1*(*image)->columns;
8557 if ((flags & PsiValue) == 0)
8558 geometry_info.psi=0.1*(*image)->rows;
8559 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
8560 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
8561 0.5),&(*image)->exception);
8562 if (vignette_image != (Image *) NULL)
8563 {
8564 *image=DestroyImage(*image);
8565 *image=vignette_image;
8566 }
8567 CatchException(&(*image)->exception);
8568 XSetCursorState(display,windows,MagickFalse);
8569 if (windows->image.orphan != MagickFalse)
8570 break;
8571 XConfigureImageColormap(display,resource_info,windows,*image);
8572 (void) XConfigureImage(display,resource_info,windows,*image);
8573 break;
8574 }
8575 case WaveCommand:
8576 {
8577 Image
8578 *wave_image;
8579
8580 static char
8581 geometry[MaxTextExtent] = "25x150";
8582
8583 /*
8584 Query user for the wave geometry.
8585 */
8586 (void) XDialogWidget(display,windows,"Wave",
8587 "Enter the amplitude and length of the wave:",geometry);
8588 if (*geometry == '\0')
8589 break;
8590 /*
8591 Alter an image along a sine wave.
8592 */
8593 XSetCursorState(display,windows,MagickTrue);
8594 XCheckRefreshWindows(display,windows);
8595 flags=ParseGeometry(geometry,&geometry_info);
8596 if ((flags & SigmaValue) == 0)
8597 geometry_info.sigma=1.0;
8598 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8599 &(*image)->exception);
8600 if (wave_image != (Image *) NULL)
8601 {
8602 *image=DestroyImage(*image);
8603 *image=wave_image;
8604 }
8605 CatchException(&(*image)->exception);
8606 XSetCursorState(display,windows,MagickFalse);
8607 if (windows->image.orphan != MagickFalse)
8608 break;
8609 XConfigureImageColormap(display,resource_info,windows,*image);
8610 (void) XConfigureImage(display,resource_info,windows,*image);
8611 break;
8612 }
8613 case OilPaintCommand:
8614 {
8615 Image
8616 *paint_image;
8617
8618 static char
8619 radius[MaxTextExtent] = "0";
8620
8621 /*
8622 Query user for circular neighborhood radius.
8623 */
8624 (void) XDialogWidget(display,windows,"Oil Paint",
8625 "Enter the mask radius:",radius);
8626 if (*radius == '\0')
8627 break;
8628 /*
8629 OilPaint image scanlines.
8630 */
8631 XSetCursorState(display,windows,MagickTrue);
8632 XCheckRefreshWindows(display,windows);
8633 flags=ParseGeometry(radius,&geometry_info);
8634 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
8635 if (paint_image != (Image *) NULL)
8636 {
8637 *image=DestroyImage(*image);
8638 *image=paint_image;
8639 }
8640 CatchException(&(*image)->exception);
8641 XSetCursorState(display,windows,MagickFalse);
8642 if (windows->image.orphan != MagickFalse)
8643 break;
8644 XConfigureImageColormap(display,resource_info,windows,*image);
8645 (void) XConfigureImage(display,resource_info,windows,*image);
8646 break;
8647 }
8648 case CharcoalDrawCommand:
8649 {
8650 Image
8651 *charcoal_image;
8652
8653 static char
8654 radius[MaxTextExtent] = "0x1";
8655
8656 /*
8657 Query user for charcoal radius.
8658 */
8659 (void) XDialogWidget(display,windows,"Charcoal Draw",
8660 "Enter the charcoal radius and sigma:",radius);
8661 if (*radius == '\0')
8662 break;
8663 /*
8664 Charcoal the image.
8665 */
8666 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8667 XSetCursorState(display,windows,MagickTrue);
8668 XCheckRefreshWindows(display,windows);
8669 flags=ParseGeometry(radius,&geometry_info);
8670 if ((flags & SigmaValue) == 0)
8671 geometry_info.sigma=geometry_info.rho;
8672 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8673 &(*image)->exception);
8674 if (charcoal_image != (Image *) NULL)
8675 {
8676 *image=DestroyImage(*image);
8677 *image=charcoal_image;
8678 }
8679 CatchException(&(*image)->exception);
8680 XSetCursorState(display,windows,MagickFalse);
8681 if (windows->image.orphan != MagickFalse)
8682 break;
8683 XConfigureImageColormap(display,resource_info,windows,*image);
8684 (void) XConfigureImage(display,resource_info,windows,*image);
8685 break;
8686 }
8687 case AnnotateCommand:
8688 {
8689 /*
8690 Annotate the image with text.
8691 */
8692 status=XAnnotateEditImage(display,resource_info,windows,*image);
8693 if (status == MagickFalse)
8694 {
8695 XNoticeWidget(display,windows,"Unable to annotate X image",
8696 (*image)->filename);
8697 break;
8698 }
8699 break;
8700 }
8701 case DrawCommand:
8702 {
8703 /*
8704 Draw image.
8705 */
8706 status=XDrawEditImage(display,resource_info,windows,image);
8707 if (status == MagickFalse)
8708 {
8709 XNoticeWidget(display,windows,"Unable to draw on the X image",
8710 (*image)->filename);
8711 break;
8712 }
8713 break;
8714 }
8715 case ColorCommand:
8716 {
8717 /*
8718 Color edit.
8719 */
8720 status=XColorEditImage(display,resource_info,windows,image);
8721 if (status == MagickFalse)
8722 {
8723 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8724 (*image)->filename);
8725 break;
8726 }
8727 break;
8728 }
8729 case MatteCommand:
8730 {
8731 /*
8732 Matte edit.
8733 */
8734 status=XMatteEditImage(display,resource_info,windows,image);
8735 if (status == MagickFalse)
8736 {
8737 XNoticeWidget(display,windows,"Unable to matte edit X image",
8738 (*image)->filename);
8739 break;
8740 }
8741 break;
8742 }
8743 case CompositeCommand:
8744 {
8745 /*
8746 Composite image.
8747 */
8748 status=XCompositeImage(display,resource_info,windows,*image);
8749 if (status == MagickFalse)
8750 {
8751 XNoticeWidget(display,windows,"Unable to composite X image",
8752 (*image)->filename);
8753 break;
8754 }
8755 break;
8756 }
8757 case AddBorderCommand:
8758 {
8759 Image
8760 *border_image;
8761
8762 static char
8763 geometry[MaxTextExtent] = "6x6";
8764
8765 /*
8766 Query user for border color and geometry.
8767 */
8768 XColorBrowserWidget(display,windows,"Select",color);
8769 if (*color == '\0')
8770 break;
8771 (void) XDialogWidget(display,windows,"Add Border",
8772 "Enter border geometry:",geometry);
8773 if (*geometry == '\0')
8774 break;
8775 /*
8776 Add a border to the image.
8777 */
8778 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8779 XSetCursorState(display,windows,MagickTrue);
8780 XCheckRefreshWindows(display,windows);
8781 (void) QueryColorDatabase(color,&(*image)->border_color,
8782 &(*image)->exception);
8783 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8784 &(*image)->exception);
8785 border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
8786 if (border_image != (Image *) NULL)
8787 {
8788 *image=DestroyImage(*image);
8789 *image=border_image;
8790 }
8791 CatchException(&(*image)->exception);
8792 XSetCursorState(display,windows,MagickFalse);
8793 if (windows->image.orphan != MagickFalse)
8794 break;
8795 windows->image.window_changes.width=(int) (*image)->columns;
8796 windows->image.window_changes.height=(int) (*image)->rows;
8797 XConfigureImageColormap(display,resource_info,windows,*image);
8798 (void) XConfigureImage(display,resource_info,windows,*image);
8799 break;
8800 }
8801 case AddFrameCommand:
8802 {
8803 FrameInfo
8804 frame_info;
8805
8806 Image
8807 *frame_image;
8808
8809 static char
8810 geometry[MaxTextExtent] = "6x6";
8811
8812 /*
8813 Query user for frame color and geometry.
8814 */
8815 XColorBrowserWidget(display,windows,"Select",color);
8816 if (*color == '\0')
8817 break;
8818 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8819 geometry);
8820 if (*geometry == '\0')
8821 break;
8822 /*
8823 Surround image with an ornamental border.
8824 */
8825 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
8826 XSetCursorState(display,windows,MagickTrue);
8827 XCheckRefreshWindows(display,windows);
8828 (void) QueryColorDatabase(color,&(*image)->matte_color,
8829 &(*image)->exception);
8830 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8831 &(*image)->exception);
8832 frame_info.width=page_geometry.width;
8833 frame_info.height=page_geometry.height;
8834 frame_info.outer_bevel=page_geometry.x;
8835 frame_info.inner_bevel=page_geometry.y;
8836 frame_info.x=(ssize_t) frame_info.width;
8837 frame_info.y=(ssize_t) frame_info.height;
8838 frame_info.width=(*image)->columns+2*frame_info.width;
8839 frame_info.height=(*image)->rows+2*frame_info.height;
8840 frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
8841 if (frame_image != (Image *) NULL)
8842 {
8843 *image=DestroyImage(*image);
8844 *image=frame_image;
8845 }
8846 CatchException(&(*image)->exception);
8847 XSetCursorState(display,windows,MagickFalse);
8848 if (windows->image.orphan != MagickFalse)
8849 break;
8850 windows->image.window_changes.width=(int) (*image)->columns;
8851 windows->image.window_changes.height=(int) (*image)->rows;
8852 XConfigureImageColormap(display,resource_info,windows,*image);
8853 (void) XConfigureImage(display,resource_info,windows,*image);
8854 break;
8855 }
8856 case CommentCommand:
8857 {
8858 const char
8859 *value;
8860
8861 FILE
8862 *file;
8863
8864 int
8865 unique_file;
8866
8867 /*
8868 Edit image comment.
8869 */
8870 unique_file=AcquireUniqueFileResource(image_info->filename);
8871 if (unique_file == -1)
8872 {
8873 XNoticeWidget(display,windows,"Unable to edit image comment",
8874 image_info->filename);
8875 break;
8876 }
8877 value=GetImageProperty(*image,"comment");
8878 if (value == (char *) NULL)
8879 unique_file=close_utf8(unique_file)-1;
8880 else
8881 {
8882 const char
8883 *p;
8884
8885 file=fdopen(unique_file,"w");
8886 if (file == (FILE *) NULL)
8887 {
8888 XNoticeWidget(display,windows,"Unable to edit image comment",
8889 image_info->filename);
8890 break;
8891 }
8892 for (p=value; *p != '\0'; p++)
8893 (void) fputc((int) *p,file);
8894 (void) fputc('\n',file);
8895 (void) fclose(file);
8896 }
8897 XSetCursorState(display,windows,MagickTrue);
8898 XCheckRefreshWindows(display,windows);
8899 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8900 &(*image)->exception);
8901 if (status == MagickFalse)
8902 XNoticeWidget(display,windows,"Unable to edit image comment",
8903 (char *) NULL);
8904 else
8905 {
8906 char
8907 *comment;
8908
8909 comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
8910 if (comment != (char *) NULL)
8911 {
8912 (void) SetImageProperty(*image,"comment",comment);
8913 (*image)->taint=MagickTrue;
8914 }
8915 }
8916 (void) RelinquishUniqueFileResource(image_info->filename);
8917 XSetCursorState(display,windows,MagickFalse);
8918 break;
8919 }
8920 case LaunchCommand:
8921 {
8922 /*
8923 Launch program.
8924 */
8925 XSetCursorState(display,windows,MagickTrue);
8926 XCheckRefreshWindows(display,windows);
8927 (void) AcquireUniqueFilename(filename);
8928 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
8929 filename);
8930 status=WriteImage(image_info,*image);
8931 if (status == MagickFalse)
8932 XNoticeWidget(display,windows,"Unable to launch image editor",
8933 (char *) NULL);
8934 else
8935 {
8936 nexus=ReadImage(resource_info->image_info,&(*image)->exception);
8937 CatchException(&(*image)->exception);
8938 XClientMessage(display,windows->image.id,windows->im_protocols,
8939 windows->im_next_image,CurrentTime);
8940 }
8941 (void) RelinquishUniqueFileResource(filename);
8942 XSetCursorState(display,windows,MagickFalse);
8943 break;
8944 }
8945 case RegionOfInterestCommand:
8946 {
8947 /*
8948 Apply an image processing technique to a region of interest.
8949 */
8950 (void) XROIImage(display,resource_info,windows,image);
8951 break;
8952 }
8953 case InfoCommand:
8954 break;
8955 case ZoomCommand:
8956 {
8957 /*
8958 Zoom image.
8959 */
8960 if (windows->magnify.mapped != MagickFalse)
8961 (void) XRaiseWindow(display,windows->magnify.id);
8962 else
8963 {
8964 /*
8965 Make magnify image.
8966 */
8967 XSetCursorState(display,windows,MagickTrue);
8968 (void) XMapRaised(display,windows->magnify.id);
8969 XSetCursorState(display,windows,MagickFalse);
8970 }
8971 break;
8972 }
8973 case ShowPreviewCommand:
8974 {
8975 char
8976 **previews;
8977
8978 Image
8979 *preview_image;
8980
8981 static char
8982 preview_type[MaxTextExtent] = "Gamma";
8983
8984 /*
8985 Select preview type from menu.
8986 */
8987 previews=GetCommandOptions(MagickPreviewOptions);
8988 if (previews == (char **) NULL)
8989 break;
8990 XListBrowserWidget(display,windows,&windows->widget,
8991 (const char **) previews,"Preview",
8992 "Select an enhancement, effect, or F/X:",preview_type);
8993 previews=DestroyStringList(previews);
8994 if (*preview_type == '\0')
8995 break;
8996 /*
8997 Show image preview.
8998 */
8999 XSetCursorState(display,windows,MagickTrue);
9000 XCheckRefreshWindows(display,windows);
9001 image_info->preview_type=(PreviewType)
9002 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
9003 image_info->group=(ssize_t) windows->image.id;
9004 (void) DeleteImageProperty(*image,"label");
9005 (void) SetImageProperty(*image,"label","Preview");
9006 (void) AcquireUniqueFilename(filename);
9007 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
9008 filename);
9009 status=WriteImage(image_info,*image);
9010 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9011 preview_image=ReadImage(image_info,&(*image)->exception);
9012 (void) RelinquishUniqueFileResource(filename);
9013 if (preview_image == (Image *) NULL)
9014 break;
9015 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
9016 filename);
9017 status=WriteImage(image_info,preview_image);
9018 preview_image=DestroyImage(preview_image);
9019 if (status == MagickFalse)
9020 XNoticeWidget(display,windows,"Unable to show image preview",
9021 (*image)->filename);
9022 XDelay(display,1500);
9023 XSetCursorState(display,windows,MagickFalse);
9024 break;
9025 }
9026 case ShowHistogramCommand:
9027 {
9028 Image
9029 *histogram_image;
9030
9031 /*
9032 Show image histogram.
9033 */
9034 XSetCursorState(display,windows,MagickTrue);
9035 XCheckRefreshWindows(display,windows);
9036 image_info->group=(ssize_t) windows->image.id;
9037 (void) DeleteImageProperty(*image,"label");
9038 (void) SetImageProperty(*image,"label","Histogram");
9039 (void) AcquireUniqueFilename(filename);
9040 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
9041 filename);
9042 status=WriteImage(image_info,*image);
9043 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9044 histogram_image=ReadImage(image_info,&(*image)->exception);
9045 (void) RelinquishUniqueFileResource(filename);
9046 if (histogram_image == (Image *) NULL)
9047 break;
9048 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
9049 "show:%s",filename);
9050 status=WriteImage(image_info,histogram_image);
9051 histogram_image=DestroyImage(histogram_image);
9052 if (status == MagickFalse)
9053 XNoticeWidget(display,windows,"Unable to show histogram",
9054 (*image)->filename);
9055 XDelay(display,1500);
9056 XSetCursorState(display,windows,MagickFalse);
9057 break;
9058 }
9059 case ShowMatteCommand:
9060 {
9061 Image
9062 *matte_image;
9063
9064 if ((*image)->matte == MagickFalse)
9065 {
9066 XNoticeWidget(display,windows,
9067 "Image does not have any matte information",(*image)->filename);
9068 break;
9069 }
9070 /*
9071 Show image matte.
9072 */
9073 XSetCursorState(display,windows,MagickTrue);
9074 XCheckRefreshWindows(display,windows);
9075 image_info->group=(ssize_t) windows->image.id;
9076 (void) DeleteImageProperty(*image,"label");
9077 (void) SetImageProperty(*image,"label","Matte");
9078 (void) AcquireUniqueFilename(filename);
9079 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
9080 filename);
9081 status=WriteImage(image_info,*image);
9082 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
9083 matte_image=ReadImage(image_info,&(*image)->exception);
9084 (void) RelinquishUniqueFileResource(filename);
9085 if (matte_image == (Image *) NULL)
9086 break;
9087 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
9088 filename);
9089 status=WriteImage(image_info,matte_image);
9090 matte_image=DestroyImage(matte_image);
9091 if (status == MagickFalse)
9092 XNoticeWidget(display,windows,"Unable to show matte",
9093 (*image)->filename);
9094 XDelay(display,1500);
9095 XSetCursorState(display,windows,MagickFalse);
9096 break;
9097 }
9098 case BackgroundCommand:
9099 {
9100 /*
9101 Background image.
9102 */
9103 status=XBackgroundImage(display,resource_info,windows,image);
9104 if (status == MagickFalse)
9105 break;
9106 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9107 if (nexus != (Image *) NULL)
9108 XClientMessage(display,windows->image.id,windows->im_protocols,
9109 windows->im_next_image,CurrentTime);
9110 break;
9111 }
9112 case SlideShowCommand:
9113 {
9114 static char
9115 delay[MaxTextExtent] = "5";
9116
9117 /*
9118 Display next image after pausing.
9119 */
9120 (void) XDialogWidget(display,windows,"Slide Show",
9121 "Pause how many 1/100ths of a second between images:",delay);
9122 if (*delay == '\0')
9123 break;
9124 resource_info->delay=StringToUnsignedLong(delay);
9125 XClientMessage(display,windows->image.id,windows->im_protocols,
9126 windows->im_next_image,CurrentTime);
9127 break;
9128 }
9129 case PreferencesCommand:
9130 {
9131 /*
9132 Set user preferences.
9133 */
9134 status=XPreferencesWidget(display,resource_info,windows);
9135 if (status == MagickFalse)
9136 break;
9137 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
9138 if (nexus != (Image *) NULL)
9139 XClientMessage(display,windows->image.id,windows->im_protocols,
9140 windows->im_next_image,CurrentTime);
9141 break;
9142 }
9143 case HelpCommand:
9144 {
9145 /*
9146 User requested help.
9147 */
9148 XTextViewHelp(display,resource_info,windows,MagickFalse,
9149 "Help Viewer - Display",DisplayHelp);
9150 break;
9151 }
9152 case BrowseDocumentationCommand:
9153 {
9154 Atom
9155 mozilla_atom;
9156
9157 Window
9158 mozilla_window,
9159 root_window;
9160
9161 /*
9162 Browse the ImageMagick documentation.
9163 */
9164 root_window=XRootWindow(display,XDefaultScreen(display));
9165 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9166 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9167 if (mozilla_window != (Window) NULL)
9168 {
9169 char
9170 command[MaxTextExtent];
9171
9172 /*
9173 Display documentation using Netscape remote control.
9174 */
9175 (void) FormatLocaleString(command,MaxTextExtent,
9176 "openurl(%s,new-tab)",MagickAuthoritativeURL);
9177 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9178 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9179 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9180 XSetCursorState(display,windows,MagickFalse);
9181 break;
9182 }
9183 XSetCursorState(display,windows,MagickTrue);
9184 XCheckRefreshWindows(display,windows);
9185 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9186 &(*image)->exception);
9187 if (status == MagickFalse)
9188 XNoticeWidget(display,windows,"Unable to browse documentation",
9189 (char *) NULL);
9190 XDelay(display,1500);
9191 XSetCursorState(display,windows,MagickFalse);
9192 break;
9193 }
9194 case VersionCommand:
9195 {
9196 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9197 GetMagickCopyright());
9198 break;
9199 }
9200 case SaveToUndoBufferCommand:
9201 break;
9202 default:
9203 {
9204 (void) XBell(display,0);
9205 break;
9206 }
9207 }
9208 image_info=DestroyImageInfo(image_info);
9209 return(nexus);
9210}
9211
9212/*
9213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9214% %
9215% %
9216% %
9217+ X M a g n i f y I m a g e %
9218% %
9219% %
9220% %
9221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9222%
9223% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9224% The magnified portion is displayed in a separate window.
9225%
9226% The format of the XMagnifyImage method is:
9227%
9228% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9229%
9230% A description of each parameter follows:
9231%
9232% o display: Specifies a connection to an X server; returned from
9233% XOpenDisplay.
9234%
9235% o windows: Specifies a pointer to a XWindows structure.
9236%
9237% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9238% the entire image is refreshed.
9239%
9240*/
9241static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
9242{
9243 char
9244 text[MaxTextExtent];
9245
9246 int
9247 x,
9248 y;
9249
9250 size_t
9251 state;
9252
9253 /*
9254 Update magnified image until the mouse button is released.
9255 */
9256 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9257 state=DefaultState;
9258 x=event->xbutton.x;
9259 y=event->xbutton.y;
9260 windows->magnify.x=(int) windows->image.x+x;
9261 windows->magnify.y=(int) windows->image.y+y;
9262 do
9263 {
9264 /*
9265 Map and unmap Info widget as text cursor crosses its boundaries.
9266 */
9267 if (windows->info.mapped != MagickFalse)
9268 {
9269 if ((x < (int) (windows->info.x+windows->info.width)) &&
9270 (y < (int) (windows->info.y+windows->info.height)))
9271 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9272 }
9273 else
9274 if ((x > (int) (windows->info.x+windows->info.width)) ||
9275 (y > (int) (windows->info.y+windows->info.height)))
9276 (void) XMapWindow(display,windows->info.id);
9277 if (windows->info.mapped != MagickFalse)
9278 {
9279 /*
9280 Display pointer position.
9281 */
9282 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9283 windows->magnify.x,windows->magnify.y);
9284 XInfoWidget(display,windows,text);
9285 }
9286 /*
9287 Wait for next event.
9288 */
9289 XScreenEvent(display,windows,event);
9290 switch (event->type)
9291 {
9292 case ButtonPress:
9293 break;
9294 case ButtonRelease:
9295 {
9296 /*
9297 User has finished magnifying image.
9298 */
9299 x=event->xbutton.x;
9300 y=event->xbutton.y;
9301 state|=ExitState;
9302 break;
9303 }
9304 case Expose:
9305 break;
9306 case MotionNotify:
9307 {
9308 x=event->xmotion.x;
9309 y=event->xmotion.y;
9310 break;
9311 }
9312 default:
9313 break;
9314 }
9315 /*
9316 Check boundary conditions.
9317 */
9318 if (x < 0)
9319 x=0;
9320 else
9321 if (x >= (int) windows->image.width)
9322 x=(int) windows->image.width-1;
9323 if (y < 0)
9324 y=0;
9325 else
9326 if (y >= (int) windows->image.height)
9327 y=(int) windows->image.height-1;
9328 } while ((state & ExitState) == 0);
9329 /*
9330 Display magnified image.
9331 */
9332 XSetCursorState(display,windows,MagickFalse);
9333}
9334
9335/*
9336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9337% %
9338% %
9339% %
9340+ X M a g n i f y W i n d o w C o m m a n d %
9341% %
9342% %
9343% %
9344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9345%
9346% XMagnifyWindowCommand() moves the image within an Magnify window by one
9347% pixel as specified by the key symbol.
9348%
9349% The format of the XMagnifyWindowCommand method is:
9350%
9351% void XMagnifyWindowCommand(Display *display,XWindows *windows,
9352% const MagickStatusType state,const KeySym key_symbol)
9353%
9354% A description of each parameter follows:
9355%
9356% o display: Specifies a connection to an X server; returned from
9357% XOpenDisplay.
9358%
9359% o windows: Specifies a pointer to a XWindows structure.
9360%
9361% o state: key mask.
9362%
9363% o key_symbol: Specifies a KeySym which indicates which side of the image
9364% to trim.
9365%
9366*/
9367static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9368 const MagickStatusType state,const KeySym key_symbol)
9369{
9370 unsigned int
9371 quantum;
9372
9373 /*
9374 User specified a magnify factor or position.
9375 */
9376 quantum=1;
9377 if ((state & Mod1Mask) != 0)
9378 quantum=10;
9379 switch ((int) key_symbol)
9380 {
9381 case QuitCommand:
9382 {
9383 (void) XWithdrawWindow(display,windows->magnify.id,
9384 windows->magnify.screen);
9385 break;
9386 }
9387 case XK_Home:
9388 case XK_KP_Home:
9389 {
9390 windows->magnify.x=(int) windows->image.width/2;
9391 windows->magnify.y=(int) windows->image.height/2;
9392 break;
9393 }
9394 case XK_Left:
9395 case XK_KP_Left:
9396 {
9397 if (windows->magnify.x > 0)
9398 windows->magnify.x-=quantum;
9399 break;
9400 }
9401 case XK_Up:
9402 case XK_KP_Up:
9403 {
9404 if (windows->magnify.y > 0)
9405 windows->magnify.y-=quantum;
9406 break;
9407 }
9408 case XK_Right:
9409 case XK_KP_Right:
9410 {
9411 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9412 windows->magnify.x+=quantum;
9413 break;
9414 }
9415 case XK_Down:
9416 case XK_KP_Down:
9417 {
9418 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9419 windows->magnify.y+=quantum;
9420 break;
9421 }
9422 case XK_0:
9423 case XK_1:
9424 case XK_2:
9425 case XK_3:
9426 case XK_4:
9427 case XK_5:
9428 case XK_6:
9429 case XK_7:
9430 case XK_8:
9431 case XK_9:
9432 {
9433 windows->magnify.data=(key_symbol-XK_0);
9434 break;
9435 }
9436 case XK_KP_0:
9437 case XK_KP_1:
9438 case XK_KP_2:
9439 case XK_KP_3:
9440 case XK_KP_4:
9441 case XK_KP_5:
9442 case XK_KP_6:
9443 case XK_KP_7:
9444 case XK_KP_8:
9445 case XK_KP_9:
9446 {
9447 windows->magnify.data=(key_symbol-XK_KP_0);
9448 break;
9449 }
9450 default:
9451 break;
9452 }
9453 XMakeMagnifyImage(display,windows);
9454}
9455
9456/*
9457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9458% %
9459% %
9460% %
9461+ X M a k e P a n I m a g e %
9462% %
9463% %
9464% %
9465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9466%
9467% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9468% icon window.
9469%
9470% The format of the XMakePanImage method is:
9471%
9472% void XMakePanImage(Display *display,XResourceInfo *resource_info,
9473% XWindows *windows,Image *image)
9474%
9475% A description of each parameter follows:
9476%
9477% o display: Specifies a connection to an X server; returned from
9478% XOpenDisplay.
9479%
9480% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9481%
9482% o windows: Specifies a pointer to a XWindows structure.
9483%
9484% o image: the image.
9485%
9486*/
9487static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9488 XWindows *windows,Image *image)
9489{
9490 MagickStatusType
9491 status;
9492
9493 /*
9494 Create and display image for panning icon.
9495 */
9496 XSetCursorState(display,windows,MagickTrue);
9497 XCheckRefreshWindows(display,windows);
9498 windows->pan.x=(int) windows->image.x;
9499 windows->pan.y=(int) windows->image.y;
9500 status=XMakeImage(display,resource_info,&windows->pan,image,
9501 windows->pan.width,windows->pan.height);
9502 if (status == MagickFalse)
9503 ThrowXWindowFatalException(XServerFatalError,image->exception.reason,
9504 image->exception.description);
9505 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9506 windows->pan.pixmap);
9507 (void) XClearWindow(display,windows->pan.id);
9508 XDrawPanRectangle(display,windows);
9509 XSetCursorState(display,windows,MagickFalse);
9510}
9511
9512/*
9513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9514% %
9515% %
9516% %
9517+ X M a t t a E d i t I m a g e %
9518% %
9519% %
9520% %
9521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9522%
9523% XMatteEditImage() allows the user to interactively change the Matte channel
9524% of an image. If the image is PseudoClass it is promoted to DirectClass
9525% before the matte information is stored.
9526%
9527% The format of the XMatteEditImage method is:
9528%
9529% MagickBooleanType XMatteEditImage(Display *display,
9530% XResourceInfo *resource_info,XWindows *windows,Image **image)
9531%
9532% A description of each parameter follows:
9533%
9534% o display: Specifies a connection to an X server; returned from
9535% XOpenDisplay.
9536%
9537% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9538%
9539% o windows: Specifies a pointer to a XWindows structure.
9540%
9541% o image: the image; returned from ReadImage.
9542%
9543*/
9544static MagickBooleanType XMatteEditImage(Display *display,
9545 XResourceInfo *resource_info,XWindows *windows,Image **image)
9546{
9547 const char
9548 *const MatteEditMenu[] =
9549 {
9550 "Method",
9551 "Border Color",
9552 "Fuzz",
9553 "Matte Value",
9554 "Undo",
9555 "Help",
9556 "Dismiss",
9557 (char *) NULL
9558 };
9559
9560 static char
9561 matte[MaxTextExtent] = "0";
9562
9563 static const ModeType
9564 MatteEditCommands[] =
9565 {
9566 MatteEditMethod,
9567 MatteEditBorderCommand,
9568 MatteEditFuzzCommand,
9569 MatteEditValueCommand,
9570 MatteEditUndoCommand,
9571 MatteEditHelpCommand,
9572 MatteEditDismissCommand
9573 };
9574
9575 static PaintMethod
9576 method = PointMethod;
9577
9578 static XColor
9579 border_color = { 0, 0, 0, 0, 0, 0 };
9580
9581 char
9582 command[MaxTextExtent],
9583 text[MaxTextExtent] = "";
9584
9585 Cursor
9586 cursor;
9587
9588 int
9589 entry,
9590 id,
9591 x,
9592 x_offset,
9593 y,
9594 y_offset;
9595
9596 int
9597 i;
9598
9599 PixelPacket
9600 *q;
9601
9602 unsigned int
9603 height,
9604 width;
9605
9606 size_t
9607 state;
9608
9609 XEvent
9610 event;
9611
9612 /*
9613 Map Command widget.
9614 */
9615 (void) CloneString(&windows->command.name,"Matte Edit");
9616 windows->command.data=4;
9617 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9618 (void) XMapRaised(display,windows->command.id);
9619 XClientMessage(display,windows->image.id,windows->im_protocols,
9620 windows->im_update_widget,CurrentTime);
9621 /*
9622 Make cursor.
9623 */
9624 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9625 resource_info->background_color,resource_info->foreground_color);
9626 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9627 /*
9628 Track pointer until button 1 is pressed.
9629 */
9630 XQueryPosition(display,windows->image.id,&x,&y);
9631 (void) XSelectInput(display,windows->image.id,
9632 windows->image.attributes.event_mask | PointerMotionMask);
9633 state=DefaultState;
9634 do
9635 {
9636 if (windows->info.mapped != MagickFalse)
9637 {
9638 /*
9639 Display pointer position.
9640 */
9641 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
9642 x+windows->image.x,y+windows->image.y);
9643 XInfoWidget(display,windows,text);
9644 }
9645 /*
9646 Wait for next event.
9647 */
9648 XScreenEvent(display,windows,&event);
9649 if (event.xany.window == windows->command.id)
9650 {
9651 /*
9652 Select a command from the Command widget.
9653 */
9654 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9655 if (id < 0)
9656 {
9657 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9658 continue;
9659 }
9660 switch (MatteEditCommands[id])
9661 {
9662 case MatteEditMethod:
9663 {
9664 char
9665 **methods;
9666
9667 /*
9668 Select a method from the pop-up menu.
9669 */
9670 methods=GetCommandOptions(MagickMethodOptions);
9671 if (methods == (char **) NULL)
9672 break;
9673 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9674 (const char **) methods,command);
9675 if (entry >= 0)
9676 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9677 MagickFalse,methods[entry]);
9678 methods=DestroyStringList(methods);
9679 break;
9680 }
9681 case MatteEditBorderCommand:
9682 {
9683 const char
9684 *ColorMenu[MaxNumberPens];
9685
9686 int
9687 pen_number;
9688
9689 /*
9690 Initialize menu selections.
9691 */
9692 for (i=0; i < (int) (MaxNumberPens-2); i++)
9693 ColorMenu[i]=resource_info->pen_colors[i];
9694 ColorMenu[MaxNumberPens-2]="Browser...";
9695 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9696 /*
9697 Select a pen color from the pop-up menu.
9698 */
9699 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9700 (const char **) ColorMenu,command);
9701 if (pen_number < 0)
9702 break;
9703 if (pen_number == (MaxNumberPens-2))
9704 {
9705 static char
9706 color_name[MaxTextExtent] = "gray";
9707
9708 /*
9709 Select a pen color from a dialog.
9710 */
9711 resource_info->pen_colors[pen_number]=color_name;
9712 XColorBrowserWidget(display,windows,"Select",color_name);
9713 if (*color_name == '\0')
9714 break;
9715 }
9716 /*
9717 Set border color.
9718 */
9719 (void) XParseColor(display,windows->map_info->colormap,
9720 resource_info->pen_colors[pen_number],&border_color);
9721 break;
9722 }
9723 case MatteEditFuzzCommand:
9724 {
9725 const char
9726 *const FuzzMenu[] =
9727 {
9728 "0%",
9729 "2%",
9730 "5%",
9731 "10%",
9732 "15%",
9733 "Dialog...",
9734 (char *) NULL,
9735 };
9736
9737 static char
9738 fuzz[MaxTextExtent];
9739
9740 /*
9741 Select a command from the pop-up menu.
9742 */
9743 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9744 command);
9745 if (entry < 0)
9746 break;
9747 if (entry != 5)
9748 {
9749 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9750 QuantumRange+1.0);
9751 break;
9752 }
9753 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9754 (void) XDialogWidget(display,windows,"Ok",
9755 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9756 if (*fuzz == '\0')
9757 break;
9758 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
9759 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9760 1.0);
9761 break;
9762 }
9763 case MatteEditValueCommand:
9764 {
9765 const char
9766 *const MatteMenu[] =
9767 {
9768 "Opaque",
9769 "Transparent",
9770 "Dialog...",
9771 (char *) NULL,
9772 };
9773
9774 static char
9775 message[MaxTextExtent];
9776
9777 /*
9778 Select a command from the pop-up menu.
9779 */
9780 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9781 command);
9782 if (entry < 0)
9783 break;
9784 if (entry != 2)
9785 {
9786 (void) FormatLocaleString(matte,MaxTextExtent,"%g",
9787 (double) OpaqueOpacity);
9788 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9789 (void) FormatLocaleString(matte,MaxTextExtent,"%g",
9790 (double) TransparentOpacity);
9791 break;
9792 }
9793 (void) FormatLocaleString(message,MaxTextExtent,
9794 "Enter matte value (0 - " "%g" "):",(double) QuantumRange);
9795 (void) XDialogWidget(display,windows,"Matte",message,matte);
9796 if (*matte == '\0')
9797 break;
9798 break;
9799 }
9800 case MatteEditUndoCommand:
9801 {
9802 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9803 image);
9804 break;
9805 }
9806 case MatteEditHelpCommand:
9807 {
9808 XTextViewHelp(display,resource_info,windows,MagickFalse,
9809 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9810 break;
9811 }
9812 case MatteEditDismissCommand:
9813 {
9814 /*
9815 Prematurely exit.
9816 */
9817 state|=EscapeState;
9818 state|=ExitState;
9819 break;
9820 }
9821 default:
9822 break;
9823 }
9824 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9825 continue;
9826 }
9827 switch (event.type)
9828 {
9829 case ButtonPress:
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 matte data.
9838 */
9839 x=event.xbutton.x;
9840 y=event.xbutton.y;
9841 (void) XMagickCommand(display,resource_info,windows,
9842 SaveToUndoBufferCommand,image);
9843 state|=UpdateConfigurationState;
9844 break;
9845 }
9846 case ButtonRelease:
9847 {
9848 if (event.xbutton.button != Button1)
9849 break;
9850 if ((event.xbutton.window != windows->image.id) &&
9851 (event.xbutton.window != windows->magnify.id))
9852 break;
9853 /*
9854 Update colormap information.
9855 */
9856 x=event.xbutton.x;
9857 y=event.xbutton.y;
9858 XConfigureImageColormap(display,resource_info,windows,*image);
9859 (void) XConfigureImage(display,resource_info,windows,*image);
9860 XInfoWidget(display,windows,text);
9861 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9862 state&=(~UpdateConfigurationState);
9863 break;
9864 }
9865 case Expose:
9866 break;
9867 case KeyPress:
9868 {
9869 char
9870 command[MaxTextExtent];
9871
9872 KeySym
9873 key_symbol;
9874
9875 if (event.xkey.window == windows->magnify.id)
9876 {
9877 Window
9878 window;
9879
9880 window=windows->magnify.id;
9881 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9882 }
9883 if (event.xkey.window != windows->image.id)
9884 break;
9885 /*
9886 Respond to a user key press.
9887 */
9888 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9889 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9890 switch ((int) key_symbol)
9891 {
9892 case XK_Escape:
9893 case XK_F20:
9894 {
9895 /*
9896 Prematurely exit.
9897 */
9898 state|=ExitState;
9899 break;
9900 }
9901 case XK_F1:
9902 case XK_Help:
9903 {
9904 XTextViewHelp(display,resource_info,windows,MagickFalse,
9905 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9906 break;
9907 }
9908 default:
9909 {
9910 (void) XBell(display,0);
9911 break;
9912 }
9913 }
9914 break;
9915 }
9916 case MotionNotify:
9917 {
9918 /*
9919 Map and unmap Info widget as cursor crosses its boundaries.
9920 */
9921 x=event.xmotion.x;
9922 y=event.xmotion.y;
9923 if (windows->info.mapped != MagickFalse)
9924 {
9925 if ((x < (int) (windows->info.x+windows->info.width)) &&
9926 (y < (int) (windows->info.y+windows->info.height)))
9927 (void) XWithdrawWindow(display,windows->info.id,
9928 windows->info.screen);
9929 }
9930 else
9931 if ((x > (int) (windows->info.x+windows->info.width)) ||
9932 (y > (int) (windows->info.y+windows->info.height)))
9933 (void) XMapWindow(display,windows->info.id);
9934 break;
9935 }
9936 default:
9937 break;
9938 }
9939 if (event.xany.window == windows->magnify.id)
9940 {
9941 x=windows->magnify.x-windows->image.x;
9942 y=windows->magnify.y-windows->image.y;
9943 }
9944 x_offset=x;
9945 y_offset=y;
9946 if ((state & UpdateConfigurationState) != 0)
9947 {
9948 CacheView
9949 *image_view;
9950
9951 ExceptionInfo
9952 *exception;
9953
9954 int
9955 x,
9956 y;
9957
9958 /*
9959 Matte edit is relative to image configuration.
9960 */
9961 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
9962 MagickTrue);
9963 XPutPixel(windows->image.ximage,x_offset,y_offset,
9964 windows->pixel_info->background_color.pixel);
9965 width=(unsigned int) (*image)->columns;
9966 height=(unsigned int) (*image)->rows;
9967 x=0;
9968 y=0;
9969 if (windows->image.crop_geometry != (char *) NULL)
9970 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
9971 &width,&height);
9972 x_offset=(int)
9973 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
9974 y_offset=(int)
9975 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
9976 if ((x_offset < 0) || (y_offset < 0))
9977 continue;
9978 if ((x_offset >= (int) (*image)->columns) ||
9979 (y_offset >= (int) (*image)->rows))
9980 continue;
9981 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
9982 return(MagickFalse);
9983 (*image)->matte=MagickTrue;
9984 exception=(&(*image)->exception);
9985 image_view=AcquireAuthenticCacheView(*image,exception);
9986 switch (method)
9987 {
9988 case PointMethod:
9989 default:
9990 {
9991 /*
9992 Update matte information using point algorithm.
9993 */
9994 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
9995 (ssize_t) y_offset,1,1,exception);
9996 if (q == (PixelPacket *) NULL)
9997 break;
9998 q->opacity=(Quantum) StringToLong(matte);
9999 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10000 break;
10001 }
10002 case ReplaceMethod:
10003 {
10004 PixelPacket
10005 target;
10006
10007 /*
10008 Update matte information using replace algorithm.
10009 */
10010 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
10011 (ssize_t) y_offset,&target,exception);
10012 for (y=0; y < (int) (*image)->rows; y++)
10013 {
10014 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10015 (*image)->columns,1,&(*image)->exception);
10016 if (q == (PixelPacket *) NULL)
10017 break;
10018 for (x=0; x < (int) (*image)->columns; x++)
10019 {
10020 if (IsColorSimilar(*image,q,&target))
10021 q->opacity=(Quantum) StringToLong(matte);
10022 q++;
10023 }
10024 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10025 break;
10026 }
10027 break;
10028 }
10029 case FloodfillMethod:
10030 case FillToBorderMethod:
10031 {
10032 DrawInfo
10033 *draw_info;
10034
10035 MagickPixelPacket
10036 target;
10037
10038 /*
10039 Update matte information using floodfill algorithm.
10040 */
10041 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
10042 (ssize_t) y_offset,&target,exception);
10043 if (method == FillToBorderMethod)
10044 {
10045 target.red=(MagickRealType)
10046 ScaleShortToQuantum(border_color.red);
10047 target.green=(MagickRealType)
10048 ScaleShortToQuantum(border_color.green);
10049 target.blue=(MagickRealType)
10050 ScaleShortToQuantum(border_color.blue);
10051 }
10052 draw_info=CloneDrawInfo(resource_info->image_info,
10053 (DrawInfo *) NULL);
10054 draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte,
10055 (char **) NULL));
10056 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
10057 (ssize_t) x_offset,(ssize_t) y_offset,
10058 method == FloodfillMethod ? MagickFalse : MagickTrue);
10059 draw_info=DestroyDrawInfo(draw_info);
10060 break;
10061 }
10062 case ResetMethod:
10063 {
10064 /*
10065 Update matte information using reset algorithm.
10066 */
10067 if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
10068 return(MagickFalse);
10069 for (y=0; y < (int) (*image)->rows; y++)
10070 {
10071 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10072 (*image)->columns,1,exception);
10073 if (q == (PixelPacket *) NULL)
10074 break;
10075 for (x=0; x < (int) (*image)->columns; x++)
10076 {
10077 q->opacity=(Quantum) StringToLong(matte);
10078 q++;
10079 }
10080 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10081 break;
10082 }
10083 if (StringToLong(matte) == OpaqueOpacity)
10084 (*image)->matte=MagickFalse;
10085 break;
10086 }
10087 }
10088 image_view=DestroyCacheView(image_view);
10089 state&=(~UpdateConfigurationState);
10090 }
10091 } while ((state & ExitState) == 0);
10092 (void) XSelectInput(display,windows->image.id,
10093 windows->image.attributes.event_mask);
10094 XSetCursorState(display,windows,MagickFalse);
10095 (void) XFreeCursor(display,cursor);
10096 return(MagickTrue);
10097}
10098
10099/*
10100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10101% %
10102% %
10103% %
10104+ X O p e n I m a g e %
10105% %
10106% %
10107% %
10108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10109%
10110% XOpenImage() loads an image from a file.
10111%
10112% The format of the XOpenImage method is:
10113%
10114% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10115% XWindows *windows,const unsigned int command)
10116%
10117% A description of each parameter follows:
10118%
10119% o display: Specifies a connection to an X server; returned from
10120% XOpenDisplay.
10121%
10122% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10123%
10124% o windows: Specifies a pointer to a XWindows structure.
10125%
10126% o command: A value other than zero indicates that the file is selected
10127% from the command line argument list.
10128%
10129*/
10130static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10131 XWindows *windows,const MagickBooleanType command)
10132{
10133 const MagickInfo
10134 *magick_info;
10135
10136 ExceptionInfo
10137 *exception;
10138
10139 Image
10140 *nexus;
10141
10142 ImageInfo
10143 *image_info;
10144
10145 static char
10146 filename[MaxTextExtent] = "\0";
10147
10148 /*
10149 Request file name from user.
10150 */
10151 if (command == MagickFalse)
10152 XFileBrowserWidget(display,windows,"Open",filename);
10153 else
10154 {
10155 char
10156 **filelist,
10157 **files;
10158
10159 int
10160 count,
10161 status;
10162
10163 int
10164 i,
10165 j;
10166
10167 /*
10168 Select next image from the command line.
10169 */
10170 status=XGetCommand(display,windows->image.id,&files,&count);
10171 if (status == 0)
10172 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10173 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10174 if (filelist == (char **) NULL)
10175 {
10176 (void) XFreeStringList(files);
10177 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
10178 "...");
10179 return((Image *) NULL);
10180 }
10181 j=0;
10182 for (i=1; i < count; i++)
10183 if (*files[i] != '-')
10184 filelist[j++]=files[i];
10185 filelist[j]=(char *) NULL;
10186 XListBrowserWidget(display,windows,&windows->widget,
10187 (const char **) filelist,"Load","Select Image to Load:",filename);
10188 filelist=(char **) RelinquishMagickMemory(filelist);
10189 (void) XFreeStringList(files);
10190 }
10191 if (*filename == '\0')
10192 return((Image *) NULL);
10193 image_info=CloneImageInfo(resource_info->image_info);
10194 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10195 (void *) NULL);
10196 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10197 exception=AcquireExceptionInfo();
10198 (void) SetImageInfo(image_info,0,exception);
10199 if (LocaleCompare(image_info->magick,"X") == 0)
10200 {
10201 char
10202 seconds[MaxTextExtent];
10203
10204 /*
10205 User may want to delay the X server screen grab.
10206 */
10207 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10208 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10209 seconds);
10210 if (*seconds == '\0')
10211 return((Image *) NULL);
10212 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10213 }
10214 magick_info=GetMagickInfo(image_info->magick,exception);
10215 if ((magick_info != (const MagickInfo *) NULL) &&
10216 (magick_info->raw != MagickFalse))
10217 {
10218 char
10219 geometry[MaxTextExtent];
10220
10221 /*
10222 Request image size from the user.
10223 */
10224 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10225 if (image_info->size != (char *) NULL)
10226 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10227 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10228 geometry);
10229 (void) CloneString(&image_info->size,geometry);
10230 }
10231 /*
10232 Load the image.
10233 */
10234 XSetCursorState(display,windows,MagickTrue);
10235 XCheckRefreshWindows(display,windows);
10236 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10237 nexus=ReadImage(image_info,exception);
10238 CatchException(exception);
10239 XSetCursorState(display,windows,MagickFalse);
10240 if (nexus != (Image *) NULL)
10241 XClientMessage(display,windows->image.id,windows->im_protocols,
10242 windows->im_next_image,CurrentTime);
10243 else
10244 {
10245 char
10246 *text,
10247 **textlist;
10248
10249 /*
10250 Unknown image format.
10251 */
10252 text=FileToString(filename,~0UL,exception);
10253 if (text == (char *) NULL)
10254 return((Image *) NULL);
10255 textlist=StringToList(text);
10256 if (textlist != (char **) NULL)
10257 {
10258 char
10259 title[MaxTextExtent];
10260
10261 int
10262 i;
10263
10264 (void) FormatLocaleString(title,MaxTextExtent,
10265 "Unknown format: %s",filename);
10266 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10267 (const char **) textlist);
10268 for (i=0; textlist[i] != (char *) NULL; i++)
10269 textlist[i]=DestroyString(textlist[i]);
10270 textlist=(char **) RelinquishMagickMemory(textlist);
10271 }
10272 text=DestroyString(text);
10273 }
10274 exception=DestroyExceptionInfo(exception);
10275 image_info=DestroyImageInfo(image_info);
10276 return(nexus);
10277}
10278
10279/*
10280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10281% %
10282% %
10283% %
10284+ X P a n I m a g e %
10285% %
10286% %
10287% %
10288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10289%
10290% XPanImage() pans the image until the mouse button is released.
10291%
10292% The format of the XPanImage method is:
10293%
10294% void XPanImage(Display *display,XWindows *windows,XEvent *event)
10295%
10296% A description of each parameter follows:
10297%
10298% o display: Specifies a connection to an X server; returned from
10299% XOpenDisplay.
10300%
10301% o windows: Specifies a pointer to a XWindows structure.
10302%
10303% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10304% the entire image is refreshed.
10305%
10306*/
10307static void XPanImage(Display *display,XWindows *windows,XEvent *event)
10308{
10309 char
10310 text[MaxTextExtent];
10311
10312 Cursor
10313 cursor;
10314
10315 MagickRealType
10316 x_factor,
10317 y_factor;
10318
10319 RectangleInfo
10320 pan_info;
10321
10322 size_t
10323 state;
10324
10325 /*
10326 Define cursor.
10327 */
10328 if ((windows->image.ximage->width > (int) windows->image.width) &&
10329 (windows->image.ximage->height > (int) windows->image.height))
10330 cursor=XCreateFontCursor(display,XC_fleur);
10331 else
10332 if (windows->image.ximage->width > (int) windows->image.width)
10333 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10334 else
10335 if (windows->image.ximage->height > (int) windows->image.height)
10336 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10337 else
10338 cursor=XCreateFontCursor(display,XC_arrow);
10339 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10340 /*
10341 Pan image as pointer moves until the mouse button is released.
10342 */
10343 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
10344 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
10345 pan_info.width=windows->pan.width*windows->image.width/
10346 windows->image.ximage->width;
10347 pan_info.height=windows->pan.height*windows->image.height/
10348 windows->image.ximage->height;
10349 pan_info.x=0;
10350 pan_info.y=0;
10351 state=UpdateConfigurationState;
10352 do
10353 {
10354 switch (event->type)
10355 {
10356 case ButtonPress:
10357 {
10358 /*
10359 User choose an initial pan location.
10360 */
10361 pan_info.x=(ssize_t) event->xbutton.x;
10362 pan_info.y=(ssize_t) event->xbutton.y;
10363 state|=UpdateConfigurationState;
10364 break;
10365 }
10366 case ButtonRelease:
10367 {
10368 /*
10369 User has finished panning the image.
10370 */
10371 pan_info.x=(ssize_t) event->xbutton.x;
10372 pan_info.y=(ssize_t) event->xbutton.y;
10373 state|=UpdateConfigurationState | ExitState;
10374 break;
10375 }
10376 case MotionNotify:
10377 {
10378 pan_info.x=(ssize_t) event->xmotion.x;
10379 pan_info.y=(ssize_t) event->xmotion.y;
10380 state|=UpdateConfigurationState;
10381 }
10382 default:
10383 break;
10384 }
10385 if ((state & UpdateConfigurationState) != 0)
10386 {
10387 /*
10388 Check boundary conditions.
10389 */
10390 if (pan_info.x < (ssize_t) (pan_info.width/2))
10391 pan_info.x=0;
10392 else
10393 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10394 if (pan_info.x < 0)
10395 pan_info.x=0;
10396 else
10397 if ((int) (pan_info.x+windows->image.width) >
10398 windows->image.ximage->width)
10399 pan_info.x=(ssize_t)
10400 (windows->image.ximage->width-windows->image.width);
10401 if (pan_info.y < (ssize_t) (pan_info.height/2))
10402 pan_info.y=0;
10403 else
10404 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10405 if (pan_info.y < 0)
10406 pan_info.y=0;
10407 else
10408 if ((int) (pan_info.y+windows->image.height) >
10409 windows->image.ximage->height)
10410 pan_info.y=(ssize_t)
10411 (windows->image.ximage->height-windows->image.height);
10412 if ((windows->image.x != (int) pan_info.x) ||
10413 (windows->image.y != (int) pan_info.y))
10414 {
10415 /*
10416 Display image pan offset.
10417 */
10418 windows->image.x=(int) pan_info.x;
10419 windows->image.y=(int) pan_info.y;
10420 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
10421 windows->image.width,windows->image.height,windows->image.x,
10422 windows->image.y);
10423 XInfoWidget(display,windows,text);
10424 /*
10425 Refresh Image window.
10426 */
10427 XDrawPanRectangle(display,windows);
10428 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10429 }
10430 state&=(~UpdateConfigurationState);
10431 }
10432 /*
10433 Wait for next event.
10434 */
10435 if ((state & ExitState) == 0)
10436 XScreenEvent(display,windows,event);
10437 } while ((state & ExitState) == 0);
10438 /*
10439 Restore cursor.
10440 */
10441 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10442 (void) XFreeCursor(display,cursor);
10443 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10444}
10445
10446/*
10447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10448% %
10449% %
10450% %
10451+ X P a s t e I m a g e %
10452% %
10453% %
10454% %
10455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10456%
10457% XPasteImage() pastes an image previously saved with XCropImage in the X
10458% window image at a location the user chooses with the pointer.
10459%
10460% The format of the XPasteImage method is:
10461%
10462% MagickBooleanType XPasteImage(Display *display,
10463% XResourceInfo *resource_info,XWindows *windows,Image *image)
10464%
10465% A description of each parameter follows:
10466%
10467% o display: Specifies a connection to an X server; returned from
10468% XOpenDisplay.
10469%
10470% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10471%
10472% o windows: Specifies a pointer to a XWindows structure.
10473%
10474% o image: the image; returned from ReadImage.
10475%
10476*/
10477static MagickBooleanType XPasteImage(Display *display,
10478 XResourceInfo *resource_info,XWindows *windows,Image *image)
10479{
10480 const char
10481 *const PasteMenu[] =
10482 {
10483 "Operator",
10484 "Help",
10485 "Dismiss",
10486 (char *) NULL
10487 };
10488
10489 static const ModeType
10490 PasteCommands[] =
10491 {
10492 PasteOperatorsCommand,
10493 PasteHelpCommand,
10494 PasteDismissCommand
10495 };
10496
10497 static CompositeOperator
10498 compose = CopyCompositeOp;
10499
10500 char
10501 text[MaxTextExtent];
10502
10503 Cursor
10504 cursor;
10505
10506 Image
10507 *paste_image;
10508
10509 int
10510 entry,
10511 id,
10512 x,
10513 y;
10514
10515 MagickRealType
10516 scale_factor;
10517
10518 RectangleInfo
10519 highlight_info,
10520 paste_info;
10521
10522 unsigned int
10523 height,
10524 width;
10525
10526 size_t
10527 state;
10528
10529 XEvent
10530 event;
10531
10532 /*
10533 Copy image.
10534 */
10535 if (resource_info->copy_image == (Image *) NULL)
10536 return(MagickFalse);
10537 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
10538 &image->exception);
10539 if (paste_image == (Image *) NULL)
10540 return(MagickFalse);
10541 /*
10542 Map Command widget.
10543 */
10544 (void) CloneString(&windows->command.name,"Paste");
10545 windows->command.data=1;
10546 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10547 (void) XMapRaised(display,windows->command.id);
10548 XClientMessage(display,windows->image.id,windows->im_protocols,
10549 windows->im_update_widget,CurrentTime);
10550 /*
10551 Track pointer until button 1 is pressed.
10552 */
10553 XSetCursorState(display,windows,MagickFalse);
10554 XQueryPosition(display,windows->image.id,&x,&y);
10555 (void) XSelectInput(display,windows->image.id,
10556 windows->image.attributes.event_mask | PointerMotionMask);
10557 paste_info.x=(ssize_t) windows->image.x+x;
10558 paste_info.y=(ssize_t) windows->image.y+y;
10559 paste_info.width=0;
10560 paste_info.height=0;
10561 cursor=XCreateFontCursor(display,XC_ul_angle);
10562 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10563 state=DefaultState;
10564 do
10565 {
10566 if (windows->info.mapped != MagickFalse)
10567 {
10568 /*
10569 Display pointer position.
10570 */
10571 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
10572 (long) paste_info.x,(long) paste_info.y);
10573 XInfoWidget(display,windows,text);
10574 }
10575 highlight_info=paste_info;
10576 highlight_info.x=paste_info.x-windows->image.x;
10577 highlight_info.y=paste_info.y-windows->image.y;
10578 XHighlightRectangle(display,windows->image.id,
10579 windows->image.highlight_context,&highlight_info);
10580 /*
10581 Wait for next event.
10582 */
10583 XScreenEvent(display,windows,&event);
10584 XHighlightRectangle(display,windows->image.id,
10585 windows->image.highlight_context,&highlight_info);
10586 if (event.xany.window == windows->command.id)
10587 {
10588 /*
10589 Select a command from the Command widget.
10590 */
10591 id=XCommandWidget(display,windows,PasteMenu,&event);
10592 if (id < 0)
10593 continue;
10594 switch (PasteCommands[id])
10595 {
10596 case PasteOperatorsCommand:
10597 {
10598 char
10599 command[MaxTextExtent],
10600 **operators;
10601
10602 /*
10603 Select a command from the pop-up menu.
10604 */
10605 operators=GetCommandOptions(MagickComposeOptions);
10606 if (operators == (char **) NULL)
10607 break;
10608 entry=XMenuWidget(display,windows,PasteMenu[id],
10609 (const char **) operators,command);
10610 if (entry >= 0)
10611 compose=(CompositeOperator) ParseCommandOption(
10612 MagickComposeOptions,MagickFalse,operators[entry]);
10613 operators=DestroyStringList(operators);
10614 break;
10615 }
10616 case PasteHelpCommand:
10617 {
10618 XTextViewHelp(display,resource_info,windows,MagickFalse,
10619 "Help Viewer - Image Composite",ImagePasteHelp);
10620 break;
10621 }
10622 case PasteDismissCommand:
10623 {
10624 /*
10625 Prematurely exit.
10626 */
10627 state|=EscapeState;
10628 state|=ExitState;
10629 break;
10630 }
10631 default:
10632 break;
10633 }
10634 continue;
10635 }
10636 switch (event.type)
10637 {
10638 case ButtonPress:
10639 {
10640 if (resource_info->debug != MagickFalse)
10641 (void) LogMagickEvent(X11Event,GetMagickModule(),
10642 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10643 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10644 if (event.xbutton.button != Button1)
10645 break;
10646 if (event.xbutton.window != windows->image.id)
10647 break;
10648 /*
10649 Paste rectangle is relative to image configuration.
10650 */
10651 width=(unsigned int) image->columns;
10652 height=(unsigned int) image->rows;
10653 x=0;
10654 y=0;
10655 if (windows->image.crop_geometry != (char *) NULL)
10656 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10657 &width,&height);
10658 scale_factor=(MagickRealType) windows->image.ximage->width/width;
10659 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10660 scale_factor=(MagickRealType) windows->image.ximage->height/height;
10661 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10662 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10663 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10664 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10665 break;
10666 }
10667 case ButtonRelease:
10668 {
10669 if (resource_info->debug != MagickFalse)
10670 (void) LogMagickEvent(X11Event,GetMagickModule(),
10671 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10672 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10673 if (event.xbutton.button != Button1)
10674 break;
10675 if (event.xbutton.window != windows->image.id)
10676 break;
10677 if ((paste_info.width != 0) && (paste_info.height != 0))
10678 {
10679 /*
10680 User has selected the location of the paste image.
10681 */
10682 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10683 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10684 state|=ExitState;
10685 }
10686 break;
10687 }
10688 case Expose:
10689 break;
10690 case KeyPress:
10691 {
10692 char
10693 command[MaxTextExtent];
10694
10695 KeySym
10696 key_symbol;
10697
10698 int
10699 length;
10700
10701 if (event.xkey.window != windows->image.id)
10702 break;
10703 /*
10704 Respond to a user key press.
10705 */
10706 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10707 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10708 *(command+length)='\0';
10709 if (resource_info->debug != MagickFalse)
10710 (void) LogMagickEvent(X11Event,GetMagickModule(),
10711 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10712 switch ((int) key_symbol)
10713 {
10714 case XK_Escape:
10715 case XK_F20:
10716 {
10717 /*
10718 Prematurely exit.
10719 */
10720 paste_image=DestroyImage(paste_image);
10721 state|=EscapeState;
10722 state|=ExitState;
10723 break;
10724 }
10725 case XK_F1:
10726 case XK_Help:
10727 {
10728 (void) XSetFunction(display,windows->image.highlight_context,
10729 GXcopy);
10730 XTextViewHelp(display,resource_info,windows,MagickFalse,
10731 "Help Viewer - Image Composite",ImagePasteHelp);
10732 (void) XSetFunction(display,windows->image.highlight_context,
10733 GXinvert);
10734 break;
10735 }
10736 default:
10737 {
10738 (void) XBell(display,0);
10739 break;
10740 }
10741 }
10742 break;
10743 }
10744 case MotionNotify:
10745 {
10746 /*
10747 Map and unmap Info widget as text cursor crosses its boundaries.
10748 */
10749 x=event.xmotion.x;
10750 y=event.xmotion.y;
10751 if (windows->info.mapped != MagickFalse)
10752 {
10753 if ((x < (int) (windows->info.x+windows->info.width)) &&
10754 (y < (int) (windows->info.y+windows->info.height)))
10755 (void) XWithdrawWindow(display,windows->info.id,
10756 windows->info.screen);
10757 }
10758 else
10759 if ((x > (int) (windows->info.x+windows->info.width)) ||
10760 (y > (int) (windows->info.y+windows->info.height)))
10761 (void) XMapWindow(display,windows->info.id);
10762 paste_info.x=(ssize_t) windows->image.x+x;
10763 paste_info.y=(ssize_t) windows->image.y+y;
10764 break;
10765 }
10766 default:
10767 {
10768 if (resource_info->debug != MagickFalse)
10769 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10770 event.type);
10771 break;
10772 }
10773 }
10774 } while ((state & ExitState) == 0);
10775 (void) XSelectInput(display,windows->image.id,
10776 windows->image.attributes.event_mask);
10777 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10778 XSetCursorState(display,windows,MagickFalse);
10779 (void) XFreeCursor(display,cursor);
10780 if ((state & EscapeState) != 0)
10781 return(MagickTrue);
10782 /*
10783 Image pasting is relative to image configuration.
10784 */
10785 XSetCursorState(display,windows,MagickTrue);
10786 XCheckRefreshWindows(display,windows);
10787 width=(unsigned int) image->columns;
10788 height=(unsigned int) image->rows;
10789 x=0;
10790 y=0;
10791 if (windows->image.crop_geometry != (char *) NULL)
10792 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10793 scale_factor=(MagickRealType) width/windows->image.ximage->width;
10794 paste_info.x+=x;
10795 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10796 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10797 scale_factor=(MagickRealType) height/windows->image.ximage->height;
10798 paste_info.y+=y;
10799 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10800 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10801 /*
10802 Paste image with X Image window.
10803 */
10804 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
10805 paste_image=DestroyImage(paste_image);
10806 XSetCursorState(display,windows,MagickFalse);
10807 /*
10808 Update image colormap.
10809 */
10810 XConfigureImageColormap(display,resource_info,windows,image);
10811 (void) XConfigureImage(display,resource_info,windows,image);
10812 return(MagickTrue);
10813}
10814
10815/*
10816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10817% %
10818% %
10819% %
10820+ X P r i n t I m a g e %
10821% %
10822% %
10823% %
10824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10825%
10826% XPrintImage() prints an image to a Postscript printer.
10827%
10828% The format of the XPrintImage method is:
10829%
10830% MagickBooleanType XPrintImage(Display *display,
10831% XResourceInfo *resource_info,XWindows *windows,Image *image)
10832%
10833% A description of each parameter follows:
10834%
10835% o display: Specifies a connection to an X server; returned from
10836% XOpenDisplay.
10837%
10838% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10839%
10840% o windows: Specifies a pointer to a XWindows structure.
10841%
10842% o image: the image.
10843%
10844*/
10845static MagickBooleanType XPrintImage(Display *display,
10846 XResourceInfo *resource_info,XWindows *windows,Image *image)
10847{
10848 char
10849 filename[MaxTextExtent],
10850 geometry[MaxTextExtent];
10851
10852 const char
10853 *const PageSizes[] =
10854 {
10855 "Letter",
10856 "Tabloid",
10857 "Ledger",
10858 "Legal",
10859 "Statement",
10860 "Executive",
10861 "A3",
10862 "A4",
10863 "A5",
10864 "B4",
10865 "B5",
10866 "Folio",
10867 "Quarto",
10868 "10x14",
10869 (char *) NULL
10870 };
10871
10872 Image
10873 *print_image;
10874
10875 ImageInfo
10876 *image_info;
10877
10878 MagickStatusType
10879 status;
10880
10881 /*
10882 Request Postscript page geometry from user.
10883 */
10884 image_info=CloneImageInfo(resource_info->image_info);
10885 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
10886 if (image_info->page != (char *) NULL)
10887 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
10888 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10889 "Select Postscript Page Geometry:",geometry);
10890 if (*geometry == '\0')
10891 return(MagickTrue);
10892 image_info->page=GetPageGeometry(geometry);
10893 /*
10894 Apply image transforms.
10895 */
10896 XSetCursorState(display,windows,MagickTrue);
10897 XCheckRefreshWindows(display,windows);
10898 print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10899 if (print_image == (Image *) NULL)
10900 return(MagickFalse);
10901 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
10902 windows->image.ximage->width,windows->image.ximage->height);
10903 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
10904 /*
10905 Print image.
10906 */
10907 (void) AcquireUniqueFilename(filename);
10908 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
10909 filename);
10910 status=WriteImage(image_info,print_image);
10911 (void) RelinquishUniqueFileResource(filename);
10912 print_image=DestroyImage(print_image);
10913 image_info=DestroyImageInfo(image_info);
10914 XSetCursorState(display,windows,MagickFalse);
10915 return(status != 0 ? MagickTrue : MagickFalse);
10916}
10917
10918/*
10919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10920% %
10921% %
10922% %
10923+ X R O I I m a g e %
10924% %
10925% %
10926% %
10927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10928%
10929% XROIImage() applies an image processing technique to a region of interest.
10930%
10931% The format of the XROIImage method is:
10932%
10933% MagickBooleanType XROIImage(Display *display,
10934% XResourceInfo *resource_info,XWindows *windows,Image **image)
10935%
10936% A description of each parameter follows:
10937%
10938% o display: Specifies a connection to an X server; returned from
10939% XOpenDisplay.
10940%
10941% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10942%
10943% o windows: Specifies a pointer to a XWindows structure.
10944%
10945% o image: the image; returned from ReadImage.
10946%
10947*/
10948static MagickBooleanType XROIImage(Display *display,
10949 XResourceInfo *resource_info,XWindows *windows,Image **image)
10950{
10951#define ApplyMenus 7
10952
10953 const char
10954 *const ROIMenu[] =
10955 {
10956 "Help",
10957 "Dismiss",
10958 (char *) NULL
10959 },
10960 *const ApplyMenu[] =
10961 {
10962 "File",
10963 "Edit",
10964 "Transform",
10965 "Enhance",
10966 "Effects",
10967 "F/X",
10968 "Miscellany",
10969 "Help",
10970 "Dismiss",
10971 (char *) NULL
10972 },
10973 *const FileMenu[] =
10974 {
10975 "Save...",
10976 "Print...",
10977 (char *) NULL
10978 },
10979 *const EditMenu[] =
10980 {
10981 "Undo",
10982 "Redo",
10983 (char *) NULL
10984 },
10985 *const TransformMenu[] =
10986 {
10987 "Flop",
10988 "Flip",
10989 "Rotate Right",
10990 "Rotate Left",
10991 (char *) NULL
10992 },
10993 *const EnhanceMenu[] =
10994 {
10995 "Hue...",
10996 "Saturation...",
10997 "Brightness...",
10998 "Gamma...",
10999 "Spiff",
11000 "Dull",
11001 "Contrast Stretch...",
11002 "Sigmoidal Contrast...",
11003 "Normalize",
11004 "Equalize",
11005 "Negate",
11006 "Grayscale",
11007 "Map...",
11008 "Quantize...",
11009 (char *) NULL
11010 },
11011 *const EffectsMenu[] =
11012 {
11013 "Despeckle",
11014 "Emboss",
11015 "Reduce Noise",
11016 "Add Noise",
11017 "Sharpen...",
11018 "Blur...",
11019 "Threshold...",
11020 "Edge Detect...",
11021 "Spread...",
11022 "Shade...",
11023 "Raise...",
11024 "Segment...",
11025 (char *) NULL
11026 },
11027 *const FXMenu[] =
11028 {
11029 "Solarize...",
11030 "Sepia Tone...",
11031 "Swirl...",
11032 "Implode...",
11033 "Vignette...",
11034 "Wave...",
11035 "Oil Paint...",
11036 "Charcoal Draw...",
11037 (char *) NULL
11038 },
11039 *const MiscellanyMenu[] =
11040 {
11041 "Image Info",
11042 "Zoom Image",
11043 "Show Preview...",
11044 "Show Histogram",
11045 "Show Matte",
11046 (char *) NULL
11047 };
11048
11049 const char
11050 *const *Menus[ApplyMenus] =
11051 {
11052 FileMenu,
11053 EditMenu,
11054 TransformMenu,
11055 EnhanceMenu,
11056 EffectsMenu,
11057 FXMenu,
11058 MiscellanyMenu
11059 };
11060
11061 static const DisplayCommand
11062 ApplyCommands[] =
11063 {
11064 NullCommand,
11065 NullCommand,
11066 NullCommand,
11067 NullCommand,
11068 NullCommand,
11069 NullCommand,
11070 NullCommand,
11071 HelpCommand,
11072 QuitCommand
11073 },
11074 FileCommands[] =
11075 {
11076 SaveCommand,
11077 PrintCommand
11078 },
11079 EditCommands[] =
11080 {
11081 UndoCommand,
11082 RedoCommand
11083 },
11084 TransformCommands[] =
11085 {
11086 FlopCommand,
11087 FlipCommand,
11088 RotateRightCommand,
11089 RotateLeftCommand
11090 },
11091 EnhanceCommands[] =
11092 {
11093 HueCommand,
11094 SaturationCommand,
11095 BrightnessCommand,
11096 GammaCommand,
11097 SpiffCommand,
11098 DullCommand,
11099 ContrastStretchCommand,
11100 SigmoidalContrastCommand,
11101 NormalizeCommand,
11102 EqualizeCommand,
11103 NegateCommand,
11104 GrayscaleCommand,
11105 MapCommand,
11106 QuantizeCommand
11107 },
11108 EffectsCommands[] =
11109 {
11110 DespeckleCommand,
11111 EmbossCommand,
11112 ReduceNoiseCommand,
11113 AddNoiseCommand,
11114 SharpenCommand,
11115 BlurCommand,
11116 ThresholdCommand,
11117 EdgeDetectCommand,
11118 SpreadCommand,
11119 ShadeCommand,
11120 RaiseCommand,
11121 SegmentCommand
11122 },
11123 FXCommands[] =
11124 {
11125 SolarizeCommand,
11126 SepiaToneCommand,
11127 SwirlCommand,
11128 ImplodeCommand,
11129 VignetteCommand,
11130 WaveCommand,
11131 OilPaintCommand,
11132 CharcoalDrawCommand
11133 },
11134 MiscellanyCommands[] =
11135 {
11136 InfoCommand,
11137 ZoomCommand,
11138 ShowPreviewCommand,
11139 ShowHistogramCommand,
11140 ShowMatteCommand
11141 },
11142 ROICommands[] =
11143 {
11144 ROIHelpCommand,
11145 ROIDismissCommand
11146 };
11147
11148 static const DisplayCommand
11149 *Commands[ApplyMenus] =
11150 {
11151 FileCommands,
11152 EditCommands,
11153 TransformCommands,
11154 EnhanceCommands,
11155 EffectsCommands,
11156 FXCommands,
11157 MiscellanyCommands
11158 };
11159
11160 char
11161 command[MaxTextExtent],
11162 text[MaxTextExtent];
11163
11164 DisplayCommand
11165 display_command;
11166
11167 Cursor
11168 cursor;
11169
11170 Image
11171 *roi_image;
11172
11173 int
11174 entry,
11175 id,
11176 x,
11177 y;
11178
11179 MagickRealType
11180 scale_factor;
11181
11182 MagickProgressMonitor
11183 progress_monitor;
11184
11185 RectangleInfo
11186 crop_info,
11187 highlight_info,
11188 roi_info;
11189
11190 unsigned int
11191 height,
11192 width;
11193
11194 size_t
11195 state;
11196
11197 XEvent
11198 event;
11199
11200 /*
11201 Map Command widget.
11202 */
11203 (void) CloneString(&windows->command.name,"ROI");
11204 windows->command.data=0;
11205 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11206 (void) XMapRaised(display,windows->command.id);
11207 XClientMessage(display,windows->image.id,windows->im_protocols,
11208 windows->im_update_widget,CurrentTime);
11209 /*
11210 Track pointer until button 1 is pressed.
11211 */
11212 XQueryPosition(display,windows->image.id,&x,&y);
11213 (void) XSelectInput(display,windows->image.id,
11214 windows->image.attributes.event_mask | PointerMotionMask);
11215 crop_info.width=0;
11216 crop_info.height=0;
11217 crop_info.x=0;
11218 crop_info.y=0;
11219 roi_info.x=(ssize_t) windows->image.x+x;
11220 roi_info.y=(ssize_t) windows->image.y+y;
11221 roi_info.width=0;
11222 roi_info.height=0;
11223 cursor=XCreateFontCursor(display,XC_fleur);
11224 state=DefaultState;
11225 do
11226 {
11227 if (windows->info.mapped != MagickFalse)
11228 {
11229 /*
11230 Display pointer position.
11231 */
11232 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
11233 (long) roi_info.x,(long) roi_info.y);
11234 XInfoWidget(display,windows,text);
11235 }
11236 /*
11237 Wait for next event.
11238 */
11239 XScreenEvent(display,windows,&event);
11240 if (event.xany.window == windows->command.id)
11241 {
11242 /*
11243 Select a command from the Command widget.
11244 */
11245 id=XCommandWidget(display,windows,ROIMenu,&event);
11246 if (id < 0)
11247 continue;
11248 switch (ROICommands[id])
11249 {
11250 case ROIHelpCommand:
11251 {
11252 XTextViewHelp(display,resource_info,windows,MagickFalse,
11253 "Help Viewer - Region of Interest",ImageROIHelp);
11254 break;
11255 }
11256 case ROIDismissCommand:
11257 {
11258 /*
11259 Prematurely exit.
11260 */
11261 state|=EscapeState;
11262 state|=ExitState;
11263 break;
11264 }
11265 default:
11266 break;
11267 }
11268 continue;
11269 }
11270 switch (event.type)
11271 {
11272 case ButtonPress:
11273 {
11274 if (event.xbutton.button != Button1)
11275 break;
11276 if (event.xbutton.window != windows->image.id)
11277 break;
11278 /*
11279 Note first corner of region of interest rectangle-- exit loop.
11280 */
11281 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11282 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11283 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11284 state|=ExitState;
11285 break;
11286 }
11287 case ButtonRelease:
11288 break;
11289 case Expose:
11290 break;
11291 case KeyPress:
11292 {
11293 KeySym
11294 key_symbol;
11295
11296 if (event.xkey.window != windows->image.id)
11297 break;
11298 /*
11299 Respond to a user key press.
11300 */
11301 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11302 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11303 switch ((int) key_symbol)
11304 {
11305 case XK_Escape:
11306 case XK_F20:
11307 {
11308 /*
11309 Prematurely exit.
11310 */
11311 state|=EscapeState;
11312 state|=ExitState;
11313 break;
11314 }
11315 case XK_F1:
11316 case XK_Help:
11317 {
11318 XTextViewHelp(display,resource_info,windows,MagickFalse,
11319 "Help Viewer - Region of Interest",ImageROIHelp);
11320 break;
11321 }
11322 default:
11323 {
11324 (void) XBell(display,0);
11325 break;
11326 }
11327 }
11328 break;
11329 }
11330 case MotionNotify:
11331 {
11332 /*
11333 Map and unmap Info widget as text cursor crosses its boundaries.
11334 */
11335 x=event.xmotion.x;
11336 y=event.xmotion.y;
11337 if (windows->info.mapped != MagickFalse)
11338 {
11339 if ((x < (int) (windows->info.x+windows->info.width)) &&
11340 (y < (int) (windows->info.y+windows->info.height)))
11341 (void) XWithdrawWindow(display,windows->info.id,
11342 windows->info.screen);
11343 }
11344 else
11345 if ((x > (int) (windows->info.x+windows->info.width)) ||
11346 (y > (int) (windows->info.y+windows->info.height)))
11347 (void) XMapWindow(display,windows->info.id);
11348 roi_info.x=(ssize_t) windows->image.x+x;
11349 roi_info.y=(ssize_t) windows->image.y+y;
11350 break;
11351 }
11352 default:
11353 break;
11354 }
11355 } while ((state & ExitState) == 0);
11356 (void) XSelectInput(display,windows->image.id,
11357 windows->image.attributes.event_mask);
11358 if ((state & EscapeState) != 0)
11359 {
11360 /*
11361 User want to exit without region of interest.
11362 */
11363 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11364 (void) XFreeCursor(display,cursor);
11365 return(MagickTrue);
11366 }
11367 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11368 do
11369 {
11370 /*
11371 Size rectangle as pointer moves until the mouse button is released.
11372 */
11373 x=(int) roi_info.x;
11374 y=(int) roi_info.y;
11375 roi_info.width=0;
11376 roi_info.height=0;
11377 state=DefaultState;
11378 do
11379 {
11380 highlight_info=roi_info;
11381 highlight_info.x=roi_info.x-windows->image.x;
11382 highlight_info.y=roi_info.y-windows->image.y;
11383 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11384 {
11385 /*
11386 Display info and draw region of interest rectangle.
11387 */
11388 if (windows->info.mapped == MagickFalse)
11389 (void) XMapWindow(display,windows->info.id);
11390 (void) FormatLocaleString(text,MaxTextExtent,
11391 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11392 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11393 XInfoWidget(display,windows,text);
11394 XHighlightRectangle(display,windows->image.id,
11395 windows->image.highlight_context,&highlight_info);
11396 }
11397 else
11398 if (windows->info.mapped != MagickFalse)
11399 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11400 /*
11401 Wait for next event.
11402 */
11403 XScreenEvent(display,windows,&event);
11404 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11405 XHighlightRectangle(display,windows->image.id,
11406 windows->image.highlight_context,&highlight_info);
11407 switch (event.type)
11408 {
11409 case ButtonPress:
11410 {
11411 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11412 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11413 break;
11414 }
11415 case ButtonRelease:
11416 {
11417 /*
11418 User has committed to region of interest rectangle.
11419 */
11420 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11421 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11422 XSetCursorState(display,windows,MagickFalse);
11423 state|=ExitState;
11424 if (LocaleCompare(windows->command.name,"Apply") == 0)
11425 break;
11426 (void) CloneString(&windows->command.name,"Apply");
11427 windows->command.data=ApplyMenus;
11428 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11429 break;
11430 }
11431 case Expose:
11432 break;
11433 case MotionNotify:
11434 {
11435 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11436 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11437 }
11438 default:
11439 break;
11440 }
11441 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11442 ((state & ExitState) != 0))
11443 {
11444 /*
11445 Check boundary conditions.
11446 */
11447 if (roi_info.x < 0)
11448 roi_info.x=0;
11449 else
11450 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11451 roi_info.x=(ssize_t) windows->image.ximage->width;
11452 if ((int) roi_info.x < x)
11453 roi_info.width=(unsigned int) (x-roi_info.x);
11454 else
11455 {
11456 roi_info.width=(unsigned int) (roi_info.x-x);
11457 roi_info.x=(ssize_t) x;
11458 }
11459 if (roi_info.y < 0)
11460 roi_info.y=0;
11461 else
11462 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11463 roi_info.y=(ssize_t) windows->image.ximage->height;
11464 if ((int) roi_info.y < y)
11465 roi_info.height=(unsigned int) (y-roi_info.y);
11466 else
11467 {
11468 roi_info.height=(unsigned int) (roi_info.y-y);
11469 roi_info.y=(ssize_t) y;
11470 }
11471 }
11472 } while ((state & ExitState) == 0);
11473 /*
11474 Wait for user to grab a corner of the rectangle or press return.
11475 */
11476 state=DefaultState;
11477 display_command=NullCommand;
11478 (void) XMapWindow(display,windows->info.id);
11479 do
11480 {
11481 if (windows->info.mapped != MagickFalse)
11482 {
11483 /*
11484 Display pointer position.
11485 */
11486 (void) FormatLocaleString(text,MaxTextExtent,
11487 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11488 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11489 XInfoWidget(display,windows,text);
11490 }
11491 highlight_info=roi_info;
11492 highlight_info.x=roi_info.x-windows->image.x;
11493 highlight_info.y=roi_info.y-windows->image.y;
11494 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11495 {
11496 state|=EscapeState;
11497 state|=ExitState;
11498 break;
11499 }
11500 if ((state & UpdateRegionState) != 0)
11501 {
11502 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11503 switch (display_command)
11504 {
11505 case UndoCommand:
11506 case RedoCommand:
11507 {
11508 (void) XMagickCommand(display,resource_info,windows,
11509 display_command,image);
11510 break;
11511 }
11512 default:
11513 {
11514 /*
11515 Region of interest is relative to image configuration.
11516 */
11517 progress_monitor=SetImageProgressMonitor(*image,
11518 (MagickProgressMonitor) NULL,(*image)->client_data);
11519 crop_info=roi_info;
11520 width=(unsigned int) (*image)->columns;
11521 height=(unsigned int) (*image)->rows;
11522 x=0;
11523 y=0;
11524 if (windows->image.crop_geometry != (char *) NULL)
11525 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11526 &width,&height);
11527 scale_factor=(MagickRealType) width/windows->image.ximage->width;
11528 crop_info.x+=x;
11529 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11530 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11531 scale_factor=(MagickRealType)
11532 height/windows->image.ximage->height;
11533 crop_info.y+=y;
11534 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11535 crop_info.height=(unsigned int)
11536 (scale_factor*crop_info.height+0.5);
11537 roi_image=CropImage(*image,&crop_info,&(*image)->exception);
11538 (void) SetImageProgressMonitor(*image,progress_monitor,
11539 (*image)->client_data);
11540 if (roi_image == (Image *) NULL)
11541 continue;
11542 /*
11543 Apply image processing technique to the region of interest.
11544 */
11545 windows->image.orphan=MagickTrue;
11546 (void) XMagickCommand(display,resource_info,windows,
11547 display_command,&roi_image);
11548 progress_monitor=SetImageProgressMonitor(*image,
11549 (MagickProgressMonitor) NULL,(*image)->client_data);
11550 (void) XMagickCommand(display,resource_info,windows,
11551 SaveToUndoBufferCommand,image);
11552 windows->image.orphan=MagickFalse;
11553 (void) CompositeImage(*image,CopyCompositeOp,roi_image,
11554 crop_info.x,crop_info.y);
11555 roi_image=DestroyImage(roi_image);
11556 (void) SetImageProgressMonitor(*image,progress_monitor,
11557 (*image)->client_data);
11558 break;
11559 }
11560 }
11561 if (display_command != InfoCommand)
11562 {
11563 XConfigureImageColormap(display,resource_info,windows,*image);
11564 (void) XConfigureImage(display,resource_info,windows,*image);
11565 }
11566 XCheckRefreshWindows(display,windows);
11567 XInfoWidget(display,windows,text);
11568 (void) XSetFunction(display,windows->image.highlight_context,
11569 GXinvert);
11570 state&=(~UpdateRegionState);
11571 }
11572 XHighlightRectangle(display,windows->image.id,
11573 windows->image.highlight_context,&highlight_info);
11574 XScreenEvent(display,windows,&event);
11575 if (event.xany.window == windows->command.id)
11576 {
11577 /*
11578 Select a command from the Command widget.
11579 */
11580 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11581 display_command=NullCommand;
11582 id=XCommandWidget(display,windows,ApplyMenu,&event);
11583 if (id >= 0)
11584 {
11585 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11586 display_command=ApplyCommands[id];
11587 if (id < ApplyMenus)
11588 {
11589 /*
11590 Select a command from a pop-up menu.
11591 */
11592 entry=XMenuWidget(display,windows,ApplyMenu[id],
11593 (const char **) Menus[id],command);
11594 if (entry >= 0)
11595 {
11596 (void) CopyMagickString(command,Menus[id][entry],
11597 MaxTextExtent);
11598 display_command=Commands[id][entry];
11599 }
11600 }
11601 }
11602 (void) XSetFunction(display,windows->image.highlight_context,
11603 GXinvert);
11604 XHighlightRectangle(display,windows->image.id,
11605 windows->image.highlight_context,&highlight_info);
11606 if (display_command == HelpCommand)
11607 {
11608 (void) XSetFunction(display,windows->image.highlight_context,
11609 GXcopy);
11610 XTextViewHelp(display,resource_info,windows,MagickFalse,
11611 "Help Viewer - Region of Interest",ImageROIHelp);
11612 (void) XSetFunction(display,windows->image.highlight_context,
11613 GXinvert);
11614 continue;
11615 }
11616 if (display_command == QuitCommand)
11617 {
11618 /*
11619 exit.
11620 */
11621 state|=EscapeState;
11622 state|=ExitState;
11623 continue;
11624 }
11625 if (display_command != NullCommand)
11626 state|=UpdateRegionState;
11627 continue;
11628 }
11629 XHighlightRectangle(display,windows->image.id,
11630 windows->image.highlight_context,&highlight_info);
11631 switch (event.type)
11632 {
11633 case ButtonPress:
11634 {
11635 x=windows->image.x;
11636 y=windows->image.y;
11637 if (event.xbutton.button != Button1)
11638 break;
11639 if (event.xbutton.window != windows->image.id)
11640 break;
11641 x=windows->image.x+event.xbutton.x;
11642 y=windows->image.y+event.xbutton.y;
11643 if ((x < (int) (roi_info.x+RoiDelta)) &&
11644 (x > (int) (roi_info.x-RoiDelta)) &&
11645 (y < (int) (roi_info.y+RoiDelta)) &&
11646 (y > (int) (roi_info.y-RoiDelta)))
11647 {
11648 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
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+RoiDelta)) &&
11654 (x > (int) (roi_info.x-RoiDelta)) &&
11655 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11656 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11657 {
11658 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11659 state|=UpdateConfigurationState;
11660 break;
11661 }
11662 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11663 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11664 (y < (int) (roi_info.y+RoiDelta)) &&
11665 (y > (int) (roi_info.y-RoiDelta)))
11666 {
11667 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11668 state|=UpdateConfigurationState;
11669 break;
11670 }
11671 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11672 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11673 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11674 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11675 {
11676 state|=UpdateConfigurationState;
11677 break;
11678 }
11679 magick_fallthrough;
11680 }
11681 case ButtonRelease:
11682 {
11683 if (event.xbutton.window == windows->pan.id)
11684 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11685 (highlight_info.y != crop_info.y-windows->image.y))
11686 XHighlightRectangle(display,windows->image.id,
11687 windows->image.highlight_context,&highlight_info);
11688 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11689 event.xbutton.time);
11690 break;
11691 }
11692 case Expose:
11693 {
11694 if (event.xexpose.window == windows->image.id)
11695 if (event.xexpose.count == 0)
11696 {
11697 event.xexpose.x=(int) highlight_info.x;
11698 event.xexpose.y=(int) highlight_info.y;
11699 event.xexpose.width=(int) highlight_info.width;
11700 event.xexpose.height=(int) highlight_info.height;
11701 XRefreshWindow(display,&windows->image,&event);
11702 }
11703 if (event.xexpose.window == windows->info.id)
11704 if (event.xexpose.count == 0)
11705 XInfoWidget(display,windows,text);
11706 break;
11707 }
11708 case KeyPress:
11709 {
11710 KeySym
11711 key_symbol;
11712
11713 if (event.xkey.window != windows->image.id)
11714 break;
11715 /*
11716 Respond to a user key press.
11717 */
11718 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11719 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11720 switch ((int) key_symbol)
11721 {
11722 case XK_Shift_L:
11723 case XK_Shift_R:
11724 break;
11725 case XK_Escape:
11726 case XK_F20:
11727 {
11728 state|=EscapeState;
11729 magick_fallthrough;
11730 }
11731 case XK_Return:
11732 {
11733 state|=ExitState;
11734 break;
11735 }
11736 case XK_Home:
11737 case XK_KP_Home:
11738 {
11739 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11740 roi_info.y=(ssize_t) (windows->image.height/2L-
11741 roi_info.height/2L);
11742 break;
11743 }
11744 case XK_Left:
11745 case XK_KP_Left:
11746 {
11747 roi_info.x--;
11748 break;
11749 }
11750 case XK_Up:
11751 case XK_KP_Up:
11752 case XK_Next:
11753 {
11754 roi_info.y--;
11755 break;
11756 }
11757 case XK_Right:
11758 case XK_KP_Right:
11759 {
11760 roi_info.x++;
11761 break;
11762 }
11763 case XK_Prior:
11764 case XK_Down:
11765 case XK_KP_Down:
11766 {
11767 roi_info.y++;
11768 break;
11769 }
11770 case XK_F1:
11771 case XK_Help:
11772 {
11773 (void) XSetFunction(display,windows->image.highlight_context,
11774 GXcopy);
11775 XTextViewHelp(display,resource_info,windows,MagickFalse,
11776 "Help Viewer - Region of Interest",ImageROIHelp);
11777 (void) XSetFunction(display,windows->image.highlight_context,
11778 GXinvert);
11779 break;
11780 }
11781 default:
11782 {
11783 display_command=XImageWindowCommand(display,resource_info,windows,
11784 event.xkey.state,key_symbol,image);
11785 if (display_command != NullCommand)
11786 state|=UpdateRegionState;
11787 break;
11788 }
11789 }
11790 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11791 event.xkey.time);
11792 break;
11793 }
11794 case KeyRelease:
11795 break;
11796 case MotionNotify:
11797 {
11798 if (event.xbutton.window != windows->image.id)
11799 break;
11800 /*
11801 Map and unmap Info widget as text cursor crosses its boundaries.
11802 */
11803 x=event.xmotion.x;
11804 y=event.xmotion.y;
11805 if (windows->info.mapped != MagickFalse)
11806 {
11807 if ((x < (int) (windows->info.x+windows->info.width)) &&
11808 (y < (int) (windows->info.y+windows->info.height)))
11809 (void) XWithdrawWindow(display,windows->info.id,
11810 windows->info.screen);
11811 }
11812 else
11813 if ((x > (int) (windows->info.x+windows->info.width)) ||
11814 (y > (int) (windows->info.y+windows->info.height)))
11815 (void) XMapWindow(display,windows->info.id);
11816 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11817 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11818 break;
11819 }
11820 case SelectionRequest:
11821 {
11822 XSelectionEvent
11823 notify;
11824
11825 XSelectionRequestEvent
11826 *request;
11827
11828 /*
11829 Set primary selection.
11830 */
11831 (void) FormatLocaleString(text,MaxTextExtent,
11832 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11833 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11834 request=(&(event.xselectionrequest));
11835 (void) XChangeProperty(request->display,request->requestor,
11836 request->property,request->target,8,PropModeReplace,
11837 (unsigned char *) text,(int) strlen(text));
11838 notify.type=SelectionNotify;
11839 notify.display=request->display;
11840 notify.requestor=request->requestor;
11841 notify.selection=request->selection;
11842 notify.target=request->target;
11843 notify.time=request->time;
11844 if (request->property == None)
11845 notify.property=request->target;
11846 else
11847 notify.property=request->property;
11848 (void) XSendEvent(request->display,request->requestor,False,0,
11849 (XEvent *) &notify);
11850 }
11851 default:
11852 break;
11853 }
11854 if ((state & UpdateConfigurationState) != 0)
11855 {
11856 (void) XPutBackEvent(display,&event);
11857 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11858 break;
11859 }
11860 } while ((state & ExitState) == 0);
11861 } while ((state & ExitState) == 0);
11862 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11863 XSetCursorState(display,windows,MagickFalse);
11864 if ((state & EscapeState) != 0)
11865 return(MagickTrue);
11866 return(MagickTrue);
11867}
11868
11869/*
11870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11871% %
11872% %
11873% %
11874+ X R o t a t e I m a g e %
11875% %
11876% %
11877% %
11878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11879%
11880% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11881% rotation angle is computed from the slope of a line drawn by the user.
11882%
11883% The format of the XRotateImage method is:
11884%
11885% MagickBooleanType XRotateImage(Display *display,
11886% XResourceInfo *resource_info,XWindows *windows,double degrees,
11887% Image **image)
11888%
11889% A description of each parameter follows:
11890%
11891% o display: Specifies a connection to an X server; returned from
11892% XOpenDisplay.
11893%
11894% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11895%
11896% o windows: Specifies a pointer to a XWindows structure.
11897%
11898% o degrees: Specifies the number of degrees to rotate the image.
11899%
11900% o image: the image.
11901%
11902*/
11903static MagickBooleanType XRotateImage(Display *display,
11904 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
11905{
11906 const char
11907 *const RotateMenu[] =
11908 {
11909 "Pixel Color",
11910 "Direction",
11911 "Help",
11912 "Dismiss",
11913 (char *) NULL
11914 };
11915
11916 static ModeType
11917 direction = HorizontalRotateCommand;
11918
11919 static const ModeType
11920 DirectionCommands[] =
11921 {
11922 HorizontalRotateCommand,
11923 VerticalRotateCommand
11924 },
11925 RotateCommands[] =
11926 {
11927 RotateColorCommand,
11928 RotateDirectionCommand,
11929 RotateHelpCommand,
11930 RotateDismissCommand
11931 };
11932
11933 static unsigned int
11934 pen_id = 0;
11935
11936 char
11937 command[MaxTextExtent],
11938 text[MaxTextExtent];
11939
11940 Image
11941 *rotate_image;
11942
11943 int
11944 id,
11945 x,
11946 y;
11947
11948 MagickRealType
11949 normalized_degrees;
11950
11951 int
11952 i;
11953
11954 unsigned int
11955 height,
11956 rotations,
11957 width;
11958
11959 if (degrees == 0.0)
11960 {
11961 unsigned int
11962 distance;
11963
11964 size_t
11965 state;
11966
11967 XEvent
11968 event;
11969
11970 XSegment
11971 rotate_info;
11972
11973 /*
11974 Map Command widget.
11975 */
11976 (void) CloneString(&windows->command.name,"Rotate");
11977 windows->command.data=2;
11978 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
11979 (void) XMapRaised(display,windows->command.id);
11980 XClientMessage(display,windows->image.id,windows->im_protocols,
11981 windows->im_update_widget,CurrentTime);
11982 /*
11983 Wait for first button press.
11984 */
11985 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11986 XQueryPosition(display,windows->image.id,&x,&y);
11987 rotate_info.x1=x;
11988 rotate_info.y1=y;
11989 rotate_info.x2=x;
11990 rotate_info.y2=y;
11991 state=DefaultState;
11992 do
11993 {
11994 XHighlightLine(display,windows->image.id,
11995 windows->image.highlight_context,&rotate_info);
11996 /*
11997 Wait for next event.
11998 */
11999 XScreenEvent(display,windows,&event);
12000 XHighlightLine(display,windows->image.id,
12001 windows->image.highlight_context,&rotate_info);
12002 if (event.xany.window == windows->command.id)
12003 {
12004 /*
12005 Select a command from the Command widget.
12006 */
12007 id=XCommandWidget(display,windows,RotateMenu,&event);
12008 if (id < 0)
12009 continue;
12010 (void) XSetFunction(display,windows->image.highlight_context,
12011 GXcopy);
12012 switch (RotateCommands[id])
12013 {
12014 case RotateColorCommand:
12015 {
12016 const char
12017 *ColorMenu[MaxNumberPens];
12018
12019 int
12020 pen_number;
12021
12022 XColor
12023 color;
12024
12025 /*
12026 Initialize menu selections.
12027 */
12028 for (i=0; i < (int) (MaxNumberPens-2); i++)
12029 ColorMenu[i]=resource_info->pen_colors[i];
12030 ColorMenu[MaxNumberPens-2]="Browser...";
12031 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12032 /*
12033 Select a pen color from the pop-up menu.
12034 */
12035 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12036 (const char **) ColorMenu,command);
12037 if (pen_number < 0)
12038 break;
12039 if (pen_number == (MaxNumberPens-2))
12040 {
12041 static char
12042 color_name[MaxTextExtent] = "gray";
12043
12044 /*
12045 Select a pen color from a dialog.
12046 */
12047 resource_info->pen_colors[pen_number]=color_name;
12048 XColorBrowserWidget(display,windows,"Select",color_name);
12049 if (*color_name == '\0')
12050 break;
12051 }
12052 /*
12053 Set pen color.
12054 */
12055 (void) XParseColor(display,windows->map_info->colormap,
12056 resource_info->pen_colors[pen_number],&color);
12057 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12058 (unsigned int) MaxColors,&color);
12059 windows->pixel_info->pen_colors[pen_number]=color;
12060 pen_id=(unsigned int) pen_number;
12061 break;
12062 }
12063 case RotateDirectionCommand:
12064 {
12065 const char
12066 *const Directions[] =
12067 {
12068 "horizontal",
12069 "vertical",
12070 (char *) NULL,
12071 };
12072
12073 /*
12074 Select a command from the pop-up menu.
12075 */
12076 id=XMenuWidget(display,windows,RotateMenu[id],
12077 Directions,command);
12078 if (id >= 0)
12079 direction=DirectionCommands[id];
12080 break;
12081 }
12082 case RotateHelpCommand:
12083 {
12084 XTextViewHelp(display,resource_info,windows,MagickFalse,
12085 "Help Viewer - Image Rotation",ImageRotateHelp);
12086 break;
12087 }
12088 case RotateDismissCommand:
12089 {
12090 /*
12091 Prematurely exit.
12092 */
12093 state|=EscapeState;
12094 state|=ExitState;
12095 break;
12096 }
12097 default:
12098 break;
12099 }
12100 (void) XSetFunction(display,windows->image.highlight_context,
12101 GXinvert);
12102 continue;
12103 }
12104 switch (event.type)
12105 {
12106 case ButtonPress:
12107 {
12108 if (event.xbutton.button != Button1)
12109 break;
12110 if (event.xbutton.window != windows->image.id)
12111 break;
12112 /*
12113 exit loop.
12114 */
12115 (void) XSetFunction(display,windows->image.highlight_context,
12116 GXcopy);
12117 rotate_info.x1=event.xbutton.x;
12118 rotate_info.y1=event.xbutton.y;
12119 state|=ExitState;
12120 break;
12121 }
12122 case ButtonRelease:
12123 break;
12124 case Expose:
12125 break;
12126 case KeyPress:
12127 {
12128 char
12129 command[MaxTextExtent];
12130
12131 KeySym
12132 key_symbol;
12133
12134 if (event.xkey.window != windows->image.id)
12135 break;
12136 /*
12137 Respond to a user key press.
12138 */
12139 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12140 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12141 switch ((int) key_symbol)
12142 {
12143 case XK_Escape:
12144 case XK_F20:
12145 {
12146 /*
12147 Prematurely exit.
12148 */
12149 state|=EscapeState;
12150 state|=ExitState;
12151 break;
12152 }
12153 case XK_F1:
12154 case XK_Help:
12155 {
12156 (void) XSetFunction(display,windows->image.highlight_context,
12157 GXcopy);
12158 XTextViewHelp(display,resource_info,windows,MagickFalse,
12159 "Help Viewer - Image Rotation",ImageRotateHelp);
12160 (void) XSetFunction(display,windows->image.highlight_context,
12161 GXinvert);
12162 break;
12163 }
12164 default:
12165 {
12166 (void) XBell(display,0);
12167 break;
12168 }
12169 }
12170 break;
12171 }
12172 case MotionNotify:
12173 {
12174 rotate_info.x1=event.xmotion.x;
12175 rotate_info.y1=event.xmotion.y;
12176 }
12177 }
12178 rotate_info.x2=rotate_info.x1;
12179 rotate_info.y2=rotate_info.y1;
12180 if (direction == HorizontalRotateCommand)
12181 rotate_info.x2+=32;
12182 else
12183 rotate_info.y2-=32;
12184 } while ((state & ExitState) == 0);
12185 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12186 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12187 if ((state & EscapeState) != 0)
12188 return(MagickTrue);
12189 /*
12190 Draw line as pointer moves until the mouse button is released.
12191 */
12192 distance=0;
12193 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12194 state=DefaultState;
12195 do
12196 {
12197 if (distance > 9)
12198 {
12199 /*
12200 Display info and draw rotation line.
12201 */
12202 if (windows->info.mapped == MagickFalse)
12203 (void) XMapWindow(display,windows->info.id);
12204 (void) FormatLocaleString(text,MaxTextExtent," %g",
12205 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12206 XInfoWidget(display,windows,text);
12207 XHighlightLine(display,windows->image.id,
12208 windows->image.highlight_context,&rotate_info);
12209 }
12210 else
12211 if (windows->info.mapped != MagickFalse)
12212 (void) XWithdrawWindow(display,windows->info.id,
12213 windows->info.screen);
12214 /*
12215 Wait for next event.
12216 */
12217 XScreenEvent(display,windows,&event);
12218 if (distance > 9)
12219 XHighlightLine(display,windows->image.id,
12220 windows->image.highlight_context,&rotate_info);
12221 switch (event.type)
12222 {
12223 case ButtonPress:
12224 break;
12225 case ButtonRelease:
12226 {
12227 /*
12228 User has committed to rotation line.
12229 */
12230 rotate_info.x2=event.xbutton.x;
12231 rotate_info.y2=event.xbutton.y;
12232 state|=ExitState;
12233 break;
12234 }
12235 case Expose:
12236 break;
12237 case MotionNotify:
12238 {
12239 rotate_info.x2=event.xmotion.x;
12240 rotate_info.y2=event.xmotion.y;
12241 }
12242 default:
12243 break;
12244 }
12245 /*
12246 Check boundary conditions.
12247 */
12248 if (rotate_info.x2 < 0)
12249 rotate_info.x2=0;
12250 else
12251 if (rotate_info.x2 > (int) windows->image.width)
12252 rotate_info.x2=(short) windows->image.width;
12253 if (rotate_info.y2 < 0)
12254 rotate_info.y2=0;
12255 else
12256 if (rotate_info.y2 > (int) windows->image.height)
12257 rotate_info.y2=(short) windows->image.height;
12258 /*
12259 Compute rotation angle from the slope of the line.
12260 */
12261 degrees=0.0;
12262 distance=(unsigned int)
12263 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12264 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12265 if (distance > 9)
12266 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12267 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12268 } while ((state & ExitState) == 0);
12269 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12270 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12271 if (distance <= 9)
12272 return(MagickTrue);
12273 }
12274 if (direction == VerticalRotateCommand)
12275 degrees-=90.0;
12276 if (degrees == 0.0)
12277 return(MagickTrue);
12278 /*
12279 Rotate image.
12280 */
12281 normalized_degrees=degrees;
12282 while (normalized_degrees < -45.0)
12283 normalized_degrees+=360.0;
12284 for (rotations=0; normalized_degrees > 45.0; rotations++)
12285 normalized_degrees-=90.0;
12286 if (normalized_degrees != 0.0)
12287 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
12288 XSetCursorState(display,windows,MagickTrue);
12289 XCheckRefreshWindows(display,windows);
12290 (*image)->background_color.red=ScaleShortToQuantum(
12291 windows->pixel_info->pen_colors[pen_id].red);
12292 (*image)->background_color.green=ScaleShortToQuantum(
12293 windows->pixel_info->pen_colors[pen_id].green);
12294 (*image)->background_color.blue=ScaleShortToQuantum(
12295 windows->pixel_info->pen_colors[pen_id].blue);
12296 rotate_image=RotateImage(*image,degrees,&(*image)->exception);
12297 XSetCursorState(display,windows,MagickFalse);
12298 if (rotate_image == (Image *) NULL)
12299 return(MagickFalse);
12300 *image=DestroyImage(*image);
12301 *image=rotate_image;
12302 if (windows->image.crop_geometry != (char *) NULL)
12303 {
12304 /*
12305 Rotate crop geometry.
12306 */
12307 width=(unsigned int) (*image)->columns;
12308 height=(unsigned int) (*image)->rows;
12309 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12310 switch (rotations % 4)
12311 {
12312 default:
12313 case 0:
12314 break;
12315 case 1:
12316 {
12317 /*
12318 Rotate 90 degrees.
12319 */
12320 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12321 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12322 (int) height-y,x);
12323 break;
12324 }
12325 case 2:
12326 {
12327 /*
12328 Rotate 180 degrees.
12329 */
12330 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12331 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12332 break;
12333 }
12334 case 3:
12335 {
12336 /*
12337 Rotate 270 degrees.
12338 */
12339 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12340 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12341 break;
12342 }
12343 }
12344 }
12345 if (windows->image.orphan != MagickFalse)
12346 return(MagickTrue);
12347 if (normalized_degrees != 0.0)
12348 {
12349 /*
12350 Update image colormap.
12351 */
12352 windows->image.window_changes.width=(int) (*image)->columns;
12353 windows->image.window_changes.height=(int) (*image)->rows;
12354 if (windows->image.crop_geometry != (char *) NULL)
12355 {
12356 /*
12357 Obtain dimensions of image from crop geometry.
12358 */
12359 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12360 &width,&height);
12361 windows->image.window_changes.width=(int) width;
12362 windows->image.window_changes.height=(int) height;
12363 }
12364 XConfigureImageColormap(display,resource_info,windows,*image);
12365 }
12366 else
12367 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12368 {
12369 windows->image.window_changes.width=windows->image.ximage->height;
12370 windows->image.window_changes.height=windows->image.ximage->width;
12371 }
12372 /*
12373 Update image configuration.
12374 */
12375 (void) XConfigureImage(display,resource_info,windows,*image);
12376 return(MagickTrue);
12377}
12378
12379/*
12380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12381% %
12382% %
12383% %
12384+ X S a v e I m a g e %
12385% %
12386% %
12387% %
12388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12389%
12390% XSaveImage() saves an image to a file.
12391%
12392% The format of the XSaveImage method is:
12393%
12394% MagickBooleanType XSaveImage(Display *display,
12395% XResourceInfo *resource_info,XWindows *windows,Image *image)
12396%
12397% A description of each parameter follows:
12398%
12399% o display: Specifies a connection to an X server; returned from
12400% XOpenDisplay.
12401%
12402% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12403%
12404% o windows: Specifies a pointer to a XWindows structure.
12405%
12406% o image: the image.
12407%
12408*/
12409static MagickBooleanType XSaveImage(Display *display,
12410 XResourceInfo *resource_info,XWindows *windows,Image *image)
12411{
12412 char
12413 filename[MaxTextExtent],
12414 geometry[MaxTextExtent];
12415
12416 Image
12417 *save_image;
12418
12419 ImageInfo
12420 *image_info;
12421
12422 MagickStatusType
12423 status;
12424
12425 /*
12426 Request file name from user.
12427 */
12428 if (resource_info->write_filename != (char *) NULL)
12429 (void) CopyMagickString(filename,resource_info->write_filename,
12430 MaxTextExtent);
12431 else
12432 {
12433 char
12434 path[MaxTextExtent];
12435
12436 int
12437 status;
12438
12439 GetPathComponent(image->filename,HeadPath,path);
12440 GetPathComponent(image->filename,TailPath,filename);
12441 if (*path != '\0')
12442 {
12443 status=chdir(path);
12444 if (status == -1)
12445 (void) ThrowMagickException(&image->exception,GetMagickModule(),
12446 FileOpenError,"UnableToOpenFile","%s",path);
12447 }
12448 }
12449 XFileBrowserWidget(display,windows,"Save",filename);
12450 if (*filename == '\0')
12451 return(MagickTrue);
12452 if (IsPathAccessible(filename) != MagickFalse)
12453 {
12454 int
12455 status;
12456
12457 /*
12458 File exists-- seek user's permission before overwriting.
12459 */
12460 status=XConfirmWidget(display,windows,"Overwrite",filename);
12461 if (status <= 0)
12462 return(MagickTrue);
12463 }
12464 image_info=CloneImageInfo(resource_info->image_info);
12465 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
12466 (void) SetImageInfo(image_info,1,&image->exception);
12467 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12468 (LocaleCompare(image_info->magick,"JPG") == 0))
12469 {
12470 char
12471 quality[MaxTextExtent];
12472
12473 int
12474 status;
12475
12476 /*
12477 Request JPEG quality from user.
12478 */
12479 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
12480 image->quality);
12481 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12482 quality);
12483 if (*quality == '\0')
12484 return(MagickTrue);
12485 image->quality=StringToUnsignedLong(quality);
12486 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12487 }
12488 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12489 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12490 (LocaleCompare(image_info->magick,"PS") == 0) ||
12491 (LocaleCompare(image_info->magick,"PS2") == 0))
12492 {
12493 char
12494 geometry[MaxTextExtent];
12495
12496 const char
12497 *const PageSizes[] =
12498 {
12499 "Letter",
12500 "Tabloid",
12501 "Ledger",
12502 "Legal",
12503 "Statement",
12504 "Executive",
12505 "A3",
12506 "A4",
12507 "A5",
12508 "B4",
12509 "B5",
12510 "Folio",
12511 "Quarto",
12512 "10x14",
12513 (char *) NULL
12514 };
12515
12516 /*
12517 Request page geometry from user.
12518 */
12519 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12520 if (LocaleCompare(image_info->magick,"PDF") == 0)
12521 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
12522 if (image_info->page != (char *) NULL)
12523 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12524 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12525 "Select page geometry:",geometry);
12526 if (*geometry != '\0')
12527 image_info->page=GetPageGeometry(geometry);
12528 }
12529 /*
12530 Apply image transforms.
12531 */
12532 XSetCursorState(display,windows,MagickTrue);
12533 XCheckRefreshWindows(display,windows);
12534 save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
12535 if (save_image == (Image *) NULL)
12536 return(MagickFalse);
12537 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
12538 windows->image.ximage->width,windows->image.ximage->height);
12539 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
12540 /*
12541 Write image.
12542 */
12543 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
12544 status=WriteImage(image_info,save_image);
12545 if (status != MagickFalse)
12546 image->taint=MagickFalse;
12547 save_image=DestroyImage(save_image);
12548 image_info=DestroyImageInfo(image_info);
12549 XSetCursorState(display,windows,MagickFalse);
12550 return(status != 0 ? MagickTrue : MagickFalse);
12551}
12552
12553/*
12554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12555% %
12556% %
12557% %
12558+ X S c r e e n E v e n t %
12559% %
12560% %
12561% %
12562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12563%
12564% XScreenEvent() handles global events associated with the Pan and Magnify
12565% windows.
12566%
12567% The format of the XScreenEvent function is:
12568%
12569% void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12570%
12571% A description of each parameter follows:
12572%
12573% o display: Specifies a pointer to the Display structure; returned from
12574% XOpenDisplay.
12575%
12576% o windows: Specifies a pointer to a XWindows structure.
12577%
12578% o event: Specifies a pointer to a X11 XEvent structure.
12579%
12580%
12581*/
12582
12583#if defined(__cplusplus) || defined(c_plusplus)
12584extern "C" {
12585#endif
12586
12587static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12588{
12589 XWindows
12590 *windows;
12591
12592 magick_unreferenced(display);
12593
12594 windows=(XWindows *) data;
12595 if ((event->type == ClientMessage) &&
12596 (event->xclient.window == windows->image.id))
12597 return(MagickFalse);
12598 return(MagickTrue);
12599}
12600
12601#if defined(__cplusplus) || defined(c_plusplus)
12602}
12603#endif
12604
12605static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
12606{
12607 int
12608 x,
12609 y;
12610
12611 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12612 if (event->xany.window == windows->command.id)
12613 return;
12614 switch (event->type)
12615 {
12616 case ButtonPress:
12617 case ButtonRelease:
12618 {
12619 if ((event->xbutton.button == Button3) &&
12620 (event->xbutton.state & Mod1Mask))
12621 {
12622 /*
12623 Convert Alt-Button3 to Button2.
12624 */
12625 event->xbutton.button=Button2;
12626 event->xbutton.state&=(~Mod1Mask);
12627 }
12628 if (event->xbutton.window == windows->backdrop.id)
12629 {
12630 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12631 event->xbutton.time);
12632 break;
12633 }
12634 if (event->xbutton.window == windows->pan.id)
12635 {
12636 XPanImage(display,windows,event);
12637 break;
12638 }
12639 if (event->xbutton.window == windows->image.id)
12640 if (event->xbutton.button == Button2)
12641 {
12642 /*
12643 Update magnified image.
12644 */
12645 x=event->xbutton.x;
12646 y=event->xbutton.y;
12647 if (x < 0)
12648 x=0;
12649 else
12650 if (x >= (int) windows->image.width)
12651 x=(int) (windows->image.width-1);
12652 windows->magnify.x=(int) windows->image.x+x;
12653 if (y < 0)
12654 y=0;
12655 else
12656 if (y >= (int) windows->image.height)
12657 y=(int) (windows->image.height-1);
12658 windows->magnify.y=windows->image.y+y;
12659 if (windows->magnify.mapped == MagickFalse)
12660 (void) XMapRaised(display,windows->magnify.id);
12661 XMakeMagnifyImage(display,windows);
12662 if (event->type == ButtonRelease)
12663 (void) XWithdrawWindow(display,windows->info.id,
12664 windows->info.screen);
12665 break;
12666 }
12667 break;
12668 }
12669 case ClientMessage:
12670 {
12671 /*
12672 If client window delete message, exit.
12673 */
12674 if (event->xclient.message_type != windows->wm_protocols)
12675 break;
12676 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12677 break;
12678 if (event->xclient.window == windows->magnify.id)
12679 {
12680 (void) XWithdrawWindow(display,windows->magnify.id,
12681 windows->magnify.screen);
12682 break;
12683 }
12684 break;
12685 }
12686 case ConfigureNotify:
12687 {
12688 if (event->xconfigure.window == windows->magnify.id)
12689 {
12690 unsigned int
12691 magnify;
12692
12693 /*
12694 Magnify window has a new configuration.
12695 */
12696 windows->magnify.width=(unsigned int) event->xconfigure.width;
12697 windows->magnify.height=(unsigned int) event->xconfigure.height;
12698 if (windows->magnify.mapped == MagickFalse)
12699 break;
12700 magnify=1;
12701 while ((int) magnify <= event->xconfigure.width)
12702 magnify<<=1;
12703 while ((int) magnify <= event->xconfigure.height)
12704 magnify<<=1;
12705 magnify>>=1;
12706 if (((int) magnify != event->xconfigure.width) ||
12707 ((int) magnify != event->xconfigure.height))
12708 {
12709 XWindowChanges
12710 window_changes;
12711
12712 window_changes.width=(int) magnify;
12713 window_changes.height=(int) magnify;
12714 (void) XReconfigureWMWindow(display,windows->magnify.id,
12715 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12716 &window_changes);
12717 break;
12718 }
12719 XMakeMagnifyImage(display,windows);
12720 break;
12721 }
12722 break;
12723 }
12724 case Expose:
12725 {
12726 if (event->xexpose.window == windows->image.id)
12727 {
12728 XRefreshWindow(display,&windows->image,event);
12729 break;
12730 }
12731 if (event->xexpose.window == windows->pan.id)
12732 if (event->xexpose.count == 0)
12733 {
12734 XDrawPanRectangle(display,windows);
12735 break;
12736 }
12737 if (event->xexpose.window == windows->magnify.id)
12738 if (event->xexpose.count == 0)
12739 {
12740 XMakeMagnifyImage(display,windows);
12741 break;
12742 }
12743 break;
12744 }
12745 case KeyPress:
12746 {
12747 char
12748 command[MaxTextExtent];
12749
12750 KeySym
12751 key_symbol;
12752
12753 if (event->xkey.window != windows->magnify.id)
12754 break;
12755 /*
12756 Respond to a user key press.
12757 */
12758 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12759 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12760 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
12761 break;
12762 }
12763 case MapNotify:
12764 {
12765 if (event->xmap.window == windows->magnify.id)
12766 {
12767 windows->magnify.mapped=MagickTrue;
12768 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12769 break;
12770 }
12771 if (event->xmap.window == windows->info.id)
12772 {
12773 windows->info.mapped=MagickTrue;
12774 break;
12775 }
12776 break;
12777 }
12778 case MotionNotify:
12779 {
12780 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12781 if (event->xmotion.window == windows->image.id)
12782 if (windows->magnify.mapped != MagickFalse)
12783 {
12784 /*
12785 Update magnified image.
12786 */
12787 x=event->xmotion.x;
12788 y=event->xmotion.y;
12789 if (x < 0)
12790 x=0;
12791 else
12792 if (x >= (int) windows->image.width)
12793 x=(int) (windows->image.width-1);
12794 windows->magnify.x=(int) windows->image.x+x;
12795 if (y < 0)
12796 y=0;
12797 else
12798 if (y >= (int) windows->image.height)
12799 y=(int) (windows->image.height-1);
12800 windows->magnify.y=windows->image.y+y;
12801 XMakeMagnifyImage(display,windows);
12802 }
12803 break;
12804 }
12805 case UnmapNotify:
12806 {
12807 if (event->xunmap.window == windows->magnify.id)
12808 {
12809 windows->magnify.mapped=MagickFalse;
12810 break;
12811 }
12812 if (event->xunmap.window == windows->info.id)
12813 {
12814 windows->info.mapped=MagickFalse;
12815 break;
12816 }
12817 break;
12818 }
12819 default:
12820 break;
12821 }
12822}
12823
12824/*
12825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12826% %
12827% %
12828% %
12829+ X S e t C r o p G e o m e t r y %
12830% %
12831% %
12832% %
12833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12834%
12835% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12836% and translates it to a cropping geometry relative to the image.
12837%
12838% The format of the XSetCropGeometry method is:
12839%
12840% void XSetCropGeometry(Display *display,XWindows *windows,
12841% RectangleInfo *crop_info,Image *image)
12842%
12843% A description of each parameter follows:
12844%
12845% o display: Specifies a connection to an X server; returned from
12846% XOpenDisplay.
12847%
12848% o windows: Specifies a pointer to a XWindows structure.
12849%
12850% o crop_info: A pointer to a RectangleInfo that defines a region of the
12851% Image window to crop.
12852%
12853% o image: the image.
12854%
12855*/
12856static void XSetCropGeometry(Display *display,XWindows *windows,
12857 RectangleInfo *crop_info,Image *image)
12858{
12859 char
12860 text[MaxTextExtent];
12861
12862 int
12863 x,
12864 y;
12865
12866 MagickRealType
12867 scale_factor;
12868
12869 unsigned int
12870 height,
12871 width;
12872
12873 if (windows->info.mapped != MagickFalse)
12874 {
12875 /*
12876 Display info on cropping rectangle.
12877 */
12878 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
12879 (double) crop_info->width,(double) crop_info->height,(double)
12880 crop_info->x,(double) crop_info->y);
12881 XInfoWidget(display,windows,text);
12882 }
12883 /*
12884 Cropping geometry is relative to any previous crop geometry.
12885 */
12886 x=0;
12887 y=0;
12888 width=(unsigned int) image->columns;
12889 height=(unsigned int) image->rows;
12890 if (windows->image.crop_geometry != (char *) NULL)
12891 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12892 else
12893 windows->image.crop_geometry=AcquireString((char *) NULL);
12894 /*
12895 Define the crop geometry string from the cropping rectangle.
12896 */
12897 scale_factor=(MagickRealType) width/windows->image.ximage->width;
12898 if (crop_info->x > 0)
12899 x+=(int) (scale_factor*crop_info->x+0.5);
12900 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12901 if (width == 0)
12902 width=1;
12903 scale_factor=(MagickRealType) height/windows->image.ximage->height;
12904 if (crop_info->y > 0)
12905 y+=(int) (scale_factor*crop_info->y+0.5);
12906 height=(unsigned int) (scale_factor*crop_info->height+0.5);
12907 if (height == 0)
12908 height=1;
12909 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
12910 "%ux%u%+d%+d",width,height,x,y);
12911}
12912
12913/*
12914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12915% %
12916% %
12917% %
12918+ X T i l e I m a g e %
12919% %
12920% %
12921% %
12922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12923%
12924% XTileImage() loads or deletes a selected tile from a visual image directory.
12925% The load or delete command is chosen from a menu.
12926%
12927% The format of the XTileImage method is:
12928%
12929% Image *XTileImage(Display *display,XResourceInfo *resource_info,
12930% XWindows *windows,Image *image,XEvent *event)
12931%
12932% A description of each parameter follows:
12933%
12934% o tile_image: XTileImage reads or deletes the tile image
12935% and returns it. A null image is returned if an error occurs.
12936%
12937% o display: Specifies a connection to an X server; returned from
12938% XOpenDisplay.
12939%
12940% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12941%
12942% o windows: Specifies a pointer to a XWindows structure.
12943%
12944% o image: the image; returned from ReadImage.
12945%
12946% o event: Specifies a pointer to a XEvent structure. If it is NULL,
12947% the entire image is refreshed.
12948%
12949*/
12950static Image *XTileImage(Display *display,XResourceInfo *resource_info,
12951 XWindows *windows,Image *image,XEvent *event)
12952{
12953 const char
12954 *const VerbMenu[] =
12955 {
12956 "Load",
12957 "Next",
12958 "Former",
12959 "Delete",
12960 "Update",
12961 (char *) NULL,
12962 };
12963
12964 static const ModeType
12965 TileCommands[] =
12966 {
12967 TileLoadCommand,
12968 TileNextCommand,
12969 TileFormerCommand,
12970 TileDeleteCommand,
12971 TileUpdateCommand
12972 };
12973
12974 char
12975 command[MaxTextExtent],
12976 filename[MaxTextExtent];
12977
12978 Image
12979 *tile_image;
12980
12981 int
12982 id,
12983 status,
12984 tile,
12985 x,
12986 y;
12987
12988 MagickRealType
12989 scale_factor;
12990
12991 char
12992 *p,
12993 *q;
12994
12995 int
12996 i;
12997
12998 unsigned int
12999 height,
13000 width;
13001
13002 /*
13003 Tile image is relative to montage image configuration.
13004 */
13005 x=0;
13006 y=0;
13007 width=(unsigned int) image->columns;
13008 height=(unsigned int) image->rows;
13009 if (windows->image.crop_geometry != (char *) NULL)
13010 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13011 scale_factor=(MagickRealType) width/windows->image.ximage->width;
13012 event->xbutton.x+=windows->image.x;
13013 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13014 scale_factor=(MagickRealType) height/windows->image.ximage->height;
13015 event->xbutton.y+=windows->image.y;
13016 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13017 /*
13018 Determine size and location of each tile in the visual image directory.
13019 */
13020 width=(unsigned int) image->columns;
13021 height=(unsigned int) image->rows;
13022 x=0;
13023 y=0;
13024 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13025 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13026 (event->xbutton.x-x)/width;
13027 if (tile < 0)
13028 {
13029 /*
13030 Button press is outside any tile.
13031 */
13032 (void) XBell(display,0);
13033 return((Image *) NULL);
13034 }
13035 /*
13036 Determine file name from the tile directory.
13037 */
13038 p=image->directory;
13039 for (i=tile; (i != 0) && (*p != '\0'); )
13040 {
13041 if (*p == '\xff')
13042 i--;
13043 p++;
13044 }
13045 if (*p == '\0')
13046 {
13047 /*
13048 Button press is outside any tile.
13049 */
13050 (void) XBell(display,0);
13051 return((Image *) NULL);
13052 }
13053 /*
13054 Select a command from the pop-up menu.
13055 */
13056 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13057 if (id < 0)
13058 return((Image *) NULL);
13059 q=p;
13060 while ((*q != '\xff') && (*q != '\0'))
13061 q++;
13062 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13063 /*
13064 Perform command for the selected tile.
13065 */
13066 XSetCursorState(display,windows,MagickTrue);
13067 XCheckRefreshWindows(display,windows);
13068 tile_image=NewImageList();
13069 switch (TileCommands[id])
13070 {
13071 case TileLoadCommand:
13072 {
13073 /*
13074 Load tile image.
13075 */
13076 XCheckRefreshWindows(display,windows);
13077 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13078 MaxTextExtent);
13079 (void) CopyMagickString(resource_info->image_info->filename,filename,
13080 MaxTextExtent);
13081 tile_image=ReadImage(resource_info->image_info,&image->exception);
13082 CatchException(&image->exception);
13083 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13084 break;
13085 }
13086 case TileNextCommand:
13087 {
13088 /*
13089 Display next image.
13090 */
13091 XClientMessage(display,windows->image.id,windows->im_protocols,
13092 windows->im_next_image,CurrentTime);
13093 break;
13094 }
13095 case TileFormerCommand:
13096 {
13097 /*
13098 Display former image.
13099 */
13100 XClientMessage(display,windows->image.id,windows->im_protocols,
13101 windows->im_former_image,CurrentTime);
13102 break;
13103 }
13104 case TileDeleteCommand:
13105 {
13106 /*
13107 Delete tile image.
13108 */
13109 if (IsPathAccessible(filename) == MagickFalse)
13110 {
13111 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13112 break;
13113 }
13114 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13115 if (status <= 0)
13116 break;
13117 status=ShredFile(filename);
13118 status|=remove_utf8(filename);
13119 if (status != MagickFalse)
13120 {
13121 XNoticeWidget(display,windows,"Unable to delete image file:",
13122 filename);
13123 break;
13124 }
13125 magick_fallthrough;
13126 }
13127 case TileUpdateCommand:
13128 {
13129 ExceptionInfo
13130 *exception;
13131
13132 int
13133 x_offset,
13134 y_offset;
13135
13136 PixelPacket
13137 pixel;
13138
13139 int
13140 j;
13141
13142 PixelPacket
13143 *s;
13144
13145 /*
13146 Ensure all the images exist.
13147 */
13148 tile=0;
13149 for (p=image->directory; *p != '\0'; p++)
13150 {
13151 CacheView
13152 *image_view;
13153
13154 q=p;
13155 while ((*q != '\xff') && (*q != '\0'))
13156 q++;
13157 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13158 p=q;
13159 if (IsPathAccessible(filename) != MagickFalse)
13160 {
13161 tile++;
13162 continue;
13163 }
13164 /*
13165 Overwrite tile with background color.
13166 */
13167 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13168 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13169 exception=(&image->exception);
13170 image_view=AcquireAuthenticCacheView(image,exception);
13171 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
13172 for (i=0; i < (int) height; i++)
13173 {
13174 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13175 y_offset+i,width,1,exception);
13176 if (s == (PixelPacket *) NULL)
13177 break;
13178 for (j=0; j < (int) width; j++)
13179 *s++=pixel;
13180 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13181 break;
13182 }
13183 image_view=DestroyCacheView(image_view);
13184 tile++;
13185 }
13186 windows->image.window_changes.width=(int) image->columns;
13187 windows->image.window_changes.height=(int) image->rows;
13188 XConfigureImageColormap(display,resource_info,windows,image);
13189 (void) XConfigureImage(display,resource_info,windows,image);
13190 break;
13191 }
13192 default:
13193 break;
13194 }
13195 XSetCursorState(display,windows,MagickFalse);
13196 return(tile_image);
13197}
13198
13199/*
13200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13201% %
13202% %
13203% %
13204+ X T r a n s l a t e I m a g e %
13205% %
13206% %
13207% %
13208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13209%
13210% XTranslateImage() translates the image within an Image window by one pixel
13211% as specified by the key symbol. If the image has a `montage string the
13212% translation is respect to the width and height contained within the string.
13213%
13214% The format of the XTranslateImage method is:
13215%
13216% void XTranslateImage(Display *display,XWindows *windows,
13217% Image *image,const KeySym key_symbol)
13218%
13219% A description of each parameter follows:
13220%
13221% o display: Specifies a connection to an X server; returned from
13222% XOpenDisplay.
13223%
13224% o windows: Specifies a pointer to a XWindows structure.
13225%
13226% o image: the image.
13227%
13228% o key_symbol: Specifies a KeySym which indicates which side of the image
13229% to trim.
13230%
13231*/
13232static void XTranslateImage(Display *display,XWindows *windows,
13233 Image *image,const KeySym key_symbol)
13234{
13235 char
13236 text[MaxTextExtent];
13237
13238 int
13239 x,
13240 y;
13241
13242 unsigned int
13243 x_offset,
13244 y_offset;
13245
13246 /*
13247 User specified a pan position offset.
13248 */
13249 x_offset=windows->image.width;
13250 y_offset=windows->image.height;
13251 if (image->montage != (char *) NULL)
13252 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13253 switch ((int) key_symbol)
13254 {
13255 case XK_Home:
13256 case XK_KP_Home:
13257 {
13258 windows->image.x=(int) windows->image.width/2;
13259 windows->image.y=(int) windows->image.height/2;
13260 break;
13261 }
13262 case XK_Left:
13263 case XK_KP_Left:
13264 {
13265 windows->image.x-=x_offset;
13266 break;
13267 }
13268 case XK_Next:
13269 case XK_Up:
13270 case XK_KP_Up:
13271 {
13272 windows->image.y-=y_offset;
13273 break;
13274 }
13275 case XK_Right:
13276 case XK_KP_Right:
13277 {
13278 windows->image.x+=x_offset;
13279 break;
13280 }
13281 case XK_Prior:
13282 case XK_Down:
13283 case XK_KP_Down:
13284 {
13285 windows->image.y+=y_offset;
13286 break;
13287 }
13288 default:
13289 return;
13290 }
13291 /*
13292 Check boundary conditions.
13293 */
13294 if (windows->image.x < 0)
13295 windows->image.x=0;
13296 else
13297 if ((int) (windows->image.x+windows->image.width) >
13298 windows->image.ximage->width)
13299 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13300 if (windows->image.y < 0)
13301 windows->image.y=0;
13302 else
13303 if ((int) (windows->image.y+windows->image.height) >
13304 windows->image.ximage->height)
13305 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13306 /*
13307 Refresh Image window.
13308 */
13309 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
13310 windows->image.width,windows->image.height,windows->image.x,
13311 windows->image.y);
13312 XInfoWidget(display,windows,text);
13313 XCheckRefreshWindows(display,windows);
13314 XDrawPanRectangle(display,windows);
13315 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13316 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13317}
13318
13319/*
13320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13321% %
13322% %
13323% %
13324+ X T r i m I m a g e %
13325% %
13326% %
13327% %
13328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13329%
13330% XTrimImage() trims the edges from the Image window.
13331%
13332% The format of the XTrimImage method is:
13333%
13334% MagickBooleanType XTrimImage(Display *display,
13335% XResourceInfo *resource_info,XWindows *windows,Image *image)
13336%
13337% A description of each parameter follows:
13338%
13339% o display: Specifies a connection to an X server; returned from
13340% XOpenDisplay.
13341%
13342% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13343%
13344% o windows: Specifies a pointer to a XWindows structure.
13345%
13346% o image: the image.
13347%
13348*/
13349static MagickBooleanType XTrimImage(Display *display,
13350 XResourceInfo *resource_info,XWindows *windows,Image *image)
13351{
13352 RectangleInfo
13353 trim_info;
13354
13355 int
13356 x,
13357 y;
13358
13359 size_t
13360 background,
13361 pixel;
13362
13363 /*
13364 Trim edges from image.
13365 */
13366 XSetCursorState(display,windows,MagickTrue);
13367 XCheckRefreshWindows(display,windows);
13368 /*
13369 Crop the left edge.
13370 */
13371 background=XGetPixel(windows->image.ximage,0,0);
13372 trim_info.width=(size_t) windows->image.ximage->width;
13373 for (x=0; x < windows->image.ximage->width; x++)
13374 {
13375 for (y=0; y < windows->image.ximage->height; y++)
13376 {
13377 pixel=XGetPixel(windows->image.ximage,x,y);
13378 if (pixel != background)
13379 break;
13380 }
13381 if (y < windows->image.ximage->height)
13382 break;
13383 }
13384 trim_info.x=(ssize_t) x;
13385 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13386 {
13387 XSetCursorState(display,windows,MagickFalse);
13388 return(MagickFalse);
13389 }
13390 /*
13391 Crop the right edge.
13392 */
13393 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13394 for (x=windows->image.ximage->width-1; x != 0; x--)
13395 {
13396 for (y=0; y < windows->image.ximage->height; y++)
13397 {
13398 pixel=XGetPixel(windows->image.ximage,x,y);
13399 if (pixel != background)
13400 break;
13401 }
13402 if (y < windows->image.ximage->height)
13403 break;
13404 }
13405 trim_info.width=(size_t) (x-trim_info.x+1);
13406 /*
13407 Crop the top edge.
13408 */
13409 background=XGetPixel(windows->image.ximage,0,0);
13410 trim_info.height=(size_t) windows->image.ximage->height;
13411 for (y=0; y < windows->image.ximage->height; y++)
13412 {
13413 for (x=0; x < windows->image.ximage->width; x++)
13414 {
13415 pixel=XGetPixel(windows->image.ximage,x,y);
13416 if (pixel != background)
13417 break;
13418 }
13419 if (x < windows->image.ximage->width)
13420 break;
13421 }
13422 trim_info.y=(ssize_t) y;
13423 /*
13424 Crop the bottom edge.
13425 */
13426 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13427 for (y=windows->image.ximage->height-1; y != 0; y--)
13428 {
13429 for (x=0; x < windows->image.ximage->width; x++)
13430 {
13431 pixel=XGetPixel(windows->image.ximage,x,y);
13432 if (pixel != background)
13433 break;
13434 }
13435 if (x < windows->image.ximage->width)
13436 break;
13437 }
13438 trim_info.height=(size_t) y-trim_info.y+1;
13439 if (((unsigned int) trim_info.width != windows->image.width) ||
13440 ((unsigned int) trim_info.height != windows->image.height))
13441 {
13442 /*
13443 Reconfigure Image window as defined by the trimming rectangle.
13444 */
13445 XSetCropGeometry(display,windows,&trim_info,image);
13446 windows->image.window_changes.width=(int) trim_info.width;
13447 windows->image.window_changes.height=(int) trim_info.height;
13448 (void) XConfigureImage(display,resource_info,windows,image);
13449 }
13450 XSetCursorState(display,windows,MagickFalse);
13451 return(MagickTrue);
13452}
13453
13454/*
13455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13456% %
13457% %
13458% %
13459+ X V i s u a l D i r e c t o r y I m a g e %
13460% %
13461% %
13462% %
13463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13464%
13465% XVisualDirectoryImage() creates a Visual Image Directory.
13466%
13467% The format of the XVisualDirectoryImage method is:
13468%
13469% Image *XVisualDirectoryImage(Display *display,
13470% XResourceInfo *resource_info,XWindows *windows)
13471%
13472% A description of each parameter follows:
13473%
13474% o nexus: Method XVisualDirectoryImage returns a visual image
13475% directory if it can be created successfully. Otherwise a null image
13476% is returned.
13477%
13478% o display: Specifies a connection to an X server; returned from
13479% XOpenDisplay.
13480%
13481% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13482%
13483% o windows: Specifies a pointer to a XWindows structure.
13484%
13485*/
13486static Image *XVisualDirectoryImage(Display *display,
13487 XResourceInfo *resource_info,XWindows *windows)
13488{
13489#define TileImageTag "Scale/Image"
13490#define XClientName "montage"
13491
13492 char
13493 **filelist;
13494
13495 ExceptionInfo
13496 *exception;
13497
13498 Image
13499 *images,
13500 *montage_image,
13501 *next_image,
13502 *thumbnail_image;
13503
13504 ImageInfo
13505 *read_info;
13506
13507 int
13508 number_files;
13509
13510 MagickBooleanType
13511 backdrop;
13512
13513 MagickStatusType
13514 status;
13515
13516 MontageInfo
13517 *montage_info;
13518
13519 RectangleInfo
13520 geometry;
13521
13522 int
13523 i;
13524
13525 static char
13526 filename[MaxTextExtent] = "\0",
13527 filenames[MaxTextExtent] = "*";
13528
13529 XResourceInfo
13530 background_resources;
13531
13532 /*
13533 Request file name from user.
13534 */
13535 XFileBrowserWidget(display,windows,"Directory",filenames);
13536 if (*filenames == '\0')
13537 return((Image *) NULL);
13538 /*
13539 Expand the filenames.
13540 */
13541 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13542 if (filelist == (char **) NULL)
13543 {
13544 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13545 filenames);
13546 return((Image *) NULL);
13547 }
13548 number_files=1;
13549 filelist[0]=filenames;
13550 status=ExpandFilenames(&number_files,&filelist);
13551 if ((status == MagickFalse) || (number_files == 0))
13552 {
13553 if (number_files == 0)
13554 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13555 else
13556 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13557 filenames);
13558 return((Image *) NULL);
13559 }
13560 /*
13561 Set image background resources.
13562 */
13563 background_resources=(*resource_info);
13564 background_resources.window_id=AcquireString("");
13565 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
13566 "0x%lx",windows->image.id);
13567 background_resources.backdrop=MagickTrue;
13568 /*
13569 Read each image and convert them to a tile.
13570 */
13571 backdrop=(windows->visual_info->klass == TrueColor) ||
13572 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
13573 read_info=CloneImageInfo(resource_info->image_info);
13574 (void) SetImageOption(read_info,"jpeg:size","120x120");
13575 (void) CloneString(&read_info->size,DefaultTileGeometry);
13576 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13577 (void *) NULL);
13578 images=NewImageList();
13579 exception=AcquireExceptionInfo();
13580 XSetCursorState(display,windows,MagickTrue);
13581 XCheckRefreshWindows(display,windows);
13582 for (i=0; i < (int) number_files; i++)
13583 {
13584 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13585 filelist[i]=DestroyString(filelist[i]);
13586 *read_info->magick='\0';
13587 next_image=ReadImage(read_info,exception);
13588 CatchException(exception);
13589 if (next_image != (Image *) NULL)
13590 {
13591 (void) DeleteImageProperty(next_image,"label");
13592 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13593 read_info,next_image,DefaultTileLabel));
13594 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13595 exception);
13596 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13597 geometry.height,exception);
13598 if (thumbnail_image != (Image *) NULL)
13599 {
13600 next_image=DestroyImage(next_image);
13601 next_image=thumbnail_image;
13602 }
13603 if (backdrop)
13604 {
13605 (void) XDisplayBackgroundImage(display,&background_resources,
13606 next_image);
13607 XSetCursorState(display,windows,MagickTrue);
13608 }
13609 AppendImageToList(&images,next_image);
13610 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13611 {
13612 MagickBooleanType
13613 proceed;
13614
13615 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13616 (MagickSizeType) number_files);
13617 if (proceed == MagickFalse)
13618 break;
13619 }
13620 }
13621 }
13622 exception=DestroyExceptionInfo(exception);
13623 filelist=(char **) RelinquishMagickMemory(filelist);
13624 if (images == (Image *) NULL)
13625 {
13626 read_info=DestroyImageInfo(read_info);
13627 XSetCursorState(display,windows,MagickFalse);
13628 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13629 return((Image *) NULL);
13630 }
13631 /*
13632 Create the Visual Image Directory.
13633 */
13634 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13635 montage_info->pointsize=10;
13636 if (resource_info->font != (char *) NULL)
13637 (void) CloneString(&montage_info->font,resource_info->font);
13638 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
13639 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13640 images),&images->exception);
13641 images=DestroyImageList(images);
13642 montage_info=DestroyMontageInfo(montage_info);
13643 read_info=DestroyImageInfo(read_info);
13644 XSetCursorState(display,windows,MagickFalse);
13645 if (montage_image == (Image *) NULL)
13646 return(montage_image);
13647 XClientMessage(display,windows->image.id,windows->im_protocols,
13648 windows->im_next_image,CurrentTime);
13649 return(montage_image);
13650}
13651
13652/*
13653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13654% %
13655% %
13656% %
13657% X D i s p l a y B a c k g r o u n d I m a g e %
13658% %
13659% %
13660% %
13661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13662%
13663% XDisplayBackgroundImage() displays an image in the background of a window.
13664%
13665% The format of the XDisplayBackgroundImage method is:
13666%
13667% MagickBooleanType XDisplayBackgroundImage(Display *display,
13668% XResourceInfo *resource_info,Image *image)
13669%
13670% A description of each parameter follows:
13671%
13672% o display: Specifies a connection to an X server; returned from
13673% XOpenDisplay.
13674%
13675% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13676%
13677% o image: the image.
13678%
13679*/
13680MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13681 XResourceInfo *resource_info,Image *image)
13682{
13683 char
13684 geometry[MaxTextExtent],
13685 visual_type[MaxTextExtent];
13686
13687 int
13688 height,
13689 status,
13690 width;
13691
13692 RectangleInfo
13693 geometry_info;
13694
13695 static XPixelInfo
13696 pixel;
13697
13698 static XStandardColormap
13699 *map_info;
13700
13701 static XVisualInfo
13702 *visual_info = (XVisualInfo *) NULL;
13703
13704 static XWindowInfo
13705 window_info;
13706
13707 size_t
13708 delay;
13709
13710 Window
13711 root_window;
13712
13713 XGCValues
13714 context_values;
13715
13716 XResourceInfo
13717 resources;
13718
13719 XWindowAttributes
13720 window_attributes;
13721
13722 /*
13723 Determine target window.
13724 */
13725 assert(image != (Image *) NULL);
13726 assert(image->signature == MagickCoreSignature);
13727 if (IsEventLogging() != MagickFalse)
13728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13729 resources=(*resource_info);
13730 window_info.id=(Window) NULL;
13731 root_window=XRootWindow(display,XDefaultScreen(display));
13732 if (LocaleCompare(resources.window_id,"root") == 0)
13733 window_info.id=root_window;
13734 else
13735 {
13736 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13737 window_info.id=XWindowByID(display,root_window,
13738 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13739 if (window_info.id == (Window) NULL)
13740 window_info.id=XWindowByName(display,root_window,resources.window_id);
13741 }
13742 if (window_info.id == (Window) NULL)
13743 {
13744 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13745 resources.window_id);
13746 }
13747 /*
13748 Determine window visual id.
13749 */
13750 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13751 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13752 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13753 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13754 if (status != 0)
13755 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
13756 XVisualIDFromVisual(window_attributes.visual));
13757 if (visual_info == (XVisualInfo *) NULL)
13758 {
13759 /*
13760 Allocate standard colormap.
13761 */
13762 map_info=XAllocStandardColormap();
13763 if (map_info == (XStandardColormap *) NULL)
13764 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13765 image->filename);
13766 map_info->colormap=(Colormap) NULL;
13767 pixel.pixels=(unsigned long *) NULL;
13768 /*
13769 Initialize visual info.
13770 */
13771 resources.map_type=(char *) NULL;
13772 resources.visual_type=visual_type;
13773 visual_info=XBestVisualInfo(display,map_info,&resources);
13774 if (visual_info == (XVisualInfo *) NULL)
13775 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13776 resources.visual_type);
13777 /*
13778 Initialize window info.
13779 */
13780 window_info.ximage=(XImage *) NULL;
13781 window_info.matte_image=(XImage *) NULL;
13782 window_info.pixmap=(Pixmap) NULL;
13783 window_info.matte_pixmap=(Pixmap) NULL;
13784 }
13785 /*
13786 Free previous root colors.
13787 */
13788 if (window_info.id == root_window)
13789 (void) XDestroyWindowColors(display,root_window);
13790 /*
13791 Initialize Standard Colormap.
13792 */
13793 resources.colormap=SharedColormap;
13794 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
13795 /*
13796 Graphic context superclass.
13797 */
13798 context_values.background=pixel.foreground_color.pixel;
13799 context_values.foreground=pixel.background_color.pixel;
13800 pixel.annotate_context=XCreateGC(display,window_info.id,
13801 (size_t) (GCBackground | GCForeground),&context_values);
13802 if (pixel.annotate_context == (GC) NULL)
13803 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13804 image->filename);
13805 /*
13806 Initialize Image window attributes.
13807 */
13808 window_info.name=AcquireString("\0");
13809 window_info.icon_name=AcquireString("\0");
13810 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13811 &resources,&window_info);
13812 /*
13813 Create the X image.
13814 */
13815 window_info.width=(unsigned int) image->columns;
13816 window_info.height=(unsigned int) image->rows;
13817 if ((image->columns != window_info.width) ||
13818 (image->rows != window_info.height))
13819 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13820 image->filename);
13821 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
13822 window_attributes.width,window_attributes.height);
13823 geometry_info.width=window_info.width;
13824 geometry_info.height=window_info.height;
13825 geometry_info.x=(ssize_t) window_info.x;
13826 geometry_info.y=(ssize_t) window_info.y;
13827 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13828 &geometry_info.width,&geometry_info.height);
13829 window_info.width=(unsigned int) geometry_info.width;
13830 window_info.height=(unsigned int) geometry_info.height;
13831 window_info.x=(int) geometry_info.x;
13832 window_info.y=(int) geometry_info.y;
13833 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13834 window_info.height);
13835 if (status == MagickFalse)
13836 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13837 image->filename);
13838 window_info.x=0;
13839 window_info.y=0;
13840 if (resource_info->debug != MagickFalse)
13841 {
13842 (void) LogMagickEvent(X11Event,GetMagickModule(),
13843 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13844 (double) image->columns,(double) image->rows);
13845 if (image->colors != 0)
13846 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13847 image->colors);
13848 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13849 }
13850 /*
13851 Adjust image dimensions as specified by backdrop or geometry options.
13852 */
13853 width=(int) window_info.width;
13854 height=(int) window_info.height;
13855 if (resources.backdrop != MagickFalse)
13856 {
13857 /*
13858 Center image on window.
13859 */
13860 window_info.x=(window_attributes.width/2)-(window_info.ximage->width/2);
13861 window_info.y=(window_attributes.height/2)-(window_info.ximage->height/2);
13862 width=window_attributes.width;
13863 height=window_attributes.height;
13864 }
13865 if ((resources.image_geometry != (char *) NULL) &&
13866 (*resources.image_geometry != '\0'))
13867 {
13868 char
13869 default_geometry[MaxTextExtent];
13870
13871 int
13872 flags,
13873 gravity;
13874
13875 XSizeHints
13876 *size_hints;
13877
13878 /*
13879 User specified geometry.
13880 */
13881 size_hints=XAllocSizeHints();
13882 if (size_hints == (XSizeHints *) NULL)
13883 ThrowXWindowFatalException(ResourceLimitFatalError,
13884 "MemoryAllocationFailed",image->filename);
13885 size_hints->flags=0L;
13886 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
13887 width,height);
13888 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13889 default_geometry,window_info.border_width,size_hints,&window_info.x,
13890 &window_info.y,&width,&height,&gravity);
13891 if (flags & (XValue | YValue))
13892 {
13893 width=window_attributes.width;
13894 height=window_attributes.height;
13895 }
13896 (void) XFree((void *) size_hints);
13897 }
13898 /*
13899 Create the X pixmap.
13900 */
13901 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
13902 (unsigned int) height,window_info.depth);
13903 if (window_info.pixmap == (Pixmap) NULL)
13904 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
13905 image->filename);
13906 /*
13907 Display pixmap on the window.
13908 */
13909 if (((unsigned int) width > window_info.width) ||
13910 ((unsigned int) height > window_info.height))
13911 (void) XFillRectangle(display,window_info.pixmap,
13912 window_info.annotate_context,0,0,(unsigned int) width,
13913 (unsigned int) height);
13914 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
13915 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
13916 window_info.width,(unsigned int) window_info.height);
13917 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
13918 (void) XClearWindow(display,window_info.id);
13919 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
13920 XDelay(display,delay == 0UL ? 10UL : delay);
13921 (void) XSync(display,MagickFalse);
13922 return(window_info.id == root_window ? MagickTrue : MagickFalse);
13923}
13924
13925/*
13926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13927% %
13928% %
13929% %
13930+ X D i s p l a y I m a g e %
13931% %
13932% %
13933% %
13934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13935%
13936% XDisplayImage() displays an image via X11. A new image is created and
13937% returned if the user interactively transforms the displayed image.
13938%
13939% The format of the XDisplayImage method is:
13940%
13941% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13942% char **argv,int argc,Image **image,size_t *state)
13943%
13944% A description of each parameter follows:
13945%
13946% o nexus: Method XDisplayImage returns an image when the
13947% user chooses 'Open Image' from the command menu or picks a tile
13948% from the image directory. Otherwise a null image is returned.
13949%
13950% o display: Specifies a connection to an X server; returned from
13951% XOpenDisplay.
13952%
13953% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13954%
13955% o argv: Specifies the application's argument list.
13956%
13957% o argc: Specifies the number of arguments.
13958%
13959% o image: Specifies an address to an address of an Image structure;
13960%
13961*/
13962MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
13963 char **argv,int argc,Image **image,size_t *state)
13964{
13965#define MagnifySize 256 /* must be a power of 2 */
13966#define MagickMenus 10
13967#define MagickTitle "Commands"
13968
13969 const char
13970 *const CommandMenu[] =
13971 {
13972 "File",
13973 "Edit",
13974 "View",
13975 "Transform",
13976 "Enhance",
13977 "Effects",
13978 "F/X",
13979 "Image Edit",
13980 "Miscellany",
13981 "Help",
13982 (char *) NULL
13983 },
13984 *const FileMenu[] =
13985 {
13986 "Open...",
13987 "Next",
13988 "Former",
13989 "Select...",
13990 "Save...",
13991 "Print...",
13992 "Delete...",
13993 "New...",
13994 "Visual Directory...",
13995 "Quit",
13996 (char *) NULL
13997 },
13998 *const EditMenu[] =
13999 {
14000 "Undo",
14001 "Redo",
14002 "Cut",
14003 "Copy",
14004 "Paste",
14005 (char *) NULL
14006 },
14007 *const ViewMenu[] =
14008 {
14009 "Half Size",
14010 "Original Size",
14011 "Double Size",
14012 "Resize...",
14013 "Apply",
14014 "Refresh",
14015 "Restore",
14016 (char *) NULL
14017 },
14018 *const TransformMenu[] =
14019 {
14020 "Crop",
14021 "Chop",
14022 "Flop",
14023 "Flip",
14024 "Rotate Right",
14025 "Rotate Left",
14026 "Rotate...",
14027 "Shear...",
14028 "Roll...",
14029 "Trim Edges",
14030 (char *) NULL
14031 },
14032 *const EnhanceMenu[] =
14033 {
14034 "Hue...",
14035 "Saturation...",
14036 "Brightness...",
14037 "Gamma...",
14038 "Spiff",
14039 "Dull",
14040 "Contrast Stretch...",
14041 "Sigmoidal Contrast...",
14042 "Normalize",
14043 "Equalize",
14044 "Negate",
14045 "Grayscale",
14046 "Map...",
14047 "Quantize...",
14048 (char *) NULL
14049 },
14050 *const EffectsMenu[] =
14051 {
14052 "Despeckle",
14053 "Emboss",
14054 "Reduce Noise",
14055 "Add Noise...",
14056 "Sharpen...",
14057 "Blur...",
14058 "Threshold...",
14059 "Edge Detect...",
14060 "Spread...",
14061 "Shade...",
14062 "Raise...",
14063 "Segment...",
14064 (char *) NULL
14065 },
14066 *const FXMenu[] =
14067 {
14068 "Solarize...",
14069 "Sepia Tone...",
14070 "Swirl...",
14071 "Implode...",
14072 "Vignette...",
14073 "Wave...",
14074 "Oil Paint...",
14075 "Charcoal Draw...",
14076 (char *) NULL
14077 },
14078 *const ImageEditMenu[] =
14079 {
14080 "Annotate...",
14081 "Draw...",
14082 "Color...",
14083 "Matte...",
14084 "Composite...",
14085 "Add Border...",
14086 "Add Frame...",
14087 "Comment...",
14088 "Launch...",
14089 "Region of Interest...",
14090 (char *) NULL
14091 },
14092 *const MiscellanyMenu[] =
14093 {
14094 "Image Info",
14095 "Zoom Image",
14096 "Show Preview...",
14097 "Show Histogram",
14098 "Show Matte",
14099 "Background...",
14100 "Slide Show...",
14101 "Preferences...",
14102 (char *) NULL
14103 },
14104 *const HelpMenu[] =
14105 {
14106 "Overview",
14107 "Browse Documentation",
14108 "About Display",
14109 (char *) NULL
14110 },
14111 *const ShortCutsMenu[] =
14112 {
14113 "Next",
14114 "Former",
14115 "Open...",
14116 "Save...",
14117 "Print...",
14118 "Undo",
14119 "Restore",
14120 "Image Info",
14121 "Quit",
14122 (char *) NULL
14123 },
14124 *const VirtualMenu[] =
14125 {
14126 "Image Info",
14127 "Print",
14128 "Next",
14129 "Quit",
14130 (char *) NULL
14131 };
14132
14133 const char
14134 *const *Menus[MagickMenus] =
14135 {
14136 FileMenu,
14137 EditMenu,
14138 ViewMenu,
14139 TransformMenu,
14140 EnhanceMenu,
14141 EffectsMenu,
14142 FXMenu,
14143 ImageEditMenu,
14144 MiscellanyMenu,
14145 HelpMenu
14146 };
14147
14148 static DisplayCommand
14149 CommandMenus[] =
14150 {
14151 NullCommand,
14152 NullCommand,
14153 NullCommand,
14154 NullCommand,
14155 NullCommand,
14156 NullCommand,
14157 NullCommand,
14158 NullCommand,
14159 NullCommand,
14160 NullCommand,
14161 },
14162 FileCommands[] =
14163 {
14164 OpenCommand,
14165 NextCommand,
14166 FormerCommand,
14167 SelectCommand,
14168 SaveCommand,
14169 PrintCommand,
14170 DeleteCommand,
14171 NewCommand,
14172 VisualDirectoryCommand,
14173 QuitCommand
14174 },
14175 EditCommands[] =
14176 {
14177 UndoCommand,
14178 RedoCommand,
14179 CutCommand,
14180 CopyCommand,
14181 PasteCommand
14182 },
14183 ViewCommands[] =
14184 {
14185 HalfSizeCommand,
14186 OriginalSizeCommand,
14187 DoubleSizeCommand,
14188 ResizeCommand,
14189 ApplyCommand,
14190 RefreshCommand,
14191 RestoreCommand
14192 },
14193 TransformCommands[] =
14194 {
14195 CropCommand,
14196 ChopCommand,
14197 FlopCommand,
14198 FlipCommand,
14199 RotateRightCommand,
14200 RotateLeftCommand,
14201 RotateCommand,
14202 ShearCommand,
14203 RollCommand,
14204 TrimCommand
14205 },
14206 EnhanceCommands[] =
14207 {
14208 HueCommand,
14209 SaturationCommand,
14210 BrightnessCommand,
14211 GammaCommand,
14212 SpiffCommand,
14213 DullCommand,
14214 ContrastStretchCommand,
14215 SigmoidalContrastCommand,
14216 NormalizeCommand,
14217 EqualizeCommand,
14218 NegateCommand,
14219 GrayscaleCommand,
14220 MapCommand,
14221 QuantizeCommand
14222 },
14223 EffectsCommands[] =
14224 {
14225 DespeckleCommand,
14226 EmbossCommand,
14227 ReduceNoiseCommand,
14228 AddNoiseCommand,
14229 SharpenCommand,
14230 BlurCommand,
14231 ThresholdCommand,
14232 EdgeDetectCommand,
14233 SpreadCommand,
14234 ShadeCommand,
14235 RaiseCommand,
14236 SegmentCommand
14237 },
14238 FXCommands[] =
14239 {
14240 SolarizeCommand,
14241 SepiaToneCommand,
14242 SwirlCommand,
14243 ImplodeCommand,
14244 VignetteCommand,
14245 WaveCommand,
14246 OilPaintCommand,
14247 CharcoalDrawCommand
14248 },
14249 ImageEditCommands[] =
14250 {
14251 AnnotateCommand,
14252 DrawCommand,
14253 ColorCommand,
14254 MatteCommand,
14255 CompositeCommand,
14256 AddBorderCommand,
14257 AddFrameCommand,
14258 CommentCommand,
14259 LaunchCommand,
14260 RegionOfInterestCommand
14261 },
14262 MiscellanyCommands[] =
14263 {
14264 InfoCommand,
14265 ZoomCommand,
14266 ShowPreviewCommand,
14267 ShowHistogramCommand,
14268 ShowMatteCommand,
14269 BackgroundCommand,
14270 SlideShowCommand,
14271 PreferencesCommand
14272 },
14273 HelpCommands[] =
14274 {
14275 HelpCommand,
14276 BrowseDocumentationCommand,
14277 VersionCommand
14278 },
14279 ShortCutsCommands[] =
14280 {
14281 NextCommand,
14282 FormerCommand,
14283 OpenCommand,
14284 SaveCommand,
14285 PrintCommand,
14286 UndoCommand,
14287 RestoreCommand,
14288 InfoCommand,
14289 QuitCommand
14290 },
14291 VirtualCommands[] =
14292 {
14293 InfoCommand,
14294 PrintCommand,
14295 NextCommand,
14296 QuitCommand
14297 };
14298
14299 static DisplayCommand
14300 *Commands[MagickMenus] =
14301 {
14302 FileCommands,
14303 EditCommands,
14304 ViewCommands,
14305 TransformCommands,
14306 EnhanceCommands,
14307 EffectsCommands,
14308 FXCommands,
14309 ImageEditCommands,
14310 MiscellanyCommands,
14311 HelpCommands
14312 };
14313
14314 char
14315 command[MaxTextExtent],
14316 *directory,
14317 geometry[MaxTextExtent],
14318 resource_name[MaxTextExtent];
14319
14320 DisplayCommand
14321 display_command;
14322
14323 Image
14324 *display_image,
14325 *nexus;
14326
14327 int
14328 entry,
14329 id;
14330
14331 KeySym
14332 key_symbol;
14333
14334 MagickStatusType
14335 context_mask,
14336 status;
14337
14338 RectangleInfo
14339 geometry_info;
14340
14341 int
14342 i;
14343
14344 static char
14345 working_directory[MaxTextExtent];
14346
14347 static XPoint
14348 vid_info;
14349
14350 static XWindowInfo
14351 *magick_windows[MaxXWindows];
14352
14353 static unsigned int
14354 number_windows;
14355
14356 struct stat
14357 attributes;
14358
14359 time_t
14360 timer,
14361 timestamp,
14362 update_time;
14363
14364 unsigned int
14365 height,
14366 width;
14367
14368 size_t
14369 delay;
14370
14371 WarningHandler
14372 warning_handler;
14373
14374 Window
14375 root_window;
14376
14377 XClassHint
14378 *class_hints;
14379
14380 XEvent
14381 event;
14382
14383 XFontStruct
14384 *font_info;
14385
14386 XGCValues
14387 context_values;
14388
14389 XPixelInfo
14390 *icon_pixel,
14391 *pixel;
14392
14393 XResourceInfo
14394 *icon_resources;
14395
14396 XStandardColormap
14397 *icon_map,
14398 *map_info;
14399
14400 XVisualInfo
14401 *icon_visual,
14402 *visual_info;
14403
14404 XWindowChanges
14405 window_changes;
14406
14407 XWindows
14408 *windows;
14409
14410 XWMHints
14411 *manager_hints;
14412
14413 assert(image != (Image **) NULL);
14414 assert((*image)->signature == MagickCoreSignature);
14415 if (IsEventLogging() != MagickFalse)
14416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14417 display_image=(*image);
14418 warning_handler=(WarningHandler) NULL;
14419 windows=XSetWindows((XWindows *) ~0);
14420 if (windows != (XWindows *) NULL)
14421 {
14422 int
14423 status;
14424
14425 if (*working_directory == '\0')
14426 (void) CopyMagickString(working_directory,".",MaxTextExtent);
14427 status=chdir(working_directory);
14428 if (status == -1)
14429 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
14430 FileOpenError,"UnableToOpenFile","%s",working_directory);
14431 warning_handler=resource_info->display_warnings ?
14432 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14433 warning_handler=resource_info->display_warnings ?
14434 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14435 }
14436 else
14437 {
14438 /*
14439 Allocate windows structure.
14440 */
14441 resource_info->colors=display_image->colors;
14442 windows=XSetWindows(XInitializeWindows(display,resource_info));
14443 if (windows == (XWindows *) NULL)
14444 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14445 (*image)->filename);
14446 /*
14447 Initialize window id's.
14448 */
14449 number_windows=0;
14450 magick_windows[number_windows++]=(&windows->icon);
14451 magick_windows[number_windows++]=(&windows->backdrop);
14452 magick_windows[number_windows++]=(&windows->image);
14453 magick_windows[number_windows++]=(&windows->info);
14454 magick_windows[number_windows++]=(&windows->command);
14455 magick_windows[number_windows++]=(&windows->widget);
14456 magick_windows[number_windows++]=(&windows->popup);
14457 magick_windows[number_windows++]=(&windows->magnify);
14458 magick_windows[number_windows++]=(&windows->pan);
14459 for (i=0; i < (int) number_windows; i++)
14460 magick_windows[i]->id=(Window) NULL;
14461 vid_info.x=0;
14462 vid_info.y=0;
14463 }
14464 /*
14465 Initialize font info.
14466 */
14467 if (windows->font_info != (XFontStruct *) NULL)
14468 (void) XFreeFont(display,windows->font_info);
14469 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14470 if (windows->font_info == (XFontStruct *) NULL)
14471 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14472 resource_info->font);
14473 /*
14474 Initialize Standard Colormap.
14475 */
14476 map_info=windows->map_info;
14477 icon_map=windows->icon_map;
14478 visual_info=windows->visual_info;
14479 icon_visual=windows->icon_visual;
14480 pixel=windows->pixel_info;
14481 icon_pixel=windows->icon_pixel;
14482 font_info=windows->font_info;
14483 icon_resources=windows->icon_resources;
14484 class_hints=windows->class_hints;
14485 manager_hints=windows->manager_hints;
14486 root_window=XRootWindow(display,visual_info->screen);
14487 nexus=NewImageList();
14488 if (resource_info->debug != MagickFalse)
14489 {
14490 (void) LogMagickEvent(X11Event,GetMagickModule(),
14491 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14492 (double) display_image->scene,(double) display_image->columns,
14493 (double) display_image->rows);
14494 if (display_image->colors != 0)
14495 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14496 display_image->colors);
14497 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14498 display_image->magick);
14499 }
14500 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14501 map_info,pixel);
14502 display_image->taint=MagickFalse;
14503 /*
14504 Initialize graphic context.
14505 */
14506 windows->context.id=(Window) NULL;
14507 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14508 resource_info,&windows->context);
14509 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14510 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14511 class_hints->res_class[0]=(char) LocaleToUppercase((int)
14512 class_hints->res_class[0]);
14513 manager_hints->flags=InputHint | StateHint;
14514 manager_hints->input=MagickFalse;
14515 manager_hints->initial_state=WithdrawnState;
14516 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14517 &windows->context);
14518 if (resource_info->debug != MagickFalse)
14519 (void) LogMagickEvent(X11Event,GetMagickModule(),
14520 "Window id: 0x%lx (context)",windows->context.id);
14521 context_values.background=pixel->background_color.pixel;
14522 context_values.font=font_info->fid;
14523 context_values.foreground=pixel->foreground_color.pixel;
14524 context_values.graphics_exposures=MagickFalse;
14525 context_mask=(MagickStatusType)
14526 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14527 if (pixel->annotate_context != (GC) NULL)
14528 (void) XFreeGC(display,pixel->annotate_context);
14529 pixel->annotate_context=XCreateGC(display,windows->context.id,
14530 context_mask,&context_values);
14531 if (pixel->annotate_context == (GC) NULL)
14532 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14533 display_image->filename);
14534 context_values.background=pixel->depth_color.pixel;
14535 if (pixel->widget_context != (GC) NULL)
14536 (void) XFreeGC(display,pixel->widget_context);
14537 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14538 &context_values);
14539 if (pixel->widget_context == (GC) NULL)
14540 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14541 display_image->filename);
14542 context_values.background=pixel->foreground_color.pixel;
14543 context_values.foreground=pixel->background_color.pixel;
14544 context_values.plane_mask=context_values.background ^
14545 context_values.foreground;
14546 if (pixel->highlight_context != (GC) NULL)
14547 (void) XFreeGC(display,pixel->highlight_context);
14548 pixel->highlight_context=XCreateGC(display,windows->context.id,
14549 (size_t) (context_mask | GCPlaneMask),&context_values);
14550 if (pixel->highlight_context == (GC) NULL)
14551 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14552 display_image->filename);
14553 (void) XDestroyWindow(display,windows->context.id);
14554 /*
14555 Initialize icon window.
14556 */
14557 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14558 icon_resources,&windows->icon);
14559 windows->icon.geometry=resource_info->icon_geometry;
14560 XBestIconSize(display,&windows->icon,display_image);
14561 windows->icon.attributes.colormap=XDefaultColormap(display,
14562 icon_visual->screen);
14563 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14564 manager_hints->flags=InputHint | StateHint;
14565 manager_hints->input=MagickFalse;
14566 manager_hints->initial_state=IconicState;
14567 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14568 &windows->icon);
14569 if (resource_info->debug != MagickFalse)
14570 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14571 windows->icon.id);
14572 /*
14573 Initialize graphic context for icon window.
14574 */
14575 if (icon_pixel->annotate_context != (GC) NULL)
14576 (void) XFreeGC(display,icon_pixel->annotate_context);
14577 context_values.background=icon_pixel->background_color.pixel;
14578 context_values.foreground=icon_pixel->foreground_color.pixel;
14579 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14580 (size_t) (GCBackground | GCForeground),&context_values);
14581 if (icon_pixel->annotate_context == (GC) NULL)
14582 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14583 display_image->filename);
14584 windows->icon.annotate_context=icon_pixel->annotate_context;
14585 /*
14586 Initialize Image window.
14587 */
14588 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14589 &windows->image);
14590 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14591 if (resource_info->use_shared_memory == MagickFalse)
14592 windows->image.shared_memory=MagickFalse;
14593 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14594 {
14595 char
14596 *title;
14597
14598 title=InterpretImageProperties(resource_info->image_info,display_image,
14599 resource_info->title);
14600 (void) CloneString(&windows->image.name,title);
14601 (void) CloneString(&windows->image.icon_name,title);
14602 title=DestroyString(title);
14603 }
14604 else
14605 {
14606 char
14607 filename[MaxTextExtent],
14608 window_name[MaxTextExtent];
14609
14610 /*
14611 Window name is the base of the filename.
14612 */
14613 GetPathComponent(display_image->magick_filename,TailPath,filename);
14614 if (display_image->scene == 0)
14615 (void) FormatLocaleString(window_name,MaxTextExtent,"%s: %s",
14616 MagickPackageName,filename);
14617 else
14618 (void) FormatLocaleString(window_name,MaxTextExtent,
14619 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14620 (double) display_image->scene,(double) GetImageListLength(
14621 display_image));
14622 (void) CloneString(&windows->image.name,window_name);
14623 (void) CloneString(&windows->image.icon_name,filename);
14624 }
14625 if (resource_info->immutable)
14626 windows->image.immutable=MagickTrue;
14627 windows->image.use_pixmap=resource_info->use_pixmap;
14628 windows->image.geometry=resource_info->image_geometry;
14629 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
14630 XDisplayWidth(display,visual_info->screen),
14631 XDisplayHeight(display,visual_info->screen));
14632 geometry_info.width=display_image->columns;
14633 geometry_info.height=display_image->rows;
14634 geometry_info.x=0;
14635 geometry_info.y=0;
14636 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14637 &geometry_info.width,&geometry_info.height);
14638 windows->image.width=(unsigned int) geometry_info.width;
14639 windows->image.height=(unsigned int) geometry_info.height;
14640 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14641 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14642 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14643 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14644 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14645 resource_info,&windows->backdrop);
14646 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14647 {
14648 /*
14649 Initialize backdrop window.
14650 */
14651 windows->backdrop.x=0;
14652 windows->backdrop.y=0;
14653 (void) CloneString(&windows->backdrop.name,"Backdrop");
14654 windows->backdrop.flags=(size_t) (USSize | USPosition);
14655 windows->backdrop.width=(unsigned int)
14656 XDisplayWidth(display,visual_info->screen);
14657 windows->backdrop.height=(unsigned int)
14658 XDisplayHeight(display,visual_info->screen);
14659 windows->backdrop.border_width=0;
14660 windows->backdrop.immutable=MagickTrue;
14661 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14662 ButtonReleaseMask;
14663 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14664 StructureNotifyMask;
14665 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14666 manager_hints->icon_window=windows->icon.id;
14667 manager_hints->input=MagickTrue;
14668 manager_hints->initial_state=resource_info->iconic ? IconicState :
14669 NormalState;
14670 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14671 &windows->backdrop);
14672 if (resource_info->debug != MagickFalse)
14673 (void) LogMagickEvent(X11Event,GetMagickModule(),
14674 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14675 (void) XMapWindow(display,windows->backdrop.id);
14676 (void) XClearWindow(display,windows->backdrop.id);
14677 if (windows->image.id != (Window) NULL)
14678 {
14679 (void) XDestroyWindow(display,windows->image.id);
14680 windows->image.id=(Window) NULL;
14681 }
14682 /*
14683 Position image in the center the backdrop.
14684 */
14685 windows->image.flags|=USPosition;
14686 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14687 (windows->image.width/2);
14688 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14689 (windows->image.height/2);
14690 }
14691 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14692 manager_hints->icon_window=windows->icon.id;
14693 manager_hints->input=MagickTrue;
14694 manager_hints->initial_state=resource_info->iconic ? IconicState :
14695 NormalState;
14696 if (windows->group_leader.id != (Window) NULL)
14697 {
14698 /*
14699 Follow the leader.
14700 */
14701 manager_hints->flags|=WindowGroupHint;
14702 manager_hints->window_group=windows->group_leader.id;
14703 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14704 if (resource_info->debug != MagickFalse)
14705 (void) LogMagickEvent(X11Event,GetMagickModule(),
14706 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14707 }
14708 XMakeWindow(display,
14709 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14710 argv,argc,class_hints,manager_hints,&windows->image);
14711 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14712 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14713 if (windows->group_leader.id != (Window) NULL)
14714 (void) XSetTransientForHint(display,windows->image.id,
14715 windows->group_leader.id);
14716 if (resource_info->debug != MagickFalse)
14717 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14718 windows->image.id);
14719 /*
14720 Initialize Info widget.
14721 */
14722 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14723 &windows->info);
14724 (void) CloneString(&windows->info.name,"Info");
14725 (void) CloneString(&windows->info.icon_name,"Info");
14726 windows->info.border_width=1;
14727 windows->info.x=2;
14728 windows->info.y=2;
14729 windows->info.flags|=PPosition;
14730 windows->info.attributes.win_gravity=UnmapGravity;
14731 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14732 StructureNotifyMask;
14733 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14734 manager_hints->input=MagickFalse;
14735 manager_hints->initial_state=NormalState;
14736 manager_hints->window_group=windows->image.id;
14737 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14738 &windows->info);
14739 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14740 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14741 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14742 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14743 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14744 if (windows->image.mapped != MagickFalse)
14745 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14746 if (resource_info->debug != MagickFalse)
14747 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14748 windows->info.id);
14749 /*
14750 Initialize Command widget.
14751 */
14752 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14753 resource_info,&windows->command);
14754 windows->command.data=MagickMenus;
14755 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14756 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
14757 resource_info->client_name);
14758 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14759 resource_name,"geometry",(char *) NULL);
14760 (void) CloneString(&windows->command.name,MagickTitle);
14761 windows->command.border_width=0;
14762 windows->command.flags|=PPosition;
14763 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14764 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14765 OwnerGrabButtonMask | StructureNotifyMask;
14766 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14767 manager_hints->input=MagickTrue;
14768 manager_hints->initial_state=NormalState;
14769 manager_hints->window_group=windows->image.id;
14770 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14771 &windows->command);
14772 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14773 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14774 HighlightHeight);
14775 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14776 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14777 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14778 if (windows->command.mapped != MagickFalse)
14779 (void) XMapRaised(display,windows->command.id);
14780 if (resource_info->debug != MagickFalse)
14781 (void) LogMagickEvent(X11Event,GetMagickModule(),
14782 "Window id: 0x%lx (command)",windows->command.id);
14783 /*
14784 Initialize Widget window.
14785 */
14786 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14787 resource_info,&windows->widget);
14788 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
14789 resource_info->client_name);
14790 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14791 resource_name,"geometry",(char *) NULL);
14792 windows->widget.border_width=0;
14793 windows->widget.flags|=PPosition;
14794 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14795 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14796 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14797 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->widget);
14804 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14805 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14806 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14807 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14808 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14809 if (resource_info->debug != MagickFalse)
14810 (void) LogMagickEvent(X11Event,GetMagickModule(),
14811 "Window id: 0x%lx (widget)",windows->widget.id);
14812 /*
14813 Initialize popup window.
14814 */
14815 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14816 resource_info,&windows->popup);
14817 windows->popup.border_width=0;
14818 windows->popup.flags|=PPosition;
14819 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14820 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14821 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14822 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14823 manager_hints->input=MagickTrue;
14824 manager_hints->initial_state=NormalState;
14825 manager_hints->window_group=windows->image.id;
14826 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14827 &windows->popup);
14828 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14829 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14830 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14831 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14832 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14833 if (resource_info->debug != MagickFalse)
14834 (void) LogMagickEvent(X11Event,GetMagickModule(),
14835 "Window id: 0x%lx (pop up)",windows->popup.id);
14836 /*
14837 Initialize Magnify window and cursor.
14838 */
14839 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14840 resource_info,&windows->magnify);
14841 if (resource_info->use_shared_memory == MagickFalse)
14842 windows->magnify.shared_memory=MagickFalse;
14843 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
14844 resource_info->client_name);
14845 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14846 resource_name,"geometry",(char *) NULL);
14847 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
14848 resource_info->magnify);
14849 if (windows->magnify.cursor != (Cursor) NULL)
14850 (void) XFreeCursor(display,windows->magnify.cursor);
14851 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14852 map_info->colormap,resource_info->background_color,
14853 resource_info->foreground_color);
14854 if (windows->magnify.cursor == (Cursor) NULL)
14855 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14856 display_image->filename);
14857 windows->magnify.width=MagnifySize;
14858 windows->magnify.height=MagnifySize;
14859 windows->magnify.flags|=PPosition;
14860 windows->magnify.min_width=MagnifySize;
14861 windows->magnify.min_height=MagnifySize;
14862 windows->magnify.width_inc=MagnifySize;
14863 windows->magnify.height_inc=MagnifySize;
14864 windows->magnify.data=resource_info->magnify;
14865 windows->magnify.attributes.cursor=windows->magnify.cursor;
14866 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14867 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14868 StructureNotifyMask;
14869 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14870 manager_hints->input=MagickTrue;
14871 manager_hints->initial_state=NormalState;
14872 manager_hints->window_group=windows->image.id;
14873 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14874 &windows->magnify);
14875 if (resource_info->debug != MagickFalse)
14876 (void) LogMagickEvent(X11Event,GetMagickModule(),
14877 "Window id: 0x%lx (magnify)",windows->magnify.id);
14878 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14879 /*
14880 Initialize panning window.
14881 */
14882 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14883 resource_info,&windows->pan);
14884 (void) CloneString(&windows->pan.name,"Pan Icon");
14885 windows->pan.width=windows->icon.width;
14886 windows->pan.height=windows->icon.height;
14887 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
14888 resource_info->client_name);
14889 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14890 resource_name,"geometry",(char *) NULL);
14891 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14892 &windows->pan.width,&windows->pan.height);
14893 windows->pan.flags|=PPosition;
14894 windows->pan.immutable=MagickTrue;
14895 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14896 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14897 StructureNotifyMask;
14898 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14899 manager_hints->input=MagickFalse;
14900 manager_hints->initial_state=NormalState;
14901 manager_hints->window_group=windows->image.id;
14902 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14903 &windows->pan);
14904 if (resource_info->debug != MagickFalse)
14905 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
14906 windows->pan.id);
14907 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
14908 if (windows->info.mapped != MagickFalse)
14909 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14910 if ((windows->image.mapped == MagickFalse) ||
14911 (windows->backdrop.id != (Window) NULL))
14912 (void) XMapWindow(display,windows->image.id);
14913 /*
14914 Set our progress monitor and warning handlers.
14915 */
14916 if (warning_handler == (WarningHandler) NULL)
14917 {
14918 warning_handler=resource_info->display_warnings ?
14919 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14920 warning_handler=resource_info->display_warnings ?
14921 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14922 }
14923 /*
14924 Initialize Image and Magnify X images.
14925 */
14926 windows->image.x=0;
14927 windows->image.y=0;
14928 windows->magnify.shape=MagickFalse;
14929 width=(unsigned int) display_image->columns;
14930 height=(unsigned int) display_image->rows;
14931 if ((display_image->columns != width) || (display_image->rows != height))
14932 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14933 display_image->filename);
14934 status=XMakeImage(display,resource_info,&windows->image,display_image,
14935 width,height);
14936 if (status == MagickFalse)
14937 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14938 display_image->filename);
14939 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
14940 windows->magnify.width,windows->magnify.height);
14941 if (status == MagickFalse)
14942 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
14943 display_image->filename);
14944 if (windows->magnify.mapped != MagickFalse)
14945 (void) XMapRaised(display,windows->magnify.id);
14946 if (windows->pan.mapped != MagickFalse)
14947 (void) XMapRaised(display,windows->pan.id);
14948 windows->image.window_changes.width=(int) display_image->columns;
14949 windows->image.window_changes.height=(int) display_image->rows;
14950 (void) XConfigureImage(display,resource_info,windows,display_image);
14951 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14952 (void) XSync(display,MagickFalse);
14953 /*
14954 Respond to events.
14955 */
14956 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
14957 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
14958 update_time=0;
14959 if (resource_info->update != MagickFalse)
14960 {
14961 MagickBooleanType
14962 status;
14963
14964 /*
14965 Determine when file data was last modified.
14966 */
14967 status=GetPathAttributes(display_image->filename,&attributes);
14968 if (status != MagickFalse)
14969 update_time=attributes.st_mtime;
14970 }
14971 *state&=(~FormerImageState);
14972 *state&=(~MontageImageState);
14973 *state&=(~NextImageState);
14974 do
14975 {
14976 /*
14977 Handle a window event.
14978 */
14979 if (windows->image.mapped != MagickFalse)
14980 if ((display_image->delay != 0) || (resource_info->update != 0))
14981 {
14982 if (timer < GetMagickTime())
14983 {
14984 if (resource_info->update == MagickFalse)
14985 *state|=NextImageState | ExitState;
14986 else
14987 {
14988 MagickBooleanType
14989 status;
14990
14991 /*
14992 Determine if image file was modified.
14993 */
14994 status=GetPathAttributes(display_image->filename,&attributes);
14995 if (status != MagickFalse)
14996 if (update_time != attributes.st_mtime)
14997 {
14998 /*
14999 Redisplay image.
15000 */
15001 (void) FormatLocaleString(
15002 resource_info->image_info->filename,MaxTextExtent,
15003 "%s:%s",display_image->magick,
15004 display_image->filename);
15005 nexus=ReadImage(resource_info->image_info,
15006 &display_image->exception);
15007 if (nexus != (Image *) NULL)
15008 *state|=NextImageState | ExitState;
15009 }
15010 delay=display_image->delay/MagickMax(
15011 display_image->ticks_per_second,1L);
15012 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15013 }
15014 }
15015 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15016 {
15017 /*
15018 Do not block if delay > 0.
15019 */
15020 XDelay(display,SuspendTime << 2);
15021 continue;
15022 }
15023 }
15024 timestamp=GetMagickTime();
15025 (void) XNextEvent(display,&event);
15026 if (windows->image.stasis == MagickFalse)
15027 windows->image.stasis=(GetMagickTime()-timestamp) > 0 ?
15028 MagickTrue : MagickFalse;
15029 if (windows->magnify.stasis == MagickFalse)
15030 windows->magnify.stasis=(GetMagickTime()-timestamp) > 0 ?
15031 MagickTrue : MagickFalse;
15032 if (event.xany.window == windows->command.id)
15033 {
15034 /*
15035 Select a command from the Command widget.
15036 */
15037 id=XCommandWidget(display,windows,CommandMenu,&event);
15038 if (id < 0)
15039 continue;
15040 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15041 display_command=CommandMenus[id];
15042 if (id < MagickMenus)
15043 {
15044 /*
15045 Select a command from a pop-up menu.
15046 */
15047 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15048 command);
15049 if (entry < 0)
15050 continue;
15051 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15052 display_command=Commands[id][entry];
15053 }
15054 if (display_command != NullCommand)
15055 nexus=XMagickCommand(display,resource_info,windows,display_command,
15056 &display_image);
15057 continue;
15058 }
15059 switch (event.type)
15060 {
15061 case ButtonPress:
15062 {
15063 if (resource_info->debug != MagickFalse)
15064 (void) LogMagickEvent(X11Event,GetMagickModule(),
15065 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15066 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15067 if ((event.xbutton.button == Button3) &&
15068 (event.xbutton.state & Mod1Mask))
15069 {
15070 /*
15071 Convert Alt-Button3 to Button2.
15072 */
15073 event.xbutton.button=Button2;
15074 event.xbutton.state&=(~Mod1Mask);
15075 }
15076 if (event.xbutton.window == windows->backdrop.id)
15077 {
15078 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15079 event.xbutton.time);
15080 break;
15081 }
15082 if (event.xbutton.window == windows->image.id)
15083 {
15084 switch (event.xbutton.button)
15085 {
15086 case Button1:
15087 {
15088 if (resource_info->immutable)
15089 {
15090 /*
15091 Select a command from the Virtual menu.
15092 */
15093 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15094 command);
15095 if (entry >= 0)
15096 nexus=XMagickCommand(display,resource_info,windows,
15097 VirtualCommands[entry],&display_image);
15098 break;
15099 }
15100 /*
15101 Map/unmap Command widget.
15102 */
15103 if (windows->command.mapped != MagickFalse)
15104 (void) XWithdrawWindow(display,windows->command.id,
15105 windows->command.screen);
15106 else
15107 {
15108 (void) XCommandWidget(display,windows,CommandMenu,
15109 (XEvent *) NULL);
15110 (void) XMapRaised(display,windows->command.id);
15111 }
15112 break;
15113 }
15114 case Button2:
15115 {
15116 /*
15117 User pressed the image magnify button.
15118 */
15119 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15120 &display_image);
15121 XMagnifyImage(display,windows,&event);
15122 break;
15123 }
15124 case Button3:
15125 {
15126 if (resource_info->immutable)
15127 {
15128 /*
15129 Select a command from the Virtual menu.
15130 */
15131 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15132 command);
15133 if (entry >= 0)
15134 nexus=XMagickCommand(display,resource_info,windows,
15135 VirtualCommands[entry],&display_image);
15136 break;
15137 }
15138 if (display_image->montage != (char *) NULL)
15139 {
15140 /*
15141 Open or delete a tile from a visual image directory.
15142 */
15143 nexus=XTileImage(display,resource_info,windows,
15144 display_image,&event);
15145 if (nexus != (Image *) NULL)
15146 *state|=MontageImageState | NextImageState | ExitState;
15147 vid_info.x=(short int) windows->image.x;
15148 vid_info.y=(short int) windows->image.y;
15149 break;
15150 }
15151 /*
15152 Select a command from the Short Cuts menu.
15153 */
15154 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15155 command);
15156 if (entry >= 0)
15157 nexus=XMagickCommand(display,resource_info,windows,
15158 ShortCutsCommands[entry],&display_image);
15159 break;
15160 }
15161 case Button4:
15162 {
15163 /*
15164 Wheel up.
15165 */
15166 XTranslateImage(display,windows,*image,XK_Up);
15167 break;
15168 }
15169 case Button5:
15170 {
15171 /*
15172 Wheel down.
15173 */
15174 XTranslateImage(display,windows,*image,XK_Down);
15175 break;
15176 }
15177 default:
15178 break;
15179 }
15180 break;
15181 }
15182 if (event.xbutton.window == windows->magnify.id)
15183 {
15184 const char
15185 *const MagnifyMenu[] =
15186 {
15187 "2",
15188 "4",
15189 "5",
15190 "6",
15191 "7",
15192 "8",
15193 "9",
15194 "3",
15195 (char *) NULL,
15196 };
15197
15198 int
15199 factor;
15200
15201 static KeySym
15202 MagnifyCommands[] =
15203 {
15204 XK_2,
15205 XK_4,
15206 XK_5,
15207 XK_6,
15208 XK_7,
15209 XK_8,
15210 XK_9,
15211 XK_3
15212 };
15213
15214 /*
15215 Select a magnify factor from the pop-up menu.
15216 */
15217 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15218 if (factor >= 0)
15219 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
15220 break;
15221 }
15222 if (event.xbutton.window == windows->pan.id)
15223 {
15224 switch (event.xbutton.button)
15225 {
15226 case Button4:
15227 {
15228 /*
15229 Wheel up.
15230 */
15231 XTranslateImage(display,windows,*image,XK_Up);
15232 break;
15233 }
15234 case Button5:
15235 {
15236 /*
15237 Wheel down.
15238 */
15239 XTranslateImage(display,windows,*image,XK_Down);
15240 break;
15241 }
15242 default:
15243 {
15244 XPanImage(display,windows,&event);
15245 break;
15246 }
15247 }
15248 break;
15249 }
15250 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15251 1L);
15252 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15253 break;
15254 }
15255 case ButtonRelease:
15256 {
15257 if (resource_info->debug != MagickFalse)
15258 (void) LogMagickEvent(X11Event,GetMagickModule(),
15259 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15260 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15261 break;
15262 }
15263 case ClientMessage:
15264 {
15265 if (resource_info->debug != MagickFalse)
15266 (void) LogMagickEvent(X11Event,GetMagickModule(),
15267 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15268 event.xclient.message_type,event.xclient.format,(unsigned long)
15269 event.xclient.data.l[0]);
15270 if (event.xclient.message_type == windows->im_protocols)
15271 {
15272 if (*event.xclient.data.l == (long) windows->im_update_widget)
15273 {
15274 (void) CloneString(&windows->command.name,MagickTitle);
15275 windows->command.data=MagickMenus;
15276 (void) XCommandWidget(display,windows,CommandMenu,
15277 (XEvent *) NULL);
15278 break;
15279 }
15280 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15281 {
15282 /*
15283 Update graphic context and window colormap.
15284 */
15285 for (i=0; i < (int) number_windows; i++)
15286 {
15287 if (magick_windows[i]->id == windows->icon.id)
15288 continue;
15289 context_values.background=pixel->background_color.pixel;
15290 context_values.foreground=pixel->foreground_color.pixel;
15291 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15292 context_mask,&context_values);
15293 (void) XChangeGC(display,magick_windows[i]->widget_context,
15294 context_mask,&context_values);
15295 context_values.background=pixel->foreground_color.pixel;
15296 context_values.foreground=pixel->background_color.pixel;
15297 context_values.plane_mask=context_values.background ^
15298 context_values.foreground;
15299 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15300 (size_t) (context_mask | GCPlaneMask),
15301 &context_values);
15302 magick_windows[i]->attributes.background_pixel=
15303 pixel->background_color.pixel;
15304 magick_windows[i]->attributes.border_pixel=
15305 pixel->border_color.pixel;
15306 magick_windows[i]->attributes.colormap=map_info->colormap;
15307 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15308 (unsigned long) magick_windows[i]->mask,
15309 &magick_windows[i]->attributes);
15310 }
15311 if (windows->pan.mapped != MagickFalse)
15312 {
15313 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15314 windows->pan.pixmap);
15315 (void) XClearWindow(display,windows->pan.id);
15316 XDrawPanRectangle(display,windows);
15317 }
15318 if (windows->backdrop.id != (Window) NULL)
15319 (void) XInstallColormap(display,map_info->colormap);
15320 break;
15321 }
15322 if (*event.xclient.data.l == (long) windows->im_former_image)
15323 {
15324 *state|=FormerImageState | ExitState;
15325 break;
15326 }
15327 if (*event.xclient.data.l == (long) windows->im_next_image)
15328 {
15329 *state|=NextImageState | ExitState;
15330 break;
15331 }
15332 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15333 {
15334 *state|=RetainColorsState;
15335 break;
15336 }
15337 if (*event.xclient.data.l == (long) windows->im_exit)
15338 {
15339 *state|=ExitState;
15340 break;
15341 }
15342 break;
15343 }
15344 if (event.xclient.message_type == windows->dnd_protocols)
15345 {
15346 Atom
15347 selection,
15348 type;
15349
15350 int
15351 format,
15352 status;
15353
15354 unsigned char
15355 *data;
15356
15357 unsigned long
15358 after,
15359 length;
15360
15361 /*
15362 Display image named by the Drag-and-Drop selection.
15363 */
15364 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15365 break;
15366 selection=XInternAtom(display,"DndSelection",MagickFalse);
15367 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15368 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15369 &length,&after,&data);
15370 if ((status != Success) || (length == 0))
15371 break;
15372 if (*event.xclient.data.l == 2)
15373 {
15374 /*
15375 Offix DND.
15376 */
15377 (void) CopyMagickString(resource_info->image_info->filename,
15378 (char *) data,MaxTextExtent);
15379 }
15380 else
15381 {
15382 /*
15383 XDND.
15384 */
15385 if (strncmp((char *) data, "file:", 5) != 0)
15386 {
15387 (void) XFree((void *) data);
15388 break;
15389 }
15390 (void) CopyMagickString(resource_info->image_info->filename,
15391 ((char *) data)+5,MaxTextExtent);
15392 }
15393 nexus=ReadImage(resource_info->image_info,
15394 &display_image->exception);
15395 CatchException(&display_image->exception);
15396 if (nexus != (Image *) NULL)
15397 *state|=NextImageState | ExitState;
15398 (void) XFree((void *) data);
15399 break;
15400 }
15401 /*
15402 If client window delete message, exit.
15403 */
15404 if (event.xclient.message_type != windows->wm_protocols)
15405 break;
15406 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15407 break;
15408 (void) XWithdrawWindow(display,event.xclient.window,
15409 visual_info->screen);
15410 if (event.xclient.window == windows->image.id)
15411 {
15412 *state|=ExitState;
15413 break;
15414 }
15415 if (event.xclient.window == windows->pan.id)
15416 {
15417 /*
15418 Restore original image size when pan window is deleted.
15419 */
15420 windows->image.window_changes.width=windows->image.ximage->width;
15421 windows->image.window_changes.height=windows->image.ximage->height;
15422 (void) XConfigureImage(display,resource_info,windows,
15423 display_image);
15424 }
15425 break;
15426 }
15427 case ConfigureNotify:
15428 {
15429 if (resource_info->debug != MagickFalse)
15430 (void) LogMagickEvent(X11Event,GetMagickModule(),
15431 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15432 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15433 event.xconfigure.y,event.xconfigure.send_event);
15434 if (event.xconfigure.window == windows->image.id)
15435 {
15436 /*
15437 Image window has a new configuration.
15438 */
15439 if (event.xconfigure.send_event != 0)
15440 {
15441 XWindowChanges
15442 window_changes;
15443
15444 /*
15445 Position the transient windows relative of the Image window.
15446 */
15447 if (windows->command.geometry == (char *) NULL)
15448 if (windows->command.mapped == MagickFalse)
15449 {
15450 windows->command.x=event.xconfigure.x-
15451 windows->command.width-25;
15452 windows->command.y=event.xconfigure.y;
15453 XConstrainWindowPosition(display,&windows->command);
15454 window_changes.x=windows->command.x;
15455 window_changes.y=windows->command.y;
15456 (void) XReconfigureWMWindow(display,windows->command.id,
15457 windows->command.screen,(unsigned int) (CWX | CWY),
15458 &window_changes);
15459 }
15460 if (windows->widget.geometry == (char *) NULL)
15461 if (windows->widget.mapped == MagickFalse)
15462 {
15463 windows->widget.x=event.xconfigure.x+
15464 event.xconfigure.width/10;
15465 windows->widget.y=event.xconfigure.y+
15466 event.xconfigure.height/10;
15467 XConstrainWindowPosition(display,&windows->widget);
15468 window_changes.x=windows->widget.x;
15469 window_changes.y=windows->widget.y;
15470 (void) XReconfigureWMWindow(display,windows->widget.id,
15471 windows->widget.screen,(unsigned int) (CWX | CWY),
15472 &window_changes);
15473 }
15474 if (windows->magnify.geometry == (char *) NULL)
15475 if (windows->magnify.mapped == MagickFalse)
15476 {
15477 windows->magnify.x=event.xconfigure.x+
15478 event.xconfigure.width+25;
15479 windows->magnify.y=event.xconfigure.y;
15480 XConstrainWindowPosition(display,&windows->magnify);
15481 window_changes.x=windows->magnify.x;
15482 window_changes.y=windows->magnify.y;
15483 (void) XReconfigureWMWindow(display,windows->magnify.id,
15484 windows->magnify.screen,(unsigned int) (CWX | CWY),
15485 &window_changes);
15486 }
15487 if (windows->pan.geometry == (char *) NULL)
15488 if (windows->pan.mapped == MagickFalse)
15489 {
15490 windows->pan.x=event.xconfigure.x+
15491 event.xconfigure.width+25;
15492 windows->pan.y=event.xconfigure.y+
15493 windows->magnify.height+50;
15494 XConstrainWindowPosition(display,&windows->pan);
15495 window_changes.x=windows->pan.x;
15496 window_changes.y=windows->pan.y;
15497 (void) XReconfigureWMWindow(display,windows->pan.id,
15498 windows->pan.screen,(unsigned int) (CWX | CWY),
15499 &window_changes);
15500 }
15501 }
15502 if ((event.xconfigure.width == (int) windows->image.width) &&
15503 (event.xconfigure.height == (int) windows->image.height))
15504 break;
15505 windows->image.width=(unsigned int) event.xconfigure.width;
15506 windows->image.height=(unsigned int) event.xconfigure.height;
15507 windows->image.x=0;
15508 windows->image.y=0;
15509 if (display_image->montage != (char *) NULL)
15510 {
15511 windows->image.x=vid_info.x;
15512 windows->image.y=vid_info.y;
15513 }
15514 if ((windows->image.mapped != MagickFalse) &&
15515 (windows->image.stasis != MagickFalse))
15516 {
15517 /*
15518 Update image window configuration.
15519 */
15520 windows->image.window_changes.width=event.xconfigure.width;
15521 windows->image.window_changes.height=event.xconfigure.height;
15522 (void) XConfigureImage(display,resource_info,windows,
15523 display_image);
15524 }
15525 /*
15526 Update pan window configuration.
15527 */
15528 if ((event.xconfigure.width < windows->image.ximage->width) ||
15529 (event.xconfigure.height < windows->image.ximage->height))
15530 {
15531 (void) XMapRaised(display,windows->pan.id);
15532 XDrawPanRectangle(display,windows);
15533 }
15534 else
15535 if (windows->pan.mapped != MagickFalse)
15536 (void) XWithdrawWindow(display,windows->pan.id,
15537 windows->pan.screen);
15538 break;
15539 }
15540 if (event.xconfigure.window == windows->magnify.id)
15541 {
15542 unsigned int
15543 magnify;
15544
15545 /*
15546 Magnify window has a new configuration.
15547 */
15548 windows->magnify.width=(unsigned int) event.xconfigure.width;
15549 windows->magnify.height=(unsigned int) event.xconfigure.height;
15550 if (windows->magnify.mapped == MagickFalse)
15551 break;
15552 magnify=1;
15553 while ((int) magnify <= event.xconfigure.width)
15554 magnify<<=1;
15555 while ((int) magnify <= event.xconfigure.height)
15556 magnify<<=1;
15557 magnify>>=1;
15558 if (((int) magnify != event.xconfigure.width) ||
15559 ((int) magnify != event.xconfigure.height))
15560 {
15561 window_changes.width=(int) magnify;
15562 window_changes.height=(int) magnify;
15563 (void) XReconfigureWMWindow(display,windows->magnify.id,
15564 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15565 &window_changes);
15566 break;
15567 }
15568 if ((windows->magnify.mapped != MagickFalse) &&
15569 (windows->magnify.stasis != MagickFalse))
15570 {
15571 status=XMakeImage(display,resource_info,&windows->magnify,
15572 display_image,windows->magnify.width,windows->magnify.height);
15573 XMakeMagnifyImage(display,windows);
15574 }
15575 break;
15576 }
15577 if ((windows->magnify.mapped != MagickFalse) &&
15578 (event.xconfigure.window == windows->pan.id))
15579 {
15580 /*
15581 Pan icon window has a new configuration.
15582 */
15583 if (event.xconfigure.send_event != 0)
15584 {
15585 windows->pan.x=event.xconfigure.x;
15586 windows->pan.y=event.xconfigure.y;
15587 }
15588 windows->pan.width=(unsigned int) event.xconfigure.width;
15589 windows->pan.height=(unsigned int) event.xconfigure.height;
15590 break;
15591 }
15592 if (event.xconfigure.window == windows->icon.id)
15593 {
15594 /*
15595 Icon window has a new configuration.
15596 */
15597 windows->icon.width=(unsigned int) event.xconfigure.width;
15598 windows->icon.height=(unsigned int) event.xconfigure.height;
15599 break;
15600 }
15601 break;
15602 }
15603 case DestroyNotify:
15604 {
15605 /*
15606 Group leader has exited.
15607 */
15608 if (resource_info->debug != MagickFalse)
15609 (void) LogMagickEvent(X11Event,GetMagickModule(),
15610 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15611 if (event.xdestroywindow.window == windows->group_leader.id)
15612 {
15613 *state|=ExitState;
15614 break;
15615 }
15616 break;
15617 }
15618 case EnterNotify:
15619 {
15620 /*
15621 Selectively install colormap.
15622 */
15623 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15624 if (event.xcrossing.mode != NotifyUngrab)
15625 XInstallColormap(display,map_info->colormap);
15626 break;
15627 }
15628 case Expose:
15629 {
15630 if (resource_info->debug != MagickFalse)
15631 (void) LogMagickEvent(X11Event,GetMagickModule(),
15632 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15633 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15634 event.xexpose.y);
15635 /*
15636 Refresh windows that are now exposed.
15637 */
15638 if ((event.xexpose.window == windows->image.id) &&
15639 (windows->image.mapped != MagickFalse))
15640 {
15641 XRefreshWindow(display,&windows->image,&event);
15642 delay=display_image->delay/MagickMax(
15643 display_image->ticks_per_second,1L);
15644 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15645 break;
15646 }
15647 if ((event.xexpose.window == windows->magnify.id) &&
15648 (windows->magnify.mapped != MagickFalse))
15649 {
15650 XMakeMagnifyImage(display,windows);
15651 break;
15652 }
15653 if (event.xexpose.window == windows->pan.id)
15654 {
15655 XDrawPanRectangle(display,windows);
15656 break;
15657 }
15658 if (event.xexpose.window == windows->icon.id)
15659 {
15660 XRefreshWindow(display,&windows->icon,&event);
15661 break;
15662 }
15663 break;
15664 }
15665 case KeyPress:
15666 {
15667 int
15668 length;
15669
15670 /*
15671 Respond to a user key press.
15672 */
15673 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15674 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15675 *(command+length)='\0';
15676 if (resource_info->debug != MagickFalse)
15677 (void) LogMagickEvent(X11Event,GetMagickModule(),
15678 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15679 key_symbol,command);
15680 if (event.xkey.window == windows->image.id)
15681 {
15682 display_command=XImageWindowCommand(display,resource_info,windows,
15683 event.xkey.state,key_symbol,&display_image);
15684 if (display_command != NullCommand)
15685 nexus=XMagickCommand(display,resource_info,windows,display_command,
15686 &display_image);
15687 }
15688 if (event.xkey.window == windows->magnify.id)
15689 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
15690 if (event.xkey.window == windows->pan.id)
15691 {
15692 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15693 (void) XWithdrawWindow(display,windows->pan.id,
15694 windows->pan.screen);
15695 else
15696 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15697 XTextViewHelp(display,resource_info,windows,MagickFalse,
15698 "Help Viewer - Image Pan",ImagePanHelp);
15699 else
15700 XTranslateImage(display,windows,*image,key_symbol);
15701 }
15702 delay=display_image->delay/MagickMax(
15703 display_image->ticks_per_second,1L);
15704 timer=GetMagickTime()+(delay == 0 ? 1 : delay)+1;
15705 break;
15706 }
15707 case KeyRelease:
15708 {
15709 /*
15710 Respond to a user key release.
15711 */
15712 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15713 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15714 if (resource_info->debug != MagickFalse)
15715 (void) LogMagickEvent(X11Event,GetMagickModule(),
15716 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15717 break;
15718 }
15719 case LeaveNotify:
15720 {
15721 /*
15722 Selectively uninstall colormap.
15723 */
15724 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15725 if (event.xcrossing.mode != NotifyUngrab)
15726 XUninstallColormap(display,map_info->colormap);
15727 break;
15728 }
15729 case MapNotify:
15730 {
15731 if (resource_info->debug != MagickFalse)
15732 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15733 event.xmap.window);
15734 if (event.xmap.window == windows->backdrop.id)
15735 {
15736 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15737 CurrentTime);
15738 windows->backdrop.mapped=MagickTrue;
15739 break;
15740 }
15741 if (event.xmap.window == windows->image.id)
15742 {
15743 if (windows->backdrop.id != (Window) NULL)
15744 (void) XInstallColormap(display,map_info->colormap);
15745 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15746 {
15747 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15748 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15749 }
15750 if (((int) windows->image.width < windows->image.ximage->width) ||
15751 ((int) windows->image.height < windows->image.ximage->height))
15752 (void) XMapRaised(display,windows->pan.id);
15753 windows->image.mapped=MagickTrue;
15754 break;
15755 }
15756 if (event.xmap.window == windows->magnify.id)
15757 {
15758 XMakeMagnifyImage(display,windows);
15759 windows->magnify.mapped=MagickTrue;
15760 (void) XWithdrawWindow(display,windows->info.id,
15761 windows->info.screen);
15762 break;
15763 }
15764 if (event.xmap.window == windows->pan.id)
15765 {
15766 XMakePanImage(display,resource_info,windows,display_image);
15767 windows->pan.mapped=MagickTrue;
15768 break;
15769 }
15770 if (event.xmap.window == windows->info.id)
15771 {
15772 windows->info.mapped=MagickTrue;
15773 break;
15774 }
15775 if (event.xmap.window == windows->icon.id)
15776 {
15777 MagickBooleanType
15778 taint;
15779
15780 /*
15781 Create an icon image.
15782 */
15783 taint=display_image->taint;
15784 XMakeStandardColormap(display,icon_visual,icon_resources,
15785 display_image,icon_map,icon_pixel);
15786 (void) XMakeImage(display,icon_resources,&windows->icon,
15787 display_image,windows->icon.width,windows->icon.height);
15788 display_image->taint=taint;
15789 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15790 windows->icon.pixmap);
15791 (void) XClearWindow(display,windows->icon.id);
15792 (void) XWithdrawWindow(display,windows->info.id,
15793 windows->info.screen);
15794 windows->icon.mapped=MagickTrue;
15795 break;
15796 }
15797 if (event.xmap.window == windows->command.id)
15798 {
15799 windows->command.mapped=MagickTrue;
15800 break;
15801 }
15802 if (event.xmap.window == windows->popup.id)
15803 {
15804 windows->popup.mapped=MagickTrue;
15805 break;
15806 }
15807 if (event.xmap.window == windows->widget.id)
15808 {
15809 windows->widget.mapped=MagickTrue;
15810 break;
15811 }
15812 break;
15813 }
15814 case MappingNotify:
15815 {
15816 (void) XRefreshKeyboardMapping(&event.xmapping);
15817 break;
15818 }
15819 case NoExpose:
15820 break;
15821 case PropertyNotify:
15822 {
15823 Atom
15824 type;
15825
15826 int
15827 format,
15828 status;
15829
15830 unsigned char
15831 *data;
15832
15833 unsigned long
15834 after,
15835 length;
15836
15837 if (resource_info->debug != MagickFalse)
15838 (void) LogMagickEvent(X11Event,GetMagickModule(),
15839 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15840 event.xproperty.atom,event.xproperty.state);
15841 if (event.xproperty.atom != windows->im_remote_command)
15842 break;
15843 /*
15844 Display image named by the remote command protocol.
15845 */
15846 status=XGetWindowProperty(display,event.xproperty.window,
15847 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
15848 AnyPropertyType,&type,&format,&length,&after,&data);
15849 if ((status != Success) || (length == 0))
15850 break;
15851 if (LocaleCompare((char *) data,"-quit") == 0)
15852 {
15853 XClientMessage(display,windows->image.id,windows->im_protocols,
15854 windows->im_exit,CurrentTime);
15855 (void) XFree((void *) data);
15856 break;
15857 }
15858 (void) CopyMagickString(resource_info->image_info->filename,
15859 (char *) data,MaxTextExtent);
15860 (void) XFree((void *) data);
15861 nexus=ReadImage(resource_info->image_info,&display_image->exception);
15862 CatchException(&display_image->exception);
15863 if (nexus != (Image *) NULL)
15864 *state|=NextImageState | ExitState;
15865 break;
15866 }
15867 case ReparentNotify:
15868 {
15869 if (resource_info->debug != MagickFalse)
15870 (void) LogMagickEvent(X11Event,GetMagickModule(),
15871 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15872 event.xreparent.window);
15873 break;
15874 }
15875 case UnmapNotify:
15876 {
15877 if (resource_info->debug != MagickFalse)
15878 (void) LogMagickEvent(X11Event,GetMagickModule(),
15879 "Unmap Notify: 0x%lx",event.xunmap.window);
15880 if (event.xunmap.window == windows->backdrop.id)
15881 {
15882 windows->backdrop.mapped=MagickFalse;
15883 break;
15884 }
15885 if (event.xunmap.window == windows->image.id)
15886 {
15887 windows->image.mapped=MagickFalse;
15888 break;
15889 }
15890 if (event.xunmap.window == windows->magnify.id)
15891 {
15892 windows->magnify.mapped=MagickFalse;
15893 break;
15894 }
15895 if (event.xunmap.window == windows->pan.id)
15896 {
15897 windows->pan.mapped=MagickFalse;
15898 break;
15899 }
15900 if (event.xunmap.window == windows->info.id)
15901 {
15902 windows->info.mapped=MagickFalse;
15903 break;
15904 }
15905 if (event.xunmap.window == windows->icon.id)
15906 {
15907 if (map_info->colormap == icon_map->colormap)
15908 XConfigureImageColormap(display,resource_info,windows,
15909 display_image);
15910 (void) XFreeStandardColormap(display,icon_visual,icon_map,
15911 icon_pixel);
15912 windows->icon.mapped=MagickFalse;
15913 break;
15914 }
15915 if (event.xunmap.window == windows->command.id)
15916 {
15917 windows->command.mapped=MagickFalse;
15918 break;
15919 }
15920 if (event.xunmap.window == windows->popup.id)
15921 {
15922 if (windows->backdrop.id != (Window) NULL)
15923 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15924 CurrentTime);
15925 windows->popup.mapped=MagickFalse;
15926 break;
15927 }
15928 if (event.xunmap.window == windows->widget.id)
15929 {
15930 if (windows->backdrop.id != (Window) NULL)
15931 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
15932 CurrentTime);
15933 windows->widget.mapped=MagickFalse;
15934 break;
15935 }
15936 break;
15937 }
15938 default:
15939 {
15940 if (resource_info->debug != MagickFalse)
15941 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
15942 event.type);
15943 break;
15944 }
15945 }
15946 } while (!(*state & ExitState));
15947 if ((*state & ExitState) == 0)
15948 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
15949 &display_image);
15950 else
15951 if (resource_info->confirm_edit != MagickFalse)
15952 {
15953 /*
15954 Query user if image has changed.
15955 */
15956 if ((resource_info->immutable == MagickFalse) &&
15957 (display_image->taint != MagickFalse))
15958 {
15959 int
15960 status;
15961
15962 status=XConfirmWidget(display,windows,"Your image changed.",
15963 "Do you want to save it");
15964 if (status == 0)
15965 *state&=(~ExitState);
15966 else
15967 if (status > 0)
15968 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
15969 &display_image);
15970 }
15971 }
15972 if ((windows->visual_info->klass == GrayScale) ||
15973 (windows->visual_info->klass == PseudoColor) ||
15974 (windows->visual_info->klass == DirectColor))
15975 {
15976 /*
15977 Withdraw pan and Magnify window.
15978 */
15979 if (windows->info.mapped != MagickFalse)
15980 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15981 if (windows->magnify.mapped != MagickFalse)
15982 (void) XWithdrawWindow(display,windows->magnify.id,
15983 windows->magnify.screen);
15984 if (windows->command.mapped != MagickFalse)
15985 (void) XWithdrawWindow(display,windows->command.id,
15986 windows->command.screen);
15987 }
15988 if (windows->pan.mapped != MagickFalse)
15989 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
15990 if (resource_info->backdrop == MagickFalse)
15991 if (windows->backdrop.mapped)
15992 {
15993 (void) XWithdrawWindow(display,windows->backdrop.id,
15994 windows->backdrop.screen);
15995 (void) XDestroyWindow(display,windows->backdrop.id);
15996 windows->backdrop.id=(Window) NULL;
15997 (void) XWithdrawWindow(display,windows->image.id,
15998 windows->image.screen);
15999 (void) XDestroyWindow(display,windows->image.id);
16000 windows->image.id=(Window) NULL;
16001 }
16002 XSetCursorState(display,windows,MagickTrue);
16003 XCheckRefreshWindows(display,windows);
16004 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16005 *state&=(~ExitState);
16006 if (*state & ExitState)
16007 {
16008 /*
16009 Free Standard Colormap.
16010 */
16011 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16012 if (resource_info->map_type == (char *) NULL)
16013 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16014 /*
16015 Free X resources.
16016 */
16017 if (resource_info->copy_image != (Image *) NULL)
16018 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16019 DestroyXResources();
16020 }
16021 (void) XSync(display,MagickFalse);
16022 /*
16023 Restore our progress monitor and warning handlers.
16024 */
16025 (void) SetErrorHandler(warning_handler);
16026 (void) SetWarningHandler(warning_handler);
16027 /*
16028 Change to home directory.
16029 */
16030 directory=getcwd(working_directory,MaxTextExtent);
16031 (void) directory;
16032 {
16033 int
16034 status;
16035
16036 if (*resource_info->home_directory == '\0')
16037 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent);
16038 status=chdir(resource_info->home_directory);
16039 if (status == -1)
16040 (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
16041 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
16042 }
16043 *image=display_image;
16044 return(nexus);
16045}
16046#else
16047
16048/*
16049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16050% %
16051% %
16052% %
16053+ D i s p l a y I m a g e s %
16054% %
16055% %
16056% %
16057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16058%
16059% DisplayImages() displays an image sequence to any X window screen. It
16060% returns a value other than 0 if successful. Check the exception member
16061% of image to determine the reason for any failure.
16062%
16063% The format of the DisplayImages method is:
16064%
16065% MagickBooleanType DisplayImages(const ImageInfo *image_info,
16066% Image *images)
16067%
16068% A description of each parameter follows:
16069%
16070% o image_info: the image info.
16071%
16072% o image: the image.
16073%
16074*/
16075MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16076 Image *image)
16077{
16078 assert(image_info != (const ImageInfo *) NULL);
16079 assert(image_info->signature == MagickCoreSignature);
16080 assert(image != (Image *) NULL);
16081 assert(image->signature == MagickCoreSignature);
16082 if (IsEventLogging() != MagickFalse)
16083 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16084 (void) image_info;
16085 (void) ThrowMagickException(&image->exception,GetMagickModule(),
16086 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
16087 image->filename);
16088 return(MagickFalse);
16089}
16090
16091/*
16092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16093% %
16094% %
16095% %
16096+ R e m o t e D i s p l a y C o m m a n d %
16097% %
16098% %
16099% %
16100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16101%
16102% RemoteDisplayCommand() encourages a remote display program to display the
16103% specified image filename.
16104%
16105% The format of the RemoteDisplayCommand method is:
16106%
16107% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16108% const char *window,const char *filename,ExceptionInfo *exception)
16109%
16110% A description of each parameter follows:
16111%
16112% o image_info: the image info.
16113%
16114% o window: Specifies the name or id of an X window.
16115%
16116% o filename: the name of the image filename to display.
16117%
16118% o exception: return any errors or warnings in this structure.
16119%
16120*/
16121MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16122 const char *window,const char *filename,ExceptionInfo *exception)
16123{
16124 assert(image_info != (const ImageInfo *) NULL);
16125 assert(image_info->signature == MagickCoreSignature);
16126 assert(filename != (char *) NULL);
16127 if (IsEventLogging() != MagickFalse)
16128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16129 (void) window;
16130 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16131 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
16132 return(MagickFalse);
16133}
16134#endif