display.c revision 63240888c3975789a09c2494a4654b523931df96
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% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 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% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/client.h" 47#include "MagickCore/color.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/composite.h" 50#include "MagickCore/constitute.h" 51#include "MagickCore/decorate.h" 52#include "MagickCore/delegate.h" 53#include "MagickCore/display.h" 54#include "MagickCore/display-private.h" 55#include "MagickCore/draw.h" 56#include "MagickCore/effect.h" 57#include "MagickCore/enhance.h" 58#include "MagickCore/exception.h" 59#include "MagickCore/exception-private.h" 60#include "MagickCore/fx.h" 61#include "MagickCore/geometry.h" 62#include "MagickCore/image.h" 63#include "MagickCore/image-private.h" 64#include "MagickCore/list.h" 65#include "MagickCore/log.h" 66#include "MagickCore/magick.h" 67#include "MagickCore/memory_.h" 68#include "MagickCore/monitor.h" 69#include "MagickCore/monitor-private.h" 70#include "MagickCore/montage.h" 71#include "MagickCore/option.h" 72#include "MagickCore/paint.h" 73#include "MagickCore/pixel.h" 74#include "MagickCore/pixel-accessor.h" 75#include "MagickCore/PreRvIcccm.h" 76#include "MagickCore/property.h" 77#include "MagickCore/quantum.h" 78#include "MagickCore/quantum-private.h" 79#include "MagickCore/resize.h" 80#include "MagickCore/resource_.h" 81#include "MagickCore/shear.h" 82#include "MagickCore/segment.h" 83#include "MagickCore/string_.h" 84#include "MagickCore/string-private.h" 85#include "MagickCore/transform.h" 86#include "MagickCore/threshold.h" 87#include "MagickCore/utility.h" 88#include "MagickCore/version.h" 89#include "MagickCore/widget.h" 90#include "MagickCore/xwindow-private.h" 91 92#if defined(MAGICKCORE_X11_DELEGATE) 93/* 94 Define declarations. 95*/ 96#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 97 98/* 99 Constant declarations. 100*/ 101static const unsigned char 102 HighlightBitmap[8] = 103 { 104 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 105 }, 106 OpaqueBitmap[8] = 107 { 108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 109 }, 110 ShadowBitmap[8] = 111 { 112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 113 }; 114 115static const char 116 *PageSizes[] = 117 { 118 "Letter", 119 "Tabloid", 120 "Ledger", 121 "Legal", 122 "Statement", 123 "Executive", 124 "A3", 125 "A4", 126 "A5", 127 "B4", 128 "B5", 129 "Folio", 130 "Quarto", 131 "10x14", 132 (char *) NULL 133 }; 134 135/* 136 Help widget declarations. 137*/ 138static const char 139 *ImageAnnotateHelp[] = 140 { 141 "In annotate mode, the Command widget has these options:", 142 "", 143 " Font Name", 144 " fixed", 145 " variable", 146 " 5x8", 147 " 6x10", 148 " 7x13bold", 149 " 8x13bold", 150 " 9x15bold", 151 " 10x20", 152 " 12x24", 153 " Browser...", 154 " Font Color", 155 " black", 156 " blue", 157 " cyan", 158 " green", 159 " gray", 160 " red", 161 " magenta", 162 " yellow", 163 " white", 164 " transparent", 165 " Browser...", 166 " Font Color", 167 " black", 168 " blue", 169 " cyan", 170 " green", 171 " gray", 172 " red", 173 " magenta", 174 " yellow", 175 " white", 176 " transparent", 177 " Browser...", 178 " Rotate Text", 179 " -90", 180 " -45", 181 " -30", 182 " 0", 183 " 30", 184 " 45", 185 " 90", 186 " 180", 187 " Dialog...", 188 " Help", 189 " Dismiss", 190 "", 191 "Choose a font name from the Font Name sub-menu. Additional", 192 "font names can be specified with the font browser. You can", 193 "change the menu names by setting the X resources font1", 194 "through font9.", 195 "", 196 "Choose a font color from the Font Color sub-menu.", 197 "Additional font colors can be specified with the color", 198 "browser. You can change the menu colors by setting the X", 199 "resources pen1 through pen9.", 200 "", 201 "If you select the color browser and press Grab, you can", 202 "choose the font color by moving the pointer to the desired", 203 "color on the screen and press any button.", 204 "", 205 "If you choose to rotate the text, choose Rotate Text from the", 206 "menu and select an angle. Typically you will only want to", 207 "rotate one line of text at a time. Depending on the angle you", 208 "choose, subsequent lines may end up overwriting each other.", 209 "", 210 "Choosing a font and its color is optional. The default font", 211 "is fixed and the default color is black. However, you must", 212 "choose a location to begin entering text and press button 1.", 213 "An underscore character will appear at the location of the", 214 "pointer. The cursor changes to a pencil to indicate you are", 215 "in text mode. To exit immediately, press Dismiss.", 216 "", 217 "In text mode, any key presses will display the character at", 218 "the location of the underscore and advance the underscore", 219 "cursor. Enter your text and once completed press Apply to", 220 "finish your image annotation. To correct errors press BACK", 221 "SPACE. To delete an entire line of text, press DELETE. Any", 222 "text that exceeds the boundaries of the image window is", 223 "automagically continued onto the next line.", 224 "", 225 "The actual color you request for the font is saved in the", 226 "image. However, the color that appears in your image window", 227 "may be different. For example, on a monochrome screen the", 228 "text will appear black or white even if you choose the color", 229 "red as the font color. However, the image saved to a file", 230 "with -write is written with red lettering. To assure the", 231 "correct color text in the final image, any PseudoClass image", 232 "is promoted to DirectClass (see miff(5)). To force a", 233 "PseudoClass image to remain PseudoClass, use -colors.", 234 (char *) NULL, 235 }, 236 *ImageChopHelp[] = 237 { 238 "In chop mode, the Command widget has these options:", 239 "", 240 " Direction", 241 " horizontal", 242 " vertical", 243 " Help", 244 " Dismiss", 245 "", 246 "If the you choose the horizontal direction (this the", 247 "default), the area of the image between the two horizontal", 248 "endpoints of the chop line is removed. Otherwise, the area", 249 "of the image between the two vertical endpoints of the chop", 250 "line is removed.", 251 "", 252 "Select a location within the image window to begin your chop,", 253 "press and hold any button. Next, move the pointer to", 254 "another location in the image. As you move a line will", 255 "connect the initial location and the pointer. When you", 256 "release the button, the area within the image to chop is", 257 "determined by which direction you choose from the Command", 258 "widget.", 259 "", 260 "To cancel the image chopping, move the pointer back to the", 261 "starting point of the line and release the button.", 262 (char *) NULL, 263 }, 264 *ImageColorEditHelp[] = 265 { 266 "In color edit mode, the Command widget has these options:", 267 "", 268 " Method", 269 " point", 270 " replace", 271 " floodfill", 272 " filltoborder", 273 " reset", 274 " Pixel Color", 275 " black", 276 " blue", 277 " cyan", 278 " green", 279 " gray", 280 " red", 281 " magenta", 282 " yellow", 283 " white", 284 " Browser...", 285 " Border Color", 286 " black", 287 " blue", 288 " cyan", 289 " green", 290 " gray", 291 " red", 292 " magenta", 293 " yellow", 294 " white", 295 " Browser...", 296 " Fuzz", 297 " 0%", 298 " 2%", 299 " 5%", 300 " 10%", 301 " 15%", 302 " Dialog...", 303 " Undo", 304 " Help", 305 " Dismiss", 306 "", 307 "Choose a color editing method from the Method sub-menu", 308 "of the Command widget. The point method recolors any pixel", 309 "selected with the pointer until the button is released. The", 310 "replace method recolors any pixel that matches the color of", 311 "the pixel you select with a button press. Floodfill recolors", 312 "any pixel that matches the color of the pixel you select with", 313 "a button press and is a neighbor. Whereas filltoborder recolors", 314 "any neighbor pixel that is not the border color. Finally reset", 315 "changes the entire image to the designated color.", 316 "", 317 "Next, choose a pixel color from the Pixel Color sub-menu.", 318 "Additional pixel colors can be specified with the color", 319 "browser. You can change the menu colors by setting the X", 320 "resources pen1 through pen9.", 321 "", 322 "Now press button 1 to select a pixel within the image window", 323 "to change its color. Additional pixels may be recolored as", 324 "prescribed by the method you choose.", 325 "", 326 "If the Magnify widget is mapped, it can be helpful in positioning", 327 "your pointer within the image (refer to button 2).", 328 "", 329 "The actual color you request for the pixels is saved in the", 330 "image. However, the color that appears in your image window", 331 "may be different. For example, on a monochrome screen the", 332 "pixel will appear black or white even if you choose the", 333 "color red as the pixel color. However, the image saved to a", 334 "file with -write is written with red pixels. To assure the", 335 "correct color text in the final image, any PseudoClass image", 336 "is promoted to DirectClass (see miff(5)). To force a", 337 "PseudoClass image to remain PseudoClass, use -colors.", 338 (char *) NULL, 339 }, 340 *ImageCompositeHelp[] = 341 { 342 "First a widget window is displayed requesting you to enter an", 343 "image name. Press Composite, Grab or type a file name.", 344 "Press Cancel if you choose not to create a composite image.", 345 "When you choose Grab, move the pointer to the desired window", 346 "and press any button.", 347 "", 348 "If the Composite image does not have any matte information,", 349 "you are informed and the file browser is displayed again.", 350 "Enter the name of a mask image. The image is typically", 351 "grayscale and the same size as the composite image. If the", 352 "image is not grayscale, it is converted to grayscale and the", 353 "resulting intensities are used as matte information.", 354 "", 355 "A small window appears showing the location of the cursor in", 356 "the image window. You are now in composite mode. To exit", 357 "immediately, press Dismiss. In composite mode, the Command", 358 "widget has these options:", 359 "", 360 " Operators", 361 " Over", 362 " In", 363 " Out", 364 " Atop", 365 " Xor", 366 " Plus", 367 " Minus", 368 " Add", 369 " Subtract", 370 " Difference", 371 " Multiply", 372 " Bumpmap", 373 " Copy", 374 " CopyRed", 375 " CopyGreen", 376 " CopyBlue", 377 " CopyOpacity", 378 " Clear", 379 " Dissolve", 380 " Displace", 381 " Help", 382 " Dismiss", 383 "", 384 "Choose a composite operation from the Operators sub-menu of", 385 "the Command widget. How each operator behaves is described", 386 "below. Image window is the image currently displayed on", 387 "your X server and image is the image obtained with the File", 388 "Browser widget.", 389 "", 390 "Over The result is the union of the two image shapes,", 391 " with image obscuring image window in the region of", 392 " overlap.", 393 "", 394 "In The result is simply image cut by the shape of", 395 " image window. None of the image data of image", 396 " window is in the result.", 397 "", 398 "Out The resulting image is image with the shape of", 399 " image window cut out.", 400 "", 401 "Atop The result is the same shape as image image window,", 402 " with image obscuring image window where the image", 403 " shapes overlap. Note this differs from over", 404 " because the portion of image outside image window's", 405 " shape does not appear in the result.", 406 "", 407 "Xor The result is the image data from both image and", 408 " image window that is outside the overlap region.", 409 " The overlap region is blank.", 410 "", 411 "Plus The result is just the sum of the image data.", 412 " Output values are cropped to QuantumRange (no overflow).", 413 "", 414 "Minus The result of image - image window, with underflow", 415 " cropped to zero.", 416 "", 417 "Add The result of image + image window, with overflow", 418 " wrapping around (mod 256).", 419 "", 420 "Subtract The result of image - image window, with underflow", 421 " wrapping around (mod 256). The add and subtract", 422 " operators can be used to perform reversible", 423 " transformations.", 424 "", 425 "Difference", 426 " The result of abs(image - image window). This", 427 " useful for comparing two very similar images.", 428 "", 429 "Multiply", 430 " The result of image * image window. This", 431 " useful for the creation of drop-shadows.", 432 "", 433 "Bumpmap The result of surface normals from image * image", 434 " window.", 435 "", 436 "Copy The resulting image is image window replaced with", 437 " image. Here the matte information is ignored.", 438 "", 439 "CopyRed The red layer of the image window is replace with", 440 " the red layer of the image. The other layers are", 441 " untouched.", 442 "", 443 "CopyGreen", 444 " The green layer of the image window is replace with", 445 " the green layer of the image. The other layers are", 446 " untouched.", 447 "", 448 "CopyBlue The blue layer of the image window is replace with", 449 " the blue layer of the image. The other layers are", 450 " untouched.", 451 "", 452 "CopyOpacity", 453 " The matte layer of the image window is replace with", 454 " the matte layer of the image. The other layers are", 455 " untouched.", 456 "", 457 "The image compositor requires a matte, or alpha channel in", 458 "the image for some operations. This extra channel usually", 459 "defines a mask which represents a sort of a cookie-cutter", 460 "for the image. This the case when matte is opaque (full", 461 "coverage) for pixels inside the shape, zero outside, and", 462 "between 0 and QuantumRange on the boundary. If image does not", 463 "have a matte channel, it is initialized with 0 for any pixel", 464 "matching in color to pixel location (0,0), otherwise QuantumRange.", 465 "", 466 "If you choose Dissolve, the composite operator becomes Over. The", 467 "image matte channel percent transparency is initialized to factor.", 468 "The image window is initialized to (100-factor). Where factor is the", 469 "value you specify in the Dialog widget.", 470 "", 471 "Displace shifts the image pixels as defined by a displacement", 472 "map. With this option, image is used as a displacement map.", 473 "Black, within the displacement map, is a maximum positive", 474 "displacement. White is a maximum negative displacement and", 475 "middle gray is neutral. The displacement is scaled to determine", 476 "the pixel shift. By default, the displacement applies in both the", 477 "horizontal and vertical directions. However, if you specify a mask,", 478 "image is the horizontal X displacement and mask the vertical Y", 479 "displacement.", 480 "", 481 "Note that matte information for image window is not retained", 482 "for colormapped X server visuals (e.g. StaticColor,", 483 "StaticColor, GrayScale, PseudoColor). Correct compositing", 484 "behavior may require a TrueColor or DirectColor visual or a", 485 "Standard Colormap.", 486 "", 487 "Choosing a composite operator is optional. The default", 488 "operator is replace. However, you must choose a location to", 489 "composite your image and press button 1. Press and hold the", 490 "button before releasing and an outline of the image will", 491 "appear to help you identify your location.", 492 "", 493 "The actual colors of the composite image is saved. However,", 494 "the color that appears in image window may be different.", 495 "For example, on a monochrome screen image window will appear", 496 "black or white even though your composited image may have", 497 "many colors. If the image is saved to a file it is written", 498 "with the correct colors. To assure the correct colors are", 499 "saved in the final image, any PseudoClass image is promoted", 500 "to DirectClass (see miff(5)). To force a PseudoClass image", 501 "to remain PseudoClass, use -colors.", 502 (char *) NULL, 503 }, 504 *ImageCutHelp[] = 505 { 506 "In cut mode, the Command widget has these options:", 507 "", 508 " Help", 509 " Dismiss", 510 "", 511 "To define a cut region, press button 1 and drag. The", 512 "cut region is defined by a highlighted rectangle that", 513 "expands or contracts as it follows the pointer. Once you", 514 "are satisfied with the cut region, release the button.", 515 "You are now in rectify mode. In rectify mode, the Command", 516 "widget has these options:", 517 "", 518 " Cut", 519 " Help", 520 " Dismiss", 521 "", 522 "You can make adjustments by moving the pointer to one of the", 523 "cut rectangle corners, pressing a button, and dragging.", 524 "Finally, press Cut to commit your copy region. To", 525 "exit without cutting the image, press Dismiss.", 526 (char *) NULL, 527 }, 528 *ImageCopyHelp[] = 529 { 530 "In copy mode, the Command widget has these options:", 531 "", 532 " Help", 533 " Dismiss", 534 "", 535 "To define a copy region, press button 1 and drag. The", 536 "copy region is defined by a highlighted rectangle that", 537 "expands or contracts as it follows the pointer. Once you", 538 "are satisfied with the copy region, release the button.", 539 "You are now in rectify mode. In rectify mode, the Command", 540 "widget has these options:", 541 "", 542 " Copy", 543 " Help", 544 " Dismiss", 545 "", 546 "You can make adjustments by moving the pointer to one of the", 547 "copy rectangle corners, pressing a button, and dragging.", 548 "Finally, press Copy to commit your copy region. To", 549 "exit without copying the image, press Dismiss.", 550 (char *) NULL, 551 }, 552 *ImageCropHelp[] = 553 { 554 "In crop mode, the Command widget has these options:", 555 "", 556 " Help", 557 " Dismiss", 558 "", 559 "To define a cropping region, press button 1 and drag. The", 560 "cropping region is defined by a highlighted rectangle that", 561 "expands or contracts as it follows the pointer. Once you", 562 "are satisfied with the cropping region, release the button.", 563 "You are now in rectify mode. In rectify mode, the Command", 564 "widget has these options:", 565 "", 566 " Crop", 567 " Help", 568 " Dismiss", 569 "", 570 "You can make adjustments by moving the pointer to one of the", 571 "cropping rectangle corners, pressing a button, and dragging.", 572 "Finally, press Crop to commit your cropping region. To", 573 "exit without cropping the image, press Dismiss.", 574 (char *) NULL, 575 }, 576 *ImageDrawHelp[] = 577 { 578 "The cursor changes to a crosshair to indicate you are in", 579 "draw mode. To exit immediately, press Dismiss. In draw mode,", 580 "the Command widget has these options:", 581 "", 582 " Element", 583 " point", 584 " line", 585 " rectangle", 586 " fill rectangle", 587 " circle", 588 " fill circle", 589 " ellipse", 590 " fill ellipse", 591 " polygon", 592 " fill polygon", 593 " Color", 594 " black", 595 " blue", 596 " cyan", 597 " green", 598 " gray", 599 " red", 600 " magenta", 601 " yellow", 602 " white", 603 " transparent", 604 " Browser...", 605 " Stipple", 606 " Brick", 607 " Diagonal", 608 " Scales", 609 " Vertical", 610 " Wavy", 611 " Translucent", 612 " Opaque", 613 " Open...", 614 " Width", 615 " 1", 616 " 2", 617 " 4", 618 " 8", 619 " 16", 620 " Dialog...", 621 " Undo", 622 " Help", 623 " Dismiss", 624 "", 625 "Choose a drawing primitive from the Element sub-menu.", 626 "", 627 "Choose a color from the Color sub-menu. Additional", 628 "colors can be specified with the color browser.", 629 "", 630 "If you choose the color browser and press Grab, you can", 631 "select the color by moving the pointer to the desired", 632 "color on the screen and press any button. The transparent", 633 "color updates the image matte channel and is useful for", 634 "image compositing.", 635 "", 636 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 637 "Additional stipples can be specified with the file browser.", 638 "Stipples obtained from the file browser must be on disk in the", 639 "X11 bitmap format.", 640 "", 641 "Choose a width, if appropriate, from the Width sub-menu. To", 642 "choose a specific width select the Dialog widget.", 643 "", 644 "Choose a point in the Image window and press button 1 and", 645 "hold. Next, move the pointer to another location in the", 646 "image. As you move, a line connects the initial location and", 647 "the pointer. When you release the button, the image is", 648 "updated with the primitive you just drew. For polygons, the", 649 "image is updated when you press and release the button without", 650 "moving the pointer.", 651 "", 652 "To cancel image drawing, move the pointer back to the", 653 "starting point of the line and release the button.", 654 (char *) NULL, 655 }, 656 *DisplayHelp[] = 657 { 658 "BUTTONS", 659 " The effects of each button press is described below. Three", 660 " buttons are required. If you have a two button mouse,", 661 " button 1 and 3 are returned. Press ALT and button 3 to", 662 " simulate button 2.", 663 "", 664 " 1 Press this button to map or unmap the Command widget.", 665 "", 666 " 2 Press and drag to define a region of the image to", 667 " magnify.", 668 "", 669 " 3 Press and drag to choose from a select set of commands.", 670 " This button behaves differently if the image being", 671 " displayed is a visual image directory. Here, choose a", 672 " particular tile of the directory and press this button and", 673 " drag to select a command from a pop-up menu. Choose from", 674 " these menu items:", 675 "", 676 " Open", 677 " Next", 678 " Former", 679 " Delete", 680 " Update", 681 "", 682 " If you choose Open, the image represented by the tile is", 683 " displayed. To return to the visual image directory, choose", 684 " Next from the Command widget. Next and Former moves to the", 685 " next or former image respectively. Choose Delete to delete", 686 " a particular image tile. Finally, choose Update to", 687 " synchronize all the image tiles with their respective", 688 " images.", 689 "", 690 "COMMAND WIDGET", 691 " The Command widget lists a number of sub-menus and commands.", 692 " They are", 693 "", 694 " File", 695 " Open...", 696 " Next", 697 " Former", 698 " Select...", 699 " Save...", 700 " Print...", 701 " Delete...", 702 " New...", 703 " Visual Directory...", 704 " Quit", 705 " Edit", 706 " Undo", 707 " Redo", 708 " Cut", 709 " Copy", 710 " Paste", 711 " View", 712 " Half Size", 713 " Original Size", 714 " Double Size", 715 " Resize...", 716 " Apply", 717 " Refresh", 718 " Restore", 719 " Transform", 720 " Crop", 721 " Chop", 722 " Flop", 723 " Flip", 724 " Rotate Right", 725 " Rotate Left", 726 " Rotate...", 727 " Shear...", 728 " Roll...", 729 " Trim Edges", 730 " Enhance", 731 " Brightness...", 732 " Saturation...", 733 " Hue...", 734 " Gamma...", 735 " Sharpen...", 736 " Dull", 737 " Contrast Stretch...", 738 " Sigmoidal Contrast...", 739 " Normalize", 740 " Equalize", 741 " Negate", 742 " Grayscale", 743 " Map...", 744 " Quantize...", 745 " Effects", 746 " Despeckle", 747 " Emboss", 748 " Reduce Noise", 749 " Add Noise", 750 " Sharpen...", 751 " Blur...", 752 " Threshold...", 753 " Edge Detect...", 754 " Spread...", 755 " Shade...", 756 " Painting...", 757 " Segment...", 758 " F/X", 759 " Solarize...", 760 " Sepia Tone...", 761 " Swirl...", 762 " Implode...", 763 " Vignette...", 764 " Wave...", 765 " Oil Painting...", 766 " Charcoal Drawing...", 767 " Image Edit", 768 " Annotate...", 769 " Draw...", 770 " Color...", 771 " Matte...", 772 " Composite...", 773 " Add Border...", 774 " Add Frame...", 775 " Comment...", 776 " Launch...", 777 " Region of Interest...", 778 " Miscellany", 779 " Image Info", 780 " Zoom Image", 781 " Show Preview...", 782 " Show Histogram", 783 " Show Matte", 784 " Background...", 785 " Slide Show", 786 " Preferences...", 787 " Help", 788 " Overview", 789 " Browse Documentation", 790 " About Display", 791 "", 792 " Menu items with a indented triangle have a sub-menu. They", 793 " are represented above as the indented items. To access a", 794 " sub-menu item, move the pointer to the appropriate menu and", 795 " press a button and drag. When you find the desired sub-menu", 796 " item, release the button and the command is executed. Move", 797 " the pointer away from the sub-menu if you decide not to", 798 " execute a particular command.", 799 "", 800 "KEYBOARD ACCELERATORS", 801 " Accelerators are one or two key presses that effect a", 802 " particular command. The keyboard accelerators that", 803 " display(1) understands is:", 804 "", 805 " Ctl+O Press to open an image from a file.", 806 "", 807 " space Press to display the next image.", 808 "", 809 " If the image is a multi-paged document such as a Postscript", 810 " document, you can skip ahead several pages by preceding", 811 " this command with a number. For example to display the", 812 " third page beyond the current page, press 3<space>.", 813 "", 814 " backspace Press to display the former image.", 815 "", 816 " If the image is a multi-paged document such as a Postscript", 817 " document, you can skip behind several pages by preceding", 818 " this command with a number. For example to display the", 819 " third page preceding the current page, press 3<backspace>.", 820 "", 821 " Ctl+S Press to write the image to a file.", 822 "", 823 " Ctl+P Press to print the image to a Postscript printer.", 824 "", 825 " Ctl+D Press to delete an image file.", 826 "", 827 " Ctl+N Press to create a blank canvas.", 828 "", 829 " Ctl+Q Press to discard all images and exit program.", 830 "", 831 " Ctl+Z Press to undo last image transformation.", 832 "", 833 " Ctl+R Press to redo last image transformation.", 834 "", 835 " Ctl+X Press to cut a region of the image.", 836 "", 837 " Ctl+C Press to copy a region of the image.", 838 "", 839 " Ctl+V Press to paste a region to the image.", 840 "", 841 " < Press to half the image size.", 842 "", 843 " - Press to return to the original image size.", 844 "", 845 " > Press to double the image size.", 846 "", 847 " % Press to resize the image to a width and height you", 848 " specify.", 849 "", 850 "Cmd-A Press to make any image transformations permanent." 851 "", 852 " By default, any image size transformations are applied", 853 " to the original image to create the image displayed on", 854 " the X server. However, the transformations are not", 855 " permanent (i.e. the original image does not change", 856 " size only the X image does). For example, if you", 857 " press > the X image will appear to double in size,", 858 " but the original image will in fact remain the same size.", 859 " To force the original image to double in size, press >", 860 " followed by Cmd-A.", 861 "", 862 " @ Press to refresh the image window.", 863 "", 864 " C Press to cut out a rectangular region of the image.", 865 "", 866 " [ Press to chop the image.", 867 "", 868 " H Press to flop image in the horizontal direction.", 869 "", 870 " V Press to flip image in the vertical direction.", 871 "", 872 " / Press to rotate the image 90 degrees clockwise.", 873 "", 874 " \\ Press to rotate the image 90 degrees counter-clockwise.", 875 "", 876 " * Press to rotate the image the number of degrees you", 877 " specify.", 878 "", 879 " S Press to shear the image the number of degrees you", 880 " specify.", 881 "", 882 " R Press to roll the image.", 883 "", 884 " T Press to trim the image edges.", 885 "", 886 " Shft-H Press to vary the image hue.", 887 "", 888 " Shft-S Press to vary the color saturation.", 889 "", 890 " Shft-L Press to vary the color brightness.", 891 "", 892 " Shft-G Press to gamma correct the image.", 893 "", 894 " Shft-C Press to sharpen the image contrast.", 895 "", 896 " Shft-Z Press to dull the image contrast.", 897 "", 898 " = Press to perform histogram equalization on the image.", 899 "", 900 " Shft-N Press to perform histogram normalization on the image.", 901 "", 902 " Shft-~ Press to negate the colors of the image.", 903 "", 904 " . Press to convert the image colors to gray.", 905 "", 906 " Shft-# Press to set the maximum number of unique colors in the", 907 " image.", 908 "", 909 " F2 Press to reduce the speckles in an image.", 910 "", 911 " F3 Press to eliminate peak noise from an image.", 912 "", 913 " F4 Press to add noise to an image.", 914 "", 915 " F5 Press to sharpen an image.", 916 "", 917 " F6 Press to delete an image file.", 918 "", 919 " F7 Press to threshold the image.", 920 "", 921 " F8 Press to detect edges within an image.", 922 "", 923 " F9 Press to emboss an image.", 924 "", 925 " F10 Press to displace pixels by a random amount.", 926 "", 927 " F11 Press to negate all pixels above the threshold level.", 928 "", 929 " F12 Press to shade the image using a distant light source.", 930 "", 931 " F13 Press to lighten or darken image edges to create a 3-D effect.", 932 "", 933 " F14 Press to segment the image by color.", 934 "", 935 " Meta-S Press to swirl image pixels about the center.", 936 "", 937 " Meta-I Press to implode image pixels about the center.", 938 "", 939 " Meta-W Press to alter an image along a sine wave.", 940 "", 941 " Meta-P Press to simulate an oil painting.", 942 "", 943 " Meta-C Press to simulate a charcoal drawing.", 944 "", 945 " Alt-A Press to annotate the image with text.", 946 "", 947 " Alt-D Press to draw on an image.", 948 "", 949 " Alt-P Press to edit an image pixel color.", 950 "", 951 " Alt-M Press to edit the image matte information.", 952 "", 953 " Alt-V Press to composite the image with another.", 954 "", 955 " Alt-B Press to add a border to the image.", 956 "", 957 " Alt-F Press to add an ornamental border to the image.", 958 "", 959 " Alt-Shft-!", 960 " Press to add an image comment.", 961 "", 962 " Ctl-A Press to apply image processing techniques to a region", 963 " of interest.", 964 "", 965 " Shft-? Press to display information about the image.", 966 "", 967 " Shft-+ Press to map the zoom image window.", 968 "", 969 " Shft-P Press to preview an image enhancement, effect, or f/x.", 970 "", 971 " F1 Press to display helpful information about display(1).", 972 "", 973 " Find Press to browse documentation about ImageMagick.", 974 "", 975 " 1-9 Press to change the level of magnification.", 976 "", 977 " Use the arrow keys to move the image one pixel up, down,", 978 " left, or right within the magnify window. Be sure to first", 979 " map the magnify window by pressing button 2.", 980 "", 981 " Press ALT and one of the arrow keys to trim off one pixel", 982 " from any side of the image.", 983 (char *) NULL, 984 }, 985 *ImageMatteEditHelp[] = 986 { 987 "Matte information within an image is useful for some", 988 "operations such as image compositing (See IMAGE", 989 "COMPOSITING). This extra channel usually defines a mask", 990 "which represents a sort of a cookie-cutter for the image.", 991 "This the case when matte is opaque (full coverage) for", 992 "pixels inside the shape, zero outside, and between 0 and", 993 "QuantumRange on the boundary.", 994 "", 995 "A small window appears showing the location of the cursor in", 996 "the image window. You are now in matte edit mode. To exit", 997 "immediately, press Dismiss. In matte edit mode, the Command", 998 "widget has these options:", 999 "", 1000 " Method", 1001 " point", 1002 " replace", 1003 " floodfill", 1004 " filltoborder", 1005 " reset", 1006 " Border Color", 1007 " black", 1008 " blue", 1009 " cyan", 1010 " green", 1011 " gray", 1012 " red", 1013 " magenta", 1014 " yellow", 1015 " white", 1016 " Browser...", 1017 " Fuzz", 1018 " 0%", 1019 " 2%", 1020 " 5%", 1021 " 10%", 1022 " 15%", 1023 " Dialog...", 1024 " Matte", 1025 " Opaque", 1026 " Transparent", 1027 " Dialog...", 1028 " Undo", 1029 " Help", 1030 " Dismiss", 1031 "", 1032 "Choose a matte editing method from the Method sub-menu of", 1033 "the Command widget. The point method changes the matte value", 1034 "of any pixel selected with the pointer until the button is", 1035 "is released. The replace method changes the matte value of", 1036 "any pixel that matches the color of the pixel you select with", 1037 "a button press. Floodfill changes the matte value of any pixel", 1038 "that matches the color of the pixel you select with a button", 1039 "press and is a neighbor. Whereas filltoborder changes the matte", 1040 "value any neighbor pixel that is not the border color. Finally", 1041 "reset changes the entire image to the designated matte value.", 1042 "", 1043 "Choose Matte Value and pick Opaque or Transarent. For other values", 1044 "select the Dialog entry. Here a dialog appears requesting a matte", 1045 "value. The value you select is assigned as the opacity value of the", 1046 "selected pixel or pixels.", 1047 "", 1048 "Now, press any button to select a pixel within the image", 1049 "window to change its matte value.", 1050 "", 1051 "If the Magnify widget is mapped, it can be helpful in positioning", 1052 "your pointer within the image (refer to button 2).", 1053 "", 1054 "Matte information is only valid in a DirectClass image.", 1055 "Therefore, any PseudoClass image is promoted to DirectClass", 1056 "(see miff(5)). Note that matte information for PseudoClass", 1057 "is not retained for colormapped X server visuals (e.g.", 1058 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1059 "immediately save your image to a file (refer to Write).", 1060 "Correct matte editing behavior may require a TrueColor or", 1061 "DirectColor visual or a Standard Colormap.", 1062 (char *) NULL, 1063 }, 1064 *ImagePanHelp[] = 1065 { 1066 "When an image exceeds the width or height of the X server", 1067 "screen, display maps a small panning icon. The rectangle", 1068 "within the panning icon shows the area that is currently", 1069 "displayed in the image window. To pan about the image,", 1070 "press any button and drag the pointer within the panning", 1071 "icon. The pan rectangle moves with the pointer and the", 1072 "image window is updated to reflect the location of the", 1073 "rectangle within the panning icon. When you have selected", 1074 "the area of the image you wish to view, release the button.", 1075 "", 1076 "Use the arrow keys to pan the image one pixel up, down,", 1077 "left, or right within the image window.", 1078 "", 1079 "The panning icon is withdrawn if the image becomes smaller", 1080 "than the dimensions of the X server screen.", 1081 (char *) NULL, 1082 }, 1083 *ImagePasteHelp[] = 1084 { 1085 "A small window appears showing the location of the cursor in", 1086 "the image window. You are now in paste mode. To exit", 1087 "immediately, press Dismiss. In paste mode, the Command", 1088 "widget has these options:", 1089 "", 1090 " Operators", 1091 " over", 1092 " in", 1093 " out", 1094 " atop", 1095 " xor", 1096 " plus", 1097 " minus", 1098 " add", 1099 " subtract", 1100 " difference", 1101 " replace", 1102 " Help", 1103 " Dismiss", 1104 "", 1105 "Choose a composite operation from the Operators sub-menu of", 1106 "the Command widget. How each operator behaves is described", 1107 "below. Image window is the image currently displayed on", 1108 "your X server and image is the image obtained with the File", 1109 "Browser widget.", 1110 "", 1111 "Over The result is the union of the two image shapes,", 1112 " with image obscuring image window in the region of", 1113 " overlap.", 1114 "", 1115 "In The result is simply image cut by the shape of", 1116 " image window. None of the image data of image", 1117 " window is in the result.", 1118 "", 1119 "Out The resulting image is image with the shape of", 1120 " image window cut out.", 1121 "", 1122 "Atop The result is the same shape as image image window,", 1123 " with image obscuring image window where the image", 1124 " shapes overlap. Note this differs from over", 1125 " because the portion of image outside image window's", 1126 " shape does not appear in the result.", 1127 "", 1128 "Xor The result is the image data from both image and", 1129 " image window that is outside the overlap region.", 1130 " The overlap region is blank.", 1131 "", 1132 "Plus The result is just the sum of the image data.", 1133 " Output values are cropped to QuantumRange (no overflow).", 1134 " This operation is independent of the matte", 1135 " channels.", 1136 "", 1137 "Minus The result of image - image window, with underflow", 1138 " cropped to zero.", 1139 "", 1140 "Add The result of image + image window, with overflow", 1141 " wrapping around (mod 256).", 1142 "", 1143 "Subtract The result of image - image window, with underflow", 1144 " wrapping around (mod 256). The add and subtract", 1145 " operators can be used to perform reversible", 1146 " transformations.", 1147 "", 1148 "Difference", 1149 " The result of abs(image - image window). This", 1150 " useful for comparing two very similar images.", 1151 "", 1152 "Copy The resulting image is image window replaced with", 1153 " image. Here the matte information is ignored.", 1154 "", 1155 "CopyRed The red layer of the image window is replace with", 1156 " the red layer of the image. The other layers are", 1157 " untouched.", 1158 "", 1159 "CopyGreen", 1160 " The green layer of the image window is replace with", 1161 " the green layer of the image. The other layers are", 1162 " untouched.", 1163 "", 1164 "CopyBlue The blue layer of the image window is replace with", 1165 " the blue layer of the image. The other layers are", 1166 " untouched.", 1167 "", 1168 "CopyOpacity", 1169 " The matte layer of the image window is replace with", 1170 " the matte layer of the image. The other layers are", 1171 " untouched.", 1172 "", 1173 "The image compositor requires a matte, or alpha channel in", 1174 "the image for some operations. This extra channel usually", 1175 "defines a mask which represents a sort of a cookie-cutter", 1176 "for the image. This the case when matte is opaque (full", 1177 "coverage) for pixels inside the shape, zero outside, and", 1178 "between 0 and QuantumRange on the boundary. If image does not", 1179 "have a matte channel, it is initialized with 0 for any pixel", 1180 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1181 "", 1182 "Note that matte information for image window is not retained", 1183 "for colormapped X server visuals (e.g. StaticColor,", 1184 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1185 "behavior may require a TrueColor or DirectColor visual or a", 1186 "Standard Colormap.", 1187 "", 1188 "Choosing a composite operator is optional. The default", 1189 "operator is replace. However, you must choose a location to", 1190 "paste your image and press button 1. Press and hold the", 1191 "button before releasing and an outline of the image will", 1192 "appear to help you identify your location.", 1193 "", 1194 "The actual colors of the pasted image is saved. However,", 1195 "the color that appears in image window may be different.", 1196 "For example, on a monochrome screen image window will appear", 1197 "black or white even though your pasted image may have", 1198 "many colors. If the image is saved to a file it is written", 1199 "with the correct colors. To assure the correct colors are", 1200 "saved in the final image, any PseudoClass image is promoted", 1201 "to DirectClass (see miff(5)). To force a PseudoClass image", 1202 "to remain PseudoClass, use -colors.", 1203 (char *) NULL, 1204 }, 1205 *ImageROIHelp[] = 1206 { 1207 "In region of interest mode, the Command widget has these", 1208 "options:", 1209 "", 1210 " Help", 1211 " Dismiss", 1212 "", 1213 "To define a region of interest, press button 1 and drag.", 1214 "The region of interest is defined by a highlighted rectangle", 1215 "that expands or contracts as it follows the pointer. Once", 1216 "you are satisfied with the region of interest, release the", 1217 "button. You are now in apply mode. In apply mode the", 1218 "Command widget has these options:", 1219 "", 1220 " File", 1221 " Save...", 1222 " Print...", 1223 " Edit", 1224 " Undo", 1225 " Redo", 1226 " Transform", 1227 " Flop", 1228 " Flip", 1229 " Rotate Right", 1230 " Rotate Left", 1231 " Enhance", 1232 " Hue...", 1233 " Saturation...", 1234 " Brightness...", 1235 " Gamma...", 1236 " Spiff", 1237 " Dull", 1238 " Contrast Stretch", 1239 " Sigmoidal Contrast...", 1240 " Normalize", 1241 " Equalize", 1242 " Negate", 1243 " Grayscale", 1244 " Map...", 1245 " Quantize...", 1246 " Effects", 1247 " Despeckle", 1248 " Emboss", 1249 " Reduce Noise", 1250 " Sharpen...", 1251 " Blur...", 1252 " Threshold...", 1253 " Edge Detect...", 1254 " Spread...", 1255 " Shade...", 1256 " Raise...", 1257 " Segment...", 1258 " F/X", 1259 " Solarize...", 1260 " Sepia Tone...", 1261 " Swirl...", 1262 " Implode...", 1263 " Vignette...", 1264 " Wave...", 1265 " Oil Painting...", 1266 " Charcoal Drawing...", 1267 " Miscellany", 1268 " Image Info", 1269 " Zoom Image", 1270 " Show Preview...", 1271 " Show Histogram", 1272 " Show Matte", 1273 " Help", 1274 " Dismiss", 1275 "", 1276 "You can make adjustments to the region of interest by moving", 1277 "the pointer to one of the rectangle corners, pressing a", 1278 "button, and dragging. Finally, choose an image processing", 1279 "technique from the Command widget. You can choose more than", 1280 "one image processing technique to apply to an area.", 1281 "Alternatively, you can move the region of interest before", 1282 "applying another image processing technique. To exit, press", 1283 "Dismiss.", 1284 (char *) NULL, 1285 }, 1286 *ImageRotateHelp[] = 1287 { 1288 "In rotate mode, the Command widget has these options:", 1289 "", 1290 " Pixel Color", 1291 " black", 1292 " blue", 1293 " cyan", 1294 " green", 1295 " gray", 1296 " red", 1297 " magenta", 1298 " yellow", 1299 " white", 1300 " Browser...", 1301 " Direction", 1302 " horizontal", 1303 " vertical", 1304 " Help", 1305 " Dismiss", 1306 "", 1307 "Choose a background color from the Pixel Color sub-menu.", 1308 "Additional background colors can be specified with the color", 1309 "browser. You can change the menu colors by setting the X", 1310 "resources pen1 through pen9.", 1311 "", 1312 "If you choose the color browser and press Grab, you can", 1313 "select the background color by moving the pointer to the", 1314 "desired color on the screen and press any button.", 1315 "", 1316 "Choose a point in the image window and press this button and", 1317 "hold. Next, move the pointer to another location in the", 1318 "image. As you move a line connects the initial location and", 1319 "the pointer. When you release the button, the degree of", 1320 "image rotation is determined by the slope of the line you", 1321 "just drew. The slope is relative to the direction you", 1322 "choose from the Direction sub-menu of the Command widget.", 1323 "", 1324 "To cancel the image rotation, move the pointer back to the", 1325 "starting point of the line and release the button.", 1326 (char *) NULL, 1327 }; 1328 1329/* 1330 Enumeration declarations. 1331*/ 1332typedef enum 1333{ 1334 CopyMode, 1335 CropMode, 1336 CutMode 1337} ClipboardMode; 1338 1339typedef enum 1340{ 1341 OpenCommand, 1342 NextCommand, 1343 FormerCommand, 1344 SelectCommand, 1345 SaveCommand, 1346 PrintCommand, 1347 DeleteCommand, 1348 NewCommand, 1349 VisualDirectoryCommand, 1350 QuitCommand, 1351 UndoCommand, 1352 RedoCommand, 1353 CutCommand, 1354 CopyCommand, 1355 PasteCommand, 1356 HalfSizeCommand, 1357 OriginalSizeCommand, 1358 DoubleSizeCommand, 1359 ResizeCommand, 1360 ApplyCommand, 1361 RefreshCommand, 1362 RestoreCommand, 1363 CropCommand, 1364 ChopCommand, 1365 FlopCommand, 1366 FlipCommand, 1367 RotateRightCommand, 1368 RotateLeftCommand, 1369 RotateCommand, 1370 ShearCommand, 1371 RollCommand, 1372 TrimCommand, 1373 HueCommand, 1374 SaturationCommand, 1375 BrightnessCommand, 1376 GammaCommand, 1377 SpiffCommand, 1378 DullCommand, 1379 ContrastStretchCommand, 1380 SigmoidalContrastCommand, 1381 NormalizeCommand, 1382 EqualizeCommand, 1383 NegateCommand, 1384 GrayscaleCommand, 1385 MapCommand, 1386 QuantizeCommand, 1387 DespeckleCommand, 1388 EmbossCommand, 1389 ReduceNoiseCommand, 1390 AddNoiseCommand, 1391 SharpenCommand, 1392 BlurCommand, 1393 ThresholdCommand, 1394 EdgeDetectCommand, 1395 SpreadCommand, 1396 ShadeCommand, 1397 RaiseCommand, 1398 SegmentCommand, 1399 SolarizeCommand, 1400 SepiaToneCommand, 1401 SwirlCommand, 1402 ImplodeCommand, 1403 VignetteCommand, 1404 WaveCommand, 1405 OilPaintCommand, 1406 CharcoalDrawCommand, 1407 AnnotateCommand, 1408 DrawCommand, 1409 ColorCommand, 1410 MatteCommand, 1411 CompositeCommand, 1412 AddBorderCommand, 1413 AddFrameCommand, 1414 CommentCommand, 1415 LaunchCommand, 1416 RegionofInterestCommand, 1417 ROIHelpCommand, 1418 ROIDismissCommand, 1419 InfoCommand, 1420 ZoomCommand, 1421 ShowPreviewCommand, 1422 ShowHistogramCommand, 1423 ShowMatteCommand, 1424 BackgroundCommand, 1425 SlideShowCommand, 1426 PreferencesCommand, 1427 HelpCommand, 1428 BrowseDocumentationCommand, 1429 VersionCommand, 1430 SaveToUndoBufferCommand, 1431 FreeBuffersCommand, 1432 NullCommand 1433} CommandType; 1434 1435typedef enum 1436{ 1437 AnnotateNameCommand, 1438 AnnotateFontColorCommand, 1439 AnnotateBackgroundColorCommand, 1440 AnnotateRotateCommand, 1441 AnnotateHelpCommand, 1442 AnnotateDismissCommand, 1443 TextHelpCommand, 1444 TextApplyCommand, 1445 ChopDirectionCommand, 1446 ChopHelpCommand, 1447 ChopDismissCommand, 1448 HorizontalChopCommand, 1449 VerticalChopCommand, 1450 ColorEditMethodCommand, 1451 ColorEditColorCommand, 1452 ColorEditBorderCommand, 1453 ColorEditFuzzCommand, 1454 ColorEditUndoCommand, 1455 ColorEditHelpCommand, 1456 ColorEditDismissCommand, 1457 CompositeOperatorsCommand, 1458 CompositeDissolveCommand, 1459 CompositeDisplaceCommand, 1460 CompositeHelpCommand, 1461 CompositeDismissCommand, 1462 CropHelpCommand, 1463 CropDismissCommand, 1464 RectifyCopyCommand, 1465 RectifyHelpCommand, 1466 RectifyDismissCommand, 1467 DrawElementCommand, 1468 DrawColorCommand, 1469 DrawStippleCommand, 1470 DrawWidthCommand, 1471 DrawUndoCommand, 1472 DrawHelpCommand, 1473 DrawDismissCommand, 1474 MatteEditMethod, 1475 MatteEditBorderCommand, 1476 MatteEditFuzzCommand, 1477 MatteEditValueCommand, 1478 MatteEditUndoCommand, 1479 MatteEditHelpCommand, 1480 MatteEditDismissCommand, 1481 PasteOperatorsCommand, 1482 PasteHelpCommand, 1483 PasteDismissCommand, 1484 RotateColorCommand, 1485 RotateDirectionCommand, 1486 RotateCropCommand, 1487 RotateSharpenCommand, 1488 RotateHelpCommand, 1489 RotateDismissCommand, 1490 HorizontalRotateCommand, 1491 VerticalRotateCommand, 1492 TileLoadCommand, 1493 TileNextCommand, 1494 TileFormerCommand, 1495 TileDeleteCommand, 1496 TileUpdateCommand 1497} ModeType; 1498 1499/* 1500 Stipples. 1501*/ 1502#define BricksWidth 20 1503#define BricksHeight 20 1504#define DiagonalWidth 16 1505#define DiagonalHeight 16 1506#define HighlightWidth 8 1507#define HighlightHeight 8 1508#define OpaqueWidth 8 1509#define OpaqueHeight 8 1510#define ScalesWidth 16 1511#define ScalesHeight 16 1512#define ShadowWidth 8 1513#define ShadowHeight 8 1514#define VerticalWidth 16 1515#define VerticalHeight 16 1516#define WavyWidth 16 1517#define WavyHeight 16 1518 1519/* 1520 Constant declaration. 1521*/ 1522static const int 1523 RoiDelta = 8; 1524 1525static const unsigned char 1526 BricksBitmap[] = 1527 { 1528 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1529 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1530 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1531 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1532 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1533 }, 1534 DiagonalBitmap[] = 1535 { 1536 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1537 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1538 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1539 }, 1540 ScalesBitmap[] = 1541 { 1542 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1543 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1544 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1545 }, 1546 VerticalBitmap[] = 1547 { 1548 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1549 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1550 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1551 }, 1552 WavyBitmap[] = 1553 { 1554 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1555 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1556 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1557 }; 1558 1559/* 1560 Function prototypes. 1561*/ 1562static CommandType 1563 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1564 const MagickStatusType,KeySym,Image **); 1565 1566static Image 1567 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1568 Image **), 1569 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1570 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *), 1571 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *); 1572 1573static MagickBooleanType 1574 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *), 1575 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1576 XChopImage(Display *,XResourceInfo *,XWindows *,Image **), 1577 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode), 1578 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **), 1579 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1580 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *), 1581 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *), 1582 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1583 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *), 1584 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *), 1585 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **), 1586 XROIImage(Display *,XResourceInfo *,XWindows *,Image **), 1587 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *), 1588 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *); 1589 1590static void 1591 XDrawPanRectangle(Display *,XWindows *), 1592 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **), 1593 XMagnifyImage(Display *,XWindows *,XEvent *), 1594 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *), 1595 XPanImage(Display *,XWindows *,XEvent *), 1596 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1597 const KeySym), 1598 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1599 XScreenEvent(Display *,XWindows *,XEvent *), 1600 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1601 1602/* 1603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1604% % 1605% % 1606% % 1607% D i s p l a y I m a g e s % 1608% % 1609% % 1610% % 1611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1612% 1613% DisplayImages() displays an image sequence to any X window screen. It 1614% returns a value other than 0 if successful. Check the exception member 1615% of image to determine the reason for any failure. 1616% 1617% The format of the DisplayImages method is: 1618% 1619% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1620% Image *images) 1621% 1622% A description of each parameter follows: 1623% 1624% o image_info: the image info. 1625% 1626% o image: the image. 1627% 1628*/ 1629MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1630 Image *images) 1631{ 1632 char 1633 *argv[1]; 1634 1635 Display 1636 *display; 1637 1638 Image 1639 *image; 1640 1641 register ssize_t 1642 i; 1643 1644 size_t 1645 state; 1646 1647 XrmDatabase 1648 resource_database; 1649 1650 XResourceInfo 1651 resource_info; 1652 1653 assert(image_info != (const ImageInfo *) NULL); 1654 assert(image_info->signature == MagickSignature); 1655 assert(images != (Image *) NULL); 1656 assert(images->signature == MagickSignature); 1657 if (images->debug != MagickFalse) 1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1659 display=XOpenDisplay(image_info->server_name); 1660 if (display == (Display *) NULL) 1661 { 1662 (void) ThrowMagickException(&images->exception,GetMagickModule(), 1663 XServerError,"UnableToOpenXServer","`%s'",XDisplayName( 1664 image_info->server_name)); 1665 return(MagickFalse); 1666 } 1667 if (images->exception.severity != UndefinedException) 1668 CatchException(&images->exception); 1669 (void) XSetErrorHandler(XError); 1670 resource_database=XGetResourceDatabase(display,GetClientName()); 1671 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1672 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1673 if (image_info->page != (char *) NULL) 1674 resource_info.image_geometry=AcquireString(image_info->page); 1675 resource_info.immutable=MagickTrue; 1676 argv[0]=AcquireString(GetClientName()); 1677 state=DefaultState; 1678 for (i=0; (state & ExitState) == 0; i++) 1679 { 1680 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1681 break; 1682 image=GetImageFromList(images,i % GetImageListLength(images)); 1683 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state); 1684 } 1685 argv[0]=DestroyString(argv[0]); 1686 (void) XCloseDisplay(display); 1687 XDestroyResourceInfo(&resource_info); 1688 if (images->exception.severity != UndefinedException) 1689 return(MagickFalse); 1690 return(MagickTrue); 1691} 1692 1693/* 1694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1695% % 1696% % 1697% % 1698% R e m o t e D i s p l a y C o m m a n d % 1699% % 1700% % 1701% % 1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1703% 1704% RemoteDisplayCommand() encourages a remote display program to display the 1705% specified image filename. 1706% 1707% The format of the RemoteDisplayCommand method is: 1708% 1709% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1710% const char *window,const char *filename,ExceptionInfo *exception) 1711% 1712% A description of each parameter follows: 1713% 1714% o image_info: the image info. 1715% 1716% o window: Specifies the name or id of an X window. 1717% 1718% o filename: the name of the image filename to display. 1719% 1720% o exception: return any errors or warnings in this structure. 1721% 1722*/ 1723MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1724 const char *window,const char *filename,ExceptionInfo *exception) 1725{ 1726 Display 1727 *display; 1728 1729 MagickStatusType 1730 status; 1731 1732 assert(image_info != (const ImageInfo *) NULL); 1733 assert(image_info->signature == MagickSignature); 1734 assert(filename != (char *) NULL); 1735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1736 display=XOpenDisplay(image_info->server_name); 1737 if (display == (Display *) NULL) 1738 { 1739 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1740 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1741 return(MagickFalse); 1742 } 1743 (void) XSetErrorHandler(XError); 1744 status=XRemoteCommand(display,window,filename); 1745 (void) XCloseDisplay(display); 1746 return(status != 0 ? MagickTrue : MagickFalse); 1747} 1748 1749/* 1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1751% % 1752% % 1753% % 1754+ X A n n o t a t e E d i t I m a g e % 1755% % 1756% % 1757% % 1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1759% 1760% XAnnotateEditImage() annotates the image with text. 1761% 1762% The format of the XAnnotateEditImage method is: 1763% 1764% MagickBooleanType XAnnotateEditImage(Display *display, 1765% XResourceInfo *resource_info,XWindows *windows,Image *image) 1766% 1767% A description of each parameter follows: 1768% 1769% o display: Specifies a connection to an X server; returned from 1770% XOpenDisplay. 1771% 1772% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1773% 1774% o windows: Specifies a pointer to a XWindows structure. 1775% 1776% o image: the image; returned from ReadImage. 1777% 1778*/ 1779 1780static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1781{ 1782 if (x > y) 1783 return(x); 1784 return(y); 1785} 1786 1787static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1788{ 1789 if (x < y) 1790 return(x); 1791 return(y); 1792} 1793 1794static MagickBooleanType XAnnotateEditImage(Display *display, 1795 XResourceInfo *resource_info,XWindows *windows,Image *image) 1796{ 1797 static const char 1798 *AnnotateMenu[] = 1799 { 1800 "Font Name", 1801 "Font Color", 1802 "Box Color", 1803 "Rotate Text", 1804 "Help", 1805 "Dismiss", 1806 (char *) NULL 1807 }, 1808 *TextMenu[] = 1809 { 1810 "Help", 1811 "Apply", 1812 (char *) NULL 1813 }; 1814 1815 static const ModeType 1816 AnnotateCommands[] = 1817 { 1818 AnnotateNameCommand, 1819 AnnotateFontColorCommand, 1820 AnnotateBackgroundColorCommand, 1821 AnnotateRotateCommand, 1822 AnnotateHelpCommand, 1823 AnnotateDismissCommand 1824 }, 1825 TextCommands[] = 1826 { 1827 TextHelpCommand, 1828 TextApplyCommand 1829 }; 1830 1831 static MagickBooleanType 1832 transparent_box = MagickTrue, 1833 transparent_pen = MagickFalse; 1834 1835 static MagickRealType 1836 degrees = 0.0; 1837 1838 static unsigned int 1839 box_id = MaxNumberPens-2, 1840 font_id = 0, 1841 pen_id = 0; 1842 1843 char 1844 command[MaxTextExtent], 1845 text[MaxTextExtent]; 1846 1847 const char 1848 *ColorMenu[MaxNumberPens+1]; 1849 1850 Cursor 1851 cursor; 1852 1853 GC 1854 annotate_context; 1855 1856 int 1857 id, 1858 pen_number, 1859 status, 1860 x, 1861 y; 1862 1863 KeySym 1864 key_symbol; 1865 1866 register char 1867 *p; 1868 1869 register ssize_t 1870 i; 1871 1872 unsigned int 1873 height, 1874 width; 1875 1876 size_t 1877 state; 1878 1879 XAnnotateInfo 1880 *annotate_info, 1881 *previous_info; 1882 1883 XColor 1884 color; 1885 1886 XFontStruct 1887 *font_info; 1888 1889 XEvent 1890 event, 1891 text_event; 1892 1893 /* 1894 Map Command widget. 1895 */ 1896 (void) CloneString(&windows->command.name,"Annotate"); 1897 windows->command.data=4; 1898 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1899 (void) XMapRaised(display,windows->command.id); 1900 XClientMessage(display,windows->image.id,windows->im_protocols, 1901 windows->im_update_widget,CurrentTime); 1902 /* 1903 Track pointer until button 1 is pressed. 1904 */ 1905 XQueryPosition(display,windows->image.id,&x,&y); 1906 (void) XSelectInput(display,windows->image.id, 1907 windows->image.attributes.event_mask | PointerMotionMask); 1908 cursor=XCreateFontCursor(display,XC_left_side); 1909 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1910 state=DefaultState; 1911 do 1912 { 1913 if (windows->info.mapped != MagickFalse) 1914 { 1915 /* 1916 Display pointer position. 1917 */ 1918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1919 x+windows->image.x,y+windows->image.y); 1920 XInfoWidget(display,windows,text); 1921 } 1922 /* 1923 Wait for next event. 1924 */ 1925 XScreenEvent(display,windows,&event); 1926 if (event.xany.window == windows->command.id) 1927 { 1928 /* 1929 Select a command from the Command widget. 1930 */ 1931 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1933 if (id < 0) 1934 continue; 1935 switch (AnnotateCommands[id]) 1936 { 1937 case AnnotateNameCommand: 1938 { 1939 const char 1940 *FontMenu[MaxNumberFonts]; 1941 1942 int 1943 font_number; 1944 1945 /* 1946 Initialize menu selections. 1947 */ 1948 for (i=0; i < MaxNumberFonts; i++) 1949 FontMenu[i]=resource_info->font_name[i]; 1950 FontMenu[MaxNumberFonts-2]="Browser..."; 1951 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1952 /* 1953 Select a font name from the pop-up menu. 1954 */ 1955 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1956 (const char **) FontMenu,command); 1957 if (font_number < 0) 1958 break; 1959 if (font_number == (MaxNumberFonts-2)) 1960 { 1961 static char 1962 font_name[MaxTextExtent] = "fixed"; 1963 1964 /* 1965 Select a font name from a browser. 1966 */ 1967 resource_info->font_name[font_number]=font_name; 1968 XFontBrowserWidget(display,windows,"Select",font_name); 1969 if (*font_name == '\0') 1970 break; 1971 } 1972 /* 1973 Initialize font info. 1974 */ 1975 font_info=XLoadQueryFont(display,resource_info->font_name[ 1976 font_number]); 1977 if (font_info == (XFontStruct *) NULL) 1978 { 1979 XNoticeWidget(display,windows,"Unable to load font:", 1980 resource_info->font_name[font_number]); 1981 break; 1982 } 1983 font_id=(unsigned int) font_number; 1984 (void) XFreeFont(display,font_info); 1985 break; 1986 } 1987 case AnnotateFontColorCommand: 1988 { 1989 /* 1990 Initialize menu selections. 1991 */ 1992 for (i=0; i < (int) (MaxNumberPens-2); i++) 1993 ColorMenu[i]=resource_info->pen_colors[i]; 1994 ColorMenu[MaxNumberPens-2]="transparent"; 1995 ColorMenu[MaxNumberPens-1]="Browser..."; 1996 ColorMenu[MaxNumberPens]=(const char *) NULL; 1997 /* 1998 Select a pen color from the pop-up menu. 1999 */ 2000 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2001 (const char **) ColorMenu,command); 2002 if (pen_number < 0) 2003 break; 2004 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2005 MagickFalse; 2006 if (transparent_pen != MagickFalse) 2007 break; 2008 if (pen_number == (MaxNumberPens-1)) 2009 { 2010 static char 2011 color_name[MaxTextExtent] = "gray"; 2012 2013 /* 2014 Select a pen color from a dialog. 2015 */ 2016 resource_info->pen_colors[pen_number]=color_name; 2017 XColorBrowserWidget(display,windows,"Select",color_name); 2018 if (*color_name == '\0') 2019 break; 2020 } 2021 /* 2022 Set pen color. 2023 */ 2024 (void) XParseColor(display,windows->map_info->colormap, 2025 resource_info->pen_colors[pen_number],&color); 2026 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2027 (unsigned int) MaxColors,&color); 2028 windows->pixel_info->pen_colors[pen_number]=color; 2029 pen_id=(unsigned int) pen_number; 2030 break; 2031 } 2032 case AnnotateBackgroundColorCommand: 2033 { 2034 /* 2035 Initialize menu selections. 2036 */ 2037 for (i=0; i < (int) (MaxNumberPens-2); i++) 2038 ColorMenu[i]=resource_info->pen_colors[i]; 2039 ColorMenu[MaxNumberPens-2]="transparent"; 2040 ColorMenu[MaxNumberPens-1]="Browser..."; 2041 ColorMenu[MaxNumberPens]=(const char *) NULL; 2042 /* 2043 Select a pen color from the pop-up menu. 2044 */ 2045 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2046 (const char **) ColorMenu,command); 2047 if (pen_number < 0) 2048 break; 2049 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2050 MagickFalse; 2051 if (transparent_box != MagickFalse) 2052 break; 2053 if (pen_number == (MaxNumberPens-1)) 2054 { 2055 static char 2056 color_name[MaxTextExtent] = "gray"; 2057 2058 /* 2059 Select a pen color from a dialog. 2060 */ 2061 resource_info->pen_colors[pen_number]=color_name; 2062 XColorBrowserWidget(display,windows,"Select",color_name); 2063 if (*color_name == '\0') 2064 break; 2065 } 2066 /* 2067 Set pen color. 2068 */ 2069 (void) XParseColor(display,windows->map_info->colormap, 2070 resource_info->pen_colors[pen_number],&color); 2071 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2072 (unsigned int) MaxColors,&color); 2073 windows->pixel_info->pen_colors[pen_number]=color; 2074 box_id=(unsigned int) pen_number; 2075 break; 2076 } 2077 case AnnotateRotateCommand: 2078 { 2079 int 2080 entry; 2081 2082 static char 2083 angle[MaxTextExtent] = "30.0"; 2084 2085 static const char 2086 *RotateMenu[] = 2087 { 2088 "-90", 2089 "-45", 2090 "-30", 2091 "0", 2092 "30", 2093 "45", 2094 "90", 2095 "180", 2096 "Dialog...", 2097 (char *) NULL, 2098 }; 2099 2100 /* 2101 Select a command from the pop-up menu. 2102 */ 2103 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2104 command); 2105 if (entry < 0) 2106 break; 2107 if (entry != 8) 2108 { 2109 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL); 2110 break; 2111 } 2112 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2113 angle); 2114 if (*angle == '\0') 2115 break; 2116 degrees=InterpretLocaleValue(angle,(char **) NULL); 2117 break; 2118 } 2119 case AnnotateHelpCommand: 2120 { 2121 XTextViewWidget(display,resource_info,windows,MagickFalse, 2122 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2123 break; 2124 } 2125 case AnnotateDismissCommand: 2126 { 2127 /* 2128 Prematurely exit. 2129 */ 2130 state|=EscapeState; 2131 state|=ExitState; 2132 break; 2133 } 2134 default: 2135 break; 2136 } 2137 continue; 2138 } 2139 switch (event.type) 2140 { 2141 case ButtonPress: 2142 { 2143 if (event.xbutton.button != Button1) 2144 break; 2145 if (event.xbutton.window != windows->image.id) 2146 break; 2147 /* 2148 Change to text entering mode. 2149 */ 2150 x=event.xbutton.x; 2151 y=event.xbutton.y; 2152 state|=ExitState; 2153 break; 2154 } 2155 case ButtonRelease: 2156 break; 2157 case Expose: 2158 break; 2159 case KeyPress: 2160 { 2161 if (event.xkey.window != windows->image.id) 2162 break; 2163 /* 2164 Respond to a user key press. 2165 */ 2166 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2167 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2168 switch ((int) key_symbol) 2169 { 2170 case XK_Escape: 2171 case XK_F20: 2172 { 2173 /* 2174 Prematurely exit. 2175 */ 2176 state|=EscapeState; 2177 state|=ExitState; 2178 break; 2179 } 2180 case XK_F1: 2181 case XK_Help: 2182 { 2183 XTextViewWidget(display,resource_info,windows,MagickFalse, 2184 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2185 break; 2186 } 2187 default: 2188 { 2189 (void) XBell(display,0); 2190 break; 2191 } 2192 } 2193 break; 2194 } 2195 case MotionNotify: 2196 { 2197 /* 2198 Map and unmap Info widget as cursor crosses its boundaries. 2199 */ 2200 x=event.xmotion.x; 2201 y=event.xmotion.y; 2202 if (windows->info.mapped != MagickFalse) 2203 { 2204 if ((x < (int) (windows->info.x+windows->info.width)) && 2205 (y < (int) (windows->info.y+windows->info.height))) 2206 (void) XWithdrawWindow(display,windows->info.id, 2207 windows->info.screen); 2208 } 2209 else 2210 if ((x > (int) (windows->info.x+windows->info.width)) || 2211 (y > (int) (windows->info.y+windows->info.height))) 2212 (void) XMapWindow(display,windows->info.id); 2213 break; 2214 } 2215 default: 2216 break; 2217 } 2218 } while ((state & ExitState) == 0); 2219 (void) XSelectInput(display,windows->image.id, 2220 windows->image.attributes.event_mask); 2221 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2222 if ((state & EscapeState) != 0) 2223 return(MagickTrue); 2224 /* 2225 Set font info and check boundary conditions. 2226 */ 2227 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2228 if (font_info == (XFontStruct *) NULL) 2229 { 2230 XNoticeWidget(display,windows,"Unable to load font:", 2231 resource_info->font_name[font_id]); 2232 font_info=windows->font_info; 2233 } 2234 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2235 x=(int) windows->image.width-font_info->max_bounds.width; 2236 if (y < (int) (font_info->ascent+font_info->descent)) 2237 y=(int) font_info->ascent+font_info->descent; 2238 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2239 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2240 return(MagickFalse); 2241 /* 2242 Initialize annotate structure. 2243 */ 2244 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2245 if (annotate_info == (XAnnotateInfo *) NULL) 2246 return(MagickFalse); 2247 XGetAnnotateInfo(annotate_info); 2248 annotate_info->x=x; 2249 annotate_info->y=y; 2250 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2251 annotate_info->stencil=OpaqueStencil; 2252 else 2253 if (transparent_box == MagickFalse) 2254 annotate_info->stencil=BackgroundStencil; 2255 else 2256 annotate_info->stencil=ForegroundStencil; 2257 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2258 annotate_info->degrees=degrees; 2259 annotate_info->font_info=font_info; 2260 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2261 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2262 sizeof(*annotate_info->text)); 2263 if (annotate_info->text == (char *) NULL) 2264 return(MagickFalse); 2265 /* 2266 Create cursor and set graphic context. 2267 */ 2268 cursor=XCreateFontCursor(display,XC_pencil); 2269 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2270 annotate_context=windows->image.annotate_context; 2271 (void) XSetFont(display,annotate_context,font_info->fid); 2272 (void) XSetBackground(display,annotate_context, 2273 windows->pixel_info->pen_colors[box_id].pixel); 2274 (void) XSetForeground(display,annotate_context, 2275 windows->pixel_info->pen_colors[pen_id].pixel); 2276 /* 2277 Begin annotating the image with text. 2278 */ 2279 (void) CloneString(&windows->command.name,"Text"); 2280 windows->command.data=0; 2281 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2282 state=DefaultState; 2283 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2284 text_event.xexpose.width=(int) font_info->max_bounds.width; 2285 text_event.xexpose.height=font_info->max_bounds.ascent+ 2286 font_info->max_bounds.descent; 2287 p=annotate_info->text; 2288 do 2289 { 2290 /* 2291 Display text cursor. 2292 */ 2293 *p='\0'; 2294 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2295 /* 2296 Wait for next event. 2297 */ 2298 XScreenEvent(display,windows,&event); 2299 if (event.xany.window == windows->command.id) 2300 { 2301 /* 2302 Select a command from the Command widget. 2303 */ 2304 (void) XSetBackground(display,annotate_context, 2305 windows->pixel_info->background_color.pixel); 2306 (void) XSetForeground(display,annotate_context, 2307 windows->pixel_info->foreground_color.pixel); 2308 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2309 (void) XSetBackground(display,annotate_context, 2310 windows->pixel_info->pen_colors[box_id].pixel); 2311 (void) XSetForeground(display,annotate_context, 2312 windows->pixel_info->pen_colors[pen_id].pixel); 2313 if (id < 0) 2314 continue; 2315 switch (TextCommands[id]) 2316 { 2317 case TextHelpCommand: 2318 { 2319 XTextViewWidget(display,resource_info,windows,MagickFalse, 2320 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2321 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2322 break; 2323 } 2324 case TextApplyCommand: 2325 { 2326 /* 2327 Finished annotating. 2328 */ 2329 annotate_info->width=(unsigned int) XTextWidth(font_info, 2330 annotate_info->text,(int) strlen(annotate_info->text)); 2331 XRefreshWindow(display,&windows->image,&text_event); 2332 state|=ExitState; 2333 break; 2334 } 2335 default: 2336 break; 2337 } 2338 continue; 2339 } 2340 /* 2341 Erase text cursor. 2342 */ 2343 text_event.xexpose.x=x; 2344 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2345 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2346 (unsigned int) text_event.xexpose.width,(unsigned int) 2347 text_event.xexpose.height,MagickFalse); 2348 XRefreshWindow(display,&windows->image,&text_event); 2349 switch (event.type) 2350 { 2351 case ButtonPress: 2352 { 2353 if (event.xbutton.window != windows->image.id) 2354 break; 2355 if (event.xbutton.button == Button2) 2356 { 2357 /* 2358 Request primary selection. 2359 */ 2360 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2361 windows->image.id,CurrentTime); 2362 break; 2363 } 2364 break; 2365 } 2366 case Expose: 2367 { 2368 if (event.xexpose.count == 0) 2369 { 2370 XAnnotateInfo 2371 *text_info; 2372 2373 /* 2374 Refresh Image window. 2375 */ 2376 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2377 text_info=annotate_info; 2378 while (text_info != (XAnnotateInfo *) NULL) 2379 { 2380 if (annotate_info->stencil == ForegroundStencil) 2381 (void) XDrawString(display,windows->image.id,annotate_context, 2382 text_info->x,text_info->y,text_info->text, 2383 (int) strlen(text_info->text)); 2384 else 2385 (void) XDrawImageString(display,windows->image.id, 2386 annotate_context,text_info->x,text_info->y,text_info->text, 2387 (int) strlen(text_info->text)); 2388 text_info=text_info->previous; 2389 } 2390 (void) XDrawString(display,windows->image.id,annotate_context, 2391 x,y,"_",1); 2392 } 2393 break; 2394 } 2395 case KeyPress: 2396 { 2397 int 2398 length; 2399 2400 if (event.xkey.window != windows->image.id) 2401 break; 2402 /* 2403 Respond to a user key press. 2404 */ 2405 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2406 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2407 *(command+length)='\0'; 2408 if (((event.xkey.state & ControlMask) != 0) || 2409 ((event.xkey.state & Mod1Mask) != 0)) 2410 state|=ModifierState; 2411 if ((state & ModifierState) != 0) 2412 switch ((int) key_symbol) 2413 { 2414 case XK_u: 2415 case XK_U: 2416 { 2417 key_symbol=DeleteCommand; 2418 break; 2419 } 2420 default: 2421 break; 2422 } 2423 switch ((int) key_symbol) 2424 { 2425 case XK_BackSpace: 2426 { 2427 /* 2428 Erase one character. 2429 */ 2430 if (p == annotate_info->text) 2431 { 2432 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2433 break; 2434 else 2435 { 2436 /* 2437 Go to end of the previous line of text. 2438 */ 2439 annotate_info=annotate_info->previous; 2440 p=annotate_info->text; 2441 x=annotate_info->x+annotate_info->width; 2442 y=annotate_info->y; 2443 if (annotate_info->width != 0) 2444 p+=strlen(annotate_info->text); 2445 break; 2446 } 2447 } 2448 p--; 2449 x-=XTextWidth(font_info,p,1); 2450 text_event.xexpose.x=x; 2451 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2452 XRefreshWindow(display,&windows->image,&text_event); 2453 break; 2454 } 2455 case XK_bracketleft: 2456 { 2457 key_symbol=XK_Escape; 2458 break; 2459 } 2460 case DeleteCommand: 2461 { 2462 /* 2463 Erase the entire line of text. 2464 */ 2465 while (p != annotate_info->text) 2466 { 2467 p--; 2468 x-=XTextWidth(font_info,p,1); 2469 text_event.xexpose.x=x; 2470 XRefreshWindow(display,&windows->image,&text_event); 2471 } 2472 break; 2473 } 2474 case XK_Escape: 2475 case XK_F20: 2476 { 2477 /* 2478 Finished annotating. 2479 */ 2480 annotate_info->width=(unsigned int) XTextWidth(font_info, 2481 annotate_info->text,(int) strlen(annotate_info->text)); 2482 XRefreshWindow(display,&windows->image,&text_event); 2483 state|=ExitState; 2484 break; 2485 } 2486 default: 2487 { 2488 /* 2489 Draw a single character on the Image window. 2490 */ 2491 if ((state & ModifierState) != 0) 2492 break; 2493 if (*command == '\0') 2494 break; 2495 *p=(*command); 2496 if (annotate_info->stencil == ForegroundStencil) 2497 (void) XDrawString(display,windows->image.id,annotate_context, 2498 x,y,p,1); 2499 else 2500 (void) XDrawImageString(display,windows->image.id, 2501 annotate_context,x,y,p,1); 2502 x+=XTextWidth(font_info,p,1); 2503 p++; 2504 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2505 break; 2506 } 2507 case XK_Return: 2508 case XK_KP_Enter: 2509 { 2510 /* 2511 Advance to the next line of text. 2512 */ 2513 *p='\0'; 2514 annotate_info->width=(unsigned int) XTextWidth(font_info, 2515 annotate_info->text,(int) strlen(annotate_info->text)); 2516 if (annotate_info->next != (XAnnotateInfo *) NULL) 2517 { 2518 /* 2519 Line of text already exists. 2520 */ 2521 annotate_info=annotate_info->next; 2522 x=annotate_info->x; 2523 y=annotate_info->y; 2524 p=annotate_info->text; 2525 break; 2526 } 2527 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2528 sizeof(*annotate_info->next)); 2529 if (annotate_info->next == (XAnnotateInfo *) NULL) 2530 return(MagickFalse); 2531 *annotate_info->next=(*annotate_info); 2532 annotate_info->next->previous=annotate_info; 2533 annotate_info=annotate_info->next; 2534 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2535 windows->image.width/MagickMax((ssize_t) 2536 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2537 if (annotate_info->text == (char *) NULL) 2538 return(MagickFalse); 2539 annotate_info->y+=annotate_info->height; 2540 if (annotate_info->y > (int) windows->image.height) 2541 annotate_info->y=(int) annotate_info->height; 2542 annotate_info->next=(XAnnotateInfo *) NULL; 2543 x=annotate_info->x; 2544 y=annotate_info->y; 2545 p=annotate_info->text; 2546 break; 2547 } 2548 } 2549 break; 2550 } 2551 case KeyRelease: 2552 { 2553 /* 2554 Respond to a user key release. 2555 */ 2556 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2557 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2558 state&=(~ModifierState); 2559 break; 2560 } 2561 case SelectionNotify: 2562 { 2563 Atom 2564 type; 2565 2566 int 2567 format; 2568 2569 unsigned char 2570 *data; 2571 2572 unsigned long 2573 after, 2574 length; 2575 2576 /* 2577 Obtain response from primary selection. 2578 */ 2579 if (event.xselection.property == (Atom) None) 2580 break; 2581 status=XGetWindowProperty(display,event.xselection.requestor, 2582 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2583 &type,&format,&length,&after,&data); 2584 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2585 (length == 0)) 2586 break; 2587 /* 2588 Annotate Image window with primary selection. 2589 */ 2590 for (i=0; i < (ssize_t) length; i++) 2591 { 2592 if ((char) data[i] != '\n') 2593 { 2594 /* 2595 Draw a single character on the Image window. 2596 */ 2597 *p=(char) data[i]; 2598 (void) XDrawString(display,windows->image.id,annotate_context, 2599 x,y,p,1); 2600 x+=XTextWidth(font_info,p,1); 2601 p++; 2602 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2603 continue; 2604 } 2605 /* 2606 Advance to the next line of text. 2607 */ 2608 *p='\0'; 2609 annotate_info->width=(unsigned int) XTextWidth(font_info, 2610 annotate_info->text,(int) strlen(annotate_info->text)); 2611 if (annotate_info->next != (XAnnotateInfo *) NULL) 2612 { 2613 /* 2614 Line of text already exists. 2615 */ 2616 annotate_info=annotate_info->next; 2617 x=annotate_info->x; 2618 y=annotate_info->y; 2619 p=annotate_info->text; 2620 continue; 2621 } 2622 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2623 sizeof(*annotate_info->next)); 2624 if (annotate_info->next == (XAnnotateInfo *) NULL) 2625 return(MagickFalse); 2626 *annotate_info->next=(*annotate_info); 2627 annotate_info->next->previous=annotate_info; 2628 annotate_info=annotate_info->next; 2629 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2630 windows->image.width/MagickMax((ssize_t) 2631 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2632 if (annotate_info->text == (char *) NULL) 2633 return(MagickFalse); 2634 annotate_info->y+=annotate_info->height; 2635 if (annotate_info->y > (int) windows->image.height) 2636 annotate_info->y=(int) annotate_info->height; 2637 annotate_info->next=(XAnnotateInfo *) NULL; 2638 x=annotate_info->x; 2639 y=annotate_info->y; 2640 p=annotate_info->text; 2641 } 2642 (void) XFree((void *) data); 2643 break; 2644 } 2645 default: 2646 break; 2647 } 2648 } while ((state & ExitState) == 0); 2649 (void) XFreeCursor(display,cursor); 2650 /* 2651 Annotation is relative to image configuration. 2652 */ 2653 width=(unsigned int) image->columns; 2654 height=(unsigned int) image->rows; 2655 x=0; 2656 y=0; 2657 if (windows->image.crop_geometry != (char *) NULL) 2658 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2659 /* 2660 Initialize annotated image. 2661 */ 2662 XSetCursorState(display,windows,MagickTrue); 2663 XCheckRefreshWindows(display,windows); 2664 while (annotate_info != (XAnnotateInfo *) NULL) 2665 { 2666 if (annotate_info->width == 0) 2667 { 2668 /* 2669 No text on this line-- go to the next line of text. 2670 */ 2671 previous_info=annotate_info->previous; 2672 annotate_info->text=(char *) 2673 RelinquishMagickMemory(annotate_info->text); 2674 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2675 annotate_info=previous_info; 2676 continue; 2677 } 2678 /* 2679 Determine pixel index for box and pen color. 2680 */ 2681 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2682 if (windows->pixel_info->colors != 0) 2683 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2684 if (windows->pixel_info->pixels[i] == 2685 windows->pixel_info->pen_colors[box_id].pixel) 2686 { 2687 windows->pixel_info->box_index=(unsigned short) i; 2688 break; 2689 } 2690 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2691 if (windows->pixel_info->colors != 0) 2692 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2693 if (windows->pixel_info->pixels[i] == 2694 windows->pixel_info->pen_colors[pen_id].pixel) 2695 { 2696 windows->pixel_info->pen_index=(unsigned short) i; 2697 break; 2698 } 2699 /* 2700 Define the annotate geometry string. 2701 */ 2702 annotate_info->x=(int) 2703 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2704 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2705 windows->image.y)/windows->image.ximage->height; 2706 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2707 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2708 height*annotate_info->height/windows->image.ximage->height, 2709 annotate_info->x+x,annotate_info->y+y); 2710 /* 2711 Annotate image with text. 2712 */ 2713 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image); 2714 if (status == 0) 2715 return(MagickFalse); 2716 /* 2717 Free up memory. 2718 */ 2719 previous_info=annotate_info->previous; 2720 annotate_info->text=DestroyString(annotate_info->text); 2721 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2722 annotate_info=previous_info; 2723 } 2724 (void) XSetForeground(display,annotate_context, 2725 windows->pixel_info->foreground_color.pixel); 2726 (void) XSetBackground(display,annotate_context, 2727 windows->pixel_info->background_color.pixel); 2728 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2729 XSetCursorState(display,windows,MagickFalse); 2730 (void) XFreeFont(display,font_info); 2731 /* 2732 Update image configuration. 2733 */ 2734 XConfigureImageColormap(display,resource_info,windows,image); 2735 (void) XConfigureImage(display,resource_info,windows,image); 2736 return(MagickTrue); 2737} 2738 2739/* 2740%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2741% % 2742% % 2743% % 2744+ X B a c k g r o u n d I m a g e % 2745% % 2746% % 2747% % 2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2749% 2750% XBackgroundImage() displays the image in the background of a window. 2751% 2752% The format of the XBackgroundImage method is: 2753% 2754% MagickBooleanType XBackgroundImage(Display *display, 2755% XResourceInfo *resource_info,XWindows *windows,Image **image) 2756% 2757% A description of each parameter follows: 2758% 2759% o display: Specifies a connection to an X server; returned from 2760% XOpenDisplay. 2761% 2762% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2763% 2764% o windows: Specifies a pointer to a XWindows structure. 2765% 2766% o image: the image. 2767% 2768*/ 2769static MagickBooleanType XBackgroundImage(Display *display, 2770 XResourceInfo *resource_info,XWindows *windows,Image **image) 2771{ 2772#define BackgroundImageTag "Background/Image" 2773 2774 int 2775 status; 2776 2777 static char 2778 window_id[MaxTextExtent] = "root"; 2779 2780 XResourceInfo 2781 background_resources; 2782 2783 /* 2784 Put image in background. 2785 */ 2786 status=XDialogWidget(display,windows,"Background", 2787 "Enter window id (id 0x00 selects window with pointer):",window_id); 2788 if (*window_id == '\0') 2789 return(MagickFalse); 2790 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 2791 XInfoWidget(display,windows,BackgroundImageTag); 2792 XSetCursorState(display,windows,MagickTrue); 2793 XCheckRefreshWindows(display,windows); 2794 background_resources=(*resource_info); 2795 background_resources.window_id=window_id; 2796 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2797 status=XDisplayBackgroundImage(display,&background_resources,*image); 2798 if (status != MagickFalse) 2799 XClientMessage(display,windows->image.id,windows->im_protocols, 2800 windows->im_retain_colors,CurrentTime); 2801 XSetCursorState(display,windows,MagickFalse); 2802 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image); 2803 return(MagickTrue); 2804} 2805 2806/* 2807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2808% % 2809% % 2810% % 2811+ X C h o p I m a g e % 2812% % 2813% % 2814% % 2815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2816% 2817% XChopImage() chops the X image. 2818% 2819% The format of the XChopImage method is: 2820% 2821% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2822% XWindows *windows,Image **image) 2823% 2824% A description of each parameter follows: 2825% 2826% o display: Specifies a connection to an X server; returned from 2827% XOpenDisplay. 2828% 2829% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2830% 2831% o windows: Specifies a pointer to a XWindows structure. 2832% 2833% o image: the image. 2834% 2835*/ 2836static MagickBooleanType XChopImage(Display *display, 2837 XResourceInfo *resource_info,XWindows *windows,Image **image) 2838{ 2839 static const char 2840 *ChopMenu[] = 2841 { 2842 "Direction", 2843 "Help", 2844 "Dismiss", 2845 (char *) NULL 2846 }; 2847 2848 static ModeType 2849 direction = HorizontalChopCommand; 2850 2851 static const ModeType 2852 ChopCommands[] = 2853 { 2854 ChopDirectionCommand, 2855 ChopHelpCommand, 2856 ChopDismissCommand 2857 }, 2858 DirectionCommands[] = 2859 { 2860 HorizontalChopCommand, 2861 VerticalChopCommand 2862 }; 2863 2864 char 2865 text[MaxTextExtent]; 2866 2867 Image 2868 *chop_image; 2869 2870 int 2871 id, 2872 x, 2873 y; 2874 2875 MagickRealType 2876 scale_factor; 2877 2878 RectangleInfo 2879 chop_info; 2880 2881 unsigned int 2882 distance, 2883 height, 2884 width; 2885 2886 size_t 2887 state; 2888 2889 XEvent 2890 event; 2891 2892 XSegment 2893 segment_info; 2894 2895 /* 2896 Map Command widget. 2897 */ 2898 (void) CloneString(&windows->command.name,"Chop"); 2899 windows->command.data=1; 2900 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2901 (void) XMapRaised(display,windows->command.id); 2902 XClientMessage(display,windows->image.id,windows->im_protocols, 2903 windows->im_update_widget,CurrentTime); 2904 /* 2905 Track pointer until button 1 is pressed. 2906 */ 2907 XQueryPosition(display,windows->image.id,&x,&y); 2908 (void) XSelectInput(display,windows->image.id, 2909 windows->image.attributes.event_mask | PointerMotionMask); 2910 state=DefaultState; 2911 do 2912 { 2913 if (windows->info.mapped != MagickFalse) 2914 { 2915 /* 2916 Display pointer position. 2917 */ 2918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2919 x+windows->image.x,y+windows->image.y); 2920 XInfoWidget(display,windows,text); 2921 } 2922 /* 2923 Wait for next event. 2924 */ 2925 XScreenEvent(display,windows,&event); 2926 if (event.xany.window == windows->command.id) 2927 { 2928 /* 2929 Select a command from the Command widget. 2930 */ 2931 id=XCommandWidget(display,windows,ChopMenu,&event); 2932 if (id < 0) 2933 continue; 2934 switch (ChopCommands[id]) 2935 { 2936 case ChopDirectionCommand: 2937 { 2938 char 2939 command[MaxTextExtent]; 2940 2941 static const char 2942 *Directions[] = 2943 { 2944 "horizontal", 2945 "vertical", 2946 (char *) NULL, 2947 }; 2948 2949 /* 2950 Select a command from the pop-up menu. 2951 */ 2952 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2953 if (id >= 0) 2954 direction=DirectionCommands[id]; 2955 break; 2956 } 2957 case ChopHelpCommand: 2958 { 2959 XTextViewWidget(display,resource_info,windows,MagickFalse, 2960 "Help Viewer - Image Chop",ImageChopHelp); 2961 break; 2962 } 2963 case ChopDismissCommand: 2964 { 2965 /* 2966 Prematurely exit. 2967 */ 2968 state|=EscapeState; 2969 state|=ExitState; 2970 break; 2971 } 2972 default: 2973 break; 2974 } 2975 continue; 2976 } 2977 switch (event.type) 2978 { 2979 case ButtonPress: 2980 { 2981 if (event.xbutton.button != Button1) 2982 break; 2983 if (event.xbutton.window != windows->image.id) 2984 break; 2985 /* 2986 User has committed to start point of chopping line. 2987 */ 2988 segment_info.x1=(short int) event.xbutton.x; 2989 segment_info.x2=(short int) event.xbutton.x; 2990 segment_info.y1=(short int) event.xbutton.y; 2991 segment_info.y2=(short int) event.xbutton.y; 2992 state|=ExitState; 2993 break; 2994 } 2995 case ButtonRelease: 2996 break; 2997 case Expose: 2998 break; 2999 case KeyPress: 3000 { 3001 char 3002 command[MaxTextExtent]; 3003 3004 KeySym 3005 key_symbol; 3006 3007 if (event.xkey.window != windows->image.id) 3008 break; 3009 /* 3010 Respond to a user key press. 3011 */ 3012 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3013 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3014 switch ((int) key_symbol) 3015 { 3016 case XK_Escape: 3017 case XK_F20: 3018 { 3019 /* 3020 Prematurely exit. 3021 */ 3022 state|=EscapeState; 3023 state|=ExitState; 3024 break; 3025 } 3026 case XK_F1: 3027 case XK_Help: 3028 { 3029 (void) XSetFunction(display,windows->image.highlight_context, 3030 GXcopy); 3031 XTextViewWidget(display,resource_info,windows,MagickFalse, 3032 "Help Viewer - Image Chop",ImageChopHelp); 3033 (void) XSetFunction(display,windows->image.highlight_context, 3034 GXinvert); 3035 break; 3036 } 3037 default: 3038 { 3039 (void) XBell(display,0); 3040 break; 3041 } 3042 } 3043 break; 3044 } 3045 case MotionNotify: 3046 { 3047 /* 3048 Map and unmap Info widget as text cursor crosses its boundaries. 3049 */ 3050 x=event.xmotion.x; 3051 y=event.xmotion.y; 3052 if (windows->info.mapped != MagickFalse) 3053 { 3054 if ((x < (int) (windows->info.x+windows->info.width)) && 3055 (y < (int) (windows->info.y+windows->info.height))) 3056 (void) XWithdrawWindow(display,windows->info.id, 3057 windows->info.screen); 3058 } 3059 else 3060 if ((x > (int) (windows->info.x+windows->info.width)) || 3061 (y > (int) (windows->info.y+windows->info.height))) 3062 (void) XMapWindow(display,windows->info.id); 3063 } 3064 } 3065 } while ((state & ExitState) == 0); 3066 (void) XSelectInput(display,windows->image.id, 3067 windows->image.attributes.event_mask); 3068 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3069 if ((state & EscapeState) != 0) 3070 return(MagickTrue); 3071 /* 3072 Draw line as pointer moves until the mouse button is released. 3073 */ 3074 chop_info.width=0; 3075 chop_info.height=0; 3076 chop_info.x=0; 3077 chop_info.y=0; 3078 distance=0; 3079 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3080 state=DefaultState; 3081 do 3082 { 3083 if (distance > 9) 3084 { 3085 /* 3086 Display info and draw chopping line. 3087 */ 3088 if (windows->info.mapped == MagickFalse) 3089 (void) XMapWindow(display,windows->info.id); 3090 (void) FormatLocaleString(text,MaxTextExtent, 3091 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3092 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3093 XInfoWidget(display,windows,text); 3094 XHighlightLine(display,windows->image.id, 3095 windows->image.highlight_context,&segment_info); 3096 } 3097 else 3098 if (windows->info.mapped != MagickFalse) 3099 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3100 /* 3101 Wait for next event. 3102 */ 3103 XScreenEvent(display,windows,&event); 3104 if (distance > 9) 3105 XHighlightLine(display,windows->image.id, 3106 windows->image.highlight_context,&segment_info); 3107 switch (event.type) 3108 { 3109 case ButtonPress: 3110 { 3111 segment_info.x2=(short int) event.xmotion.x; 3112 segment_info.y2=(short int) event.xmotion.y; 3113 break; 3114 } 3115 case ButtonRelease: 3116 { 3117 /* 3118 User has committed to chopping line. 3119 */ 3120 segment_info.x2=(short int) event.xbutton.x; 3121 segment_info.y2=(short int) event.xbutton.y; 3122 state|=ExitState; 3123 break; 3124 } 3125 case Expose: 3126 break; 3127 case MotionNotify: 3128 { 3129 segment_info.x2=(short int) event.xmotion.x; 3130 segment_info.y2=(short int) event.xmotion.y; 3131 } 3132 default: 3133 break; 3134 } 3135 /* 3136 Check boundary conditions. 3137 */ 3138 if (segment_info.x2 < 0) 3139 segment_info.x2=0; 3140 else 3141 if (segment_info.x2 > windows->image.ximage->width) 3142 segment_info.x2=windows->image.ximage->width; 3143 if (segment_info.y2 < 0) 3144 segment_info.y2=0; 3145 else 3146 if (segment_info.y2 > windows->image.ximage->height) 3147 segment_info.y2=windows->image.ximage->height; 3148 distance=(unsigned int) 3149 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3150 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3151 /* 3152 Compute chopping geometry. 3153 */ 3154 if (direction == HorizontalChopCommand) 3155 { 3156 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3157 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3158 chop_info.height=0; 3159 chop_info.y=0; 3160 if (segment_info.x1 > (int) segment_info.x2) 3161 { 3162 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3163 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3164 } 3165 } 3166 else 3167 { 3168 chop_info.width=0; 3169 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3170 chop_info.x=0; 3171 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3172 if (segment_info.y1 > segment_info.y2) 3173 { 3174 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3175 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3176 } 3177 } 3178 } while ((state & ExitState) == 0); 3179 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3180 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3181 if (distance <= 9) 3182 return(MagickTrue); 3183 /* 3184 Image chopping is relative to image configuration. 3185 */ 3186 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 3187 XSetCursorState(display,windows,MagickTrue); 3188 XCheckRefreshWindows(display,windows); 3189 windows->image.window_changes.width=windows->image.ximage->width- 3190 (unsigned int) chop_info.width; 3191 windows->image.window_changes.height=windows->image.ximage->height- 3192 (unsigned int) chop_info.height; 3193 width=(unsigned int) (*image)->columns; 3194 height=(unsigned int) (*image)->rows; 3195 x=0; 3196 y=0; 3197 if (windows->image.crop_geometry != (char *) NULL) 3198 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3199 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3200 chop_info.x+=x; 3201 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3202 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3203 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3204 chop_info.y+=y; 3205 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3206 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3207 /* 3208 Chop image. 3209 */ 3210 chop_image=ChopImage(*image,&chop_info,&(*image)->exception); 3211 XSetCursorState(display,windows,MagickFalse); 3212 if (chop_image == (Image *) NULL) 3213 return(MagickFalse); 3214 *image=DestroyImage(*image); 3215 *image=chop_image; 3216 /* 3217 Update image configuration. 3218 */ 3219 XConfigureImageColormap(display,resource_info,windows,*image); 3220 (void) XConfigureImage(display,resource_info,windows,*image); 3221 return(MagickTrue); 3222} 3223 3224/* 3225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3226% % 3227% % 3228% % 3229+ X C o l o r E d i t I m a g e % 3230% % 3231% % 3232% % 3233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3234% 3235% XColorEditImage() allows the user to interactively change the color of one 3236% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3237% 3238% The format of the XColorEditImage method is: 3239% 3240% MagickBooleanType XColorEditImage(Display *display, 3241% XResourceInfo *resource_info,XWindows *windows,Image **image) 3242% 3243% A description of each parameter follows: 3244% 3245% o display: Specifies a connection to an X server; returned from 3246% XOpenDisplay. 3247% 3248% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3249% 3250% o windows: Specifies a pointer to a XWindows structure. 3251% 3252% o image: the image; returned from ReadImage. 3253% 3254*/ 3255 3256 3257static MagickBooleanType XColorEditImage(Display *display, 3258 XResourceInfo *resource_info,XWindows *windows,Image **image) 3259{ 3260 static const char 3261 *ColorEditMenu[] = 3262 { 3263 "Method", 3264 "Pixel Color", 3265 "Border Color", 3266 "Fuzz", 3267 "Undo", 3268 "Help", 3269 "Dismiss", 3270 (char *) NULL 3271 }; 3272 3273 static const ModeType 3274 ColorEditCommands[] = 3275 { 3276 ColorEditMethodCommand, 3277 ColorEditColorCommand, 3278 ColorEditBorderCommand, 3279 ColorEditFuzzCommand, 3280 ColorEditUndoCommand, 3281 ColorEditHelpCommand, 3282 ColorEditDismissCommand 3283 }; 3284 3285 static PaintMethod 3286 method = PointMethod; 3287 3288 static unsigned int 3289 pen_id = 0; 3290 3291 static XColor 3292 border_color = { 0, 0, 0, 0, 0, 0 }; 3293 3294 char 3295 command[MaxTextExtent], 3296 text[MaxTextExtent]; 3297 3298 Cursor 3299 cursor; 3300 3301 ExceptionInfo 3302 *exception; 3303 3304 int 3305 entry, 3306 id, 3307 x, 3308 x_offset, 3309 y, 3310 y_offset; 3311 3312 register Quantum 3313 *q; 3314 3315 register ssize_t 3316 i; 3317 3318 unsigned int 3319 height, 3320 width; 3321 3322 size_t 3323 state; 3324 3325 XColor 3326 color; 3327 3328 XEvent 3329 event; 3330 3331 /* 3332 Map Command widget. 3333 */ 3334 (void) CloneString(&windows->command.name,"Color Edit"); 3335 windows->command.data=4; 3336 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3337 (void) XMapRaised(display,windows->command.id); 3338 XClientMessage(display,windows->image.id,windows->im_protocols, 3339 windows->im_update_widget,CurrentTime); 3340 /* 3341 Make cursor. 3342 */ 3343 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3344 resource_info->background_color,resource_info->foreground_color); 3345 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3346 /* 3347 Track pointer until button 1 is pressed. 3348 */ 3349 XQueryPosition(display,windows->image.id,&x,&y); 3350 (void) XSelectInput(display,windows->image.id, 3351 windows->image.attributes.event_mask | PointerMotionMask); 3352 state=DefaultState; 3353 do 3354 { 3355 if (windows->info.mapped != MagickFalse) 3356 { 3357 /* 3358 Display pointer position. 3359 */ 3360 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3361 x+windows->image.x,y+windows->image.y); 3362 XInfoWidget(display,windows,text); 3363 } 3364 /* 3365 Wait for next event. 3366 */ 3367 XScreenEvent(display,windows,&event); 3368 if (event.xany.window == windows->command.id) 3369 { 3370 /* 3371 Select a command from the Command widget. 3372 */ 3373 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3374 if (id < 0) 3375 { 3376 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3377 continue; 3378 } 3379 switch (ColorEditCommands[id]) 3380 { 3381 case ColorEditMethodCommand: 3382 { 3383 char 3384 **methods; 3385 3386 /* 3387 Select a method from the pop-up menu. 3388 */ 3389 methods=(char **) GetCommandOptions(MagickMethodOptions); 3390 if (methods == (char **) NULL) 3391 break; 3392 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3393 (const char **) methods,command); 3394 if (entry >= 0) 3395 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3396 MagickFalse,methods[entry]); 3397 methods=DestroyStringList(methods); 3398 break; 3399 } 3400 case ColorEditColorCommand: 3401 { 3402 const char 3403 *ColorMenu[MaxNumberPens]; 3404 3405 int 3406 pen_number; 3407 3408 /* 3409 Initialize menu selections. 3410 */ 3411 for (i=0; i < (int) (MaxNumberPens-2); i++) 3412 ColorMenu[i]=resource_info->pen_colors[i]; 3413 ColorMenu[MaxNumberPens-2]="Browser..."; 3414 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3415 /* 3416 Select a pen color from the pop-up menu. 3417 */ 3418 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3419 (const char **) ColorMenu,command); 3420 if (pen_number < 0) 3421 break; 3422 if (pen_number == (MaxNumberPens-2)) 3423 { 3424 static char 3425 color_name[MaxTextExtent] = "gray"; 3426 3427 /* 3428 Select a pen color from a dialog. 3429 */ 3430 resource_info->pen_colors[pen_number]=color_name; 3431 XColorBrowserWidget(display,windows,"Select",color_name); 3432 if (*color_name == '\0') 3433 break; 3434 } 3435 /* 3436 Set pen color. 3437 */ 3438 (void) XParseColor(display,windows->map_info->colormap, 3439 resource_info->pen_colors[pen_number],&color); 3440 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3441 (unsigned int) MaxColors,&color); 3442 windows->pixel_info->pen_colors[pen_number]=color; 3443 pen_id=(unsigned int) pen_number; 3444 break; 3445 } 3446 case ColorEditBorderCommand: 3447 { 3448 const char 3449 *ColorMenu[MaxNumberPens]; 3450 3451 int 3452 pen_number; 3453 3454 /* 3455 Initialize menu selections. 3456 */ 3457 for (i=0; i < (int) (MaxNumberPens-2); i++) 3458 ColorMenu[i]=resource_info->pen_colors[i]; 3459 ColorMenu[MaxNumberPens-2]="Browser..."; 3460 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3461 /* 3462 Select a pen color from the pop-up menu. 3463 */ 3464 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3465 (const char **) ColorMenu,command); 3466 if (pen_number < 0) 3467 break; 3468 if (pen_number == (MaxNumberPens-2)) 3469 { 3470 static char 3471 color_name[MaxTextExtent] = "gray"; 3472 3473 /* 3474 Select a pen color from a dialog. 3475 */ 3476 resource_info->pen_colors[pen_number]=color_name; 3477 XColorBrowserWidget(display,windows,"Select",color_name); 3478 if (*color_name == '\0') 3479 break; 3480 } 3481 /* 3482 Set border color. 3483 */ 3484 (void) XParseColor(display,windows->map_info->colormap, 3485 resource_info->pen_colors[pen_number],&border_color); 3486 break; 3487 } 3488 case ColorEditFuzzCommand: 3489 { 3490 static char 3491 fuzz[MaxTextExtent]; 3492 3493 static const char 3494 *FuzzMenu[] = 3495 { 3496 "0%", 3497 "2%", 3498 "5%", 3499 "10%", 3500 "15%", 3501 "Dialog...", 3502 (char *) NULL, 3503 }; 3504 3505 /* 3506 Select a command from the pop-up menu. 3507 */ 3508 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3509 command); 3510 if (entry < 0) 3511 break; 3512 if (entry != 5) 3513 { 3514 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 3515 QuantumRange+1.0); 3516 break; 3517 } 3518 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3519 (void) XDialogWidget(display,windows,"Ok", 3520 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3521 if (*fuzz == '\0') 3522 break; 3523 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3524 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 3525 break; 3526 } 3527 case ColorEditUndoCommand: 3528 { 3529 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3530 image); 3531 break; 3532 } 3533 case ColorEditHelpCommand: 3534 default: 3535 { 3536 XTextViewWidget(display,resource_info,windows,MagickFalse, 3537 "Help Viewer - Image Annotation",ImageColorEditHelp); 3538 break; 3539 } 3540 case ColorEditDismissCommand: 3541 { 3542 /* 3543 Prematurely exit. 3544 */ 3545 state|=EscapeState; 3546 state|=ExitState; 3547 break; 3548 } 3549 } 3550 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3551 continue; 3552 } 3553 switch (event.type) 3554 { 3555 case ButtonPress: 3556 { 3557 if (event.xbutton.button != Button1) 3558 break; 3559 if ((event.xbutton.window != windows->image.id) && 3560 (event.xbutton.window != windows->magnify.id)) 3561 break; 3562 /* 3563 exit loop. 3564 */ 3565 x=event.xbutton.x; 3566 y=event.xbutton.y; 3567 (void) XMagickCommand(display,resource_info,windows, 3568 SaveToUndoBufferCommand,image); 3569 state|=UpdateConfigurationState; 3570 break; 3571 } 3572 case ButtonRelease: 3573 { 3574 if (event.xbutton.button != Button1) 3575 break; 3576 if ((event.xbutton.window != windows->image.id) && 3577 (event.xbutton.window != windows->magnify.id)) 3578 break; 3579 /* 3580 Update colormap information. 3581 */ 3582 x=event.xbutton.x; 3583 y=event.xbutton.y; 3584 XConfigureImageColormap(display,resource_info,windows,*image); 3585 (void) XConfigureImage(display,resource_info,windows,*image); 3586 XInfoWidget(display,windows,text); 3587 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3588 state&=(~UpdateConfigurationState); 3589 break; 3590 } 3591 case Expose: 3592 break; 3593 case KeyPress: 3594 { 3595 KeySym 3596 key_symbol; 3597 3598 if (event.xkey.window == windows->magnify.id) 3599 { 3600 Window 3601 window; 3602 3603 window=windows->magnify.id; 3604 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3605 } 3606 if (event.xkey.window != windows->image.id) 3607 break; 3608 /* 3609 Respond to a user key press. 3610 */ 3611 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3612 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3613 switch ((int) key_symbol) 3614 { 3615 case XK_Escape: 3616 case XK_F20: 3617 { 3618 /* 3619 Prematurely exit. 3620 */ 3621 state|=ExitState; 3622 break; 3623 } 3624 case XK_F1: 3625 case XK_Help: 3626 { 3627 XTextViewWidget(display,resource_info,windows,MagickFalse, 3628 "Help Viewer - Image Annotation",ImageColorEditHelp); 3629 break; 3630 } 3631 default: 3632 { 3633 (void) XBell(display,0); 3634 break; 3635 } 3636 } 3637 break; 3638 } 3639 case MotionNotify: 3640 { 3641 /* 3642 Map and unmap Info widget as cursor crosses its boundaries. 3643 */ 3644 x=event.xmotion.x; 3645 y=event.xmotion.y; 3646 if (windows->info.mapped != MagickFalse) 3647 { 3648 if ((x < (int) (windows->info.x+windows->info.width)) && 3649 (y < (int) (windows->info.y+windows->info.height))) 3650 (void) XWithdrawWindow(display,windows->info.id, 3651 windows->info.screen); 3652 } 3653 else 3654 if ((x > (int) (windows->info.x+windows->info.width)) || 3655 (y > (int) (windows->info.y+windows->info.height))) 3656 (void) XMapWindow(display,windows->info.id); 3657 break; 3658 } 3659 default: 3660 break; 3661 } 3662 if (event.xany.window == windows->magnify.id) 3663 { 3664 x=windows->magnify.x-windows->image.x; 3665 y=windows->magnify.y-windows->image.y; 3666 } 3667 x_offset=x; 3668 y_offset=y; 3669 if ((state & UpdateConfigurationState) != 0) 3670 { 3671 CacheView 3672 *image_view; 3673 3674 int 3675 x, 3676 y; 3677 3678 /* 3679 Pixel edit is relative to image configuration. 3680 */ 3681 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3682 MagickTrue); 3683 color=windows->pixel_info->pen_colors[pen_id]; 3684 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3685 width=(unsigned int) (*image)->columns; 3686 height=(unsigned int) (*image)->rows; 3687 x=0; 3688 y=0; 3689 if (windows->image.crop_geometry != (char *) NULL) 3690 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3691 &width,&height); 3692 x_offset=(int) 3693 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3694 y_offset=(int) 3695 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3696 if ((x_offset < 0) || (y_offset < 0)) 3697 continue; 3698 if ((x_offset >= (int) (*image)->columns) || 3699 (y_offset >= (int) (*image)->rows)) 3700 continue; 3701 exception=(&(*image)->exception); 3702 image_view=AcquireCacheView(*image); 3703 switch (method) 3704 { 3705 case PointMethod: 3706 default: 3707 { 3708 /* 3709 Update color information using point algorithm. 3710 */ 3711 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3712 return(MagickFalse); 3713 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3714 (ssize_t) y_offset,1,1,exception); 3715 if (q == (Quantum *) NULL) 3716 break; 3717 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3718 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3719 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3720 (void) SyncCacheViewAuthenticPixels(image_view, 3721 &(*image)->exception); 3722 break; 3723 } 3724 case ReplaceMethod: 3725 { 3726 PixelPacket 3727 pixel, 3728 target; 3729 3730 /* 3731 Update color information using replace algorithm. 3732 */ 3733 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3734 (ssize_t) y_offset,&target,&(*image)->exception); 3735 if ((*image)->storage_class == DirectClass) 3736 { 3737 for (y=0; y < (int) (*image)->rows; y++) 3738 { 3739 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3740 (*image)->columns,1,exception); 3741 if (q == (Quantum *) NULL) 3742 break; 3743 for (x=0; x < (int) (*image)->columns; x++) 3744 { 3745 GetPixelPacket(*image,q,&pixel); 3746 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 3747 { 3748 SetPixelRed(*image,ScaleShortToQuantum( 3749 color.red),q); 3750 SetPixelGreen(*image,ScaleShortToQuantum( 3751 color.green),q); 3752 SetPixelBlue(*image,ScaleShortToQuantum( 3753 color.blue),q); 3754 } 3755 q+=GetPixelChannels(*image); 3756 } 3757 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3758 break; 3759 } 3760 } 3761 else 3762 { 3763 for (i=0; i < (ssize_t) (*image)->colors; i++) 3764 if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target)) 3765 { 3766 (*image)->colormap[i].red=ScaleShortToQuantum( 3767 color.red); 3768 (*image)->colormap[i].green=ScaleShortToQuantum( 3769 color.green); 3770 (*image)->colormap[i].blue=ScaleShortToQuantum( 3771 color.blue); 3772 } 3773 (void) SyncImage(*image); 3774 } 3775 break; 3776 } 3777 case FloodfillMethod: 3778 case FillToBorderMethod: 3779 { 3780 DrawInfo 3781 *draw_info; 3782 3783 PixelInfo 3784 target; 3785 3786 /* 3787 Update color information using floodfill algorithm. 3788 */ 3789 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 3790 (ssize_t) y_offset,&target,exception); 3791 if (method == FillToBorderMethod) 3792 { 3793 target.red=(MagickRealType) 3794 ScaleShortToQuantum(border_color.red); 3795 target.green=(MagickRealType) 3796 ScaleShortToQuantum(border_color.green); 3797 target.blue=(MagickRealType) 3798 ScaleShortToQuantum(border_color.blue); 3799 } 3800 draw_info=CloneDrawInfo(resource_info->image_info, 3801 (DrawInfo *) NULL); 3802 (void) QueryColorDatabase(resource_info->pen_colors[pen_id], 3803 &draw_info->fill,exception); 3804 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3805 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3806 MagickFalse : MagickTrue); 3807 draw_info=DestroyDrawInfo(draw_info); 3808 break; 3809 } 3810 case ResetMethod: 3811 { 3812 /* 3813 Update color information using reset algorithm. 3814 */ 3815 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3816 return(MagickFalse); 3817 for (y=0; y < (int) (*image)->rows; y++) 3818 { 3819 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3820 (*image)->columns,1,exception); 3821 if (q == (Quantum *) NULL) 3822 break; 3823 for (x=0; x < (int) (*image)->columns; x++) 3824 { 3825 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3826 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3827 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3828 q+=GetPixelChannels(*image); 3829 } 3830 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3831 break; 3832 } 3833 break; 3834 } 3835 } 3836 image_view=DestroyCacheView(image_view); 3837 state&=(~UpdateConfigurationState); 3838 } 3839 } while ((state & ExitState) == 0); 3840 (void) XSelectInput(display,windows->image.id, 3841 windows->image.attributes.event_mask); 3842 XSetCursorState(display,windows,MagickFalse); 3843 (void) XFreeCursor(display,cursor); 3844 return(MagickTrue); 3845} 3846 3847/* 3848%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3849% % 3850% % 3851% % 3852+ X C o m p o s i t e I m a g e % 3853% % 3854% % 3855% % 3856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3857% 3858% XCompositeImage() requests an image name from the user, reads the image and 3859% composites it with the X window image at a location the user chooses with 3860% the pointer. 3861% 3862% The format of the XCompositeImage method is: 3863% 3864% MagickBooleanType XCompositeImage(Display *display, 3865% XResourceInfo *resource_info,XWindows *windows,Image *image) 3866% 3867% A description of each parameter follows: 3868% 3869% o display: Specifies a connection to an X server; returned from 3870% XOpenDisplay. 3871% 3872% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3873% 3874% o windows: Specifies a pointer to a XWindows structure. 3875% 3876% o image: the image; returned from ReadImage. 3877% 3878*/ 3879static MagickBooleanType XCompositeImage(Display *display, 3880 XResourceInfo *resource_info,XWindows *windows,Image *image) 3881{ 3882 static char 3883 displacement_geometry[MaxTextExtent] = "30x30", 3884 filename[MaxTextExtent] = "\0"; 3885 3886 static const char 3887 *CompositeMenu[] = 3888 { 3889 "Operators", 3890 "Dissolve", 3891 "Displace", 3892 "Help", 3893 "Dismiss", 3894 (char *) NULL 3895 }; 3896 3897 static CompositeOperator 3898 compose = CopyCompositeOp; 3899 3900 static const ModeType 3901 CompositeCommands[] = 3902 { 3903 CompositeOperatorsCommand, 3904 CompositeDissolveCommand, 3905 CompositeDisplaceCommand, 3906 CompositeHelpCommand, 3907 CompositeDismissCommand 3908 }; 3909 3910 char 3911 text[MaxTextExtent]; 3912 3913 Cursor 3914 cursor; 3915 3916 Image 3917 *composite_image; 3918 3919 int 3920 entry, 3921 id, 3922 x, 3923 y; 3924 3925 MagickRealType 3926 blend, 3927 scale_factor; 3928 3929 RectangleInfo 3930 highlight_info, 3931 composite_info; 3932 3933 unsigned int 3934 height, 3935 width; 3936 3937 size_t 3938 state; 3939 3940 XEvent 3941 event; 3942 3943 /* 3944 Request image file name from user. 3945 */ 3946 XFileBrowserWidget(display,windows,"Composite",filename); 3947 if (*filename == '\0') 3948 return(MagickTrue); 3949 /* 3950 Read image. 3951 */ 3952 XSetCursorState(display,windows,MagickTrue); 3953 XCheckRefreshWindows(display,windows); 3954 (void) CopyMagickString(resource_info->image_info->filename,filename, 3955 MaxTextExtent); 3956 composite_image=ReadImage(resource_info->image_info,&image->exception); 3957 CatchException(&image->exception); 3958 XSetCursorState(display,windows,MagickFalse); 3959 if (composite_image == (Image *) NULL) 3960 return(MagickFalse); 3961 /* 3962 Map Command widget. 3963 */ 3964 (void) CloneString(&windows->command.name,"Composite"); 3965 windows->command.data=1; 3966 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 3967 (void) XMapRaised(display,windows->command.id); 3968 XClientMessage(display,windows->image.id,windows->im_protocols, 3969 windows->im_update_widget,CurrentTime); 3970 /* 3971 Track pointer until button 1 is pressed. 3972 */ 3973 XQueryPosition(display,windows->image.id,&x,&y); 3974 (void) XSelectInput(display,windows->image.id, 3975 windows->image.attributes.event_mask | PointerMotionMask); 3976 composite_info.x=(ssize_t) windows->image.x+x; 3977 composite_info.y=(ssize_t) windows->image.y+y; 3978 composite_info.width=0; 3979 composite_info.height=0; 3980 cursor=XCreateFontCursor(display,XC_ul_angle); 3981 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3982 blend=0.0; 3983 state=DefaultState; 3984 do 3985 { 3986 if (windows->info.mapped != MagickFalse) 3987 { 3988 /* 3989 Display pointer position. 3990 */ 3991 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 3992 (long) composite_info.x,(long) composite_info.y); 3993 XInfoWidget(display,windows,text); 3994 } 3995 highlight_info=composite_info; 3996 highlight_info.x=composite_info.x-windows->image.x; 3997 highlight_info.y=composite_info.y-windows->image.y; 3998 XHighlightRectangle(display,windows->image.id, 3999 windows->image.highlight_context,&highlight_info); 4000 /* 4001 Wait for next event. 4002 */ 4003 XScreenEvent(display,windows,&event); 4004 XHighlightRectangle(display,windows->image.id, 4005 windows->image.highlight_context,&highlight_info); 4006 if (event.xany.window == windows->command.id) 4007 { 4008 /* 4009 Select a command from the Command widget. 4010 */ 4011 id=XCommandWidget(display,windows,CompositeMenu,&event); 4012 if (id < 0) 4013 continue; 4014 switch (CompositeCommands[id]) 4015 { 4016 case CompositeOperatorsCommand: 4017 { 4018 char 4019 command[MaxTextExtent], 4020 **operators; 4021 4022 /* 4023 Select a command from the pop-up menu. 4024 */ 4025 operators=GetCommandOptions(MagickComposeOptions); 4026 if (operators == (char **) NULL) 4027 break; 4028 entry=XMenuWidget(display,windows,CompositeMenu[id], 4029 (const char **) operators,command); 4030 if (entry >= 0) 4031 compose=(CompositeOperator) ParseCommandOption( 4032 MagickComposeOptions,MagickFalse,operators[entry]); 4033 operators=DestroyStringList(operators); 4034 break; 4035 } 4036 case CompositeDissolveCommand: 4037 { 4038 static char 4039 factor[MaxTextExtent] = "20.0"; 4040 4041 /* 4042 Dissolve the two images a given percent. 4043 */ 4044 (void) XSetFunction(display,windows->image.highlight_context, 4045 GXcopy); 4046 (void) XDialogWidget(display,windows,"Dissolve", 4047 "Enter the blend factor (0.0 - 99.9%):",factor); 4048 (void) XSetFunction(display,windows->image.highlight_context, 4049 GXinvert); 4050 if (*factor == '\0') 4051 break; 4052 blend=InterpretLocaleValue(factor,(char **) NULL); 4053 compose=DissolveCompositeOp; 4054 break; 4055 } 4056 case CompositeDisplaceCommand: 4057 { 4058 /* 4059 Get horizontal and vertical scale displacement geometry. 4060 */ 4061 (void) XSetFunction(display,windows->image.highlight_context, 4062 GXcopy); 4063 (void) XDialogWidget(display,windows,"Displace", 4064 "Enter the horizontal and vertical scale:",displacement_geometry); 4065 (void) XSetFunction(display,windows->image.highlight_context, 4066 GXinvert); 4067 if (*displacement_geometry == '\0') 4068 break; 4069 compose=DisplaceCompositeOp; 4070 break; 4071 } 4072 case CompositeHelpCommand: 4073 { 4074 (void) XSetFunction(display,windows->image.highlight_context, 4075 GXcopy); 4076 XTextViewWidget(display,resource_info,windows,MagickFalse, 4077 "Help Viewer - Image Composite",ImageCompositeHelp); 4078 (void) XSetFunction(display,windows->image.highlight_context, 4079 GXinvert); 4080 break; 4081 } 4082 case CompositeDismissCommand: 4083 { 4084 /* 4085 Prematurely exit. 4086 */ 4087 state|=EscapeState; 4088 state|=ExitState; 4089 break; 4090 } 4091 default: 4092 break; 4093 } 4094 continue; 4095 } 4096 switch (event.type) 4097 { 4098 case ButtonPress: 4099 { 4100 if (image->debug != MagickFalse) 4101 (void) LogMagickEvent(X11Event,GetMagickModule(), 4102 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4103 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4104 if (event.xbutton.button != Button1) 4105 break; 4106 if (event.xbutton.window != windows->image.id) 4107 break; 4108 /* 4109 Change cursor. 4110 */ 4111 composite_info.width=composite_image->columns; 4112 composite_info.height=composite_image->rows; 4113 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4114 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4115 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4116 break; 4117 } 4118 case ButtonRelease: 4119 { 4120 if (image->debug != MagickFalse) 4121 (void) LogMagickEvent(X11Event,GetMagickModule(), 4122 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4123 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4124 if (event.xbutton.button != Button1) 4125 break; 4126 if (event.xbutton.window != windows->image.id) 4127 break; 4128 if ((composite_info.width != 0) && (composite_info.height != 0)) 4129 { 4130 /* 4131 User has selected the location of the composite image. 4132 */ 4133 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4134 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4135 state|=ExitState; 4136 } 4137 break; 4138 } 4139 case Expose: 4140 break; 4141 case KeyPress: 4142 { 4143 char 4144 command[MaxTextExtent]; 4145 4146 KeySym 4147 key_symbol; 4148 4149 int 4150 length; 4151 4152 if (event.xkey.window != windows->image.id) 4153 break; 4154 /* 4155 Respond to a user key press. 4156 */ 4157 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4158 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4159 *(command+length)='\0'; 4160 if (image->debug != MagickFalse) 4161 (void) LogMagickEvent(X11Event,GetMagickModule(), 4162 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4163 switch ((int) key_symbol) 4164 { 4165 case XK_Escape: 4166 case XK_F20: 4167 { 4168 /* 4169 Prematurely exit. 4170 */ 4171 composite_image=DestroyImage(composite_image); 4172 state|=EscapeState; 4173 state|=ExitState; 4174 break; 4175 } 4176 case XK_F1: 4177 case XK_Help: 4178 { 4179 (void) XSetFunction(display,windows->image.highlight_context, 4180 GXcopy); 4181 XTextViewWidget(display,resource_info,windows,MagickFalse, 4182 "Help Viewer - Image Composite",ImageCompositeHelp); 4183 (void) XSetFunction(display,windows->image.highlight_context, 4184 GXinvert); 4185 break; 4186 } 4187 default: 4188 { 4189 (void) XBell(display,0); 4190 break; 4191 } 4192 } 4193 break; 4194 } 4195 case MotionNotify: 4196 { 4197 /* 4198 Map and unmap Info widget as text cursor crosses its boundaries. 4199 */ 4200 x=event.xmotion.x; 4201 y=event.xmotion.y; 4202 if (windows->info.mapped != MagickFalse) 4203 { 4204 if ((x < (int) (windows->info.x+windows->info.width)) && 4205 (y < (int) (windows->info.y+windows->info.height))) 4206 (void) XWithdrawWindow(display,windows->info.id, 4207 windows->info.screen); 4208 } 4209 else 4210 if ((x > (int) (windows->info.x+windows->info.width)) || 4211 (y > (int) (windows->info.y+windows->info.height))) 4212 (void) XMapWindow(display,windows->info.id); 4213 composite_info.x=(ssize_t) windows->image.x+x; 4214 composite_info.y=(ssize_t) windows->image.y+y; 4215 break; 4216 } 4217 default: 4218 { 4219 if (image->debug != MagickFalse) 4220 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4221 event.type); 4222 break; 4223 } 4224 } 4225 } while ((state & ExitState) == 0); 4226 (void) XSelectInput(display,windows->image.id, 4227 windows->image.attributes.event_mask); 4228 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4229 XSetCursorState(display,windows,MagickFalse); 4230 (void) XFreeCursor(display,cursor); 4231 if ((state & EscapeState) != 0) 4232 return(MagickTrue); 4233 /* 4234 Image compositing is relative to image configuration. 4235 */ 4236 XSetCursorState(display,windows,MagickTrue); 4237 XCheckRefreshWindows(display,windows); 4238 width=(unsigned int) image->columns; 4239 height=(unsigned int) image->rows; 4240 x=0; 4241 y=0; 4242 if (windows->image.crop_geometry != (char *) NULL) 4243 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4244 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4245 composite_info.x+=x; 4246 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4247 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4248 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4249 composite_info.y+=y; 4250 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4251 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4252 if ((composite_info.width != composite_image->columns) || 4253 (composite_info.height != composite_image->rows)) 4254 { 4255 Image 4256 *resize_image; 4257 4258 /* 4259 Scale composite image. 4260 */ 4261 resize_image=ResizeImage(composite_image,composite_info.width, 4262 composite_info.height,composite_image->filter,composite_image->blur, 4263 &image->exception); 4264 composite_image=DestroyImage(composite_image); 4265 if (resize_image == (Image *) NULL) 4266 { 4267 XSetCursorState(display,windows,MagickFalse); 4268 return(MagickFalse); 4269 } 4270 composite_image=resize_image; 4271 } 4272 if (compose == DisplaceCompositeOp) 4273 (void) SetImageArtifact(composite_image,"compose:args", 4274 displacement_geometry); 4275 if (blend != 0.0) 4276 { 4277 CacheView 4278 *image_view; 4279 4280 ExceptionInfo 4281 *exception; 4282 4283 int 4284 y; 4285 4286 Quantum 4287 opacity; 4288 4289 register int 4290 x; 4291 4292 register Quantum 4293 *q; 4294 4295 /* 4296 Create mattes for blending. 4297 */ 4298 exception=(&image->exception); 4299 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4300 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4301 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4302 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4303 return(MagickFalse); 4304 image->matte=MagickTrue; 4305 image_view=AcquireCacheView(image); 4306 for (y=0; y < (int) image->rows; y++) 4307 { 4308 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4309 exception); 4310 if (q == (Quantum *) NULL) 4311 break; 4312 for (x=0; x < (int) image->columns; x++) 4313 { 4314 SetPixelAlpha(image,opacity,q); 4315 q+=GetPixelChannels(image); 4316 } 4317 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4318 break; 4319 } 4320 image_view=DestroyCacheView(image_view); 4321 } 4322 /* 4323 Composite image with X Image window. 4324 */ 4325 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4326 composite_info.y); 4327 composite_image=DestroyImage(composite_image); 4328 XSetCursorState(display,windows,MagickFalse); 4329 /* 4330 Update image configuration. 4331 */ 4332 XConfigureImageColormap(display,resource_info,windows,image); 4333 (void) XConfigureImage(display,resource_info,windows,image); 4334 return(MagickTrue); 4335} 4336 4337/* 4338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4339% % 4340% % 4341% % 4342+ X C o n f i g u r e I m a g e % 4343% % 4344% % 4345% % 4346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4347% 4348% XConfigureImage() creates a new X image. It also notifies the window 4349% manager of the new image size and configures the transient widows. 4350% 4351% The format of the XConfigureImage method is: 4352% 4353% MagickBooleanType XConfigureImage(Display *display, 4354% XResourceInfo *resource_info,XWindows *windows,Image *image) 4355% 4356% A description of each parameter follows: 4357% 4358% o display: Specifies a connection to an X server; returned from 4359% XOpenDisplay. 4360% 4361% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4362% 4363% o windows: Specifies a pointer to a XWindows structure. 4364% 4365% o image: the image. 4366% 4367% 4368*/ 4369static MagickBooleanType XConfigureImage(Display *display, 4370 XResourceInfo *resource_info,XWindows *windows,Image *image) 4371{ 4372 char 4373 geometry[MaxTextExtent]; 4374 4375 MagickStatusType 4376 status; 4377 4378 size_t 4379 mask, 4380 height, 4381 width; 4382 4383 ssize_t 4384 x, 4385 y; 4386 4387 XSizeHints 4388 *size_hints; 4389 4390 XWindowChanges 4391 window_changes; 4392 4393 /* 4394 Dismiss if window dimensions are zero. 4395 */ 4396 width=(unsigned int) windows->image.window_changes.width; 4397 height=(unsigned int) windows->image.window_changes.height; 4398 if (image->debug != MagickFalse) 4399 (void) LogMagickEvent(X11Event,GetMagickModule(), 4400 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4401 windows->image.ximage->height,(double) width,(double) height); 4402 if ((width*height) == 0) 4403 return(MagickTrue); 4404 x=0; 4405 y=0; 4406 /* 4407 Resize image to fit Image window dimensions. 4408 */ 4409 XSetCursorState(display,windows,MagickTrue); 4410 (void) XFlush(display); 4411 if (((int) width != windows->image.ximage->width) || 4412 ((int) height != windows->image.ximage->height)) 4413 image->taint=MagickTrue; 4414 windows->magnify.x=(int) 4415 width*windows->magnify.x/windows->image.ximage->width; 4416 windows->magnify.y=(int) 4417 height*windows->magnify.y/windows->image.ximage->height; 4418 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4419 windows->image.y=(int) 4420 (height*windows->image.y/windows->image.ximage->height); 4421 status=XMakeImage(display,resource_info,&windows->image,image, 4422 (unsigned int) width,(unsigned int) height); 4423 if (status == MagickFalse) 4424 XNoticeWidget(display,windows,"Unable to configure X image:", 4425 windows->image.name); 4426 /* 4427 Notify window manager of the new configuration. 4428 */ 4429 if (resource_info->image_geometry != (char *) NULL) 4430 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4431 resource_info->image_geometry); 4432 else 4433 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4434 XDisplayWidth(display,windows->image.screen), 4435 XDisplayHeight(display,windows->image.screen)); 4436 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4437 window_changes.width=(int) width; 4438 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4439 window_changes.width=XDisplayWidth(display,windows->image.screen); 4440 window_changes.height=(int) height; 4441 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4442 window_changes.height=XDisplayHeight(display,windows->image.screen); 4443 mask=(size_t) (CWWidth | CWHeight); 4444 if (resource_info->backdrop) 4445 { 4446 mask|=CWX | CWY; 4447 window_changes.x=(int) 4448 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4449 window_changes.y=(int) 4450 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4451 } 4452 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4453 (unsigned int) mask,&window_changes); 4454 (void) XClearWindow(display,windows->image.id); 4455 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4456 /* 4457 Update Magnify window configuration. 4458 */ 4459 if (windows->magnify.mapped != MagickFalse) 4460 XMakeMagnifyImage(display,windows); 4461 windows->pan.crop_geometry=windows->image.crop_geometry; 4462 XBestIconSize(display,&windows->pan,image); 4463 while (((windows->pan.width << 1) < MaxIconSize) && 4464 ((windows->pan.height << 1) < MaxIconSize)) 4465 { 4466 windows->pan.width<<=1; 4467 windows->pan.height<<=1; 4468 } 4469 if (windows->pan.geometry != (char *) NULL) 4470 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4471 &windows->pan.width,&windows->pan.height); 4472 window_changes.width=(int) windows->pan.width; 4473 window_changes.height=(int) windows->pan.height; 4474 size_hints=XAllocSizeHints(); 4475 if (size_hints != (XSizeHints *) NULL) 4476 { 4477 /* 4478 Set new size hints. 4479 */ 4480 size_hints->flags=PSize | PMinSize | PMaxSize; 4481 size_hints->width=window_changes.width; 4482 size_hints->height=window_changes.height; 4483 size_hints->min_width=size_hints->width; 4484 size_hints->min_height=size_hints->height; 4485 size_hints->max_width=size_hints->width; 4486 size_hints->max_height=size_hints->height; 4487 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4488 (void) XFree((void *) size_hints); 4489 } 4490 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4491 (unsigned int) (CWWidth | CWHeight),&window_changes); 4492 /* 4493 Update icon window configuration. 4494 */ 4495 windows->icon.crop_geometry=windows->image.crop_geometry; 4496 XBestIconSize(display,&windows->icon,image); 4497 window_changes.width=(int) windows->icon.width; 4498 window_changes.height=(int) windows->icon.height; 4499 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4500 (unsigned int) (CWWidth | CWHeight),&window_changes); 4501 XSetCursorState(display,windows,MagickFalse); 4502 return(status != 0 ? MagickTrue : MagickFalse); 4503} 4504 4505/* 4506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4507% % 4508% % 4509% % 4510+ X C r o p I m a g e % 4511% % 4512% % 4513% % 4514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4515% 4516% XCropImage() allows the user to select a region of the image and crop, copy, 4517% or cut it. For copy or cut, the image can subsequently be composited onto 4518% the image with XPasteImage. 4519% 4520% The format of the XCropImage method is: 4521% 4522% MagickBooleanType XCropImage(Display *display, 4523% XResourceInfo *resource_info,XWindows *windows,Image *image, 4524% const ClipboardMode mode) 4525% 4526% A description of each parameter follows: 4527% 4528% o display: Specifies a connection to an X server; returned from 4529% XOpenDisplay. 4530% 4531% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4532% 4533% o windows: Specifies a pointer to a XWindows structure. 4534% 4535% o image: the image; returned from ReadImage. 4536% 4537% o mode: This unsigned value specified whether the image should be 4538% cropped, copied, or cut. 4539% 4540*/ 4541static MagickBooleanType XCropImage(Display *display, 4542 XResourceInfo *resource_info,XWindows *windows,Image *image, 4543 const ClipboardMode mode) 4544{ 4545 static const char 4546 *CropModeMenu[] = 4547 { 4548 "Help", 4549 "Dismiss", 4550 (char *) NULL 4551 }, 4552 *RectifyModeMenu[] = 4553 { 4554 "Crop", 4555 "Help", 4556 "Dismiss", 4557 (char *) NULL 4558 }; 4559 4560 static const ModeType 4561 CropCommands[] = 4562 { 4563 CropHelpCommand, 4564 CropDismissCommand 4565 }, 4566 RectifyCommands[] = 4567 { 4568 RectifyCopyCommand, 4569 RectifyHelpCommand, 4570 RectifyDismissCommand 4571 }; 4572 4573 CacheView 4574 *image_view; 4575 4576 char 4577 command[MaxTextExtent], 4578 text[MaxTextExtent]; 4579 4580 Cursor 4581 cursor; 4582 4583 ExceptionInfo 4584 *exception; 4585 4586 int 4587 id, 4588 x, 4589 y; 4590 4591 KeySym 4592 key_symbol; 4593 4594 Image 4595 *crop_image; 4596 4597 MagickRealType 4598 scale_factor; 4599 4600 RectangleInfo 4601 crop_info, 4602 highlight_info; 4603 4604 register Quantum 4605 *q; 4606 4607 unsigned int 4608 height, 4609 width; 4610 4611 size_t 4612 state; 4613 4614 XEvent 4615 event; 4616 4617 /* 4618 Map Command widget. 4619 */ 4620 switch (mode) 4621 { 4622 case CopyMode: 4623 { 4624 (void) CloneString(&windows->command.name,"Copy"); 4625 break; 4626 } 4627 case CropMode: 4628 { 4629 (void) CloneString(&windows->command.name,"Crop"); 4630 break; 4631 } 4632 case CutMode: 4633 { 4634 (void) CloneString(&windows->command.name,"Cut"); 4635 break; 4636 } 4637 } 4638 RectifyModeMenu[0]=windows->command.name; 4639 windows->command.data=0; 4640 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4641 (void) XMapRaised(display,windows->command.id); 4642 XClientMessage(display,windows->image.id,windows->im_protocols, 4643 windows->im_update_widget,CurrentTime); 4644 /* 4645 Track pointer until button 1 is pressed. 4646 */ 4647 XQueryPosition(display,windows->image.id,&x,&y); 4648 (void) XSelectInput(display,windows->image.id, 4649 windows->image.attributes.event_mask | PointerMotionMask); 4650 crop_info.x=(ssize_t) windows->image.x+x; 4651 crop_info.y=(ssize_t) windows->image.y+y; 4652 crop_info.width=0; 4653 crop_info.height=0; 4654 cursor=XCreateFontCursor(display,XC_fleur); 4655 state=DefaultState; 4656 do 4657 { 4658 if (windows->info.mapped != MagickFalse) 4659 { 4660 /* 4661 Display pointer position. 4662 */ 4663 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4664 (long) crop_info.x,(long) crop_info.y); 4665 XInfoWidget(display,windows,text); 4666 } 4667 /* 4668 Wait for next event. 4669 */ 4670 XScreenEvent(display,windows,&event); 4671 if (event.xany.window == windows->command.id) 4672 { 4673 /* 4674 Select a command from the Command widget. 4675 */ 4676 id=XCommandWidget(display,windows,CropModeMenu,&event); 4677 if (id < 0) 4678 continue; 4679 switch (CropCommands[id]) 4680 { 4681 case CropHelpCommand: 4682 { 4683 switch (mode) 4684 { 4685 case CopyMode: 4686 { 4687 XTextViewWidget(display,resource_info,windows,MagickFalse, 4688 "Help Viewer - Image Copy",ImageCopyHelp); 4689 break; 4690 } 4691 case CropMode: 4692 { 4693 XTextViewWidget(display,resource_info,windows,MagickFalse, 4694 "Help Viewer - Image Crop",ImageCropHelp); 4695 break; 4696 } 4697 case CutMode: 4698 { 4699 XTextViewWidget(display,resource_info,windows,MagickFalse, 4700 "Help Viewer - Image Cut",ImageCutHelp); 4701 break; 4702 } 4703 } 4704 break; 4705 } 4706 case CropDismissCommand: 4707 { 4708 /* 4709 Prematurely exit. 4710 */ 4711 state|=EscapeState; 4712 state|=ExitState; 4713 break; 4714 } 4715 default: 4716 break; 4717 } 4718 continue; 4719 } 4720 switch (event.type) 4721 { 4722 case ButtonPress: 4723 { 4724 if (event.xbutton.button != Button1) 4725 break; 4726 if (event.xbutton.window != windows->image.id) 4727 break; 4728 /* 4729 Note first corner of cropping rectangle-- exit loop. 4730 */ 4731 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4732 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4733 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4734 state|=ExitState; 4735 break; 4736 } 4737 case ButtonRelease: 4738 break; 4739 case Expose: 4740 break; 4741 case KeyPress: 4742 { 4743 if (event.xkey.window != windows->image.id) 4744 break; 4745 /* 4746 Respond to a user key press. 4747 */ 4748 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4749 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4750 switch ((int) key_symbol) 4751 { 4752 case XK_Escape: 4753 case XK_F20: 4754 { 4755 /* 4756 Prematurely exit. 4757 */ 4758 state|=EscapeState; 4759 state|=ExitState; 4760 break; 4761 } 4762 case XK_F1: 4763 case XK_Help: 4764 { 4765 switch (mode) 4766 { 4767 case CopyMode: 4768 { 4769 XTextViewWidget(display,resource_info,windows,MagickFalse, 4770 "Help Viewer - Image Copy",ImageCopyHelp); 4771 break; 4772 } 4773 case CropMode: 4774 { 4775 XTextViewWidget(display,resource_info,windows,MagickFalse, 4776 "Help Viewer - Image Crop",ImageCropHelp); 4777 break; 4778 } 4779 case CutMode: 4780 { 4781 XTextViewWidget(display,resource_info,windows,MagickFalse, 4782 "Help Viewer - Image Cut",ImageCutHelp); 4783 break; 4784 } 4785 } 4786 break; 4787 } 4788 default: 4789 { 4790 (void) XBell(display,0); 4791 break; 4792 } 4793 } 4794 break; 4795 } 4796 case MotionNotify: 4797 { 4798 if (event.xmotion.window != windows->image.id) 4799 break; 4800 /* 4801 Map and unmap Info widget as text cursor crosses its boundaries. 4802 */ 4803 x=event.xmotion.x; 4804 y=event.xmotion.y; 4805 if (windows->info.mapped != MagickFalse) 4806 { 4807 if ((x < (int) (windows->info.x+windows->info.width)) && 4808 (y < (int) (windows->info.y+windows->info.height))) 4809 (void) XWithdrawWindow(display,windows->info.id, 4810 windows->info.screen); 4811 } 4812 else 4813 if ((x > (int) (windows->info.x+windows->info.width)) || 4814 (y > (int) (windows->info.y+windows->info.height))) 4815 (void) XMapWindow(display,windows->info.id); 4816 crop_info.x=(ssize_t) windows->image.x+x; 4817 crop_info.y=(ssize_t) windows->image.y+y; 4818 break; 4819 } 4820 default: 4821 break; 4822 } 4823 } while ((state & ExitState) == 0); 4824 (void) XSelectInput(display,windows->image.id, 4825 windows->image.attributes.event_mask); 4826 if ((state & EscapeState) != 0) 4827 { 4828 /* 4829 User want to exit without cropping. 4830 */ 4831 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4832 (void) XFreeCursor(display,cursor); 4833 return(MagickTrue); 4834 } 4835 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4836 do 4837 { 4838 /* 4839 Size rectangle as pointer moves until the mouse button is released. 4840 */ 4841 x=(int) crop_info.x; 4842 y=(int) crop_info.y; 4843 crop_info.width=0; 4844 crop_info.height=0; 4845 state=DefaultState; 4846 do 4847 { 4848 highlight_info=crop_info; 4849 highlight_info.x=crop_info.x-windows->image.x; 4850 highlight_info.y=crop_info.y-windows->image.y; 4851 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4852 { 4853 /* 4854 Display info and draw cropping rectangle. 4855 */ 4856 if (windows->info.mapped == MagickFalse) 4857 (void) XMapWindow(display,windows->info.id); 4858 (void) FormatLocaleString(text,MaxTextExtent, 4859 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4860 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4861 XInfoWidget(display,windows,text); 4862 XHighlightRectangle(display,windows->image.id, 4863 windows->image.highlight_context,&highlight_info); 4864 } 4865 else 4866 if (windows->info.mapped != MagickFalse) 4867 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4868 /* 4869 Wait for next event. 4870 */ 4871 XScreenEvent(display,windows,&event); 4872 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4873 XHighlightRectangle(display,windows->image.id, 4874 windows->image.highlight_context,&highlight_info); 4875 switch (event.type) 4876 { 4877 case ButtonPress: 4878 { 4879 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4880 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4881 break; 4882 } 4883 case ButtonRelease: 4884 { 4885 /* 4886 User has committed to cropping rectangle. 4887 */ 4888 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4889 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4890 XSetCursorState(display,windows,MagickFalse); 4891 state|=ExitState; 4892 windows->command.data=0; 4893 (void) XCommandWidget(display,windows,RectifyModeMenu, 4894 (XEvent *) NULL); 4895 break; 4896 } 4897 case Expose: 4898 break; 4899 case MotionNotify: 4900 { 4901 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4902 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4903 } 4904 default: 4905 break; 4906 } 4907 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4908 ((state & ExitState) != 0)) 4909 { 4910 /* 4911 Check boundary conditions. 4912 */ 4913 if (crop_info.x < 0) 4914 crop_info.x=0; 4915 else 4916 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4917 crop_info.x=(ssize_t) windows->image.ximage->width; 4918 if ((int) crop_info.x < x) 4919 crop_info.width=(unsigned int) (x-crop_info.x); 4920 else 4921 { 4922 crop_info.width=(unsigned int) (crop_info.x-x); 4923 crop_info.x=(ssize_t) x; 4924 } 4925 if (crop_info.y < 0) 4926 crop_info.y=0; 4927 else 4928 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4929 crop_info.y=(ssize_t) windows->image.ximage->height; 4930 if ((int) crop_info.y < y) 4931 crop_info.height=(unsigned int) (y-crop_info.y); 4932 else 4933 { 4934 crop_info.height=(unsigned int) (crop_info.y-y); 4935 crop_info.y=(ssize_t) y; 4936 } 4937 } 4938 } while ((state & ExitState) == 0); 4939 /* 4940 Wait for user to grab a corner of the rectangle or press return. 4941 */ 4942 state=DefaultState; 4943 (void) XMapWindow(display,windows->info.id); 4944 do 4945 { 4946 if (windows->info.mapped != MagickFalse) 4947 { 4948 /* 4949 Display pointer position. 4950 */ 4951 (void) FormatLocaleString(text,MaxTextExtent, 4952 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4953 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4954 XInfoWidget(display,windows,text); 4955 } 4956 highlight_info=crop_info; 4957 highlight_info.x=crop_info.x-windows->image.x; 4958 highlight_info.y=crop_info.y-windows->image.y; 4959 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4960 { 4961 state|=EscapeState; 4962 state|=ExitState; 4963 break; 4964 } 4965 XHighlightRectangle(display,windows->image.id, 4966 windows->image.highlight_context,&highlight_info); 4967 XScreenEvent(display,windows,&event); 4968 if (event.xany.window == windows->command.id) 4969 { 4970 /* 4971 Select a command from the Command widget. 4972 */ 4973 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4974 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 4975 (void) XSetFunction(display,windows->image.highlight_context, 4976 GXinvert); 4977 XHighlightRectangle(display,windows->image.id, 4978 windows->image.highlight_context,&highlight_info); 4979 if (id >= 0) 4980 switch (RectifyCommands[id]) 4981 { 4982 case RectifyCopyCommand: 4983 { 4984 state|=ExitState; 4985 break; 4986 } 4987 case RectifyHelpCommand: 4988 { 4989 (void) XSetFunction(display,windows->image.highlight_context, 4990 GXcopy); 4991 switch (mode) 4992 { 4993 case CopyMode: 4994 { 4995 XTextViewWidget(display,resource_info,windows,MagickFalse, 4996 "Help Viewer - Image Copy",ImageCopyHelp); 4997 break; 4998 } 4999 case CropMode: 5000 { 5001 XTextViewWidget(display,resource_info,windows,MagickFalse, 5002 "Help Viewer - Image Crop",ImageCropHelp); 5003 break; 5004 } 5005 case CutMode: 5006 { 5007 XTextViewWidget(display,resource_info,windows,MagickFalse, 5008 "Help Viewer - Image Cut",ImageCutHelp); 5009 break; 5010 } 5011 } 5012 (void) XSetFunction(display,windows->image.highlight_context, 5013 GXinvert); 5014 break; 5015 } 5016 case RectifyDismissCommand: 5017 { 5018 /* 5019 Prematurely exit. 5020 */ 5021 state|=EscapeState; 5022 state|=ExitState; 5023 break; 5024 } 5025 default: 5026 break; 5027 } 5028 continue; 5029 } 5030 XHighlightRectangle(display,windows->image.id, 5031 windows->image.highlight_context,&highlight_info); 5032 switch (event.type) 5033 { 5034 case ButtonPress: 5035 { 5036 if (event.xbutton.button != Button1) 5037 break; 5038 if (event.xbutton.window != windows->image.id) 5039 break; 5040 x=windows->image.x+event.xbutton.x; 5041 y=windows->image.y+event.xbutton.y; 5042 if ((x < (int) (crop_info.x+RoiDelta)) && 5043 (x > (int) (crop_info.x-RoiDelta)) && 5044 (y < (int) (crop_info.y+RoiDelta)) && 5045 (y > (int) (crop_info.y-RoiDelta))) 5046 { 5047 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5048 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5049 state|=UpdateConfigurationState; 5050 break; 5051 } 5052 if ((x < (int) (crop_info.x+RoiDelta)) && 5053 (x > (int) (crop_info.x-RoiDelta)) && 5054 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5055 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5056 { 5057 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5058 state|=UpdateConfigurationState; 5059 break; 5060 } 5061 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5062 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5063 (y < (int) (crop_info.y+RoiDelta)) && 5064 (y > (int) (crop_info.y-RoiDelta))) 5065 { 5066 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5067 state|=UpdateConfigurationState; 5068 break; 5069 } 5070 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5071 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5072 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5073 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5074 { 5075 state|=UpdateConfigurationState; 5076 break; 5077 } 5078 } 5079 case ButtonRelease: 5080 { 5081 if (event.xbutton.window == windows->pan.id) 5082 if ((highlight_info.x != crop_info.x-windows->image.x) || 5083 (highlight_info.y != crop_info.y-windows->image.y)) 5084 XHighlightRectangle(display,windows->image.id, 5085 windows->image.highlight_context,&highlight_info); 5086 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5087 event.xbutton.time); 5088 break; 5089 } 5090 case Expose: 5091 { 5092 if (event.xexpose.window == windows->image.id) 5093 if (event.xexpose.count == 0) 5094 { 5095 event.xexpose.x=(int) highlight_info.x; 5096 event.xexpose.y=(int) highlight_info.y; 5097 event.xexpose.width=(int) highlight_info.width; 5098 event.xexpose.height=(int) highlight_info.height; 5099 XRefreshWindow(display,&windows->image,&event); 5100 } 5101 if (event.xexpose.window == windows->info.id) 5102 if (event.xexpose.count == 0) 5103 XInfoWidget(display,windows,text); 5104 break; 5105 } 5106 case KeyPress: 5107 { 5108 if (event.xkey.window != windows->image.id) 5109 break; 5110 /* 5111 Respond to a user key press. 5112 */ 5113 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5114 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5115 switch ((int) key_symbol) 5116 { 5117 case XK_Escape: 5118 case XK_F20: 5119 state|=EscapeState; 5120 case XK_Return: 5121 { 5122 state|=ExitState; 5123 break; 5124 } 5125 case XK_Home: 5126 case XK_KP_Home: 5127 { 5128 crop_info.x=(ssize_t) (windows->image.width/2L- 5129 crop_info.width/2L); 5130 crop_info.y=(ssize_t) (windows->image.height/2L- 5131 crop_info.height/2L); 5132 break; 5133 } 5134 case XK_Left: 5135 case XK_KP_Left: 5136 { 5137 crop_info.x--; 5138 break; 5139 } 5140 case XK_Up: 5141 case XK_KP_Up: 5142 case XK_Next: 5143 { 5144 crop_info.y--; 5145 break; 5146 } 5147 case XK_Right: 5148 case XK_KP_Right: 5149 { 5150 crop_info.x++; 5151 break; 5152 } 5153 case XK_Prior: 5154 case XK_Down: 5155 case XK_KP_Down: 5156 { 5157 crop_info.y++; 5158 break; 5159 } 5160 case XK_F1: 5161 case XK_Help: 5162 { 5163 (void) XSetFunction(display,windows->image.highlight_context, 5164 GXcopy); 5165 switch (mode) 5166 { 5167 case CopyMode: 5168 { 5169 XTextViewWidget(display,resource_info,windows,MagickFalse, 5170 "Help Viewer - Image Copy",ImageCopyHelp); 5171 break; 5172 } 5173 case CropMode: 5174 { 5175 XTextViewWidget(display,resource_info,windows,MagickFalse, 5176 "Help Viewer - Image Cropg",ImageCropHelp); 5177 break; 5178 } 5179 case CutMode: 5180 { 5181 XTextViewWidget(display,resource_info,windows,MagickFalse, 5182 "Help Viewer - Image Cutg",ImageCutHelp); 5183 break; 5184 } 5185 } 5186 (void) XSetFunction(display,windows->image.highlight_context, 5187 GXinvert); 5188 break; 5189 } 5190 default: 5191 { 5192 (void) XBell(display,0); 5193 break; 5194 } 5195 } 5196 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5197 event.xkey.time); 5198 break; 5199 } 5200 case KeyRelease: 5201 break; 5202 case MotionNotify: 5203 { 5204 if (event.xmotion.window != windows->image.id) 5205 break; 5206 /* 5207 Map and unmap Info widget as text cursor crosses its boundaries. 5208 */ 5209 x=event.xmotion.x; 5210 y=event.xmotion.y; 5211 if (windows->info.mapped != MagickFalse) 5212 { 5213 if ((x < (int) (windows->info.x+windows->info.width)) && 5214 (y < (int) (windows->info.y+windows->info.height))) 5215 (void) XWithdrawWindow(display,windows->info.id, 5216 windows->info.screen); 5217 } 5218 else 5219 if ((x > (int) (windows->info.x+windows->info.width)) || 5220 (y > (int) (windows->info.y+windows->info.height))) 5221 (void) XMapWindow(display,windows->info.id); 5222 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5223 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5224 break; 5225 } 5226 case SelectionRequest: 5227 { 5228 XSelectionEvent 5229 notify; 5230 5231 XSelectionRequestEvent 5232 *request; 5233 5234 /* 5235 Set primary selection. 5236 */ 5237 (void) FormatLocaleString(text,MaxTextExtent, 5238 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5239 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5240 request=(&(event.xselectionrequest)); 5241 (void) XChangeProperty(request->display,request->requestor, 5242 request->property,request->target,8,PropModeReplace, 5243 (unsigned char *) text,(int) strlen(text)); 5244 notify.type=SelectionNotify; 5245 notify.display=request->display; 5246 notify.requestor=request->requestor; 5247 notify.selection=request->selection; 5248 notify.target=request->target; 5249 notify.time=request->time; 5250 if (request->property == None) 5251 notify.property=request->target; 5252 else 5253 notify.property=request->property; 5254 (void) XSendEvent(request->display,request->requestor,False,0, 5255 (XEvent *) ¬ify); 5256 } 5257 default: 5258 break; 5259 } 5260 if ((state & UpdateConfigurationState) != 0) 5261 { 5262 (void) XPutBackEvent(display,&event); 5263 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5264 break; 5265 } 5266 } while ((state & ExitState) == 0); 5267 } while ((state & ExitState) == 0); 5268 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5269 XSetCursorState(display,windows,MagickFalse); 5270 if ((state & EscapeState) != 0) 5271 return(MagickTrue); 5272 if (mode == CropMode) 5273 if (((int) crop_info.width != windows->image.ximage->width) || 5274 ((int) crop_info.height != windows->image.ximage->height)) 5275 { 5276 /* 5277 Reconfigure Image window as defined by cropping rectangle. 5278 */ 5279 XSetCropGeometry(display,windows,&crop_info,image); 5280 windows->image.window_changes.width=(int) crop_info.width; 5281 windows->image.window_changes.height=(int) crop_info.height; 5282 (void) XConfigureImage(display,resource_info,windows,image); 5283 return(MagickTrue); 5284 } 5285 /* 5286 Copy image before applying image transforms. 5287 */ 5288 XSetCursorState(display,windows,MagickTrue); 5289 XCheckRefreshWindows(display,windows); 5290 width=(unsigned int) image->columns; 5291 height=(unsigned int) image->rows; 5292 x=0; 5293 y=0; 5294 if (windows->image.crop_geometry != (char *) NULL) 5295 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5296 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5297 crop_info.x+=x; 5298 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5299 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5300 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5301 crop_info.y+=y; 5302 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5303 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5304 crop_image=CropImage(image,&crop_info,&image->exception); 5305 XSetCursorState(display,windows,MagickFalse); 5306 if (crop_image == (Image *) NULL) 5307 return(MagickFalse); 5308 if (resource_info->copy_image != (Image *) NULL) 5309 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5310 resource_info->copy_image=crop_image; 5311 if (mode == CopyMode) 5312 { 5313 (void) XConfigureImage(display,resource_info,windows,image); 5314 return(MagickTrue); 5315 } 5316 /* 5317 Cut image. 5318 */ 5319 exception=(&image->exception); 5320 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5321 return(MagickFalse); 5322 image->matte=MagickTrue; 5323 image_view=AcquireCacheView(image); 5324 for (y=0; y < (int) crop_info.height; y++) 5325 { 5326 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5327 crop_info.width,1,exception); 5328 if (q == (Quantum *) NULL) 5329 break; 5330 for (x=0; x < (int) crop_info.width; x++) 5331 { 5332 SetPixelAlpha(image,TransparentAlpha,q); 5333 q+=GetPixelChannels(image); 5334 } 5335 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5336 break; 5337 } 5338 image_view=DestroyCacheView(image_view); 5339 /* 5340 Update image configuration. 5341 */ 5342 XConfigureImageColormap(display,resource_info,windows,image); 5343 (void) XConfigureImage(display,resource_info,windows,image); 5344 return(MagickTrue); 5345} 5346 5347/* 5348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5349% % 5350% % 5351% % 5352+ X D r a w I m a g e % 5353% % 5354% % 5355% % 5356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5357% 5358% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5359% the image. 5360% 5361% The format of the XDrawEditImage method is: 5362% 5363% MagickBooleanType XDrawEditImage(Display *display, 5364% XResourceInfo *resource_info,XWindows *windows,Image **image) 5365% 5366% A description of each parameter follows: 5367% 5368% o display: Specifies a connection to an X server; returned from 5369% XOpenDisplay. 5370% 5371% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5372% 5373% o windows: Specifies a pointer to a XWindows structure. 5374% 5375% o image: the image. 5376% 5377*/ 5378static MagickBooleanType XDrawEditImage(Display *display, 5379 XResourceInfo *resource_info,XWindows *windows,Image **image) 5380{ 5381 static const char 5382 *DrawMenu[] = 5383 { 5384 "Element", 5385 "Color", 5386 "Stipple", 5387 "Width", 5388 "Undo", 5389 "Help", 5390 "Dismiss", 5391 (char *) NULL 5392 }; 5393 5394 static ElementType 5395 element = PointElement; 5396 5397 static const ModeType 5398 DrawCommands[] = 5399 { 5400 DrawElementCommand, 5401 DrawColorCommand, 5402 DrawStippleCommand, 5403 DrawWidthCommand, 5404 DrawUndoCommand, 5405 DrawHelpCommand, 5406 DrawDismissCommand 5407 }; 5408 5409 static Pixmap 5410 stipple = (Pixmap) NULL; 5411 5412 static unsigned int 5413 pen_id = 0, 5414 line_width = 1; 5415 5416 char 5417 command[MaxTextExtent], 5418 text[MaxTextExtent]; 5419 5420 Cursor 5421 cursor; 5422 5423 int 5424 entry, 5425 id, 5426 number_coordinates, 5427 x, 5428 y; 5429 5430 MagickRealType 5431 degrees; 5432 5433 MagickStatusType 5434 status; 5435 5436 RectangleInfo 5437 rectangle_info; 5438 5439 register int 5440 i; 5441 5442 unsigned int 5443 distance, 5444 height, 5445 max_coordinates, 5446 width; 5447 5448 size_t 5449 state; 5450 5451 Window 5452 root_window; 5453 5454 XDrawInfo 5455 draw_info; 5456 5457 XEvent 5458 event; 5459 5460 XPoint 5461 *coordinate_info; 5462 5463 XSegment 5464 line_info; 5465 5466 /* 5467 Allocate polygon info. 5468 */ 5469 max_coordinates=2048; 5470 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5471 sizeof(*coordinate_info)); 5472 if (coordinate_info == (XPoint *) NULL) 5473 { 5474 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 5475 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5476 return(MagickFalse); 5477 } 5478 /* 5479 Map Command widget. 5480 */ 5481 (void) CloneString(&windows->command.name,"Draw"); 5482 windows->command.data=4; 5483 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5484 (void) XMapRaised(display,windows->command.id); 5485 XClientMessage(display,windows->image.id,windows->im_protocols, 5486 windows->im_update_widget,CurrentTime); 5487 /* 5488 Wait for first button press. 5489 */ 5490 root_window=XRootWindow(display,XDefaultScreen(display)); 5491 draw_info.stencil=OpaqueStencil; 5492 status=MagickTrue; 5493 cursor=XCreateFontCursor(display,XC_tcross); 5494 for ( ; ; ) 5495 { 5496 XQueryPosition(display,windows->image.id,&x,&y); 5497 (void) XSelectInput(display,windows->image.id, 5498 windows->image.attributes.event_mask | PointerMotionMask); 5499 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5500 state=DefaultState; 5501 do 5502 { 5503 if (windows->info.mapped != MagickFalse) 5504 { 5505 /* 5506 Display pointer position. 5507 */ 5508 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5509 x+windows->image.x,y+windows->image.y); 5510 XInfoWidget(display,windows,text); 5511 } 5512 /* 5513 Wait for next event. 5514 */ 5515 XScreenEvent(display,windows,&event); 5516 if (event.xany.window == windows->command.id) 5517 { 5518 /* 5519 Select a command from the Command widget. 5520 */ 5521 id=XCommandWidget(display,windows,DrawMenu,&event); 5522 if (id < 0) 5523 continue; 5524 switch (DrawCommands[id]) 5525 { 5526 case DrawElementCommand: 5527 { 5528 static const char 5529 *Elements[] = 5530 { 5531 "point", 5532 "line", 5533 "rectangle", 5534 "fill rectangle", 5535 "circle", 5536 "fill circle", 5537 "ellipse", 5538 "fill ellipse", 5539 "polygon", 5540 "fill polygon", 5541 (char *) NULL, 5542 }; 5543 5544 /* 5545 Select a command from the pop-up menu. 5546 */ 5547 element=(ElementType) (XMenuWidget(display,windows, 5548 DrawMenu[id],Elements,command)+1); 5549 break; 5550 } 5551 case DrawColorCommand: 5552 { 5553 const char 5554 *ColorMenu[MaxNumberPens+1]; 5555 5556 int 5557 pen_number; 5558 5559 MagickBooleanType 5560 transparent; 5561 5562 XColor 5563 color; 5564 5565 /* 5566 Initialize menu selections. 5567 */ 5568 for (i=0; i < (int) (MaxNumberPens-2); i++) 5569 ColorMenu[i]=resource_info->pen_colors[i]; 5570 ColorMenu[MaxNumberPens-2]="transparent"; 5571 ColorMenu[MaxNumberPens-1]="Browser..."; 5572 ColorMenu[MaxNumberPens]=(char *) NULL; 5573 /* 5574 Select a pen color from the pop-up menu. 5575 */ 5576 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5577 (const char **) ColorMenu,command); 5578 if (pen_number < 0) 5579 break; 5580 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5581 MagickFalse; 5582 if (transparent != MagickFalse) 5583 { 5584 draw_info.stencil=TransparentStencil; 5585 break; 5586 } 5587 if (pen_number == (MaxNumberPens-1)) 5588 { 5589 static char 5590 color_name[MaxTextExtent] = "gray"; 5591 5592 /* 5593 Select a pen color from a dialog. 5594 */ 5595 resource_info->pen_colors[pen_number]=color_name; 5596 XColorBrowserWidget(display,windows,"Select",color_name); 5597 if (*color_name == '\0') 5598 break; 5599 } 5600 /* 5601 Set pen color. 5602 */ 5603 (void) XParseColor(display,windows->map_info->colormap, 5604 resource_info->pen_colors[pen_number],&color); 5605 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5606 (unsigned int) MaxColors,&color); 5607 windows->pixel_info->pen_colors[pen_number]=color; 5608 pen_id=(unsigned int) pen_number; 5609 draw_info.stencil=OpaqueStencil; 5610 break; 5611 } 5612 case DrawStippleCommand: 5613 { 5614 Image 5615 *stipple_image; 5616 5617 ImageInfo 5618 *image_info; 5619 5620 int 5621 status; 5622 5623 static char 5624 filename[MaxTextExtent] = "\0"; 5625 5626 static const char 5627 *StipplesMenu[] = 5628 { 5629 "Brick", 5630 "Diagonal", 5631 "Scales", 5632 "Vertical", 5633 "Wavy", 5634 "Translucent", 5635 "Opaque", 5636 (char *) NULL, 5637 (char *) NULL, 5638 }; 5639 5640 /* 5641 Select a command from the pop-up menu. 5642 */ 5643 StipplesMenu[7]="Open..."; 5644 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5645 command); 5646 if (entry < 0) 5647 break; 5648 if (stipple != (Pixmap) NULL) 5649 (void) XFreePixmap(display,stipple); 5650 stipple=(Pixmap) NULL; 5651 if (entry != 7) 5652 { 5653 switch (entry) 5654 { 5655 case 0: 5656 { 5657 stipple=XCreateBitmapFromData(display,root_window, 5658 (char *) BricksBitmap,BricksWidth,BricksHeight); 5659 break; 5660 } 5661 case 1: 5662 { 5663 stipple=XCreateBitmapFromData(display,root_window, 5664 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5665 break; 5666 } 5667 case 2: 5668 { 5669 stipple=XCreateBitmapFromData(display,root_window, 5670 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5671 break; 5672 } 5673 case 3: 5674 { 5675 stipple=XCreateBitmapFromData(display,root_window, 5676 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5677 break; 5678 } 5679 case 4: 5680 { 5681 stipple=XCreateBitmapFromData(display,root_window, 5682 (char *) WavyBitmap,WavyWidth,WavyHeight); 5683 break; 5684 } 5685 case 5: 5686 { 5687 stipple=XCreateBitmapFromData(display,root_window, 5688 (char *) HighlightBitmap,HighlightWidth, 5689 HighlightHeight); 5690 break; 5691 } 5692 case 6: 5693 default: 5694 { 5695 stipple=XCreateBitmapFromData(display,root_window, 5696 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5697 break; 5698 } 5699 } 5700 break; 5701 } 5702 XFileBrowserWidget(display,windows,"Stipple",filename); 5703 if (*filename == '\0') 5704 break; 5705 /* 5706 Read image. 5707 */ 5708 XSetCursorState(display,windows,MagickTrue); 5709 XCheckRefreshWindows(display,windows); 5710 image_info=AcquireImageInfo(); 5711 (void) CopyMagickString(image_info->filename,filename, 5712 MaxTextExtent); 5713 stipple_image=ReadImage(image_info,&(*image)->exception); 5714 CatchException(&(*image)->exception); 5715 XSetCursorState(display,windows,MagickFalse); 5716 if (stipple_image == (Image *) NULL) 5717 break; 5718 (void) AcquireUniqueFileResource(filename); 5719 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5720 "xbm:%s",filename); 5721 (void) WriteImage(image_info,stipple_image); 5722 stipple_image=DestroyImage(stipple_image); 5723 image_info=DestroyImageInfo(image_info); 5724 status=XReadBitmapFile(display,root_window,filename,&width, 5725 &height,&stipple,&x,&y); 5726 (void) RelinquishUniqueFileResource(filename); 5727 if ((status != BitmapSuccess) != 0) 5728 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5729 filename); 5730 break; 5731 } 5732 case DrawWidthCommand: 5733 { 5734 static char 5735 width[MaxTextExtent] = "0"; 5736 5737 static const char 5738 *WidthsMenu[] = 5739 { 5740 "1", 5741 "2", 5742 "4", 5743 "8", 5744 "16", 5745 "Dialog...", 5746 (char *) NULL, 5747 }; 5748 5749 /* 5750 Select a command from the pop-up menu. 5751 */ 5752 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5753 command); 5754 if (entry < 0) 5755 break; 5756 if (entry != 5) 5757 { 5758 line_width=(unsigned int) StringToUnsignedLong( 5759 WidthsMenu[entry]); 5760 break; 5761 } 5762 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5763 width); 5764 if (*width == '\0') 5765 break; 5766 line_width=(unsigned int) StringToUnsignedLong(width); 5767 break; 5768 } 5769 case DrawUndoCommand: 5770 { 5771 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5772 image); 5773 break; 5774 } 5775 case DrawHelpCommand: 5776 { 5777 XTextViewWidget(display,resource_info,windows,MagickFalse, 5778 "Help Viewer - Image Rotation",ImageDrawHelp); 5779 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5780 break; 5781 } 5782 case DrawDismissCommand: 5783 { 5784 /* 5785 Prematurely exit. 5786 */ 5787 state|=EscapeState; 5788 state|=ExitState; 5789 break; 5790 } 5791 default: 5792 break; 5793 } 5794 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5795 continue; 5796 } 5797 switch (event.type) 5798 { 5799 case ButtonPress: 5800 { 5801 if (event.xbutton.button != Button1) 5802 break; 5803 if (event.xbutton.window != windows->image.id) 5804 break; 5805 /* 5806 exit loop. 5807 */ 5808 x=event.xbutton.x; 5809 y=event.xbutton.y; 5810 state|=ExitState; 5811 break; 5812 } 5813 case ButtonRelease: 5814 break; 5815 case Expose: 5816 break; 5817 case KeyPress: 5818 { 5819 KeySym 5820 key_symbol; 5821 5822 if (event.xkey.window != windows->image.id) 5823 break; 5824 /* 5825 Respond to a user key press. 5826 */ 5827 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5828 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5829 switch ((int) key_symbol) 5830 { 5831 case XK_Escape: 5832 case XK_F20: 5833 { 5834 /* 5835 Prematurely exit. 5836 */ 5837 state|=EscapeState; 5838 state|=ExitState; 5839 break; 5840 } 5841 case XK_F1: 5842 case XK_Help: 5843 { 5844 XTextViewWidget(display,resource_info,windows,MagickFalse, 5845 "Help Viewer - Image Rotation",ImageDrawHelp); 5846 break; 5847 } 5848 default: 5849 { 5850 (void) XBell(display,0); 5851 break; 5852 } 5853 } 5854 break; 5855 } 5856 case MotionNotify: 5857 { 5858 /* 5859 Map and unmap Info widget as text cursor crosses its boundaries. 5860 */ 5861 x=event.xmotion.x; 5862 y=event.xmotion.y; 5863 if (windows->info.mapped != MagickFalse) 5864 { 5865 if ((x < (int) (windows->info.x+windows->info.width)) && 5866 (y < (int) (windows->info.y+windows->info.height))) 5867 (void) XWithdrawWindow(display,windows->info.id, 5868 windows->info.screen); 5869 } 5870 else 5871 if ((x > (int) (windows->info.x+windows->info.width)) || 5872 (y > (int) (windows->info.y+windows->info.height))) 5873 (void) XMapWindow(display,windows->info.id); 5874 break; 5875 } 5876 } 5877 } while ((state & ExitState) == 0); 5878 (void) XSelectInput(display,windows->image.id, 5879 windows->image.attributes.event_mask); 5880 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5881 if ((state & EscapeState) != 0) 5882 break; 5883 /* 5884 Draw element as pointer moves until the button is released. 5885 */ 5886 distance=0; 5887 degrees=0.0; 5888 line_info.x1=x; 5889 line_info.y1=y; 5890 line_info.x2=x; 5891 line_info.y2=y; 5892 rectangle_info.x=(ssize_t) x; 5893 rectangle_info.y=(ssize_t) y; 5894 rectangle_info.width=0; 5895 rectangle_info.height=0; 5896 number_coordinates=1; 5897 coordinate_info->x=x; 5898 coordinate_info->y=y; 5899 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5900 state=DefaultState; 5901 do 5902 { 5903 switch (element) 5904 { 5905 case PointElement: 5906 default: 5907 { 5908 if (number_coordinates > 1) 5909 { 5910 (void) XDrawLines(display,windows->image.id, 5911 windows->image.highlight_context,coordinate_info, 5912 number_coordinates,CoordModeOrigin); 5913 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5914 coordinate_info[number_coordinates-1].x, 5915 coordinate_info[number_coordinates-1].y); 5916 XInfoWidget(display,windows,text); 5917 } 5918 break; 5919 } 5920 case LineElement: 5921 { 5922 if (distance > 9) 5923 { 5924 /* 5925 Display angle of the line. 5926 */ 5927 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5928 line_info.y1),(double) (line_info.x2-line_info.x1))); 5929 (void) FormatLocaleString(text,MaxTextExtent," %g", 5930 (double) degrees); 5931 XInfoWidget(display,windows,text); 5932 XHighlightLine(display,windows->image.id, 5933 windows->image.highlight_context,&line_info); 5934 } 5935 else 5936 if (windows->info.mapped != MagickFalse) 5937 (void) XWithdrawWindow(display,windows->info.id, 5938 windows->info.screen); 5939 break; 5940 } 5941 case RectangleElement: 5942 case FillRectangleElement: 5943 { 5944 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5945 { 5946 /* 5947 Display info and draw drawing rectangle. 5948 */ 5949 (void) FormatLocaleString(text,MaxTextExtent, 5950 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5951 (double) rectangle_info.height,(double) rectangle_info.x, 5952 (double) rectangle_info.y); 5953 XInfoWidget(display,windows,text); 5954 XHighlightRectangle(display,windows->image.id, 5955 windows->image.highlight_context,&rectangle_info); 5956 } 5957 else 5958 if (windows->info.mapped != MagickFalse) 5959 (void) XWithdrawWindow(display,windows->info.id, 5960 windows->info.screen); 5961 break; 5962 } 5963 case CircleElement: 5964 case FillCircleElement: 5965 case EllipseElement: 5966 case FillEllipseElement: 5967 { 5968 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5969 { 5970 /* 5971 Display info and draw drawing rectangle. 5972 */ 5973 (void) FormatLocaleString(text,MaxTextExtent, 5974 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5975 (double) rectangle_info.height,(double) rectangle_info.x, 5976 (double) rectangle_info.y); 5977 XInfoWidget(display,windows,text); 5978 XHighlightEllipse(display,windows->image.id, 5979 windows->image.highlight_context,&rectangle_info); 5980 } 5981 else 5982 if (windows->info.mapped != MagickFalse) 5983 (void) XWithdrawWindow(display,windows->info.id, 5984 windows->info.screen); 5985 break; 5986 } 5987 case PolygonElement: 5988 case FillPolygonElement: 5989 { 5990 if (number_coordinates > 1) 5991 (void) XDrawLines(display,windows->image.id, 5992 windows->image.highlight_context,coordinate_info, 5993 number_coordinates,CoordModeOrigin); 5994 if (distance > 9) 5995 { 5996 /* 5997 Display angle of the line. 5998 */ 5999 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6000 line_info.y1),(double) (line_info.x2-line_info.x1))); 6001 (void) FormatLocaleString(text,MaxTextExtent," %g", 6002 (double) degrees); 6003 XInfoWidget(display,windows,text); 6004 XHighlightLine(display,windows->image.id, 6005 windows->image.highlight_context,&line_info); 6006 } 6007 else 6008 if (windows->info.mapped != MagickFalse) 6009 (void) XWithdrawWindow(display,windows->info.id, 6010 windows->info.screen); 6011 break; 6012 } 6013 } 6014 /* 6015 Wait for next event. 6016 */ 6017 XScreenEvent(display,windows,&event); 6018 switch (element) 6019 { 6020 case PointElement: 6021 default: 6022 { 6023 if (number_coordinates > 1) 6024 (void) XDrawLines(display,windows->image.id, 6025 windows->image.highlight_context,coordinate_info, 6026 number_coordinates,CoordModeOrigin); 6027 break; 6028 } 6029 case LineElement: 6030 { 6031 if (distance > 9) 6032 XHighlightLine(display,windows->image.id, 6033 windows->image.highlight_context,&line_info); 6034 break; 6035 } 6036 case RectangleElement: 6037 case FillRectangleElement: 6038 { 6039 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6040 XHighlightRectangle(display,windows->image.id, 6041 windows->image.highlight_context,&rectangle_info); 6042 break; 6043 } 6044 case CircleElement: 6045 case FillCircleElement: 6046 case EllipseElement: 6047 case FillEllipseElement: 6048 { 6049 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6050 XHighlightEllipse(display,windows->image.id, 6051 windows->image.highlight_context,&rectangle_info); 6052 break; 6053 } 6054 case PolygonElement: 6055 case FillPolygonElement: 6056 { 6057 if (number_coordinates > 1) 6058 (void) XDrawLines(display,windows->image.id, 6059 windows->image.highlight_context,coordinate_info, 6060 number_coordinates,CoordModeOrigin); 6061 if (distance > 9) 6062 XHighlightLine(display,windows->image.id, 6063 windows->image.highlight_context,&line_info); 6064 break; 6065 } 6066 } 6067 switch (event.type) 6068 { 6069 case ButtonPress: 6070 break; 6071 case ButtonRelease: 6072 { 6073 /* 6074 User has committed to element. 6075 */ 6076 line_info.x2=event.xbutton.x; 6077 line_info.y2=event.xbutton.y; 6078 rectangle_info.x=(ssize_t) event.xbutton.x; 6079 rectangle_info.y=(ssize_t) event.xbutton.y; 6080 coordinate_info[number_coordinates].x=event.xbutton.x; 6081 coordinate_info[number_coordinates].y=event.xbutton.y; 6082 if (((element != PolygonElement) && 6083 (element != FillPolygonElement)) || (distance <= 9)) 6084 { 6085 state|=ExitState; 6086 break; 6087 } 6088 number_coordinates++; 6089 if (number_coordinates < (int) max_coordinates) 6090 { 6091 line_info.x1=event.xbutton.x; 6092 line_info.y1=event.xbutton.y; 6093 break; 6094 } 6095 max_coordinates<<=1; 6096 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6097 max_coordinates,sizeof(*coordinate_info)); 6098 if (coordinate_info == (XPoint *) NULL) 6099 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 6100 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6101 break; 6102 } 6103 case Expose: 6104 break; 6105 case MotionNotify: 6106 { 6107 if (event.xmotion.window != windows->image.id) 6108 break; 6109 if (element != PointElement) 6110 { 6111 line_info.x2=event.xmotion.x; 6112 line_info.y2=event.xmotion.y; 6113 rectangle_info.x=(ssize_t) event.xmotion.x; 6114 rectangle_info.y=(ssize_t) event.xmotion.y; 6115 break; 6116 } 6117 coordinate_info[number_coordinates].x=event.xbutton.x; 6118 coordinate_info[number_coordinates].y=event.xbutton.y; 6119 number_coordinates++; 6120 if (number_coordinates < (int) max_coordinates) 6121 break; 6122 max_coordinates<<=1; 6123 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6124 max_coordinates,sizeof(*coordinate_info)); 6125 if (coordinate_info == (XPoint *) NULL) 6126 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 6127 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6128 break; 6129 } 6130 default: 6131 break; 6132 } 6133 /* 6134 Check boundary conditions. 6135 */ 6136 if (line_info.x2 < 0) 6137 line_info.x2=0; 6138 else 6139 if (line_info.x2 > (int) windows->image.width) 6140 line_info.x2=(short) windows->image.width; 6141 if (line_info.y2 < 0) 6142 line_info.y2=0; 6143 else 6144 if (line_info.y2 > (int) windows->image.height) 6145 line_info.y2=(short) windows->image.height; 6146 distance=(unsigned int) 6147 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6148 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6149 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6150 ((state & ExitState) != 0)) 6151 { 6152 if (rectangle_info.x < 0) 6153 rectangle_info.x=0; 6154 else 6155 if (rectangle_info.x > (ssize_t) windows->image.width) 6156 rectangle_info.x=(ssize_t) windows->image.width; 6157 if ((int) rectangle_info.x < x) 6158 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6159 else 6160 { 6161 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6162 rectangle_info.x=(ssize_t) x; 6163 } 6164 if (rectangle_info.y < 0) 6165 rectangle_info.y=0; 6166 else 6167 if (rectangle_info.y > (ssize_t) windows->image.height) 6168 rectangle_info.y=(ssize_t) windows->image.height; 6169 if ((int) rectangle_info.y < y) 6170 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6171 else 6172 { 6173 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6174 rectangle_info.y=(ssize_t) y; 6175 } 6176 } 6177 } while ((state & ExitState) == 0); 6178 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6179 if ((element == PointElement) || (element == PolygonElement) || 6180 (element == FillPolygonElement)) 6181 { 6182 /* 6183 Determine polygon bounding box. 6184 */ 6185 rectangle_info.x=(ssize_t) coordinate_info->x; 6186 rectangle_info.y=(ssize_t) coordinate_info->y; 6187 x=coordinate_info->x; 6188 y=coordinate_info->y; 6189 for (i=1; i < number_coordinates; i++) 6190 { 6191 if (coordinate_info[i].x > x) 6192 x=coordinate_info[i].x; 6193 if (coordinate_info[i].y > y) 6194 y=coordinate_info[i].y; 6195 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6196 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6197 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6198 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6199 } 6200 rectangle_info.width=(size_t) (x-rectangle_info.x); 6201 rectangle_info.height=(size_t) (y-rectangle_info.y); 6202 for (i=0; i < number_coordinates; i++) 6203 { 6204 coordinate_info[i].x-=rectangle_info.x; 6205 coordinate_info[i].y-=rectangle_info.y; 6206 } 6207 } 6208 else 6209 if (distance <= 9) 6210 continue; 6211 else 6212 if ((element == RectangleElement) || 6213 (element == CircleElement) || (element == EllipseElement)) 6214 { 6215 rectangle_info.width--; 6216 rectangle_info.height--; 6217 } 6218 /* 6219 Drawing is relative to image configuration. 6220 */ 6221 draw_info.x=(int) rectangle_info.x; 6222 draw_info.y=(int) rectangle_info.y; 6223 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6224 image); 6225 width=(unsigned int) (*image)->columns; 6226 height=(unsigned int) (*image)->rows; 6227 x=0; 6228 y=0; 6229 if (windows->image.crop_geometry != (char *) NULL) 6230 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6231 draw_info.x+=windows->image.x-(line_width/2); 6232 if (draw_info.x < 0) 6233 draw_info.x=0; 6234 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6235 draw_info.y+=windows->image.y-(line_width/2); 6236 if (draw_info.y < 0) 6237 draw_info.y=0; 6238 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6239 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6240 if (draw_info.width > (unsigned int) (*image)->columns) 6241 draw_info.width=(unsigned int) (*image)->columns; 6242 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6243 if (draw_info.height > (unsigned int) (*image)->rows) 6244 draw_info.height=(unsigned int) (*image)->rows; 6245 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6246 width*draw_info.width/windows->image.ximage->width, 6247 height*draw_info.height/windows->image.ximage->height, 6248 draw_info.x+x,draw_info.y+y); 6249 /* 6250 Initialize drawing attributes. 6251 */ 6252 draw_info.degrees=0.0; 6253 draw_info.element=element; 6254 draw_info.stipple=stipple; 6255 draw_info.line_width=line_width; 6256 draw_info.line_info=line_info; 6257 if (line_info.x1 > (int) (line_width/2)) 6258 draw_info.line_info.x1=(short) line_width/2; 6259 if (line_info.y1 > (int) (line_width/2)) 6260 draw_info.line_info.y1=(short) line_width/2; 6261 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6262 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6263 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6264 { 6265 draw_info.line_info.x2=(-draw_info.line_info.x2); 6266 draw_info.line_info.y2=(-draw_info.line_info.y2); 6267 } 6268 if (draw_info.line_info.x2 < 0) 6269 { 6270 draw_info.line_info.x2=(-draw_info.line_info.x2); 6271 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6272 } 6273 if (draw_info.line_info.y2 < 0) 6274 { 6275 draw_info.line_info.y2=(-draw_info.line_info.y2); 6276 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6277 } 6278 draw_info.rectangle_info=rectangle_info; 6279 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6280 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6281 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6282 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6283 draw_info.number_coordinates=(unsigned int) number_coordinates; 6284 draw_info.coordinate_info=coordinate_info; 6285 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6286 /* 6287 Draw element on image. 6288 */ 6289 XSetCursorState(display,windows,MagickTrue); 6290 XCheckRefreshWindows(display,windows); 6291 status=XDrawImage(display,windows->pixel_info,&draw_info,*image); 6292 XSetCursorState(display,windows,MagickFalse); 6293 /* 6294 Update image colormap and return to image drawing. 6295 */ 6296 XConfigureImageColormap(display,resource_info,windows,*image); 6297 (void) XConfigureImage(display,resource_info,windows,*image); 6298 } 6299 XSetCursorState(display,windows,MagickFalse); 6300 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6301 return(status != 0 ? MagickTrue : MagickFalse); 6302} 6303 6304/* 6305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6306% % 6307% % 6308% % 6309+ X D r a w P a n R e c t a n g l e % 6310% % 6311% % 6312% % 6313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6314% 6315% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6316% displays a zoom image and the rectangle shows which portion of the image is 6317% displayed in the Image window. 6318% 6319% The format of the XDrawPanRectangle method is: 6320% 6321% XDrawPanRectangle(Display *display,XWindows *windows) 6322% 6323% A description of each parameter follows: 6324% 6325% o display: Specifies a connection to an X server; returned from 6326% XOpenDisplay. 6327% 6328% o windows: Specifies a pointer to a XWindows structure. 6329% 6330*/ 6331static void XDrawPanRectangle(Display *display,XWindows *windows) 6332{ 6333 MagickRealType 6334 scale_factor; 6335 6336 RectangleInfo 6337 highlight_info; 6338 6339 /* 6340 Determine dimensions of the panning rectangle. 6341 */ 6342 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6343 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6344 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6345 scale_factor=(MagickRealType) 6346 windows->pan.height/windows->image.ximage->height; 6347 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6348 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6349 /* 6350 Display the panning rectangle. 6351 */ 6352 (void) XClearWindow(display,windows->pan.id); 6353 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6354 &highlight_info); 6355} 6356 6357/* 6358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6359% % 6360% % 6361% % 6362+ X I m a g e C a c h e % 6363% % 6364% % 6365% % 6366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6367% 6368% XImageCache() handles the creation, manipulation, and destruction of the 6369% image cache (undo and redo buffers). 6370% 6371% The format of the XImageCache method is: 6372% 6373% void XImageCache(Display *display,XResourceInfo *resource_info, 6374% XWindows *windows,const CommandType command,Image **image) 6375% 6376% A description of each parameter follows: 6377% 6378% o display: Specifies a connection to an X server; returned from 6379% XOpenDisplay. 6380% 6381% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6382% 6383% o windows: Specifies a pointer to a XWindows structure. 6384% 6385% o command: Specifies a command to perform. 6386% 6387% o image: the image; XImageCache may transform the image and return a new 6388% image pointer. 6389% 6390*/ 6391static void XImageCache(Display *display,XResourceInfo *resource_info, 6392 XWindows *windows,const CommandType command,Image **image) 6393{ 6394 Image 6395 *cache_image; 6396 6397 static Image 6398 *redo_image = (Image *) NULL, 6399 *undo_image = (Image *) NULL; 6400 6401 switch (command) 6402 { 6403 case FreeBuffersCommand: 6404 { 6405 /* 6406 Free memory from the undo and redo cache. 6407 */ 6408 while (undo_image != (Image *) NULL) 6409 { 6410 cache_image=undo_image; 6411 undo_image=GetPreviousImageInList(undo_image); 6412 cache_image->list=DestroyImage(cache_image->list); 6413 cache_image=DestroyImage(cache_image); 6414 } 6415 undo_image=NewImageList(); 6416 if (redo_image != (Image *) NULL) 6417 redo_image=DestroyImage(redo_image); 6418 redo_image=NewImageList(); 6419 return; 6420 } 6421 case UndoCommand: 6422 { 6423 char 6424 image_geometry[MaxTextExtent]; 6425 6426 /* 6427 Undo the last image transformation. 6428 */ 6429 if (undo_image == (Image *) NULL) 6430 { 6431 (void) XBell(display,0); 6432 return; 6433 } 6434 cache_image=undo_image; 6435 undo_image=GetPreviousImageInList(undo_image); 6436 windows->image.window_changes.width=(int) cache_image->columns; 6437 windows->image.window_changes.height=(int) cache_image->rows; 6438 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6439 windows->image.ximage->width,windows->image.ximage->height); 6440 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 6441 if (windows->image.crop_geometry != (char *) NULL) 6442 windows->image.crop_geometry=(char *) 6443 RelinquishMagickMemory(windows->image.crop_geometry); 6444 windows->image.crop_geometry=cache_image->geometry; 6445 if (redo_image != (Image *) NULL) 6446 redo_image=DestroyImage(redo_image); 6447 redo_image=(*image); 6448 *image=cache_image->list; 6449 cache_image=DestroyImage(cache_image); 6450 if (windows->image.orphan != MagickFalse) 6451 return; 6452 XConfigureImageColormap(display,resource_info,windows,*image); 6453 (void) XConfigureImage(display,resource_info,windows,*image); 6454 return; 6455 } 6456 case CutCommand: 6457 case PasteCommand: 6458 case ApplyCommand: 6459 case HalfSizeCommand: 6460 case OriginalSizeCommand: 6461 case DoubleSizeCommand: 6462 case ResizeCommand: 6463 case TrimCommand: 6464 case CropCommand: 6465 case ChopCommand: 6466 case FlipCommand: 6467 case FlopCommand: 6468 case RotateRightCommand: 6469 case RotateLeftCommand: 6470 case RotateCommand: 6471 case ShearCommand: 6472 case RollCommand: 6473 case NegateCommand: 6474 case ContrastStretchCommand: 6475 case SigmoidalContrastCommand: 6476 case NormalizeCommand: 6477 case EqualizeCommand: 6478 case HueCommand: 6479 case SaturationCommand: 6480 case BrightnessCommand: 6481 case GammaCommand: 6482 case SpiffCommand: 6483 case DullCommand: 6484 case GrayscaleCommand: 6485 case MapCommand: 6486 case QuantizeCommand: 6487 case DespeckleCommand: 6488 case EmbossCommand: 6489 case ReduceNoiseCommand: 6490 case AddNoiseCommand: 6491 case SharpenCommand: 6492 case BlurCommand: 6493 case ThresholdCommand: 6494 case EdgeDetectCommand: 6495 case SpreadCommand: 6496 case ShadeCommand: 6497 case RaiseCommand: 6498 case SegmentCommand: 6499 case SolarizeCommand: 6500 case SepiaToneCommand: 6501 case SwirlCommand: 6502 case ImplodeCommand: 6503 case VignetteCommand: 6504 case WaveCommand: 6505 case OilPaintCommand: 6506 case CharcoalDrawCommand: 6507 case AnnotateCommand: 6508 case AddBorderCommand: 6509 case AddFrameCommand: 6510 case CompositeCommand: 6511 case CommentCommand: 6512 case LaunchCommand: 6513 case RegionofInterestCommand: 6514 case SaveToUndoBufferCommand: 6515 case RedoCommand: 6516 { 6517 Image 6518 *previous_image; 6519 6520 ssize_t 6521 bytes; 6522 6523 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket)); 6524 if (undo_image != (Image *) NULL) 6525 { 6526 /* 6527 Ensure the undo cache has enough memory available. 6528 */ 6529 previous_image=undo_image; 6530 while (previous_image != (Image *) NULL) 6531 { 6532 bytes+=previous_image->list->columns*previous_image->list->rows* 6533 sizeof(PixelPacket); 6534 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6535 { 6536 previous_image=GetPreviousImageInList(previous_image); 6537 continue; 6538 } 6539 bytes-=previous_image->list->columns*previous_image->list->rows* 6540 sizeof(PixelPacket); 6541 if (previous_image == undo_image) 6542 undo_image=NewImageList(); 6543 else 6544 previous_image->next->previous=NewImageList(); 6545 break; 6546 } 6547 while (previous_image != (Image *) NULL) 6548 { 6549 /* 6550 Delete any excess memory from undo cache. 6551 */ 6552 cache_image=previous_image; 6553 previous_image=GetPreviousImageInList(previous_image); 6554 cache_image->list=DestroyImage(cache_image->list); 6555 cache_image=DestroyImage(cache_image); 6556 } 6557 } 6558 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6559 break; 6560 /* 6561 Save image before transformations are applied. 6562 */ 6563 cache_image=AcquireImage((ImageInfo *) NULL); 6564 if (cache_image == (Image *) NULL) 6565 break; 6566 XSetCursorState(display,windows,MagickTrue); 6567 XCheckRefreshWindows(display,windows); 6568 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 6569 XSetCursorState(display,windows,MagickFalse); 6570 if (cache_image->list == (Image *) NULL) 6571 { 6572 cache_image=DestroyImage(cache_image); 6573 break; 6574 } 6575 cache_image->columns=(size_t) windows->image.ximage->width; 6576 cache_image->rows=(size_t) windows->image.ximage->height; 6577 cache_image->geometry=windows->image.crop_geometry; 6578 if (windows->image.crop_geometry != (char *) NULL) 6579 { 6580 cache_image->geometry=AcquireString((char *) NULL); 6581 (void) CopyMagickString(cache_image->geometry, 6582 windows->image.crop_geometry,MaxTextExtent); 6583 } 6584 if (undo_image == (Image *) NULL) 6585 { 6586 undo_image=cache_image; 6587 break; 6588 } 6589 undo_image->next=cache_image; 6590 undo_image->next->previous=undo_image; 6591 undo_image=undo_image->next; 6592 break; 6593 } 6594 default: 6595 break; 6596 } 6597 if (command == RedoCommand) 6598 { 6599 /* 6600 Redo the last image transformation. 6601 */ 6602 if (redo_image == (Image *) NULL) 6603 { 6604 (void) XBell(display,0); 6605 return; 6606 } 6607 windows->image.window_changes.width=(int) redo_image->columns; 6608 windows->image.window_changes.height=(int) redo_image->rows; 6609 if (windows->image.crop_geometry != (char *) NULL) 6610 windows->image.crop_geometry=(char *) 6611 RelinquishMagickMemory(windows->image.crop_geometry); 6612 windows->image.crop_geometry=redo_image->geometry; 6613 *image=DestroyImage(*image); 6614 *image=redo_image; 6615 redo_image=NewImageList(); 6616 if (windows->image.orphan != MagickFalse) 6617 return; 6618 XConfigureImageColormap(display,resource_info,windows,*image); 6619 (void) XConfigureImage(display,resource_info,windows,*image); 6620 return; 6621 } 6622 if (command != InfoCommand) 6623 return; 6624 /* 6625 Display image info. 6626 */ 6627 XSetCursorState(display,windows,MagickTrue); 6628 XCheckRefreshWindows(display,windows); 6629 XDisplayImageInfo(display,resource_info,windows,undo_image,*image); 6630 XSetCursorState(display,windows,MagickFalse); 6631} 6632 6633/* 6634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6635% % 6636% % 6637% % 6638+ X I m a g e W i n d o w C o m m a n d % 6639% % 6640% % 6641% % 6642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6643% 6644% XImageWindowCommand() makes a transform to the image or Image window as 6645% specified by a user menu button or keyboard command. 6646% 6647% The format of the XMagickCommand method is: 6648% 6649% CommandType XImageWindowCommand(Display *display, 6650% XResourceInfo *resource_info,XWindows *windows, 6651% const MagickStatusType state,KeySym key_symbol,Image **image) 6652% 6653% A description of each parameter follows: 6654% 6655% o nexus: Method XImageWindowCommand returns an image when the 6656% user chooses 'Open Image' from the command menu. Otherwise a null 6657% image is returned. 6658% 6659% o display: Specifies a connection to an X server; returned from 6660% XOpenDisplay. 6661% 6662% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6663% 6664% o windows: Specifies a pointer to a XWindows structure. 6665% 6666% o state: key mask. 6667% 6668% o key_symbol: Specifies a command to perform. 6669% 6670% o image: the image; XImageWIndowCommand 6671% may transform the image and return a new image pointer. 6672% 6673*/ 6674static CommandType XImageWindowCommand(Display *display, 6675 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6676 KeySym key_symbol,Image **image) 6677{ 6678 static char 6679 delta[MaxTextExtent] = ""; 6680 6681 static const char 6682 Digits[] = "01234567890"; 6683 6684 static KeySym 6685 last_symbol = XK_0; 6686 6687 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6688 { 6689 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6690 { 6691 *delta='\0'; 6692 resource_info->quantum=1; 6693 } 6694 last_symbol=key_symbol; 6695 delta[strlen(delta)+1]='\0'; 6696 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6697 resource_info->quantum=StringToLong(delta); 6698 return(NullCommand); 6699 } 6700 last_symbol=key_symbol; 6701 if (resource_info->immutable) 6702 { 6703 /* 6704 Virtual image window has a restricted command set. 6705 */ 6706 switch (key_symbol) 6707 { 6708 case XK_question: 6709 return(InfoCommand); 6710 case XK_p: 6711 case XK_Print: 6712 return(PrintCommand); 6713 case XK_space: 6714 return(NextCommand); 6715 case XK_q: 6716 case XK_Escape: 6717 return(QuitCommand); 6718 default: 6719 break; 6720 } 6721 return(NullCommand); 6722 } 6723 switch ((int) key_symbol) 6724 { 6725 case XK_o: 6726 { 6727 if ((state & ControlMask) == 0) 6728 break; 6729 return(OpenCommand); 6730 } 6731 case XK_space: 6732 return(NextCommand); 6733 case XK_BackSpace: 6734 return(FormerCommand); 6735 case XK_s: 6736 { 6737 if ((state & Mod1Mask) != 0) 6738 return(SwirlCommand); 6739 if ((state & ControlMask) == 0) 6740 return(ShearCommand); 6741 return(SaveCommand); 6742 } 6743 case XK_p: 6744 case XK_Print: 6745 { 6746 if ((state & Mod1Mask) != 0) 6747 return(OilPaintCommand); 6748 if ((state & Mod4Mask) != 0) 6749 return(ColorCommand); 6750 if ((state & ControlMask) == 0) 6751 return(NullCommand); 6752 return(PrintCommand); 6753 } 6754 case XK_d: 6755 { 6756 if ((state & Mod4Mask) != 0) 6757 return(DrawCommand); 6758 if ((state & ControlMask) == 0) 6759 return(NullCommand); 6760 return(DeleteCommand); 6761 } 6762 case XK_Select: 6763 { 6764 if ((state & ControlMask) == 0) 6765 return(NullCommand); 6766 return(SelectCommand); 6767 } 6768 case XK_n: 6769 { 6770 if ((state & ControlMask) == 0) 6771 return(NullCommand); 6772 return(NewCommand); 6773 } 6774 case XK_q: 6775 case XK_Escape: 6776 return(QuitCommand); 6777 case XK_z: 6778 case XK_Undo: 6779 { 6780 if ((state & ControlMask) == 0) 6781 return(NullCommand); 6782 return(UndoCommand); 6783 } 6784 case XK_r: 6785 case XK_Redo: 6786 { 6787 if ((state & ControlMask) == 0) 6788 return(RollCommand); 6789 return(RedoCommand); 6790 } 6791 case XK_x: 6792 { 6793 if ((state & ControlMask) == 0) 6794 return(NullCommand); 6795 return(CutCommand); 6796 } 6797 case XK_c: 6798 { 6799 if ((state & Mod1Mask) != 0) 6800 return(CharcoalDrawCommand); 6801 if ((state & ControlMask) == 0) 6802 return(CropCommand); 6803 return(CopyCommand); 6804 } 6805 case XK_v: 6806 case XK_Insert: 6807 { 6808 if ((state & Mod4Mask) != 0) 6809 return(CompositeCommand); 6810 if ((state & ControlMask) == 0) 6811 return(FlipCommand); 6812 return(PasteCommand); 6813 } 6814 case XK_less: 6815 return(HalfSizeCommand); 6816 case XK_minus: 6817 return(OriginalSizeCommand); 6818 case XK_greater: 6819 return(DoubleSizeCommand); 6820 case XK_percent: 6821 return(ResizeCommand); 6822 case XK_at: 6823 return(RefreshCommand); 6824 case XK_bracketleft: 6825 return(ChopCommand); 6826 case XK_h: 6827 return(FlopCommand); 6828 case XK_slash: 6829 return(RotateRightCommand); 6830 case XK_backslash: 6831 return(RotateLeftCommand); 6832 case XK_asterisk: 6833 return(RotateCommand); 6834 case XK_t: 6835 return(TrimCommand); 6836 case XK_H: 6837 return(HueCommand); 6838 case XK_S: 6839 return(SaturationCommand); 6840 case XK_L: 6841 return(BrightnessCommand); 6842 case XK_G: 6843 return(GammaCommand); 6844 case XK_C: 6845 return(SpiffCommand); 6846 case XK_Z: 6847 return(DullCommand); 6848 case XK_N: 6849 return(NormalizeCommand); 6850 case XK_equal: 6851 return(EqualizeCommand); 6852 case XK_asciitilde: 6853 return(NegateCommand); 6854 case XK_period: 6855 return(GrayscaleCommand); 6856 case XK_numbersign: 6857 return(QuantizeCommand); 6858 case XK_F2: 6859 return(DespeckleCommand); 6860 case XK_F3: 6861 return(EmbossCommand); 6862 case XK_F4: 6863 return(ReduceNoiseCommand); 6864 case XK_F5: 6865 return(AddNoiseCommand); 6866 case XK_F6: 6867 return(SharpenCommand); 6868 case XK_F7: 6869 return(BlurCommand); 6870 case XK_F8: 6871 return(ThresholdCommand); 6872 case XK_F9: 6873 return(EdgeDetectCommand); 6874 case XK_F10: 6875 return(SpreadCommand); 6876 case XK_F11: 6877 return(ShadeCommand); 6878 case XK_F12: 6879 return(RaiseCommand); 6880 case XK_F13: 6881 return(SegmentCommand); 6882 case XK_i: 6883 { 6884 if ((state & Mod1Mask) == 0) 6885 return(NullCommand); 6886 return(ImplodeCommand); 6887 } 6888 case XK_w: 6889 { 6890 if ((state & Mod1Mask) == 0) 6891 return(NullCommand); 6892 return(WaveCommand); 6893 } 6894 case XK_m: 6895 { 6896 if ((state & Mod4Mask) == 0) 6897 return(NullCommand); 6898 return(MatteCommand); 6899 } 6900 case XK_b: 6901 { 6902 if ((state & Mod4Mask) == 0) 6903 return(NullCommand); 6904 return(AddBorderCommand); 6905 } 6906 case XK_f: 6907 { 6908 if ((state & Mod4Mask) == 0) 6909 return(NullCommand); 6910 return(AddFrameCommand); 6911 } 6912 case XK_exclam: 6913 { 6914 if ((state & Mod4Mask) == 0) 6915 return(NullCommand); 6916 return(CommentCommand); 6917 } 6918 case XK_a: 6919 { 6920 if ((state & Mod1Mask) != 0) 6921 return(ApplyCommand); 6922 if ((state & Mod4Mask) != 0) 6923 return(AnnotateCommand); 6924 if ((state & ControlMask) == 0) 6925 return(NullCommand); 6926 return(RegionofInterestCommand); 6927 } 6928 case XK_question: 6929 return(InfoCommand); 6930 case XK_plus: 6931 return(ZoomCommand); 6932 case XK_P: 6933 { 6934 if ((state & ShiftMask) == 0) 6935 return(NullCommand); 6936 return(ShowPreviewCommand); 6937 } 6938 case XK_Execute: 6939 return(LaunchCommand); 6940 case XK_F1: 6941 return(HelpCommand); 6942 case XK_Find: 6943 return(BrowseDocumentationCommand); 6944 case XK_Menu: 6945 { 6946 (void) XMapRaised(display,windows->command.id); 6947 return(NullCommand); 6948 } 6949 case XK_Next: 6950 case XK_Prior: 6951 case XK_Home: 6952 case XK_KP_Home: 6953 { 6954 XTranslateImage(display,windows,*image,key_symbol); 6955 return(NullCommand); 6956 } 6957 case XK_Up: 6958 case XK_KP_Up: 6959 case XK_Down: 6960 case XK_KP_Down: 6961 case XK_Left: 6962 case XK_KP_Left: 6963 case XK_Right: 6964 case XK_KP_Right: 6965 { 6966 if ((state & Mod1Mask) != 0) 6967 { 6968 RectangleInfo 6969 crop_info; 6970 6971 /* 6972 Trim one pixel from edge of image. 6973 */ 6974 crop_info.x=0; 6975 crop_info.y=0; 6976 crop_info.width=(size_t) windows->image.ximage->width; 6977 crop_info.height=(size_t) windows->image.ximage->height; 6978 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 6979 { 6980 if (resource_info->quantum >= (int) crop_info.height) 6981 resource_info->quantum=(int) crop_info.height-1; 6982 crop_info.height-=resource_info->quantum; 6983 } 6984 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 6985 { 6986 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 6987 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 6988 crop_info.y+=resource_info->quantum; 6989 crop_info.height-=resource_info->quantum; 6990 } 6991 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 6992 { 6993 if (resource_info->quantum >= (int) crop_info.width) 6994 resource_info->quantum=(int) crop_info.width-1; 6995 crop_info.width-=resource_info->quantum; 6996 } 6997 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 6998 { 6999 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7000 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7001 crop_info.x+=resource_info->quantum; 7002 crop_info.width-=resource_info->quantum; 7003 } 7004 if ((int) (windows->image.x+windows->image.width) > 7005 (int) crop_info.width) 7006 windows->image.x=(int) (crop_info.width-windows->image.width); 7007 if ((int) (windows->image.y+windows->image.height) > 7008 (int) crop_info.height) 7009 windows->image.y=(int) (crop_info.height-windows->image.height); 7010 XSetCropGeometry(display,windows,&crop_info,*image); 7011 windows->image.window_changes.width=(int) crop_info.width; 7012 windows->image.window_changes.height=(int) crop_info.height; 7013 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7014 (void) XConfigureImage(display,resource_info,windows,*image); 7015 return(NullCommand); 7016 } 7017 XTranslateImage(display,windows,*image,key_symbol); 7018 return(NullCommand); 7019 } 7020 default: 7021 return(NullCommand); 7022 } 7023 return(NullCommand); 7024} 7025 7026/* 7027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7028% % 7029% % 7030% % 7031+ X M a g i c k C o m m a n d % 7032% % 7033% % 7034% % 7035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7036% 7037% XMagickCommand() makes a transform to the image or Image window as 7038% specified by a user menu button or keyboard command. 7039% 7040% The format of the XMagickCommand method is: 7041% 7042% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7043% XWindows *windows,const CommandType command,Image **image) 7044% 7045% A description of each parameter follows: 7046% 7047% o nexus: Method XMagickCommand returns an image when the 7048% user chooses 'Load Image' from the command menu. Otherwise a null 7049% image is returned. 7050% 7051% o display: Specifies a connection to an X server; returned from 7052% XOpenDisplay. 7053% 7054% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7055% 7056% o windows: Specifies a pointer to a XWindows structure. 7057% 7058% o command: Specifies a command to perform. 7059% 7060% o image: the image; XMagickCommand 7061% may transform the image and return a new image pointer. 7062% 7063*/ 7064static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7065 XWindows *windows,const CommandType command,Image **image) 7066{ 7067 char 7068 filename[MaxTextExtent], 7069 geometry[MaxTextExtent], 7070 modulate_factors[MaxTextExtent]; 7071 7072 GeometryInfo 7073 geometry_info; 7074 7075 Image 7076 *nexus; 7077 7078 ImageInfo 7079 *image_info; 7080 7081 int 7082 x, 7083 y; 7084 7085 MagickStatusType 7086 flags, 7087 status; 7088 7089 QuantizeInfo 7090 quantize_info; 7091 7092 RectangleInfo 7093 page_geometry; 7094 7095 register int 7096 i; 7097 7098 static char 7099 color[MaxTextExtent] = "gray"; 7100 7101 unsigned int 7102 height, 7103 width; 7104 7105 /* 7106 Process user command. 7107 */ 7108 XCheckRefreshWindows(display,windows); 7109 XImageCache(display,resource_info,windows,command,image); 7110 nexus=NewImageList(); 7111 windows->image.window_changes.width=windows->image.ximage->width; 7112 windows->image.window_changes.height=windows->image.ximage->height; 7113 image_info=CloneImageInfo(resource_info->image_info); 7114 SetGeometryInfo(&geometry_info); 7115 GetQuantizeInfo(&quantize_info); 7116 switch (command) 7117 { 7118 case OpenCommand: 7119 { 7120 /* 7121 Load image. 7122 */ 7123 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7124 break; 7125 } 7126 case NextCommand: 7127 { 7128 /* 7129 Display next image. 7130 */ 7131 for (i=0; i < resource_info->quantum; i++) 7132 XClientMessage(display,windows->image.id,windows->im_protocols, 7133 windows->im_next_image,CurrentTime); 7134 break; 7135 } 7136 case FormerCommand: 7137 { 7138 /* 7139 Display former image. 7140 */ 7141 for (i=0; i < resource_info->quantum; i++) 7142 XClientMessage(display,windows->image.id,windows->im_protocols, 7143 windows->im_former_image,CurrentTime); 7144 break; 7145 } 7146 case SelectCommand: 7147 { 7148 int 7149 status; 7150 7151 /* 7152 Select image. 7153 */ 7154 status=chdir(resource_info->home_directory); 7155 if (status == -1) 7156 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 7157 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 7158 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7159 break; 7160 } 7161 case SaveCommand: 7162 { 7163 /* 7164 Save image. 7165 */ 7166 status=XSaveImage(display,resource_info,windows,*image); 7167 if (status == MagickFalse) 7168 { 7169 XNoticeWidget(display,windows,"Unable to write X image:", 7170 (*image)->filename); 7171 break; 7172 } 7173 break; 7174 } 7175 case PrintCommand: 7176 { 7177 /* 7178 Print image. 7179 */ 7180 status=XPrintImage(display,resource_info,windows,*image); 7181 if (status == MagickFalse) 7182 { 7183 XNoticeWidget(display,windows,"Unable to print X image:", 7184 (*image)->filename); 7185 break; 7186 } 7187 break; 7188 } 7189 case DeleteCommand: 7190 { 7191 static char 7192 filename[MaxTextExtent] = "\0"; 7193 7194 /* 7195 Delete image file. 7196 */ 7197 XFileBrowserWidget(display,windows,"Delete",filename); 7198 if (*filename == '\0') 7199 break; 7200 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 7201 if (status != MagickFalse) 7202 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7203 break; 7204 } 7205 case NewCommand: 7206 { 7207 int 7208 status; 7209 7210 static char 7211 color[MaxTextExtent] = "gray", 7212 geometry[MaxTextExtent] = "640x480"; 7213 7214 static const char 7215 *format = "gradient"; 7216 7217 /* 7218 Query user for canvas geometry. 7219 */ 7220 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7221 geometry); 7222 if (*geometry == '\0') 7223 break; 7224 if (status == 0) 7225 format="xc"; 7226 XColorBrowserWidget(display,windows,"Select",color); 7227 if (*color == '\0') 7228 break; 7229 /* 7230 Create canvas. 7231 */ 7232 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7233 "%s:%s",format,color); 7234 (void) CloneString(&image_info->size,geometry); 7235 nexus=ReadImage(image_info,&(*image)->exception); 7236 CatchException(&(*image)->exception); 7237 XClientMessage(display,windows->image.id,windows->im_protocols, 7238 windows->im_next_image,CurrentTime); 7239 break; 7240 } 7241 case VisualDirectoryCommand: 7242 { 7243 /* 7244 Visual Image directory. 7245 */ 7246 nexus=XVisualDirectoryImage(display,resource_info,windows); 7247 break; 7248 } 7249 case QuitCommand: 7250 { 7251 /* 7252 exit program. 7253 */ 7254 if (resource_info->confirm_exit == MagickFalse) 7255 XClientMessage(display,windows->image.id,windows->im_protocols, 7256 windows->im_exit,CurrentTime); 7257 else 7258 { 7259 int 7260 status; 7261 7262 /* 7263 Confirm program exit. 7264 */ 7265 status=XConfirmWidget(display,windows,"Do you really want to exit", 7266 resource_info->client_name); 7267 if (status > 0) 7268 XClientMessage(display,windows->image.id,windows->im_protocols, 7269 windows->im_exit,CurrentTime); 7270 } 7271 break; 7272 } 7273 case CutCommand: 7274 { 7275 /* 7276 Cut image. 7277 */ 7278 (void) XCropImage(display,resource_info,windows,*image,CutMode); 7279 break; 7280 } 7281 case CopyCommand: 7282 { 7283 /* 7284 Copy image. 7285 */ 7286 (void) XCropImage(display,resource_info,windows,*image,CopyMode); 7287 break; 7288 } 7289 case PasteCommand: 7290 { 7291 /* 7292 Paste image. 7293 */ 7294 status=XPasteImage(display,resource_info,windows,*image); 7295 if (status == MagickFalse) 7296 { 7297 XNoticeWidget(display,windows,"Unable to paste X image", 7298 (*image)->filename); 7299 break; 7300 } 7301 break; 7302 } 7303 case HalfSizeCommand: 7304 { 7305 /* 7306 Half image size. 7307 */ 7308 windows->image.window_changes.width=windows->image.ximage->width/2; 7309 windows->image.window_changes.height=windows->image.ximage->height/2; 7310 (void) XConfigureImage(display,resource_info,windows,*image); 7311 break; 7312 } 7313 case OriginalSizeCommand: 7314 { 7315 /* 7316 Original image size. 7317 */ 7318 windows->image.window_changes.width=(int) (*image)->columns; 7319 windows->image.window_changes.height=(int) (*image)->rows; 7320 (void) XConfigureImage(display,resource_info,windows,*image); 7321 break; 7322 } 7323 case DoubleSizeCommand: 7324 { 7325 /* 7326 Double the image size. 7327 */ 7328 windows->image.window_changes.width=windows->image.ximage->width << 1; 7329 windows->image.window_changes.height=windows->image.ximage->height << 1; 7330 (void) XConfigureImage(display,resource_info,windows,*image); 7331 break; 7332 } 7333 case ResizeCommand: 7334 { 7335 int 7336 status; 7337 7338 size_t 7339 height, 7340 width; 7341 7342 ssize_t 7343 x, 7344 y; 7345 7346 /* 7347 Resize image. 7348 */ 7349 width=(size_t) windows->image.ximage->width; 7350 height=(size_t) windows->image.ximage->height; 7351 x=0; 7352 y=0; 7353 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7354 (double) width,(double) height); 7355 status=XDialogWidget(display,windows,"Resize", 7356 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7357 if (*geometry == '\0') 7358 break; 7359 if (status == 0) 7360 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7361 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7362 windows->image.window_changes.width=(int) width; 7363 windows->image.window_changes.height=(int) height; 7364 (void) XConfigureImage(display,resource_info,windows,*image); 7365 break; 7366 } 7367 case ApplyCommand: 7368 { 7369 char 7370 image_geometry[MaxTextExtent]; 7371 7372 if ((windows->image.crop_geometry == (char *) NULL) && 7373 ((int) (*image)->columns == windows->image.ximage->width) && 7374 ((int) (*image)->rows == windows->image.ximage->height)) 7375 break; 7376 /* 7377 Apply size transforms to image. 7378 */ 7379 XSetCursorState(display,windows,MagickTrue); 7380 XCheckRefreshWindows(display,windows); 7381 /* 7382 Crop and/or scale displayed image. 7383 */ 7384 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7385 windows->image.ximage->width,windows->image.ximage->height); 7386 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 7387 if (windows->image.crop_geometry != (char *) NULL) 7388 windows->image.crop_geometry=(char *) 7389 RelinquishMagickMemory(windows->image.crop_geometry); 7390 windows->image.x=0; 7391 windows->image.y=0; 7392 XConfigureImageColormap(display,resource_info,windows,*image); 7393 (void) XConfigureImage(display,resource_info,windows,*image); 7394 break; 7395 } 7396 case RefreshCommand: 7397 { 7398 (void) XConfigureImage(display,resource_info,windows,*image); 7399 break; 7400 } 7401 case RestoreCommand: 7402 { 7403 /* 7404 Restore Image window to its original size. 7405 */ 7406 if ((windows->image.width == (unsigned int) (*image)->columns) && 7407 (windows->image.height == (unsigned int) (*image)->rows) && 7408 (windows->image.crop_geometry == (char *) NULL)) 7409 { 7410 (void) XBell(display,0); 7411 break; 7412 } 7413 windows->image.window_changes.width=(int) (*image)->columns; 7414 windows->image.window_changes.height=(int) (*image)->rows; 7415 if (windows->image.crop_geometry != (char *) NULL) 7416 { 7417 windows->image.crop_geometry=(char *) 7418 RelinquishMagickMemory(windows->image.crop_geometry); 7419 windows->image.crop_geometry=(char *) NULL; 7420 windows->image.x=0; 7421 windows->image.y=0; 7422 } 7423 XConfigureImageColormap(display,resource_info,windows,*image); 7424 (void) XConfigureImage(display,resource_info,windows,*image); 7425 break; 7426 } 7427 case CropCommand: 7428 { 7429 /* 7430 Crop image. 7431 */ 7432 (void) XCropImage(display,resource_info,windows,*image,CropMode); 7433 break; 7434 } 7435 case ChopCommand: 7436 { 7437 /* 7438 Chop image. 7439 */ 7440 status=XChopImage(display,resource_info,windows,image); 7441 if (status == MagickFalse) 7442 { 7443 XNoticeWidget(display,windows,"Unable to cut X image", 7444 (*image)->filename); 7445 break; 7446 } 7447 break; 7448 } 7449 case FlopCommand: 7450 { 7451 Image 7452 *flop_image; 7453 7454 /* 7455 Flop image scanlines. 7456 */ 7457 XSetCursorState(display,windows,MagickTrue); 7458 XCheckRefreshWindows(display,windows); 7459 flop_image=FlopImage(*image,&(*image)->exception); 7460 if (flop_image != (Image *) NULL) 7461 { 7462 *image=DestroyImage(*image); 7463 *image=flop_image; 7464 } 7465 CatchException(&(*image)->exception); 7466 XSetCursorState(display,windows,MagickFalse); 7467 if (windows->image.crop_geometry != (char *) NULL) 7468 { 7469 /* 7470 Flop crop geometry. 7471 */ 7472 width=(unsigned int) (*image)->columns; 7473 height=(unsigned int) (*image)->rows; 7474 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7475 &width,&height); 7476 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7477 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7478 } 7479 if (windows->image.orphan != MagickFalse) 7480 break; 7481 (void) XConfigureImage(display,resource_info,windows,*image); 7482 break; 7483 } 7484 case FlipCommand: 7485 { 7486 Image 7487 *flip_image; 7488 7489 /* 7490 Flip image scanlines. 7491 */ 7492 XSetCursorState(display,windows,MagickTrue); 7493 XCheckRefreshWindows(display,windows); 7494 flip_image=FlipImage(*image,&(*image)->exception); 7495 if (flip_image != (Image *) NULL) 7496 { 7497 *image=DestroyImage(*image); 7498 *image=flip_image; 7499 } 7500 CatchException(&(*image)->exception); 7501 XSetCursorState(display,windows,MagickFalse); 7502 if (windows->image.crop_geometry != (char *) NULL) 7503 { 7504 /* 7505 Flip crop geometry. 7506 */ 7507 width=(unsigned int) (*image)->columns; 7508 height=(unsigned int) (*image)->rows; 7509 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7510 &width,&height); 7511 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7512 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7513 } 7514 if (windows->image.orphan != MagickFalse) 7515 break; 7516 (void) XConfigureImage(display,resource_info,windows,*image); 7517 break; 7518 } 7519 case RotateRightCommand: 7520 { 7521 /* 7522 Rotate image 90 degrees clockwise. 7523 */ 7524 status=XRotateImage(display,resource_info,windows,90.0,image); 7525 if (status == MagickFalse) 7526 { 7527 XNoticeWidget(display,windows,"Unable to rotate X image", 7528 (*image)->filename); 7529 break; 7530 } 7531 break; 7532 } 7533 case RotateLeftCommand: 7534 { 7535 /* 7536 Rotate image 90 degrees counter-clockwise. 7537 */ 7538 status=XRotateImage(display,resource_info,windows,-90.0,image); 7539 if (status == MagickFalse) 7540 { 7541 XNoticeWidget(display,windows,"Unable to rotate X image", 7542 (*image)->filename); 7543 break; 7544 } 7545 break; 7546 } 7547 case RotateCommand: 7548 { 7549 /* 7550 Rotate image. 7551 */ 7552 status=XRotateImage(display,resource_info,windows,0.0,image); 7553 if (status == MagickFalse) 7554 { 7555 XNoticeWidget(display,windows,"Unable to rotate X image", 7556 (*image)->filename); 7557 break; 7558 } 7559 break; 7560 } 7561 case ShearCommand: 7562 { 7563 Image 7564 *shear_image; 7565 7566 static char 7567 geometry[MaxTextExtent] = "45.0x45.0"; 7568 7569 /* 7570 Query user for shear color and geometry. 7571 */ 7572 XColorBrowserWidget(display,windows,"Select",color); 7573 if (*color == '\0') 7574 break; 7575 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7576 geometry); 7577 if (*geometry == '\0') 7578 break; 7579 /* 7580 Shear image. 7581 */ 7582 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 7583 XSetCursorState(display,windows,MagickTrue); 7584 XCheckRefreshWindows(display,windows); 7585 (void) QueryColorDatabase(color,&(*image)->background_color, 7586 &(*image)->exception); 7587 flags=ParseGeometry(geometry,&geometry_info); 7588 if ((flags & SigmaValue) == 0) 7589 geometry_info.sigma=geometry_info.rho; 7590 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7591 &(*image)->exception); 7592 if (shear_image != (Image *) NULL) 7593 { 7594 *image=DestroyImage(*image); 7595 *image=shear_image; 7596 } 7597 CatchException(&(*image)->exception); 7598 XSetCursorState(display,windows,MagickFalse); 7599 if (windows->image.orphan != MagickFalse) 7600 break; 7601 windows->image.window_changes.width=(int) (*image)->columns; 7602 windows->image.window_changes.height=(int) (*image)->rows; 7603 XConfigureImageColormap(display,resource_info,windows,*image); 7604 (void) XConfigureImage(display,resource_info,windows,*image); 7605 break; 7606 } 7607 case RollCommand: 7608 { 7609 Image 7610 *roll_image; 7611 7612 static char 7613 geometry[MaxTextExtent] = "+2+2"; 7614 7615 /* 7616 Query user for the roll geometry. 7617 */ 7618 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7619 geometry); 7620 if (*geometry == '\0') 7621 break; 7622 /* 7623 Roll image. 7624 */ 7625 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 7626 XSetCursorState(display,windows,MagickTrue); 7627 XCheckRefreshWindows(display,windows); 7628 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7629 &(*image)->exception); 7630 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7631 &(*image)->exception); 7632 if (roll_image != (Image *) NULL) 7633 { 7634 *image=DestroyImage(*image); 7635 *image=roll_image; 7636 } 7637 CatchException(&(*image)->exception); 7638 XSetCursorState(display,windows,MagickFalse); 7639 if (windows->image.orphan != MagickFalse) 7640 break; 7641 windows->image.window_changes.width=(int) (*image)->columns; 7642 windows->image.window_changes.height=(int) (*image)->rows; 7643 XConfigureImageColormap(display,resource_info,windows,*image); 7644 (void) XConfigureImage(display,resource_info,windows,*image); 7645 break; 7646 } 7647 case TrimCommand: 7648 { 7649 static char 7650 fuzz[MaxTextExtent]; 7651 7652 /* 7653 Query user for the fuzz factor. 7654 */ 7655 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7656 (*image)->fuzz/(QuantumRange+1.0)); 7657 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7658 if (*fuzz == '\0') 7659 break; 7660 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7661 /* 7662 Trim image. 7663 */ 7664 status=XTrimImage(display,resource_info,windows,*image); 7665 if (status == MagickFalse) 7666 { 7667 XNoticeWidget(display,windows,"Unable to trim X image", 7668 (*image)->filename); 7669 break; 7670 } 7671 break; 7672 } 7673 case HueCommand: 7674 { 7675 static char 7676 hue_percent[MaxTextExtent] = "110"; 7677 7678 /* 7679 Query user for percent hue change. 7680 */ 7681 (void) XDialogWidget(display,windows,"Apply", 7682 "Enter percent change in image hue (0-200):",hue_percent); 7683 if (*hue_percent == '\0') 7684 break; 7685 /* 7686 Vary the image hue. 7687 */ 7688 XSetCursorState(display,windows,MagickTrue); 7689 XCheckRefreshWindows(display,windows); 7690 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7691 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7692 MaxTextExtent); 7693 (void) ModulateImage(*image,modulate_factors); 7694 XSetCursorState(display,windows,MagickFalse); 7695 if (windows->image.orphan != MagickFalse) 7696 break; 7697 XConfigureImageColormap(display,resource_info,windows,*image); 7698 (void) XConfigureImage(display,resource_info,windows,*image); 7699 break; 7700 } 7701 case SaturationCommand: 7702 { 7703 static char 7704 saturation_percent[MaxTextExtent] = "110"; 7705 7706 /* 7707 Query user for percent saturation change. 7708 */ 7709 (void) XDialogWidget(display,windows,"Apply", 7710 "Enter percent change in color saturation (0-200):",saturation_percent); 7711 if (*saturation_percent == '\0') 7712 break; 7713 /* 7714 Vary color saturation. 7715 */ 7716 XSetCursorState(display,windows,MagickTrue); 7717 XCheckRefreshWindows(display,windows); 7718 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7719 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7720 MaxTextExtent); 7721 (void) ModulateImage(*image,modulate_factors); 7722 XSetCursorState(display,windows,MagickFalse); 7723 if (windows->image.orphan != MagickFalse) 7724 break; 7725 XConfigureImageColormap(display,resource_info,windows,*image); 7726 (void) XConfigureImage(display,resource_info,windows,*image); 7727 break; 7728 } 7729 case BrightnessCommand: 7730 { 7731 static char 7732 brightness_percent[MaxTextExtent] = "110"; 7733 7734 /* 7735 Query user for percent brightness change. 7736 */ 7737 (void) XDialogWidget(display,windows,"Apply", 7738 "Enter percent change in color brightness (0-200):",brightness_percent); 7739 if (*brightness_percent == '\0') 7740 break; 7741 /* 7742 Vary the color brightness. 7743 */ 7744 XSetCursorState(display,windows,MagickTrue); 7745 XCheckRefreshWindows(display,windows); 7746 (void) CopyMagickString(modulate_factors,brightness_percent, 7747 MaxTextExtent); 7748 (void) ModulateImage(*image,modulate_factors); 7749 XSetCursorState(display,windows,MagickFalse); 7750 if (windows->image.orphan != MagickFalse) 7751 break; 7752 XConfigureImageColormap(display,resource_info,windows,*image); 7753 (void) XConfigureImage(display,resource_info,windows,*image); 7754 break; 7755 } 7756 case GammaCommand: 7757 { 7758 static char 7759 factor[MaxTextExtent] = "1.6"; 7760 7761 /* 7762 Query user for gamma value. 7763 */ 7764 (void) XDialogWidget(display,windows,"Gamma", 7765 "Enter gamma value (e.g. 1.2):",factor); 7766 if (*factor == '\0') 7767 break; 7768 /* 7769 Gamma correct image. 7770 */ 7771 XSetCursorState(display,windows,MagickTrue); 7772 XCheckRefreshWindows(display,windows); 7773 (void) GammaImage(*image,atof(factor),&(*image)->exception); 7774 XSetCursorState(display,windows,MagickFalse); 7775 if (windows->image.orphan != MagickFalse) 7776 break; 7777 XConfigureImageColormap(display,resource_info,windows,*image); 7778 (void) XConfigureImage(display,resource_info,windows,*image); 7779 break; 7780 } 7781 case SpiffCommand: 7782 { 7783 /* 7784 Sharpen the image contrast. 7785 */ 7786 XSetCursorState(display,windows,MagickTrue); 7787 XCheckRefreshWindows(display,windows); 7788 (void) ContrastImage(*image,MagickTrue); 7789 XSetCursorState(display,windows,MagickFalse); 7790 if (windows->image.orphan != MagickFalse) 7791 break; 7792 XConfigureImageColormap(display,resource_info,windows,*image); 7793 (void) XConfigureImage(display,resource_info,windows,*image); 7794 break; 7795 } 7796 case DullCommand: 7797 { 7798 /* 7799 Dull the image contrast. 7800 */ 7801 XSetCursorState(display,windows,MagickTrue); 7802 XCheckRefreshWindows(display,windows); 7803 (void) ContrastImage(*image,MagickFalse); 7804 XSetCursorState(display,windows,MagickFalse); 7805 if (windows->image.orphan != MagickFalse) 7806 break; 7807 XConfigureImageColormap(display,resource_info,windows,*image); 7808 (void) XConfigureImage(display,resource_info,windows,*image); 7809 break; 7810 } 7811 case ContrastStretchCommand: 7812 { 7813 double 7814 black_point, 7815 white_point; 7816 7817 static char 7818 levels[MaxTextExtent] = "1%"; 7819 7820 /* 7821 Query user for gamma value. 7822 */ 7823 (void) XDialogWidget(display,windows,"Contrast Stretch", 7824 "Enter black and white points:",levels); 7825 if (*levels == '\0') 7826 break; 7827 /* 7828 Contrast stretch image. 7829 */ 7830 XSetCursorState(display,windows,MagickTrue); 7831 XCheckRefreshWindows(display,windows); 7832 flags=ParseGeometry(levels,&geometry_info); 7833 black_point=geometry_info.rho; 7834 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7835 if ((flags & PercentValue) != 0) 7836 { 7837 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7838 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7839 } 7840 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7841 (void) ContrastStretchImage(*image,black_point,white_point); 7842 XSetCursorState(display,windows,MagickFalse); 7843 if (windows->image.orphan != MagickFalse) 7844 break; 7845 XConfigureImageColormap(display,resource_info,windows,*image); 7846 (void) XConfigureImage(display,resource_info,windows,*image); 7847 break; 7848 } 7849 case SigmoidalContrastCommand: 7850 { 7851 GeometryInfo 7852 geometry_info; 7853 7854 MagickStatusType 7855 flags; 7856 7857 static char 7858 levels[MaxTextExtent] = "3x50%"; 7859 7860 /* 7861 Query user for gamma value. 7862 */ 7863 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7864 "Enter contrast and midpoint:",levels); 7865 if (*levels == '\0') 7866 break; 7867 /* 7868 Contrast stretch image. 7869 */ 7870 XSetCursorState(display,windows,MagickTrue); 7871 XCheckRefreshWindows(display,windows); 7872 flags=ParseGeometry(levels,&geometry_info); 7873 if ((flags & SigmaValue) == 0) 7874 geometry_info.sigma=1.0*QuantumRange/2.0; 7875 if ((flags & PercentValue) != 0) 7876 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7877 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7878 geometry_info.sigma); 7879 XSetCursorState(display,windows,MagickFalse); 7880 if (windows->image.orphan != MagickFalse) 7881 break; 7882 XConfigureImageColormap(display,resource_info,windows,*image); 7883 (void) XConfigureImage(display,resource_info,windows,*image); 7884 break; 7885 } 7886 case NormalizeCommand: 7887 { 7888 /* 7889 Perform histogram normalization on the image. 7890 */ 7891 XSetCursorState(display,windows,MagickTrue); 7892 XCheckRefreshWindows(display,windows); 7893 (void) NormalizeImage(*image); 7894 XSetCursorState(display,windows,MagickFalse); 7895 if (windows->image.orphan != MagickFalse) 7896 break; 7897 XConfigureImageColormap(display,resource_info,windows,*image); 7898 (void) XConfigureImage(display,resource_info,windows,*image); 7899 break; 7900 } 7901 case EqualizeCommand: 7902 { 7903 /* 7904 Perform histogram equalization on the image. 7905 */ 7906 XSetCursorState(display,windows,MagickTrue); 7907 XCheckRefreshWindows(display,windows); 7908 (void) EqualizeImage(*image); 7909 XSetCursorState(display,windows,MagickFalse); 7910 if (windows->image.orphan != MagickFalse) 7911 break; 7912 XConfigureImageColormap(display,resource_info,windows,*image); 7913 (void) XConfigureImage(display,resource_info,windows,*image); 7914 break; 7915 } 7916 case NegateCommand: 7917 { 7918 /* 7919 Negate colors in image. 7920 */ 7921 XSetCursorState(display,windows,MagickTrue); 7922 XCheckRefreshWindows(display,windows); 7923 (void) NegateImage(*image,MagickFalse,&(*image)->exception); 7924 XSetCursorState(display,windows,MagickFalse); 7925 if (windows->image.orphan != MagickFalse) 7926 break; 7927 XConfigureImageColormap(display,resource_info,windows,*image); 7928 (void) XConfigureImage(display,resource_info,windows,*image); 7929 break; 7930 } 7931 case GrayscaleCommand: 7932 { 7933 /* 7934 Convert image to grayscale. 7935 */ 7936 XSetCursorState(display,windows,MagickTrue); 7937 XCheckRefreshWindows(display,windows); 7938 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 7939 GrayscaleType : GrayscaleMatteType); 7940 XSetCursorState(display,windows,MagickFalse); 7941 if (windows->image.orphan != MagickFalse) 7942 break; 7943 XConfigureImageColormap(display,resource_info,windows,*image); 7944 (void) XConfigureImage(display,resource_info,windows,*image); 7945 break; 7946 } 7947 case MapCommand: 7948 { 7949 Image 7950 *affinity_image; 7951 7952 static char 7953 filename[MaxTextExtent] = "\0"; 7954 7955 /* 7956 Request image file name from user. 7957 */ 7958 XFileBrowserWidget(display,windows,"Map",filename); 7959 if (*filename == '\0') 7960 break; 7961 /* 7962 Map image. 7963 */ 7964 XSetCursorState(display,windows,MagickTrue); 7965 XCheckRefreshWindows(display,windows); 7966 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 7967 affinity_image=ReadImage(image_info,&(*image)->exception); 7968 if (affinity_image != (Image *) NULL) 7969 { 7970 (void) RemapImage(&quantize_info,*image,affinity_image); 7971 affinity_image=DestroyImage(affinity_image); 7972 } 7973 CatchException(&(*image)->exception); 7974 XSetCursorState(display,windows,MagickFalse); 7975 if (windows->image.orphan != MagickFalse) 7976 break; 7977 XConfigureImageColormap(display,resource_info,windows,*image); 7978 (void) XConfigureImage(display,resource_info,windows,*image); 7979 break; 7980 } 7981 case QuantizeCommand: 7982 { 7983 int 7984 status; 7985 7986 static char 7987 colors[MaxTextExtent] = "256"; 7988 7989 /* 7990 Query user for maximum number of colors. 7991 */ 7992 status=XDialogWidget(display,windows,"Quantize", 7993 "Maximum number of colors:",colors); 7994 if (*colors == '\0') 7995 break; 7996 /* 7997 Color reduce the image. 7998 */ 7999 XSetCursorState(display,windows,MagickTrue); 8000 XCheckRefreshWindows(display,windows); 8001 quantize_info.number_colors=StringToUnsignedLong(colors); 8002 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8003 (void) QuantizeImage(&quantize_info,*image); 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 DespeckleCommand: 8012 { 8013 Image 8014 *despeckle_image; 8015 8016 /* 8017 Despeckle image. 8018 */ 8019 XSetCursorState(display,windows,MagickTrue); 8020 XCheckRefreshWindows(display,windows); 8021 despeckle_image=DespeckleImage(*image,&(*image)->exception); 8022 if (despeckle_image != (Image *) NULL) 8023 { 8024 *image=DestroyImage(*image); 8025 *image=despeckle_image; 8026 } 8027 CatchException(&(*image)->exception); 8028 XSetCursorState(display,windows,MagickFalse); 8029 if (windows->image.orphan != MagickFalse) 8030 break; 8031 XConfigureImageColormap(display,resource_info,windows,*image); 8032 (void) XConfigureImage(display,resource_info,windows,*image); 8033 break; 8034 } 8035 case EmbossCommand: 8036 { 8037 Image 8038 *emboss_image; 8039 8040 static char 8041 radius[MaxTextExtent] = "0.0x1.0"; 8042 8043 /* 8044 Query user for emboss radius. 8045 */ 8046 (void) XDialogWidget(display,windows,"Emboss", 8047 "Enter the emboss radius and standard deviation:",radius); 8048 if (*radius == '\0') 8049 break; 8050 /* 8051 Reduce noise in the image. 8052 */ 8053 XSetCursorState(display,windows,MagickTrue); 8054 XCheckRefreshWindows(display,windows); 8055 flags=ParseGeometry(radius,&geometry_info); 8056 if ((flags & SigmaValue) == 0) 8057 geometry_info.sigma=1.0; 8058 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8059 &(*image)->exception); 8060 if (emboss_image != (Image *) NULL) 8061 { 8062 *image=DestroyImage(*image); 8063 *image=emboss_image; 8064 } 8065 CatchException(&(*image)->exception); 8066 XSetCursorState(display,windows,MagickFalse); 8067 if (windows->image.orphan != MagickFalse) 8068 break; 8069 XConfigureImageColormap(display,resource_info,windows,*image); 8070 (void) XConfigureImage(display,resource_info,windows,*image); 8071 break; 8072 } 8073 case ReduceNoiseCommand: 8074 { 8075 Image 8076 *noise_image; 8077 8078 static char 8079 radius[MaxTextExtent] = "0"; 8080 8081 /* 8082 Query user for noise radius. 8083 */ 8084 (void) XDialogWidget(display,windows,"Reduce Noise", 8085 "Enter the noise radius:",radius); 8086 if (*radius == '\0') 8087 break; 8088 /* 8089 Reduce noise in the image. 8090 */ 8091 XSetCursorState(display,windows,MagickTrue); 8092 XCheckRefreshWindows(display,windows); 8093 flags=ParseGeometry(radius,&geometry_info); 8094 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8095 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception); 8096 if (noise_image != (Image *) NULL) 8097 { 8098 *image=DestroyImage(*image); 8099 *image=noise_image; 8100 } 8101 CatchException(&(*image)->exception); 8102 XSetCursorState(display,windows,MagickFalse); 8103 if (windows->image.orphan != MagickFalse) 8104 break; 8105 XConfigureImageColormap(display,resource_info,windows,*image); 8106 (void) XConfigureImage(display,resource_info,windows,*image); 8107 break; 8108 } 8109 case AddNoiseCommand: 8110 { 8111 char 8112 **noises; 8113 8114 Image 8115 *noise_image; 8116 8117 static char 8118 noise_type[MaxTextExtent] = "Gaussian"; 8119 8120 /* 8121 Add noise to the image. 8122 */ 8123 noises=GetCommandOptions(MagickNoiseOptions); 8124 if (noises == (char **) NULL) 8125 break; 8126 XListBrowserWidget(display,windows,&windows->widget, 8127 (const char **) noises,"Add Noise", 8128 "Select a type of noise to add to your image:",noise_type); 8129 noises=DestroyStringList(noises); 8130 if (*noise_type == '\0') 8131 break; 8132 XSetCursorState(display,windows,MagickTrue); 8133 XCheckRefreshWindows(display,windows); 8134 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8135 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception); 8136 if (noise_image != (Image *) NULL) 8137 { 8138 *image=DestroyImage(*image); 8139 *image=noise_image; 8140 } 8141 CatchException(&(*image)->exception); 8142 XSetCursorState(display,windows,MagickFalse); 8143 if (windows->image.orphan != MagickFalse) 8144 break; 8145 XConfigureImageColormap(display,resource_info,windows,*image); 8146 (void) XConfigureImage(display,resource_info,windows,*image); 8147 break; 8148 } 8149 case SharpenCommand: 8150 { 8151 Image 8152 *sharp_image; 8153 8154 static char 8155 radius[MaxTextExtent] = "0.0x1.0"; 8156 8157 /* 8158 Query user for sharpen radius. 8159 */ 8160 (void) XDialogWidget(display,windows,"Sharpen", 8161 "Enter the sharpen radius and standard deviation:",radius); 8162 if (*radius == '\0') 8163 break; 8164 /* 8165 Sharpen image scanlines. 8166 */ 8167 XSetCursorState(display,windows,MagickTrue); 8168 XCheckRefreshWindows(display,windows); 8169 flags=ParseGeometry(radius,&geometry_info); 8170 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8171 &(*image)->exception); 8172 if (sharp_image != (Image *) NULL) 8173 { 8174 *image=DestroyImage(*image); 8175 *image=sharp_image; 8176 } 8177 CatchException(&(*image)->exception); 8178 XSetCursorState(display,windows,MagickFalse); 8179 if (windows->image.orphan != MagickFalse) 8180 break; 8181 XConfigureImageColormap(display,resource_info,windows,*image); 8182 (void) XConfigureImage(display,resource_info,windows,*image); 8183 break; 8184 } 8185 case BlurCommand: 8186 { 8187 Image 8188 *blur_image; 8189 8190 static char 8191 radius[MaxTextExtent] = "0.0x1.0"; 8192 8193 /* 8194 Query user for blur radius. 8195 */ 8196 (void) XDialogWidget(display,windows,"Blur", 8197 "Enter the blur radius and standard deviation:",radius); 8198 if (*radius == '\0') 8199 break; 8200 /* 8201 Blur an image. 8202 */ 8203 XSetCursorState(display,windows,MagickTrue); 8204 XCheckRefreshWindows(display,windows); 8205 flags=ParseGeometry(radius,&geometry_info); 8206 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8207 &(*image)->exception); 8208 if (blur_image != (Image *) NULL) 8209 { 8210 *image=DestroyImage(*image); 8211 *image=blur_image; 8212 } 8213 CatchException(&(*image)->exception); 8214 XSetCursorState(display,windows,MagickFalse); 8215 if (windows->image.orphan != MagickFalse) 8216 break; 8217 XConfigureImageColormap(display,resource_info,windows,*image); 8218 (void) XConfigureImage(display,resource_info,windows,*image); 8219 break; 8220 } 8221 case ThresholdCommand: 8222 { 8223 double 8224 threshold; 8225 8226 static char 8227 factor[MaxTextExtent] = "128"; 8228 8229 /* 8230 Query user for threshold value. 8231 */ 8232 (void) XDialogWidget(display,windows,"Threshold", 8233 "Enter threshold value:",factor); 8234 if (*factor == '\0') 8235 break; 8236 /* 8237 Gamma correct image. 8238 */ 8239 XSetCursorState(display,windows,MagickTrue); 8240 XCheckRefreshWindows(display,windows); 8241 threshold=SiPrefixToDouble(factor,QuantumRange); 8242 (void) BilevelImage(*image,threshold); 8243 XSetCursorState(display,windows,MagickFalse); 8244 if (windows->image.orphan != MagickFalse) 8245 break; 8246 XConfigureImageColormap(display,resource_info,windows,*image); 8247 (void) XConfigureImage(display,resource_info,windows,*image); 8248 break; 8249 } 8250 case EdgeDetectCommand: 8251 { 8252 Image 8253 *edge_image; 8254 8255 static char 8256 radius[MaxTextExtent] = "0"; 8257 8258 /* 8259 Query user for edge factor. 8260 */ 8261 (void) XDialogWidget(display,windows,"Detect Edges", 8262 "Enter the edge detect radius:",radius); 8263 if (*radius == '\0') 8264 break; 8265 /* 8266 Detect edge in image. 8267 */ 8268 XSetCursorState(display,windows,MagickTrue); 8269 XCheckRefreshWindows(display,windows); 8270 flags=ParseGeometry(radius,&geometry_info); 8271 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception); 8272 if (edge_image != (Image *) NULL) 8273 { 8274 *image=DestroyImage(*image); 8275 *image=edge_image; 8276 } 8277 CatchException(&(*image)->exception); 8278 XSetCursorState(display,windows,MagickFalse); 8279 if (windows->image.orphan != MagickFalse) 8280 break; 8281 XConfigureImageColormap(display,resource_info,windows,*image); 8282 (void) XConfigureImage(display,resource_info,windows,*image); 8283 break; 8284 } 8285 case SpreadCommand: 8286 { 8287 Image 8288 *spread_image; 8289 8290 static char 8291 amount[MaxTextExtent] = "2"; 8292 8293 /* 8294 Query user for spread amount. 8295 */ 8296 (void) XDialogWidget(display,windows,"Spread", 8297 "Enter the displacement amount:",amount); 8298 if (*amount == '\0') 8299 break; 8300 /* 8301 Displace image pixels by a random amount. 8302 */ 8303 XSetCursorState(display,windows,MagickTrue); 8304 XCheckRefreshWindows(display,windows); 8305 flags=ParseGeometry(amount,&geometry_info); 8306 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception); 8307 if (spread_image != (Image *) NULL) 8308 { 8309 *image=DestroyImage(*image); 8310 *image=spread_image; 8311 } 8312 CatchException(&(*image)->exception); 8313 XSetCursorState(display,windows,MagickFalse); 8314 if (windows->image.orphan != MagickFalse) 8315 break; 8316 XConfigureImageColormap(display,resource_info,windows,*image); 8317 (void) XConfigureImage(display,resource_info,windows,*image); 8318 break; 8319 } 8320 case ShadeCommand: 8321 { 8322 Image 8323 *shade_image; 8324 8325 int 8326 status; 8327 8328 static char 8329 geometry[MaxTextExtent] = "30x30"; 8330 8331 /* 8332 Query user for the shade geometry. 8333 */ 8334 status=XDialogWidget(display,windows,"Shade", 8335 "Enter the azimuth and elevation of the light source:",geometry); 8336 if (*geometry == '\0') 8337 break; 8338 /* 8339 Shade image pixels. 8340 */ 8341 XSetCursorState(display,windows,MagickTrue); 8342 XCheckRefreshWindows(display,windows); 8343 flags=ParseGeometry(geometry,&geometry_info); 8344 if ((flags & SigmaValue) == 0) 8345 geometry_info.sigma=1.0; 8346 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8347 geometry_info.rho,geometry_info.sigma,&(*image)->exception); 8348 if (shade_image != (Image *) NULL) 8349 { 8350 *image=DestroyImage(*image); 8351 *image=shade_image; 8352 } 8353 CatchException(&(*image)->exception); 8354 XSetCursorState(display,windows,MagickFalse); 8355 if (windows->image.orphan != MagickFalse) 8356 break; 8357 XConfigureImageColormap(display,resource_info,windows,*image); 8358 (void) XConfigureImage(display,resource_info,windows,*image); 8359 break; 8360 } 8361 case RaiseCommand: 8362 { 8363 static char 8364 bevel_width[MaxTextExtent] = "10"; 8365 8366 /* 8367 Query user for bevel width. 8368 */ 8369 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8370 if (*bevel_width == '\0') 8371 break; 8372 /* 8373 Raise an image. 8374 */ 8375 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8376 XSetCursorState(display,windows,MagickTrue); 8377 XCheckRefreshWindows(display,windows); 8378 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8379 &(*image)->exception); 8380 (void) RaiseImage(*image,&page_geometry,MagickTrue); 8381 XSetCursorState(display,windows,MagickFalse); 8382 if (windows->image.orphan != MagickFalse) 8383 break; 8384 XConfigureImageColormap(display,resource_info,windows,*image); 8385 (void) XConfigureImage(display,resource_info,windows,*image); 8386 break; 8387 } 8388 case SegmentCommand: 8389 { 8390 static char 8391 threshold[MaxTextExtent] = "1.0x1.5"; 8392 8393 /* 8394 Query user for smoothing threshold. 8395 */ 8396 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8397 threshold); 8398 if (*threshold == '\0') 8399 break; 8400 /* 8401 Segment an image. 8402 */ 8403 XSetCursorState(display,windows,MagickTrue); 8404 XCheckRefreshWindows(display,windows); 8405 flags=ParseGeometry(threshold,&geometry_info); 8406 if ((flags & SigmaValue) == 0) 8407 geometry_info.sigma=1.0; 8408 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8409 geometry_info.sigma); 8410 XSetCursorState(display,windows,MagickFalse); 8411 if (windows->image.orphan != MagickFalse) 8412 break; 8413 XConfigureImageColormap(display,resource_info,windows,*image); 8414 (void) XConfigureImage(display,resource_info,windows,*image); 8415 break; 8416 } 8417 case SepiaToneCommand: 8418 { 8419 double 8420 threshold; 8421 8422 Image 8423 *sepia_image; 8424 8425 static char 8426 factor[MaxTextExtent] = "80%"; 8427 8428 /* 8429 Query user for sepia-tone factor. 8430 */ 8431 (void) XDialogWidget(display,windows,"Sepia Tone", 8432 "Enter the sepia tone factor (0 - 99.9%):",factor); 8433 if (*factor == '\0') 8434 break; 8435 /* 8436 Sepia tone image pixels. 8437 */ 8438 XSetCursorState(display,windows,MagickTrue); 8439 XCheckRefreshWindows(display,windows); 8440 threshold=SiPrefixToDouble(factor,QuantumRange); 8441 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception); 8442 if (sepia_image != (Image *) NULL) 8443 { 8444 *image=DestroyImage(*image); 8445 *image=sepia_image; 8446 } 8447 CatchException(&(*image)->exception); 8448 XSetCursorState(display,windows,MagickFalse); 8449 if (windows->image.orphan != MagickFalse) 8450 break; 8451 XConfigureImageColormap(display,resource_info,windows,*image); 8452 (void) XConfigureImage(display,resource_info,windows,*image); 8453 break; 8454 } 8455 case SolarizeCommand: 8456 { 8457 double 8458 threshold; 8459 8460 static char 8461 factor[MaxTextExtent] = "60%"; 8462 8463 /* 8464 Query user for solarize factor. 8465 */ 8466 (void) XDialogWidget(display,windows,"Solarize", 8467 "Enter the solarize factor (0 - 99.9%):",factor); 8468 if (*factor == '\0') 8469 break; 8470 /* 8471 Solarize image pixels. 8472 */ 8473 XSetCursorState(display,windows,MagickTrue); 8474 XCheckRefreshWindows(display,windows); 8475 threshold=SiPrefixToDouble(factor,QuantumRange); 8476 (void) SolarizeImage(*image,threshold); 8477 XSetCursorState(display,windows,MagickFalse); 8478 if (windows->image.orphan != MagickFalse) 8479 break; 8480 XConfigureImageColormap(display,resource_info,windows,*image); 8481 (void) XConfigureImage(display,resource_info,windows,*image); 8482 break; 8483 } 8484 case SwirlCommand: 8485 { 8486 Image 8487 *swirl_image; 8488 8489 static char 8490 degrees[MaxTextExtent] = "60"; 8491 8492 /* 8493 Query user for swirl angle. 8494 */ 8495 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8496 degrees); 8497 if (*degrees == '\0') 8498 break; 8499 /* 8500 Swirl image pixels about the center. 8501 */ 8502 XSetCursorState(display,windows,MagickTrue); 8503 XCheckRefreshWindows(display,windows); 8504 flags=ParseGeometry(degrees,&geometry_info); 8505 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception); 8506 if (swirl_image != (Image *) NULL) 8507 { 8508 *image=DestroyImage(*image); 8509 *image=swirl_image; 8510 } 8511 CatchException(&(*image)->exception); 8512 XSetCursorState(display,windows,MagickFalse); 8513 if (windows->image.orphan != MagickFalse) 8514 break; 8515 XConfigureImageColormap(display,resource_info,windows,*image); 8516 (void) XConfigureImage(display,resource_info,windows,*image); 8517 break; 8518 } 8519 case ImplodeCommand: 8520 { 8521 Image 8522 *implode_image; 8523 8524 static char 8525 factor[MaxTextExtent] = "0.3"; 8526 8527 /* 8528 Query user for implode factor. 8529 */ 8530 (void) XDialogWidget(display,windows,"Implode", 8531 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8532 if (*factor == '\0') 8533 break; 8534 /* 8535 Implode image pixels about the center. 8536 */ 8537 XSetCursorState(display,windows,MagickTrue); 8538 XCheckRefreshWindows(display,windows); 8539 flags=ParseGeometry(factor,&geometry_info); 8540 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception); 8541 if (implode_image != (Image *) NULL) 8542 { 8543 *image=DestroyImage(*image); 8544 *image=implode_image; 8545 } 8546 CatchException(&(*image)->exception); 8547 XSetCursorState(display,windows,MagickFalse); 8548 if (windows->image.orphan != MagickFalse) 8549 break; 8550 XConfigureImageColormap(display,resource_info,windows,*image); 8551 (void) XConfigureImage(display,resource_info,windows,*image); 8552 break; 8553 } 8554 case VignetteCommand: 8555 { 8556 Image 8557 *vignette_image; 8558 8559 static char 8560 geometry[MaxTextExtent] = "0x20"; 8561 8562 /* 8563 Query user for the vignette geometry. 8564 */ 8565 (void) XDialogWidget(display,windows,"Vignette", 8566 "Enter the radius, sigma, and x and y offsets:",geometry); 8567 if (*geometry == '\0') 8568 break; 8569 /* 8570 Soften the edges of the image in vignette style 8571 */ 8572 XSetCursorState(display,windows,MagickTrue); 8573 XCheckRefreshWindows(display,windows); 8574 flags=ParseGeometry(geometry,&geometry_info); 8575 if ((flags & SigmaValue) == 0) 8576 geometry_info.sigma=1.0; 8577 if ((flags & XiValue) == 0) 8578 geometry_info.xi=0.1*(*image)->columns; 8579 if ((flags & PsiValue) == 0) 8580 geometry_info.psi=0.1*(*image)->rows; 8581 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8582 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8583 0.5),&(*image)->exception); 8584 if (vignette_image != (Image *) NULL) 8585 { 8586 *image=DestroyImage(*image); 8587 *image=vignette_image; 8588 } 8589 CatchException(&(*image)->exception); 8590 XSetCursorState(display,windows,MagickFalse); 8591 if (windows->image.orphan != MagickFalse) 8592 break; 8593 XConfigureImageColormap(display,resource_info,windows,*image); 8594 (void) XConfigureImage(display,resource_info,windows,*image); 8595 break; 8596 } 8597 case WaveCommand: 8598 { 8599 Image 8600 *wave_image; 8601 8602 static char 8603 geometry[MaxTextExtent] = "25x150"; 8604 8605 /* 8606 Query user for the wave geometry. 8607 */ 8608 (void) XDialogWidget(display,windows,"Wave", 8609 "Enter the amplitude and length of the wave:",geometry); 8610 if (*geometry == '\0') 8611 break; 8612 /* 8613 Alter an image along a sine wave. 8614 */ 8615 XSetCursorState(display,windows,MagickTrue); 8616 XCheckRefreshWindows(display,windows); 8617 flags=ParseGeometry(geometry,&geometry_info); 8618 if ((flags & SigmaValue) == 0) 8619 geometry_info.sigma=1.0; 8620 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8621 &(*image)->exception); 8622 if (wave_image != (Image *) NULL) 8623 { 8624 *image=DestroyImage(*image); 8625 *image=wave_image; 8626 } 8627 CatchException(&(*image)->exception); 8628 XSetCursorState(display,windows,MagickFalse); 8629 if (windows->image.orphan != MagickFalse) 8630 break; 8631 XConfigureImageColormap(display,resource_info,windows,*image); 8632 (void) XConfigureImage(display,resource_info,windows,*image); 8633 break; 8634 } 8635 case OilPaintCommand: 8636 { 8637 Image 8638 *paint_image; 8639 8640 static char 8641 radius[MaxTextExtent] = "0"; 8642 8643 /* 8644 Query user for circular neighborhood radius. 8645 */ 8646 (void) XDialogWidget(display,windows,"Oil Paint", 8647 "Enter the mask radius:",radius); 8648 if (*radius == '\0') 8649 break; 8650 /* 8651 OilPaint image scanlines. 8652 */ 8653 XSetCursorState(display,windows,MagickTrue); 8654 XCheckRefreshWindows(display,windows); 8655 flags=ParseGeometry(radius,&geometry_info); 8656 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception); 8657 if (paint_image != (Image *) NULL) 8658 { 8659 *image=DestroyImage(*image); 8660 *image=paint_image; 8661 } 8662 CatchException(&(*image)->exception); 8663 XSetCursorState(display,windows,MagickFalse); 8664 if (windows->image.orphan != MagickFalse) 8665 break; 8666 XConfigureImageColormap(display,resource_info,windows,*image); 8667 (void) XConfigureImage(display,resource_info,windows,*image); 8668 break; 8669 } 8670 case CharcoalDrawCommand: 8671 { 8672 Image 8673 *charcoal_image; 8674 8675 static char 8676 radius[MaxTextExtent] = "0x1"; 8677 8678 /* 8679 Query user for charcoal radius. 8680 */ 8681 (void) XDialogWidget(display,windows,"Charcoal Draw", 8682 "Enter the charcoal radius and sigma:",radius); 8683 if (*radius == '\0') 8684 break; 8685 /* 8686 Charcoal the image. 8687 */ 8688 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8689 XSetCursorState(display,windows,MagickTrue); 8690 XCheckRefreshWindows(display,windows); 8691 flags=ParseGeometry(radius,&geometry_info); 8692 if ((flags & SigmaValue) == 0) 8693 geometry_info.sigma=geometry_info.rho; 8694 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8695 &(*image)->exception); 8696 if (charcoal_image != (Image *) NULL) 8697 { 8698 *image=DestroyImage(*image); 8699 *image=charcoal_image; 8700 } 8701 CatchException(&(*image)->exception); 8702 XSetCursorState(display,windows,MagickFalse); 8703 if (windows->image.orphan != MagickFalse) 8704 break; 8705 XConfigureImageColormap(display,resource_info,windows,*image); 8706 (void) XConfigureImage(display,resource_info,windows,*image); 8707 break; 8708 } 8709 case AnnotateCommand: 8710 { 8711 /* 8712 Annotate the image with text. 8713 */ 8714 status=XAnnotateEditImage(display,resource_info,windows,*image); 8715 if (status == MagickFalse) 8716 { 8717 XNoticeWidget(display,windows,"Unable to annotate X image", 8718 (*image)->filename); 8719 break; 8720 } 8721 break; 8722 } 8723 case DrawCommand: 8724 { 8725 /* 8726 Draw image. 8727 */ 8728 status=XDrawEditImage(display,resource_info,windows,image); 8729 if (status == MagickFalse) 8730 { 8731 XNoticeWidget(display,windows,"Unable to draw on the X image", 8732 (*image)->filename); 8733 break; 8734 } 8735 break; 8736 } 8737 case ColorCommand: 8738 { 8739 /* 8740 Color edit. 8741 */ 8742 status=XColorEditImage(display,resource_info,windows,image); 8743 if (status == MagickFalse) 8744 { 8745 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8746 (*image)->filename); 8747 break; 8748 } 8749 break; 8750 } 8751 case MatteCommand: 8752 { 8753 /* 8754 Matte edit. 8755 */ 8756 status=XMatteEditImage(display,resource_info,windows,image); 8757 if (status == MagickFalse) 8758 { 8759 XNoticeWidget(display,windows,"Unable to matte edit X image", 8760 (*image)->filename); 8761 break; 8762 } 8763 break; 8764 } 8765 case CompositeCommand: 8766 { 8767 /* 8768 Composite image. 8769 */ 8770 status=XCompositeImage(display,resource_info,windows,*image); 8771 if (status == MagickFalse) 8772 { 8773 XNoticeWidget(display,windows,"Unable to composite X image", 8774 (*image)->filename); 8775 break; 8776 } 8777 break; 8778 } 8779 case AddBorderCommand: 8780 { 8781 Image 8782 *border_image; 8783 8784 static char 8785 geometry[MaxTextExtent] = "6x6"; 8786 8787 /* 8788 Query user for border color and geometry. 8789 */ 8790 XColorBrowserWidget(display,windows,"Select",color); 8791 if (*color == '\0') 8792 break; 8793 (void) XDialogWidget(display,windows,"Add Border", 8794 "Enter border geometry:",geometry); 8795 if (*geometry == '\0') 8796 break; 8797 /* 8798 Add a border to the image. 8799 */ 8800 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8801 XSetCursorState(display,windows,MagickTrue); 8802 XCheckRefreshWindows(display,windows); 8803 (void) QueryColorDatabase(color,&(*image)->border_color, 8804 &(*image)->exception); 8805 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8806 &(*image)->exception); 8807 border_image=BorderImage(*image,&page_geometry,&(*image)->exception); 8808 if (border_image != (Image *) NULL) 8809 { 8810 *image=DestroyImage(*image); 8811 *image=border_image; 8812 } 8813 CatchException(&(*image)->exception); 8814 XSetCursorState(display,windows,MagickFalse); 8815 if (windows->image.orphan != MagickFalse) 8816 break; 8817 windows->image.window_changes.width=(int) (*image)->columns; 8818 windows->image.window_changes.height=(int) (*image)->rows; 8819 XConfigureImageColormap(display,resource_info,windows,*image); 8820 (void) XConfigureImage(display,resource_info,windows,*image); 8821 break; 8822 } 8823 case AddFrameCommand: 8824 { 8825 FrameInfo 8826 frame_info; 8827 8828 Image 8829 *frame_image; 8830 8831 static char 8832 geometry[MaxTextExtent] = "6x6"; 8833 8834 /* 8835 Query user for frame color and geometry. 8836 */ 8837 XColorBrowserWidget(display,windows,"Select",color); 8838 if (*color == '\0') 8839 break; 8840 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8841 geometry); 8842 if (*geometry == '\0') 8843 break; 8844 /* 8845 Surround image with an ornamental border. 8846 */ 8847 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8848 XSetCursorState(display,windows,MagickTrue); 8849 XCheckRefreshWindows(display,windows); 8850 (void) QueryColorDatabase(color,&(*image)->matte_color, 8851 &(*image)->exception); 8852 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8853 &(*image)->exception); 8854 frame_info.width=page_geometry.width; 8855 frame_info.height=page_geometry.height; 8856 frame_info.outer_bevel=page_geometry.x; 8857 frame_info.inner_bevel=page_geometry.y; 8858 frame_info.x=(ssize_t) frame_info.width; 8859 frame_info.y=(ssize_t) frame_info.height; 8860 frame_info.width=(*image)->columns+2*frame_info.width; 8861 frame_info.height=(*image)->rows+2*frame_info.height; 8862 frame_image=FrameImage(*image,&frame_info,&(*image)->exception); 8863 if (frame_image != (Image *) NULL) 8864 { 8865 *image=DestroyImage(*image); 8866 *image=frame_image; 8867 } 8868 CatchException(&(*image)->exception); 8869 XSetCursorState(display,windows,MagickFalse); 8870 if (windows->image.orphan != MagickFalse) 8871 break; 8872 windows->image.window_changes.width=(int) (*image)->columns; 8873 windows->image.window_changes.height=(int) (*image)->rows; 8874 XConfigureImageColormap(display,resource_info,windows,*image); 8875 (void) XConfigureImage(display,resource_info,windows,*image); 8876 break; 8877 } 8878 case CommentCommand: 8879 { 8880 const char 8881 *value; 8882 8883 FILE 8884 *file; 8885 8886 int 8887 unique_file; 8888 8889 /* 8890 Edit image comment. 8891 */ 8892 unique_file=AcquireUniqueFileResource(image_info->filename); 8893 if (unique_file == -1) 8894 XNoticeWidget(display,windows,"Unable to edit image comment", 8895 image_info->filename); 8896 value=GetImageProperty(*image,"comment"); 8897 if (value == (char *) NULL) 8898 unique_file=close(unique_file)-1; 8899 else 8900 { 8901 register const char 8902 *p; 8903 8904 file=fdopen(unique_file,"w"); 8905 if (file == (FILE *) NULL) 8906 { 8907 XNoticeWidget(display,windows,"Unable to edit image comment", 8908 image_info->filename); 8909 break; 8910 } 8911 for (p=value; *p != '\0'; p++) 8912 (void) fputc((int) *p,file); 8913 (void) fputc('\n',file); 8914 (void) fclose(file); 8915 } 8916 XSetCursorState(display,windows,MagickTrue); 8917 XCheckRefreshWindows(display,windows); 8918 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8919 &(*image)->exception); 8920 if (status == MagickFalse) 8921 XNoticeWidget(display,windows,"Unable to edit image comment", 8922 (char *) NULL); 8923 else 8924 { 8925 char 8926 *comment; 8927 8928 comment=FileToString(image_info->filename,~0UL,&(*image)->exception); 8929 if (comment != (char *) NULL) 8930 { 8931 (void) SetImageProperty(*image,"comment",comment); 8932 (*image)->taint=MagickTrue; 8933 } 8934 } 8935 (void) RelinquishUniqueFileResource(image_info->filename); 8936 XSetCursorState(display,windows,MagickFalse); 8937 break; 8938 } 8939 case LaunchCommand: 8940 { 8941 /* 8942 Launch program. 8943 */ 8944 XSetCursorState(display,windows,MagickTrue); 8945 XCheckRefreshWindows(display,windows); 8946 (void) AcquireUniqueFilename(filename); 8947 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 8948 filename); 8949 status=WriteImage(image_info,*image); 8950 if (status == MagickFalse) 8951 XNoticeWidget(display,windows,"Unable to launch image editor", 8952 (char *) NULL); 8953 else 8954 { 8955 nexus=ReadImage(resource_info->image_info,&(*image)->exception); 8956 CatchException(&(*image)->exception); 8957 XClientMessage(display,windows->image.id,windows->im_protocols, 8958 windows->im_next_image,CurrentTime); 8959 } 8960 (void) RelinquishUniqueFileResource(filename); 8961 XSetCursorState(display,windows,MagickFalse); 8962 break; 8963 } 8964 case RegionofInterestCommand: 8965 { 8966 /* 8967 Apply an image processing technique to a region of interest. 8968 */ 8969 (void) XROIImage(display,resource_info,windows,image); 8970 break; 8971 } 8972 case InfoCommand: 8973 break; 8974 case ZoomCommand: 8975 { 8976 /* 8977 Zoom image. 8978 */ 8979 if (windows->magnify.mapped != MagickFalse) 8980 (void) XRaiseWindow(display,windows->magnify.id); 8981 else 8982 { 8983 /* 8984 Make magnify image. 8985 */ 8986 XSetCursorState(display,windows,MagickTrue); 8987 (void) XMapRaised(display,windows->magnify.id); 8988 XSetCursorState(display,windows,MagickFalse); 8989 } 8990 break; 8991 } 8992 case ShowPreviewCommand: 8993 { 8994 char 8995 **previews; 8996 8997 Image 8998 *preview_image; 8999 9000 static char 9001 preview_type[MaxTextExtent] = "Gamma"; 9002 9003 /* 9004 Select preview type from menu. 9005 */ 9006 previews=GetCommandOptions(MagickPreviewOptions); 9007 if (previews == (char **) NULL) 9008 break; 9009 XListBrowserWidget(display,windows,&windows->widget, 9010 (const char **) previews,"Preview", 9011 "Select an enhancement, effect, or F/X:",preview_type); 9012 previews=DestroyStringList(previews); 9013 if (*preview_type == '\0') 9014 break; 9015 /* 9016 Show image preview. 9017 */ 9018 XSetCursorState(display,windows,MagickTrue); 9019 XCheckRefreshWindows(display,windows); 9020 image_info->preview_type=(PreviewType) 9021 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9022 image_info->group=(ssize_t) windows->image.id; 9023 (void) DeleteImageProperty(*image,"label"); 9024 (void) SetImageProperty(*image,"label","Preview"); 9025 (void) AcquireUniqueFilename(filename); 9026 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9027 filename); 9028 status=WriteImage(image_info,*image); 9029 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9030 preview_image=ReadImage(image_info,&(*image)->exception); 9031 (void) RelinquishUniqueFileResource(filename); 9032 if (preview_image == (Image *) NULL) 9033 break; 9034 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9035 filename); 9036 status=WriteImage(image_info,preview_image); 9037 preview_image=DestroyImage(preview_image); 9038 if (status == MagickFalse) 9039 XNoticeWidget(display,windows,"Unable to show image preview", 9040 (*image)->filename); 9041 XDelay(display,1500); 9042 XSetCursorState(display,windows,MagickFalse); 9043 break; 9044 } 9045 case ShowHistogramCommand: 9046 { 9047 Image 9048 *histogram_image; 9049 9050 /* 9051 Show image histogram. 9052 */ 9053 XSetCursorState(display,windows,MagickTrue); 9054 XCheckRefreshWindows(display,windows); 9055 image_info->group=(ssize_t) windows->image.id; 9056 (void) DeleteImageProperty(*image,"label"); 9057 (void) SetImageProperty(*image,"label","Histogram"); 9058 (void) AcquireUniqueFilename(filename); 9059 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9060 filename); 9061 status=WriteImage(image_info,*image); 9062 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9063 histogram_image=ReadImage(image_info,&(*image)->exception); 9064 (void) RelinquishUniqueFileResource(filename); 9065 if (histogram_image == (Image *) NULL) 9066 break; 9067 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9068 "show:%s",filename); 9069 status=WriteImage(image_info,histogram_image); 9070 histogram_image=DestroyImage(histogram_image); 9071 if (status == MagickFalse) 9072 XNoticeWidget(display,windows,"Unable to show histogram", 9073 (*image)->filename); 9074 XDelay(display,1500); 9075 XSetCursorState(display,windows,MagickFalse); 9076 break; 9077 } 9078 case ShowMatteCommand: 9079 { 9080 Image 9081 *matte_image; 9082 9083 if ((*image)->matte == MagickFalse) 9084 { 9085 XNoticeWidget(display,windows, 9086 "Image does not have any matte information",(*image)->filename); 9087 break; 9088 } 9089 /* 9090 Show image matte. 9091 */ 9092 XSetCursorState(display,windows,MagickTrue); 9093 XCheckRefreshWindows(display,windows); 9094 image_info->group=(ssize_t) windows->image.id; 9095 (void) DeleteImageProperty(*image,"label"); 9096 (void) SetImageProperty(*image,"label","Matte"); 9097 (void) AcquireUniqueFilename(filename); 9098 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9099 filename); 9100 status=WriteImage(image_info,*image); 9101 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9102 matte_image=ReadImage(image_info,&(*image)->exception); 9103 (void) RelinquishUniqueFileResource(filename); 9104 if (matte_image == (Image *) NULL) 9105 break; 9106 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9107 filename); 9108 status=WriteImage(image_info,matte_image); 9109 matte_image=DestroyImage(matte_image); 9110 if (status == MagickFalse) 9111 XNoticeWidget(display,windows,"Unable to show matte", 9112 (*image)->filename); 9113 XDelay(display,1500); 9114 XSetCursorState(display,windows,MagickFalse); 9115 break; 9116 } 9117 case BackgroundCommand: 9118 { 9119 /* 9120 Background image. 9121 */ 9122 status=XBackgroundImage(display,resource_info,windows,image); 9123 if (status == MagickFalse) 9124 break; 9125 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 9126 if (nexus != (Image *) NULL) 9127 XClientMessage(display,windows->image.id,windows->im_protocols, 9128 windows->im_next_image,CurrentTime); 9129 break; 9130 } 9131 case SlideShowCommand: 9132 { 9133 static char 9134 delay[MaxTextExtent] = "5"; 9135 9136 /* 9137 Display next image after pausing. 9138 */ 9139 (void) XDialogWidget(display,windows,"Slide Show", 9140 "Pause how many 1/100ths of a second between images:",delay); 9141 if (*delay == '\0') 9142 break; 9143 resource_info->delay=StringToUnsignedLong(delay); 9144 XClientMessage(display,windows->image.id,windows->im_protocols, 9145 windows->im_next_image,CurrentTime); 9146 break; 9147 } 9148 case PreferencesCommand: 9149 { 9150 /* 9151 Set user preferences. 9152 */ 9153 status=XPreferencesWidget(display,resource_info,windows); 9154 if (status == MagickFalse) 9155 break; 9156 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 9157 if (nexus != (Image *) NULL) 9158 XClientMessage(display,windows->image.id,windows->im_protocols, 9159 windows->im_next_image,CurrentTime); 9160 break; 9161 } 9162 case HelpCommand: 9163 { 9164 /* 9165 User requested help. 9166 */ 9167 XTextViewWidget(display,resource_info,windows,MagickFalse, 9168 "Help Viewer - Display",DisplayHelp); 9169 break; 9170 } 9171 case BrowseDocumentationCommand: 9172 { 9173 Atom 9174 mozilla_atom; 9175 9176 Window 9177 mozilla_window, 9178 root_window; 9179 9180 /* 9181 Browse the ImageMagick documentation. 9182 */ 9183 root_window=XRootWindow(display,XDefaultScreen(display)); 9184 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9185 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9186 if (mozilla_window != (Window) NULL) 9187 { 9188 char 9189 command[MaxTextExtent], 9190 *url; 9191 9192 /* 9193 Display documentation using Netscape remote control. 9194 */ 9195 url=GetMagickHomeURL(); 9196 (void) FormatLocaleString(command,MaxTextExtent, 9197 "openurl(%s,new-tab)",url); 9198 url=DestroyString(url); 9199 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9200 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9201 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9202 XSetCursorState(display,windows,MagickFalse); 9203 break; 9204 } 9205 XSetCursorState(display,windows,MagickTrue); 9206 XCheckRefreshWindows(display,windows); 9207 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9208 &(*image)->exception); 9209 if (status == MagickFalse) 9210 XNoticeWidget(display,windows,"Unable to browse documentation", 9211 (char *) NULL); 9212 XDelay(display,1500); 9213 XSetCursorState(display,windows,MagickFalse); 9214 break; 9215 } 9216 case VersionCommand: 9217 { 9218 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9219 GetMagickCopyright()); 9220 break; 9221 } 9222 case SaveToUndoBufferCommand: 9223 break; 9224 default: 9225 { 9226 (void) XBell(display,0); 9227 break; 9228 } 9229 } 9230 image_info=DestroyImageInfo(image_info); 9231 return(nexus); 9232} 9233 9234/* 9235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9236% % 9237% % 9238% % 9239+ X M a g n i f y I m a g e % 9240% % 9241% % 9242% % 9243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9244% 9245% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9246% The magnified portion is displayed in a separate window. 9247% 9248% The format of the XMagnifyImage method is: 9249% 9250% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9251% 9252% A description of each parameter follows: 9253% 9254% o display: Specifies a connection to an X server; returned from 9255% XOpenDisplay. 9256% 9257% o windows: Specifies a pointer to a XWindows structure. 9258% 9259% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9260% the entire image is refreshed. 9261% 9262*/ 9263static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9264{ 9265 char 9266 text[MaxTextExtent]; 9267 9268 register int 9269 x, 9270 y; 9271 9272 size_t 9273 state; 9274 9275 /* 9276 Update magnified image until the mouse button is released. 9277 */ 9278 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9279 state=DefaultState; 9280 x=event->xbutton.x; 9281 y=event->xbutton.y; 9282 windows->magnify.x=(int) windows->image.x+x; 9283 windows->magnify.y=(int) windows->image.y+y; 9284 do 9285 { 9286 /* 9287 Map and unmap Info widget as text cursor crosses its boundaries. 9288 */ 9289 if (windows->info.mapped != MagickFalse) 9290 { 9291 if ((x < (int) (windows->info.x+windows->info.width)) && 9292 (y < (int) (windows->info.y+windows->info.height))) 9293 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9294 } 9295 else 9296 if ((x > (int) (windows->info.x+windows->info.width)) || 9297 (y > (int) (windows->info.y+windows->info.height))) 9298 (void) XMapWindow(display,windows->info.id); 9299 if (windows->info.mapped != MagickFalse) 9300 { 9301 /* 9302 Display pointer position. 9303 */ 9304 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9305 windows->magnify.x,windows->magnify.y); 9306 XInfoWidget(display,windows,text); 9307 } 9308 /* 9309 Wait for next event. 9310 */ 9311 XScreenEvent(display,windows,event); 9312 switch (event->type) 9313 { 9314 case ButtonPress: 9315 break; 9316 case ButtonRelease: 9317 { 9318 /* 9319 User has finished magnifying image. 9320 */ 9321 x=event->xbutton.x; 9322 y=event->xbutton.y; 9323 state|=ExitState; 9324 break; 9325 } 9326 case Expose: 9327 break; 9328 case MotionNotify: 9329 { 9330 x=event->xmotion.x; 9331 y=event->xmotion.y; 9332 break; 9333 } 9334 default: 9335 break; 9336 } 9337 /* 9338 Check boundary conditions. 9339 */ 9340 if (x < 0) 9341 x=0; 9342 else 9343 if (x >= (int) windows->image.width) 9344 x=(int) windows->image.width-1; 9345 if (y < 0) 9346 y=0; 9347 else 9348 if (y >= (int) windows->image.height) 9349 y=(int) windows->image.height-1; 9350 } while ((state & ExitState) == 0); 9351 /* 9352 Display magnified image. 9353 */ 9354 XSetCursorState(display,windows,MagickFalse); 9355} 9356 9357/* 9358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9359% % 9360% % 9361% % 9362+ X M a g n i f y W i n d o w C o m m a n d % 9363% % 9364% % 9365% % 9366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9367% 9368% XMagnifyWindowCommand() moves the image within an Magnify window by one 9369% pixel as specified by the key symbol. 9370% 9371% The format of the XMagnifyWindowCommand method is: 9372% 9373% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9374% const MagickStatusType state,const KeySym key_symbol) 9375% 9376% A description of each parameter follows: 9377% 9378% o display: Specifies a connection to an X server; returned from 9379% XOpenDisplay. 9380% 9381% o windows: Specifies a pointer to a XWindows structure. 9382% 9383% o state: key mask. 9384% 9385% o key_symbol: Specifies a KeySym which indicates which side of the image 9386% to trim. 9387% 9388*/ 9389static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9390 const MagickStatusType state,const KeySym key_symbol) 9391{ 9392 unsigned int 9393 quantum; 9394 9395 /* 9396 User specified a magnify factor or position. 9397 */ 9398 quantum=1; 9399 if ((state & Mod1Mask) != 0) 9400 quantum=10; 9401 switch ((int) key_symbol) 9402 { 9403 case QuitCommand: 9404 { 9405 (void) XWithdrawWindow(display,windows->magnify.id, 9406 windows->magnify.screen); 9407 break; 9408 } 9409 case XK_Home: 9410 case XK_KP_Home: 9411 { 9412 windows->magnify.x=(int) windows->image.width/2; 9413 windows->magnify.y=(int) windows->image.height/2; 9414 break; 9415 } 9416 case XK_Left: 9417 case XK_KP_Left: 9418 { 9419 if (windows->magnify.x > 0) 9420 windows->magnify.x-=quantum; 9421 break; 9422 } 9423 case XK_Up: 9424 case XK_KP_Up: 9425 { 9426 if (windows->magnify.y > 0) 9427 windows->magnify.y-=quantum; 9428 break; 9429 } 9430 case XK_Right: 9431 case XK_KP_Right: 9432 { 9433 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9434 windows->magnify.x+=quantum; 9435 break; 9436 } 9437 case XK_Down: 9438 case XK_KP_Down: 9439 { 9440 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9441 windows->magnify.y+=quantum; 9442 break; 9443 } 9444 case XK_0: 9445 case XK_1: 9446 case XK_2: 9447 case XK_3: 9448 case XK_4: 9449 case XK_5: 9450 case XK_6: 9451 case XK_7: 9452 case XK_8: 9453 case XK_9: 9454 { 9455 windows->magnify.data=(key_symbol-XK_0); 9456 break; 9457 } 9458 case XK_KP_0: 9459 case XK_KP_1: 9460 case XK_KP_2: 9461 case XK_KP_3: 9462 case XK_KP_4: 9463 case XK_KP_5: 9464 case XK_KP_6: 9465 case XK_KP_7: 9466 case XK_KP_8: 9467 case XK_KP_9: 9468 { 9469 windows->magnify.data=(key_symbol-XK_KP_0); 9470 break; 9471 } 9472 default: 9473 break; 9474 } 9475 XMakeMagnifyImage(display,windows); 9476} 9477 9478/* 9479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9480% % 9481% % 9482% % 9483+ X M a k e P a n I m a g e % 9484% % 9485% % 9486% % 9487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9488% 9489% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9490% icon window. 9491% 9492% The format of the XMakePanImage method is: 9493% 9494% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9495% XWindows *windows,Image *image) 9496% 9497% A description of each parameter follows: 9498% 9499% o display: Specifies a connection to an X server; returned from 9500% XOpenDisplay. 9501% 9502% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9503% 9504% o windows: Specifies a pointer to a XWindows structure. 9505% 9506% o image: the image. 9507% 9508*/ 9509static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9510 XWindows *windows,Image *image) 9511{ 9512 MagickStatusType 9513 status; 9514 9515 /* 9516 Create and display image for panning icon. 9517 */ 9518 XSetCursorState(display,windows,MagickTrue); 9519 XCheckRefreshWindows(display,windows); 9520 windows->pan.x=(int) windows->image.x; 9521 windows->pan.y=(int) windows->image.y; 9522 status=XMakeImage(display,resource_info,&windows->pan,image, 9523 windows->pan.width,windows->pan.height); 9524 if (status == MagickFalse) 9525 ThrowXWindowFatalException(XServerError,image->exception.reason, 9526 image->exception.description); 9527 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9528 windows->pan.pixmap); 9529 (void) XClearWindow(display,windows->pan.id); 9530 XDrawPanRectangle(display,windows); 9531 XSetCursorState(display,windows,MagickFalse); 9532} 9533 9534/* 9535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9536% % 9537% % 9538% % 9539+ X M a t t a E d i t I m a g e % 9540% % 9541% % 9542% % 9543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9544% 9545% XMatteEditImage() allows the user to interactively change the Matte channel 9546% of an image. If the image is PseudoClass it is promoted to DirectClass 9547% before the matte information is stored. 9548% 9549% The format of the XMatteEditImage method is: 9550% 9551% MagickBooleanType XMatteEditImage(Display *display, 9552% XResourceInfo *resource_info,XWindows *windows,Image **image) 9553% 9554% A description of each parameter follows: 9555% 9556% o display: Specifies a connection to an X server; returned from 9557% XOpenDisplay. 9558% 9559% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9560% 9561% o windows: Specifies a pointer to a XWindows structure. 9562% 9563% o image: the image; returned from ReadImage. 9564% 9565*/ 9566static MagickBooleanType XMatteEditImage(Display *display, 9567 XResourceInfo *resource_info,XWindows *windows,Image **image) 9568{ 9569 static char 9570 matte[MaxTextExtent] = "0"; 9571 9572 static const char 9573 *MatteEditMenu[] = 9574 { 9575 "Method", 9576 "Border Color", 9577 "Fuzz", 9578 "Matte Value", 9579 "Undo", 9580 "Help", 9581 "Dismiss", 9582 (char *) NULL 9583 }; 9584 9585 static const ModeType 9586 MatteEditCommands[] = 9587 { 9588 MatteEditMethod, 9589 MatteEditBorderCommand, 9590 MatteEditFuzzCommand, 9591 MatteEditValueCommand, 9592 MatteEditUndoCommand, 9593 MatteEditHelpCommand, 9594 MatteEditDismissCommand 9595 }; 9596 9597 static PaintMethod 9598 method = PointMethod; 9599 9600 static XColor 9601 border_color = { 0, 0, 0, 0, 0, 0 }; 9602 9603 char 9604 command[MaxTextExtent], 9605 text[MaxTextExtent]; 9606 9607 Cursor 9608 cursor; 9609 9610 int 9611 entry, 9612 id, 9613 x, 9614 x_offset, 9615 y, 9616 y_offset; 9617 9618 register int 9619 i; 9620 9621 register Quantum 9622 *q; 9623 9624 unsigned int 9625 height, 9626 width; 9627 9628 size_t 9629 state; 9630 9631 XEvent 9632 event; 9633 9634 /* 9635 Map Command widget. 9636 */ 9637 (void) CloneString(&windows->command.name,"Matte Edit"); 9638 windows->command.data=4; 9639 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9640 (void) XMapRaised(display,windows->command.id); 9641 XClientMessage(display,windows->image.id,windows->im_protocols, 9642 windows->im_update_widget,CurrentTime); 9643 /* 9644 Make cursor. 9645 */ 9646 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9647 resource_info->background_color,resource_info->foreground_color); 9648 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9649 /* 9650 Track pointer until button 1 is pressed. 9651 */ 9652 XQueryPosition(display,windows->image.id,&x,&y); 9653 (void) XSelectInput(display,windows->image.id, 9654 windows->image.attributes.event_mask | PointerMotionMask); 9655 state=DefaultState; 9656 do 9657 { 9658 if (windows->info.mapped != MagickFalse) 9659 { 9660 /* 9661 Display pointer position. 9662 */ 9663 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9664 x+windows->image.x,y+windows->image.y); 9665 XInfoWidget(display,windows,text); 9666 } 9667 /* 9668 Wait for next event. 9669 */ 9670 XScreenEvent(display,windows,&event); 9671 if (event.xany.window == windows->command.id) 9672 { 9673 /* 9674 Select a command from the Command widget. 9675 */ 9676 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9677 if (id < 0) 9678 { 9679 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9680 continue; 9681 } 9682 switch (MatteEditCommands[id]) 9683 { 9684 case MatteEditMethod: 9685 { 9686 char 9687 **methods; 9688 9689 /* 9690 Select a method from the pop-up menu. 9691 */ 9692 methods=GetCommandOptions(MagickMethodOptions); 9693 if (methods == (char **) NULL) 9694 break; 9695 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9696 (const char **) methods,command); 9697 if (entry >= 0) 9698 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9699 MagickFalse,methods[entry]); 9700 methods=DestroyStringList(methods); 9701 break; 9702 } 9703 case MatteEditBorderCommand: 9704 { 9705 const char 9706 *ColorMenu[MaxNumberPens]; 9707 9708 int 9709 pen_number; 9710 9711 /* 9712 Initialize menu selections. 9713 */ 9714 for (i=0; i < (int) (MaxNumberPens-2); i++) 9715 ColorMenu[i]=resource_info->pen_colors[i]; 9716 ColorMenu[MaxNumberPens-2]="Browser..."; 9717 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9718 /* 9719 Select a pen color from the pop-up menu. 9720 */ 9721 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9722 (const char **) ColorMenu,command); 9723 if (pen_number < 0) 9724 break; 9725 if (pen_number == (MaxNumberPens-2)) 9726 { 9727 static char 9728 color_name[MaxTextExtent] = "gray"; 9729 9730 /* 9731 Select a pen color from a dialog. 9732 */ 9733 resource_info->pen_colors[pen_number]=color_name; 9734 XColorBrowserWidget(display,windows,"Select",color_name); 9735 if (*color_name == '\0') 9736 break; 9737 } 9738 /* 9739 Set border color. 9740 */ 9741 (void) XParseColor(display,windows->map_info->colormap, 9742 resource_info->pen_colors[pen_number],&border_color); 9743 break; 9744 } 9745 case MatteEditFuzzCommand: 9746 { 9747 static char 9748 fuzz[MaxTextExtent]; 9749 9750 static const char 9751 *FuzzMenu[] = 9752 { 9753 "0%", 9754 "2%", 9755 "5%", 9756 "10%", 9757 "15%", 9758 "Dialog...", 9759 (char *) NULL, 9760 }; 9761 9762 /* 9763 Select a command from the pop-up menu. 9764 */ 9765 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9766 command); 9767 if (entry < 0) 9768 break; 9769 if (entry != 5) 9770 { 9771 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 9772 QuantumRange+1.0); 9773 break; 9774 } 9775 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9776 (void) XDialogWidget(display,windows,"Ok", 9777 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9778 if (*fuzz == '\0') 9779 break; 9780 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9781 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 9782 break; 9783 } 9784 case MatteEditValueCommand: 9785 { 9786 static char 9787 message[MaxTextExtent]; 9788 9789 static const char 9790 *MatteMenu[] = 9791 { 9792 "Opaque", 9793 "Transparent", 9794 "Dialog...", 9795 (char *) NULL, 9796 }; 9797 9798 /* 9799 Select a command from the pop-up menu. 9800 */ 9801 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9802 command); 9803 if (entry < 0) 9804 break; 9805 if (entry != 2) 9806 { 9807 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9808 OpaqueAlpha); 9809 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9810 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9811 (Quantum) TransparentAlpha); 9812 break; 9813 } 9814 (void) FormatLocaleString(message,MaxTextExtent, 9815 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9816 QuantumRange); 9817 (void) XDialogWidget(display,windows,"Matte",message,matte); 9818 if (*matte == '\0') 9819 break; 9820 break; 9821 } 9822 case MatteEditUndoCommand: 9823 { 9824 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9825 image); 9826 break; 9827 } 9828 case MatteEditHelpCommand: 9829 { 9830 XTextViewWidget(display,resource_info,windows,MagickFalse, 9831 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9832 break; 9833 } 9834 case MatteEditDismissCommand: 9835 { 9836 /* 9837 Prematurely exit. 9838 */ 9839 state|=EscapeState; 9840 state|=ExitState; 9841 break; 9842 } 9843 default: 9844 break; 9845 } 9846 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9847 continue; 9848 } 9849 switch (event.type) 9850 { 9851 case ButtonPress: 9852 { 9853 if (event.xbutton.button != Button1) 9854 break; 9855 if ((event.xbutton.window != windows->image.id) && 9856 (event.xbutton.window != windows->magnify.id)) 9857 break; 9858 /* 9859 Update matte data. 9860 */ 9861 x=event.xbutton.x; 9862 y=event.xbutton.y; 9863 (void) XMagickCommand(display,resource_info,windows, 9864 SaveToUndoBufferCommand,image); 9865 state|=UpdateConfigurationState; 9866 break; 9867 } 9868 case ButtonRelease: 9869 { 9870 if (event.xbutton.button != Button1) 9871 break; 9872 if ((event.xbutton.window != windows->image.id) && 9873 (event.xbutton.window != windows->magnify.id)) 9874 break; 9875 /* 9876 Update colormap information. 9877 */ 9878 x=event.xbutton.x; 9879 y=event.xbutton.y; 9880 XConfigureImageColormap(display,resource_info,windows,*image); 9881 (void) XConfigureImage(display,resource_info,windows,*image); 9882 XInfoWidget(display,windows,text); 9883 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9884 state&=(~UpdateConfigurationState); 9885 break; 9886 } 9887 case Expose: 9888 break; 9889 case KeyPress: 9890 { 9891 char 9892 command[MaxTextExtent]; 9893 9894 KeySym 9895 key_symbol; 9896 9897 if (event.xkey.window == windows->magnify.id) 9898 { 9899 Window 9900 window; 9901 9902 window=windows->magnify.id; 9903 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9904 } 9905 if (event.xkey.window != windows->image.id) 9906 break; 9907 /* 9908 Respond to a user key press. 9909 */ 9910 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9911 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9912 switch ((int) key_symbol) 9913 { 9914 case XK_Escape: 9915 case XK_F20: 9916 { 9917 /* 9918 Prematurely exit. 9919 */ 9920 state|=ExitState; 9921 break; 9922 } 9923 case XK_F1: 9924 case XK_Help: 9925 { 9926 XTextViewWidget(display,resource_info,windows,MagickFalse, 9927 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9928 break; 9929 } 9930 default: 9931 { 9932 (void) XBell(display,0); 9933 break; 9934 } 9935 } 9936 break; 9937 } 9938 case MotionNotify: 9939 { 9940 /* 9941 Map and unmap Info widget as cursor crosses its boundaries. 9942 */ 9943 x=event.xmotion.x; 9944 y=event.xmotion.y; 9945 if (windows->info.mapped != MagickFalse) 9946 { 9947 if ((x < (int) (windows->info.x+windows->info.width)) && 9948 (y < (int) (windows->info.y+windows->info.height))) 9949 (void) XWithdrawWindow(display,windows->info.id, 9950 windows->info.screen); 9951 } 9952 else 9953 if ((x > (int) (windows->info.x+windows->info.width)) || 9954 (y > (int) (windows->info.y+windows->info.height))) 9955 (void) XMapWindow(display,windows->info.id); 9956 break; 9957 } 9958 default: 9959 break; 9960 } 9961 if (event.xany.window == windows->magnify.id) 9962 { 9963 x=windows->magnify.x-windows->image.x; 9964 y=windows->magnify.y-windows->image.y; 9965 } 9966 x_offset=x; 9967 y_offset=y; 9968 if ((state & UpdateConfigurationState) != 0) 9969 { 9970 CacheView 9971 *image_view; 9972 9973 ExceptionInfo 9974 *exception; 9975 9976 int 9977 x, 9978 y; 9979 9980 /* 9981 Matte edit is relative to image configuration. 9982 */ 9983 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 9984 MagickTrue); 9985 XPutPixel(windows->image.ximage,x_offset,y_offset, 9986 windows->pixel_info->background_color.pixel); 9987 width=(unsigned int) (*image)->columns; 9988 height=(unsigned int) (*image)->rows; 9989 x=0; 9990 y=0; 9991 if (windows->image.crop_geometry != (char *) NULL) 9992 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 9993 &height); 9994 x_offset=(int) (width*(windows->image.x+x_offset)/ 9995 windows->image.ximage->width+x); 9996 y_offset=(int) (height*(windows->image.y+y_offset)/ 9997 windows->image.ximage->height+y); 9998 if ((x_offset < 0) || (y_offset < 0)) 9999 continue; 10000 if ((x_offset >= (int) (*image)->columns) || 10001 (y_offset >= (int) (*image)->rows)) 10002 continue; 10003 exception=(&(*image)->exception); 10004 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10005 return(MagickFalse); 10006 (*image)->matte=MagickTrue; 10007 image_view=AcquireCacheView(*image); 10008 switch (method) 10009 { 10010 case PointMethod: 10011 default: 10012 { 10013 /* 10014 Update matte information using point algorithm. 10015 */ 10016 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10017 (ssize_t) y_offset,1,1,exception); 10018 if (q == (Quantum *) NULL) 10019 break; 10020 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10021 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10022 break; 10023 } 10024 case ReplaceMethod: 10025 { 10026 PixelPacket 10027 pixel, 10028 target; 10029 10030 /* 10031 Update matte information using replace algorithm. 10032 */ 10033 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10034 (ssize_t) y_offset,&target,exception); 10035 for (y=0; y < (int) (*image)->rows; y++) 10036 { 10037 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10038 (*image)->columns,1,&(*image)->exception); 10039 if (q == (Quantum *) NULL) 10040 break; 10041 for (x=0; x < (int) (*image)->columns; x++) 10042 { 10043 GetPixelPacket(*image,q,&pixel); 10044 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 10045 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10046 q+=GetPixelChannels(*image); 10047 } 10048 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10049 break; 10050 } 10051 break; 10052 } 10053 case FloodfillMethod: 10054 case FillToBorderMethod: 10055 { 10056 DrawInfo 10057 *draw_info; 10058 10059 PixelInfo 10060 target; 10061 10062 /* 10063 Update matte information using floodfill algorithm. 10064 */ 10065 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10066 (ssize_t) y_offset,&target,exception); 10067 if (method == FillToBorderMethod) 10068 { 10069 target.red=(MagickRealType) ScaleShortToQuantum( 10070 border_color.red); 10071 target.green=(MagickRealType) ScaleShortToQuantum( 10072 border_color.green); 10073 target.blue=(MagickRealType) ScaleShortToQuantum( 10074 border_color.blue); 10075 } 10076 draw_info=CloneDrawInfo(resource_info->image_info, 10077 (DrawInfo *) NULL); 10078 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10079 (char **) NULL)); 10080 PushPixelChannelMap(*image,AlphaChannel); 10081 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10082 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10083 MagickFalse : MagickTrue); 10084 PopPixelChannelMap(*image); 10085 draw_info=DestroyDrawInfo(draw_info); 10086 break; 10087 } 10088 case ResetMethod: 10089 { 10090 /* 10091 Update matte information using reset algorithm. 10092 */ 10093 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10094 return(MagickFalse); 10095 for (y=0; y < (int) (*image)->rows; y++) 10096 { 10097 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10098 (*image)->columns,1,exception); 10099 if (q == (Quantum *) NULL) 10100 break; 10101 for (x=0; x < (int) (*image)->columns; x++) 10102 { 10103 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10104 q+=GetPixelChannels(*image); 10105 } 10106 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10107 break; 10108 } 10109 if (StringToLong(matte) == (long) OpaqueAlpha) 10110 (*image)->matte=MagickFalse; 10111 break; 10112 } 10113 } 10114 image_view=DestroyCacheView(image_view); 10115 state&=(~UpdateConfigurationState); 10116 } 10117 } while ((state & ExitState) == 0); 10118 (void) XSelectInput(display,windows->image.id, 10119 windows->image.attributes.event_mask); 10120 XSetCursorState(display,windows,MagickFalse); 10121 (void) XFreeCursor(display,cursor); 10122 return(MagickTrue); 10123} 10124 10125/* 10126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10127% % 10128% % 10129% % 10130+ X O p e n I m a g e % 10131% % 10132% % 10133% % 10134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10135% 10136% XOpenImage() loads an image from a file. 10137% 10138% The format of the XOpenImage method is: 10139% 10140% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10141% XWindows *windows,const unsigned int command) 10142% 10143% A description of each parameter follows: 10144% 10145% o display: Specifies a connection to an X server; returned from 10146% XOpenDisplay. 10147% 10148% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10149% 10150% o windows: Specifies a pointer to a XWindows structure. 10151% 10152% o command: A value other than zero indicates that the file is selected 10153% from the command line argument list. 10154% 10155*/ 10156static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10157 XWindows *windows,const MagickBooleanType command) 10158{ 10159 const MagickInfo 10160 *magick_info; 10161 10162 ExceptionInfo 10163 *exception; 10164 10165 Image 10166 *nexus; 10167 10168 ImageInfo 10169 *image_info; 10170 10171 static char 10172 filename[MaxTextExtent] = "\0"; 10173 10174 /* 10175 Request file name from user. 10176 */ 10177 if (command == MagickFalse) 10178 XFileBrowserWidget(display,windows,"Open",filename); 10179 else 10180 { 10181 char 10182 **filelist, 10183 **files; 10184 10185 int 10186 count, 10187 status; 10188 10189 register int 10190 i, 10191 j; 10192 10193 /* 10194 Select next image from the command line. 10195 */ 10196 status=XGetCommand(display,windows->image.id,&files,&count); 10197 if (status == 0) 10198 { 10199 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10200 return((Image *) NULL); 10201 } 10202 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10203 if (filelist == (char **) NULL) 10204 { 10205 ThrowXWindowFatalException(ResourceLimitError, 10206 "MemoryAllocationFailed","..."); 10207 (void) XFreeStringList(files); 10208 return((Image *) NULL); 10209 } 10210 j=0; 10211 for (i=1; i < count; i++) 10212 if (*files[i] != '-') 10213 filelist[j++]=files[i]; 10214 filelist[j]=(char *) NULL; 10215 XListBrowserWidget(display,windows,&windows->widget, 10216 (const char **) filelist,"Load","Select Image to Load:",filename); 10217 filelist=(char **) RelinquishMagickMemory(filelist); 10218 (void) XFreeStringList(files); 10219 } 10220 if (*filename == '\0') 10221 return((Image *) NULL); 10222 image_info=CloneImageInfo(resource_info->image_info); 10223 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10224 (void *) NULL); 10225 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10226 exception=AcquireExceptionInfo(); 10227 (void) SetImageInfo(image_info,0,exception); 10228 if (LocaleCompare(image_info->magick,"X") == 0) 10229 { 10230 char 10231 seconds[MaxTextExtent]; 10232 10233 /* 10234 User may want to delay the X server screen grab. 10235 */ 10236 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10237 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10238 seconds); 10239 if (*seconds == '\0') 10240 return((Image *) NULL); 10241 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10242 } 10243 magick_info=GetMagickInfo(image_info->magick,exception); 10244 if ((magick_info != (const MagickInfo *) NULL) && 10245 (magick_info->raw != MagickFalse)) 10246 { 10247 char 10248 geometry[MaxTextExtent]; 10249 10250 /* 10251 Request image size from the user. 10252 */ 10253 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10254 if (image_info->size != (char *) NULL) 10255 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10256 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10257 geometry); 10258 (void) CloneString(&image_info->size,geometry); 10259 } 10260 /* 10261 Load the image. 10262 */ 10263 XSetCursorState(display,windows,MagickTrue); 10264 XCheckRefreshWindows(display,windows); 10265 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10266 nexus=ReadImage(image_info,exception); 10267 CatchException(exception); 10268 XSetCursorState(display,windows,MagickFalse); 10269 if (nexus != (Image *) NULL) 10270 XClientMessage(display,windows->image.id,windows->im_protocols, 10271 windows->im_next_image,CurrentTime); 10272 else 10273 { 10274 char 10275 *text, 10276 **textlist; 10277 10278 /* 10279 Unknown image format. 10280 */ 10281 text=FileToString(filename,~0,exception); 10282 if (text == (char *) NULL) 10283 return((Image *) NULL); 10284 textlist=StringToList(text); 10285 if (textlist != (char **) NULL) 10286 { 10287 char 10288 title[MaxTextExtent]; 10289 10290 register int 10291 i; 10292 10293 (void) FormatLocaleString(title,MaxTextExtent, 10294 "Unknown format: %s",filename); 10295 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10296 (const char **) textlist); 10297 for (i=0; textlist[i] != (char *) NULL; i++) 10298 textlist[i]=DestroyString(textlist[i]); 10299 textlist=(char **) RelinquishMagickMemory(textlist); 10300 } 10301 text=DestroyString(text); 10302 } 10303 exception=DestroyExceptionInfo(exception); 10304 image_info=DestroyImageInfo(image_info); 10305 return(nexus); 10306} 10307 10308/* 10309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10310% % 10311% % 10312% % 10313+ X P a n I m a g e % 10314% % 10315% % 10316% % 10317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10318% 10319% XPanImage() pans the image until the mouse button is released. 10320% 10321% The format of the XPanImage method is: 10322% 10323% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10324% 10325% A description of each parameter follows: 10326% 10327% o display: Specifies a connection to an X server; returned from 10328% XOpenDisplay. 10329% 10330% o windows: Specifies a pointer to a XWindows structure. 10331% 10332% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10333% the entire image is refreshed. 10334% 10335*/ 10336static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10337{ 10338 char 10339 text[MaxTextExtent]; 10340 10341 Cursor 10342 cursor; 10343 10344 MagickRealType 10345 x_factor, 10346 y_factor; 10347 10348 RectangleInfo 10349 pan_info; 10350 10351 size_t 10352 state; 10353 10354 /* 10355 Define cursor. 10356 */ 10357 if ((windows->image.ximage->width > (int) windows->image.width) && 10358 (windows->image.ximage->height > (int) windows->image.height)) 10359 cursor=XCreateFontCursor(display,XC_fleur); 10360 else 10361 if (windows->image.ximage->width > (int) windows->image.width) 10362 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10363 else 10364 if (windows->image.ximage->height > (int) windows->image.height) 10365 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10366 else 10367 cursor=XCreateFontCursor(display,XC_arrow); 10368 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10369 /* 10370 Pan image as pointer moves until the mouse button is released. 10371 */ 10372 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10373 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10374 pan_info.width=windows->pan.width*windows->image.width/ 10375 windows->image.ximage->width; 10376 pan_info.height=windows->pan.height*windows->image.height/ 10377 windows->image.ximage->height; 10378 pan_info.x=0; 10379 pan_info.y=0; 10380 state=UpdateConfigurationState; 10381 do 10382 { 10383 switch (event->type) 10384 { 10385 case ButtonPress: 10386 { 10387 /* 10388 User choose an initial pan location. 10389 */ 10390 pan_info.x=(ssize_t) event->xbutton.x; 10391 pan_info.y=(ssize_t) event->xbutton.y; 10392 state|=UpdateConfigurationState; 10393 break; 10394 } 10395 case ButtonRelease: 10396 { 10397 /* 10398 User has finished panning the image. 10399 */ 10400 pan_info.x=(ssize_t) event->xbutton.x; 10401 pan_info.y=(ssize_t) event->xbutton.y; 10402 state|=UpdateConfigurationState | ExitState; 10403 break; 10404 } 10405 case MotionNotify: 10406 { 10407 pan_info.x=(ssize_t) event->xmotion.x; 10408 pan_info.y=(ssize_t) event->xmotion.y; 10409 state|=UpdateConfigurationState; 10410 } 10411 default: 10412 break; 10413 } 10414 if ((state & UpdateConfigurationState) != 0) 10415 { 10416 /* 10417 Check boundary conditions. 10418 */ 10419 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10420 pan_info.x=0; 10421 else 10422 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10423 if (pan_info.x < 0) 10424 pan_info.x=0; 10425 else 10426 if ((int) (pan_info.x+windows->image.width) > 10427 windows->image.ximage->width) 10428 pan_info.x=(ssize_t) 10429 (windows->image.ximage->width-windows->image.width); 10430 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10431 pan_info.y=0; 10432 else 10433 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10434 if (pan_info.y < 0) 10435 pan_info.y=0; 10436 else 10437 if ((int) (pan_info.y+windows->image.height) > 10438 windows->image.ximage->height) 10439 pan_info.y=(ssize_t) 10440 (windows->image.ximage->height-windows->image.height); 10441 if ((windows->image.x != (int) pan_info.x) || 10442 (windows->image.y != (int) pan_info.y)) 10443 { 10444 /* 10445 Display image pan offset. 10446 */ 10447 windows->image.x=(int) pan_info.x; 10448 windows->image.y=(int) pan_info.y; 10449 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10450 windows->image.width,windows->image.height,windows->image.x, 10451 windows->image.y); 10452 XInfoWidget(display,windows,text); 10453 /* 10454 Refresh Image window. 10455 */ 10456 XDrawPanRectangle(display,windows); 10457 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10458 } 10459 state&=(~UpdateConfigurationState); 10460 } 10461 /* 10462 Wait for next event. 10463 */ 10464 if ((state & ExitState) == 0) 10465 XScreenEvent(display,windows,event); 10466 } while ((state & ExitState) == 0); 10467 /* 10468 Restore cursor. 10469 */ 10470 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10471 (void) XFreeCursor(display,cursor); 10472 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10473} 10474 10475/* 10476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10477% % 10478% % 10479% % 10480+ X P a s t e I m a g e % 10481% % 10482% % 10483% % 10484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10485% 10486% XPasteImage() pastes an image previously saved with XCropImage in the X 10487% window image at a location the user chooses with the pointer. 10488% 10489% The format of the XPasteImage method is: 10490% 10491% MagickBooleanType XPasteImage(Display *display, 10492% XResourceInfo *resource_info,XWindows *windows,Image *image) 10493% 10494% A description of each parameter follows: 10495% 10496% o display: Specifies a connection to an X server; returned from 10497% XOpenDisplay. 10498% 10499% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10500% 10501% o windows: Specifies a pointer to a XWindows structure. 10502% 10503% o image: the image; returned from ReadImage. 10504% 10505*/ 10506static MagickBooleanType XPasteImage(Display *display, 10507 XResourceInfo *resource_info,XWindows *windows,Image *image) 10508{ 10509 static const char 10510 *PasteMenu[] = 10511 { 10512 "Operator", 10513 "Help", 10514 "Dismiss", 10515 (char *) NULL 10516 }; 10517 10518 static const ModeType 10519 PasteCommands[] = 10520 { 10521 PasteOperatorsCommand, 10522 PasteHelpCommand, 10523 PasteDismissCommand 10524 }; 10525 10526 static CompositeOperator 10527 compose = CopyCompositeOp; 10528 10529 char 10530 text[MaxTextExtent]; 10531 10532 Cursor 10533 cursor; 10534 10535 Image 10536 *paste_image; 10537 10538 int 10539 entry, 10540 id, 10541 x, 10542 y; 10543 10544 MagickRealType 10545 scale_factor; 10546 10547 RectangleInfo 10548 highlight_info, 10549 paste_info; 10550 10551 unsigned int 10552 height, 10553 width; 10554 10555 size_t 10556 state; 10557 10558 XEvent 10559 event; 10560 10561 /* 10562 Copy image. 10563 */ 10564 if (resource_info->copy_image == (Image *) NULL) 10565 return(MagickFalse); 10566 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue, 10567 &image->exception); 10568 /* 10569 Map Command widget. 10570 */ 10571 (void) CloneString(&windows->command.name,"Paste"); 10572 windows->command.data=1; 10573 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10574 (void) XMapRaised(display,windows->command.id); 10575 XClientMessage(display,windows->image.id,windows->im_protocols, 10576 windows->im_update_widget,CurrentTime); 10577 /* 10578 Track pointer until button 1 is pressed. 10579 */ 10580 XSetCursorState(display,windows,MagickFalse); 10581 XQueryPosition(display,windows->image.id,&x,&y); 10582 (void) XSelectInput(display,windows->image.id, 10583 windows->image.attributes.event_mask | PointerMotionMask); 10584 paste_info.x=(ssize_t) windows->image.x+x; 10585 paste_info.y=(ssize_t) windows->image.y+y; 10586 paste_info.width=0; 10587 paste_info.height=0; 10588 cursor=XCreateFontCursor(display,XC_ul_angle); 10589 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10590 state=DefaultState; 10591 do 10592 { 10593 if (windows->info.mapped != MagickFalse) 10594 { 10595 /* 10596 Display pointer position. 10597 */ 10598 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10599 (long) paste_info.x,(long) paste_info.y); 10600 XInfoWidget(display,windows,text); 10601 } 10602 highlight_info=paste_info; 10603 highlight_info.x=paste_info.x-windows->image.x; 10604 highlight_info.y=paste_info.y-windows->image.y; 10605 XHighlightRectangle(display,windows->image.id, 10606 windows->image.highlight_context,&highlight_info); 10607 /* 10608 Wait for next event. 10609 */ 10610 XScreenEvent(display,windows,&event); 10611 XHighlightRectangle(display,windows->image.id, 10612 windows->image.highlight_context,&highlight_info); 10613 if (event.xany.window == windows->command.id) 10614 { 10615 /* 10616 Select a command from the Command widget. 10617 */ 10618 id=XCommandWidget(display,windows,PasteMenu,&event); 10619 if (id < 0) 10620 continue; 10621 switch (PasteCommands[id]) 10622 { 10623 case PasteOperatorsCommand: 10624 { 10625 char 10626 command[MaxTextExtent], 10627 **operators; 10628 10629 /* 10630 Select a command from the pop-up menu. 10631 */ 10632 operators=GetCommandOptions(MagickComposeOptions); 10633 if (operators == (char **) NULL) 10634 break; 10635 entry=XMenuWidget(display,windows,PasteMenu[id], 10636 (const char **) operators,command); 10637 if (entry >= 0) 10638 compose=(CompositeOperator) ParseCommandOption( 10639 MagickComposeOptions,MagickFalse,operators[entry]); 10640 operators=DestroyStringList(operators); 10641 break; 10642 } 10643 case PasteHelpCommand: 10644 { 10645 XTextViewWidget(display,resource_info,windows,MagickFalse, 10646 "Help Viewer - Image Composite",ImagePasteHelp); 10647 break; 10648 } 10649 case PasteDismissCommand: 10650 { 10651 /* 10652 Prematurely exit. 10653 */ 10654 state|=EscapeState; 10655 state|=ExitState; 10656 break; 10657 } 10658 default: 10659 break; 10660 } 10661 continue; 10662 } 10663 switch (event.type) 10664 { 10665 case ButtonPress: 10666 { 10667 if (image->debug != MagickFalse) 10668 (void) LogMagickEvent(X11Event,GetMagickModule(), 10669 "Button Press: 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 /* 10676 Paste rectangle is relative to image configuration. 10677 */ 10678 width=(unsigned int) image->columns; 10679 height=(unsigned int) image->rows; 10680 x=0; 10681 y=0; 10682 if (windows->image.crop_geometry != (char *) NULL) 10683 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10684 &width,&height); 10685 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10686 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10687 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10688 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10689 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10690 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10691 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10692 break; 10693 } 10694 case ButtonRelease: 10695 { 10696 if (image->debug != MagickFalse) 10697 (void) LogMagickEvent(X11Event,GetMagickModule(), 10698 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10699 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10700 if (event.xbutton.button != Button1) 10701 break; 10702 if (event.xbutton.window != windows->image.id) 10703 break; 10704 if ((paste_info.width != 0) && (paste_info.height != 0)) 10705 { 10706 /* 10707 User has selected the location of the paste image. 10708 */ 10709 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10710 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10711 state|=ExitState; 10712 } 10713 break; 10714 } 10715 case Expose: 10716 break; 10717 case KeyPress: 10718 { 10719 char 10720 command[MaxTextExtent]; 10721 10722 KeySym 10723 key_symbol; 10724 10725 int 10726 length; 10727 10728 if (event.xkey.window != windows->image.id) 10729 break; 10730 /* 10731 Respond to a user key press. 10732 */ 10733 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10734 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10735 *(command+length)='\0'; 10736 if (image->debug != MagickFalse) 10737 (void) LogMagickEvent(X11Event,GetMagickModule(), 10738 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10739 switch ((int) key_symbol) 10740 { 10741 case XK_Escape: 10742 case XK_F20: 10743 { 10744 /* 10745 Prematurely exit. 10746 */ 10747 paste_image=DestroyImage(paste_image); 10748 state|=EscapeState; 10749 state|=ExitState; 10750 break; 10751 } 10752 case XK_F1: 10753 case XK_Help: 10754 { 10755 (void) XSetFunction(display,windows->image.highlight_context, 10756 GXcopy); 10757 XTextViewWidget(display,resource_info,windows,MagickFalse, 10758 "Help Viewer - Image Composite",ImagePasteHelp); 10759 (void) XSetFunction(display,windows->image.highlight_context, 10760 GXinvert); 10761 break; 10762 } 10763 default: 10764 { 10765 (void) XBell(display,0); 10766 break; 10767 } 10768 } 10769 break; 10770 } 10771 case MotionNotify: 10772 { 10773 /* 10774 Map and unmap Info widget as text cursor crosses its boundaries. 10775 */ 10776 x=event.xmotion.x; 10777 y=event.xmotion.y; 10778 if (windows->info.mapped != MagickFalse) 10779 { 10780 if ((x < (int) (windows->info.x+windows->info.width)) && 10781 (y < (int) (windows->info.y+windows->info.height))) 10782 (void) XWithdrawWindow(display,windows->info.id, 10783 windows->info.screen); 10784 } 10785 else 10786 if ((x > (int) (windows->info.x+windows->info.width)) || 10787 (y > (int) (windows->info.y+windows->info.height))) 10788 (void) XMapWindow(display,windows->info.id); 10789 paste_info.x=(ssize_t) windows->image.x+x; 10790 paste_info.y=(ssize_t) windows->image.y+y; 10791 break; 10792 } 10793 default: 10794 { 10795 if (image->debug != MagickFalse) 10796 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10797 event.type); 10798 break; 10799 } 10800 } 10801 } while ((state & ExitState) == 0); 10802 (void) XSelectInput(display,windows->image.id, 10803 windows->image.attributes.event_mask); 10804 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10805 XSetCursorState(display,windows,MagickFalse); 10806 (void) XFreeCursor(display,cursor); 10807 if ((state & EscapeState) != 0) 10808 return(MagickTrue); 10809 /* 10810 Image pasting is relative to image configuration. 10811 */ 10812 XSetCursorState(display,windows,MagickTrue); 10813 XCheckRefreshWindows(display,windows); 10814 width=(unsigned int) image->columns; 10815 height=(unsigned int) image->rows; 10816 x=0; 10817 y=0; 10818 if (windows->image.crop_geometry != (char *) NULL) 10819 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10820 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10821 paste_info.x+=x; 10822 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10823 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10824 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10825 paste_info.y+=y; 10826 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10827 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10828 /* 10829 Paste image with X Image window. 10830 */ 10831 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y); 10832 paste_image=DestroyImage(paste_image); 10833 XSetCursorState(display,windows,MagickFalse); 10834 /* 10835 Update image colormap. 10836 */ 10837 XConfigureImageColormap(display,resource_info,windows,image); 10838 (void) XConfigureImage(display,resource_info,windows,image); 10839 return(MagickTrue); 10840} 10841 10842/* 10843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10844% % 10845% % 10846% % 10847+ X P r i n t I m a g e % 10848% % 10849% % 10850% % 10851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10852% 10853% XPrintImage() prints an image to a Postscript printer. 10854% 10855% The format of the XPrintImage method is: 10856% 10857% MagickBooleanType XPrintImage(Display *display, 10858% XResourceInfo *resource_info,XWindows *windows,Image *image) 10859% 10860% A description of each parameter follows: 10861% 10862% o display: Specifies a connection to an X server; returned from 10863% XOpenDisplay. 10864% 10865% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10866% 10867% o windows: Specifies a pointer to a XWindows structure. 10868% 10869% o image: the image. 10870% 10871*/ 10872static MagickBooleanType XPrintImage(Display *display, 10873 XResourceInfo *resource_info,XWindows *windows,Image *image) 10874{ 10875 char 10876 filename[MaxTextExtent], 10877 geometry[MaxTextExtent]; 10878 10879 Image 10880 *print_image; 10881 10882 ImageInfo 10883 *image_info; 10884 10885 MagickStatusType 10886 status; 10887 10888 /* 10889 Request Postscript page geometry from user. 10890 */ 10891 image_info=CloneImageInfo(resource_info->image_info); 10892 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10893 if (image_info->page != (char *) NULL) 10894 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10895 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10896 "Select Postscript Page Geometry:",geometry); 10897 if (*geometry == '\0') 10898 return(MagickTrue); 10899 image_info->page=GetPageGeometry(geometry); 10900 /* 10901 Apply image transforms. 10902 */ 10903 XSetCursorState(display,windows,MagickTrue); 10904 XCheckRefreshWindows(display,windows); 10905 print_image=CloneImage(image,0,0,MagickTrue,&image->exception); 10906 if (print_image == (Image *) NULL) 10907 return(MagickFalse); 10908 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 10909 windows->image.ximage->width,windows->image.ximage->height); 10910 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry); 10911 /* 10912 Print image. 10913 */ 10914 (void) AcquireUniqueFilename(filename); 10915 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 10916 filename); 10917 status=WriteImage(image_info,print_image); 10918 (void) RelinquishUniqueFileResource(filename); 10919 print_image=DestroyImage(print_image); 10920 image_info=DestroyImageInfo(image_info); 10921 XSetCursorState(display,windows,MagickFalse); 10922 return(status != 0 ? MagickTrue : MagickFalse); 10923} 10924 10925/* 10926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10927% % 10928% % 10929% % 10930+ X R O I I m a g e % 10931% % 10932% % 10933% % 10934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10935% 10936% XROIImage() applies an image processing technique to a region of interest. 10937% 10938% The format of the XROIImage method is: 10939% 10940% MagickBooleanType XROIImage(Display *display, 10941% XResourceInfo *resource_info,XWindows *windows,Image **image) 10942% 10943% A description of each parameter follows: 10944% 10945% o display: Specifies a connection to an X server; returned from 10946% XOpenDisplay. 10947% 10948% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10949% 10950% o windows: Specifies a pointer to a XWindows structure. 10951% 10952% o image: the image; returned from ReadImage. 10953% 10954*/ 10955static MagickBooleanType XROIImage(Display *display, 10956 XResourceInfo *resource_info,XWindows *windows,Image **image) 10957{ 10958#define ApplyMenus 7 10959 10960 static const char 10961 *ROIMenu[] = 10962 { 10963 "Help", 10964 "Dismiss", 10965 (char *) NULL 10966 }, 10967 *ApplyMenu[] = 10968 { 10969 "File", 10970 "Edit", 10971 "Transform", 10972 "Enhance", 10973 "Effects", 10974 "F/X", 10975 "Miscellany", 10976 "Help", 10977 "Dismiss", 10978 (char *) NULL 10979 }, 10980 *FileMenu[] = 10981 { 10982 "Save...", 10983 "Print...", 10984 (char *) NULL 10985 }, 10986 *EditMenu[] = 10987 { 10988 "Undo", 10989 "Redo", 10990 (char *) NULL 10991 }, 10992 *TransformMenu[] = 10993 { 10994 "Flop", 10995 "Flip", 10996 "Rotate Right", 10997 "Rotate Left", 10998 (char *) NULL 10999 }, 11000 *EnhanceMenu[] = 11001 { 11002 "Hue...", 11003 "Saturation...", 11004 "Brightness...", 11005 "Gamma...", 11006 "Spiff", 11007 "Dull", 11008 "Contrast Stretch...", 11009 "Sigmoidal Contrast...", 11010 "Normalize", 11011 "Equalize", 11012 "Negate", 11013 "Grayscale", 11014 "Map...", 11015 "Quantize...", 11016 (char *) NULL 11017 }, 11018 *EffectsMenu[] = 11019 { 11020 "Despeckle", 11021 "Emboss", 11022 "Reduce Noise", 11023 "Add Noise", 11024 "Sharpen...", 11025 "Blur...", 11026 "Threshold...", 11027 "Edge Detect...", 11028 "Spread...", 11029 "Shade...", 11030 "Raise...", 11031 "Segment...", 11032 (char *) NULL 11033 }, 11034 *FXMenu[] = 11035 { 11036 "Solarize...", 11037 "Sepia Tone...", 11038 "Swirl...", 11039 "Implode...", 11040 "Vignette...", 11041 "Wave...", 11042 "Oil Paint...", 11043 "Charcoal Draw...", 11044 (char *) NULL 11045 }, 11046 *MiscellanyMenu[] = 11047 { 11048 "Image Info", 11049 "Zoom Image", 11050 "Show Preview...", 11051 "Show Histogram", 11052 "Show Matte", 11053 (char *) NULL 11054 }; 11055 11056 static const char 11057 **Menus[ApplyMenus] = 11058 { 11059 FileMenu, 11060 EditMenu, 11061 TransformMenu, 11062 EnhanceMenu, 11063 EffectsMenu, 11064 FXMenu, 11065 MiscellanyMenu 11066 }; 11067 11068 static const CommandType 11069 ApplyCommands[] = 11070 { 11071 NullCommand, 11072 NullCommand, 11073 NullCommand, 11074 NullCommand, 11075 NullCommand, 11076 NullCommand, 11077 NullCommand, 11078 HelpCommand, 11079 QuitCommand 11080 }, 11081 FileCommands[] = 11082 { 11083 SaveCommand, 11084 PrintCommand 11085 }, 11086 EditCommands[] = 11087 { 11088 UndoCommand, 11089 RedoCommand 11090 }, 11091 TransformCommands[] = 11092 { 11093 FlopCommand, 11094 FlipCommand, 11095 RotateRightCommand, 11096 RotateLeftCommand 11097 }, 11098 EnhanceCommands[] = 11099 { 11100 HueCommand, 11101 SaturationCommand, 11102 BrightnessCommand, 11103 GammaCommand, 11104 SpiffCommand, 11105 DullCommand, 11106 ContrastStretchCommand, 11107 SigmoidalContrastCommand, 11108 NormalizeCommand, 11109 EqualizeCommand, 11110 NegateCommand, 11111 GrayscaleCommand, 11112 MapCommand, 11113 QuantizeCommand 11114 }, 11115 EffectsCommands[] = 11116 { 11117 DespeckleCommand, 11118 EmbossCommand, 11119 ReduceNoiseCommand, 11120 AddNoiseCommand, 11121 SharpenCommand, 11122 BlurCommand, 11123 EdgeDetectCommand, 11124 SpreadCommand, 11125 ShadeCommand, 11126 RaiseCommand, 11127 SegmentCommand 11128 }, 11129 FXCommands[] = 11130 { 11131 SolarizeCommand, 11132 SepiaToneCommand, 11133 SwirlCommand, 11134 ImplodeCommand, 11135 VignetteCommand, 11136 WaveCommand, 11137 OilPaintCommand, 11138 CharcoalDrawCommand 11139 }, 11140 MiscellanyCommands[] = 11141 { 11142 InfoCommand, 11143 ZoomCommand, 11144 ShowPreviewCommand, 11145 ShowHistogramCommand, 11146 ShowMatteCommand 11147 }, 11148 ROICommands[] = 11149 { 11150 ROIHelpCommand, 11151 ROIDismissCommand 11152 }; 11153 11154 static const CommandType 11155 *Commands[ApplyMenus] = 11156 { 11157 FileCommands, 11158 EditCommands, 11159 TransformCommands, 11160 EnhanceCommands, 11161 EffectsCommands, 11162 FXCommands, 11163 MiscellanyCommands 11164 }; 11165 11166 char 11167 command[MaxTextExtent], 11168 text[MaxTextExtent]; 11169 11170 CommandType 11171 command_type; 11172 11173 Cursor 11174 cursor; 11175 11176 Image 11177 *roi_image; 11178 11179 int 11180 entry, 11181 id, 11182 x, 11183 y; 11184 11185 MagickRealType 11186 scale_factor; 11187 11188 MagickProgressMonitor 11189 progress_monitor; 11190 11191 RectangleInfo 11192 crop_info, 11193 highlight_info, 11194 roi_info; 11195 11196 unsigned int 11197 height, 11198 width; 11199 11200 size_t 11201 state; 11202 11203 XEvent 11204 event; 11205 11206 /* 11207 Map Command widget. 11208 */ 11209 (void) CloneString(&windows->command.name,"ROI"); 11210 windows->command.data=0; 11211 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11212 (void) XMapRaised(display,windows->command.id); 11213 XClientMessage(display,windows->image.id,windows->im_protocols, 11214 windows->im_update_widget,CurrentTime); 11215 /* 11216 Track pointer until button 1 is pressed. 11217 */ 11218 XQueryPosition(display,windows->image.id,&x,&y); 11219 (void) XSelectInput(display,windows->image.id, 11220 windows->image.attributes.event_mask | PointerMotionMask); 11221 roi_info.x=(ssize_t) windows->image.x+x; 11222 roi_info.y=(ssize_t) windows->image.y+y; 11223 roi_info.width=0; 11224 roi_info.height=0; 11225 cursor=XCreateFontCursor(display,XC_fleur); 11226 state=DefaultState; 11227 do 11228 { 11229 if (windows->info.mapped != MagickFalse) 11230 { 11231 /* 11232 Display pointer position. 11233 */ 11234 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11235 (long) roi_info.x,(long) roi_info.y); 11236 XInfoWidget(display,windows,text); 11237 } 11238 /* 11239 Wait for next event. 11240 */ 11241 XScreenEvent(display,windows,&event); 11242 if (event.xany.window == windows->command.id) 11243 { 11244 /* 11245 Select a command from the Command widget. 11246 */ 11247 id=XCommandWidget(display,windows,ROIMenu,&event); 11248 if (id < 0) 11249 continue; 11250 switch (ROICommands[id]) 11251 { 11252 case ROIHelpCommand: 11253 { 11254 XTextViewWidget(display,resource_info,windows,MagickFalse, 11255 "Help Viewer - Region of Interest",ImageROIHelp); 11256 break; 11257 } 11258 case ROIDismissCommand: 11259 { 11260 /* 11261 Prematurely exit. 11262 */ 11263 state|=EscapeState; 11264 state|=ExitState; 11265 break; 11266 } 11267 default: 11268 break; 11269 } 11270 continue; 11271 } 11272 switch (event.type) 11273 { 11274 case ButtonPress: 11275 { 11276 if (event.xbutton.button != Button1) 11277 break; 11278 if (event.xbutton.window != windows->image.id) 11279 break; 11280 /* 11281 Note first corner of region of interest rectangle-- exit loop. 11282 */ 11283 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11284 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11285 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11286 state|=ExitState; 11287 break; 11288 } 11289 case ButtonRelease: 11290 break; 11291 case Expose: 11292 break; 11293 case KeyPress: 11294 { 11295 KeySym 11296 key_symbol; 11297 11298 if (event.xkey.window != windows->image.id) 11299 break; 11300 /* 11301 Respond to a user key press. 11302 */ 11303 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11304 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11305 switch ((int) key_symbol) 11306 { 11307 case XK_Escape: 11308 case XK_F20: 11309 { 11310 /* 11311 Prematurely exit. 11312 */ 11313 state|=EscapeState; 11314 state|=ExitState; 11315 break; 11316 } 11317 case XK_F1: 11318 case XK_Help: 11319 { 11320 XTextViewWidget(display,resource_info,windows,MagickFalse, 11321 "Help Viewer - Region of Interest",ImageROIHelp); 11322 break; 11323 } 11324 default: 11325 { 11326 (void) XBell(display,0); 11327 break; 11328 } 11329 } 11330 break; 11331 } 11332 case MotionNotify: 11333 { 11334 /* 11335 Map and unmap Info widget as text cursor crosses its boundaries. 11336 */ 11337 x=event.xmotion.x; 11338 y=event.xmotion.y; 11339 if (windows->info.mapped != MagickFalse) 11340 { 11341 if ((x < (int) (windows->info.x+windows->info.width)) && 11342 (y < (int) (windows->info.y+windows->info.height))) 11343 (void) XWithdrawWindow(display,windows->info.id, 11344 windows->info.screen); 11345 } 11346 else 11347 if ((x > (int) (windows->info.x+windows->info.width)) || 11348 (y > (int) (windows->info.y+windows->info.height))) 11349 (void) XMapWindow(display,windows->info.id); 11350 roi_info.x=(ssize_t) windows->image.x+x; 11351 roi_info.y=(ssize_t) windows->image.y+y; 11352 break; 11353 } 11354 default: 11355 break; 11356 } 11357 } while ((state & ExitState) == 0); 11358 (void) XSelectInput(display,windows->image.id, 11359 windows->image.attributes.event_mask); 11360 if ((state & EscapeState) != 0) 11361 { 11362 /* 11363 User want to exit without region of interest. 11364 */ 11365 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11366 (void) XFreeCursor(display,cursor); 11367 return(MagickTrue); 11368 } 11369 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11370 do 11371 { 11372 /* 11373 Size rectangle as pointer moves until the mouse button is released. 11374 */ 11375 x=(int) roi_info.x; 11376 y=(int) roi_info.y; 11377 roi_info.width=0; 11378 roi_info.height=0; 11379 state=DefaultState; 11380 do 11381 { 11382 highlight_info=roi_info; 11383 highlight_info.x=roi_info.x-windows->image.x; 11384 highlight_info.y=roi_info.y-windows->image.y; 11385 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11386 { 11387 /* 11388 Display info and draw region of interest rectangle. 11389 */ 11390 if (windows->info.mapped == MagickFalse) 11391 (void) XMapWindow(display,windows->info.id); 11392 (void) FormatLocaleString(text,MaxTextExtent, 11393 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11394 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11395 XInfoWidget(display,windows,text); 11396 XHighlightRectangle(display,windows->image.id, 11397 windows->image.highlight_context,&highlight_info); 11398 } 11399 else 11400 if (windows->info.mapped != MagickFalse) 11401 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11402 /* 11403 Wait for next event. 11404 */ 11405 XScreenEvent(display,windows,&event); 11406 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11407 XHighlightRectangle(display,windows->image.id, 11408 windows->image.highlight_context,&highlight_info); 11409 switch (event.type) 11410 { 11411 case ButtonPress: 11412 { 11413 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11414 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11415 break; 11416 } 11417 case ButtonRelease: 11418 { 11419 /* 11420 User has committed to region of interest rectangle. 11421 */ 11422 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11423 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11424 XSetCursorState(display,windows,MagickFalse); 11425 state|=ExitState; 11426 if (LocaleCompare(windows->command.name,"Apply") == 0) 11427 break; 11428 (void) CloneString(&windows->command.name,"Apply"); 11429 windows->command.data=ApplyMenus; 11430 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11431 break; 11432 } 11433 case Expose: 11434 break; 11435 case MotionNotify: 11436 { 11437 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11438 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11439 } 11440 default: 11441 break; 11442 } 11443 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11444 ((state & ExitState) != 0)) 11445 { 11446 /* 11447 Check boundary conditions. 11448 */ 11449 if (roi_info.x < 0) 11450 roi_info.x=0; 11451 else 11452 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11453 roi_info.x=(ssize_t) windows->image.ximage->width; 11454 if ((int) roi_info.x < x) 11455 roi_info.width=(unsigned int) (x-roi_info.x); 11456 else 11457 { 11458 roi_info.width=(unsigned int) (roi_info.x-x); 11459 roi_info.x=(ssize_t) x; 11460 } 11461 if (roi_info.y < 0) 11462 roi_info.y=0; 11463 else 11464 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11465 roi_info.y=(ssize_t) windows->image.ximage->height; 11466 if ((int) roi_info.y < y) 11467 roi_info.height=(unsigned int) (y-roi_info.y); 11468 else 11469 { 11470 roi_info.height=(unsigned int) (roi_info.y-y); 11471 roi_info.y=(ssize_t) y; 11472 } 11473 } 11474 } while ((state & ExitState) == 0); 11475 /* 11476 Wait for user to grab a corner of the rectangle or press return. 11477 */ 11478 state=DefaultState; 11479 command_type=NullCommand; 11480 (void) XMapWindow(display,windows->info.id); 11481 do 11482 { 11483 if (windows->info.mapped != MagickFalse) 11484 { 11485 /* 11486 Display pointer position. 11487 */ 11488 (void) FormatLocaleString(text,MaxTextExtent, 11489 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11490 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11491 XInfoWidget(display,windows,text); 11492 } 11493 highlight_info=roi_info; 11494 highlight_info.x=roi_info.x-windows->image.x; 11495 highlight_info.y=roi_info.y-windows->image.y; 11496 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11497 { 11498 state|=EscapeState; 11499 state|=ExitState; 11500 break; 11501 } 11502 if ((state & UpdateRegionState) != 0) 11503 { 11504 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11505 switch (command_type) 11506 { 11507 case UndoCommand: 11508 case RedoCommand: 11509 { 11510 (void) XMagickCommand(display,resource_info,windows,command_type, 11511 image); 11512 break; 11513 } 11514 default: 11515 { 11516 /* 11517 Region of interest is relative to image configuration. 11518 */ 11519 progress_monitor=SetImageProgressMonitor(*image, 11520 (MagickProgressMonitor) NULL,(*image)->client_data); 11521 crop_info=roi_info; 11522 width=(unsigned int) (*image)->columns; 11523 height=(unsigned int) (*image)->rows; 11524 x=0; 11525 y=0; 11526 if (windows->image.crop_geometry != (char *) NULL) 11527 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11528 &width,&height); 11529 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11530 crop_info.x+=x; 11531 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11532 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11533 scale_factor=(MagickRealType) 11534 height/windows->image.ximage->height; 11535 crop_info.y+=y; 11536 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11537 crop_info.height=(unsigned int) 11538 (scale_factor*crop_info.height+0.5); 11539 roi_image=CropImage(*image,&crop_info,&(*image)->exception); 11540 (void) SetImageProgressMonitor(*image,progress_monitor, 11541 (*image)->client_data); 11542 if (roi_image == (Image *) NULL) 11543 continue; 11544 /* 11545 Apply image processing technique to the region of interest. 11546 */ 11547 windows->image.orphan=MagickTrue; 11548 (void) XMagickCommand(display,resource_info,windows,command_type, 11549 &roi_image); 11550 progress_monitor=SetImageProgressMonitor(*image, 11551 (MagickProgressMonitor) NULL,(*image)->client_data); 11552 (void) XMagickCommand(display,resource_info,windows, 11553 SaveToUndoBufferCommand,image); 11554 windows->image.orphan=MagickFalse; 11555 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11556 crop_info.x,crop_info.y); 11557 roi_image=DestroyImage(roi_image); 11558 (void) SetImageProgressMonitor(*image,progress_monitor, 11559 (*image)->client_data); 11560 break; 11561 } 11562 } 11563 if (command_type != InfoCommand) 11564 { 11565 XConfigureImageColormap(display,resource_info,windows,*image); 11566 (void) XConfigureImage(display,resource_info,windows,*image); 11567 } 11568 XCheckRefreshWindows(display,windows); 11569 XInfoWidget(display,windows,text); 11570 (void) XSetFunction(display,windows->image.highlight_context, 11571 GXinvert); 11572 state&=(~UpdateRegionState); 11573 } 11574 XHighlightRectangle(display,windows->image.id, 11575 windows->image.highlight_context,&highlight_info); 11576 XScreenEvent(display,windows,&event); 11577 if (event.xany.window == windows->command.id) 11578 { 11579 /* 11580 Select a command from the Command widget. 11581 */ 11582 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11583 command_type=NullCommand; 11584 id=XCommandWidget(display,windows,ApplyMenu,&event); 11585 if (id >= 0) 11586 { 11587 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11588 command_type=ApplyCommands[id]; 11589 if (id < ApplyMenus) 11590 { 11591 /* 11592 Select a command from a pop-up menu. 11593 */ 11594 entry=XMenuWidget(display,windows,ApplyMenu[id], 11595 (const char **) Menus[id],command); 11596 if (entry >= 0) 11597 { 11598 (void) CopyMagickString(command,Menus[id][entry], 11599 MaxTextExtent); 11600 command_type=Commands[id][entry]; 11601 } 11602 } 11603 } 11604 (void) XSetFunction(display,windows->image.highlight_context, 11605 GXinvert); 11606 XHighlightRectangle(display,windows->image.id, 11607 windows->image.highlight_context,&highlight_info); 11608 if (command_type == HelpCommand) 11609 { 11610 (void) XSetFunction(display,windows->image.highlight_context, 11611 GXcopy); 11612 XTextViewWidget(display,resource_info,windows,MagickFalse, 11613 "Help Viewer - Region of Interest",ImageROIHelp); 11614 (void) XSetFunction(display,windows->image.highlight_context, 11615 GXinvert); 11616 continue; 11617 } 11618 if (command_type == QuitCommand) 11619 { 11620 /* 11621 exit. 11622 */ 11623 state|=EscapeState; 11624 state|=ExitState; 11625 continue; 11626 } 11627 if (command_type != NullCommand) 11628 state|=UpdateRegionState; 11629 continue; 11630 } 11631 XHighlightRectangle(display,windows->image.id, 11632 windows->image.highlight_context,&highlight_info); 11633 switch (event.type) 11634 { 11635 case ButtonPress: 11636 { 11637 x=windows->image.x; 11638 y=windows->image.y; 11639 if (event.xbutton.button != Button1) 11640 break; 11641 if (event.xbutton.window != windows->image.id) 11642 break; 11643 x=windows->image.x+event.xbutton.x; 11644 y=windows->image.y+event.xbutton.y; 11645 if ((x < (int) (roi_info.x+RoiDelta)) && 11646 (x > (int) (roi_info.x-RoiDelta)) && 11647 (y < (int) (roi_info.y+RoiDelta)) && 11648 (y > (int) (roi_info.y-RoiDelta))) 11649 { 11650 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11651 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11652 state|=UpdateConfigurationState; 11653 break; 11654 } 11655 if ((x < (int) (roi_info.x+RoiDelta)) && 11656 (x > (int) (roi_info.x-RoiDelta)) && 11657 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11658 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11659 { 11660 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11661 state|=UpdateConfigurationState; 11662 break; 11663 } 11664 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11665 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11666 (y < (int) (roi_info.y+RoiDelta)) && 11667 (y > (int) (roi_info.y-RoiDelta))) 11668 { 11669 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11670 state|=UpdateConfigurationState; 11671 break; 11672 } 11673 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11674 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11675 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11676 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11677 { 11678 state|=UpdateConfigurationState; 11679 break; 11680 } 11681 } 11682 case ButtonRelease: 11683 { 11684 if (event.xbutton.window == windows->pan.id) 11685 if ((highlight_info.x != crop_info.x-windows->image.x) || 11686 (highlight_info.y != crop_info.y-windows->image.y)) 11687 XHighlightRectangle(display,windows->image.id, 11688 windows->image.highlight_context,&highlight_info); 11689 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11690 event.xbutton.time); 11691 break; 11692 } 11693 case Expose: 11694 { 11695 if (event.xexpose.window == windows->image.id) 11696 if (event.xexpose.count == 0) 11697 { 11698 event.xexpose.x=(int) highlight_info.x; 11699 event.xexpose.y=(int) highlight_info.y; 11700 event.xexpose.width=(int) highlight_info.width; 11701 event.xexpose.height=(int) highlight_info.height; 11702 XRefreshWindow(display,&windows->image,&event); 11703 } 11704 if (event.xexpose.window == windows->info.id) 11705 if (event.xexpose.count == 0) 11706 XInfoWidget(display,windows,text); 11707 break; 11708 } 11709 case KeyPress: 11710 { 11711 KeySym 11712 key_symbol; 11713 11714 if (event.xkey.window != windows->image.id) 11715 break; 11716 /* 11717 Respond to a user key press. 11718 */ 11719 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11720 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11721 switch ((int) key_symbol) 11722 { 11723 case XK_Shift_L: 11724 case XK_Shift_R: 11725 break; 11726 case XK_Escape: 11727 case XK_F20: 11728 state|=EscapeState; 11729 case XK_Return: 11730 { 11731 state|=ExitState; 11732 break; 11733 } 11734 case XK_Home: 11735 case XK_KP_Home: 11736 { 11737 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11738 roi_info.y=(ssize_t) (windows->image.height/2L- 11739 roi_info.height/2L); 11740 break; 11741 } 11742 case XK_Left: 11743 case XK_KP_Left: 11744 { 11745 roi_info.x--; 11746 break; 11747 } 11748 case XK_Up: 11749 case XK_KP_Up: 11750 case XK_Next: 11751 { 11752 roi_info.y--; 11753 break; 11754 } 11755 case XK_Right: 11756 case XK_KP_Right: 11757 { 11758 roi_info.x++; 11759 break; 11760 } 11761 case XK_Prior: 11762 case XK_Down: 11763 case XK_KP_Down: 11764 { 11765 roi_info.y++; 11766 break; 11767 } 11768 case XK_F1: 11769 case XK_Help: 11770 { 11771 (void) XSetFunction(display,windows->image.highlight_context, 11772 GXcopy); 11773 XTextViewWidget(display,resource_info,windows,MagickFalse, 11774 "Help Viewer - Region of Interest",ImageROIHelp); 11775 (void) XSetFunction(display,windows->image.highlight_context, 11776 GXinvert); 11777 break; 11778 } 11779 default: 11780 { 11781 command_type=XImageWindowCommand(display,resource_info,windows, 11782 event.xkey.state,key_symbol,image); 11783 if (command_type != NullCommand) 11784 state|=UpdateRegionState; 11785 break; 11786 } 11787 } 11788 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11789 event.xkey.time); 11790 break; 11791 } 11792 case KeyRelease: 11793 break; 11794 case MotionNotify: 11795 { 11796 if (event.xbutton.window != windows->image.id) 11797 break; 11798 /* 11799 Map and unmap Info widget as text cursor crosses its boundaries. 11800 */ 11801 x=event.xmotion.x; 11802 y=event.xmotion.y; 11803 if (windows->info.mapped != MagickFalse) 11804 { 11805 if ((x < (int) (windows->info.x+windows->info.width)) && 11806 (y < (int) (windows->info.y+windows->info.height))) 11807 (void) XWithdrawWindow(display,windows->info.id, 11808 windows->info.screen); 11809 } 11810 else 11811 if ((x > (int) (windows->info.x+windows->info.width)) || 11812 (y > (int) (windows->info.y+windows->info.height))) 11813 (void) XMapWindow(display,windows->info.id); 11814 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11815 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11816 break; 11817 } 11818 case SelectionRequest: 11819 { 11820 XSelectionEvent 11821 notify; 11822 11823 XSelectionRequestEvent 11824 *request; 11825 11826 /* 11827 Set primary selection. 11828 */ 11829 (void) FormatLocaleString(text,MaxTextExtent, 11830 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11831 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11832 request=(&(event.xselectionrequest)); 11833 (void) XChangeProperty(request->display,request->requestor, 11834 request->property,request->target,8,PropModeReplace, 11835 (unsigned char *) text,(int) strlen(text)); 11836 notify.type=SelectionNotify; 11837 notify.display=request->display; 11838 notify.requestor=request->requestor; 11839 notify.selection=request->selection; 11840 notify.target=request->target; 11841 notify.time=request->time; 11842 if (request->property == None) 11843 notify.property=request->target; 11844 else 11845 notify.property=request->property; 11846 (void) XSendEvent(request->display,request->requestor,False,0, 11847 (XEvent *) ¬ify); 11848 } 11849 default: 11850 break; 11851 } 11852 if ((state & UpdateConfigurationState) != 0) 11853 { 11854 (void) XPutBackEvent(display,&event); 11855 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11856 break; 11857 } 11858 } while ((state & ExitState) == 0); 11859 } while ((state & ExitState) == 0); 11860 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11861 XSetCursorState(display,windows,MagickFalse); 11862 if ((state & EscapeState) != 0) 11863 return(MagickTrue); 11864 return(MagickTrue); 11865} 11866 11867/* 11868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11869% % 11870% % 11871% % 11872+ X R o t a t e I m a g e % 11873% % 11874% % 11875% % 11876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11877% 11878% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11879% rotation angle is computed from the slope of a line drawn by the user. 11880% 11881% The format of the XRotateImage method is: 11882% 11883% MagickBooleanType XRotateImage(Display *display, 11884% XResourceInfo *resource_info,XWindows *windows,double degrees, 11885% Image **image) 11886% 11887% A description of each parameter follows: 11888% 11889% o display: Specifies a connection to an X server; returned from 11890% XOpenDisplay. 11891% 11892% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11893% 11894% o windows: Specifies a pointer to a XWindows structure. 11895% 11896% o degrees: Specifies the number of degrees to rotate the image. 11897% 11898% o image: the image. 11899% 11900*/ 11901static MagickBooleanType XRotateImage(Display *display, 11902 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image) 11903{ 11904 static const char 11905 *RotateMenu[] = 11906 { 11907 "Pixel Color", 11908 "Direction", 11909 "Help", 11910 "Dismiss", 11911 (char *) NULL 11912 }; 11913 11914 static ModeType 11915 direction = HorizontalRotateCommand; 11916 11917 static const ModeType 11918 DirectionCommands[] = 11919 { 11920 HorizontalRotateCommand, 11921 VerticalRotateCommand 11922 }, 11923 RotateCommands[] = 11924 { 11925 RotateColorCommand, 11926 RotateDirectionCommand, 11927 RotateHelpCommand, 11928 RotateDismissCommand 11929 }; 11930 11931 static unsigned int 11932 pen_id = 0; 11933 11934 char 11935 command[MaxTextExtent], 11936 text[MaxTextExtent]; 11937 11938 Image 11939 *rotate_image; 11940 11941 int 11942 id, 11943 x, 11944 y; 11945 11946 MagickRealType 11947 normalized_degrees; 11948 11949 register int 11950 i; 11951 11952 unsigned int 11953 height, 11954 rotations, 11955 width; 11956 11957 if (degrees == 0.0) 11958 { 11959 unsigned int 11960 distance; 11961 11962 size_t 11963 state; 11964 11965 XEvent 11966 event; 11967 11968 XSegment 11969 rotate_info; 11970 11971 /* 11972 Map Command widget. 11973 */ 11974 (void) CloneString(&windows->command.name,"Rotate"); 11975 windows->command.data=2; 11976 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 11977 (void) XMapRaised(display,windows->command.id); 11978 XClientMessage(display,windows->image.id,windows->im_protocols, 11979 windows->im_update_widget,CurrentTime); 11980 /* 11981 Wait for first button press. 11982 */ 11983 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11984 XQueryPosition(display,windows->image.id,&x,&y); 11985 rotate_info.x1=x; 11986 rotate_info.y1=y; 11987 rotate_info.x2=x; 11988 rotate_info.y2=y; 11989 state=DefaultState; 11990 do 11991 { 11992 XHighlightLine(display,windows->image.id, 11993 windows->image.highlight_context,&rotate_info); 11994 /* 11995 Wait for next event. 11996 */ 11997 XScreenEvent(display,windows,&event); 11998 XHighlightLine(display,windows->image.id, 11999 windows->image.highlight_context,&rotate_info); 12000 if (event.xany.window == windows->command.id) 12001 { 12002 /* 12003 Select a command from the Command widget. 12004 */ 12005 id=XCommandWidget(display,windows,RotateMenu,&event); 12006 if (id < 0) 12007 continue; 12008 (void) XSetFunction(display,windows->image.highlight_context, 12009 GXcopy); 12010 switch (RotateCommands[id]) 12011 { 12012 case RotateColorCommand: 12013 { 12014 const char 12015 *ColorMenu[MaxNumberPens]; 12016 12017 int 12018 pen_number; 12019 12020 XColor 12021 color; 12022 12023 /* 12024 Initialize menu selections. 12025 */ 12026 for (i=0; i < (int) (MaxNumberPens-2); i++) 12027 ColorMenu[i]=resource_info->pen_colors[i]; 12028 ColorMenu[MaxNumberPens-2]="Browser..."; 12029 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12030 /* 12031 Select a pen color from the pop-up menu. 12032 */ 12033 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12034 (const char **) ColorMenu,command); 12035 if (pen_number < 0) 12036 break; 12037 if (pen_number == (MaxNumberPens-2)) 12038 { 12039 static char 12040 color_name[MaxTextExtent] = "gray"; 12041 12042 /* 12043 Select a pen color from a dialog. 12044 */ 12045 resource_info->pen_colors[pen_number]=color_name; 12046 XColorBrowserWidget(display,windows,"Select",color_name); 12047 if (*color_name == '\0') 12048 break; 12049 } 12050 /* 12051 Set pen color. 12052 */ 12053 (void) XParseColor(display,windows->map_info->colormap, 12054 resource_info->pen_colors[pen_number],&color); 12055 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12056 (unsigned int) MaxColors,&color); 12057 windows->pixel_info->pen_colors[pen_number]=color; 12058 pen_id=(unsigned int) pen_number; 12059 break; 12060 } 12061 case RotateDirectionCommand: 12062 { 12063 static const char 12064 *Directions[] = 12065 { 12066 "horizontal", 12067 "vertical", 12068 (char *) NULL, 12069 }; 12070 12071 /* 12072 Select a command from the pop-up menu. 12073 */ 12074 id=XMenuWidget(display,windows,RotateMenu[id], 12075 Directions,command); 12076 if (id >= 0) 12077 direction=DirectionCommands[id]; 12078 break; 12079 } 12080 case RotateHelpCommand: 12081 { 12082 XTextViewWidget(display,resource_info,windows,MagickFalse, 12083 "Help Viewer - Image Rotation",ImageRotateHelp); 12084 break; 12085 } 12086 case RotateDismissCommand: 12087 { 12088 /* 12089 Prematurely exit. 12090 */ 12091 state|=EscapeState; 12092 state|=ExitState; 12093 break; 12094 } 12095 default: 12096 break; 12097 } 12098 (void) XSetFunction(display,windows->image.highlight_context, 12099 GXinvert); 12100 continue; 12101 } 12102 switch (event.type) 12103 { 12104 case ButtonPress: 12105 { 12106 if (event.xbutton.button != Button1) 12107 break; 12108 if (event.xbutton.window != windows->image.id) 12109 break; 12110 /* 12111 exit loop. 12112 */ 12113 (void) XSetFunction(display,windows->image.highlight_context, 12114 GXcopy); 12115 rotate_info.x1=event.xbutton.x; 12116 rotate_info.y1=event.xbutton.y; 12117 state|=ExitState; 12118 break; 12119 } 12120 case ButtonRelease: 12121 break; 12122 case Expose: 12123 break; 12124 case KeyPress: 12125 { 12126 char 12127 command[MaxTextExtent]; 12128 12129 KeySym 12130 key_symbol; 12131 12132 if (event.xkey.window != windows->image.id) 12133 break; 12134 /* 12135 Respond to a user key press. 12136 */ 12137 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12138 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12139 switch ((int) key_symbol) 12140 { 12141 case XK_Escape: 12142 case XK_F20: 12143 { 12144 /* 12145 Prematurely exit. 12146 */ 12147 state|=EscapeState; 12148 state|=ExitState; 12149 break; 12150 } 12151 case XK_F1: 12152 case XK_Help: 12153 { 12154 (void) XSetFunction(display,windows->image.highlight_context, 12155 GXcopy); 12156 XTextViewWidget(display,resource_info,windows,MagickFalse, 12157 "Help Viewer - Image Rotation",ImageRotateHelp); 12158 (void) XSetFunction(display,windows->image.highlight_context, 12159 GXinvert); 12160 break; 12161 } 12162 default: 12163 { 12164 (void) XBell(display,0); 12165 break; 12166 } 12167 } 12168 break; 12169 } 12170 case MotionNotify: 12171 { 12172 rotate_info.x1=event.xmotion.x; 12173 rotate_info.y1=event.xmotion.y; 12174 } 12175 } 12176 rotate_info.x2=rotate_info.x1; 12177 rotate_info.y2=rotate_info.y1; 12178 if (direction == HorizontalRotateCommand) 12179 rotate_info.x2+=32; 12180 else 12181 rotate_info.y2-=32; 12182 } while ((state & ExitState) == 0); 12183 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12184 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12185 if ((state & EscapeState) != 0) 12186 return(MagickTrue); 12187 /* 12188 Draw line as pointer moves until the mouse button is released. 12189 */ 12190 distance=0; 12191 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12192 state=DefaultState; 12193 do 12194 { 12195 if (distance > 9) 12196 { 12197 /* 12198 Display info and draw rotation line. 12199 */ 12200 if (windows->info.mapped == MagickFalse) 12201 (void) XMapWindow(display,windows->info.id); 12202 (void) FormatLocaleString(text,MaxTextExtent," %g", 12203 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12204 XInfoWidget(display,windows,text); 12205 XHighlightLine(display,windows->image.id, 12206 windows->image.highlight_context,&rotate_info); 12207 } 12208 else 12209 if (windows->info.mapped != MagickFalse) 12210 (void) XWithdrawWindow(display,windows->info.id, 12211 windows->info.screen); 12212 /* 12213 Wait for next event. 12214 */ 12215 XScreenEvent(display,windows,&event); 12216 if (distance > 9) 12217 XHighlightLine(display,windows->image.id, 12218 windows->image.highlight_context,&rotate_info); 12219 switch (event.type) 12220 { 12221 case ButtonPress: 12222 break; 12223 case ButtonRelease: 12224 { 12225 /* 12226 User has committed to rotation line. 12227 */ 12228 rotate_info.x2=event.xbutton.x; 12229 rotate_info.y2=event.xbutton.y; 12230 state|=ExitState; 12231 break; 12232 } 12233 case Expose: 12234 break; 12235 case MotionNotify: 12236 { 12237 rotate_info.x2=event.xmotion.x; 12238 rotate_info.y2=event.xmotion.y; 12239 } 12240 default: 12241 break; 12242 } 12243 /* 12244 Check boundary conditions. 12245 */ 12246 if (rotate_info.x2 < 0) 12247 rotate_info.x2=0; 12248 else 12249 if (rotate_info.x2 > (int) windows->image.width) 12250 rotate_info.x2=(short) windows->image.width; 12251 if (rotate_info.y2 < 0) 12252 rotate_info.y2=0; 12253 else 12254 if (rotate_info.y2 > (int) windows->image.height) 12255 rotate_info.y2=(short) windows->image.height; 12256 /* 12257 Compute rotation angle from the slope of the line. 12258 */ 12259 degrees=0.0; 12260 distance=(unsigned int) 12261 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12262 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12263 if (distance > 9) 12264 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12265 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12266 } while ((state & ExitState) == 0); 12267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12268 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12269 if (distance <= 9) 12270 return(MagickTrue); 12271 } 12272 if (direction == VerticalRotateCommand) 12273 degrees-=90.0; 12274 if (degrees == 0.0) 12275 return(MagickTrue); 12276 /* 12277 Rotate image. 12278 */ 12279 normalized_degrees=degrees; 12280 while (normalized_degrees < -45.0) 12281 normalized_degrees+=360.0; 12282 for (rotations=0; normalized_degrees > 45.0; rotations++) 12283 normalized_degrees-=90.0; 12284 if (normalized_degrees != 0.0) 12285 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 12286 XSetCursorState(display,windows,MagickTrue); 12287 XCheckRefreshWindows(display,windows); 12288 (*image)->background_color.red=ScaleShortToQuantum( 12289 windows->pixel_info->pen_colors[pen_id].red); 12290 (*image)->background_color.green=ScaleShortToQuantum( 12291 windows->pixel_info->pen_colors[pen_id].green); 12292 (*image)->background_color.blue=ScaleShortToQuantum( 12293 windows->pixel_info->pen_colors[pen_id].blue); 12294 rotate_image=RotateImage(*image,degrees,&(*image)->exception); 12295 XSetCursorState(display,windows,MagickFalse); 12296 if (rotate_image == (Image *) NULL) 12297 return(MagickFalse); 12298 *image=DestroyImage(*image); 12299 *image=rotate_image; 12300 if (windows->image.crop_geometry != (char *) NULL) 12301 { 12302 /* 12303 Rotate crop geometry. 12304 */ 12305 width=(unsigned int) (*image)->columns; 12306 height=(unsigned int) (*image)->rows; 12307 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12308 switch (rotations % 4) 12309 { 12310 default: 12311 case 0: 12312 break; 12313 case 1: 12314 { 12315 /* 12316 Rotate 90 degrees. 12317 */ 12318 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12319 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12320 (int) height-y,x); 12321 break; 12322 } 12323 case 2: 12324 { 12325 /* 12326 Rotate 180 degrees. 12327 */ 12328 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12329 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12330 break; 12331 } 12332 case 3: 12333 { 12334 /* 12335 Rotate 270 degrees. 12336 */ 12337 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12338 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12339 break; 12340 } 12341 } 12342 } 12343 if (windows->image.orphan != MagickFalse) 12344 return(MagickTrue); 12345 if (normalized_degrees != 0.0) 12346 { 12347 /* 12348 Update image colormap. 12349 */ 12350 windows->image.window_changes.width=(int) (*image)->columns; 12351 windows->image.window_changes.height=(int) (*image)->rows; 12352 if (windows->image.crop_geometry != (char *) NULL) 12353 { 12354 /* 12355 Obtain dimensions of image from crop geometry. 12356 */ 12357 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12358 &width,&height); 12359 windows->image.window_changes.width=(int) width; 12360 windows->image.window_changes.height=(int) height; 12361 } 12362 XConfigureImageColormap(display,resource_info,windows,*image); 12363 } 12364 else 12365 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12366 { 12367 windows->image.window_changes.width=windows->image.ximage->height; 12368 windows->image.window_changes.height=windows->image.ximage->width; 12369 } 12370 /* 12371 Update image configuration. 12372 */ 12373 (void) XConfigureImage(display,resource_info,windows,*image); 12374 return(MagickTrue); 12375} 12376 12377/* 12378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12379% % 12380% % 12381% % 12382+ X S a v e I m a g e % 12383% % 12384% % 12385% % 12386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12387% 12388% XSaveImage() saves an image to a file. 12389% 12390% The format of the XSaveImage method is: 12391% 12392% MagickBooleanType XSaveImage(Display *display, 12393% XResourceInfo *resource_info,XWindows *windows,Image *image) 12394% 12395% A description of each parameter follows: 12396% 12397% o display: Specifies a connection to an X server; returned from 12398% XOpenDisplay. 12399% 12400% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12401% 12402% o windows: Specifies a pointer to a XWindows structure. 12403% 12404% o image: the image. 12405% 12406*/ 12407static MagickBooleanType XSaveImage(Display *display, 12408 XResourceInfo *resource_info,XWindows *windows,Image *image) 12409{ 12410 char 12411 filename[MaxTextExtent], 12412 geometry[MaxTextExtent]; 12413 12414 Image 12415 *save_image; 12416 12417 ImageInfo 12418 *image_info; 12419 12420 MagickStatusType 12421 status; 12422 12423 /* 12424 Request file name from user. 12425 */ 12426 if (resource_info->write_filename != (char *) NULL) 12427 (void) CopyMagickString(filename,resource_info->write_filename, 12428 MaxTextExtent); 12429 else 12430 { 12431 char 12432 path[MaxTextExtent]; 12433 12434 int 12435 status; 12436 12437 GetPathComponent(image->filename,HeadPath,path); 12438 GetPathComponent(image->filename,TailPath,filename); 12439 status=chdir(path); 12440 if (status == -1) 12441 (void) ThrowMagickException(&image->exception,GetMagickModule(), 12442 FileOpenError,"UnableToOpenFile","%s",path); 12443 } 12444 XFileBrowserWidget(display,windows,"Save",filename); 12445 if (*filename == '\0') 12446 return(MagickTrue); 12447 if (IsPathAccessible(filename) != MagickFalse) 12448 { 12449 int 12450 status; 12451 12452 /* 12453 File exists-- seek user's permission before overwriting. 12454 */ 12455 status=XConfirmWidget(display,windows,"Overwrite",filename); 12456 if (status <= 0) 12457 return(MagickTrue); 12458 } 12459 image_info=CloneImageInfo(resource_info->image_info); 12460 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12461 (void) SetImageInfo(image_info,1,&image->exception); 12462 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12463 (LocaleCompare(image_info->magick,"JPG") == 0)) 12464 { 12465 char 12466 quality[MaxTextExtent]; 12467 12468 int 12469 status; 12470 12471 /* 12472 Request JPEG quality from user. 12473 */ 12474 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12475 image->quality); 12476 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12477 quality); 12478 if (*quality == '\0') 12479 return(MagickTrue); 12480 image->quality=StringToUnsignedLong(quality); 12481 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12482 } 12483 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12484 (LocaleCompare(image_info->magick,"PDF") == 0) || 12485 (LocaleCompare(image_info->magick,"PS") == 0) || 12486 (LocaleCompare(image_info->magick,"PS2") == 0)) 12487 { 12488 char 12489 geometry[MaxTextExtent]; 12490 12491 /* 12492 Request page geometry from user. 12493 */ 12494 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12495 if (LocaleCompare(image_info->magick,"PDF") == 0) 12496 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12497 if (image_info->page != (char *) NULL) 12498 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12499 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12500 "Select page geometry:",geometry); 12501 if (*geometry != '\0') 12502 image_info->page=GetPageGeometry(geometry); 12503 } 12504 /* 12505 Apply image transforms. 12506 */ 12507 XSetCursorState(display,windows,MagickTrue); 12508 XCheckRefreshWindows(display,windows); 12509 save_image=CloneImage(image,0,0,MagickTrue,&image->exception); 12510 if (save_image == (Image *) NULL) 12511 return(MagickFalse); 12512 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12513 windows->image.ximage->width,windows->image.ximage->height); 12514 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry); 12515 /* 12516 Write image. 12517 */ 12518 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12519 status=WriteImage(image_info,save_image); 12520 if (status != MagickFalse) 12521 image->taint=MagickFalse; 12522 save_image=DestroyImage(save_image); 12523 image_info=DestroyImageInfo(image_info); 12524 XSetCursorState(display,windows,MagickFalse); 12525 return(status != 0 ? MagickTrue : MagickFalse); 12526} 12527 12528/* 12529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12530% % 12531% % 12532% % 12533+ X S c r e e n E v e n t % 12534% % 12535% % 12536% % 12537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12538% 12539% XScreenEvent() handles global events associated with the Pan and Magnify 12540% windows. 12541% 12542% The format of the XScreenEvent function is: 12543% 12544% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12545% 12546% A description of each parameter follows: 12547% 12548% o display: Specifies a pointer to the Display structure; returned from 12549% XOpenDisplay. 12550% 12551% o windows: Specifies a pointer to a XWindows structure. 12552% 12553% o event: Specifies a pointer to a X11 XEvent structure. 12554% 12555% 12556*/ 12557 12558#if defined(__cplusplus) || defined(c_plusplus) 12559extern "C" { 12560#endif 12561 12562static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12563{ 12564 register XWindows 12565 *windows; 12566 12567 windows=(XWindows *) data; 12568 if ((event->type == ClientMessage) && 12569 (event->xclient.window == windows->image.id)) 12570 return(MagickFalse); 12571 return(MagickTrue); 12572} 12573 12574#if defined(__cplusplus) || defined(c_plusplus) 12575} 12576#endif 12577 12578static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12579{ 12580 register int 12581 x, 12582 y; 12583 12584 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12585 if (event->xany.window == windows->command.id) 12586 return; 12587 switch (event->type) 12588 { 12589 case ButtonPress: 12590 case ButtonRelease: 12591 { 12592 if ((event->xbutton.button == Button3) && 12593 (event->xbutton.state & Mod1Mask)) 12594 { 12595 /* 12596 Convert Alt-Button3 to Button2. 12597 */ 12598 event->xbutton.button=Button2; 12599 event->xbutton.state&=(~Mod1Mask); 12600 } 12601 if (event->xbutton.window == windows->backdrop.id) 12602 { 12603 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12604 event->xbutton.time); 12605 break; 12606 } 12607 if (event->xbutton.window == windows->pan.id) 12608 { 12609 XPanImage(display,windows,event); 12610 break; 12611 } 12612 if (event->xbutton.window == windows->image.id) 12613 if (event->xbutton.button == Button2) 12614 { 12615 /* 12616 Update magnified image. 12617 */ 12618 x=event->xbutton.x; 12619 y=event->xbutton.y; 12620 if (x < 0) 12621 x=0; 12622 else 12623 if (x >= (int) windows->image.width) 12624 x=(int) (windows->image.width-1); 12625 windows->magnify.x=(int) windows->image.x+x; 12626 if (y < 0) 12627 y=0; 12628 else 12629 if (y >= (int) windows->image.height) 12630 y=(int) (windows->image.height-1); 12631 windows->magnify.y=windows->image.y+y; 12632 if (windows->magnify.mapped == MagickFalse) 12633 (void) XMapRaised(display,windows->magnify.id); 12634 XMakeMagnifyImage(display,windows); 12635 if (event->type == ButtonRelease) 12636 (void) XWithdrawWindow(display,windows->info.id, 12637 windows->info.screen); 12638 break; 12639 } 12640 break; 12641 } 12642 case ClientMessage: 12643 { 12644 /* 12645 If client window delete message, exit. 12646 */ 12647 if (event->xclient.message_type != windows->wm_protocols) 12648 break; 12649 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12650 break; 12651 if (event->xclient.window == windows->magnify.id) 12652 { 12653 (void) XWithdrawWindow(display,windows->magnify.id, 12654 windows->magnify.screen); 12655 break; 12656 } 12657 break; 12658 } 12659 case ConfigureNotify: 12660 { 12661 if (event->xconfigure.window == windows->magnify.id) 12662 { 12663 unsigned int 12664 magnify; 12665 12666 /* 12667 Magnify window has a new configuration. 12668 */ 12669 windows->magnify.width=(unsigned int) event->xconfigure.width; 12670 windows->magnify.height=(unsigned int) event->xconfigure.height; 12671 if (windows->magnify.mapped == MagickFalse) 12672 break; 12673 magnify=1; 12674 while ((int) magnify <= event->xconfigure.width) 12675 magnify<<=1; 12676 while ((int) magnify <= event->xconfigure.height) 12677 magnify<<=1; 12678 magnify>>=1; 12679 if (((int) magnify != event->xconfigure.width) || 12680 ((int) magnify != event->xconfigure.height)) 12681 { 12682 XWindowChanges 12683 window_changes; 12684 12685 window_changes.width=(int) magnify; 12686 window_changes.height=(int) magnify; 12687 (void) XReconfigureWMWindow(display,windows->magnify.id, 12688 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12689 &window_changes); 12690 break; 12691 } 12692 XMakeMagnifyImage(display,windows); 12693 break; 12694 } 12695 break; 12696 } 12697 case Expose: 12698 { 12699 if (event->xexpose.window == windows->image.id) 12700 { 12701 XRefreshWindow(display,&windows->image,event); 12702 break; 12703 } 12704 if (event->xexpose.window == windows->pan.id) 12705 if (event->xexpose.count == 0) 12706 { 12707 XDrawPanRectangle(display,windows); 12708 break; 12709 } 12710 if (event->xexpose.window == windows->magnify.id) 12711 if (event->xexpose.count == 0) 12712 { 12713 XMakeMagnifyImage(display,windows); 12714 break; 12715 } 12716 break; 12717 } 12718 case KeyPress: 12719 { 12720 char 12721 command[MaxTextExtent]; 12722 12723 KeySym 12724 key_symbol; 12725 12726 if (event->xkey.window != windows->magnify.id) 12727 break; 12728 /* 12729 Respond to a user key press. 12730 */ 12731 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12732 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12733 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12734 break; 12735 } 12736 case MapNotify: 12737 { 12738 if (event->xmap.window == windows->magnify.id) 12739 { 12740 windows->magnify.mapped=MagickTrue; 12741 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12742 break; 12743 } 12744 if (event->xmap.window == windows->info.id) 12745 { 12746 windows->info.mapped=MagickTrue; 12747 break; 12748 } 12749 break; 12750 } 12751 case MotionNotify: 12752 { 12753 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12754 if (event->xmotion.window == windows->image.id) 12755 if (windows->magnify.mapped != MagickFalse) 12756 { 12757 /* 12758 Update magnified image. 12759 */ 12760 x=event->xmotion.x; 12761 y=event->xmotion.y; 12762 if (x < 0) 12763 x=0; 12764 else 12765 if (x >= (int) windows->image.width) 12766 x=(int) (windows->image.width-1); 12767 windows->magnify.x=(int) windows->image.x+x; 12768 if (y < 0) 12769 y=0; 12770 else 12771 if (y >= (int) windows->image.height) 12772 y=(int) (windows->image.height-1); 12773 windows->magnify.y=windows->image.y+y; 12774 XMakeMagnifyImage(display,windows); 12775 } 12776 break; 12777 } 12778 case UnmapNotify: 12779 { 12780 if (event->xunmap.window == windows->magnify.id) 12781 { 12782 windows->magnify.mapped=MagickFalse; 12783 break; 12784 } 12785 if (event->xunmap.window == windows->info.id) 12786 { 12787 windows->info.mapped=MagickFalse; 12788 break; 12789 } 12790 break; 12791 } 12792 default: 12793 break; 12794 } 12795} 12796 12797/* 12798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12799% % 12800% % 12801% % 12802+ X S e t C r o p G e o m e t r y % 12803% % 12804% % 12805% % 12806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12807% 12808% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12809% and translates it to a cropping geometry relative to the image. 12810% 12811% The format of the XSetCropGeometry method is: 12812% 12813% void XSetCropGeometry(Display *display,XWindows *windows, 12814% RectangleInfo *crop_info,Image *image) 12815% 12816% A description of each parameter follows: 12817% 12818% o display: Specifies a connection to an X server; returned from 12819% XOpenDisplay. 12820% 12821% o windows: Specifies a pointer to a XWindows structure. 12822% 12823% o crop_info: A pointer to a RectangleInfo that defines a region of the 12824% Image window to crop. 12825% 12826% o image: the image. 12827% 12828*/ 12829static void XSetCropGeometry(Display *display,XWindows *windows, 12830 RectangleInfo *crop_info,Image *image) 12831{ 12832 char 12833 text[MaxTextExtent]; 12834 12835 int 12836 x, 12837 y; 12838 12839 MagickRealType 12840 scale_factor; 12841 12842 unsigned int 12843 height, 12844 width; 12845 12846 if (windows->info.mapped != MagickFalse) 12847 { 12848 /* 12849 Display info on cropping rectangle. 12850 */ 12851 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12852 (double) crop_info->width,(double) crop_info->height,(double) 12853 crop_info->x,(double) crop_info->y); 12854 XInfoWidget(display,windows,text); 12855 } 12856 /* 12857 Cropping geometry is relative to any previous crop geometry. 12858 */ 12859 x=0; 12860 y=0; 12861 width=(unsigned int) image->columns; 12862 height=(unsigned int) image->rows; 12863 if (windows->image.crop_geometry != (char *) NULL) 12864 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12865 else 12866 windows->image.crop_geometry=AcquireString((char *) NULL); 12867 /* 12868 Define the crop geometry string from the cropping rectangle. 12869 */ 12870 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12871 if (crop_info->x > 0) 12872 x+=(int) (scale_factor*crop_info->x+0.5); 12873 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12874 if (width == 0) 12875 width=1; 12876 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12877 if (crop_info->y > 0) 12878 y+=(int) (scale_factor*crop_info->y+0.5); 12879 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12880 if (height == 0) 12881 height=1; 12882 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12883 "%ux%u%+d%+d",width,height,x,y); 12884} 12885 12886/* 12887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12888% % 12889% % 12890% % 12891+ X T i l e I m a g e % 12892% % 12893% % 12894% % 12895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12896% 12897% XTileImage() loads or deletes a selected tile from a visual image directory. 12898% The load or delete command is chosen from a menu. 12899% 12900% The format of the XTileImage method is: 12901% 12902% Image *XTileImage(Display *display,XResourceInfo *resource_info, 12903% XWindows *windows,Image *image,XEvent *event) 12904% 12905% A description of each parameter follows: 12906% 12907% o tile_image: XTileImage reads or deletes the tile image 12908% and returns it. A null image is returned if an error occurs. 12909% 12910% o display: Specifies a connection to an X server; returned from 12911% XOpenDisplay. 12912% 12913% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12914% 12915% o windows: Specifies a pointer to a XWindows structure. 12916% 12917% o image: the image; returned from ReadImage. 12918% 12919% o event: Specifies a pointer to a XEvent structure. If it is NULL, 12920% the entire image is refreshed. 12921% 12922*/ 12923static Image *XTileImage(Display *display,XResourceInfo *resource_info, 12924 XWindows *windows,Image *image,XEvent *event) 12925{ 12926 static const char 12927 *VerbMenu[] = 12928 { 12929 "Load", 12930 "Next", 12931 "Former", 12932 "Delete", 12933 "Update", 12934 (char *) NULL, 12935 }; 12936 12937 static const ModeType 12938 TileCommands[] = 12939 { 12940 TileLoadCommand, 12941 TileNextCommand, 12942 TileFormerCommand, 12943 TileDeleteCommand, 12944 TileUpdateCommand 12945 }; 12946 12947 char 12948 command[MaxTextExtent], 12949 filename[MaxTextExtent]; 12950 12951 Image 12952 *tile_image; 12953 12954 int 12955 id, 12956 status, 12957 tile, 12958 x, 12959 y; 12960 12961 MagickRealType 12962 scale_factor; 12963 12964 register char 12965 *p, 12966 *q; 12967 12968 register int 12969 i; 12970 12971 unsigned int 12972 height, 12973 width; 12974 12975 /* 12976 Tile image is relative to montage image configuration. 12977 */ 12978 x=0; 12979 y=0; 12980 width=(unsigned int) image->columns; 12981 height=(unsigned int) image->rows; 12982 if (windows->image.crop_geometry != (char *) NULL) 12983 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12984 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12985 event->xbutton.x+=windows->image.x; 12986 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 12987 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12988 event->xbutton.y+=windows->image.y; 12989 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 12990 /* 12991 Determine size and location of each tile in the visual image directory. 12992 */ 12993 width=(unsigned int) image->columns; 12994 height=(unsigned int) image->rows; 12995 x=0; 12996 y=0; 12997 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 12998 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 12999 (event->xbutton.x-x)/width; 13000 if (tile < 0) 13001 { 13002 /* 13003 Button press is outside any tile. 13004 */ 13005 (void) XBell(display,0); 13006 return((Image *) NULL); 13007 } 13008 /* 13009 Determine file name from the tile directory. 13010 */ 13011 p=image->directory; 13012 for (i=tile; (i != 0) && (*p != '\0'); ) 13013 { 13014 if (*p == '\n') 13015 i--; 13016 p++; 13017 } 13018 if (*p == '\0') 13019 { 13020 /* 13021 Button press is outside any tile. 13022 */ 13023 (void) XBell(display,0); 13024 return((Image *) NULL); 13025 } 13026 /* 13027 Select a command from the pop-up menu. 13028 */ 13029 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13030 if (id < 0) 13031 return((Image *) NULL); 13032 q=p; 13033 while ((*q != '\n') && (*q != '\0')) 13034 q++; 13035 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13036 /* 13037 Perform command for the selected tile. 13038 */ 13039 XSetCursorState(display,windows,MagickTrue); 13040 XCheckRefreshWindows(display,windows); 13041 tile_image=NewImageList(); 13042 switch (TileCommands[id]) 13043 { 13044 case TileLoadCommand: 13045 { 13046 /* 13047 Load tile image. 13048 */ 13049 XCheckRefreshWindows(display,windows); 13050 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13051 MaxTextExtent); 13052 (void) CopyMagickString(resource_info->image_info->filename,filename, 13053 MaxTextExtent); 13054 tile_image=ReadImage(resource_info->image_info,&image->exception); 13055 CatchException(&image->exception); 13056 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13057 break; 13058 } 13059 case TileNextCommand: 13060 { 13061 /* 13062 Display next image. 13063 */ 13064 XClientMessage(display,windows->image.id,windows->im_protocols, 13065 windows->im_next_image,CurrentTime); 13066 break; 13067 } 13068 case TileFormerCommand: 13069 { 13070 /* 13071 Display former image. 13072 */ 13073 XClientMessage(display,windows->image.id,windows->im_protocols, 13074 windows->im_former_image,CurrentTime); 13075 break; 13076 } 13077 case TileDeleteCommand: 13078 { 13079 /* 13080 Delete tile image. 13081 */ 13082 if (IsPathAccessible(filename) == MagickFalse) 13083 { 13084 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13085 break; 13086 } 13087 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13088 if (status <= 0) 13089 break; 13090 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 13091 if (status != MagickFalse) 13092 { 13093 XNoticeWidget(display,windows,"Unable to delete image file:", 13094 filename); 13095 break; 13096 } 13097 } 13098 case TileUpdateCommand: 13099 { 13100 ExceptionInfo 13101 *exception; 13102 13103 int 13104 x_offset, 13105 y_offset; 13106 13107 PixelPacket 13108 pixel; 13109 13110 register int 13111 j; 13112 13113 register Quantum 13114 *s; 13115 13116 /* 13117 Ensure all the images exist. 13118 */ 13119 tile=0; 13120 for (p=image->directory; *p != '\0'; p++) 13121 { 13122 CacheView 13123 *image_view; 13124 13125 q=p; 13126 while ((*q != '\n') && (*q != '\0')) 13127 q++; 13128 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13129 p=q; 13130 if (IsPathAccessible(filename) != MagickFalse) 13131 { 13132 tile++; 13133 continue; 13134 } 13135 /* 13136 Overwrite tile with background color. 13137 */ 13138 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13139 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13140 exception=(&image->exception); 13141 image_view=AcquireCacheView(image); 13142 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception); 13143 for (i=0; i < (int) height; i++) 13144 { 13145 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13146 y_offset+i,width,1,exception); 13147 if (s == (Quantum *) NULL) 13148 break; 13149 for (j=0; j < (int) width; j++) 13150 { 13151 SetPixelPacket(image,&pixel,s); 13152 s+=GetPixelChannels(image); 13153 } 13154 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13155 break; 13156 } 13157 image_view=DestroyCacheView(image_view); 13158 tile++; 13159 } 13160 windows->image.window_changes.width=(int) image->columns; 13161 windows->image.window_changes.height=(int) image->rows; 13162 XConfigureImageColormap(display,resource_info,windows,image); 13163 (void) XConfigureImage(display,resource_info,windows,image); 13164 break; 13165 } 13166 default: 13167 break; 13168 } 13169 XSetCursorState(display,windows,MagickFalse); 13170 return(tile_image); 13171} 13172 13173/* 13174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13175% % 13176% % 13177% % 13178+ X T r a n s l a t e I m a g e % 13179% % 13180% % 13181% % 13182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13183% 13184% XTranslateImage() translates the image within an Image window by one pixel 13185% as specified by the key symbol. If the image has a `montage string the 13186% translation is respect to the width and height contained within the string. 13187% 13188% The format of the XTranslateImage method is: 13189% 13190% void XTranslateImage(Display *display,XWindows *windows, 13191% Image *image,const KeySym key_symbol) 13192% 13193% A description of each parameter follows: 13194% 13195% o display: Specifies a connection to an X server; returned from 13196% XOpenDisplay. 13197% 13198% o windows: Specifies a pointer to a XWindows structure. 13199% 13200% o image: the image. 13201% 13202% o key_symbol: Specifies a KeySym which indicates which side of the image 13203% to trim. 13204% 13205*/ 13206static void XTranslateImage(Display *display,XWindows *windows, 13207 Image *image,const KeySym key_symbol) 13208{ 13209 char 13210 text[MaxTextExtent]; 13211 13212 int 13213 x, 13214 y; 13215 13216 unsigned int 13217 x_offset, 13218 y_offset; 13219 13220 /* 13221 User specified a pan position offset. 13222 */ 13223 x_offset=windows->image.width; 13224 y_offset=windows->image.height; 13225 if (image->montage != (char *) NULL) 13226 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13227 switch ((int) key_symbol) 13228 { 13229 case XK_Home: 13230 case XK_KP_Home: 13231 { 13232 windows->image.x=(int) windows->image.width/2; 13233 windows->image.y=(int) windows->image.height/2; 13234 break; 13235 } 13236 case XK_Left: 13237 case XK_KP_Left: 13238 { 13239 windows->image.x-=x_offset; 13240 break; 13241 } 13242 case XK_Next: 13243 case XK_Up: 13244 case XK_KP_Up: 13245 { 13246 windows->image.y-=y_offset; 13247 break; 13248 } 13249 case XK_Right: 13250 case XK_KP_Right: 13251 { 13252 windows->image.x+=x_offset; 13253 break; 13254 } 13255 case XK_Prior: 13256 case XK_Down: 13257 case XK_KP_Down: 13258 { 13259 windows->image.y+=y_offset; 13260 break; 13261 } 13262 default: 13263 return; 13264 } 13265 /* 13266 Check boundary conditions. 13267 */ 13268 if (windows->image.x < 0) 13269 windows->image.x=0; 13270 else 13271 if ((int) (windows->image.x+windows->image.width) > 13272 windows->image.ximage->width) 13273 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13274 if (windows->image.y < 0) 13275 windows->image.y=0; 13276 else 13277 if ((int) (windows->image.y+windows->image.height) > 13278 windows->image.ximage->height) 13279 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13280 /* 13281 Refresh Image window. 13282 */ 13283 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13284 windows->image.width,windows->image.height,windows->image.x, 13285 windows->image.y); 13286 XInfoWidget(display,windows,text); 13287 XCheckRefreshWindows(display,windows); 13288 XDrawPanRectangle(display,windows); 13289 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13290 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13291} 13292 13293/* 13294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13295% % 13296% % 13297% % 13298+ X T r i m I m a g e % 13299% % 13300% % 13301% % 13302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13303% 13304% XTrimImage() trims the edges from the Image window. 13305% 13306% The format of the XTrimImage method is: 13307% 13308% MagickBooleanType XTrimImage(Display *display, 13309% XResourceInfo *resource_info,XWindows *windows,Image *image) 13310% 13311% A description of each parameter follows: 13312% 13313% o display: Specifies a connection to an X server; returned from 13314% XOpenDisplay. 13315% 13316% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13317% 13318% o windows: Specifies a pointer to a XWindows structure. 13319% 13320% o image: the image. 13321% 13322*/ 13323static MagickBooleanType XTrimImage(Display *display, 13324 XResourceInfo *resource_info,XWindows *windows,Image *image) 13325{ 13326 RectangleInfo 13327 trim_info; 13328 13329 register int 13330 x, 13331 y; 13332 13333 size_t 13334 background, 13335 pixel; 13336 13337 /* 13338 Trim edges from image. 13339 */ 13340 XSetCursorState(display,windows,MagickTrue); 13341 XCheckRefreshWindows(display,windows); 13342 /* 13343 Crop the left edge. 13344 */ 13345 background=XGetPixel(windows->image.ximage,0,0); 13346 trim_info.width=(size_t) windows->image.ximage->width; 13347 for (x=0; x < windows->image.ximage->width; x++) 13348 { 13349 for (y=0; y < windows->image.ximage->height; y++) 13350 { 13351 pixel=XGetPixel(windows->image.ximage,x,y); 13352 if (pixel != background) 13353 break; 13354 } 13355 if (y < windows->image.ximage->height) 13356 break; 13357 } 13358 trim_info.x=(ssize_t) x; 13359 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13360 { 13361 XSetCursorState(display,windows,MagickFalse); 13362 return(MagickFalse); 13363 } 13364 /* 13365 Crop the right edge. 13366 */ 13367 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13368 for (x=windows->image.ximage->width-1; x != 0; x--) 13369 { 13370 for (y=0; y < windows->image.ximage->height; y++) 13371 { 13372 pixel=XGetPixel(windows->image.ximage,x,y); 13373 if (pixel != background) 13374 break; 13375 } 13376 if (y < windows->image.ximage->height) 13377 break; 13378 } 13379 trim_info.width=(size_t) (x-trim_info.x+1); 13380 /* 13381 Crop the top edge. 13382 */ 13383 background=XGetPixel(windows->image.ximage,0,0); 13384 trim_info.height=(size_t) windows->image.ximage->height; 13385 for (y=0; y < windows->image.ximage->height; y++) 13386 { 13387 for (x=0; x < windows->image.ximage->width; x++) 13388 { 13389 pixel=XGetPixel(windows->image.ximage,x,y); 13390 if (pixel != background) 13391 break; 13392 } 13393 if (x < windows->image.ximage->width) 13394 break; 13395 } 13396 trim_info.y=(ssize_t) y; 13397 /* 13398 Crop the bottom edge. 13399 */ 13400 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13401 for (y=windows->image.ximage->height-1; y != 0; y--) 13402 { 13403 for (x=0; x < windows->image.ximage->width; x++) 13404 { 13405 pixel=XGetPixel(windows->image.ximage,x,y); 13406 if (pixel != background) 13407 break; 13408 } 13409 if (x < windows->image.ximage->width) 13410 break; 13411 } 13412 trim_info.height=(size_t) y-trim_info.y+1; 13413 if (((unsigned int) trim_info.width != windows->image.width) || 13414 ((unsigned int) trim_info.height != windows->image.height)) 13415 { 13416 /* 13417 Reconfigure Image window as defined by the trimming rectangle. 13418 */ 13419 XSetCropGeometry(display,windows,&trim_info,image); 13420 windows->image.window_changes.width=(int) trim_info.width; 13421 windows->image.window_changes.height=(int) trim_info.height; 13422 (void) XConfigureImage(display,resource_info,windows,image); 13423 } 13424 XSetCursorState(display,windows,MagickFalse); 13425 return(MagickTrue); 13426} 13427 13428/* 13429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13430% % 13431% % 13432% % 13433+ X V i s u a l D i r e c t o r y I m a g e % 13434% % 13435% % 13436% % 13437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13438% 13439% XVisualDirectoryImage() creates a Visual Image Directory. 13440% 13441% The format of the XVisualDirectoryImage method is: 13442% 13443% Image *XVisualDirectoryImage(Display *display, 13444% XResourceInfo *resource_info,XWindows *windows) 13445% 13446% A description of each parameter follows: 13447% 13448% o nexus: Method XVisualDirectoryImage returns a visual image 13449% directory if it can be created successfully. Otherwise a null image 13450% is returned. 13451% 13452% o display: Specifies a connection to an X server; returned from 13453% XOpenDisplay. 13454% 13455% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13456% 13457% o windows: Specifies a pointer to a XWindows structure. 13458% 13459*/ 13460static Image *XVisualDirectoryImage(Display *display, 13461 XResourceInfo *resource_info,XWindows *windows) 13462{ 13463#define TileImageTag "Scale/Image" 13464#define XClientName "montage" 13465 13466 char 13467 **filelist; 13468 13469 ExceptionInfo 13470 *exception; 13471 13472 Image 13473 *images, 13474 *montage_image, 13475 *next_image, 13476 *thumbnail_image; 13477 13478 ImageInfo 13479 *read_info; 13480 13481 int 13482 number_files; 13483 13484 MagickBooleanType 13485 backdrop; 13486 13487 MagickStatusType 13488 status; 13489 13490 MontageInfo 13491 *montage_info; 13492 13493 RectangleInfo 13494 geometry; 13495 13496 register int 13497 i; 13498 13499 static char 13500 filename[MaxTextExtent] = "\0", 13501 filenames[MaxTextExtent] = "*"; 13502 13503 XResourceInfo 13504 background_resources; 13505 13506 /* 13507 Request file name from user. 13508 */ 13509 XFileBrowserWidget(display,windows,"Directory",filenames); 13510 if (*filenames == '\0') 13511 return((Image *) NULL); 13512 /* 13513 Expand the filenames. 13514 */ 13515 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13516 if (filelist == (char **) NULL) 13517 { 13518 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13519 filenames); 13520 return((Image *) NULL); 13521 } 13522 number_files=1; 13523 filelist[0]=filenames; 13524 status=ExpandFilenames(&number_files,&filelist); 13525 if ((status == MagickFalse) || (number_files == 0)) 13526 { 13527 if (number_files == 0) 13528 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13529 else 13530 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13531 filenames); 13532 return((Image *) NULL); 13533 } 13534 /* 13535 Set image background resources. 13536 */ 13537 background_resources=(*resource_info); 13538 background_resources.window_id=AcquireString(""); 13539 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13540 "0x%lx",windows->image.id); 13541 background_resources.backdrop=MagickTrue; 13542 /* 13543 Read each image and convert them to a tile. 13544 */ 13545 backdrop=(windows->visual_info->klass == TrueColor) || 13546 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13547 read_info=CloneImageInfo(resource_info->image_info); 13548 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13549 (void) CloneString(&read_info->size,DefaultTileGeometry); 13550 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13551 (void *) NULL); 13552 images=NewImageList(); 13553 exception=AcquireExceptionInfo(); 13554 XSetCursorState(display,windows,MagickTrue); 13555 XCheckRefreshWindows(display,windows); 13556 for (i=0; i < (int) number_files; i++) 13557 { 13558 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13559 filelist[i]=DestroyString(filelist[i]); 13560 *read_info->magick='\0'; 13561 next_image=ReadImage(read_info,exception); 13562 CatchException(exception); 13563 if (next_image != (Image *) NULL) 13564 { 13565 (void) DeleteImageProperty(next_image,"label"); 13566 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13567 read_info,next_image,DefaultTileLabel)); 13568 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13569 exception); 13570 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13571 geometry.height,exception); 13572 if (thumbnail_image != (Image *) NULL) 13573 { 13574 next_image=DestroyImage(next_image); 13575 next_image=thumbnail_image; 13576 } 13577 if (backdrop) 13578 { 13579 (void) XDisplayBackgroundImage(display,&background_resources, 13580 next_image); 13581 XSetCursorState(display,windows,MagickTrue); 13582 } 13583 AppendImageToList(&images,next_image); 13584 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13585 { 13586 MagickBooleanType 13587 proceed; 13588 13589 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13590 (MagickSizeType) number_files); 13591 if (proceed == MagickFalse) 13592 break; 13593 } 13594 } 13595 } 13596 exception=DestroyExceptionInfo(exception); 13597 filelist=(char **) RelinquishMagickMemory(filelist); 13598 if (images == (Image *) NULL) 13599 { 13600 read_info=DestroyImageInfo(read_info); 13601 XSetCursorState(display,windows,MagickFalse); 13602 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13603 return((Image *) NULL); 13604 } 13605 /* 13606 Create the Visual Image Directory. 13607 */ 13608 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13609 montage_info->pointsize=10; 13610 if (resource_info->font != (char *) NULL) 13611 (void) CloneString(&montage_info->font,resource_info->font); 13612 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13613 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13614 images),&images->exception); 13615 images=DestroyImageList(images); 13616 montage_info=DestroyMontageInfo(montage_info); 13617 read_info=DestroyImageInfo(read_info); 13618 XSetCursorState(display,windows,MagickFalse); 13619 if (montage_image == (Image *) NULL) 13620 return(montage_image); 13621 XClientMessage(display,windows->image.id,windows->im_protocols, 13622 windows->im_next_image,CurrentTime); 13623 return(montage_image); 13624} 13625 13626/* 13627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13628% % 13629% % 13630% % 13631% X D i s p l a y B a c k g r o u n d I m a g e % 13632% % 13633% % 13634% % 13635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13636% 13637% XDisplayBackgroundImage() displays an image in the background of a window. 13638% 13639% The format of the XDisplayBackgroundImage method is: 13640% 13641% MagickBooleanType XDisplayBackgroundImage(Display *display, 13642% XResourceInfo *resource_info,Image *image) 13643% 13644% A description of each parameter follows: 13645% 13646% o display: Specifies a connection to an X server; returned from 13647% XOpenDisplay. 13648% 13649% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13650% 13651% o image: the image. 13652% 13653*/ 13654MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13655 XResourceInfo *resource_info,Image *image) 13656{ 13657 char 13658 geometry[MaxTextExtent], 13659 visual_type[MaxTextExtent]; 13660 13661 int 13662 height, 13663 status, 13664 width; 13665 13666 RectangleInfo 13667 geometry_info; 13668 13669 static XPixelInfo 13670 pixel; 13671 13672 static XStandardColormap 13673 *map_info; 13674 13675 static XVisualInfo 13676 *visual_info = (XVisualInfo *) NULL; 13677 13678 static XWindowInfo 13679 window_info; 13680 13681 size_t 13682 delay; 13683 13684 Window 13685 root_window; 13686 13687 XGCValues 13688 context_values; 13689 13690 XResourceInfo 13691 resources; 13692 13693 XWindowAttributes 13694 window_attributes; 13695 13696 /* 13697 Determine target window. 13698 */ 13699 assert(image != (Image *) NULL); 13700 assert(image->signature == MagickSignature); 13701 if (image->debug != MagickFalse) 13702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13703 resources=(*resource_info); 13704 window_info.id=(Window) NULL; 13705 root_window=XRootWindow(display,XDefaultScreen(display)); 13706 if (LocaleCompare(resources.window_id,"root") == 0) 13707 window_info.id=root_window; 13708 else 13709 { 13710 if (isdigit((unsigned char) *resources.window_id) != 0) 13711 window_info.id=XWindowByID(display,root_window, 13712 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13713 if (window_info.id == (Window) NULL) 13714 window_info.id=XWindowByName(display,root_window,resources.window_id); 13715 } 13716 if (window_info.id == (Window) NULL) 13717 { 13718 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13719 resources.window_id); 13720 return(MagickFalse); 13721 } 13722 /* 13723 Determine window visual id. 13724 */ 13725 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13726 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13727 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13728 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13729 if (status != 0) 13730 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13731 XVisualIDFromVisual(window_attributes.visual)); 13732 if (visual_info == (XVisualInfo *) NULL) 13733 { 13734 /* 13735 Allocate standard colormap. 13736 */ 13737 map_info=XAllocStandardColormap(); 13738 if (map_info == (XStandardColormap *) NULL) 13739 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13740 image->filename); 13741 map_info->colormap=(Colormap) NULL; 13742 pixel.pixels=(unsigned long *) NULL; 13743 /* 13744 Initialize visual info. 13745 */ 13746 resources.map_type=(char *) NULL; 13747 resources.visual_type=visual_type; 13748 visual_info=XBestVisualInfo(display,map_info,&resources); 13749 if (visual_info == (XVisualInfo *) NULL) 13750 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13751 resources.visual_type); 13752 /* 13753 Initialize window info. 13754 */ 13755 window_info.ximage=(XImage *) NULL; 13756 window_info.matte_image=(XImage *) NULL; 13757 window_info.pixmap=(Pixmap) NULL; 13758 window_info.matte_pixmap=(Pixmap) NULL; 13759 } 13760 /* 13761 Free previous root colors. 13762 */ 13763 if (window_info.id == root_window) 13764 (void) XDestroyWindowColors(display,root_window); 13765 /* 13766 Initialize Standard Colormap. 13767 */ 13768 resources.colormap=SharedColormap; 13769 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13770 /* 13771 Graphic context superclass. 13772 */ 13773 context_values.background=pixel.background_color.pixel; 13774 context_values.foreground=pixel.foreground_color.pixel; 13775 pixel.annotate_context=XCreateGC(display,window_info.id, 13776 (size_t) (GCBackground | GCForeground),&context_values); 13777 if (pixel.annotate_context == (GC) NULL) 13778 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13779 image->filename); 13780 /* 13781 Initialize Image window attributes. 13782 */ 13783 window_info.name=AcquireString("\0"); 13784 window_info.icon_name=AcquireString("\0"); 13785 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13786 &resources,&window_info); 13787 /* 13788 Create the X image. 13789 */ 13790 window_info.width=(unsigned int) image->columns; 13791 window_info.height=(unsigned int) image->rows; 13792 if ((image->columns != window_info.width) || 13793 (image->rows != window_info.height)) 13794 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13795 image->filename); 13796 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13797 window_attributes.width,window_attributes.height); 13798 geometry_info.width=window_info.width; 13799 geometry_info.height=window_info.height; 13800 geometry_info.x=(ssize_t) window_info.x; 13801 geometry_info.y=(ssize_t) window_info.y; 13802 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13803 &geometry_info.width,&geometry_info.height); 13804 window_info.width=(unsigned int) geometry_info.width; 13805 window_info.height=(unsigned int) geometry_info.height; 13806 window_info.x=(int) geometry_info.x; 13807 window_info.y=(int) geometry_info.y; 13808 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13809 window_info.height); 13810 if (status == MagickFalse) 13811 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13812 image->filename); 13813 window_info.x=0; 13814 window_info.y=0; 13815 if (image->debug != MagickFalse) 13816 { 13817 (void) LogMagickEvent(X11Event,GetMagickModule(), 13818 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13819 (double) image->columns,(double) image->rows); 13820 if (image->colors != 0) 13821 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13822 image->colors); 13823 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13824 } 13825 /* 13826 Adjust image dimensions as specified by backdrop or geometry options. 13827 */ 13828 width=(int) window_info.width; 13829 height=(int) window_info.height; 13830 if (resources.backdrop != MagickFalse) 13831 { 13832 /* 13833 Center image on window. 13834 */ 13835 window_info.x=(window_attributes.width/2)- 13836 (window_info.ximage->width/2); 13837 window_info.y=(window_attributes.height/2)- 13838 (window_info.ximage->height/2); 13839 width=window_attributes.width; 13840 height=window_attributes.height; 13841 } 13842 if ((resources.image_geometry != (char *) NULL) && 13843 (*resources.image_geometry != '\0')) 13844 { 13845 char 13846 default_geometry[MaxTextExtent]; 13847 13848 int 13849 flags, 13850 gravity; 13851 13852 XSizeHints 13853 *size_hints; 13854 13855 /* 13856 User specified geometry. 13857 */ 13858 size_hints=XAllocSizeHints(); 13859 if (size_hints == (XSizeHints *) NULL) 13860 ThrowXWindowFatalException(ResourceLimitFatalError, 13861 "MemoryAllocationFailed",image->filename); 13862 size_hints->flags=0L; 13863 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13864 width,height); 13865 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13866 default_geometry,window_info.border_width,size_hints,&window_info.x, 13867 &window_info.y,&width,&height,&gravity); 13868 if (flags & (XValue | YValue)) 13869 { 13870 width=window_attributes.width; 13871 height=window_attributes.height; 13872 } 13873 (void) XFree((void *) size_hints); 13874 } 13875 /* 13876 Create the X pixmap. 13877 */ 13878 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 13879 (unsigned int) height,window_info.depth); 13880 if (window_info.pixmap == (Pixmap) NULL) 13881 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 13882 image->filename); 13883 /* 13884 Display pixmap on the window. 13885 */ 13886 if (((unsigned int) width > window_info.width) || 13887 ((unsigned int) height > window_info.height)) 13888 (void) XFillRectangle(display,window_info.pixmap, 13889 window_info.annotate_context,0,0,(unsigned int) width, 13890 (unsigned int) height); 13891 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 13892 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 13893 window_info.width,(unsigned int) window_info.height); 13894 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 13895 (void) XClearWindow(display,window_info.id); 13896 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 13897 XDelay(display,delay == 0UL ? 10UL : delay); 13898 (void) XSync(display,MagickFalse); 13899 return(window_info.id == root_window ? MagickTrue : MagickFalse); 13900} 13901 13902/* 13903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13904% % 13905% % 13906% % 13907+ X D i s p l a y I m a g e % 13908% % 13909% % 13910% % 13911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13912% 13913% XDisplayImage() displays an image via X11. A new image is created and 13914% returned if the user interactively transforms the displayed image. 13915% 13916% The format of the XDisplayImage method is: 13917% 13918% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 13919% char **argv,int argc,Image **image,size_t *state) 13920% 13921% A description of each parameter follows: 13922% 13923% o nexus: Method XDisplayImage returns an image when the 13924% user chooses 'Open Image' from the command menu or picks a tile 13925% from the image directory. Otherwise a null image is returned. 13926% 13927% o display: Specifies a connection to an X server; returned from 13928% XOpenDisplay. 13929% 13930% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13931% 13932% o argv: Specifies the application's argument list. 13933% 13934% o argc: Specifies the number of arguments. 13935% 13936% o image: Specifies an address to an address of an Image structure; 13937% 13938*/ 13939MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 13940 char **argv,int argc,Image **image,size_t *state) 13941{ 13942#define MagnifySize 256 /* must be a power of 2 */ 13943#define MagickMenus 10 13944#define MagickTitle "Commands" 13945 13946 static const char 13947 *CommandMenu[] = 13948 { 13949 "File", 13950 "Edit", 13951 "View", 13952 "Transform", 13953 "Enhance", 13954 "Effects", 13955 "F/X", 13956 "Image Edit", 13957 "Miscellany", 13958 "Help", 13959 (char *) NULL 13960 }, 13961 *FileMenu[] = 13962 { 13963 "Open...", 13964 "Next", 13965 "Former", 13966 "Select...", 13967 "Save...", 13968 "Print...", 13969 "Delete...", 13970 "New...", 13971 "Visual Directory...", 13972 "Quit", 13973 (char *) NULL 13974 }, 13975 *EditMenu[] = 13976 { 13977 "Undo", 13978 "Redo", 13979 "Cut", 13980 "Copy", 13981 "Paste", 13982 (char *) NULL 13983 }, 13984 *ViewMenu[] = 13985 { 13986 "Half Size", 13987 "Original Size", 13988 "Double Size", 13989 "Resize...", 13990 "Apply", 13991 "Refresh", 13992 "Restore", 13993 (char *) NULL 13994 }, 13995 *TransformMenu[] = 13996 { 13997 "Crop", 13998 "Chop", 13999 "Flop", 14000 "Flip", 14001 "Rotate Right", 14002 "Rotate Left", 14003 "Rotate...", 14004 "Shear...", 14005 "Roll...", 14006 "Trim Edges", 14007 (char *) NULL 14008 }, 14009 *EnhanceMenu[] = 14010 { 14011 "Hue...", 14012 "Saturation...", 14013 "Brightness...", 14014 "Gamma...", 14015 "Spiff", 14016 "Dull", 14017 "Contrast Stretch...", 14018 "Sigmoidal Contrast...", 14019 "Normalize", 14020 "Equalize", 14021 "Negate", 14022 "Grayscale", 14023 "Map...", 14024 "Quantize...", 14025 (char *) NULL 14026 }, 14027 *EffectsMenu[] = 14028 { 14029 "Despeckle", 14030 "Emboss", 14031 "Reduce Noise", 14032 "Add Noise...", 14033 "Sharpen...", 14034 "Blur...", 14035 "Threshold...", 14036 "Edge Detect...", 14037 "Spread...", 14038 "Shade...", 14039 "Raise...", 14040 "Segment...", 14041 (char *) NULL 14042 }, 14043 *FXMenu[] = 14044 { 14045 "Solarize...", 14046 "Sepia Tone...", 14047 "Swirl...", 14048 "Implode...", 14049 "Vignette...", 14050 "Wave...", 14051 "Oil Paint...", 14052 "Charcoal Draw...", 14053 (char *) NULL 14054 }, 14055 *ImageEditMenu[] = 14056 { 14057 "Annotate...", 14058 "Draw...", 14059 "Color...", 14060 "Matte...", 14061 "Composite...", 14062 "Add Border...", 14063 "Add Frame...", 14064 "Comment...", 14065 "Launch...", 14066 "Region of Interest...", 14067 (char *) NULL 14068 }, 14069 *MiscellanyMenu[] = 14070 { 14071 "Image Info", 14072 "Zoom Image", 14073 "Show Preview...", 14074 "Show Histogram", 14075 "Show Matte", 14076 "Background...", 14077 "Slide Show...", 14078 "Preferences...", 14079 (char *) NULL 14080 }, 14081 *HelpMenu[] = 14082 { 14083 "Overview", 14084 "Browse Documentation", 14085 "About Display", 14086 (char *) NULL 14087 }, 14088 *ShortCutsMenu[] = 14089 { 14090 "Next", 14091 "Former", 14092 "Open...", 14093 "Save...", 14094 "Print...", 14095 "Undo", 14096 "Restore", 14097 "Image Info", 14098 "Quit", 14099 (char *) NULL 14100 }, 14101 *VirtualMenu[] = 14102 { 14103 "Image Info", 14104 "Print", 14105 "Next", 14106 "Quit", 14107 (char *) NULL 14108 }; 14109 14110 static const char 14111 **Menus[MagickMenus] = 14112 { 14113 FileMenu, 14114 EditMenu, 14115 ViewMenu, 14116 TransformMenu, 14117 EnhanceMenu, 14118 EffectsMenu, 14119 FXMenu, 14120 ImageEditMenu, 14121 MiscellanyMenu, 14122 HelpMenu 14123 }; 14124 14125 static CommandType 14126 CommandMenus[] = 14127 { 14128 NullCommand, 14129 NullCommand, 14130 NullCommand, 14131 NullCommand, 14132 NullCommand, 14133 NullCommand, 14134 NullCommand, 14135 NullCommand, 14136 NullCommand, 14137 NullCommand, 14138 }, 14139 FileCommands[] = 14140 { 14141 OpenCommand, 14142 NextCommand, 14143 FormerCommand, 14144 SelectCommand, 14145 SaveCommand, 14146 PrintCommand, 14147 DeleteCommand, 14148 NewCommand, 14149 VisualDirectoryCommand, 14150 QuitCommand 14151 }, 14152 EditCommands[] = 14153 { 14154 UndoCommand, 14155 RedoCommand, 14156 CutCommand, 14157 CopyCommand, 14158 PasteCommand 14159 }, 14160 ViewCommands[] = 14161 { 14162 HalfSizeCommand, 14163 OriginalSizeCommand, 14164 DoubleSizeCommand, 14165 ResizeCommand, 14166 ApplyCommand, 14167 RefreshCommand, 14168 RestoreCommand 14169 }, 14170 TransformCommands[] = 14171 { 14172 CropCommand, 14173 ChopCommand, 14174 FlopCommand, 14175 FlipCommand, 14176 RotateRightCommand, 14177 RotateLeftCommand, 14178 RotateCommand, 14179 ShearCommand, 14180 RollCommand, 14181 TrimCommand 14182 }, 14183 EnhanceCommands[] = 14184 { 14185 HueCommand, 14186 SaturationCommand, 14187 BrightnessCommand, 14188 GammaCommand, 14189 SpiffCommand, 14190 DullCommand, 14191 ContrastStretchCommand, 14192 SigmoidalContrastCommand, 14193 NormalizeCommand, 14194 EqualizeCommand, 14195 NegateCommand, 14196 GrayscaleCommand, 14197 MapCommand, 14198 QuantizeCommand 14199 }, 14200 EffectsCommands[] = 14201 { 14202 DespeckleCommand, 14203 EmbossCommand, 14204 ReduceNoiseCommand, 14205 AddNoiseCommand, 14206 SharpenCommand, 14207 BlurCommand, 14208 ThresholdCommand, 14209 EdgeDetectCommand, 14210 SpreadCommand, 14211 ShadeCommand, 14212 RaiseCommand, 14213 SegmentCommand 14214 }, 14215 FXCommands[] = 14216 { 14217 SolarizeCommand, 14218 SepiaToneCommand, 14219 SwirlCommand, 14220 ImplodeCommand, 14221 VignetteCommand, 14222 WaveCommand, 14223 OilPaintCommand, 14224 CharcoalDrawCommand 14225 }, 14226 ImageEditCommands[] = 14227 { 14228 AnnotateCommand, 14229 DrawCommand, 14230 ColorCommand, 14231 MatteCommand, 14232 CompositeCommand, 14233 AddBorderCommand, 14234 AddFrameCommand, 14235 CommentCommand, 14236 LaunchCommand, 14237 RegionofInterestCommand 14238 }, 14239 MiscellanyCommands[] = 14240 { 14241 InfoCommand, 14242 ZoomCommand, 14243 ShowPreviewCommand, 14244 ShowHistogramCommand, 14245 ShowMatteCommand, 14246 BackgroundCommand, 14247 SlideShowCommand, 14248 PreferencesCommand 14249 }, 14250 HelpCommands[] = 14251 { 14252 HelpCommand, 14253 BrowseDocumentationCommand, 14254 VersionCommand 14255 }, 14256 ShortCutsCommands[] = 14257 { 14258 NextCommand, 14259 FormerCommand, 14260 OpenCommand, 14261 SaveCommand, 14262 PrintCommand, 14263 UndoCommand, 14264 RestoreCommand, 14265 InfoCommand, 14266 QuitCommand 14267 }, 14268 VirtualCommands[] = 14269 { 14270 InfoCommand, 14271 PrintCommand, 14272 NextCommand, 14273 QuitCommand 14274 }; 14275 14276 static CommandType 14277 *Commands[MagickMenus] = 14278 { 14279 FileCommands, 14280 EditCommands, 14281 ViewCommands, 14282 TransformCommands, 14283 EnhanceCommands, 14284 EffectsCommands, 14285 FXCommands, 14286 ImageEditCommands, 14287 MiscellanyCommands, 14288 HelpCommands 14289 }; 14290 14291 char 14292 command[MaxTextExtent], 14293 *directory, 14294 geometry[MaxTextExtent], 14295 resource_name[MaxTextExtent]; 14296 14297 CommandType 14298 command_type; 14299 14300 Image 14301 *display_image, 14302 *nexus; 14303 14304 int 14305 entry, 14306 id; 14307 14308 KeySym 14309 key_symbol; 14310 14311 MagickStatusType 14312 context_mask, 14313 status; 14314 14315 RectangleInfo 14316 geometry_info; 14317 14318 register int 14319 i; 14320 14321 static char 14322 working_directory[MaxTextExtent]; 14323 14324 static XPoint 14325 vid_info; 14326 14327 static XWindowInfo 14328 *magick_windows[MaxXWindows]; 14329 14330 static unsigned int 14331 number_windows; 14332 14333 struct stat 14334 attributes; 14335 14336 time_t 14337 timer, 14338 timestamp, 14339 update_time; 14340 14341 unsigned int 14342 height, 14343 width; 14344 14345 size_t 14346 delay; 14347 14348 WarningHandler 14349 warning_handler; 14350 14351 Window 14352 root_window; 14353 14354 XClassHint 14355 *class_hints; 14356 14357 XEvent 14358 event; 14359 14360 XFontStruct 14361 *font_info; 14362 14363 XGCValues 14364 context_values; 14365 14366 XPixelInfo 14367 *icon_pixel, 14368 *pixel; 14369 14370 XResourceInfo 14371 *icon_resources; 14372 14373 XStandardColormap 14374 *icon_map, 14375 *map_info; 14376 14377 XVisualInfo 14378 *icon_visual, 14379 *visual_info; 14380 14381 XWindowChanges 14382 window_changes; 14383 14384 XWindows 14385 *windows; 14386 14387 XWMHints 14388 *manager_hints; 14389 14390 assert(image != (Image **) NULL); 14391 assert((*image)->signature == MagickSignature); 14392 if ((*image)->debug != MagickFalse) 14393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14394 display_image=(*image); 14395 warning_handler=(WarningHandler) NULL; 14396 windows=XSetWindows((XWindows *) ~0); 14397 if (windows != (XWindows *) NULL) 14398 { 14399 int 14400 status; 14401 14402 status=chdir(working_directory); 14403 if (status == -1) 14404 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 14405 FileOpenError,"UnableToOpenFile","%s",working_directory); 14406 warning_handler=resource_info->display_warnings ? 14407 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14408 warning_handler=resource_info->display_warnings ? 14409 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14410 } 14411 else 14412 { 14413 /* 14414 Allocate windows structure. 14415 */ 14416 resource_info->colors=display_image->colors; 14417 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14418 if (windows == (XWindows *) NULL) 14419 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14420 (*image)->filename); 14421 /* 14422 Initialize window id's. 14423 */ 14424 number_windows=0; 14425 magick_windows[number_windows++]=(&windows->icon); 14426 magick_windows[number_windows++]=(&windows->backdrop); 14427 magick_windows[number_windows++]=(&windows->image); 14428 magick_windows[number_windows++]=(&windows->info); 14429 magick_windows[number_windows++]=(&windows->command); 14430 magick_windows[number_windows++]=(&windows->widget); 14431 magick_windows[number_windows++]=(&windows->popup); 14432 magick_windows[number_windows++]=(&windows->magnify); 14433 magick_windows[number_windows++]=(&windows->pan); 14434 for (i=0; i < (int) number_windows; i++) 14435 magick_windows[i]->id=(Window) NULL; 14436 vid_info.x=0; 14437 vid_info.y=0; 14438 } 14439 /* 14440 Initialize font info. 14441 */ 14442 if (windows->font_info != (XFontStruct *) NULL) 14443 (void) XFreeFont(display,windows->font_info); 14444 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14445 if (windows->font_info == (XFontStruct *) NULL) 14446 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14447 resource_info->font); 14448 /* 14449 Initialize Standard Colormap. 14450 */ 14451 map_info=windows->map_info; 14452 icon_map=windows->icon_map; 14453 visual_info=windows->visual_info; 14454 icon_visual=windows->icon_visual; 14455 pixel=windows->pixel_info; 14456 icon_pixel=windows->icon_pixel; 14457 font_info=windows->font_info; 14458 icon_resources=windows->icon_resources; 14459 class_hints=windows->class_hints; 14460 manager_hints=windows->manager_hints; 14461 root_window=XRootWindow(display,visual_info->screen); 14462 nexus=NewImageList(); 14463 if (display_image->debug != MagickFalse) 14464 { 14465 (void) LogMagickEvent(X11Event,GetMagickModule(), 14466 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14467 (double) display_image->scene,(double) display_image->columns, 14468 (double) display_image->rows); 14469 if (display_image->colors != 0) 14470 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14471 display_image->colors); 14472 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14473 display_image->magick); 14474 } 14475 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14476 map_info,pixel); 14477 display_image->taint=MagickFalse; 14478 /* 14479 Initialize graphic context. 14480 */ 14481 windows->context.id=(Window) NULL; 14482 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14483 resource_info,&windows->context); 14484 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14485 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14486 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14487 manager_hints->flags=InputHint | StateHint; 14488 manager_hints->input=MagickFalse; 14489 manager_hints->initial_state=WithdrawnState; 14490 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14491 &windows->context); 14492 if (display_image->debug != MagickFalse) 14493 (void) LogMagickEvent(X11Event,GetMagickModule(), 14494 "Window id: 0x%lx (context)",windows->context.id); 14495 context_values.background=pixel->background_color.pixel; 14496 context_values.font=font_info->fid; 14497 context_values.foreground=pixel->foreground_color.pixel; 14498 context_values.graphics_exposures=MagickFalse; 14499 context_mask=(MagickStatusType) 14500 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14501 if (pixel->annotate_context != (GC) NULL) 14502 (void) XFreeGC(display,pixel->annotate_context); 14503 pixel->annotate_context=XCreateGC(display,windows->context.id, 14504 context_mask,&context_values); 14505 if (pixel->annotate_context == (GC) NULL) 14506 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14507 display_image->filename); 14508 context_values.background=pixel->depth_color.pixel; 14509 if (pixel->widget_context != (GC) NULL) 14510 (void) XFreeGC(display,pixel->widget_context); 14511 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14512 &context_values); 14513 if (pixel->widget_context == (GC) NULL) 14514 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14515 display_image->filename); 14516 context_values.background=pixel->foreground_color.pixel; 14517 context_values.foreground=pixel->background_color.pixel; 14518 context_values.plane_mask=context_values.background ^ 14519 context_values.foreground; 14520 if (pixel->highlight_context != (GC) NULL) 14521 (void) XFreeGC(display,pixel->highlight_context); 14522 pixel->highlight_context=XCreateGC(display,windows->context.id, 14523 (size_t) (context_mask | GCPlaneMask),&context_values); 14524 if (pixel->highlight_context == (GC) NULL) 14525 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14526 display_image->filename); 14527 (void) XDestroyWindow(display,windows->context.id); 14528 /* 14529 Initialize icon window. 14530 */ 14531 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14532 icon_resources,&windows->icon); 14533 windows->icon.geometry=resource_info->icon_geometry; 14534 XBestIconSize(display,&windows->icon,display_image); 14535 windows->icon.attributes.colormap=XDefaultColormap(display, 14536 icon_visual->screen); 14537 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14538 manager_hints->flags=InputHint | StateHint; 14539 manager_hints->input=MagickFalse; 14540 manager_hints->initial_state=IconicState; 14541 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14542 &windows->icon); 14543 if (display_image->debug != MagickFalse) 14544 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14545 windows->icon.id); 14546 /* 14547 Initialize graphic context for icon window. 14548 */ 14549 if (icon_pixel->annotate_context != (GC) NULL) 14550 (void) XFreeGC(display,icon_pixel->annotate_context); 14551 context_values.background=icon_pixel->background_color.pixel; 14552 context_values.foreground=icon_pixel->foreground_color.pixel; 14553 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14554 (size_t) (GCBackground | GCForeground),&context_values); 14555 if (icon_pixel->annotate_context == (GC) NULL) 14556 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14557 display_image->filename); 14558 windows->icon.annotate_context=icon_pixel->annotate_context; 14559 /* 14560 Initialize Image window. 14561 */ 14562 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14563 &windows->image); 14564 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14565 if (resource_info->use_shared_memory == MagickFalse) 14566 windows->image.shared_memory=MagickFalse; 14567 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14568 { 14569 char 14570 *title; 14571 14572 title=InterpretImageProperties(resource_info->image_info,display_image, 14573 resource_info->title); 14574 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14575 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14576 title=DestroyString(title); 14577 } 14578 else 14579 { 14580 char 14581 filename[MaxTextExtent]; 14582 14583 /* 14584 Window name is the base of the filename. 14585 */ 14586 GetPathComponent(display_image->magick_filename,TailPath,filename); 14587 if (GetImageListLength(display_image) == 1) 14588 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14589 "%s: %s",MagickPackageName,filename); 14590 else 14591 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14592 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14593 (double) display_image->scene,(double) GetImageListLength( 14594 display_image)); 14595 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14596 } 14597 if (resource_info->immutable) 14598 windows->image.immutable=MagickTrue; 14599 windows->image.use_pixmap=resource_info->use_pixmap; 14600 windows->image.geometry=resource_info->image_geometry; 14601 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14602 XDisplayWidth(display,visual_info->screen), 14603 XDisplayHeight(display,visual_info->screen)); 14604 geometry_info.width=display_image->columns; 14605 geometry_info.height=display_image->rows; 14606 geometry_info.x=0; 14607 geometry_info.y=0; 14608 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14609 &geometry_info.width,&geometry_info.height); 14610 windows->image.width=(unsigned int) geometry_info.width; 14611 windows->image.height=(unsigned int) geometry_info.height; 14612 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14613 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14614 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14615 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14616 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14617 resource_info,&windows->backdrop); 14618 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14619 { 14620 /* 14621 Initialize backdrop window. 14622 */ 14623 windows->backdrop.x=0; 14624 windows->backdrop.y=0; 14625 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14626 windows->backdrop.flags=(size_t) (USSize | USPosition); 14627 windows->backdrop.width=(unsigned int) 14628 XDisplayWidth(display,visual_info->screen); 14629 windows->backdrop.height=(unsigned int) 14630 XDisplayHeight(display,visual_info->screen); 14631 windows->backdrop.border_width=0; 14632 windows->backdrop.immutable=MagickTrue; 14633 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14634 ButtonReleaseMask; 14635 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14636 StructureNotifyMask; 14637 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14638 manager_hints->icon_window=windows->icon.id; 14639 manager_hints->input=MagickTrue; 14640 manager_hints->initial_state=resource_info->iconic ? IconicState : 14641 NormalState; 14642 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14643 &windows->backdrop); 14644 if (display_image->debug != MagickFalse) 14645 (void) LogMagickEvent(X11Event,GetMagickModule(), 14646 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14647 (void) XMapWindow(display,windows->backdrop.id); 14648 (void) XClearWindow(display,windows->backdrop.id); 14649 if (windows->image.id != (Window) NULL) 14650 { 14651 (void) XDestroyWindow(display,windows->image.id); 14652 windows->image.id=(Window) NULL; 14653 } 14654 /* 14655 Position image in the center the backdrop. 14656 */ 14657 windows->image.flags|=USPosition; 14658 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14659 (windows->image.width/2); 14660 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14661 (windows->image.height/2); 14662 } 14663 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14664 manager_hints->icon_window=windows->icon.id; 14665 manager_hints->input=MagickTrue; 14666 manager_hints->initial_state=resource_info->iconic ? IconicState : 14667 NormalState; 14668 if (windows->group_leader.id != (Window) NULL) 14669 { 14670 /* 14671 Follow the leader. 14672 */ 14673 manager_hints->flags|=WindowGroupHint; 14674 manager_hints->window_group=windows->group_leader.id; 14675 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14676 if (display_image->debug != MagickFalse) 14677 (void) LogMagickEvent(X11Event,GetMagickModule(), 14678 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14679 } 14680 XMakeWindow(display, 14681 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14682 argv,argc,class_hints,manager_hints,&windows->image); 14683 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14684 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14685 if (windows->group_leader.id != (Window) NULL) 14686 (void) XSetTransientForHint(display,windows->image.id, 14687 windows->group_leader.id); 14688 if (display_image->debug != MagickFalse) 14689 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14690 windows->image.id); 14691 /* 14692 Initialize Info widget. 14693 */ 14694 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14695 &windows->info); 14696 (void) CloneString(&windows->info.name,"Info"); 14697 (void) CloneString(&windows->info.icon_name,"Info"); 14698 windows->info.border_width=1; 14699 windows->info.x=2; 14700 windows->info.y=2; 14701 windows->info.flags|=PPosition; 14702 windows->info.attributes.win_gravity=UnmapGravity; 14703 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14704 StructureNotifyMask; 14705 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14706 manager_hints->input=MagickFalse; 14707 manager_hints->initial_state=NormalState; 14708 manager_hints->window_group=windows->image.id; 14709 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14710 &windows->info); 14711 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14712 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14713 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14714 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14715 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14716 if (windows->image.mapped != MagickFalse) 14717 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14718 if (display_image->debug != MagickFalse) 14719 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14720 windows->info.id); 14721 /* 14722 Initialize Command widget. 14723 */ 14724 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14725 resource_info,&windows->command); 14726 windows->command.data=MagickMenus; 14727 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14728 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14729 resource_info->client_name); 14730 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14731 resource_name,"geometry",(char *) NULL); 14732 (void) CloneString(&windows->command.name,MagickTitle); 14733 windows->command.border_width=0; 14734 windows->command.flags|=PPosition; 14735 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14736 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14737 OwnerGrabButtonMask | StructureNotifyMask; 14738 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14739 manager_hints->input=MagickTrue; 14740 manager_hints->initial_state=NormalState; 14741 manager_hints->window_group=windows->image.id; 14742 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14743 &windows->command); 14744 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14745 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14746 HighlightHeight); 14747 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14748 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14749 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14750 if (windows->command.mapped != MagickFalse) 14751 (void) XMapRaised(display,windows->command.id); 14752 if (display_image->debug != MagickFalse) 14753 (void) LogMagickEvent(X11Event,GetMagickModule(), 14754 "Window id: 0x%lx (command)",windows->command.id); 14755 /* 14756 Initialize Widget window. 14757 */ 14758 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14759 resource_info,&windows->widget); 14760 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14761 resource_info->client_name); 14762 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14763 resource_name,"geometry",(char *) NULL); 14764 windows->widget.border_width=0; 14765 windows->widget.flags|=PPosition; 14766 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14767 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14768 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14769 StructureNotifyMask; 14770 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14771 manager_hints->input=MagickTrue; 14772 manager_hints->initial_state=NormalState; 14773 manager_hints->window_group=windows->image.id; 14774 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14775 &windows->widget); 14776 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14777 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14778 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14779 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14780 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14781 if (display_image->debug != MagickFalse) 14782 (void) LogMagickEvent(X11Event,GetMagickModule(), 14783 "Window id: 0x%lx (widget)",windows->widget.id); 14784 /* 14785 Initialize popup window. 14786 */ 14787 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14788 resource_info,&windows->popup); 14789 windows->popup.border_width=0; 14790 windows->popup.flags|=PPosition; 14791 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14792 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14793 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14794 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14795 manager_hints->input=MagickTrue; 14796 manager_hints->initial_state=NormalState; 14797 manager_hints->window_group=windows->image.id; 14798 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14799 &windows->popup); 14800 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14801 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14802 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14803 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14804 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14805 if (display_image->debug != MagickFalse) 14806 (void) LogMagickEvent(X11Event,GetMagickModule(), 14807 "Window id: 0x%lx (pop up)",windows->popup.id); 14808 /* 14809 Initialize Magnify window and cursor. 14810 */ 14811 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14812 resource_info,&windows->magnify); 14813 if (resource_info->use_shared_memory == MagickFalse) 14814 windows->magnify.shared_memory=MagickFalse; 14815 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14816 resource_info->client_name); 14817 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14818 resource_name,"geometry",(char *) NULL); 14819 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14820 resource_info->magnify); 14821 if (windows->magnify.cursor != (Cursor) NULL) 14822 (void) XFreeCursor(display,windows->magnify.cursor); 14823 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14824 map_info->colormap,resource_info->background_color, 14825 resource_info->foreground_color); 14826 if (windows->magnify.cursor == (Cursor) NULL) 14827 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14828 display_image->filename); 14829 windows->magnify.width=MagnifySize; 14830 windows->magnify.height=MagnifySize; 14831 windows->magnify.flags|=PPosition; 14832 windows->magnify.min_width=MagnifySize; 14833 windows->magnify.min_height=MagnifySize; 14834 windows->magnify.width_inc=MagnifySize; 14835 windows->magnify.height_inc=MagnifySize; 14836 windows->magnify.data=resource_info->magnify; 14837 windows->magnify.attributes.cursor=windows->magnify.cursor; 14838 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14839 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14840 StructureNotifyMask; 14841 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14842 manager_hints->input=MagickTrue; 14843 manager_hints->initial_state=NormalState; 14844 manager_hints->window_group=windows->image.id; 14845 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14846 &windows->magnify); 14847 if (display_image->debug != MagickFalse) 14848 (void) LogMagickEvent(X11Event,GetMagickModule(), 14849 "Window id: 0x%lx (magnify)",windows->magnify.id); 14850 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14851 /* 14852 Initialize panning window. 14853 */ 14854 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14855 resource_info,&windows->pan); 14856 (void) CloneString(&windows->pan.name,"Pan Icon"); 14857 windows->pan.width=windows->icon.width; 14858 windows->pan.height=windows->icon.height; 14859 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14860 resource_info->client_name); 14861 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14862 resource_name,"geometry",(char *) NULL); 14863 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14864 &windows->pan.width,&windows->pan.height); 14865 windows->pan.flags|=PPosition; 14866 windows->pan.immutable=MagickTrue; 14867 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14868 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14869 StructureNotifyMask; 14870 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14871 manager_hints->input=MagickFalse; 14872 manager_hints->initial_state=NormalState; 14873 manager_hints->window_group=windows->image.id; 14874 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14875 &windows->pan); 14876 if (display_image->debug != MagickFalse) 14877 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 14878 windows->pan.id); 14879 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 14880 if (windows->info.mapped != MagickFalse) 14881 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14882 if ((windows->image.mapped == MagickFalse) || 14883 (windows->backdrop.id != (Window) NULL)) 14884 (void) XMapWindow(display,windows->image.id); 14885 /* 14886 Set our progress monitor and warning handlers. 14887 */ 14888 if (warning_handler == (WarningHandler) NULL) 14889 { 14890 warning_handler=resource_info->display_warnings ? 14891 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14892 warning_handler=resource_info->display_warnings ? 14893 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14894 } 14895 /* 14896 Initialize Image and Magnify X images. 14897 */ 14898 windows->image.x=0; 14899 windows->image.y=0; 14900 windows->magnify.shape=MagickFalse; 14901 width=(unsigned int) display_image->columns; 14902 height=(unsigned int) display_image->rows; 14903 if ((display_image->columns != width) || (display_image->rows != height)) 14904 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14905 display_image->filename); 14906 status=XMakeImage(display,resource_info,&windows->image,display_image, 14907 width,height); 14908 if (status == MagickFalse) 14909 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14910 display_image->filename); 14911 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 14912 windows->magnify.width,windows->magnify.height); 14913 if (status == MagickFalse) 14914 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14915 display_image->filename); 14916 if (windows->magnify.mapped != MagickFalse) 14917 (void) XMapRaised(display,windows->magnify.id); 14918 if (windows->pan.mapped != MagickFalse) 14919 (void) XMapRaised(display,windows->pan.id); 14920 windows->image.window_changes.width=(int) display_image->columns; 14921 windows->image.window_changes.height=(int) display_image->rows; 14922 (void) XConfigureImage(display,resource_info,windows,display_image); 14923 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14924 (void) XSync(display,MagickFalse); 14925 /* 14926 Respond to events. 14927 */ 14928 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 14929 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 14930 update_time=0; 14931 if (resource_info->update != MagickFalse) 14932 { 14933 MagickBooleanType 14934 status; 14935 14936 /* 14937 Determine when file data was last modified. 14938 */ 14939 status=GetPathAttributes(display_image->filename,&attributes); 14940 if (status != MagickFalse) 14941 update_time=attributes.st_mtime; 14942 } 14943 *state&=(~FormerImageState); 14944 *state&=(~MontageImageState); 14945 *state&=(~NextImageState); 14946 do 14947 { 14948 /* 14949 Handle a window event. 14950 */ 14951 if (windows->image.mapped != MagickFalse) 14952 if ((display_image->delay != 0) || (resource_info->update != 0)) 14953 { 14954 if (timer < time((time_t *) NULL)) 14955 { 14956 if (resource_info->update == MagickFalse) 14957 *state|=NextImageState | ExitState; 14958 else 14959 { 14960 MagickBooleanType 14961 status; 14962 14963 /* 14964 Determine if image file was modified. 14965 */ 14966 status=GetPathAttributes(display_image->filename,&attributes); 14967 if (status != MagickFalse) 14968 if (update_time != attributes.st_mtime) 14969 { 14970 /* 14971 Redisplay image. 14972 */ 14973 (void) FormatLocaleString( 14974 resource_info->image_info->filename,MaxTextExtent, 14975 "%s:%s",display_image->magick, 14976 display_image->filename); 14977 nexus=ReadImage(resource_info->image_info, 14978 &display_image->exception); 14979 if (nexus != (Image *) NULL) 14980 { 14981 nexus=DestroyImage(nexus); 14982 *state|=NextImageState | ExitState; 14983 } 14984 } 14985 delay=display_image->delay/MagickMax( 14986 display_image->ticks_per_second,1L); 14987 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 14988 } 14989 } 14990 if (XEventsQueued(display,QueuedAfterFlush) == 0) 14991 { 14992 /* 14993 Do not block if delay > 0. 14994 */ 14995 XDelay(display,SuspendTime << 2); 14996 continue; 14997 } 14998 } 14999 timestamp=time((time_t *) NULL); 15000 (void) XNextEvent(display,&event); 15001 if (windows->image.stasis == MagickFalse) 15002 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15003 MagickTrue : MagickFalse; 15004 if (windows->magnify.stasis == MagickFalse) 15005 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15006 MagickTrue : MagickFalse; 15007 if (event.xany.window == windows->command.id) 15008 { 15009 /* 15010 Select a command from the Command widget. 15011 */ 15012 id=XCommandWidget(display,windows,CommandMenu,&event); 15013 if (id < 0) 15014 continue; 15015 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15016 command_type=CommandMenus[id]; 15017 if (id < MagickMenus) 15018 { 15019 /* 15020 Select a command from a pop-up menu. 15021 */ 15022 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15023 command); 15024 if (entry < 0) 15025 continue; 15026 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15027 command_type=Commands[id][entry]; 15028 } 15029 if (command_type != NullCommand) 15030 nexus=XMagickCommand(display,resource_info,windows,command_type, 15031 &display_image); 15032 continue; 15033 } 15034 switch (event.type) 15035 { 15036 case ButtonPress: 15037 { 15038 if (display_image->debug != MagickFalse) 15039 (void) LogMagickEvent(X11Event,GetMagickModule(), 15040 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15041 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15042 if ((event.xbutton.button == Button3) && 15043 (event.xbutton.state & Mod1Mask)) 15044 { 15045 /* 15046 Convert Alt-Button3 to Button2. 15047 */ 15048 event.xbutton.button=Button2; 15049 event.xbutton.state&=(~Mod1Mask); 15050 } 15051 if (event.xbutton.window == windows->backdrop.id) 15052 { 15053 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15054 event.xbutton.time); 15055 break; 15056 } 15057 if (event.xbutton.window == windows->image.id) 15058 { 15059 switch (event.xbutton.button) 15060 { 15061 case Button1: 15062 { 15063 if (resource_info->immutable) 15064 { 15065 /* 15066 Select a command from the Virtual menu. 15067 */ 15068 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15069 command); 15070 if (entry >= 0) 15071 nexus=XMagickCommand(display,resource_info,windows, 15072 VirtualCommands[entry],&display_image); 15073 break; 15074 } 15075 /* 15076 Map/unmap Command widget. 15077 */ 15078 if (windows->command.mapped != MagickFalse) 15079 (void) XWithdrawWindow(display,windows->command.id, 15080 windows->command.screen); 15081 else 15082 { 15083 (void) XCommandWidget(display,windows,CommandMenu, 15084 (XEvent *) NULL); 15085 (void) XMapRaised(display,windows->command.id); 15086 } 15087 break; 15088 } 15089 case Button2: 15090 { 15091 /* 15092 User pressed the image magnify button. 15093 */ 15094 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15095 &display_image); 15096 XMagnifyImage(display,windows,&event); 15097 break; 15098 } 15099 case Button3: 15100 { 15101 if (resource_info->immutable) 15102 { 15103 /* 15104 Select a command from the Virtual menu. 15105 */ 15106 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15107 command); 15108 if (entry >= 0) 15109 nexus=XMagickCommand(display,resource_info,windows, 15110 VirtualCommands[entry],&display_image); 15111 break; 15112 } 15113 if (display_image->montage != (char *) NULL) 15114 { 15115 /* 15116 Open or delete a tile from a visual image directory. 15117 */ 15118 nexus=XTileImage(display,resource_info,windows, 15119 display_image,&event); 15120 if (nexus != (Image *) NULL) 15121 *state|=MontageImageState | NextImageState | ExitState; 15122 vid_info.x=(short int) windows->image.x; 15123 vid_info.y=(short int) windows->image.y; 15124 break; 15125 } 15126 /* 15127 Select a command from the Short Cuts menu. 15128 */ 15129 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15130 command); 15131 if (entry >= 0) 15132 nexus=XMagickCommand(display,resource_info,windows, 15133 ShortCutsCommands[entry],&display_image); 15134 break; 15135 } 15136 case Button4: 15137 { 15138 /* 15139 Wheel up. 15140 */ 15141 XTranslateImage(display,windows,*image,XK_Up); 15142 break; 15143 } 15144 case Button5: 15145 { 15146 /* 15147 Wheel down. 15148 */ 15149 XTranslateImage(display,windows,*image,XK_Down); 15150 break; 15151 } 15152 default: 15153 break; 15154 } 15155 break; 15156 } 15157 if (event.xbutton.window == windows->magnify.id) 15158 { 15159 int 15160 factor; 15161 15162 static const char 15163 *MagnifyMenu[] = 15164 { 15165 "2", 15166 "4", 15167 "5", 15168 "6", 15169 "7", 15170 "8", 15171 "9", 15172 "3", 15173 (char *) NULL, 15174 }; 15175 15176 static KeySym 15177 MagnifyCommands[] = 15178 { 15179 XK_2, 15180 XK_4, 15181 XK_5, 15182 XK_6, 15183 XK_7, 15184 XK_8, 15185 XK_9, 15186 XK_3 15187 }; 15188 15189 /* 15190 Select a magnify factor from the pop-up menu. 15191 */ 15192 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15193 if (factor >= 0) 15194 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15195 break; 15196 } 15197 if (event.xbutton.window == windows->pan.id) 15198 { 15199 switch (event.xbutton.button) 15200 { 15201 case Button4: 15202 { 15203 /* 15204 Wheel up. 15205 */ 15206 XTranslateImage(display,windows,*image,XK_Up); 15207 break; 15208 } 15209 case Button5: 15210 { 15211 /* 15212 Wheel down. 15213 */ 15214 XTranslateImage(display,windows,*image,XK_Down); 15215 break; 15216 } 15217 default: 15218 { 15219 XPanImage(display,windows,&event); 15220 break; 15221 } 15222 } 15223 break; 15224 } 15225 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15226 1L); 15227 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15228 break; 15229 } 15230 case ButtonRelease: 15231 { 15232 if (display_image->debug != MagickFalse) 15233 (void) LogMagickEvent(X11Event,GetMagickModule(), 15234 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15235 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15236 break; 15237 } 15238 case ClientMessage: 15239 { 15240 if (display_image->debug != MagickFalse) 15241 (void) LogMagickEvent(X11Event,GetMagickModule(), 15242 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15243 event.xclient.message_type,event.xclient.format,(unsigned long) 15244 event.xclient.data.l[0]); 15245 if (event.xclient.message_type == windows->im_protocols) 15246 { 15247 if (*event.xclient.data.l == (long) windows->im_update_widget) 15248 { 15249 (void) CloneString(&windows->command.name,MagickTitle); 15250 windows->command.data=MagickMenus; 15251 (void) XCommandWidget(display,windows,CommandMenu, 15252 (XEvent *) NULL); 15253 break; 15254 } 15255 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15256 { 15257 /* 15258 Update graphic context and window colormap. 15259 */ 15260 for (i=0; i < (int) number_windows; i++) 15261 { 15262 if (magick_windows[i]->id == windows->icon.id) 15263 continue; 15264 context_values.background=pixel->background_color.pixel; 15265 context_values.foreground=pixel->foreground_color.pixel; 15266 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15267 context_mask,&context_values); 15268 (void) XChangeGC(display,magick_windows[i]->widget_context, 15269 context_mask,&context_values); 15270 context_values.background=pixel->foreground_color.pixel; 15271 context_values.foreground=pixel->background_color.pixel; 15272 context_values.plane_mask=context_values.background ^ 15273 context_values.foreground; 15274 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15275 (size_t) (context_mask | GCPlaneMask), 15276 &context_values); 15277 magick_windows[i]->attributes.background_pixel= 15278 pixel->background_color.pixel; 15279 magick_windows[i]->attributes.border_pixel= 15280 pixel->border_color.pixel; 15281 magick_windows[i]->attributes.colormap=map_info->colormap; 15282 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15283 (unsigned long) magick_windows[i]->mask, 15284 &magick_windows[i]->attributes); 15285 } 15286 if (windows->pan.mapped != MagickFalse) 15287 { 15288 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15289 windows->pan.pixmap); 15290 (void) XClearWindow(display,windows->pan.id); 15291 XDrawPanRectangle(display,windows); 15292 } 15293 if (windows->backdrop.id != (Window) NULL) 15294 (void) XInstallColormap(display,map_info->colormap); 15295 break; 15296 } 15297 if (*event.xclient.data.l == (long) windows->im_former_image) 15298 { 15299 *state|=FormerImageState | ExitState; 15300 break; 15301 } 15302 if (*event.xclient.data.l == (long) windows->im_next_image) 15303 { 15304 *state|=NextImageState | ExitState; 15305 break; 15306 } 15307 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15308 { 15309 *state|=RetainColorsState; 15310 break; 15311 } 15312 if (*event.xclient.data.l == (long) windows->im_exit) 15313 { 15314 *state|=ExitState; 15315 break; 15316 } 15317 break; 15318 } 15319 if (event.xclient.message_type == windows->dnd_protocols) 15320 { 15321 Atom 15322 selection, 15323 type; 15324 15325 int 15326 format, 15327 status; 15328 15329 unsigned char 15330 *data; 15331 15332 unsigned long 15333 after, 15334 length; 15335 15336 /* 15337 Display image named by the Drag-and-Drop selection. 15338 */ 15339 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15340 break; 15341 selection=XInternAtom(display,"DndSelection",MagickFalse); 15342 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15343 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15344 &length,&after,&data); 15345 if ((status != Success) || (length == 0)) 15346 break; 15347 if (*event.xclient.data.l == 2) 15348 { 15349 /* 15350 Offix DND. 15351 */ 15352 (void) CopyMagickString(resource_info->image_info->filename, 15353 (char *) data,MaxTextExtent); 15354 } 15355 else 15356 { 15357 /* 15358 XDND. 15359 */ 15360 if (strncmp((char *) data, "file:", 5) != 0) 15361 { 15362 (void) XFree((void *) data); 15363 break; 15364 } 15365 (void) CopyMagickString(resource_info->image_info->filename, 15366 ((char *) data)+5,MaxTextExtent); 15367 } 15368 nexus=ReadImage(resource_info->image_info, 15369 &display_image->exception); 15370 CatchException(&display_image->exception); 15371 if (nexus != (Image *) NULL) 15372 *state|=NextImageState | ExitState; 15373 (void) XFree((void *) data); 15374 break; 15375 } 15376 /* 15377 If client window delete message, exit. 15378 */ 15379 if (event.xclient.message_type != windows->wm_protocols) 15380 break; 15381 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15382 break; 15383 (void) XWithdrawWindow(display,event.xclient.window, 15384 visual_info->screen); 15385 if (event.xclient.window == windows->image.id) 15386 { 15387 *state|=ExitState; 15388 break; 15389 } 15390 if (event.xclient.window == windows->pan.id) 15391 { 15392 /* 15393 Restore original image size when pan window is deleted. 15394 */ 15395 windows->image.window_changes.width=windows->image.ximage->width; 15396 windows->image.window_changes.height=windows->image.ximage->height; 15397 (void) XConfigureImage(display,resource_info,windows, 15398 display_image); 15399 } 15400 break; 15401 } 15402 case ConfigureNotify: 15403 { 15404 if (display_image->debug != MagickFalse) 15405 (void) LogMagickEvent(X11Event,GetMagickModule(), 15406 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15407 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15408 event.xconfigure.y,event.xconfigure.send_event); 15409 if (event.xconfigure.window == windows->image.id) 15410 { 15411 /* 15412 Image window has a new configuration. 15413 */ 15414 if (event.xconfigure.send_event != 0) 15415 { 15416 XWindowChanges 15417 window_changes; 15418 15419 /* 15420 Position the transient windows relative of the Image window. 15421 */ 15422 if (windows->command.geometry == (char *) NULL) 15423 if (windows->command.mapped == MagickFalse) 15424 { 15425 windows->command.x=event.xconfigure.x- 15426 windows->command.width-25; 15427 windows->command.y=event.xconfigure.y; 15428 XConstrainWindowPosition(display,&windows->command); 15429 window_changes.x=windows->command.x; 15430 window_changes.y=windows->command.y; 15431 (void) XReconfigureWMWindow(display,windows->command.id, 15432 windows->command.screen,(unsigned int) (CWX | CWY), 15433 &window_changes); 15434 } 15435 if (windows->widget.geometry == (char *) NULL) 15436 if (windows->widget.mapped == MagickFalse) 15437 { 15438 windows->widget.x=event.xconfigure.x+ 15439 event.xconfigure.width/10; 15440 windows->widget.y=event.xconfigure.y+ 15441 event.xconfigure.height/10; 15442 XConstrainWindowPosition(display,&windows->widget); 15443 window_changes.x=windows->widget.x; 15444 window_changes.y=windows->widget.y; 15445 (void) XReconfigureWMWindow(display,windows->widget.id, 15446 windows->widget.screen,(unsigned int) (CWX | CWY), 15447 &window_changes); 15448 } 15449 if (windows->magnify.geometry == (char *) NULL) 15450 if (windows->magnify.mapped == MagickFalse) 15451 { 15452 windows->magnify.x=event.xconfigure.x+ 15453 event.xconfigure.width+25; 15454 windows->magnify.y=event.xconfigure.y; 15455 XConstrainWindowPosition(display,&windows->magnify); 15456 window_changes.x=windows->magnify.x; 15457 window_changes.y=windows->magnify.y; 15458 (void) XReconfigureWMWindow(display,windows->magnify.id, 15459 windows->magnify.screen,(unsigned int) (CWX | CWY), 15460 &window_changes); 15461 } 15462 if (windows->pan.geometry == (char *) NULL) 15463 if (windows->pan.mapped == MagickFalse) 15464 { 15465 windows->pan.x=event.xconfigure.x+ 15466 event.xconfigure.width+25; 15467 windows->pan.y=event.xconfigure.y+ 15468 windows->magnify.height+50; 15469 XConstrainWindowPosition(display,&windows->pan); 15470 window_changes.x=windows->pan.x; 15471 window_changes.y=windows->pan.y; 15472 (void) XReconfigureWMWindow(display,windows->pan.id, 15473 windows->pan.screen,(unsigned int) (CWX | CWY), 15474 &window_changes); 15475 } 15476 } 15477 if ((event.xconfigure.width == (int) windows->image.width) && 15478 (event.xconfigure.height == (int) windows->image.height)) 15479 break; 15480 windows->image.width=(unsigned int) event.xconfigure.width; 15481 windows->image.height=(unsigned int) event.xconfigure.height; 15482 windows->image.x=0; 15483 windows->image.y=0; 15484 if (display_image->montage != (char *) NULL) 15485 { 15486 windows->image.x=vid_info.x; 15487 windows->image.y=vid_info.y; 15488 } 15489 if ((windows->image.mapped != MagickFalse) && 15490 (windows->image.stasis != MagickFalse)) 15491 { 15492 /* 15493 Update image window configuration. 15494 */ 15495 windows->image.window_changes.width=event.xconfigure.width; 15496 windows->image.window_changes.height=event.xconfigure.height; 15497 (void) XConfigureImage(display,resource_info,windows, 15498 display_image); 15499 } 15500 /* 15501 Update pan window configuration. 15502 */ 15503 if ((event.xconfigure.width < windows->image.ximage->width) || 15504 (event.xconfigure.height < windows->image.ximage->height)) 15505 { 15506 (void) XMapRaised(display,windows->pan.id); 15507 XDrawPanRectangle(display,windows); 15508 } 15509 else 15510 if (windows->pan.mapped != MagickFalse) 15511 (void) XWithdrawWindow(display,windows->pan.id, 15512 windows->pan.screen); 15513 break; 15514 } 15515 if (event.xconfigure.window == windows->magnify.id) 15516 { 15517 unsigned int 15518 magnify; 15519 15520 /* 15521 Magnify window has a new configuration. 15522 */ 15523 windows->magnify.width=(unsigned int) event.xconfigure.width; 15524 windows->magnify.height=(unsigned int) event.xconfigure.height; 15525 if (windows->magnify.mapped == MagickFalse) 15526 break; 15527 magnify=1; 15528 while ((int) magnify <= event.xconfigure.width) 15529 magnify<<=1; 15530 while ((int) magnify <= event.xconfigure.height) 15531 magnify<<=1; 15532 magnify>>=1; 15533 if (((int) magnify != event.xconfigure.width) || 15534 ((int) magnify != event.xconfigure.height)) 15535 { 15536 window_changes.width=(int) magnify; 15537 window_changes.height=(int) magnify; 15538 (void) XReconfigureWMWindow(display,windows->magnify.id, 15539 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15540 &window_changes); 15541 break; 15542 } 15543 if ((windows->magnify.mapped != MagickFalse) && 15544 (windows->magnify.stasis != MagickFalse)) 15545 { 15546 status=XMakeImage(display,resource_info,&windows->magnify, 15547 display_image,windows->magnify.width,windows->magnify.height); 15548 XMakeMagnifyImage(display,windows); 15549 } 15550 break; 15551 } 15552 if ((windows->magnify.mapped != MagickFalse) && 15553 (event.xconfigure.window == windows->pan.id)) 15554 { 15555 /* 15556 Pan icon window has a new configuration. 15557 */ 15558 if (event.xconfigure.send_event != 0) 15559 { 15560 windows->pan.x=event.xconfigure.x; 15561 windows->pan.y=event.xconfigure.y; 15562 } 15563 windows->pan.width=(unsigned int) event.xconfigure.width; 15564 windows->pan.height=(unsigned int) event.xconfigure.height; 15565 break; 15566 } 15567 if (event.xconfigure.window == windows->icon.id) 15568 { 15569 /* 15570 Icon window has a new configuration. 15571 */ 15572 windows->icon.width=(unsigned int) event.xconfigure.width; 15573 windows->icon.height=(unsigned int) event.xconfigure.height; 15574 break; 15575 } 15576 break; 15577 } 15578 case DestroyNotify: 15579 { 15580 /* 15581 Group leader has exited. 15582 */ 15583 if (display_image->debug != MagickFalse) 15584 (void) LogMagickEvent(X11Event,GetMagickModule(), 15585 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15586 if (event.xdestroywindow.window == windows->group_leader.id) 15587 { 15588 *state|=ExitState; 15589 break; 15590 } 15591 break; 15592 } 15593 case EnterNotify: 15594 { 15595 /* 15596 Selectively install colormap. 15597 */ 15598 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15599 if (event.xcrossing.mode != NotifyUngrab) 15600 XInstallColormap(display,map_info->colormap); 15601 break; 15602 } 15603 case Expose: 15604 { 15605 if (display_image->debug != MagickFalse) 15606 (void) LogMagickEvent(X11Event,GetMagickModule(), 15607 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15608 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15609 event.xexpose.y); 15610 /* 15611 Refresh windows that are now exposed. 15612 */ 15613 if ((event.xexpose.window == windows->image.id) && 15614 (windows->image.mapped != MagickFalse)) 15615 { 15616 XRefreshWindow(display,&windows->image,&event); 15617 delay=display_image->delay/MagickMax( 15618 display_image->ticks_per_second,1L); 15619 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15620 break; 15621 } 15622 if ((event.xexpose.window == windows->magnify.id) && 15623 (windows->magnify.mapped != MagickFalse)) 15624 { 15625 XMakeMagnifyImage(display,windows); 15626 break; 15627 } 15628 if (event.xexpose.window == windows->pan.id) 15629 { 15630 XDrawPanRectangle(display,windows); 15631 break; 15632 } 15633 if (event.xexpose.window == windows->icon.id) 15634 { 15635 XRefreshWindow(display,&windows->icon,&event); 15636 break; 15637 } 15638 break; 15639 } 15640 case KeyPress: 15641 { 15642 int 15643 length; 15644 15645 /* 15646 Respond to a user key press. 15647 */ 15648 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15649 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15650 *(command+length)='\0'; 15651 if (display_image->debug != MagickFalse) 15652 (void) LogMagickEvent(X11Event,GetMagickModule(), 15653 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15654 key_symbol,command); 15655 if (event.xkey.window == windows->image.id) 15656 { 15657 command_type=XImageWindowCommand(display,resource_info,windows, 15658 event.xkey.state,key_symbol,&display_image); 15659 if (command_type != NullCommand) 15660 nexus=XMagickCommand(display,resource_info,windows,command_type, 15661 &display_image); 15662 } 15663 if (event.xkey.window == windows->magnify.id) 15664 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15665 if (event.xkey.window == windows->pan.id) 15666 { 15667 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15668 (void) XWithdrawWindow(display,windows->pan.id, 15669 windows->pan.screen); 15670 else 15671 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15672 XTextViewWidget(display,resource_info,windows,MagickFalse, 15673 "Help Viewer - Image Pan",ImagePanHelp); 15674 else 15675 XTranslateImage(display,windows,*image,key_symbol); 15676 } 15677 delay=display_image->delay/MagickMax( 15678 display_image->ticks_per_second,1L); 15679 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15680 break; 15681 } 15682 case KeyRelease: 15683 { 15684 /* 15685 Respond to a user key release. 15686 */ 15687 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15688 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15689 if (display_image->debug != MagickFalse) 15690 (void) LogMagickEvent(X11Event,GetMagickModule(), 15691 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15692 break; 15693 } 15694 case LeaveNotify: 15695 { 15696 /* 15697 Selectively uninstall colormap. 15698 */ 15699 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15700 if (event.xcrossing.mode != NotifyUngrab) 15701 XUninstallColormap(display,map_info->colormap); 15702 break; 15703 } 15704 case MapNotify: 15705 { 15706 if (display_image->debug != MagickFalse) 15707 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15708 event.xmap.window); 15709 if (event.xmap.window == windows->backdrop.id) 15710 { 15711 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15712 CurrentTime); 15713 windows->backdrop.mapped=MagickTrue; 15714 break; 15715 } 15716 if (event.xmap.window == windows->image.id) 15717 { 15718 if (windows->backdrop.id != (Window) NULL) 15719 (void) XInstallColormap(display,map_info->colormap); 15720 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15721 { 15722 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15723 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15724 } 15725 if (((int) windows->image.width < windows->image.ximage->width) || 15726 ((int) windows->image.height < windows->image.ximage->height)) 15727 (void) XMapRaised(display,windows->pan.id); 15728 windows->image.mapped=MagickTrue; 15729 break; 15730 } 15731 if (event.xmap.window == windows->magnify.id) 15732 { 15733 XMakeMagnifyImage(display,windows); 15734 windows->magnify.mapped=MagickTrue; 15735 (void) XWithdrawWindow(display,windows->info.id, 15736 windows->info.screen); 15737 break; 15738 } 15739 if (event.xmap.window == windows->pan.id) 15740 { 15741 XMakePanImage(display,resource_info,windows,display_image); 15742 windows->pan.mapped=MagickTrue; 15743 break; 15744 } 15745 if (event.xmap.window == windows->info.id) 15746 { 15747 windows->info.mapped=MagickTrue; 15748 break; 15749 } 15750 if (event.xmap.window == windows->icon.id) 15751 { 15752 MagickBooleanType 15753 taint; 15754 15755 /* 15756 Create an icon image. 15757 */ 15758 taint=display_image->taint; 15759 XMakeStandardColormap(display,icon_visual,icon_resources, 15760 display_image,icon_map,icon_pixel); 15761 (void) XMakeImage(display,icon_resources,&windows->icon, 15762 display_image,windows->icon.width,windows->icon.height); 15763 display_image->taint=taint; 15764 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15765 windows->icon.pixmap); 15766 (void) XClearWindow(display,windows->icon.id); 15767 (void) XWithdrawWindow(display,windows->info.id, 15768 windows->info.screen); 15769 windows->icon.mapped=MagickTrue; 15770 break; 15771 } 15772 if (event.xmap.window == windows->command.id) 15773 { 15774 windows->command.mapped=MagickTrue; 15775 break; 15776 } 15777 if (event.xmap.window == windows->popup.id) 15778 { 15779 windows->popup.mapped=MagickTrue; 15780 break; 15781 } 15782 if (event.xmap.window == windows->widget.id) 15783 { 15784 windows->widget.mapped=MagickTrue; 15785 break; 15786 } 15787 break; 15788 } 15789 case MappingNotify: 15790 { 15791 (void) XRefreshKeyboardMapping(&event.xmapping); 15792 break; 15793 } 15794 case NoExpose: 15795 break; 15796 case PropertyNotify: 15797 { 15798 Atom 15799 type; 15800 15801 int 15802 format, 15803 status; 15804 15805 unsigned char 15806 *data; 15807 15808 unsigned long 15809 after, 15810 length; 15811 15812 if (display_image->debug != MagickFalse) 15813 (void) LogMagickEvent(X11Event,GetMagickModule(), 15814 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15815 event.xproperty.atom,event.xproperty.state); 15816 if (event.xproperty.atom != windows->im_remote_command) 15817 break; 15818 /* 15819 Display image named by the remote command protocol. 15820 */ 15821 status=XGetWindowProperty(display,event.xproperty.window, 15822 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15823 AnyPropertyType,&type,&format,&length,&after,&data); 15824 if ((status != Success) || (length == 0)) 15825 break; 15826 if (LocaleCompare((char *) data,"-quit") == 0) 15827 { 15828 XClientMessage(display,windows->image.id,windows->im_protocols, 15829 windows->im_exit,CurrentTime); 15830 (void) XFree((void *) data); 15831 break; 15832 } 15833 (void) CopyMagickString(resource_info->image_info->filename, 15834 (char *) data,MaxTextExtent); 15835 (void) XFree((void *) data); 15836 nexus=ReadImage(resource_info->image_info,&display_image->exception); 15837 CatchException(&display_image->exception); 15838 if (nexus != (Image *) NULL) 15839 *state|=NextImageState | ExitState; 15840 break; 15841 } 15842 case ReparentNotify: 15843 { 15844 if (display_image->debug != MagickFalse) 15845 (void) LogMagickEvent(X11Event,GetMagickModule(), 15846 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15847 event.xreparent.window); 15848 break; 15849 } 15850 case UnmapNotify: 15851 { 15852 if (display_image->debug != MagickFalse) 15853 (void) LogMagickEvent(X11Event,GetMagickModule(), 15854 "Unmap Notify: 0x%lx",event.xunmap.window); 15855 if (event.xunmap.window == windows->backdrop.id) 15856 { 15857 windows->backdrop.mapped=MagickFalse; 15858 break; 15859 } 15860 if (event.xunmap.window == windows->image.id) 15861 { 15862 windows->image.mapped=MagickFalse; 15863 break; 15864 } 15865 if (event.xunmap.window == windows->magnify.id) 15866 { 15867 windows->magnify.mapped=MagickFalse; 15868 break; 15869 } 15870 if (event.xunmap.window == windows->pan.id) 15871 { 15872 windows->pan.mapped=MagickFalse; 15873 break; 15874 } 15875 if (event.xunmap.window == windows->info.id) 15876 { 15877 windows->info.mapped=MagickFalse; 15878 break; 15879 } 15880 if (event.xunmap.window == windows->icon.id) 15881 { 15882 if (map_info->colormap == icon_map->colormap) 15883 XConfigureImageColormap(display,resource_info,windows, 15884 display_image); 15885 (void) XFreeStandardColormap(display,icon_visual,icon_map, 15886 icon_pixel); 15887 windows->icon.mapped=MagickFalse; 15888 break; 15889 } 15890 if (event.xunmap.window == windows->command.id) 15891 { 15892 windows->command.mapped=MagickFalse; 15893 break; 15894 } 15895 if (event.xunmap.window == windows->popup.id) 15896 { 15897 if (windows->backdrop.id != (Window) NULL) 15898 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15899 CurrentTime); 15900 windows->popup.mapped=MagickFalse; 15901 break; 15902 } 15903 if (event.xunmap.window == windows->widget.id) 15904 { 15905 if (windows->backdrop.id != (Window) NULL) 15906 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15907 CurrentTime); 15908 windows->widget.mapped=MagickFalse; 15909 break; 15910 } 15911 break; 15912 } 15913 default: 15914 { 15915 if (display_image->debug != MagickFalse) 15916 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 15917 event.type); 15918 break; 15919 } 15920 } 15921 } while (!(*state & ExitState)); 15922 if ((*state & ExitState) == 0) 15923 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 15924 &display_image); 15925 else 15926 if (resource_info->confirm_edit != MagickFalse) 15927 { 15928 /* 15929 Query user if image has changed. 15930 */ 15931 if ((resource_info->immutable == MagickFalse) && 15932 (display_image->taint != MagickFalse)) 15933 { 15934 int 15935 status; 15936 15937 status=XConfirmWidget(display,windows,"Your image changed.", 15938 "Do you want to save it"); 15939 if (status == 0) 15940 *state&=(~ExitState); 15941 else 15942 if (status > 0) 15943 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 15944 &display_image); 15945 } 15946 } 15947 if ((windows->visual_info->klass == GrayScale) || 15948 (windows->visual_info->klass == PseudoColor) || 15949 (windows->visual_info->klass == DirectColor)) 15950 { 15951 /* 15952 Withdraw pan and Magnify window. 15953 */ 15954 if (windows->info.mapped != MagickFalse) 15955 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15956 if (windows->magnify.mapped != MagickFalse) 15957 (void) XWithdrawWindow(display,windows->magnify.id, 15958 windows->magnify.screen); 15959 if (windows->command.mapped != MagickFalse) 15960 (void) XWithdrawWindow(display,windows->command.id, 15961 windows->command.screen); 15962 } 15963 if (windows->pan.mapped != MagickFalse) 15964 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 15965 if (resource_info->backdrop == MagickFalse) 15966 if (windows->backdrop.mapped) 15967 { 15968 (void) XWithdrawWindow(display,windows->backdrop.id, 15969 windows->backdrop.screen); 15970 (void) XDestroyWindow(display,windows->backdrop.id); 15971 windows->backdrop.id=(Window) NULL; 15972 (void) XWithdrawWindow(display,windows->image.id, 15973 windows->image.screen); 15974 (void) XDestroyWindow(display,windows->image.id); 15975 windows->image.id=(Window) NULL; 15976 } 15977 XSetCursorState(display,windows,MagickTrue); 15978 XCheckRefreshWindows(display,windows); 15979 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 15980 *state&=(~ExitState); 15981 if (*state & ExitState) 15982 { 15983 /* 15984 Free Standard Colormap. 15985 */ 15986 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 15987 if (resource_info->map_type == (char *) NULL) 15988 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 15989 /* 15990 Free X resources. 15991 */ 15992 if (resource_info->copy_image != (Image *) NULL) 15993 { 15994 resource_info->copy_image=DestroyImage(resource_info->copy_image); 15995 resource_info->copy_image=NewImageList(); 15996 } 15997 DestroyXResources(); 15998 } 15999 (void) XSync(display,MagickFalse); 16000 /* 16001 Restore our progress monitor and warning handlers. 16002 */ 16003 (void) SetErrorHandler(warning_handler); 16004 (void) SetWarningHandler(warning_handler); 16005 /* 16006 Change to home directory. 16007 */ 16008 directory=getcwd(working_directory,MaxTextExtent); 16009 (void) directory; 16010 { 16011 int 16012 status; 16013 16014 status=chdir(resource_info->home_directory); 16015 if (status == -1) 16016 (void) ThrowMagickException(&display_image->exception,GetMagickModule(), 16017 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 16018 } 16019 *image=display_image; 16020 return(nexus); 16021} 16022#else 16023 16024/* 16025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16026% % 16027% % 16028% % 16029+ D i s p l a y I m a g e s % 16030% % 16031% % 16032% % 16033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16034% 16035% DisplayImages() displays an image sequence to any X window screen. It 16036% returns a value other than 0 if successful. Check the exception member 16037% of image to determine the reason for any failure. 16038% 16039% The format of the DisplayImages method is: 16040% 16041% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16042% Image *images) 16043% 16044% A description of each parameter follows: 16045% 16046% o image_info: the image info. 16047% 16048% o image: the image. 16049% 16050*/ 16051MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16052 Image *image) 16053{ 16054 assert(image_info != (const ImageInfo *) NULL); 16055 assert(image_info->signature == MagickSignature); 16056 assert(image != (Image *) NULL); 16057 assert(image->signature == MagickSignature); 16058 if (image->debug != MagickFalse) 16059 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16060 (void) ThrowMagickException(&image->exception,GetMagickModule(), 16061 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)", 16062 image->filename); 16063 return(MagickFalse); 16064} 16065 16066/* 16067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16068% % 16069% % 16070% % 16071+ R e m o t e D i s p l a y C o m m a n d % 16072% % 16073% % 16074% % 16075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16076% 16077% RemoteDisplayCommand() encourages a remote display program to display the 16078% specified image filename. 16079% 16080% The format of the RemoteDisplayCommand method is: 16081% 16082% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16083% const char *window,const char *filename,ExceptionInfo *exception) 16084% 16085% A description of each parameter follows: 16086% 16087% o image_info: the image info. 16088% 16089% o window: Specifies the name or id of an X window. 16090% 16091% o filename: the name of the image filename to display. 16092% 16093% o exception: return any errors or warnings in this structure. 16094% 16095*/ 16096MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16097 const char *window,const char *filename,ExceptionInfo *exception) 16098{ 16099 assert(image_info != (const ImageInfo *) NULL); 16100 assert(image_info->signature == MagickSignature); 16101 assert(filename != (char *) NULL); 16102 (void) window; 16103 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16104 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16105 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16106 return(MagickFalse); 16107} 16108#endif 16109