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