1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % DDDD IIIII SSSSS PPPP L AAA Y Y % 7 % D D I SS P P L A A Y Y % 8 % D D I SSS PPPP L AAAAA Y % 9 % D D I SS P L A A Y % 10 % DDDD IIIII SSSSS P LLLLL A A Y % 11 % % 12 % % 13 % MagickCore Methods to Interactively Display and Edit an Image % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2016 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 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/artifact.h" 45 #include "MagickCore/attribute.h" 46 #include "MagickCore/blob.h" 47 #include "MagickCore/cache.h" 48 #include "MagickCore/cache-private.h" 49 #include "MagickCore/channel.h" 50 #include "MagickCore/client.h" 51 #include "MagickCore/color.h" 52 #include "MagickCore/colorspace.h" 53 #include "MagickCore/composite.h" 54 #include "MagickCore/constitute.h" 55 #include "MagickCore/decorate.h" 56 #include "MagickCore/delegate.h" 57 #include "MagickCore/display.h" 58 #include "MagickCore/display-private.h" 59 #include "MagickCore/distort.h" 60 #include "MagickCore/draw.h" 61 #include "MagickCore/effect.h" 62 #include "MagickCore/enhance.h" 63 #include "MagickCore/exception.h" 64 #include "MagickCore/exception-private.h" 65 #include "MagickCore/fx.h" 66 #include "MagickCore/geometry.h" 67 #include "MagickCore/image.h" 68 #include "MagickCore/image-private.h" 69 #include "MagickCore/list.h" 70 #include "MagickCore/log.h" 71 #include "MagickCore/magick.h" 72 #include "MagickCore/memory_.h" 73 #include "MagickCore/monitor.h" 74 #include "MagickCore/monitor-private.h" 75 #include "MagickCore/montage.h" 76 #include "MagickCore/nt-base-private.h" 77 #include "MagickCore/option.h" 78 #include "MagickCore/paint.h" 79 #include "MagickCore/pixel.h" 80 #include "MagickCore/pixel-accessor.h" 81 #include "MagickCore/property.h" 82 #include "MagickCore/quantum.h" 83 #include "MagickCore/quantum-private.h" 84 #include "MagickCore/resize.h" 85 #include "MagickCore/resource_.h" 86 #include "MagickCore/shear.h" 87 #include "MagickCore/segment.h" 88 #include "MagickCore/statistic.h" 89 #include "MagickCore/string_.h" 90 #include "MagickCore/string-private.h" 91 #include "MagickCore/transform.h" 92 #include "MagickCore/transform-private.h" 93 #include "MagickCore/threshold.h" 94 #include "MagickCore/utility.h" 95 #include "MagickCore/utility-private.h" 96 #include "MagickCore/version.h" 97 #include "MagickCore/widget.h" 98 #include "MagickCore/widget-private.h" 99 #include "MagickCore/xwindow.h" 100 #include "MagickCore/xwindow-private.h" 101 102 #if defined(MAGICKCORE_X11_DELEGATE) 104 /* 105 Define declarations. 106 */ 107 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 108 109 /* 111 Constant declarations. 112 */ 113 static const unsigned char 114 HighlightBitmap[8] = 115 { 116 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 117 }, 118 OpaqueBitmap[8] = 119 { 120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 121 }, 122 ShadowBitmap[8] = 123 { 124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 125 }; 126 127 static const char 128 *PageSizes[] = 129 { 130 "Letter", 131 "Tabloid", 132 "Ledger", 133 "Legal", 134 "Statement", 135 "Executive", 136 "A3", 137 "A4", 138 "A5", 139 "B4", 140 "B5", 141 "Folio", 142 "Quarto", 143 "10x14", 144 (char *) NULL 145 }; 146 147 /* 149 Help widget declarations. 150 */ 151 static const char 152 *ImageAnnotateHelp[] = 153 { 154 "In annotate mode, the Command widget has these options:", 155 "", 156 " Font Name", 157 " fixed", 158 " variable", 159 " 5x8", 160 " 6x10", 161 " 7x13bold", 162 " 8x13bold", 163 " 9x15bold", 164 " 10x20", 165 " 12x24", 166 " Browser...", 167 " Font Color", 168 " black", 169 " blue", 170 " cyan", 171 " green", 172 " gray", 173 " red", 174 " magenta", 175 " yellow", 176 " white", 177 " transparent", 178 " Browser...", 179 " Font Color", 180 " black", 181 " blue", 182 " cyan", 183 " green", 184 " gray", 185 " red", 186 " magenta", 187 " yellow", 188 " white", 189 " transparent", 190 " Browser...", 191 " Rotate Text", 192 " -90", 193 " -45", 194 " -30", 195 " 0", 196 " 30", 197 " 45", 198 " 90", 199 " 180", 200 " Dialog...", 201 " Help", 202 " Dismiss", 203 "", 204 "Choose a font name from the Font Name sub-menu. Additional", 205 "font names can be specified with the font browser. You can", 206 "change the menu names by setting the X resources font1", 207 "through font9.", 208 "", 209 "Choose a font color from the Font Color sub-menu.", 210 "Additional font colors can be specified with the color", 211 "browser. You can change the menu colors by setting the X", 212 "resources pen1 through pen9.", 213 "", 214 "If you select the color browser and press Grab, you can", 215 "choose the font color by moving the pointer to the desired", 216 "color on the screen and press any button.", 217 "", 218 "If you choose to rotate the text, choose Rotate Text from the", 219 "menu and select an angle. Typically you will only want to", 220 "rotate one line of text at a time. Depending on the angle you", 221 "choose, subsequent lines may end up overwriting each other.", 222 "", 223 "Choosing a font and its color is optional. The default font", 224 "is fixed and the default color is black. However, you must", 225 "choose a location to begin entering text and press button 1.", 226 "An underscore character will appear at the location of the", 227 "pointer. The cursor changes to a pencil to indicate you are", 228 "in text mode. To exit immediately, press Dismiss.", 229 "", 230 "In text mode, any key presses will display the character at", 231 "the location of the underscore and advance the underscore", 232 "cursor. Enter your text and once completed press Apply to", 233 "finish your image annotation. To correct errors press BACK", 234 "SPACE. To delete an entire line of text, press DELETE. Any", 235 "text that exceeds the boundaries of the image window is", 236 "automagically continued onto the next line.", 237 "", 238 "The actual color you request for the font is saved in the", 239 "image. However, the color that appears in your image window", 240 "may be different. For example, on a monochrome screen the", 241 "text will appear black or white even if you choose the color", 242 "red as the font color. However, the image saved to a file", 243 "with -write is written with red lettering. To assure the", 244 "correct color text in the final image, any PseudoClass image", 245 "is promoted to DirectClass (see miff(5)). To force a", 246 "PseudoClass image to remain PseudoClass, use -colors.", 247 (char *) NULL, 248 }, 249 *ImageChopHelp[] = 250 { 251 "In chop mode, the Command widget has these options:", 252 "", 253 " Direction", 254 " horizontal", 255 " vertical", 256 " Help", 257 " Dismiss", 258 "", 259 "If the you choose the horizontal direction (this the", 260 "default), the area of the image between the two horizontal", 261 "endpoints of the chop line is removed. Otherwise, the area", 262 "of the image between the two vertical endpoints of the chop", 263 "line is removed.", 264 "", 265 "Select a location within the image window to begin your chop,", 266 "press and hold any button. Next, move the pointer to", 267 "another location in the image. As you move a line will", 268 "connect the initial location and the pointer. When you", 269 "release the button, the area within the image to chop is", 270 "determined by which direction you choose from the Command", 271 "widget.", 272 "", 273 "To cancel the image chopping, move the pointer back to the", 274 "starting point of the line and release the button.", 275 (char *) NULL, 276 }, 277 *ImageColorEditHelp[] = 278 { 279 "In color edit mode, the Command widget has these options:", 280 "", 281 " Method", 282 " point", 283 " replace", 284 " floodfill", 285 " filltoborder", 286 " reset", 287 " Pixel Color", 288 " black", 289 " blue", 290 " cyan", 291 " green", 292 " gray", 293 " red", 294 " magenta", 295 " yellow", 296 " white", 297 " Browser...", 298 " Border Color", 299 " black", 300 " blue", 301 " cyan", 302 " green", 303 " gray", 304 " red", 305 " magenta", 306 " yellow", 307 " white", 308 " Browser...", 309 " Fuzz", 310 " 0%", 311 " 2%", 312 " 5%", 313 " 10%", 314 " 15%", 315 " Dialog...", 316 " Undo", 317 " Help", 318 " Dismiss", 319 "", 320 "Choose a color editing method from the Method sub-menu", 321 "of the Command widget. The point method recolors any pixel", 322 "selected with the pointer until the button is released. The", 323 "replace method recolors any pixel that matches the color of", 324 "the pixel you select with a button press. Floodfill recolors", 325 "any pixel that matches the color of the pixel you select with", 326 "a button press and is a neighbor. Whereas filltoborder recolors", 327 "any neighbor pixel that is not the border color. Finally reset", 328 "changes the entire image to the designated color.", 329 "", 330 "Next, choose a pixel color from the Pixel Color sub-menu.", 331 "Additional pixel colors can be specified with the color", 332 "browser. You can change the menu colors by setting the X", 333 "resources pen1 through pen9.", 334 "", 335 "Now press button 1 to select a pixel within the image window", 336 "to change its color. Additional pixels may be recolored as", 337 "prescribed by the method you choose.", 338 "", 339 "If the Magnify widget is mapped, it can be helpful in positioning", 340 "your pointer within the image (refer to button 2).", 341 "", 342 "The actual color you request for the pixels is saved in the", 343 "image. However, the color that appears in your image window", 344 "may be different. For example, on a monochrome screen the", 345 "pixel will appear black or white even if you choose the", 346 "color red as the pixel color. However, the image saved to a", 347 "file with -write is written with red pixels. To assure the", 348 "correct color text in the final image, any PseudoClass image", 349 "is promoted to DirectClass (see miff(5)). To force a", 350 "PseudoClass image to remain PseudoClass, use -colors.", 351 (char *) NULL, 352 }, 353 *ImageCompositeHelp[] = 354 { 355 "First a widget window is displayed requesting you to enter an", 356 "image name. Press Composite, Grab or type a file name.", 357 "Press Cancel if you choose not to create a composite image.", 358 "When you choose Grab, move the pointer to the desired window", 359 "and press any button.", 360 "", 361 "If the Composite image does not have any matte information,", 362 "you are informed and the file browser is displayed again.", 363 "Enter the name of a mask image. The image is typically", 364 "grayscale and the same size as the composite image. If the", 365 "image is not grayscale, it is converted to grayscale and the", 366 "resulting intensities are used as matte information.", 367 "", 368 "A small window appears showing the location of the cursor in", 369 "the image window. You are now in composite mode. To exit", 370 "immediately, press Dismiss. In composite mode, the Command", 371 "widget has these options:", 372 "", 373 " Operators", 374 " Over", 375 " In", 376 " Out", 377 " Atop", 378 " Xor", 379 " Plus", 380 " Minus", 381 " Add", 382 " Subtract", 383 " Difference", 384 " Multiply", 385 " Bumpmap", 386 " Copy", 387 " CopyRed", 388 " CopyGreen", 389 " CopyBlue", 390 " CopyOpacity", 391 " Clear", 392 " Dissolve", 393 " Displace", 394 " Help", 395 " Dismiss", 396 "", 397 "Choose a composite operation from the Operators sub-menu of", 398 "the Command widget. How each operator behaves is described", 399 "below. Image window is the image currently displayed on", 400 "your X server and image is the image obtained with the File", 401 "Browser widget.", 402 "", 403 "Over The result is the union of the two image shapes,", 404 " with image obscuring image window in the region of", 405 " overlap.", 406 "", 407 "In The result is simply image cut by the shape of", 408 " image window. None of the image data of image", 409 " window is in the result.", 410 "", 411 "Out The resulting image is image with the shape of", 412 " image window cut out.", 413 "", 414 "Atop The result is the same shape as image image window,", 415 " with image obscuring image window where the image", 416 " shapes overlap. Note this differs from over", 417 " because the portion of image outside image window's", 418 " shape does not appear in the result.", 419 "", 420 "Xor The result is the image data from both image and", 421 " image window that is outside the overlap region.", 422 " The overlap region is blank.", 423 "", 424 "Plus The result is just the sum of the image data.", 425 " Output values are cropped to QuantumRange (no overflow).", 426 "", 427 "Minus The result of image - image window, with underflow", 428 " cropped to zero.", 429 "", 430 "Add The result of image + image window, with overflow", 431 " wrapping around (mod 256).", 432 "", 433 "Subtract The result of image - image window, with underflow", 434 " wrapping around (mod 256). The add and subtract", 435 " operators can be used to perform reversible", 436 " transformations.", 437 "", 438 "Difference", 439 " The result of abs(image - image window). This", 440 " useful for comparing two very similar images.", 441 "", 442 "Multiply", 443 " The result of image * image window. This", 444 " useful for the creation of drop-shadows.", 445 "", 446 "Bumpmap The result of surface normals from image * image", 447 " window.", 448 "", 449 "Copy The resulting image is image window replaced with", 450 " image. Here the matte information is ignored.", 451 "", 452 "CopyRed The red layer of the image window is replace with", 453 " the red layer of the image. The other layers are", 454 " untouched.", 455 "", 456 "CopyGreen", 457 " The green layer of the image window is replace with", 458 " the green layer of the image. The other layers are", 459 " untouched.", 460 "", 461 "CopyBlue The blue layer of the image window is replace with", 462 " the blue layer of the image. The other layers are", 463 " untouched.", 464 "", 465 "CopyOpacity", 466 " The matte layer of the image window is replace with", 467 " the matte layer of the image. The other layers are", 468 " untouched.", 469 "", 470 "The image compositor requires a matte, or alpha channel in", 471 "the image for some operations. This extra channel usually", 472 "defines a mask which represents a sort of a cookie-cutter", 473 "for the image. This the case when matte is opaque (full", 474 "coverage) for pixels inside the shape, zero outside, and", 475 "between 0 and QuantumRange on the boundary. If image does not", 476 "have a matte channel, it is initialized with 0 for any pixel", 477 "matching in color to pixel location (0,0), otherwise QuantumRange.", 478 "", 479 "If you choose Dissolve, the composite operator becomes Over. The", 480 "image matte channel percent transparency is initialized to factor.", 481 "The image window is initialized to (100-factor). Where factor is the", 482 "value you specify in the Dialog widget.", 483 "", 484 "Displace shifts the image pixels as defined by a displacement", 485 "map. With this option, image is used as a displacement map.", 486 "Black, within the displacement map, is a maximum positive", 487 "displacement. White is a maximum negative displacement and", 488 "middle gray is neutral. The displacement is scaled to determine", 489 "the pixel shift. By default, the displacement applies in both the", 490 "horizontal and vertical directions. However, if you specify a mask,", 491 "image is the horizontal X displacement and mask the vertical Y", 492 "displacement.", 493 "", 494 "Note that matte information for image window is not retained", 495 "for colormapped X server visuals (e.g. StaticColor,", 496 "StaticColor, GrayScale, PseudoColor). Correct compositing", 497 "behavior may require a TrueColor or DirectColor visual or a", 498 "Standard Colormap.", 499 "", 500 "Choosing a composite operator is optional. The default", 501 "operator is replace. However, you must choose a location to", 502 "composite your image and press button 1. Press and hold the", 503 "button before releasing and an outline of the image will", 504 "appear to help you identify your location.", 505 "", 506 "The actual colors of the composite image is saved. However,", 507 "the color that appears in image window may be different.", 508 "For example, on a monochrome screen image window will appear", 509 "black or white even though your composited image may have", 510 "many colors. If the image is saved to a file it is written", 511 "with the correct colors. To assure the correct colors are", 512 "saved in the final image, any PseudoClass image is promoted", 513 "to DirectClass (see miff(5)). To force a PseudoClass image", 514 "to remain PseudoClass, use -colors.", 515 (char *) NULL, 516 }, 517 *ImageCutHelp[] = 518 { 519 "In cut mode, the Command widget has these options:", 520 "", 521 " Help", 522 " Dismiss", 523 "", 524 "To define a cut region, press button 1 and drag. The", 525 "cut region is defined by a highlighted rectangle that", 526 "expands or contracts as it follows the pointer. Once you", 527 "are satisfied with the cut region, release the button.", 528 "You are now in rectify mode. In rectify mode, the Command", 529 "widget has these options:", 530 "", 531 " Cut", 532 " Help", 533 " Dismiss", 534 "", 535 "You can make adjustments by moving the pointer to one of the", 536 "cut rectangle corners, pressing a button, and dragging.", 537 "Finally, press Cut to commit your copy region. To", 538 "exit without cutting the image, press Dismiss.", 539 (char *) NULL, 540 }, 541 *ImageCopyHelp[] = 542 { 543 "In copy mode, the Command widget has these options:", 544 "", 545 " Help", 546 " Dismiss", 547 "", 548 "To define a copy region, press button 1 and drag. The", 549 "copy region is defined by a highlighted rectangle that", 550 "expands or contracts as it follows the pointer. Once you", 551 "are satisfied with the copy region, release the button.", 552 "You are now in rectify mode. In rectify mode, the Command", 553 "widget has these options:", 554 "", 555 " Copy", 556 " Help", 557 " Dismiss", 558 "", 559 "You can make adjustments by moving the pointer to one of the", 560 "copy rectangle corners, pressing a button, and dragging.", 561 "Finally, press Copy to commit your copy region. To", 562 "exit without copying the image, press Dismiss.", 563 (char *) NULL, 564 }, 565 *ImageCropHelp[] = 566 { 567 "In crop mode, the Command widget has these options:", 568 "", 569 " Help", 570 " Dismiss", 571 "", 572 "To define a cropping region, press button 1 and drag. The", 573 "cropping region is defined by a highlighted rectangle that", 574 "expands or contracts as it follows the pointer. Once you", 575 "are satisfied with the cropping region, release the button.", 576 "You are now in rectify mode. In rectify mode, the Command", 577 "widget has these options:", 578 "", 579 " Crop", 580 " Help", 581 " Dismiss", 582 "", 583 "You can make adjustments by moving the pointer to one of the", 584 "cropping rectangle corners, pressing a button, and dragging.", 585 "Finally, press Crop to commit your cropping region. To", 586 "exit without cropping the image, press Dismiss.", 587 (char *) NULL, 588 }, 589 *ImageDrawHelp[] = 590 { 591 "The cursor changes to a crosshair to indicate you are in", 592 "draw mode. To exit immediately, press Dismiss. In draw mode,", 593 "the Command widget has these options:", 594 "", 595 " Element", 596 " point", 597 " line", 598 " rectangle", 599 " fill rectangle", 600 " circle", 601 " fill circle", 602 " ellipse", 603 " fill ellipse", 604 " polygon", 605 " fill polygon", 606 " Color", 607 " black", 608 " blue", 609 " cyan", 610 " green", 611 " gray", 612 " red", 613 " magenta", 614 " yellow", 615 " white", 616 " transparent", 617 " Browser...", 618 " Stipple", 619 " Brick", 620 " Diagonal", 621 " Scales", 622 " Vertical", 623 " Wavy", 624 " Translucent", 625 " Opaque", 626 " Open...", 627 " Width", 628 " 1", 629 " 2", 630 " 4", 631 " 8", 632 " 16", 633 " Dialog...", 634 " Undo", 635 " Help", 636 " Dismiss", 637 "", 638 "Choose a drawing primitive from the Element sub-menu.", 639 "", 640 "Choose a color from the Color sub-menu. Additional", 641 "colors can be specified with the color browser.", 642 "", 643 "If you choose the color browser and press Grab, you can", 644 "select the color by moving the pointer to the desired", 645 "color on the screen and press any button. The transparent", 646 "color updates the image matte channel and is useful for", 647 "image compositing.", 648 "", 649 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 650 "Additional stipples can be specified with the file browser.", 651 "Stipples obtained from the file browser must be on disk in the", 652 "X11 bitmap format.", 653 "", 654 "Choose a width, if appropriate, from the Width sub-menu. To", 655 "choose a specific width select the Dialog widget.", 656 "", 657 "Choose a point in the Image window and press button 1 and", 658 "hold. Next, move the pointer to another location in the", 659 "image. As you move, a line connects the initial location and", 660 "the pointer. When you release the button, the image is", 661 "updated with the primitive you just drew. For polygons, the", 662 "image is updated when you press and release the button without", 663 "moving the pointer.", 664 "", 665 "To cancel image drawing, move the pointer back to the", 666 "starting point of the line and release the button.", 667 (char *) NULL, 668 }, 669 *DisplayHelp[] = 670 { 671 "BUTTONS", 672 " The effects of each button press is described below. Three", 673 " buttons are required. If you have a two button mouse,", 674 " button 1 and 3 are returned. Press ALT and button 3 to", 675 " simulate button 2.", 676 "", 677 " 1 Press this button to map or unmap the Command widget.", 678 "", 679 " 2 Press and drag to define a region of the image to", 680 " magnify.", 681 "", 682 " 3 Press and drag to choose from a select set of commands.", 683 " This button behaves differently if the image being", 684 " displayed is a visual image directory. Here, choose a", 685 " particular tile of the directory and press this button and", 686 " drag to select a command from a pop-up menu. Choose from", 687 " these menu items:", 688 "", 689 " Open", 690 " Next", 691 " Former", 692 " Delete", 693 " Update", 694 "", 695 " If you choose Open, the image represented by the tile is", 696 " displayed. To return to the visual image directory, choose", 697 " Next from the Command widget. Next and Former moves to the", 698 " next or former image respectively. Choose Delete to delete", 699 " a particular image tile. Finally, choose Update to", 700 " synchronize all the image tiles with their respective", 701 " images.", 702 "", 703 "COMMAND WIDGET", 704 " The Command widget lists a number of sub-menus and commands.", 705 " They are", 706 "", 707 " File", 708 " Open...", 709 " Next", 710 " Former", 711 " Select...", 712 " Save...", 713 " Print...", 714 " Delete...", 715 " New...", 716 " Visual Directory...", 717 " Quit", 718 " Edit", 719 " Undo", 720 " Redo", 721 " Cut", 722 " Copy", 723 " Paste", 724 " View", 725 " Half Size", 726 " Original Size", 727 " Double Size", 728 " Resize...", 729 " Apply", 730 " Refresh", 731 " Restore", 732 " Transform", 733 " Crop", 734 " Chop", 735 " Flop", 736 " Flip", 737 " Rotate Right", 738 " Rotate Left", 739 " Rotate...", 740 " Shear...", 741 " Roll...", 742 " Trim Edges", 743 " Enhance", 744 " Brightness...", 745 " Saturation...", 746 " Hue...", 747 " Gamma...", 748 " Sharpen...", 749 " Dull", 750 " Contrast Stretch...", 751 " Sigmoidal Contrast...", 752 " Normalize", 753 " Equalize", 754 " Negate", 755 " Grayscale", 756 " Map...", 757 " Quantize...", 758 " Effects", 759 " Despeckle", 760 " Emboss", 761 " Reduce Noise", 762 " Add Noise", 763 " Sharpen...", 764 " Blur...", 765 " Threshold...", 766 " Edge Detect...", 767 " Spread...", 768 " Shade...", 769 " Painting...", 770 " Segment...", 771 " F/X", 772 " Solarize...", 773 " Sepia Tone...", 774 " Swirl...", 775 " Implode...", 776 " Vignette...", 777 " Wave...", 778 " Oil Painting...", 779 " Charcoal Drawing...", 780 " Image Edit", 781 " Annotate...", 782 " Draw...", 783 " Color...", 784 " Matte...", 785 " Composite...", 786 " Add Border...", 787 " Add Frame...", 788 " Comment...", 789 " Launch...", 790 " Region of Interest...", 791 " Miscellany", 792 " Image Info", 793 " Zoom Image", 794 " Show Preview...", 795 " Show Histogram", 796 " Show Matte", 797 " Background...", 798 " Slide Show", 799 " Preferences...", 800 " Help", 801 " Overview", 802 " Browse Documentation", 803 " About Display", 804 "", 805 " Menu items with a indented triangle have a sub-menu. They", 806 " are represented above as the indented items. To access a", 807 " sub-menu item, move the pointer to the appropriate menu and", 808 " press a button and drag. When you find the desired sub-menu", 809 " item, release the button and the command is executed. Move", 810 " the pointer away from the sub-menu if you decide not to", 811 " execute a particular command.", 812 "", 813 "KEYBOARD ACCELERATORS", 814 " Accelerators are one or two key presses that effect a", 815 " particular command. The keyboard accelerators that", 816 " display(1) understands is:", 817 "", 818 " Ctl+O Press to open an image from a file.", 819 "", 820 " space Press to display the next image.", 821 "", 822 " If the image is a multi-paged document such as a Postscript", 823 " document, you can skip ahead several pages by preceding", 824 " this command with a number. For example to display the", 825 " third page beyond the current page, press 3<space>.", 826 "", 827 " backspace Press to display the former image.", 828 "", 829 " If the image is a multi-paged document such as a Postscript", 830 " document, you can skip behind several pages by preceding", 831 " this command with a number. For example to display the", 832 " third page preceding the current page, press 3<backspace>.", 833 "", 834 " Ctl+S Press to write the image to a file.", 835 "", 836 " Ctl+P Press to print the image to a Postscript printer.", 837 "", 838 " Ctl+D Press to delete an image file.", 839 "", 840 " Ctl+N Press to create a blank canvas.", 841 "", 842 " Ctl+Q Press to discard all images and exit program.", 843 "", 844 " Ctl+Z Press to undo last image transformation.", 845 "", 846 " Ctl+R Press to redo last image transformation.", 847 "", 848 " Ctl+X Press to cut a region of the image.", 849 "", 850 " Ctl+C Press to copy a region of the image.", 851 "", 852 " Ctl+V Press to paste a region to the image.", 853 "", 854 " < Press to half the image size.", 855 "", 856 " - Press to return to the original image size.", 857 "", 858 " > Press to double the image size.", 859 "", 860 " % Press to resize the image to a width and height you", 861 " specify.", 862 "", 863 "Cmd-A Press to make any image transformations permanent." 864 "", 865 " By default, any image size transformations are applied", 866 " to the original image to create the image displayed on", 867 " the X server. However, the transformations are not", 868 " permanent (i.e. the original image does not change", 869 " size only the X image does). For example, if you", 870 " press > the X image will appear to double in size,", 871 " but the original image will in fact remain the same size.", 872 " To force the original image to double in size, press >", 873 " followed by Cmd-A.", 874 "", 875 " @ Press to refresh the image window.", 876 "", 877 " C Press to cut out a rectangular region of the image.", 878 "", 879 " [ Press to chop the image.", 880 "", 881 " H Press to flop image in the horizontal direction.", 882 "", 883 " V Press to flip image in the vertical direction.", 884 "", 885 " / Press to rotate the image 90 degrees clockwise.", 886 "", 887 " \\ Press to rotate the image 90 degrees counter-clockwise.", 888 "", 889 " * Press to rotate the image the number of degrees you", 890 " specify.", 891 "", 892 " S Press to shear the image the number of degrees you", 893 " specify.", 894 "", 895 " R Press to roll the image.", 896 "", 897 " T Press to trim the image edges.", 898 "", 899 " Shft-H Press to vary the image hue.", 900 "", 901 " Shft-S Press to vary the color saturation.", 902 "", 903 " Shft-L Press to vary the color brightness.", 904 "", 905 " Shft-G Press to gamma correct the image.", 906 "", 907 " Shft-C Press to sharpen the image contrast.", 908 "", 909 " Shft-Z Press to dull the image contrast.", 910 "", 911 " = Press to perform histogram equalization on the image.", 912 "", 913 " Shft-N Press to perform histogram normalization on the image.", 914 "", 915 " Shft-~ Press to negate the colors of the image.", 916 "", 917 " . Press to convert the image colors to gray.", 918 "", 919 " Shft-# Press to set the maximum number of unique colors in the", 920 " image.", 921 "", 922 " F2 Press to reduce the speckles in an image.", 923 "", 924 " F3 Press to eliminate peak noise from an image.", 925 "", 926 " F4 Press to add noise to an image.", 927 "", 928 " F5 Press to sharpen an image.", 929 "", 930 " F6 Press to delete an image file.", 931 "", 932 " F7 Press to threshold the image.", 933 "", 934 " F8 Press to detect edges within an image.", 935 "", 936 " F9 Press to emboss an image.", 937 "", 938 " F10 Press to displace pixels by a random amount.", 939 "", 940 " F11 Press to negate all pixels above the threshold level.", 941 "", 942 " F12 Press to shade the image using a distant light source.", 943 "", 944 " F13 Press to lighten or darken image edges to create a 3-D effect.", 945 "", 946 " F14 Press to segment the image by color.", 947 "", 948 " Meta-S Press to swirl image pixels about the center.", 949 "", 950 " Meta-I Press to implode image pixels about the center.", 951 "", 952 " Meta-W Press to alter an image along a sine wave.", 953 "", 954 " Meta-P Press to simulate an oil painting.", 955 "", 956 " Meta-C Press to simulate a charcoal drawing.", 957 "", 958 " Alt-A Press to annotate the image with text.", 959 "", 960 " Alt-D Press to draw on an image.", 961 "", 962 " Alt-P Press to edit an image pixel color.", 963 "", 964 " Alt-M Press to edit the image matte information.", 965 "", 966 " Alt-V Press to composite the image with another.", 967 "", 968 " Alt-B Press to add a border to the image.", 969 "", 970 " Alt-F Press to add an ornamental border to the image.", 971 "", 972 " Alt-Shft-!", 973 " Press to add an image comment.", 974 "", 975 " Ctl-A Press to apply image processing techniques to a region", 976 " of interest.", 977 "", 978 " Shft-? Press to display information about the image.", 979 "", 980 " Shft-+ Press to map the zoom image window.", 981 "", 982 " Shft-P Press to preview an image enhancement, effect, or f/x.", 983 "", 984 " F1 Press to display helpful information about display(1).", 985 "", 986 " Find Press to browse documentation about ImageMagick.", 987 "", 988 " 1-9 Press to change the level of magnification.", 989 "", 990 " Use the arrow keys to move the image one pixel up, down,", 991 " left, or right within the magnify window. Be sure to first", 992 " map the magnify window by pressing button 2.", 993 "", 994 " Press ALT and one of the arrow keys to trim off one pixel", 995 " from any side of the image.", 996 (char *) NULL, 997 }, 998 *ImageMatteEditHelp[] = 999 { 1000 "Matte information within an image is useful for some", 1001 "operations such as image compositing (See IMAGE", 1002 "COMPOSITING). This extra channel usually defines a mask", 1003 "which represents a sort of a cookie-cutter for the image.", 1004 "This the case when matte is opaque (full coverage) for", 1005 "pixels inside the shape, zero outside, and between 0 and", 1006 "QuantumRange on the boundary.", 1007 "", 1008 "A small window appears showing the location of the cursor in", 1009 "the image window. You are now in matte edit mode. To exit", 1010 "immediately, press Dismiss. In matte edit mode, the Command", 1011 "widget has these options:", 1012 "", 1013 " Method", 1014 " point", 1015 " replace", 1016 " floodfill", 1017 " filltoborder", 1018 " reset", 1019 " Border Color", 1020 " black", 1021 " blue", 1022 " cyan", 1023 " green", 1024 " gray", 1025 " red", 1026 " magenta", 1027 " yellow", 1028 " white", 1029 " Browser...", 1030 " Fuzz", 1031 " 0%", 1032 " 2%", 1033 " 5%", 1034 " 10%", 1035 " 15%", 1036 " Dialog...", 1037 " Matte", 1038 " Opaque", 1039 " Transparent", 1040 " Dialog...", 1041 " Undo", 1042 " Help", 1043 " Dismiss", 1044 "", 1045 "Choose a matte editing method from the Method sub-menu of", 1046 "the Command widget. The point method changes the matte value", 1047 "of any pixel selected with the pointer until the button is", 1048 "is released. The replace method changes the matte value of", 1049 "any pixel that matches the color of the pixel you select with", 1050 "a button press. Floodfill changes the matte value of any pixel", 1051 "that matches the color of the pixel you select with a button", 1052 "press and is a neighbor. Whereas filltoborder changes the matte", 1053 "value any neighbor pixel that is not the border color. Finally", 1054 "reset changes the entire image to the designated matte value.", 1055 "", 1056 "Choose Matte Value and pick Opaque or Transarent. For other values", 1057 "select the Dialog entry. Here a dialog appears requesting a matte", 1058 "value. The value you select is assigned as the opacity value of the", 1059 "selected pixel or pixels.", 1060 "", 1061 "Now, press any button to select a pixel within the image", 1062 "window to change its matte value.", 1063 "", 1064 "If the Magnify widget is mapped, it can be helpful in positioning", 1065 "your pointer within the image (refer to button 2).", 1066 "", 1067 "Matte information is only valid in a DirectClass image.", 1068 "Therefore, any PseudoClass image is promoted to DirectClass", 1069 "(see miff(5)). Note that matte information for PseudoClass", 1070 "is not retained for colormapped X server visuals (e.g.", 1071 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1072 "immediately save your image to a file (refer to Write).", 1073 "Correct matte editing behavior may require a TrueColor or", 1074 "DirectColor visual or a Standard Colormap.", 1075 (char *) NULL, 1076 }, 1077 *ImagePanHelp[] = 1078 { 1079 "When an image exceeds the width or height of the X server", 1080 "screen, display maps a small panning icon. The rectangle", 1081 "within the panning icon shows the area that is currently", 1082 "displayed in the image window. To pan about the image,", 1083 "press any button and drag the pointer within the panning", 1084 "icon. The pan rectangle moves with the pointer and the", 1085 "image window is updated to reflect the location of the", 1086 "rectangle within the panning icon. When you have selected", 1087 "the area of the image you wish to view, release the button.", 1088 "", 1089 "Use the arrow keys to pan the image one pixel up, down,", 1090 "left, or right within the image window.", 1091 "", 1092 "The panning icon is withdrawn if the image becomes smaller", 1093 "than the dimensions of the X server screen.", 1094 (char *) NULL, 1095 }, 1096 *ImagePasteHelp[] = 1097 { 1098 "A small window appears showing the location of the cursor in", 1099 "the image window. You are now in paste mode. To exit", 1100 "immediately, press Dismiss. In paste mode, the Command", 1101 "widget has these options:", 1102 "", 1103 " Operators", 1104 " over", 1105 " in", 1106 " out", 1107 " atop", 1108 " xor", 1109 " plus", 1110 " minus", 1111 " add", 1112 " subtract", 1113 " difference", 1114 " replace", 1115 " Help", 1116 " Dismiss", 1117 "", 1118 "Choose a composite operation from the Operators sub-menu of", 1119 "the Command widget. How each operator behaves is described", 1120 "below. Image window is the image currently displayed on", 1121 "your X server and image is the image obtained with the File", 1122 "Browser widget.", 1123 "", 1124 "Over The result is the union of the two image shapes,", 1125 " with image obscuring image window in the region of", 1126 " overlap.", 1127 "", 1128 "In The result is simply image cut by the shape of", 1129 " image window. None of the image data of image", 1130 " window is in the result.", 1131 "", 1132 "Out The resulting image is image with the shape of", 1133 " image window cut out.", 1134 "", 1135 "Atop The result is the same shape as image image window,", 1136 " with image obscuring image window where the image", 1137 " shapes overlap. Note this differs from over", 1138 " because the portion of image outside image window's", 1139 " shape does not appear in the result.", 1140 "", 1141 "Xor The result is the image data from both image and", 1142 " image window that is outside the overlap region.", 1143 " The overlap region is blank.", 1144 "", 1145 "Plus The result is just the sum of the image data.", 1146 " Output values are cropped to QuantumRange (no overflow).", 1147 " This operation is independent of the matte", 1148 " channels.", 1149 "", 1150 "Minus The result of image - image window, with underflow", 1151 " cropped to zero.", 1152 "", 1153 "Add The result of image + image window, with overflow", 1154 " wrapping around (mod 256).", 1155 "", 1156 "Subtract The result of image - image window, with underflow", 1157 " wrapping around (mod 256). The add and subtract", 1158 " operators can be used to perform reversible", 1159 " transformations.", 1160 "", 1161 "Difference", 1162 " The result of abs(image - image window). This", 1163 " useful for comparing two very similar images.", 1164 "", 1165 "Copy The resulting image is image window replaced with", 1166 " image. Here the matte information is ignored.", 1167 "", 1168 "CopyRed The red layer of the image window is replace with", 1169 " the red layer of the image. The other layers are", 1170 " untouched.", 1171 "", 1172 "CopyGreen", 1173 " The green layer of the image window is replace with", 1174 " the green layer of the image. The other layers are", 1175 " untouched.", 1176 "", 1177 "CopyBlue The blue layer of the image window is replace with", 1178 " the blue layer of the image. The other layers are", 1179 " untouched.", 1180 "", 1181 "CopyOpacity", 1182 " The matte layer of the image window is replace with", 1183 " the matte layer of the image. The other layers are", 1184 " untouched.", 1185 "", 1186 "The image compositor requires a matte, or alpha channel in", 1187 "the image for some operations. This extra channel usually", 1188 "defines a mask which represents a sort of a cookie-cutter", 1189 "for the image. This the case when matte is opaque (full", 1190 "coverage) for pixels inside the shape, zero outside, and", 1191 "between 0 and QuantumRange on the boundary. If image does not", 1192 "have a matte channel, it is initialized with 0 for any pixel", 1193 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1194 "", 1195 "Note that matte information for image window is not retained", 1196 "for colormapped X server visuals (e.g. StaticColor,", 1197 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1198 "behavior may require a TrueColor or DirectColor visual or a", 1199 "Standard Colormap.", 1200 "", 1201 "Choosing a composite operator is optional. The default", 1202 "operator is replace. However, you must choose a location to", 1203 "paste your image and press button 1. Press and hold the", 1204 "button before releasing and an outline of the image will", 1205 "appear to help you identify your location.", 1206 "", 1207 "The actual colors of the pasted image is saved. However,", 1208 "the color that appears in image window may be different.", 1209 "For example, on a monochrome screen image window will appear", 1210 "black or white even though your pasted image may have", 1211 "many colors. If the image is saved to a file it is written", 1212 "with the correct colors. To assure the correct colors are", 1213 "saved in the final image, any PseudoClass image is promoted", 1214 "to DirectClass (see miff(5)). To force a PseudoClass image", 1215 "to remain PseudoClass, use -colors.", 1216 (char *) NULL, 1217 }, 1218 *ImageROIHelp[] = 1219 { 1220 "In region of interest mode, the Command widget has these", 1221 "options:", 1222 "", 1223 " Help", 1224 " Dismiss", 1225 "", 1226 "To define a region of interest, press button 1 and drag.", 1227 "The region of interest is defined by a highlighted rectangle", 1228 "that expands or contracts as it follows the pointer. Once", 1229 "you are satisfied with the region of interest, release the", 1230 "button. You are now in apply mode. In apply mode the", 1231 "Command widget has these options:", 1232 "", 1233 " File", 1234 " Save...", 1235 " Print...", 1236 " Edit", 1237 " Undo", 1238 " Redo", 1239 " Transform", 1240 " Flop", 1241 " Flip", 1242 " Rotate Right", 1243 " Rotate Left", 1244 " Enhance", 1245 " Hue...", 1246 " Saturation...", 1247 " Brightness...", 1248 " Gamma...", 1249 " Spiff", 1250 " Dull", 1251 " Contrast Stretch", 1252 " Sigmoidal Contrast...", 1253 " Normalize", 1254 " Equalize", 1255 " Negate", 1256 " Grayscale", 1257 " Map...", 1258 " Quantize...", 1259 " Effects", 1260 " Despeckle", 1261 " Emboss", 1262 " Reduce Noise", 1263 " Sharpen...", 1264 " Blur...", 1265 " Threshold...", 1266 " Edge Detect...", 1267 " Spread...", 1268 " Shade...", 1269 " Raise...", 1270 " Segment...", 1271 " F/X", 1272 " Solarize...", 1273 " Sepia Tone...", 1274 " Swirl...", 1275 " Implode...", 1276 " Vignette...", 1277 " Wave...", 1278 " Oil Painting...", 1279 " Charcoal Drawing...", 1280 " Miscellany", 1281 " Image Info", 1282 " Zoom Image", 1283 " Show Preview...", 1284 " Show Histogram", 1285 " Show Matte", 1286 " Help", 1287 " Dismiss", 1288 "", 1289 "You can make adjustments to the region of interest by moving", 1290 "the pointer to one of the rectangle corners, pressing a", 1291 "button, and dragging. Finally, choose an image processing", 1292 "technique from the Command widget. You can choose more than", 1293 "one image processing technique to apply to an area.", 1294 "Alternatively, you can move the region of interest before", 1295 "applying another image processing technique. To exit, press", 1296 "Dismiss.", 1297 (char *) NULL, 1298 }, 1299 *ImageRotateHelp[] = 1300 { 1301 "In rotate mode, the Command widget has these options:", 1302 "", 1303 " Pixel Color", 1304 " black", 1305 " blue", 1306 " cyan", 1307 " green", 1308 " gray", 1309 " red", 1310 " magenta", 1311 " yellow", 1312 " white", 1313 " Browser...", 1314 " Direction", 1315 " horizontal", 1316 " vertical", 1317 " Help", 1318 " Dismiss", 1319 "", 1320 "Choose a background color from the Pixel Color sub-menu.", 1321 "Additional background colors can be specified with the color", 1322 "browser. You can change the menu colors by setting the X", 1323 "resources pen1 through pen9.", 1324 "", 1325 "If you choose the color browser and press Grab, you can", 1326 "select the background color by moving the pointer to the", 1327 "desired color on the screen and press any button.", 1328 "", 1329 "Choose a point in the image window and press this button and", 1330 "hold. Next, move the pointer to another location in the", 1331 "image. As you move a line connects the initial location and", 1332 "the pointer. When you release the button, the degree of", 1333 "image rotation is determined by the slope of the line you", 1334 "just drew. The slope is relative to the direction you", 1335 "choose from the Direction sub-menu of the Command widget.", 1336 "", 1337 "To cancel the image rotation, move the pointer back to the", 1338 "starting point of the line and release the button.", 1339 (char *) NULL, 1340 }; 1341 1342 /* 1344 Enumeration declarations. 1345 */ 1346 typedef enum 1347 { 1348 CopyMode, 1349 CropMode, 1350 CutMode 1351 } ClipboardMode; 1352 1353 typedef enum 1354 { 1355 OpenCommand, 1356 NextCommand, 1357 FormerCommand, 1358 SelectCommand, 1359 SaveCommand, 1360 PrintCommand, 1361 DeleteCommand, 1362 NewCommand, 1363 VisualDirectoryCommand, 1364 QuitCommand, 1365 UndoCommand, 1366 RedoCommand, 1367 CutCommand, 1368 CopyCommand, 1369 PasteCommand, 1370 HalfSizeCommand, 1371 OriginalSizeCommand, 1372 DoubleSizeCommand, 1373 ResizeCommand, 1374 ApplyCommand, 1375 RefreshCommand, 1376 RestoreCommand, 1377 CropCommand, 1378 ChopCommand, 1379 FlopCommand, 1380 FlipCommand, 1381 RotateRightCommand, 1382 RotateLeftCommand, 1383 RotateCommand, 1384 ShearCommand, 1385 RollCommand, 1386 TrimCommand, 1387 HueCommand, 1388 SaturationCommand, 1389 BrightnessCommand, 1390 GammaCommand, 1391 SpiffCommand, 1392 DullCommand, 1393 ContrastStretchCommand, 1394 SigmoidalContrastCommand, 1395 NormalizeCommand, 1396 EqualizeCommand, 1397 NegateCommand, 1398 GrayscaleCommand, 1399 MapCommand, 1400 QuantizeCommand, 1401 DespeckleCommand, 1402 EmbossCommand, 1403 ReduceNoiseCommand, 1404 AddNoiseCommand, 1405 SharpenCommand, 1406 BlurCommand, 1407 ThresholdCommand, 1408 EdgeDetectCommand, 1409 SpreadCommand, 1410 ShadeCommand, 1411 RaiseCommand, 1412 SegmentCommand, 1413 SolarizeCommand, 1414 SepiaToneCommand, 1415 SwirlCommand, 1416 ImplodeCommand, 1417 VignetteCommand, 1418 WaveCommand, 1419 OilPaintCommand, 1420 CharcoalDrawCommand, 1421 AnnotateCommand, 1422 DrawCommand, 1423 ColorCommand, 1424 MatteCommand, 1425 CompositeCommand, 1426 AddBorderCommand, 1427 AddFrameCommand, 1428 CommentCommand, 1429 LaunchCommand, 1430 RegionofInterestCommand, 1431 ROIHelpCommand, 1432 ROIDismissCommand, 1433 InfoCommand, 1434 ZoomCommand, 1435 ShowPreviewCommand, 1436 ShowHistogramCommand, 1437 ShowMatteCommand, 1438 BackgroundCommand, 1439 SlideShowCommand, 1440 PreferencesCommand, 1441 HelpCommand, 1442 BrowseDocumentationCommand, 1443 VersionCommand, 1444 SaveToUndoBufferCommand, 1445 FreeBuffersCommand, 1446 NullCommand 1447 } CommandType; 1448 1449 typedef enum 1450 { 1451 AnnotateNameCommand, 1452 AnnotateFontColorCommand, 1453 AnnotateBackgroundColorCommand, 1454 AnnotateRotateCommand, 1455 AnnotateHelpCommand, 1456 AnnotateDismissCommand, 1457 TextHelpCommand, 1458 TextApplyCommand, 1459 ChopDirectionCommand, 1460 ChopHelpCommand, 1461 ChopDismissCommand, 1462 HorizontalChopCommand, 1463 VerticalChopCommand, 1464 ColorEditMethodCommand, 1465 ColorEditColorCommand, 1466 ColorEditBorderCommand, 1467 ColorEditFuzzCommand, 1468 ColorEditUndoCommand, 1469 ColorEditHelpCommand, 1470 ColorEditDismissCommand, 1471 CompositeOperatorsCommand, 1472 CompositeDissolveCommand, 1473 CompositeDisplaceCommand, 1474 CompositeHelpCommand, 1475 CompositeDismissCommand, 1476 CropHelpCommand, 1477 CropDismissCommand, 1478 RectifyCopyCommand, 1479 RectifyHelpCommand, 1480 RectifyDismissCommand, 1481 DrawElementCommand, 1482 DrawColorCommand, 1483 DrawStippleCommand, 1484 DrawWidthCommand, 1485 DrawUndoCommand, 1486 DrawHelpCommand, 1487 DrawDismissCommand, 1488 MatteEditMethod, 1489 MatteEditBorderCommand, 1490 MatteEditFuzzCommand, 1491 MatteEditValueCommand, 1492 MatteEditUndoCommand, 1493 MatteEditHelpCommand, 1494 MatteEditDismissCommand, 1495 PasteOperatorsCommand, 1496 PasteHelpCommand, 1497 PasteDismissCommand, 1498 RotateColorCommand, 1499 RotateDirectionCommand, 1500 RotateCropCommand, 1501 RotateSharpenCommand, 1502 RotateHelpCommand, 1503 RotateDismissCommand, 1504 HorizontalRotateCommand, 1505 VerticalRotateCommand, 1506 TileLoadCommand, 1507 TileNextCommand, 1508 TileFormerCommand, 1509 TileDeleteCommand, 1510 TileUpdateCommand 1511 } ModeType; 1512 1513 /* 1515 Stipples. 1516 */ 1517 #define BricksWidth 20 1518 #define BricksHeight 20 1519 #define DiagonalWidth 16 1520 #define DiagonalHeight 16 1521 #define HighlightWidth 8 1522 #define HighlightHeight 8 1523 #define OpaqueWidth 8 1524 #define OpaqueHeight 8 1525 #define ScalesWidth 16 1526 #define ScalesHeight 16 1527 #define ShadowWidth 8 1528 #define ShadowHeight 8 1529 #define VerticalWidth 16 1530 #define VerticalHeight 16 1531 #define WavyWidth 16 1532 #define WavyHeight 16 1533 1534 /* 1536 Constant declaration. 1537 */ 1538 static const int 1539 RoiDelta = 8; 1540 1541 static const unsigned char 1542 BricksBitmap[] = 1543 { 1544 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1545 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1546 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1547 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1548 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1549 }, 1550 DiagonalBitmap[] = 1551 { 1552 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1553 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1554 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1555 }, 1556 ScalesBitmap[] = 1557 { 1558 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1559 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1560 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1561 }, 1562 VerticalBitmap[] = 1563 { 1564 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1565 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1566 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1567 }, 1568 WavyBitmap[] = 1569 { 1570 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1571 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1572 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1573 }; 1574 1575 /* 1577 Function prototypes. 1578 */ 1579 static CommandType 1580 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1581 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1582 1583 static Image 1584 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1585 Image **,ExceptionInfo *), 1586 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1587 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1588 ExceptionInfo *), 1589 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1590 ExceptionInfo *); 1591 1592 static MagickBooleanType 1593 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1594 ExceptionInfo *), 1595 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1596 ExceptionInfo *), 1597 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1598 ExceptionInfo *), 1599 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1600 ExceptionInfo *), 1601 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1602 ExceptionInfo *), 1603 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1604 ExceptionInfo *), 1605 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1606 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1607 ExceptionInfo *), 1608 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1609 ExceptionInfo *), 1610 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1611 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1612 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1613 ExceptionInfo *), 1614 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1615 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1616 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1617 1618 static void 1619 XDrawPanRectangle(Display *,XWindows *), 1620 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1621 ExceptionInfo *), 1622 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1623 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1624 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1625 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1626 const KeySym,ExceptionInfo *), 1627 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1628 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1629 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1630 1631 /* 1633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1634 % % 1635 % % 1636 % % 1637 % D i s p l a y I m a g e s % 1638 % % 1639 % % 1640 % % 1641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1642 % 1643 % DisplayImages() displays an image sequence to any X window screen. It 1644 % returns a value other than 0 if successful. Check the exception member 1645 % of image to determine the reason for any failure. 1646 % 1647 % The format of the DisplayImages method is: 1648 % 1649 % MagickBooleanType DisplayImages(const ImageInfo *image_info, 1650 % Image *images,ExceptionInfo *exception) 1651 % 1652 % A description of each parameter follows: 1653 % 1654 % o image_info: the image info. 1655 % 1656 % o image: the image. 1657 % 1658 % o exception: return any errors or warnings in this structure. 1659 % 1660 */ 1661 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1662 Image *images,ExceptionInfo *exception) 1663 { 1664 char 1665 *argv[1]; 1666 1667 Display 1668 *display; 1669 1670 Image 1671 *image; 1672 1673 register ssize_t 1674 i; 1675 1676 size_t 1677 state; 1678 1679 XrmDatabase 1680 resource_database; 1681 1682 XResourceInfo 1683 resource_info; 1684 1685 assert(image_info != (const ImageInfo *) NULL); 1686 assert(image_info->signature == MagickCoreSignature); 1687 assert(images != (Image *) NULL); 1688 assert(images->signature == MagickCoreSignature); 1689 if (images->debug != MagickFalse ) 1690 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1691 display=XOpenDisplay(image_info->server_name); 1692 if (display == (Display *) NULL) 1693 { 1694 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1695 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1696 return(MagickFalse); 1697 } 1698 if (exception->severity != UndefinedException) 1699 CatchException(exception); 1700 (void) XSetErrorHandler(XError); 1701 resource_database=XGetResourceDatabase(display,GetClientName()); 1702 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1703 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1704 if (image_info->page != (char *) NULL) 1705 resource_info.image_geometry=AcquireString(image_info->page); 1706 resource_info.immutable=MagickTrue; 1707 argv[0]=AcquireString(GetClientName()); 1708 state=DefaultState; 1709 for (i=0; (state & ExitState) == 0; i++) 1710 { 1711 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1712 break; 1713 image=GetImageFromList(images,i % GetImageListLength(images)); 1714 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1715 } 1716 (void) SetErrorHandler((ErrorHandler) NULL); 1717 (void) SetWarningHandler((WarningHandler) NULL); 1718 argv[0]=DestroyString(argv[0]); 1719 (void) XCloseDisplay(display); 1720 XDestroyResourceInfo(&resource_info); 1721 if (exception->severity != UndefinedException) 1722 return(MagickFalse); 1723 return(MagickTrue); 1724 } 1725 1726 /* 1728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1729 % % 1730 % % 1731 % % 1732 % R e m o t e D i s p l a y C o m m a n d % 1733 % % 1734 % % 1735 % % 1736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1737 % 1738 % RemoteDisplayCommand() encourages a remote display program to display the 1739 % specified image filename. 1740 % 1741 % The format of the RemoteDisplayCommand method is: 1742 % 1743 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1744 % const char *window,const char *filename,ExceptionInfo *exception) 1745 % 1746 % A description of each parameter follows: 1747 % 1748 % o image_info: the image info. 1749 % 1750 % o window: Specifies the name or id of an X window. 1751 % 1752 % o filename: the name of the image filename to display. 1753 % 1754 % o exception: return any errors or warnings in this structure. 1755 % 1756 */ 1757 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1758 const char *window,const char *filename,ExceptionInfo *exception) 1759 { 1760 Display 1761 *display; 1762 1763 MagickStatusType 1764 status; 1765 1766 assert(image_info != (const ImageInfo *) NULL); 1767 assert(image_info->signature == MagickCoreSignature); 1768 assert(filename != (char *) NULL); 1769 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1770 display=XOpenDisplay(image_info->server_name); 1771 if (display == (Display *) NULL) 1772 { 1773 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1774 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1775 return(MagickFalse); 1776 } 1777 (void) XSetErrorHandler(XError); 1778 status=XRemoteCommand(display,window,filename); 1779 (void) XCloseDisplay(display); 1780 return(status != 0 ? MagickTrue : MagickFalse); 1781 } 1782 1783 /* 1785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1786 % % 1787 % % 1788 % % 1789 + X A n n o t a t e E d i t I m a g e % 1790 % % 1791 % % 1792 % % 1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1794 % 1795 % XAnnotateEditImage() annotates the image with text. 1796 % 1797 % The format of the XAnnotateEditImage method is: 1798 % 1799 % MagickBooleanType XAnnotateEditImage(Display *display, 1800 % XResourceInfo *resource_info,XWindows *windows,Image *image, 1801 % ExceptionInfo *exception) 1802 % 1803 % A description of each parameter follows: 1804 % 1805 % o display: Specifies a connection to an X server; returned from 1806 % XOpenDisplay. 1807 % 1808 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1809 % 1810 % o windows: Specifies a pointer to a XWindows structure. 1811 % 1812 % o image: the image; returned from ReadImage. 1813 % 1814 */ 1815 1816 static MagickBooleanType XAnnotateEditImage(Display *display, 1817 XResourceInfo *resource_info,XWindows *windows,Image *image, 1818 ExceptionInfo *exception) 1819 { 1820 static const char 1821 *AnnotateMenu[] = 1822 { 1823 "Font Name", 1824 "Font Color", 1825 "Box Color", 1826 "Rotate Text", 1827 "Help", 1828 "Dismiss", 1829 (char *) NULL 1830 }, 1831 *TextMenu[] = 1832 { 1833 "Help", 1834 "Apply", 1835 (char *) NULL 1836 }; 1837 1838 static const ModeType 1839 AnnotateCommands[] = 1840 { 1841 AnnotateNameCommand, 1842 AnnotateFontColorCommand, 1843 AnnotateBackgroundColorCommand, 1844 AnnotateRotateCommand, 1845 AnnotateHelpCommand, 1846 AnnotateDismissCommand 1847 }, 1848 TextCommands[] = 1849 { 1850 TextHelpCommand, 1851 TextApplyCommand 1852 }; 1853 1854 static MagickBooleanType 1855 transparent_box = MagickTrue, 1856 transparent_pen = MagickFalse; 1857 1858 static double 1859 degrees = 0.0; 1860 1861 static unsigned int 1862 box_id = MaxNumberPens-2, 1863 font_id = 0, 1864 pen_id = 0; 1865 1866 char 1867 command[MagickPathExtent], 1868 text[MagickPathExtent]; 1869 1870 const char 1871 *ColorMenu[MaxNumberPens+1]; 1872 1873 Cursor 1874 cursor; 1875 1876 GC 1877 annotate_context; 1878 1879 int 1880 id, 1881 pen_number, 1882 status, 1883 x, 1884 y; 1885 1886 KeySym 1887 key_symbol; 1888 1889 register char 1890 *p; 1891 1892 register ssize_t 1893 i; 1894 1895 unsigned int 1896 height, 1897 width; 1898 1899 size_t 1900 state; 1901 1902 XAnnotateInfo 1903 *annotate_info, 1904 *previous_info; 1905 1906 XColor 1907 color; 1908 1909 XFontStruct 1910 *font_info; 1911 1912 XEvent 1913 event, 1914 text_event; 1915 1916 /* 1917 Map Command widget. 1918 */ 1919 (void) CloneString(&windows->command.name,"Annotate"); 1920 windows->command.data=4; 1921 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1922 (void) XMapRaised(display,windows->command.id); 1923 XClientMessage(display,windows->image.id,windows->im_protocols, 1924 windows->im_update_widget,CurrentTime); 1925 /* 1926 Track pointer until button 1 is pressed. 1927 */ 1928 XQueryPosition(display,windows->image.id,&x,&y); 1929 (void) XSelectInput(display,windows->image.id, 1930 windows->image.attributes.event_mask | PointerMotionMask); 1931 cursor=XCreateFontCursor(display,XC_left_side); 1932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1933 state=DefaultState; 1934 do 1935 { 1936 if (windows->info.mapped != MagickFalse ) 1937 { 1938 /* 1939 Display pointer position. 1940 */ 1941 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 1942 x+windows->image.x,y+windows->image.y); 1943 XInfoWidget(display,windows,text); 1944 } 1945 /* 1946 Wait for next event. 1947 */ 1948 XScreenEvent(display,windows,&event,exception); 1949 if (event.xany.window == windows->command.id) 1950 { 1951 /* 1952 Select a command from the Command widget. 1953 */ 1954 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1955 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1956 if (id < 0) 1957 continue; 1958 switch (AnnotateCommands[id]) 1959 { 1960 case AnnotateNameCommand: 1961 { 1962 const char 1963 *FontMenu[MaxNumberFonts]; 1964 1965 int 1966 font_number; 1967 1968 /* 1969 Initialize menu selections. 1970 */ 1971 for (i=0; i < MaxNumberFonts; i++) 1972 FontMenu[i]=resource_info->font_name[i]; 1973 FontMenu[MaxNumberFonts-2]="Browser..."; 1974 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1975 /* 1976 Select a font name from the pop-up menu. 1977 */ 1978 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1979 (const char **) FontMenu,command); 1980 if (font_number < 0) 1981 break; 1982 if (font_number == (MaxNumberFonts-2)) 1983 { 1984 static char 1985 font_name[MagickPathExtent] = "fixed"; 1986 1987 /* 1988 Select a font name from a browser. 1989 */ 1990 resource_info->font_name[font_number]=font_name; 1991 XFontBrowserWidget(display,windows,"Select",font_name); 1992 if (*font_name == '\0') 1993 break; 1994 } 1995 /* 1996 Initialize font info. 1997 */ 1998 font_info=XLoadQueryFont(display,resource_info->font_name[ 1999 font_number]); 2000 if (font_info == (XFontStruct *) NULL) 2001 { 2002 XNoticeWidget(display,windows,"Unable to load font:", 2003 resource_info->font_name[font_number]); 2004 break; 2005 } 2006 font_id=(unsigned int) font_number; 2007 (void) XFreeFont(display,font_info); 2008 break; 2009 } 2010 case AnnotateFontColorCommand: 2011 { 2012 /* 2013 Initialize menu selections. 2014 */ 2015 for (i=0; i < (int) (MaxNumberPens-2); i++) 2016 ColorMenu[i]=resource_info->pen_colors[i]; 2017 ColorMenu[MaxNumberPens-2]="transparent"; 2018 ColorMenu[MaxNumberPens-1]="Browser..."; 2019 ColorMenu[MaxNumberPens]=(const char *) NULL; 2020 /* 2021 Select a pen color from the pop-up menu. 2022 */ 2023 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2024 (const char **) ColorMenu,command); 2025 if (pen_number < 0) 2026 break; 2027 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2028 MagickFalse; 2029 if (transparent_pen != MagickFalse ) 2030 break; 2031 if (pen_number == (MaxNumberPens-1)) 2032 { 2033 static char 2034 color_name[MagickPathExtent] = "gray"; 2035 2036 /* 2037 Select a pen color from a dialog. 2038 */ 2039 resource_info->pen_colors[pen_number]=color_name; 2040 XColorBrowserWidget(display,windows,"Select",color_name); 2041 if (*color_name == '\0') 2042 break; 2043 } 2044 /* 2045 Set pen color. 2046 */ 2047 (void) XParseColor(display,windows->map_info->colormap, 2048 resource_info->pen_colors[pen_number],&color); 2049 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2050 (unsigned int) MaxColors,&color); 2051 windows->pixel_info->pen_colors[pen_number]=color; 2052 pen_id=(unsigned int) pen_number; 2053 break; 2054 } 2055 case AnnotateBackgroundColorCommand: 2056 { 2057 /* 2058 Initialize menu selections. 2059 */ 2060 for (i=0; i < (int) (MaxNumberPens-2); i++) 2061 ColorMenu[i]=resource_info->pen_colors[i]; 2062 ColorMenu[MaxNumberPens-2]="transparent"; 2063 ColorMenu[MaxNumberPens-1]="Browser..."; 2064 ColorMenu[MaxNumberPens]=(const char *) NULL; 2065 /* 2066 Select a pen color from the pop-up menu. 2067 */ 2068 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2069 (const char **) ColorMenu,command); 2070 if (pen_number < 0) 2071 break; 2072 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2073 MagickFalse; 2074 if (transparent_box != MagickFalse ) 2075 break; 2076 if (pen_number == (MaxNumberPens-1)) 2077 { 2078 static char 2079 color_name[MagickPathExtent] = "gray"; 2080 2081 /* 2082 Select a pen color from a dialog. 2083 */ 2084 resource_info->pen_colors[pen_number]=color_name; 2085 XColorBrowserWidget(display,windows,"Select",color_name); 2086 if (*color_name == '\0') 2087 break; 2088 } 2089 /* 2090 Set pen color. 2091 */ 2092 (void) XParseColor(display,windows->map_info->colormap, 2093 resource_info->pen_colors[pen_number],&color); 2094 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2095 (unsigned int) MaxColors,&color); 2096 windows->pixel_info->pen_colors[pen_number]=color; 2097 box_id=(unsigned int) pen_number; 2098 break; 2099 } 2100 case AnnotateRotateCommand: 2101 { 2102 int 2103 entry; 2104 2105 static char 2106 angle[MagickPathExtent] = "30.0"; 2107 2108 static const char 2109 *RotateMenu[] = 2110 { 2111 "-90", 2112 "-45", 2113 "-30", 2114 "0", 2115 "30", 2116 "45", 2117 "90", 2118 "180", 2119 "Dialog...", 2120 (char *) NULL, 2121 }; 2122 2123 /* 2124 Select a command from the pop-up menu. 2125 */ 2126 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2127 command); 2128 if (entry < 0) 2129 break; 2130 if (entry != 8) 2131 { 2132 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2133 break; 2134 } 2135 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2136 angle); 2137 if (*angle == '\0') 2138 break; 2139 degrees=StringToDouble(angle,(char **) NULL); 2140 break; 2141 } 2142 case AnnotateHelpCommand: 2143 { 2144 XTextViewWidget(display,resource_info,windows,MagickFalse, 2145 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2146 break; 2147 } 2148 case AnnotateDismissCommand: 2149 { 2150 /* 2151 Prematurely exit. 2152 */ 2153 state|=EscapeState; 2154 state|=ExitState; 2155 break; 2156 } 2157 default: 2158 break; 2159 } 2160 continue; 2161 } 2162 switch (event.type) 2163 { 2164 case ButtonPress: 2165 { 2166 if (event.xbutton.button != Button1) 2167 break; 2168 if (event.xbutton.window != windows->image.id) 2169 break; 2170 /* 2171 Change to text entering mode. 2172 */ 2173 x=event.xbutton.x; 2174 y=event.xbutton.y; 2175 state|=ExitState; 2176 break; 2177 } 2178 case ButtonRelease: 2179 break; 2180 case Expose: 2181 break; 2182 case KeyPress: 2183 { 2184 if (event.xkey.window != windows->image.id) 2185 break; 2186 /* 2187 Respond to a user key press. 2188 */ 2189 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2190 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2191 switch ((int) key_symbol) 2192 { 2193 case XK_Escape: 2194 case XK_F20: 2195 { 2196 /* 2197 Prematurely exit. 2198 */ 2199 state|=EscapeState; 2200 state|=ExitState; 2201 break; 2202 } 2203 case XK_F1: 2204 case XK_Help: 2205 { 2206 XTextViewWidget(display,resource_info,windows,MagickFalse, 2207 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2208 break; 2209 } 2210 default: 2211 { 2212 (void) XBell(display,0); 2213 break; 2214 } 2215 } 2216 break; 2217 } 2218 case MotionNotify: 2219 { 2220 /* 2221 Map and unmap Info widget as cursor crosses its boundaries. 2222 */ 2223 x=event.xmotion.x; 2224 y=event.xmotion.y; 2225 if (windows->info.mapped != MagickFalse ) 2226 { 2227 if ((x < (int) (windows->info.x+windows->info.width)) && 2228 (y < (int) (windows->info.y+windows->info.height))) 2229 (void) XWithdrawWindow(display,windows->info.id, 2230 windows->info.screen); 2231 } 2232 else 2233 if ((x > (int) (windows->info.x+windows->info.width)) || 2234 (y > (int) (windows->info.y+windows->info.height))) 2235 (void) XMapWindow(display,windows->info.id); 2236 break; 2237 } 2238 default: 2239 break; 2240 } 2241 } while ((state & ExitState) == 0); 2242 (void) XSelectInput(display,windows->image.id, 2243 windows->image.attributes.event_mask); 2244 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2245 if ((state & EscapeState) != 0) 2246 return(MagickTrue); 2247 /* 2248 Set font info and check boundary conditions. 2249 */ 2250 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2251 if (font_info == (XFontStruct *) NULL) 2252 { 2253 XNoticeWidget(display,windows,"Unable to load font:", 2254 resource_info->font_name[font_id]); 2255 font_info=windows->font_info; 2256 } 2257 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2258 x=(int) windows->image.width-font_info->max_bounds.width; 2259 if (y < (int) (font_info->ascent+font_info->descent)) 2260 y=(int) font_info->ascent+font_info->descent; 2261 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2262 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2263 return(MagickFalse); 2264 /* 2265 Initialize annotate structure. 2266 */ 2267 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2268 if (annotate_info == (XAnnotateInfo *) NULL) 2269 return(MagickFalse); 2270 XGetAnnotateInfo(annotate_info); 2271 annotate_info->x=x; 2272 annotate_info->y=y; 2273 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2274 annotate_info->stencil=OpaqueStencil; 2275 else 2276 if (transparent_box == MagickFalse) 2277 annotate_info->stencil=BackgroundStencil; 2278 else 2279 annotate_info->stencil=ForegroundStencil; 2280 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2281 annotate_info->degrees=degrees; 2282 annotate_info->font_info=font_info; 2283 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2284 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2285 sizeof(*annotate_info->text)); 2286 if (annotate_info->text == (char *) NULL) 2287 return(MagickFalse); 2288 /* 2289 Create cursor and set graphic context. 2290 */ 2291 cursor=XCreateFontCursor(display,XC_pencil); 2292 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2293 annotate_context=windows->image.annotate_context; 2294 (void) XSetFont(display,annotate_context,font_info->fid); 2295 (void) XSetBackground(display,annotate_context, 2296 windows->pixel_info->pen_colors[box_id].pixel); 2297 (void) XSetForeground(display,annotate_context, 2298 windows->pixel_info->pen_colors[pen_id].pixel); 2299 /* 2300 Begin annotating the image with text. 2301 */ 2302 (void) CloneString(&windows->command.name,"Text"); 2303 windows->command.data=0; 2304 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2305 state=DefaultState; 2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2307 text_event.xexpose.width=(int) font_info->max_bounds.width; 2308 text_event.xexpose.height=font_info->max_bounds.ascent+ 2309 font_info->max_bounds.descent; 2310 p=annotate_info->text; 2311 do 2312 { 2313 /* 2314 Display text cursor. 2315 */ 2316 *p='\0'; 2317 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2318 /* 2319 Wait for next event. 2320 */ 2321 XScreenEvent(display,windows,&event,exception); 2322 if (event.xany.window == windows->command.id) 2323 { 2324 /* 2325 Select a command from the Command widget. 2326 */ 2327 (void) XSetBackground(display,annotate_context, 2328 windows->pixel_info->background_color.pixel); 2329 (void) XSetForeground(display,annotate_context, 2330 windows->pixel_info->foreground_color.pixel); 2331 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2332 (void) XSetBackground(display,annotate_context, 2333 windows->pixel_info->pen_colors[box_id].pixel); 2334 (void) XSetForeground(display,annotate_context, 2335 windows->pixel_info->pen_colors[pen_id].pixel); 2336 if (id < 0) 2337 continue; 2338 switch (TextCommands[id]) 2339 { 2340 case TextHelpCommand: 2341 { 2342 XTextViewWidget(display,resource_info,windows,MagickFalse, 2343 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2344 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2345 break; 2346 } 2347 case TextApplyCommand: 2348 { 2349 /* 2350 Finished annotating. 2351 */ 2352 annotate_info->width=(unsigned int) XTextWidth(font_info, 2353 annotate_info->text,(int) strlen(annotate_info->text)); 2354 XRefreshWindow(display,&windows->image,&text_event); 2355 state|=ExitState; 2356 break; 2357 } 2358 default: 2359 break; 2360 } 2361 continue; 2362 } 2363 /* 2364 Erase text cursor. 2365 */ 2366 text_event.xexpose.x=x; 2367 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2368 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2369 (unsigned int) text_event.xexpose.width,(unsigned int) 2370 text_event.xexpose.height,MagickFalse); 2371 XRefreshWindow(display,&windows->image,&text_event); 2372 switch (event.type) 2373 { 2374 case ButtonPress: 2375 { 2376 if (event.xbutton.window != windows->image.id) 2377 break; 2378 if (event.xbutton.button == Button2) 2379 { 2380 /* 2381 Request primary selection. 2382 */ 2383 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2384 windows->image.id,CurrentTime); 2385 break; 2386 } 2387 break; 2388 } 2389 case Expose: 2390 { 2391 if (event.xexpose.count == 0) 2392 { 2393 XAnnotateInfo 2394 *text_info; 2395 2396 /* 2397 Refresh Image window. 2398 */ 2399 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2400 text_info=annotate_info; 2401 while (text_info != (XAnnotateInfo *) NULL) 2402 { 2403 if (annotate_info->stencil == ForegroundStencil) 2404 (void) XDrawString(display,windows->image.id,annotate_context, 2405 text_info->x,text_info->y,text_info->text, 2406 (int) strlen(text_info->text)); 2407 else 2408 (void) XDrawImageString(display,windows->image.id, 2409 annotate_context,text_info->x,text_info->y,text_info->text, 2410 (int) strlen(text_info->text)); 2411 text_info=text_info->previous; 2412 } 2413 (void) XDrawString(display,windows->image.id,annotate_context, 2414 x,y,"_",1); 2415 } 2416 break; 2417 } 2418 case KeyPress: 2419 { 2420 int 2421 length; 2422 2423 if (event.xkey.window != windows->image.id) 2424 break; 2425 /* 2426 Respond to a user key press. 2427 */ 2428 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2429 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2430 *(command+length)='\0'; 2431 if (((event.xkey.state & ControlMask) != 0) || 2432 ((event.xkey.state & Mod1Mask) != 0)) 2433 state|=ModifierState; 2434 if ((state & ModifierState) != 0) 2435 switch ((int) key_symbol) 2436 { 2437 case XK_u: 2438 case XK_U: 2439 { 2440 key_symbol=DeleteCommand; 2441 break; 2442 } 2443 default: 2444 break; 2445 } 2446 switch ((int) key_symbol) 2447 { 2448 case XK_BackSpace: 2449 { 2450 /* 2451 Erase one character. 2452 */ 2453 if (p == annotate_info->text) 2454 { 2455 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2456 break; 2457 else 2458 { 2459 /* 2460 Go to end of the previous line of text. 2461 */ 2462 annotate_info=annotate_info->previous; 2463 p=annotate_info->text; 2464 x=annotate_info->x+annotate_info->width; 2465 y=annotate_info->y; 2466 if (annotate_info->width != 0) 2467 p+=strlen(annotate_info->text); 2468 break; 2469 } 2470 } 2471 p--; 2472 x-=XTextWidth(font_info,p,1); 2473 text_event.xexpose.x=x; 2474 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2475 XRefreshWindow(display,&windows->image,&text_event); 2476 break; 2477 } 2478 case XK_bracketleft: 2479 { 2480 key_symbol=XK_Escape; 2481 break; 2482 } 2483 case DeleteCommand: 2484 { 2485 /* 2486 Erase the entire line of text. 2487 */ 2488 while (p != annotate_info->text) 2489 { 2490 p--; 2491 x-=XTextWidth(font_info,p,1); 2492 text_event.xexpose.x=x; 2493 XRefreshWindow(display,&windows->image,&text_event); 2494 } 2495 break; 2496 } 2497 case XK_Escape: 2498 case XK_F20: 2499 { 2500 /* 2501 Finished annotating. 2502 */ 2503 annotate_info->width=(unsigned int) XTextWidth(font_info, 2504 annotate_info->text,(int) strlen(annotate_info->text)); 2505 XRefreshWindow(display,&windows->image,&text_event); 2506 state|=ExitState; 2507 break; 2508 } 2509 default: 2510 { 2511 /* 2512 Draw a single character on the Image window. 2513 */ 2514 if ((state & ModifierState) != 0) 2515 break; 2516 if (*command == '\0') 2517 break; 2518 *p=(*command); 2519 if (annotate_info->stencil == ForegroundStencil) 2520 (void) XDrawString(display,windows->image.id,annotate_context, 2521 x,y,p,1); 2522 else 2523 (void) XDrawImageString(display,windows->image.id, 2524 annotate_context,x,y,p,1); 2525 x+=XTextWidth(font_info,p,1); 2526 p++; 2527 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2528 break; 2529 } 2530 case XK_Return: 2531 case XK_KP_Enter: 2532 { 2533 /* 2534 Advance to the next line of text. 2535 */ 2536 *p='\0'; 2537 annotate_info->width=(unsigned int) XTextWidth(font_info, 2538 annotate_info->text,(int) strlen(annotate_info->text)); 2539 if (annotate_info->next != (XAnnotateInfo *) NULL) 2540 { 2541 /* 2542 Line of text already exists. 2543 */ 2544 annotate_info=annotate_info->next; 2545 x=annotate_info->x; 2546 y=annotate_info->y; 2547 p=annotate_info->text; 2548 break; 2549 } 2550 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2551 sizeof(*annotate_info->next)); 2552 if (annotate_info->next == (XAnnotateInfo *) NULL) 2553 return(MagickFalse); 2554 *annotate_info->next=(*annotate_info); 2555 annotate_info->next->previous=annotate_info; 2556 annotate_info=annotate_info->next; 2557 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2558 windows->image.width/MagickMax((ssize_t) 2559 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2560 if (annotate_info->text == (char *) NULL) 2561 return(MagickFalse); 2562 annotate_info->y+=annotate_info->height; 2563 if (annotate_info->y > (int) windows->image.height) 2564 annotate_info->y=(int) annotate_info->height; 2565 annotate_info->next=(XAnnotateInfo *) NULL; 2566 x=annotate_info->x; 2567 y=annotate_info->y; 2568 p=annotate_info->text; 2569 break; 2570 } 2571 } 2572 break; 2573 } 2574 case KeyRelease: 2575 { 2576 /* 2577 Respond to a user key release. 2578 */ 2579 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2580 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2581 state&=(~ModifierState); 2582 break; 2583 } 2584 case SelectionNotify: 2585 { 2586 Atom 2587 type; 2588 2589 int 2590 format; 2591 2592 unsigned char 2593 *data; 2594 2595 unsigned long 2596 after, 2597 length; 2598 2599 /* 2600 Obtain response from primary selection. 2601 */ 2602 if (event.xselection.property == (Atom) None) 2603 break; 2604 status=XGetWindowProperty(display,event.xselection.requestor, 2605 event.xselection.property,0L,(long) MagickPathExtent,True,XA_STRING, 2606 &type,&format,&length,&after,&data); 2607 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2608 (length == 0)) 2609 break; 2610 /* 2611 Annotate Image window with primary selection. 2612 */ 2613 for (i=0; i < (ssize_t) length; i++) 2614 { 2615 if ((char) data[i] != '\n') 2616 { 2617 /* 2618 Draw a single character on the Image window. 2619 */ 2620 *p=(char) data[i]; 2621 (void) XDrawString(display,windows->image.id,annotate_context, 2622 x,y,p,1); 2623 x+=XTextWidth(font_info,p,1); 2624 p++; 2625 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2626 continue; 2627 } 2628 /* 2629 Advance to the next line of text. 2630 */ 2631 *p='\0'; 2632 annotate_info->width=(unsigned int) XTextWidth(font_info, 2633 annotate_info->text,(int) strlen(annotate_info->text)); 2634 if (annotate_info->next != (XAnnotateInfo *) NULL) 2635 { 2636 /* 2637 Line of text already exists. 2638 */ 2639 annotate_info=annotate_info->next; 2640 x=annotate_info->x; 2641 y=annotate_info->y; 2642 p=annotate_info->text; 2643 continue; 2644 } 2645 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2646 sizeof(*annotate_info->next)); 2647 if (annotate_info->next == (XAnnotateInfo *) NULL) 2648 return(MagickFalse); 2649 *annotate_info->next=(*annotate_info); 2650 annotate_info->next->previous=annotate_info; 2651 annotate_info=annotate_info->next; 2652 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2653 windows->image.width/MagickMax((ssize_t) 2654 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2655 if (annotate_info->text == (char *) NULL) 2656 return(MagickFalse); 2657 annotate_info->y+=annotate_info->height; 2658 if (annotate_info->y > (int) windows->image.height) 2659 annotate_info->y=(int) annotate_info->height; 2660 annotate_info->next=(XAnnotateInfo *) NULL; 2661 x=annotate_info->x; 2662 y=annotate_info->y; 2663 p=annotate_info->text; 2664 } 2665 (void) XFree((void *) data); 2666 break; 2667 } 2668 default: 2669 break; 2670 } 2671 } while ((state & ExitState) == 0); 2672 (void) XFreeCursor(display,cursor); 2673 /* 2674 Annotation is relative to image configuration. 2675 */ 2676 width=(unsigned int) image->columns; 2677 height=(unsigned int) image->rows; 2678 x=0; 2679 y=0; 2680 if (windows->image.crop_geometry != (char *) NULL) 2681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2682 /* 2683 Initialize annotated image. 2684 */ 2685 XSetCursorState(display,windows,MagickTrue); 2686 XCheckRefreshWindows(display,windows); 2687 while (annotate_info != (XAnnotateInfo *) NULL) 2688 { 2689 if (annotate_info->width == 0) 2690 { 2691 /* 2692 No text on this line-- go to the next line of text. 2693 */ 2694 previous_info=annotate_info->previous; 2695 annotate_info->text=(char *) 2696 RelinquishMagickMemory(annotate_info->text); 2697 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2698 annotate_info=previous_info; 2699 continue; 2700 } 2701 /* 2702 Determine pixel index for box and pen color. 2703 */ 2704 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2705 if (windows->pixel_info->colors != 0) 2706 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2707 if (windows->pixel_info->pixels[i] == 2708 windows->pixel_info->pen_colors[box_id].pixel) 2709 { 2710 windows->pixel_info->box_index=(unsigned short) i; 2711 break; 2712 } 2713 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2714 if (windows->pixel_info->colors != 0) 2715 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2716 if (windows->pixel_info->pixels[i] == 2717 windows->pixel_info->pen_colors[pen_id].pixel) 2718 { 2719 windows->pixel_info->pen_index=(unsigned short) i; 2720 break; 2721 } 2722 /* 2723 Define the annotate geometry string. 2724 */ 2725 annotate_info->x=(int) 2726 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2727 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2728 windows->image.y)/windows->image.ximage->height; 2729 (void) FormatLocaleString(annotate_info->geometry,MagickPathExtent, 2730 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2731 height*annotate_info->height/windows->image.ximage->height, 2732 annotate_info->x+x,annotate_info->y+y); 2733 /* 2734 Annotate image with text. 2735 */ 2736 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2737 exception); 2738 if (status == 0) 2739 return(MagickFalse); 2740 /* 2741 Free up memory. 2742 */ 2743 previous_info=annotate_info->previous; 2744 annotate_info->text=DestroyString(annotate_info->text); 2745 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2746 annotate_info=previous_info; 2747 } 2748 (void) XSetForeground(display,annotate_context, 2749 windows->pixel_info->foreground_color.pixel); 2750 (void) XSetBackground(display,annotate_context, 2751 windows->pixel_info->background_color.pixel); 2752 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2753 XSetCursorState(display,windows,MagickFalse); 2754 (void) XFreeFont(display,font_info); 2755 /* 2756 Update image configuration. 2757 */ 2758 XConfigureImageColormap(display,resource_info,windows,image,exception); 2759 (void) XConfigureImage(display,resource_info,windows,image,exception); 2760 return(MagickTrue); 2761 } 2762 2763 /* 2765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2766 % % 2767 % % 2768 % % 2769 + X B a c k g r o u n d I m a g e % 2770 % % 2771 % % 2772 % % 2773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2774 % 2775 % XBackgroundImage() displays the image in the background of a window. 2776 % 2777 % The format of the XBackgroundImage method is: 2778 % 2779 % MagickBooleanType XBackgroundImage(Display *display, 2780 % XResourceInfo *resource_info,XWindows *windows,Image **image, 2781 % ExceptionInfo *exception) 2782 % 2783 % A description of each parameter follows: 2784 % 2785 % o display: Specifies a connection to an X server; returned from 2786 % XOpenDisplay. 2787 % 2788 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2789 % 2790 % o windows: Specifies a pointer to a XWindows structure. 2791 % 2792 % o image: the image. 2793 % 2794 % o exception: return any errors or warnings in this structure. 2795 % 2796 */ 2797 static MagickBooleanType XBackgroundImage(Display *display, 2798 XResourceInfo *resource_info,XWindows *windows,Image **image, 2799 ExceptionInfo *exception) 2800 { 2801 #define BackgroundImageTag "Background/Image" 2802 2803 int 2804 status; 2805 2806 static char 2807 window_id[MagickPathExtent] = "root"; 2808 2809 XResourceInfo 2810 background_resources; 2811 2812 /* 2813 Put image in background. 2814 */ 2815 status=XDialogWidget(display,windows,"Background", 2816 "Enter window id (id 0x00 selects window with pointer):",window_id); 2817 if (*window_id == '\0') 2818 return(MagickFalse); 2819 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2820 exception); 2821 XInfoWidget(display,windows,BackgroundImageTag); 2822 XSetCursorState(display,windows,MagickTrue); 2823 XCheckRefreshWindows(display,windows); 2824 background_resources=(*resource_info); 2825 background_resources.window_id=window_id; 2826 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2827 status=XDisplayBackgroundImage(display,&background_resources,*image, 2828 exception); 2829 if (status != MagickFalse) 2830 XClientMessage(display,windows->image.id,windows->im_protocols, 2831 windows->im_retain_colors,CurrentTime); 2832 XSetCursorState(display,windows,MagickFalse); 2833 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2834 exception); 2835 return(MagickTrue); 2836 } 2837 2838 /* 2840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2841 % % 2842 % % 2843 % % 2844 + X C h o p I m a g e % 2845 % % 2846 % % 2847 % % 2848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2849 % 2850 % XChopImage() chops the X image. 2851 % 2852 % The format of the XChopImage method is: 2853 % 2854 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2855 % XWindows *windows,Image **image,ExceptionInfo *exception) 2856 % 2857 % A description of each parameter follows: 2858 % 2859 % o display: Specifies a connection to an X server; returned from 2860 % XOpenDisplay. 2861 % 2862 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2863 % 2864 % o windows: Specifies a pointer to a XWindows structure. 2865 % 2866 % o image: the image. 2867 % 2868 % o exception: return any errors or warnings in this structure. 2869 % 2870 */ 2871 static MagickBooleanType XChopImage(Display *display, 2872 XResourceInfo *resource_info,XWindows *windows,Image **image, 2873 ExceptionInfo *exception) 2874 { 2875 static const char 2876 *ChopMenu[] = 2877 { 2878 "Direction", 2879 "Help", 2880 "Dismiss", 2881 (char *) NULL 2882 }; 2883 2884 static ModeType 2885 direction = HorizontalChopCommand; 2886 2887 static const ModeType 2888 ChopCommands[] = 2889 { 2890 ChopDirectionCommand, 2891 ChopHelpCommand, 2892 ChopDismissCommand 2893 }, 2894 DirectionCommands[] = 2895 { 2896 HorizontalChopCommand, 2897 VerticalChopCommand 2898 }; 2899 2900 char 2901 text[MagickPathExtent]; 2902 2903 Image 2904 *chop_image; 2905 2906 int 2907 id, 2908 x, 2909 y; 2910 2911 double 2912 scale_factor; 2913 2914 RectangleInfo 2915 chop_info; 2916 2917 unsigned int 2918 distance, 2919 height, 2920 width; 2921 2922 size_t 2923 state; 2924 2925 XEvent 2926 event; 2927 2928 XSegment 2929 segment_info; 2930 2931 /* 2932 Map Command widget. 2933 */ 2934 (void) CloneString(&windows->command.name,"Chop"); 2935 windows->command.data=1; 2936 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2937 (void) XMapRaised(display,windows->command.id); 2938 XClientMessage(display,windows->image.id,windows->im_protocols, 2939 windows->im_update_widget,CurrentTime); 2940 /* 2941 Track pointer until button 1 is pressed. 2942 */ 2943 XQueryPosition(display,windows->image.id,&x,&y); 2944 (void) XSelectInput(display,windows->image.id, 2945 windows->image.attributes.event_mask | PointerMotionMask); 2946 state=DefaultState; 2947 (void) ResetMagickMemory(&segment_info,0,sizeof(segment_info)); 2948 do 2949 { 2950 if (windows->info.mapped != MagickFalse ) 2951 { 2952 /* 2953 Display pointer position. 2954 */ 2955 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 2956 x+windows->image.x,y+windows->image.y); 2957 XInfoWidget(display,windows,text); 2958 } 2959 /* 2960 Wait for next event. 2961 */ 2962 XScreenEvent(display,windows,&event,exception); 2963 if (event.xany.window == windows->command.id) 2964 { 2965 /* 2966 Select a command from the Command widget. 2967 */ 2968 id=XCommandWidget(display,windows,ChopMenu,&event); 2969 if (id < 0) 2970 continue; 2971 switch (ChopCommands[id]) 2972 { 2973 case ChopDirectionCommand: 2974 { 2975 char 2976 command[MagickPathExtent]; 2977 2978 static const char 2979 *Directions[] = 2980 { 2981 "horizontal", 2982 "vertical", 2983 (char *) NULL, 2984 }; 2985 2986 /* 2987 Select a command from the pop-up menu. 2988 */ 2989 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2990 if (id >= 0) 2991 direction=DirectionCommands[id]; 2992 break; 2993 } 2994 case ChopHelpCommand: 2995 { 2996 XTextViewWidget(display,resource_info,windows,MagickFalse, 2997 "Help Viewer - Image Chop",ImageChopHelp); 2998 break; 2999 } 3000 case ChopDismissCommand: 3001 { 3002 /* 3003 Prematurely exit. 3004 */ 3005 state|=EscapeState; 3006 state|=ExitState; 3007 break; 3008 } 3009 default: 3010 break; 3011 } 3012 continue; 3013 } 3014 switch (event.type) 3015 { 3016 case ButtonPress: 3017 { 3018 if (event.xbutton.button != Button1) 3019 break; 3020 if (event.xbutton.window != windows->image.id) 3021 break; 3022 /* 3023 User has committed to start point of chopping line. 3024 */ 3025 segment_info.x1=(short int) event.xbutton.x; 3026 segment_info.x2=(short int) event.xbutton.x; 3027 segment_info.y1=(short int) event.xbutton.y; 3028 segment_info.y2=(short int) event.xbutton.y; 3029 state|=ExitState; 3030 break; 3031 } 3032 case ButtonRelease: 3033 break; 3034 case Expose: 3035 break; 3036 case KeyPress: 3037 { 3038 char 3039 command[MagickPathExtent]; 3040 3041 KeySym 3042 key_symbol; 3043 3044 if (event.xkey.window != windows->image.id) 3045 break; 3046 /* 3047 Respond to a user key press. 3048 */ 3049 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3050 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3051 switch ((int) key_symbol) 3052 { 3053 case XK_Escape: 3054 case XK_F20: 3055 { 3056 /* 3057 Prematurely exit. 3058 */ 3059 state|=EscapeState; 3060 state|=ExitState; 3061 break; 3062 } 3063 case XK_F1: 3064 case XK_Help: 3065 { 3066 (void) XSetFunction(display,windows->image.highlight_context, 3067 GXcopy); 3068 XTextViewWidget(display,resource_info,windows,MagickFalse, 3069 "Help Viewer - Image Chop",ImageChopHelp); 3070 (void) XSetFunction(display,windows->image.highlight_context, 3071 GXinvert); 3072 break; 3073 } 3074 default: 3075 { 3076 (void) XBell(display,0); 3077 break; 3078 } 3079 } 3080 break; 3081 } 3082 case MotionNotify: 3083 { 3084 /* 3085 Map and unmap Info widget as text cursor crosses its boundaries. 3086 */ 3087 x=event.xmotion.x; 3088 y=event.xmotion.y; 3089 if (windows->info.mapped != MagickFalse ) 3090 { 3091 if ((x < (int) (windows->info.x+windows->info.width)) && 3092 (y < (int) (windows->info.y+windows->info.height))) 3093 (void) XWithdrawWindow(display,windows->info.id, 3094 windows->info.screen); 3095 } 3096 else 3097 if ((x > (int) (windows->info.x+windows->info.width)) || 3098 (y > (int) (windows->info.y+windows->info.height))) 3099 (void) XMapWindow(display,windows->info.id); 3100 } 3101 } 3102 } while ((state & ExitState) == 0); 3103 (void) XSelectInput(display,windows->image.id, 3104 windows->image.attributes.event_mask); 3105 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3106 if ((state & EscapeState) != 0) 3107 return(MagickTrue); 3108 /* 3109 Draw line as pointer moves until the mouse button is released. 3110 */ 3111 chop_info.width=0; 3112 chop_info.height=0; 3113 chop_info.x=0; 3114 chop_info.y=0; 3115 distance=0; 3116 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3117 state=DefaultState; 3118 do 3119 { 3120 if (distance > 9) 3121 { 3122 /* 3123 Display info and draw chopping line. 3124 */ 3125 if (windows->info.mapped == MagickFalse) 3126 (void) XMapWindow(display,windows->info.id); 3127 (void) FormatLocaleString(text,MagickPathExtent, 3128 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3129 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3130 XInfoWidget(display,windows,text); 3131 XHighlightLine(display,windows->image.id, 3132 windows->image.highlight_context,&segment_info); 3133 } 3134 else 3135 if (windows->info.mapped != MagickFalse ) 3136 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3137 /* 3138 Wait for next event. 3139 */ 3140 XScreenEvent(display,windows,&event,exception); 3141 if (distance > 9) 3142 XHighlightLine(display,windows->image.id, 3143 windows->image.highlight_context,&segment_info); 3144 switch (event.type) 3145 { 3146 case ButtonPress: 3147 { 3148 segment_info.x2=(short int) event.xmotion.x; 3149 segment_info.y2=(short int) event.xmotion.y; 3150 break; 3151 } 3152 case ButtonRelease: 3153 { 3154 /* 3155 User has committed to chopping line. 3156 */ 3157 segment_info.x2=(short int) event.xbutton.x; 3158 segment_info.y2=(short int) event.xbutton.y; 3159 state|=ExitState; 3160 break; 3161 } 3162 case Expose: 3163 break; 3164 case MotionNotify: 3165 { 3166 segment_info.x2=(short int) event.xmotion.x; 3167 segment_info.y2=(short int) event.xmotion.y; 3168 } 3169 default: 3170 break; 3171 } 3172 /* 3173 Check boundary conditions. 3174 */ 3175 if (segment_info.x2 < 0) 3176 segment_info.x2=0; 3177 else 3178 if (segment_info.x2 > windows->image.ximage->width) 3179 segment_info.x2=windows->image.ximage->width; 3180 if (segment_info.y2 < 0) 3181 segment_info.y2=0; 3182 else 3183 if (segment_info.y2 > windows->image.ximage->height) 3184 segment_info.y2=windows->image.ximage->height; 3185 distance=(unsigned int) 3186 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3187 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3188 /* 3189 Compute chopping geometry. 3190 */ 3191 if (direction == HorizontalChopCommand) 3192 { 3193 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3194 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3195 chop_info.height=0; 3196 chop_info.y=0; 3197 if (segment_info.x1 > (int) segment_info.x2) 3198 { 3199 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3200 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3201 } 3202 } 3203 else 3204 { 3205 chop_info.width=0; 3206 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3207 chop_info.x=0; 3208 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3209 if (segment_info.y1 > segment_info.y2) 3210 { 3211 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3212 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3213 } 3214 } 3215 } while ((state & ExitState) == 0); 3216 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3217 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3218 if (distance <= 9) 3219 return(MagickTrue); 3220 /* 3221 Image chopping is relative to image configuration. 3222 */ 3223 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3224 exception); 3225 XSetCursorState(display,windows,MagickTrue); 3226 XCheckRefreshWindows(display,windows); 3227 windows->image.window_changes.width=windows->image.ximage->width- 3228 (unsigned int) chop_info.width; 3229 windows->image.window_changes.height=windows->image.ximage->height- 3230 (unsigned int) chop_info.height; 3231 width=(unsigned int) (*image)->columns; 3232 height=(unsigned int) (*image)->rows; 3233 x=0; 3234 y=0; 3235 if (windows->image.crop_geometry != (char *) NULL) 3236 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3237 scale_factor=(double) width/windows->image.ximage->width; 3238 chop_info.x+=x; 3239 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3240 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3241 scale_factor=(double) height/windows->image.ximage->height; 3242 chop_info.y+=y; 3243 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3244 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3245 /* 3246 Chop image. 3247 */ 3248 chop_image=ChopImage(*image,&chop_info,exception); 3249 XSetCursorState(display,windows,MagickFalse); 3250 if (chop_image == (Image *) NULL) 3251 return(MagickFalse); 3252 *image=DestroyImage(*image); 3253 *image=chop_image; 3254 /* 3255 Update image configuration. 3256 */ 3257 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3258 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3259 return(MagickTrue); 3260 } 3261 3262 /* 3264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3265 % % 3266 % % 3267 % % 3268 + X C o l o r E d i t I m a g e % 3269 % % 3270 % % 3271 % % 3272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3273 % 3274 % XColorEditImage() allows the user to interactively change the color of one 3275 % pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3276 % 3277 % The format of the XColorEditImage method is: 3278 % 3279 % MagickBooleanType XColorEditImage(Display *display, 3280 % XResourceInfo *resource_info,XWindows *windows,Image **image, 3281 % ExceptionInfo *exception) 3282 % 3283 % A description of each parameter follows: 3284 % 3285 % o display: Specifies a connection to an X server; returned from 3286 % XOpenDisplay. 3287 % 3288 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3289 % 3290 % o windows: Specifies a pointer to a XWindows structure. 3291 % 3292 % o image: the image; returned from ReadImage. 3293 % 3294 % o exception: return any errors or warnings in this structure. 3295 % 3296 */ 3297 static MagickBooleanType XColorEditImage(Display *display, 3298 XResourceInfo *resource_info,XWindows *windows,Image **image, 3299 ExceptionInfo *exception) 3300 { 3301 static const char 3302 *ColorEditMenu[] = 3303 { 3304 "Method", 3305 "Pixel Color", 3306 "Border Color", 3307 "Fuzz", 3308 "Undo", 3309 "Help", 3310 "Dismiss", 3311 (char *) NULL 3312 }; 3313 3314 static const ModeType 3315 ColorEditCommands[] = 3316 { 3317 ColorEditMethodCommand, 3318 ColorEditColorCommand, 3319 ColorEditBorderCommand, 3320 ColorEditFuzzCommand, 3321 ColorEditUndoCommand, 3322 ColorEditHelpCommand, 3323 ColorEditDismissCommand 3324 }; 3325 3326 static PaintMethod 3327 method = PointMethod; 3328 3329 static unsigned int 3330 pen_id = 0; 3331 3332 static XColor 3333 border_color = { 0, 0, 0, 0, 0, 0 }; 3334 3335 char 3336 command[MagickPathExtent], 3337 text[MagickPathExtent]; 3338 3339 Cursor 3340 cursor; 3341 3342 int 3343 entry, 3344 id, 3345 x, 3346 x_offset, 3347 y, 3348 y_offset; 3349 3350 register Quantum 3351 *q; 3352 3353 register ssize_t 3354 i; 3355 3356 unsigned int 3357 height, 3358 width; 3359 3360 size_t 3361 state; 3362 3363 XColor 3364 color; 3365 3366 XEvent 3367 event; 3368 3369 /* 3370 Map Command widget. 3371 */ 3372 (void) CloneString(&windows->command.name,"Color Edit"); 3373 windows->command.data=4; 3374 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3375 (void) XMapRaised(display,windows->command.id); 3376 XClientMessage(display,windows->image.id,windows->im_protocols, 3377 windows->im_update_widget,CurrentTime); 3378 /* 3379 Make cursor. 3380 */ 3381 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3382 resource_info->background_color,resource_info->foreground_color); 3383 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3384 /* 3385 Track pointer until button 1 is pressed. 3386 */ 3387 XQueryPosition(display,windows->image.id,&x,&y); 3388 (void) XSelectInput(display,windows->image.id, 3389 windows->image.attributes.event_mask | PointerMotionMask); 3390 state=DefaultState; 3391 do 3392 { 3393 if (windows->info.mapped != MagickFalse ) 3394 { 3395 /* 3396 Display pointer position. 3397 */ 3398 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 3399 x+windows->image.x,y+windows->image.y); 3400 XInfoWidget(display,windows,text); 3401 } 3402 /* 3403 Wait for next event. 3404 */ 3405 XScreenEvent(display,windows,&event,exception); 3406 if (event.xany.window == windows->command.id) 3407 { 3408 /* 3409 Select a command from the Command widget. 3410 */ 3411 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3412 if (id < 0) 3413 { 3414 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3415 continue; 3416 } 3417 switch (ColorEditCommands[id]) 3418 { 3419 case ColorEditMethodCommand: 3420 { 3421 char 3422 **methods; 3423 3424 /* 3425 Select a method from the pop-up menu. 3426 */ 3427 methods=(char **) GetCommandOptions(MagickMethodOptions); 3428 if (methods == (char **) NULL) 3429 break; 3430 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3431 (const char **) methods,command); 3432 if (entry >= 0) 3433 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3434 MagickFalse,methods[entry]); 3435 methods=DestroyStringList(methods); 3436 break; 3437 } 3438 case ColorEditColorCommand: 3439 { 3440 const char 3441 *ColorMenu[MaxNumberPens]; 3442 3443 int 3444 pen_number; 3445 3446 /* 3447 Initialize menu selections. 3448 */ 3449 for (i=0; i < (int) (MaxNumberPens-2); i++) 3450 ColorMenu[i]=resource_info->pen_colors[i]; 3451 ColorMenu[MaxNumberPens-2]="Browser..."; 3452 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3453 /* 3454 Select a pen color from the pop-up menu. 3455 */ 3456 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3457 (const char **) ColorMenu,command); 3458 if (pen_number < 0) 3459 break; 3460 if (pen_number == (MaxNumberPens-2)) 3461 { 3462 static char 3463 color_name[MagickPathExtent] = "gray"; 3464 3465 /* 3466 Select a pen color from a dialog. 3467 */ 3468 resource_info->pen_colors[pen_number]=color_name; 3469 XColorBrowserWidget(display,windows,"Select",color_name); 3470 if (*color_name == '\0') 3471 break; 3472 } 3473 /* 3474 Set pen color. 3475 */ 3476 (void) XParseColor(display,windows->map_info->colormap, 3477 resource_info->pen_colors[pen_number],&color); 3478 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3479 (unsigned int) MaxColors,&color); 3480 windows->pixel_info->pen_colors[pen_number]=color; 3481 pen_id=(unsigned int) pen_number; 3482 break; 3483 } 3484 case ColorEditBorderCommand: 3485 { 3486 const char 3487 *ColorMenu[MaxNumberPens]; 3488 3489 int 3490 pen_number; 3491 3492 /* 3493 Initialize menu selections. 3494 */ 3495 for (i=0; i < (int) (MaxNumberPens-2); i++) 3496 ColorMenu[i]=resource_info->pen_colors[i]; 3497 ColorMenu[MaxNumberPens-2]="Browser..."; 3498 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3499 /* 3500 Select a pen color from the pop-up menu. 3501 */ 3502 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3503 (const char **) ColorMenu,command); 3504 if (pen_number < 0) 3505 break; 3506 if (pen_number == (MaxNumberPens-2)) 3507 { 3508 static char 3509 color_name[MagickPathExtent] = "gray"; 3510 3511 /* 3512 Select a pen color from a dialog. 3513 */ 3514 resource_info->pen_colors[pen_number]=color_name; 3515 XColorBrowserWidget(display,windows,"Select",color_name); 3516 if (*color_name == '\0') 3517 break; 3518 } 3519 /* 3520 Set border color. 3521 */ 3522 (void) XParseColor(display,windows->map_info->colormap, 3523 resource_info->pen_colors[pen_number],&border_color); 3524 break; 3525 } 3526 case ColorEditFuzzCommand: 3527 { 3528 static char 3529 fuzz[MagickPathExtent]; 3530 3531 static const char 3532 *FuzzMenu[] = 3533 { 3534 "0%", 3535 "2%", 3536 "5%", 3537 "10%", 3538 "15%", 3539 "Dialog...", 3540 (char *) NULL, 3541 }; 3542 3543 /* 3544 Select a command from the pop-up menu. 3545 */ 3546 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3547 command); 3548 if (entry < 0) 3549 break; 3550 if (entry != 5) 3551 { 3552 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3553 QuantumRange+1.0); 3554 break; 3555 } 3556 (void) (void) CopyMagickString(fuzz,"20%",MagickPathExtent); 3557 (void) XDialogWidget(display,windows,"Ok", 3558 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3559 if (*fuzz == '\0') 3560 break; 3561 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent); 3562 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3563 1.0); 3564 break; 3565 } 3566 case ColorEditUndoCommand: 3567 { 3568 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3569 image,exception); 3570 break; 3571 } 3572 case ColorEditHelpCommand: 3573 default: 3574 { 3575 XTextViewWidget(display,resource_info,windows,MagickFalse, 3576 "Help Viewer - Image Annotation",ImageColorEditHelp); 3577 break; 3578 } 3579 case ColorEditDismissCommand: 3580 { 3581 /* 3582 Prematurely exit. 3583 */ 3584 state|=EscapeState; 3585 state|=ExitState; 3586 break; 3587 } 3588 } 3589 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3590 continue; 3591 } 3592 switch (event.type) 3593 { 3594 case ButtonPress: 3595 { 3596 if (event.xbutton.button != Button1) 3597 break; 3598 if ((event.xbutton.window != windows->image.id) && 3599 (event.xbutton.window != windows->magnify.id)) 3600 break; 3601 /* 3602 exit loop. 3603 */ 3604 x=event.xbutton.x; 3605 y=event.xbutton.y; 3606 (void) XMagickCommand(display,resource_info,windows, 3607 SaveToUndoBufferCommand,image,exception); 3608 state|=UpdateConfigurationState; 3609 break; 3610 } 3611 case ButtonRelease: 3612 { 3613 if (event.xbutton.button != Button1) 3614 break; 3615 if ((event.xbutton.window != windows->image.id) && 3616 (event.xbutton.window != windows->magnify.id)) 3617 break; 3618 /* 3619 Update colormap information. 3620 */ 3621 x=event.xbutton.x; 3622 y=event.xbutton.y; 3623 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3624 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3625 XInfoWidget(display,windows,text); 3626 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3627 state&=(~UpdateConfigurationState); 3628 break; 3629 } 3630 case Expose: 3631 break; 3632 case KeyPress: 3633 { 3634 KeySym 3635 key_symbol; 3636 3637 if (event.xkey.window == windows->magnify.id) 3638 { 3639 Window 3640 window; 3641 3642 window=windows->magnify.id; 3643 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3644 } 3645 if (event.xkey.window != windows->image.id) 3646 break; 3647 /* 3648 Respond to a user key press. 3649 */ 3650 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3651 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3652 switch ((int) key_symbol) 3653 { 3654 case XK_Escape: 3655 case XK_F20: 3656 { 3657 /* 3658 Prematurely exit. 3659 */ 3660 state|=ExitState; 3661 break; 3662 } 3663 case XK_F1: 3664 case XK_Help: 3665 { 3666 XTextViewWidget(display,resource_info,windows,MagickFalse, 3667 "Help Viewer - Image Annotation",ImageColorEditHelp); 3668 break; 3669 } 3670 default: 3671 { 3672 (void) XBell(display,0); 3673 break; 3674 } 3675 } 3676 break; 3677 } 3678 case MotionNotify: 3679 { 3680 /* 3681 Map and unmap Info widget as cursor crosses its boundaries. 3682 */ 3683 x=event.xmotion.x; 3684 y=event.xmotion.y; 3685 if (windows->info.mapped != MagickFalse ) 3686 { 3687 if ((x < (int) (windows->info.x+windows->info.width)) && 3688 (y < (int) (windows->info.y+windows->info.height))) 3689 (void) XWithdrawWindow(display,windows->info.id, 3690 windows->info.screen); 3691 } 3692 else 3693 if ((x > (int) (windows->info.x+windows->info.width)) || 3694 (y > (int) (windows->info.y+windows->info.height))) 3695 (void) XMapWindow(display,windows->info.id); 3696 break; 3697 } 3698 default: 3699 break; 3700 } 3701 if (event.xany.window == windows->magnify.id) 3702 { 3703 x=windows->magnify.x-windows->image.x; 3704 y=windows->magnify.y-windows->image.y; 3705 } 3706 x_offset=x; 3707 y_offset=y; 3708 if ((state & UpdateConfigurationState) != 0) 3709 { 3710 CacheView 3711 *image_view; 3712 3713 int 3714 x, 3715 y; 3716 3717 /* 3718 Pixel edit is relative to image configuration. 3719 */ 3720 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3721 MagickTrue); 3722 color=windows->pixel_info->pen_colors[pen_id]; 3723 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3724 width=(unsigned int) (*image)->columns; 3725 height=(unsigned int) (*image)->rows; 3726 x=0; 3727 y=0; 3728 if (windows->image.crop_geometry != (char *) NULL) 3729 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3730 &width,&height); 3731 x_offset=(int) 3732 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3733 y_offset=(int) 3734 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3735 if ((x_offset < 0) || (y_offset < 0)) 3736 continue; 3737 if ((x_offset >= (int) (*image)->columns) || 3738 (y_offset >= (int) (*image)->rows)) 3739 continue; 3740 image_view=AcquireAuthenticCacheView(*image,exception); 3741 switch (method) 3742 { 3743 case PointMethod: 3744 default: 3745 { 3746 /* 3747 Update color information using point algorithm. 3748 */ 3749 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3750 return(MagickFalse); 3751 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3752 (ssize_t) y_offset,1,1,exception); 3753 if (q == (Quantum *) NULL) 3754 break; 3755 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3756 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3757 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3758 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3759 break; 3760 } 3761 case ReplaceMethod: 3762 { 3763 PixelInfo 3764 pixel, 3765 target; 3766 3767 /* 3768 Update color information using replace algorithm. 3769 */ 3770 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3771 x_offset,(ssize_t) y_offset,&target,exception); 3772 if ((*image)->storage_class == DirectClass) 3773 { 3774 for (y=0; y < (int) (*image)->rows; y++) 3775 { 3776 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3777 (*image)->columns,1,exception); 3778 if (q == (Quantum *) NULL) 3779 break; 3780 for (x=0; x < (int) (*image)->columns; x++) 3781 { 3782 GetPixelInfoPixel(*image,q,&pixel); 3783 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3784 { 3785 SetPixelRed(*image,ScaleShortToQuantum( 3786 color.red),q); 3787 SetPixelGreen(*image,ScaleShortToQuantum( 3788 color.green),q); 3789 SetPixelBlue(*image,ScaleShortToQuantum( 3790 color.blue),q); 3791 } 3792 q+=GetPixelChannels(*image); 3793 } 3794 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3795 break; 3796 } 3797 } 3798 else 3799 { 3800 for (i=0; i < (ssize_t) (*image)->colors; i++) 3801 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3802 { 3803 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3804 color.red); 3805 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3806 color.green); 3807 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3808 color.blue); 3809 } 3810 (void) SyncImage(*image,exception); 3811 } 3812 break; 3813 } 3814 case FloodfillMethod: 3815 case FillToBorderMethod: 3816 { 3817 DrawInfo 3818 *draw_info; 3819 3820 PixelInfo 3821 target; 3822 3823 /* 3824 Update color information using floodfill algorithm. 3825 */ 3826 (void) GetOneVirtualPixelInfo(*image, 3827 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3828 y_offset,&target,exception); 3829 if (method == FillToBorderMethod) 3830 { 3831 target.red=(double) 3832 ScaleShortToQuantum(border_color.red); 3833 target.green=(double) 3834 ScaleShortToQuantum(border_color.green); 3835 target.blue=(double) 3836 ScaleShortToQuantum(border_color.blue); 3837 } 3838 draw_info=CloneDrawInfo(resource_info->image_info, 3839 (DrawInfo *) NULL); 3840 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3841 AllCompliance,&draw_info->fill,exception); 3842 (void) FloodfillPaintImage(*image,draw_info,&target, 3843 (ssize_t)x_offset,(ssize_t)y_offset, 3844 method != FloodfillMethod ? MagickTrue : MagickFalse,exception); 3845 draw_info=DestroyDrawInfo(draw_info); 3846 break; 3847 } 3848 case ResetMethod: 3849 { 3850 /* 3851 Update color information using reset algorithm. 3852 */ 3853 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3854 return(MagickFalse); 3855 for (y=0; y < (int) (*image)->rows; y++) 3856 { 3857 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3858 (*image)->columns,1,exception); 3859 if (q == (Quantum *) NULL) 3860 break; 3861 for (x=0; x < (int) (*image)->columns; x++) 3862 { 3863 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3864 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3865 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3866 q+=GetPixelChannels(*image); 3867 } 3868 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3869 break; 3870 } 3871 break; 3872 } 3873 } 3874 image_view=DestroyCacheView(image_view); 3875 state&=(~UpdateConfigurationState); 3876 } 3877 } while ((state & ExitState) == 0); 3878 (void) XSelectInput(display,windows->image.id, 3879 windows->image.attributes.event_mask); 3880 XSetCursorState(display,windows,MagickFalse); 3881 (void) XFreeCursor(display,cursor); 3882 return(MagickTrue); 3883 } 3884 3885 /* 3887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3888 % % 3889 % % 3890 % % 3891 + X C o m p o s i t e I m a g e % 3892 % % 3893 % % 3894 % % 3895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3896 % 3897 % XCompositeImage() requests an image name from the user, reads the image and 3898 % composites it with the X window image at a location the user chooses with 3899 % the pointer. 3900 % 3901 % The format of the XCompositeImage method is: 3902 % 3903 % MagickBooleanType XCompositeImage(Display *display, 3904 % XResourceInfo *resource_info,XWindows *windows,Image *image, 3905 % ExceptionInfo *exception) 3906 % 3907 % A description of each parameter follows: 3908 % 3909 % o display: Specifies a connection to an X server; returned from 3910 % XOpenDisplay. 3911 % 3912 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3913 % 3914 % o windows: Specifies a pointer to a XWindows structure. 3915 % 3916 % o image: the image; returned from ReadImage. 3917 % 3918 % o exception: return any errors or warnings in this structure. 3919 % 3920 */ 3921 static MagickBooleanType XCompositeImage(Display *display, 3922 XResourceInfo *resource_info,XWindows *windows,Image *image, 3923 ExceptionInfo *exception) 3924 { 3925 static char 3926 displacement_geometry[MagickPathExtent] = "30x30", 3927 filename[MagickPathExtent] = "\0"; 3928 3929 static const char 3930 *CompositeMenu[] = 3931 { 3932 "Operators", 3933 "Dissolve", 3934 "Displace", 3935 "Help", 3936 "Dismiss", 3937 (char *) NULL 3938 }; 3939 3940 static CompositeOperator 3941 compose = CopyCompositeOp; 3942 3943 static const ModeType 3944 CompositeCommands[] = 3945 { 3946 CompositeOperatorsCommand, 3947 CompositeDissolveCommand, 3948 CompositeDisplaceCommand, 3949 CompositeHelpCommand, 3950 CompositeDismissCommand 3951 }; 3952 3953 char 3954 text[MagickPathExtent]; 3955 3956 Cursor 3957 cursor; 3958 3959 Image 3960 *composite_image; 3961 3962 int 3963 entry, 3964 id, 3965 x, 3966 y; 3967 3968 double 3969 blend, 3970 scale_factor; 3971 3972 RectangleInfo 3973 highlight_info, 3974 composite_info; 3975 3976 unsigned int 3977 height, 3978 width; 3979 3980 size_t 3981 state; 3982 3983 XEvent 3984 event; 3985 3986 /* 3987 Request image file name from user. 3988 */ 3989 XFileBrowserWidget(display,windows,"Composite",filename); 3990 if (*filename == '\0') 3991 return(MagickTrue); 3992 /* 3993 Read image. 3994 */ 3995 XSetCursorState(display,windows,MagickTrue); 3996 XCheckRefreshWindows(display,windows); 3997 (void) CopyMagickString(resource_info->image_info->filename,filename, 3998 MagickPathExtent); 3999 composite_image=ReadImage(resource_info->image_info,exception); 4000 CatchException(exception); 4001 XSetCursorState(display,windows,MagickFalse); 4002 if (composite_image == (Image *) NULL) 4003 return(MagickFalse); 4004 /* 4005 Map Command widget. 4006 */ 4007 (void) CloneString(&windows->command.name,"Composite"); 4008 windows->command.data=1; 4009 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4010 (void) XMapRaised(display,windows->command.id); 4011 XClientMessage(display,windows->image.id,windows->im_protocols, 4012 windows->im_update_widget,CurrentTime); 4013 /* 4014 Track pointer until button 1 is pressed. 4015 */ 4016 XQueryPosition(display,windows->image.id,&x,&y); 4017 (void) XSelectInput(display,windows->image.id, 4018 windows->image.attributes.event_mask | PointerMotionMask); 4019 composite_info.x=(ssize_t) windows->image.x+x; 4020 composite_info.y=(ssize_t) windows->image.y+y; 4021 composite_info.width=0; 4022 composite_info.height=0; 4023 cursor=XCreateFontCursor(display,XC_ul_angle); 4024 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4025 blend=0.0; 4026 state=DefaultState; 4027 do 4028 { 4029 if (windows->info.mapped != MagickFalse ) 4030 { 4031 /* 4032 Display pointer position. 4033 */ 4034 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 4035 (long) composite_info.x,(long) composite_info.y); 4036 XInfoWidget(display,windows,text); 4037 } 4038 highlight_info=composite_info; 4039 highlight_info.x=composite_info.x-windows->image.x; 4040 highlight_info.y=composite_info.y-windows->image.y; 4041 XHighlightRectangle(display,windows->image.id, 4042 windows->image.highlight_context,&highlight_info); 4043 /* 4044 Wait for next event. 4045 */ 4046 XScreenEvent(display,windows,&event,exception); 4047 XHighlightRectangle(display,windows->image.id, 4048 windows->image.highlight_context,&highlight_info); 4049 if (event.xany.window == windows->command.id) 4050 { 4051 /* 4052 Select a command from the Command widget. 4053 */ 4054 id=XCommandWidget(display,windows,CompositeMenu,&event); 4055 if (id < 0) 4056 continue; 4057 switch (CompositeCommands[id]) 4058 { 4059 case CompositeOperatorsCommand: 4060 { 4061 char 4062 command[MagickPathExtent], 4063 **operators; 4064 4065 /* 4066 Select a command from the pop-up menu. 4067 */ 4068 operators=GetCommandOptions(MagickComposeOptions); 4069 if (operators == (char **) NULL) 4070 break; 4071 entry=XMenuWidget(display,windows,CompositeMenu[id], 4072 (const char **) operators,command); 4073 if (entry >= 0) 4074 compose=(CompositeOperator) ParseCommandOption( 4075 MagickComposeOptions,MagickFalse,operators[entry]); 4076 operators=DestroyStringList(operators); 4077 break; 4078 } 4079 case CompositeDissolveCommand: 4080 { 4081 static char 4082 factor[MagickPathExtent] = "20.0"; 4083 4084 /* 4085 Dissolve the two images a given percent. 4086 */ 4087 (void) XSetFunction(display,windows->image.highlight_context, 4088 GXcopy); 4089 (void) XDialogWidget(display,windows,"Dissolve", 4090 "Enter the blend factor (0.0 - 99.9%):",factor); 4091 (void) XSetFunction(display,windows->image.highlight_context, 4092 GXinvert); 4093 if (*factor == '\0') 4094 break; 4095 blend=StringToDouble(factor,(char **) NULL); 4096 compose=DissolveCompositeOp; 4097 break; 4098 } 4099 case CompositeDisplaceCommand: 4100 { 4101 /* 4102 Get horizontal and vertical scale displacement geometry. 4103 */ 4104 (void) XSetFunction(display,windows->image.highlight_context, 4105 GXcopy); 4106 (void) XDialogWidget(display,windows,"Displace", 4107 "Enter the horizontal and vertical scale:",displacement_geometry); 4108 (void) XSetFunction(display,windows->image.highlight_context, 4109 GXinvert); 4110 if (*displacement_geometry == '\0') 4111 break; 4112 compose=DisplaceCompositeOp; 4113 break; 4114 } 4115 case CompositeHelpCommand: 4116 { 4117 (void) XSetFunction(display,windows->image.highlight_context, 4118 GXcopy); 4119 XTextViewWidget(display,resource_info,windows,MagickFalse, 4120 "Help Viewer - Image Composite",ImageCompositeHelp); 4121 (void) XSetFunction(display,windows->image.highlight_context, 4122 GXinvert); 4123 break; 4124 } 4125 case CompositeDismissCommand: 4126 { 4127 /* 4128 Prematurely exit. 4129 */ 4130 state|=EscapeState; 4131 state|=ExitState; 4132 break; 4133 } 4134 default: 4135 break; 4136 } 4137 continue; 4138 } 4139 switch (event.type) 4140 { 4141 case ButtonPress: 4142 { 4143 if (image->debug != MagickFalse ) 4144 (void) LogMagickEvent(X11Event,GetMagickModule(), 4145 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4146 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4147 if (event.xbutton.button != Button1) 4148 break; 4149 if (event.xbutton.window != windows->image.id) 4150 break; 4151 /* 4152 Change cursor. 4153 */ 4154 composite_info.width=composite_image->columns; 4155 composite_info.height=composite_image->rows; 4156 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4157 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4158 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4159 break; 4160 } 4161 case ButtonRelease: 4162 { 4163 if (image->debug != MagickFalse ) 4164 (void) LogMagickEvent(X11Event,GetMagickModule(), 4165 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4166 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4167 if (event.xbutton.button != Button1) 4168 break; 4169 if (event.xbutton.window != windows->image.id) 4170 break; 4171 if ((composite_info.width != 0) && (composite_info.height != 0)) 4172 { 4173 /* 4174 User has selected the location of the composite image. 4175 */ 4176 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4177 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4178 state|=ExitState; 4179 } 4180 break; 4181 } 4182 case Expose: 4183 break; 4184 case KeyPress: 4185 { 4186 char 4187 command[MagickPathExtent]; 4188 4189 KeySym 4190 key_symbol; 4191 4192 int 4193 length; 4194 4195 if (event.xkey.window != windows->image.id) 4196 break; 4197 /* 4198 Respond to a user key press. 4199 */ 4200 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4201 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4202 *(command+length)='\0'; 4203 if (image->debug != MagickFalse ) 4204 (void) LogMagickEvent(X11Event,GetMagickModule(), 4205 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4206 switch ((int) key_symbol) 4207 { 4208 case XK_Escape: 4209 case XK_F20: 4210 { 4211 /* 4212 Prematurely exit. 4213 */ 4214 composite_image=DestroyImage(composite_image); 4215 state|=EscapeState; 4216 state|=ExitState; 4217 break; 4218 } 4219 case XK_F1: 4220 case XK_Help: 4221 { 4222 (void) XSetFunction(display,windows->image.highlight_context, 4223 GXcopy); 4224 XTextViewWidget(display,resource_info,windows,MagickFalse, 4225 "Help Viewer - Image Composite",ImageCompositeHelp); 4226 (void) XSetFunction(display,windows->image.highlight_context, 4227 GXinvert); 4228 break; 4229 } 4230 default: 4231 { 4232 (void) XBell(display,0); 4233 break; 4234 } 4235 } 4236 break; 4237 } 4238 case MotionNotify: 4239 { 4240 /* 4241 Map and unmap Info widget as text cursor crosses its boundaries. 4242 */ 4243 x=event.xmotion.x; 4244 y=event.xmotion.y; 4245 if (windows->info.mapped != MagickFalse ) 4246 { 4247 if ((x < (int) (windows->info.x+windows->info.width)) && 4248 (y < (int) (windows->info.y+windows->info.height))) 4249 (void) XWithdrawWindow(display,windows->info.id, 4250 windows->info.screen); 4251 } 4252 else 4253 if ((x > (int) (windows->info.x+windows->info.width)) || 4254 (y > (int) (windows->info.y+windows->info.height))) 4255 (void) XMapWindow(display,windows->info.id); 4256 composite_info.x=(ssize_t) windows->image.x+x; 4257 composite_info.y=(ssize_t) windows->image.y+y; 4258 break; 4259 } 4260 default: 4261 { 4262 if (image->debug != MagickFalse ) 4263 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4264 event.type); 4265 break; 4266 } 4267 } 4268 } while ((state & ExitState) == 0); 4269 (void) XSelectInput(display,windows->image.id, 4270 windows->image.attributes.event_mask); 4271 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4272 XSetCursorState(display,windows,MagickFalse); 4273 (void) XFreeCursor(display,cursor); 4274 if ((state & EscapeState) != 0) 4275 return(MagickTrue); 4276 /* 4277 Image compositing is relative to image configuration. 4278 */ 4279 XSetCursorState(display,windows,MagickTrue); 4280 XCheckRefreshWindows(display,windows); 4281 width=(unsigned int) image->columns; 4282 height=(unsigned int) image->rows; 4283 x=0; 4284 y=0; 4285 if (windows->image.crop_geometry != (char *) NULL) 4286 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4287 scale_factor=(double) width/windows->image.ximage->width; 4288 composite_info.x+=x; 4289 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4290 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4291 scale_factor=(double) height/windows->image.ximage->height; 4292 composite_info.y+=y; 4293 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4294 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4295 if ((composite_info.width != composite_image->columns) || 4296 (composite_info.height != composite_image->rows)) 4297 { 4298 Image 4299 *resize_image; 4300 4301 /* 4302 Scale composite image. 4303 */ 4304 resize_image=ResizeImage(composite_image,composite_info.width, 4305 composite_info.height,composite_image->filter,exception); 4306 composite_image=DestroyImage(composite_image); 4307 if (resize_image == (Image *) NULL) 4308 { 4309 XSetCursorState(display,windows,MagickFalse); 4310 return(MagickFalse); 4311 } 4312 composite_image=resize_image; 4313 } 4314 if (compose == DisplaceCompositeOp) 4315 (void) SetImageArtifact(composite_image,"compose:args", 4316 displacement_geometry); 4317 if (blend != 0.0) 4318 { 4319 CacheView 4320 *image_view; 4321 4322 int 4323 y; 4324 4325 Quantum 4326 opacity; 4327 4328 register int 4329 x; 4330 4331 register Quantum 4332 *q; 4333 4334 /* 4335 Create mattes for blending. 4336 */ 4337 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4338 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4339 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4340 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4341 return(MagickFalse); 4342 image->alpha_trait=BlendPixelTrait; 4343 image_view=AcquireAuthenticCacheView(image,exception); 4344 for (y=0; y < (int) image->rows; y++) 4345 { 4346 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4347 exception); 4348 if (q == (Quantum *) NULL) 4349 break; 4350 for (x=0; x < (int) image->columns; x++) 4351 { 4352 SetPixelAlpha(image,opacity,q); 4353 q+=GetPixelChannels(image); 4354 } 4355 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4356 break; 4357 } 4358 image_view=DestroyCacheView(image_view); 4359 } 4360 /* 4361 Composite image with X Image window. 4362 */ 4363 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4364 composite_info.x,composite_info.y,exception); 4365 composite_image=DestroyImage(composite_image); 4366 XSetCursorState(display,windows,MagickFalse); 4367 /* 4368 Update image configuration. 4369 */ 4370 XConfigureImageColormap(display,resource_info,windows,image,exception); 4371 (void) XConfigureImage(display,resource_info,windows,image,exception); 4372 return(MagickTrue); 4373 } 4374 4375 /* 4377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4378 % % 4379 % % 4380 % % 4381 + X C o n f i g u r e I m a g e % 4382 % % 4383 % % 4384 % % 4385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4386 % 4387 % XConfigureImage() creates a new X image. It also notifies the window 4388 % manager of the new image size and configures the transient widows. 4389 % 4390 % The format of the XConfigureImage method is: 4391 % 4392 % MagickBooleanType XConfigureImage(Display *display, 4393 % XResourceInfo *resource_info,XWindows *windows,Image *image, 4394 % ExceptionInfo *exception) 4395 % 4396 % A description of each parameter follows: 4397 % 4398 % o display: Specifies a connection to an X server; returned from 4399 % XOpenDisplay. 4400 % 4401 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4402 % 4403 % o windows: Specifies a pointer to a XWindows structure. 4404 % 4405 % o image: the image. 4406 % 4407 % o exception: return any errors or warnings in this structure. 4408 % 4409 % o exception: return any errors or warnings in this structure. 4410 % 4411 */ 4412 static MagickBooleanType XConfigureImage(Display *display, 4413 XResourceInfo *resource_info,XWindows *windows,Image *image, 4414 ExceptionInfo *exception) 4415 { 4416 char 4417 geometry[MagickPathExtent]; 4418 4419 MagickStatusType 4420 status; 4421 4422 size_t 4423 mask, 4424 height, 4425 width; 4426 4427 ssize_t 4428 x, 4429 y; 4430 4431 XSizeHints 4432 *size_hints; 4433 4434 XWindowChanges 4435 window_changes; 4436 4437 /* 4438 Dismiss if window dimensions are zero. 4439 */ 4440 width=(unsigned int) windows->image.window_changes.width; 4441 height=(unsigned int) windows->image.window_changes.height; 4442 if (image->debug != MagickFalse ) 4443 (void) LogMagickEvent(X11Event,GetMagickModule(), 4444 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4445 windows->image.ximage->height,(double) width,(double) height); 4446 if ((width*height) == 0) 4447 return(MagickTrue); 4448 x=0; 4449 y=0; 4450 /* 4451 Resize image to fit Image window dimensions. 4452 */ 4453 XSetCursorState(display,windows,MagickTrue); 4454 (void) XFlush(display); 4455 if (((int) width != windows->image.ximage->width) || 4456 ((int) height != windows->image.ximage->height)) 4457 image->taint=MagickTrue; 4458 windows->magnify.x=(int) 4459 width*windows->magnify.x/windows->image.ximage->width; 4460 windows->magnify.y=(int) 4461 height*windows->magnify.y/windows->image.ximage->height; 4462 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4463 windows->image.y=(int) 4464 (height*windows->image.y/windows->image.ximage->height); 4465 status=XMakeImage(display,resource_info,&windows->image,image, 4466 (unsigned int) width,(unsigned int) height,exception); 4467 if (status == MagickFalse) 4468 XNoticeWidget(display,windows,"Unable to configure X image:", 4469 windows->image.name); 4470 /* 4471 Notify window manager of the new configuration. 4472 */ 4473 if (resource_info->image_geometry != (char *) NULL) 4474 (void) FormatLocaleString(geometry,MagickPathExtent,"%s>!", 4475 resource_info->image_geometry); 4476 else 4477 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!", 4478 XDisplayWidth(display,windows->image.screen), 4479 XDisplayHeight(display,windows->image.screen)); 4480 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4481 window_changes.width=(int) width; 4482 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4483 window_changes.width=XDisplayWidth(display,windows->image.screen); 4484 window_changes.height=(int) height; 4485 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4486 window_changes.height=XDisplayHeight(display,windows->image.screen); 4487 mask=(size_t) (CWWidth | CWHeight); 4488 if (resource_info->backdrop) 4489 { 4490 mask|=CWX | CWY; 4491 window_changes.x=(int) 4492 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4493 window_changes.y=(int) 4494 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4495 } 4496 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4497 (unsigned int) mask,&window_changes); 4498 (void) XClearWindow(display,windows->image.id); 4499 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4500 /* 4501 Update Magnify window configuration. 4502 */ 4503 if (windows->magnify.mapped != MagickFalse ) 4504 XMakeMagnifyImage(display,windows,exception); 4505 windows->pan.crop_geometry=windows->image.crop_geometry; 4506 XBestIconSize(display,&windows->pan,image); 4507 while (((windows->pan.width << 1) < MaxIconSize) && 4508 ((windows->pan.height << 1) < MaxIconSize)) 4509 { 4510 windows->pan.width<<=1; 4511 windows->pan.height<<=1; 4512 } 4513 if (windows->pan.geometry != (char *) NULL) 4514 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4515 &windows->pan.width,&windows->pan.height); 4516 window_changes.width=(int) windows->pan.width; 4517 window_changes.height=(int) windows->pan.height; 4518 size_hints=XAllocSizeHints(); 4519 if (size_hints != (XSizeHints *) NULL) 4520 { 4521 /* 4522 Set new size hints. 4523 */ 4524 size_hints->flags=PSize | PMinSize | PMaxSize; 4525 size_hints->width=window_changes.width; 4526 size_hints->height=window_changes.height; 4527 size_hints->min_width=size_hints->width; 4528 size_hints->min_height=size_hints->height; 4529 size_hints->max_width=size_hints->width; 4530 size_hints->max_height=size_hints->height; 4531 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4532 (void) XFree((void *) size_hints); 4533 } 4534 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4535 (unsigned int) (CWWidth | CWHeight),&window_changes); 4536 /* 4537 Update icon window configuration. 4538 */ 4539 windows->icon.crop_geometry=windows->image.crop_geometry; 4540 XBestIconSize(display,&windows->icon,image); 4541 window_changes.width=(int) windows->icon.width; 4542 window_changes.height=(int) windows->icon.height; 4543 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4544 (unsigned int) (CWWidth | CWHeight),&window_changes); 4545 XSetCursorState(display,windows,MagickFalse); 4546 return(status != 0 ? MagickTrue : MagickFalse); 4547 } 4548 4549 /* 4551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4552 % % 4553 % % 4554 % % 4555 + X C r o p I m a g e % 4556 % % 4557 % % 4558 % % 4559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4560 % 4561 % XCropImage() allows the user to select a region of the image and crop, copy, 4562 % or cut it. For copy or cut, the image can subsequently be composited onto 4563 % the image with XPasteImage. 4564 % 4565 % The format of the XCropImage method is: 4566 % 4567 % MagickBooleanType XCropImage(Display *display, 4568 % XResourceInfo *resource_info,XWindows *windows,Image *image, 4569 % const ClipboardMode mode,ExceptionInfo *exception) 4570 % 4571 % A description of each parameter follows: 4572 % 4573 % o display: Specifies a connection to an X server; returned from 4574 % XOpenDisplay. 4575 % 4576 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4577 % 4578 % o windows: Specifies a pointer to a XWindows structure. 4579 % 4580 % o image: the image; returned from ReadImage. 4581 % 4582 % o mode: This unsigned value specified whether the image should be 4583 % cropped, copied, or cut. 4584 % 4585 % o exception: return any errors or warnings in this structure. 4586 % 4587 */ 4588 static MagickBooleanType XCropImage(Display *display, 4589 XResourceInfo *resource_info,XWindows *windows,Image *image, 4590 const ClipboardMode mode,ExceptionInfo *exception) 4591 { 4592 static const char 4593 *CropModeMenu[] = 4594 { 4595 "Help", 4596 "Dismiss", 4597 (char *) NULL 4598 }, 4599 *RectifyModeMenu[] = 4600 { 4601 "Crop", 4602 "Help", 4603 "Dismiss", 4604 (char *) NULL 4605 }; 4606 4607 static const ModeType 4608 CropCommands[] = 4609 { 4610 CropHelpCommand, 4611 CropDismissCommand 4612 }, 4613 RectifyCommands[] = 4614 { 4615 RectifyCopyCommand, 4616 RectifyHelpCommand, 4617 RectifyDismissCommand 4618 }; 4619 4620 CacheView 4621 *image_view; 4622 4623 char 4624 command[MagickPathExtent], 4625 text[MagickPathExtent]; 4626 4627 Cursor 4628 cursor; 4629 4630 int 4631 id, 4632 x, 4633 y; 4634 4635 KeySym 4636 key_symbol; 4637 4638 Image 4639 *crop_image; 4640 4641 double 4642 scale_factor; 4643 4644 RectangleInfo 4645 crop_info, 4646 highlight_info; 4647 4648 register Quantum 4649 *q; 4650 4651 unsigned int 4652 height, 4653 width; 4654 4655 size_t 4656 state; 4657 4658 XEvent 4659 event; 4660 4661 /* 4662 Map Command widget. 4663 */ 4664 switch (mode) 4665 { 4666 case CopyMode: 4667 { 4668 (void) CloneString(&windows->command.name,"Copy"); 4669 break; 4670 } 4671 case CropMode: 4672 { 4673 (void) CloneString(&windows->command.name,"Crop"); 4674 break; 4675 } 4676 case CutMode: 4677 { 4678 (void) CloneString(&windows->command.name,"Cut"); 4679 break; 4680 } 4681 } 4682 RectifyModeMenu[0]=windows->command.name; 4683 windows->command.data=0; 4684 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4685 (void) XMapRaised(display,windows->command.id); 4686 XClientMessage(display,windows->image.id,windows->im_protocols, 4687 windows->im_update_widget,CurrentTime); 4688 /* 4689 Track pointer until button 1 is pressed. 4690 */ 4691 XQueryPosition(display,windows->image.id,&x,&y); 4692 (void) XSelectInput(display,windows->image.id, 4693 windows->image.attributes.event_mask | PointerMotionMask); 4694 crop_info.x=(ssize_t) windows->image.x+x; 4695 crop_info.y=(ssize_t) windows->image.y+y; 4696 crop_info.width=0; 4697 crop_info.height=0; 4698 cursor=XCreateFontCursor(display,XC_fleur); 4699 state=DefaultState; 4700 do 4701 { 4702 if (windows->info.mapped != MagickFalse ) 4703 { 4704 /* 4705 Display pointer position. 4706 */ 4707 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 4708 (long) crop_info.x,(long) crop_info.y); 4709 XInfoWidget(display,windows,text); 4710 } 4711 /* 4712 Wait for next event. 4713 */ 4714 XScreenEvent(display,windows,&event,exception); 4715 if (event.xany.window == windows->command.id) 4716 { 4717 /* 4718 Select a command from the Command widget. 4719 */ 4720 id=XCommandWidget(display,windows,CropModeMenu,&event); 4721 if (id < 0) 4722 continue; 4723 switch (CropCommands[id]) 4724 { 4725 case CropHelpCommand: 4726 { 4727 switch (mode) 4728 { 4729 case CopyMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Copy",ImageCopyHelp); 4733 break; 4734 } 4735 case CropMode: 4736 { 4737 XTextViewWidget(display,resource_info,windows,MagickFalse, 4738 "Help Viewer - Image Crop",ImageCropHelp); 4739 break; 4740 } 4741 case CutMode: 4742 { 4743 XTextViewWidget(display,resource_info,windows,MagickFalse, 4744 "Help Viewer - Image Cut",ImageCutHelp); 4745 break; 4746 } 4747 } 4748 break; 4749 } 4750 case CropDismissCommand: 4751 { 4752 /* 4753 Prematurely exit. 4754 */ 4755 state|=EscapeState; 4756 state|=ExitState; 4757 break; 4758 } 4759 default: 4760 break; 4761 } 4762 continue; 4763 } 4764 switch (event.type) 4765 { 4766 case ButtonPress: 4767 { 4768 if (event.xbutton.button != Button1) 4769 break; 4770 if (event.xbutton.window != windows->image.id) 4771 break; 4772 /* 4773 Note first corner of cropping rectangle-- exit loop. 4774 */ 4775 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4776 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4777 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4778 state|=ExitState; 4779 break; 4780 } 4781 case ButtonRelease: 4782 break; 4783 case Expose: 4784 break; 4785 case KeyPress: 4786 { 4787 if (event.xkey.window != windows->image.id) 4788 break; 4789 /* 4790 Respond to a user key press. 4791 */ 4792 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4793 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4794 switch ((int) key_symbol) 4795 { 4796 case XK_Escape: 4797 case XK_F20: 4798 { 4799 /* 4800 Prematurely exit. 4801 */ 4802 state|=EscapeState; 4803 state|=ExitState; 4804 break; 4805 } 4806 case XK_F1: 4807 case XK_Help: 4808 { 4809 switch (mode) 4810 { 4811 case CopyMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Copy",ImageCopyHelp); 4815 break; 4816 } 4817 case CropMode: 4818 { 4819 XTextViewWidget(display,resource_info,windows,MagickFalse, 4820 "Help Viewer - Image Crop",ImageCropHelp); 4821 break; 4822 } 4823 case CutMode: 4824 { 4825 XTextViewWidget(display,resource_info,windows,MagickFalse, 4826 "Help Viewer - Image Cut",ImageCutHelp); 4827 break; 4828 } 4829 } 4830 break; 4831 } 4832 default: 4833 { 4834 (void) XBell(display,0); 4835 break; 4836 } 4837 } 4838 break; 4839 } 4840 case MotionNotify: 4841 { 4842 if (event.xmotion.window != windows->image.id) 4843 break; 4844 /* 4845 Map and unmap Info widget as text cursor crosses its boundaries. 4846 */ 4847 x=event.xmotion.x; 4848 y=event.xmotion.y; 4849 if (windows->info.mapped != MagickFalse ) 4850 { 4851 if ((x < (int) (windows->info.x+windows->info.width)) && 4852 (y < (int) (windows->info.y+windows->info.height))) 4853 (void) XWithdrawWindow(display,windows->info.id, 4854 windows->info.screen); 4855 } 4856 else 4857 if ((x > (int) (windows->info.x+windows->info.width)) || 4858 (y > (int) (windows->info.y+windows->info.height))) 4859 (void) XMapWindow(display,windows->info.id); 4860 crop_info.x=(ssize_t) windows->image.x+x; 4861 crop_info.y=(ssize_t) windows->image.y+y; 4862 break; 4863 } 4864 default: 4865 break; 4866 } 4867 } while ((state & ExitState) == 0); 4868 (void) XSelectInput(display,windows->image.id, 4869 windows->image.attributes.event_mask); 4870 if ((state & EscapeState) != 0) 4871 { 4872 /* 4873 User want to exit without cropping. 4874 */ 4875 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4876 (void) XFreeCursor(display,cursor); 4877 return(MagickTrue); 4878 } 4879 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4880 do 4881 { 4882 /* 4883 Size rectangle as pointer moves until the mouse button is released. 4884 */ 4885 x=(int) crop_info.x; 4886 y=(int) crop_info.y; 4887 crop_info.width=0; 4888 crop_info.height=0; 4889 state=DefaultState; 4890 do 4891 { 4892 highlight_info=crop_info; 4893 highlight_info.x=crop_info.x-windows->image.x; 4894 highlight_info.y=crop_info.y-windows->image.y; 4895 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4896 { 4897 /* 4898 Display info and draw cropping rectangle. 4899 */ 4900 if (windows->info.mapped == MagickFalse) 4901 (void) XMapWindow(display,windows->info.id); 4902 (void) FormatLocaleString(text,MagickPathExtent, 4903 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4904 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4905 XInfoWidget(display,windows,text); 4906 XHighlightRectangle(display,windows->image.id, 4907 windows->image.highlight_context,&highlight_info); 4908 } 4909 else 4910 if (windows->info.mapped != MagickFalse ) 4911 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4912 /* 4913 Wait for next event. 4914 */ 4915 XScreenEvent(display,windows,&event,exception); 4916 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4917 XHighlightRectangle(display,windows->image.id, 4918 windows->image.highlight_context,&highlight_info); 4919 switch (event.type) 4920 { 4921 case ButtonPress: 4922 { 4923 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4924 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4925 break; 4926 } 4927 case ButtonRelease: 4928 { 4929 /* 4930 User has committed to cropping rectangle. 4931 */ 4932 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4933 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4934 XSetCursorState(display,windows,MagickFalse); 4935 state|=ExitState; 4936 windows->command.data=0; 4937 (void) XCommandWidget(display,windows,RectifyModeMenu, 4938 (XEvent *) NULL); 4939 break; 4940 } 4941 case Expose: 4942 break; 4943 case MotionNotify: 4944 { 4945 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4946 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4947 } 4948 default: 4949 break; 4950 } 4951 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4952 ((state & ExitState) != 0)) 4953 { 4954 /* 4955 Check boundary conditions. 4956 */ 4957 if (crop_info.x < 0) 4958 crop_info.x=0; 4959 else 4960 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4961 crop_info.x=(ssize_t) windows->image.ximage->width; 4962 if ((int) crop_info.x < x) 4963 crop_info.width=(unsigned int) (x-crop_info.x); 4964 else 4965 { 4966 crop_info.width=(unsigned int) (crop_info.x-x); 4967 crop_info.x=(ssize_t) x; 4968 } 4969 if (crop_info.y < 0) 4970 crop_info.y=0; 4971 else 4972 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4973 crop_info.y=(ssize_t) windows->image.ximage->height; 4974 if ((int) crop_info.y < y) 4975 crop_info.height=(unsigned int) (y-crop_info.y); 4976 else 4977 { 4978 crop_info.height=(unsigned int) (crop_info.y-y); 4979 crop_info.y=(ssize_t) y; 4980 } 4981 } 4982 } while ((state & ExitState) == 0); 4983 /* 4984 Wait for user to grab a corner of the rectangle or press return. 4985 */ 4986 state=DefaultState; 4987 (void) XMapWindow(display,windows->info.id); 4988 do 4989 { 4990 if (windows->info.mapped != MagickFalse ) 4991 { 4992 /* 4993 Display pointer position. 4994 */ 4995 (void) FormatLocaleString(text,MagickPathExtent, 4996 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4997 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4998 XInfoWidget(display,windows,text); 4999 } 5000 highlight_info=crop_info; 5001 highlight_info.x=crop_info.x-windows->image.x; 5002 highlight_info.y=crop_info.y-windows->image.y; 5003 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5004 { 5005 state|=EscapeState; 5006 state|=ExitState; 5007 break; 5008 } 5009 XHighlightRectangle(display,windows->image.id, 5010 windows->image.highlight_context,&highlight_info); 5011 XScreenEvent(display,windows,&event,exception); 5012 if (event.xany.window == windows->command.id) 5013 { 5014 /* 5015 Select a command from the Command widget. 5016 */ 5017 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5018 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5019 (void) XSetFunction(display,windows->image.highlight_context, 5020 GXinvert); 5021 XHighlightRectangle(display,windows->image.id, 5022 windows->image.highlight_context,&highlight_info); 5023 if (id >= 0) 5024 switch (RectifyCommands[id]) 5025 { 5026 case RectifyCopyCommand: 5027 { 5028 state|=ExitState; 5029 break; 5030 } 5031 case RectifyHelpCommand: 5032 { 5033 (void) XSetFunction(display,windows->image.highlight_context, 5034 GXcopy); 5035 switch (mode) 5036 { 5037 case CopyMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Copy",ImageCopyHelp); 5041 break; 5042 } 5043 case CropMode: 5044 { 5045 XTextViewWidget(display,resource_info,windows,MagickFalse, 5046 "Help Viewer - Image Crop",ImageCropHelp); 5047 break; 5048 } 5049 case CutMode: 5050 { 5051 XTextViewWidget(display,resource_info,windows,MagickFalse, 5052 "Help Viewer - Image Cut",ImageCutHelp); 5053 break; 5054 } 5055 } 5056 (void) XSetFunction(display,windows->image.highlight_context, 5057 GXinvert); 5058 break; 5059 } 5060 case RectifyDismissCommand: 5061 { 5062 /* 5063 Prematurely exit. 5064 */ 5065 state|=EscapeState; 5066 state|=ExitState; 5067 break; 5068 } 5069 default: 5070 break; 5071 } 5072 continue; 5073 } 5074 XHighlightRectangle(display,windows->image.id, 5075 windows->image.highlight_context,&highlight_info); 5076 switch (event.type) 5077 { 5078 case ButtonPress: 5079 { 5080 if (event.xbutton.button != Button1) 5081 break; 5082 if (event.xbutton.window != windows->image.id) 5083 break; 5084 x=windows->image.x+event.xbutton.x; 5085 y=windows->image.y+event.xbutton.y; 5086 if ((x < (int) (crop_info.x+RoiDelta)) && 5087 (x > (int) (crop_info.x-RoiDelta)) && 5088 (y < (int) (crop_info.y+RoiDelta)) && 5089 (y > (int) (crop_info.y-RoiDelta))) 5090 { 5091 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5092 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5093 state|=UpdateConfigurationState; 5094 break; 5095 } 5096 if ((x < (int) (crop_info.x+RoiDelta)) && 5097 (x > (int) (crop_info.x-RoiDelta)) && 5098 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5099 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5100 { 5101 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5102 state|=UpdateConfigurationState; 5103 break; 5104 } 5105 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5106 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5107 (y < (int) (crop_info.y+RoiDelta)) && 5108 (y > (int) (crop_info.y-RoiDelta))) 5109 { 5110 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5111 state|=UpdateConfigurationState; 5112 break; 5113 } 5114 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5115 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5116 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5117 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5118 { 5119 state|=UpdateConfigurationState; 5120 break; 5121 } 5122 } 5123 case ButtonRelease: 5124 { 5125 if (event.xbutton.window == windows->pan.id) 5126 if ((highlight_info.x != crop_info.x-windows->image.x) || 5127 (highlight_info.y != crop_info.y-windows->image.y)) 5128 XHighlightRectangle(display,windows->image.id, 5129 windows->image.highlight_context,&highlight_info); 5130 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5131 event.xbutton.time); 5132 break; 5133 } 5134 case Expose: 5135 { 5136 if (event.xexpose.window == windows->image.id) 5137 if (event.xexpose.count == 0) 5138 { 5139 event.xexpose.x=(int) highlight_info.x; 5140 event.xexpose.y=(int) highlight_info.y; 5141 event.xexpose.width=(int) highlight_info.width; 5142 event.xexpose.height=(int) highlight_info.height; 5143 XRefreshWindow(display,&windows->image,&event); 5144 } 5145 if (event.xexpose.window == windows->info.id) 5146 if (event.xexpose.count == 0) 5147 XInfoWidget(display,windows,text); 5148 break; 5149 } 5150 case KeyPress: 5151 { 5152 if (event.xkey.window != windows->image.id) 5153 break; 5154 /* 5155 Respond to a user key press. 5156 */ 5157 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5158 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5159 switch ((int) key_symbol) 5160 { 5161 case XK_Escape: 5162 case XK_F20: 5163 state|=EscapeState; 5164 case XK_Return: 5165 { 5166 state|=ExitState; 5167 break; 5168 } 5169 case XK_Home: 5170 case XK_KP_Home: 5171 { 5172 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/ 5173 2L); 5174 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/ 5175 2L); 5176 break; 5177 } 5178 case XK_Left: 5179 case XK_KP_Left: 5180 { 5181 crop_info.x--; 5182 break; 5183 } 5184 case XK_Up: 5185 case XK_KP_Up: 5186 case XK_Next: 5187 { 5188 crop_info.y--; 5189 break; 5190 } 5191 case XK_Right: 5192 case XK_KP_Right: 5193 { 5194 crop_info.x++; 5195 break; 5196 } 5197 case XK_Prior: 5198 case XK_Down: 5199 case XK_KP_Down: 5200 { 5201 crop_info.y++; 5202 break; 5203 } 5204 case XK_F1: 5205 case XK_Help: 5206 { 5207 (void) XSetFunction(display,windows->image.highlight_context, 5208 GXcopy); 5209 switch (mode) 5210 { 5211 case CopyMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Copy",ImageCopyHelp); 5215 break; 5216 } 5217 case CropMode: 5218 { 5219 XTextViewWidget(display,resource_info,windows,MagickFalse, 5220 "Help Viewer - Image Cropg",ImageCropHelp); 5221 break; 5222 } 5223 case CutMode: 5224 { 5225 XTextViewWidget(display,resource_info,windows,MagickFalse, 5226 "Help Viewer - Image Cutg",ImageCutHelp); 5227 break; 5228 } 5229 } 5230 (void) XSetFunction(display,windows->image.highlight_context, 5231 GXinvert); 5232 break; 5233 } 5234 default: 5235 { 5236 (void) XBell(display,0); 5237 break; 5238 } 5239 } 5240 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5241 event.xkey.time); 5242 break; 5243 } 5244 case KeyRelease: 5245 break; 5246 case MotionNotify: 5247 { 5248 if (event.xmotion.window != windows->image.id) 5249 break; 5250 /* 5251 Map and unmap Info widget as text cursor crosses its boundaries. 5252 */ 5253 x=event.xmotion.x; 5254 y=event.xmotion.y; 5255 if (windows->info.mapped != MagickFalse ) 5256 { 5257 if ((x < (int) (windows->info.x+windows->info.width)) && 5258 (y < (int) (windows->info.y+windows->info.height))) 5259 (void) XWithdrawWindow(display,windows->info.id, 5260 windows->info.screen); 5261 } 5262 else 5263 if ((x > (int) (windows->info.x+windows->info.width)) || 5264 (y > (int) (windows->info.y+windows->info.height))) 5265 (void) XMapWindow(display,windows->info.id); 5266 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5267 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5268 break; 5269 } 5270 case SelectionRequest: 5271 { 5272 XSelectionEvent 5273 notify; 5274 5275 XSelectionRequestEvent 5276 *request; 5277 5278 /* 5279 Set primary selection. 5280 */ 5281 (void) FormatLocaleString(text,MagickPathExtent, 5282 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5283 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5284 request=(&(event.xselectionrequest)); 5285 (void) XChangeProperty(request->display,request->requestor, 5286 request->property,request->target,8,PropModeReplace, 5287 (unsigned char *) text,(int) strlen(text)); 5288 notify.type=SelectionNotify; 5289 notify.display=request->display; 5290 notify.requestor=request->requestor; 5291 notify.selection=request->selection; 5292 notify.target=request->target; 5293 notify.time=request->time; 5294 if (request->property == None) 5295 notify.property=request->target; 5296 else 5297 notify.property=request->property; 5298 (void) XSendEvent(request->display,request->requestor,False,0, 5299 (XEvent *) ¬ify); 5300 } 5301 default: 5302 break; 5303 } 5304 if ((state & UpdateConfigurationState) != 0) 5305 { 5306 (void) XPutBackEvent(display,&event); 5307 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5308 break; 5309 } 5310 } while ((state & ExitState) == 0); 5311 } while ((state & ExitState) == 0); 5312 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5313 XSetCursorState(display,windows,MagickFalse); 5314 if ((state & EscapeState) != 0) 5315 return(MagickTrue); 5316 if (mode == CropMode) 5317 if (((int) crop_info.width != windows->image.ximage->width) || 5318 ((int) crop_info.height != windows->image.ximage->height)) 5319 { 5320 /* 5321 Reconfigure Image window as defined by cropping rectangle. 5322 */ 5323 XSetCropGeometry(display,windows,&crop_info,image); 5324 windows->image.window_changes.width=(int) crop_info.width; 5325 windows->image.window_changes.height=(int) crop_info.height; 5326 (void) XConfigureImage(display,resource_info,windows,image,exception); 5327 return(MagickTrue); 5328 } 5329 /* 5330 Copy image before applying image transforms. 5331 */ 5332 XSetCursorState(display,windows,MagickTrue); 5333 XCheckRefreshWindows(display,windows); 5334 width=(unsigned int) image->columns; 5335 height=(unsigned int) image->rows; 5336 x=0; 5337 y=0; 5338 if (windows->image.crop_geometry != (char *) NULL) 5339 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5340 scale_factor=(double) width/windows->image.ximage->width; 5341 crop_info.x+=x; 5342 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5343 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5344 scale_factor=(double) height/windows->image.ximage->height; 5345 crop_info.y+=y; 5346 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5347 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5348 crop_image=CropImage(image,&crop_info,exception); 5349 XSetCursorState(display,windows,MagickFalse); 5350 if (crop_image == (Image *) NULL) 5351 return(MagickFalse); 5352 if (resource_info->copy_image != (Image *) NULL) 5353 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5354 resource_info->copy_image=crop_image; 5355 if (mode == CopyMode) 5356 { 5357 (void) XConfigureImage(display,resource_info,windows,image,exception); 5358 return(MagickTrue); 5359 } 5360 /* 5361 Cut image. 5362 */ 5363 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5364 return(MagickFalse); 5365 image->alpha_trait=BlendPixelTrait; 5366 image_view=AcquireAuthenticCacheView(image,exception); 5367 for (y=0; y < (int) crop_info.height; y++) 5368 { 5369 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5370 crop_info.width,1,exception); 5371 if (q == (Quantum *) NULL) 5372 break; 5373 for (x=0; x < (int) crop_info.width; x++) 5374 { 5375 SetPixelAlpha(image,TransparentAlpha,q); 5376 q+=GetPixelChannels(image); 5377 } 5378 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5379 break; 5380 } 5381 image_view=DestroyCacheView(image_view); 5382 /* 5383 Update image configuration. 5384 */ 5385 XConfigureImageColormap(display,resource_info,windows,image,exception); 5386 (void) XConfigureImage(display,resource_info,windows,image,exception); 5387 return(MagickTrue); 5388 } 5389 5390 /* 5392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5393 % % 5394 % % 5395 % % 5396 + X D r a w I m a g e % 5397 % % 5398 % % 5399 % % 5400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5401 % 5402 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5403 % the image. 5404 % 5405 % The format of the XDrawEditImage method is: 5406 % 5407 % MagickBooleanType XDrawEditImage(Display *display, 5408 % XResourceInfo *resource_info,XWindows *windows,Image **image, 5409 % ExceptionInfo *exception) 5410 % 5411 % A description of each parameter follows: 5412 % 5413 % o display: Specifies a connection to an X server; returned from 5414 % XOpenDisplay. 5415 % 5416 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5417 % 5418 % o windows: Specifies a pointer to a XWindows structure. 5419 % 5420 % o image: the image. 5421 % 5422 % o exception: return any errors or warnings in this structure. 5423 % 5424 */ 5425 static MagickBooleanType XDrawEditImage(Display *display, 5426 XResourceInfo *resource_info,XWindows *windows,Image **image, 5427 ExceptionInfo *exception) 5428 { 5429 static const char 5430 *DrawMenu[] = 5431 { 5432 "Element", 5433 "Color", 5434 "Stipple", 5435 "Width", 5436 "Undo", 5437 "Help", 5438 "Dismiss", 5439 (char *) NULL 5440 }; 5441 5442 static ElementType 5443 element = PointElement; 5444 5445 static const ModeType 5446 DrawCommands[] = 5447 { 5448 DrawElementCommand, 5449 DrawColorCommand, 5450 DrawStippleCommand, 5451 DrawWidthCommand, 5452 DrawUndoCommand, 5453 DrawHelpCommand, 5454 DrawDismissCommand 5455 }; 5456 5457 static Pixmap 5458 stipple = (Pixmap) NULL; 5459 5460 static unsigned int 5461 pen_id = 0, 5462 line_width = 1; 5463 5464 char 5465 command[MagickPathExtent], 5466 text[MagickPathExtent]; 5467 5468 Cursor 5469 cursor; 5470 5471 int 5472 entry, 5473 id, 5474 number_coordinates, 5475 x, 5476 y; 5477 5478 double 5479 degrees; 5480 5481 MagickStatusType 5482 status; 5483 5484 RectangleInfo 5485 rectangle_info; 5486 5487 register int 5488 i; 5489 5490 unsigned int 5491 distance, 5492 height, 5493 max_coordinates, 5494 width; 5495 5496 size_t 5497 state; 5498 5499 Window 5500 root_window; 5501 5502 XDrawInfo 5503 draw_info; 5504 5505 XEvent 5506 event; 5507 5508 XPoint 5509 *coordinate_info; 5510 5511 XSegment 5512 line_info; 5513 5514 /* 5515 Allocate polygon info. 5516 */ 5517 max_coordinates=2048; 5518 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5519 sizeof(*coordinate_info)); 5520 if (coordinate_info == (XPoint *) NULL) 5521 { 5522 (void) ThrowMagickException(exception,GetMagickModule(), 5523 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5524 return(MagickFalse); 5525 } 5526 /* 5527 Map Command widget. 5528 */ 5529 (void) CloneString(&windows->command.name,"Draw"); 5530 windows->command.data=4; 5531 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5532 (void) XMapRaised(display,windows->command.id); 5533 XClientMessage(display,windows->image.id,windows->im_protocols, 5534 windows->im_update_widget,CurrentTime); 5535 /* 5536 Wait for first button press. 5537 */ 5538 root_window=XRootWindow(display,XDefaultScreen(display)); 5539 draw_info.stencil=OpaqueStencil; 5540 status=MagickTrue; 5541 cursor=XCreateFontCursor(display,XC_tcross); 5542 for ( ; ; ) 5543 { 5544 XQueryPosition(display,windows->image.id,&x,&y); 5545 (void) XSelectInput(display,windows->image.id, 5546 windows->image.attributes.event_mask | PointerMotionMask); 5547 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5548 state=DefaultState; 5549 do 5550 { 5551 if (windows->info.mapped != MagickFalse ) 5552 { 5553 /* 5554 Display pointer position. 5555 */ 5556 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 5557 x+windows->image.x,y+windows->image.y); 5558 XInfoWidget(display,windows,text); 5559 } 5560 /* 5561 Wait for next event. 5562 */ 5563 XScreenEvent(display,windows,&event,exception); 5564 if (event.xany.window == windows->command.id) 5565 { 5566 /* 5567 Select a command from the Command widget. 5568 */ 5569 id=XCommandWidget(display,windows,DrawMenu,&event); 5570 if (id < 0) 5571 continue; 5572 switch (DrawCommands[id]) 5573 { 5574 case DrawElementCommand: 5575 { 5576 static const char 5577 *Elements[] = 5578 { 5579 "point", 5580 "line", 5581 "rectangle", 5582 "fill rectangle", 5583 "circle", 5584 "fill circle", 5585 "ellipse", 5586 "fill ellipse", 5587 "polygon", 5588 "fill polygon", 5589 (char *) NULL, 5590 }; 5591 5592 /* 5593 Select a command from the pop-up menu. 5594 */ 5595 element=(ElementType) (XMenuWidget(display,windows, 5596 DrawMenu[id],Elements,command)+1); 5597 break; 5598 } 5599 case DrawColorCommand: 5600 { 5601 const char 5602 *ColorMenu[MaxNumberPens+1]; 5603 5604 int 5605 pen_number; 5606 5607 MagickBooleanType 5608 transparent; 5609 5610 XColor 5611 color; 5612 5613 /* 5614 Initialize menu selections. 5615 */ 5616 for (i=0; i < (int) (MaxNumberPens-2); i++) 5617 ColorMenu[i]=resource_info->pen_colors[i]; 5618 ColorMenu[MaxNumberPens-2]="transparent"; 5619 ColorMenu[MaxNumberPens-1]="Browser..."; 5620 ColorMenu[MaxNumberPens]=(char *) NULL; 5621 /* 5622 Select a pen color from the pop-up menu. 5623 */ 5624 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5625 (const char **) ColorMenu,command); 5626 if (pen_number < 0) 5627 break; 5628 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5629 MagickFalse; 5630 if (transparent != MagickFalse ) 5631 { 5632 draw_info.stencil=TransparentStencil; 5633 break; 5634 } 5635 if (pen_number == (MaxNumberPens-1)) 5636 { 5637 static char 5638 color_name[MagickPathExtent] = "gray"; 5639 5640 /* 5641 Select a pen color from a dialog. 5642 */ 5643 resource_info->pen_colors[pen_number]=color_name; 5644 XColorBrowserWidget(display,windows,"Select",color_name); 5645 if (*color_name == '\0') 5646 break; 5647 } 5648 /* 5649 Set pen color. 5650 */ 5651 (void) XParseColor(display,windows->map_info->colormap, 5652 resource_info->pen_colors[pen_number],&color); 5653 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5654 (unsigned int) MaxColors,&color); 5655 windows->pixel_info->pen_colors[pen_number]=color; 5656 pen_id=(unsigned int) pen_number; 5657 draw_info.stencil=OpaqueStencil; 5658 break; 5659 } 5660 case DrawStippleCommand: 5661 { 5662 Image 5663 *stipple_image; 5664 5665 ImageInfo 5666 *image_info; 5667 5668 int 5669 status; 5670 5671 static char 5672 filename[MagickPathExtent] = "\0"; 5673 5674 static const char 5675 *StipplesMenu[] = 5676 { 5677 "Brick", 5678 "Diagonal", 5679 "Scales", 5680 "Vertical", 5681 "Wavy", 5682 "Translucent", 5683 "Opaque", 5684 (char *) NULL, 5685 (char *) NULL, 5686 }; 5687 5688 /* 5689 Select a command from the pop-up menu. 5690 */ 5691 StipplesMenu[7]="Open..."; 5692 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5693 command); 5694 if (entry < 0) 5695 break; 5696 if (stipple != (Pixmap) NULL) 5697 (void) XFreePixmap(display,stipple); 5698 stipple=(Pixmap) NULL; 5699 if (entry != 7) 5700 { 5701 switch (entry) 5702 { 5703 case 0: 5704 { 5705 stipple=XCreateBitmapFromData(display,root_window, 5706 (char *) BricksBitmap,BricksWidth,BricksHeight); 5707 break; 5708 } 5709 case 1: 5710 { 5711 stipple=XCreateBitmapFromData(display,root_window, 5712 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5713 break; 5714 } 5715 case 2: 5716 { 5717 stipple=XCreateBitmapFromData(display,root_window, 5718 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5719 break; 5720 } 5721 case 3: 5722 { 5723 stipple=XCreateBitmapFromData(display,root_window, 5724 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5725 break; 5726 } 5727 case 4: 5728 { 5729 stipple=XCreateBitmapFromData(display,root_window, 5730 (char *) WavyBitmap,WavyWidth,WavyHeight); 5731 break; 5732 } 5733 case 5: 5734 { 5735 stipple=XCreateBitmapFromData(display,root_window, 5736 (char *) HighlightBitmap,HighlightWidth, 5737 HighlightHeight); 5738 break; 5739 } 5740 case 6: 5741 default: 5742 { 5743 stipple=XCreateBitmapFromData(display,root_window, 5744 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5745 break; 5746 } 5747 } 5748 break; 5749 } 5750 XFileBrowserWidget(display,windows,"Stipple",filename); 5751 if (*filename == '\0') 5752 break; 5753 /* 5754 Read image. 5755 */ 5756 XSetCursorState(display,windows,MagickTrue); 5757 XCheckRefreshWindows(display,windows); 5758 image_info=AcquireImageInfo(); 5759 (void) CopyMagickString(image_info->filename,filename, 5760 MagickPathExtent); 5761 stipple_image=ReadImage(image_info,exception); 5762 CatchException(exception); 5763 XSetCursorState(display,windows,MagickFalse); 5764 if (stipple_image == (Image *) NULL) 5765 break; 5766 (void) AcquireUniqueFileResource(filename); 5767 (void) FormatLocaleString(stipple_image->filename,MagickPathExtent, 5768 "xbm:%s",filename); 5769 (void) WriteImage(image_info,stipple_image,exception); 5770 stipple_image=DestroyImage(stipple_image); 5771 image_info=DestroyImageInfo(image_info); 5772 status=XReadBitmapFile(display,root_window,filename,&width, 5773 &height,&stipple,&x,&y); 5774 (void) RelinquishUniqueFileResource(filename); 5775 if ((status != BitmapSuccess) != 0) 5776 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5777 filename); 5778 break; 5779 } 5780 case DrawWidthCommand: 5781 { 5782 static char 5783 width[MagickPathExtent] = "0"; 5784 5785 static const char 5786 *WidthsMenu[] = 5787 { 5788 "1", 5789 "2", 5790 "4", 5791 "8", 5792 "16", 5793 "Dialog...", 5794 (char *) NULL, 5795 }; 5796 5797 /* 5798 Select a command from the pop-up menu. 5799 */ 5800 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5801 command); 5802 if (entry < 0) 5803 break; 5804 if (entry != 5) 5805 { 5806 line_width=(unsigned int) StringToUnsignedLong( 5807 WidthsMenu[entry]); 5808 break; 5809 } 5810 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5811 width); 5812 if (*width == '\0') 5813 break; 5814 line_width=(unsigned int) StringToUnsignedLong(width); 5815 break; 5816 } 5817 case DrawUndoCommand: 5818 { 5819 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5820 image,exception); 5821 break; 5822 } 5823 case DrawHelpCommand: 5824 { 5825 XTextViewWidget(display,resource_info,windows,MagickFalse, 5826 "Help Viewer - Image Rotation",ImageDrawHelp); 5827 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5828 break; 5829 } 5830 case DrawDismissCommand: 5831 { 5832 /* 5833 Prematurely exit. 5834 */ 5835 state|=EscapeState; 5836 state|=ExitState; 5837 break; 5838 } 5839 default: 5840 break; 5841 } 5842 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5843 continue; 5844 } 5845 switch (event.type) 5846 { 5847 case ButtonPress: 5848 { 5849 if (event.xbutton.button != Button1) 5850 break; 5851 if (event.xbutton.window != windows->image.id) 5852 break; 5853 /* 5854 exit loop. 5855 */ 5856 x=event.xbutton.x; 5857 y=event.xbutton.y; 5858 state|=ExitState; 5859 break; 5860 } 5861 case ButtonRelease: 5862 break; 5863 case Expose: 5864 break; 5865 case KeyPress: 5866 { 5867 KeySym 5868 key_symbol; 5869 5870 if (event.xkey.window != windows->image.id) 5871 break; 5872 /* 5873 Respond to a user key press. 5874 */ 5875 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5876 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5877 switch ((int) key_symbol) 5878 { 5879 case XK_Escape: 5880 case XK_F20: 5881 { 5882 /* 5883 Prematurely exit. 5884 */ 5885 state|=EscapeState; 5886 state|=ExitState; 5887 break; 5888 } 5889 case XK_F1: 5890 case XK_Help: 5891 { 5892 XTextViewWidget(display,resource_info,windows,MagickFalse, 5893 "Help Viewer - Image Rotation",ImageDrawHelp); 5894 break; 5895 } 5896 default: 5897 { 5898 (void) XBell(display,0); 5899 break; 5900 } 5901 } 5902 break; 5903 } 5904 case MotionNotify: 5905 { 5906 /* 5907 Map and unmap Info widget as text cursor crosses its boundaries. 5908 */ 5909 x=event.xmotion.x; 5910 y=event.xmotion.y; 5911 if (windows->info.mapped != MagickFalse ) 5912 { 5913 if ((x < (int) (windows->info.x+windows->info.width)) && 5914 (y < (int) (windows->info.y+windows->info.height))) 5915 (void) XWithdrawWindow(display,windows->info.id, 5916 windows->info.screen); 5917 } 5918 else 5919 if ((x > (int) (windows->info.x+windows->info.width)) || 5920 (y > (int) (windows->info.y+windows->info.height))) 5921 (void) XMapWindow(display,windows->info.id); 5922 break; 5923 } 5924 } 5925 } while ((state & ExitState) == 0); 5926 (void) XSelectInput(display,windows->image.id, 5927 windows->image.attributes.event_mask); 5928 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5929 if ((state & EscapeState) != 0) 5930 break; 5931 /* 5932 Draw element as pointer moves until the button is released. 5933 */ 5934 distance=0; 5935 degrees=0.0; 5936 line_info.x1=x; 5937 line_info.y1=y; 5938 line_info.x2=x; 5939 line_info.y2=y; 5940 rectangle_info.x=(ssize_t) x; 5941 rectangle_info.y=(ssize_t) y; 5942 rectangle_info.width=0; 5943 rectangle_info.height=0; 5944 number_coordinates=1; 5945 coordinate_info->x=x; 5946 coordinate_info->y=y; 5947 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5948 state=DefaultState; 5949 do 5950 { 5951 switch (element) 5952 { 5953 case PointElement: 5954 default: 5955 { 5956 if (number_coordinates > 1) 5957 { 5958 (void) XDrawLines(display,windows->image.id, 5959 windows->image.highlight_context,coordinate_info, 5960 number_coordinates,CoordModeOrigin); 5961 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d", 5962 coordinate_info[number_coordinates-1].x, 5963 coordinate_info[number_coordinates-1].y); 5964 XInfoWidget(display,windows,text); 5965 } 5966 break; 5967 } 5968 case LineElement: 5969 { 5970 if (distance > 9) 5971 { 5972 /* 5973 Display angle of the line. 5974 */ 5975 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5976 line_info.y1),(double) (line_info.x2-line_info.x1))); 5977 (void) FormatLocaleString(text,MagickPathExtent," %g", 5978 (double) degrees); 5979 XInfoWidget(display,windows,text); 5980 XHighlightLine(display,windows->image.id, 5981 windows->image.highlight_context,&line_info); 5982 } 5983 else 5984 if (windows->info.mapped != MagickFalse ) 5985 (void) XWithdrawWindow(display,windows->info.id, 5986 windows->info.screen); 5987 break; 5988 } 5989 case RectangleElement: 5990 case FillRectangleElement: 5991 { 5992 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5993 { 5994 /* 5995 Display info and draw drawing rectangle. 5996 */ 5997 (void) FormatLocaleString(text,MagickPathExtent, 5998 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5999 (double) rectangle_info.height,(double) rectangle_info.x, 6000 (double) rectangle_info.y); 6001 XInfoWidget(display,windows,text); 6002 XHighlightRectangle(display,windows->image.id, 6003 windows->image.highlight_context,&rectangle_info); 6004 } 6005 else 6006 if (windows->info.mapped != MagickFalse ) 6007 (void) XWithdrawWindow(display,windows->info.id, 6008 windows->info.screen); 6009 break; 6010 } 6011 case CircleElement: 6012 case FillCircleElement: 6013 case EllipseElement: 6014 case FillEllipseElement: 6015 { 6016 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6017 { 6018 /* 6019 Display info and draw drawing rectangle. 6020 */ 6021 (void) FormatLocaleString(text,MagickPathExtent, 6022 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6023 (double) rectangle_info.height,(double) rectangle_info.x, 6024 (double) rectangle_info.y); 6025 XInfoWidget(display,windows,text); 6026 XHighlightEllipse(display,windows->image.id, 6027 windows->image.highlight_context,&rectangle_info); 6028 } 6029 else 6030 if (windows->info.mapped != MagickFalse ) 6031 (void) XWithdrawWindow(display,windows->info.id, 6032 windows->info.screen); 6033 break; 6034 } 6035 case PolygonElement: 6036 case FillPolygonElement: 6037 { 6038 if (number_coordinates > 1) 6039 (void) XDrawLines(display,windows->image.id, 6040 windows->image.highlight_context,coordinate_info, 6041 number_coordinates,CoordModeOrigin); 6042 if (distance > 9) 6043 { 6044 /* 6045 Display angle of the line. 6046 */ 6047 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6048 line_info.y1),(double) (line_info.x2-line_info.x1))); 6049 (void) FormatLocaleString(text,MagickPathExtent," %g", 6050 (double) degrees); 6051 XInfoWidget(display,windows,text); 6052 XHighlightLine(display,windows->image.id, 6053 windows->image.highlight_context,&line_info); 6054 } 6055 else 6056 if (windows->info.mapped != MagickFalse ) 6057 (void) XWithdrawWindow(display,windows->info.id, 6058 windows->info.screen); 6059 break; 6060 } 6061 } 6062 /* 6063 Wait for next event. 6064 */ 6065 XScreenEvent(display,windows,&event,exception); 6066 switch (element) 6067 { 6068 case PointElement: 6069 default: 6070 { 6071 if (number_coordinates > 1) 6072 (void) XDrawLines(display,windows->image.id, 6073 windows->image.highlight_context,coordinate_info, 6074 number_coordinates,CoordModeOrigin); 6075 break; 6076 } 6077 case LineElement: 6078 { 6079 if (distance > 9) 6080 XHighlightLine(display,windows->image.id, 6081 windows->image.highlight_context,&line_info); 6082 break; 6083 } 6084 case RectangleElement: 6085 case FillRectangleElement: 6086 { 6087 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6088 XHighlightRectangle(display,windows->image.id, 6089 windows->image.highlight_context,&rectangle_info); 6090 break; 6091 } 6092 case CircleElement: 6093 case FillCircleElement: 6094 case EllipseElement: 6095 case FillEllipseElement: 6096 { 6097 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6098 XHighlightEllipse(display,windows->image.id, 6099 windows->image.highlight_context,&rectangle_info); 6100 break; 6101 } 6102 case PolygonElement: 6103 case FillPolygonElement: 6104 { 6105 if (number_coordinates > 1) 6106 (void) XDrawLines(display,windows->image.id, 6107 windows->image.highlight_context,coordinate_info, 6108 number_coordinates,CoordModeOrigin); 6109 if (distance > 9) 6110 XHighlightLine(display,windows->image.id, 6111 windows->image.highlight_context,&line_info); 6112 break; 6113 } 6114 } 6115 switch (event.type) 6116 { 6117 case ButtonPress: 6118 break; 6119 case ButtonRelease: 6120 { 6121 /* 6122 User has committed to element. 6123 */ 6124 line_info.x2=event.xbutton.x; 6125 line_info.y2=event.xbutton.y; 6126 rectangle_info.x=(ssize_t) event.xbutton.x; 6127 rectangle_info.y=(ssize_t) event.xbutton.y; 6128 coordinate_info[number_coordinates].x=event.xbutton.x; 6129 coordinate_info[number_coordinates].y=event.xbutton.y; 6130 if (((element != PolygonElement) && 6131 (element != FillPolygonElement)) || (distance <= 9)) 6132 { 6133 state|=ExitState; 6134 break; 6135 } 6136 number_coordinates++; 6137 if (number_coordinates < (int) max_coordinates) 6138 { 6139 line_info.x1=event.xbutton.x; 6140 line_info.y1=event.xbutton.y; 6141 break; 6142 } 6143 max_coordinates<<=1; 6144 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6145 max_coordinates,sizeof(*coordinate_info)); 6146 if (coordinate_info == (XPoint *) NULL) 6147 (void) ThrowMagickException(exception,GetMagickModule(), 6148 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6149 break; 6150 } 6151 case Expose: 6152 break; 6153 case MotionNotify: 6154 { 6155 if (event.xmotion.window != windows->image.id) 6156 break; 6157 if (element != PointElement) 6158 { 6159 line_info.x2=event.xmotion.x; 6160 line_info.y2=event.xmotion.y; 6161 rectangle_info.x=(ssize_t) event.xmotion.x; 6162 rectangle_info.y=(ssize_t) event.xmotion.y; 6163 break; 6164 } 6165 coordinate_info[number_coordinates].x=event.xbutton.x; 6166 coordinate_info[number_coordinates].y=event.xbutton.y; 6167 number_coordinates++; 6168 if (number_coordinates < (int) max_coordinates) 6169 break; 6170 max_coordinates<<=1; 6171 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6172 max_coordinates,sizeof(*coordinate_info)); 6173 if (coordinate_info == (XPoint *) NULL) 6174 (void) ThrowMagickException(exception,GetMagickModule(), 6175 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6176 break; 6177 } 6178 default: 6179 break; 6180 } 6181 /* 6182 Check boundary conditions. 6183 */ 6184 if (line_info.x2 < 0) 6185 line_info.x2=0; 6186 else 6187 if (line_info.x2 > (int) windows->image.width) 6188 line_info.x2=(short) windows->image.width; 6189 if (line_info.y2 < 0) 6190 line_info.y2=0; 6191 else 6192 if (line_info.y2 > (int) windows->image.height) 6193 line_info.y2=(short) windows->image.height; 6194 distance=(unsigned int) 6195 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6196 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6197 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6198 ((state & ExitState) != 0)) 6199 { 6200 if (rectangle_info.x < 0) 6201 rectangle_info.x=0; 6202 else 6203 if (rectangle_info.x > (ssize_t) windows->image.width) 6204 rectangle_info.x=(ssize_t) windows->image.width; 6205 if ((int) rectangle_info.x < x) 6206 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6207 else 6208 { 6209 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6210 rectangle_info.x=(ssize_t) x; 6211 } 6212 if (rectangle_info.y < 0) 6213 rectangle_info.y=0; 6214 else 6215 if (rectangle_info.y > (ssize_t) windows->image.height) 6216 rectangle_info.y=(ssize_t) windows->image.height; 6217 if ((int) rectangle_info.y < y) 6218 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6219 else 6220 { 6221 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6222 rectangle_info.y=(ssize_t) y; 6223 } 6224 } 6225 } while ((state & ExitState) == 0); 6226 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6227 if ((element == PointElement) || (element == PolygonElement) || 6228 (element == FillPolygonElement)) 6229 { 6230 /* 6231 Determine polygon bounding box. 6232 */ 6233 rectangle_info.x=(ssize_t) coordinate_info->x; 6234 rectangle_info.y=(ssize_t) coordinate_info->y; 6235 x=coordinate_info->x; 6236 y=coordinate_info->y; 6237 for (i=1; i < number_coordinates; i++) 6238 { 6239 if (coordinate_info[i].x > x) 6240 x=coordinate_info[i].x; 6241 if (coordinate_info[i].y > y) 6242 y=coordinate_info[i].y; 6243 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6244 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6245 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6246 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6247 } 6248 rectangle_info.width=(size_t) (x-rectangle_info.x); 6249 rectangle_info.height=(size_t) (y-rectangle_info.y); 6250 for (i=0; i < number_coordinates; i++) 6251 { 6252 coordinate_info[i].x-=rectangle_info.x; 6253 coordinate_info[i].y-=rectangle_info.y; 6254 } 6255 } 6256 else 6257 if (distance <= 9) 6258 continue; 6259 else 6260 if ((element == RectangleElement) || 6261 (element == CircleElement) || (element == EllipseElement)) 6262 { 6263 rectangle_info.width--; 6264 rectangle_info.height--; 6265 } 6266 /* 6267 Drawing is relative to image configuration. 6268 */ 6269 draw_info.x=(int) rectangle_info.x; 6270 draw_info.y=(int) rectangle_info.y; 6271 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6272 image,exception); 6273 width=(unsigned int) (*image)->columns; 6274 height=(unsigned int) (*image)->rows; 6275 x=0; 6276 y=0; 6277 if (windows->image.crop_geometry != (char *) NULL) 6278 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6279 draw_info.x+=windows->image.x-(line_width/2); 6280 if (draw_info.x < 0) 6281 draw_info.x=0; 6282 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6283 draw_info.y+=windows->image.y-(line_width/2); 6284 if (draw_info.y < 0) 6285 draw_info.y=0; 6286 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6287 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6288 if (draw_info.width > (unsigned int) (*image)->columns) 6289 draw_info.width=(unsigned int) (*image)->columns; 6290 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6291 if (draw_info.height > (unsigned int) (*image)->rows) 6292 draw_info.height=(unsigned int) (*image)->rows; 6293 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d", 6294 width*draw_info.width/windows->image.ximage->width, 6295 height*draw_info.height/windows->image.ximage->height, 6296 draw_info.x+x,draw_info.y+y); 6297 /* 6298 Initialize drawing attributes. 6299 */ 6300 draw_info.degrees=0.0; 6301 draw_info.element=element; 6302 draw_info.stipple=stipple; 6303 draw_info.line_width=line_width; 6304 draw_info.line_info=line_info; 6305 if (line_info.x1 > (int) (line_width/2)) 6306 draw_info.line_info.x1=(short) line_width/2; 6307 if (line_info.y1 > (int) (line_width/2)) 6308 draw_info.line_info.y1=(short) line_width/2; 6309 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6310 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6311 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6312 { 6313 draw_info.line_info.x2=(-draw_info.line_info.x2); 6314 draw_info.line_info.y2=(-draw_info.line_info.y2); 6315 } 6316 if (draw_info.line_info.x2 < 0) 6317 { 6318 draw_info.line_info.x2=(-draw_info.line_info.x2); 6319 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6320 } 6321 if (draw_info.line_info.y2 < 0) 6322 { 6323 draw_info.line_info.y2=(-draw_info.line_info.y2); 6324 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6325 } 6326 draw_info.rectangle_info=rectangle_info; 6327 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6328 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6329 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6330 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6331 draw_info.number_coordinates=(unsigned int) number_coordinates; 6332 draw_info.coordinate_info=coordinate_info; 6333 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6334 /* 6335 Draw element on image. 6336 */ 6337 XSetCursorState(display,windows,MagickTrue); 6338 XCheckRefreshWindows(display,windows); 6339 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6340 XSetCursorState(display,windows,MagickFalse); 6341 /* 6342 Update image colormap and return to image drawing. 6343 */ 6344 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6345 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6346 } 6347 XSetCursorState(display,windows,MagickFalse); 6348 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6349 return(status != 0 ? MagickTrue : MagickFalse); 6350 } 6351 6352 /* 6354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6355 % % 6356 % % 6357 % % 6358 + X D r a w P a n R e c t a n g l e % 6359 % % 6360 % % 6361 % % 6362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6363 % 6364 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6365 % displays a zoom image and the rectangle shows which portion of the image is 6366 % displayed in the Image window. 6367 % 6368 % The format of the XDrawPanRectangle method is: 6369 % 6370 % XDrawPanRectangle(Display *display,XWindows *windows) 6371 % 6372 % A description of each parameter follows: 6373 % 6374 % o display: Specifies a connection to an X server; returned from 6375 % XOpenDisplay. 6376 % 6377 % o windows: Specifies a pointer to a XWindows structure. 6378 % 6379 */ 6380 static void XDrawPanRectangle(Display *display,XWindows *windows) 6381 { 6382 double 6383 scale_factor; 6384 6385 RectangleInfo 6386 highlight_info; 6387 6388 /* 6389 Determine dimensions of the panning rectangle. 6390 */ 6391 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6392 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6393 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6394 scale_factor=(double) 6395 windows->pan.height/windows->image.ximage->height; 6396 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6397 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6398 /* 6399 Display the panning rectangle. 6400 */ 6401 (void) XClearWindow(display,windows->pan.id); 6402 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6403 &highlight_info); 6404 } 6405 6406 /* 6408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6409 % % 6410 % % 6411 % % 6412 + X I m a g e C a c h e % 6413 % % 6414 % % 6415 % % 6416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6417 % 6418 % XImageCache() handles the creation, manipulation, and destruction of the 6419 % image cache (undo and redo buffers). 6420 % 6421 % The format of the XImageCache method is: 6422 % 6423 % void XImageCache(Display *display,XResourceInfo *resource_info, 6424 % XWindows *windows,const CommandType command,Image **image, 6425 % ExceptionInfo *exception) 6426 % 6427 % A description of each parameter follows: 6428 % 6429 % o display: Specifies a connection to an X server; returned from 6430 % XOpenDisplay. 6431 % 6432 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6433 % 6434 % o windows: Specifies a pointer to a XWindows structure. 6435 % 6436 % o command: Specifies a command to perform. 6437 % 6438 % o image: the image; XImageCache may transform the image and return a new 6439 % image pointer. 6440 % 6441 % o exception: return any errors or warnings in this structure. 6442 % 6443 */ 6444 static void XImageCache(Display *display,XResourceInfo *resource_info, 6445 XWindows *windows,const CommandType command,Image **image, 6446 ExceptionInfo *exception) 6447 { 6448 Image 6449 *cache_image; 6450 6451 static Image 6452 *redo_image = (Image *) NULL, 6453 *undo_image = (Image *) NULL; 6454 6455 switch (command) 6456 { 6457 case FreeBuffersCommand: 6458 { 6459 /* 6460 Free memory from the undo and redo cache. 6461 */ 6462 while (undo_image != (Image *) NULL) 6463 { 6464 cache_image=undo_image; 6465 undo_image=GetPreviousImageInList(undo_image); 6466 cache_image->list=DestroyImage(cache_image->list); 6467 cache_image=DestroyImage(cache_image); 6468 } 6469 undo_image=NewImageList(); 6470 if (redo_image != (Image *) NULL) 6471 redo_image=DestroyImage(redo_image); 6472 redo_image=NewImageList(); 6473 return; 6474 } 6475 case UndoCommand: 6476 { 6477 char 6478 image_geometry[MagickPathExtent]; 6479 6480 /* 6481 Undo the last image transformation. 6482 */ 6483 if (undo_image == (Image *) NULL) 6484 { 6485 (void) XBell(display,0); 6486 return; 6487 } 6488 cache_image=undo_image; 6489 undo_image=GetPreviousImageInList(undo_image); 6490 windows->image.window_changes.width=(int) cache_image->columns; 6491 windows->image.window_changes.height=(int) cache_image->rows; 6492 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!", 6493 windows->image.ximage->width,windows->image.ximage->height); 6494 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6495 exception); 6496 if (windows->image.crop_geometry != (char *) NULL) 6497 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6498 windows->image.crop_geometry); 6499 windows->image.crop_geometry=cache_image->geometry; 6500 if (redo_image != (Image *) NULL) 6501 redo_image=DestroyImage(redo_image); 6502 redo_image=(*image); 6503 *image=cache_image->list; 6504 cache_image=DestroyImage(cache_image); 6505 if (windows->image.orphan != MagickFalse ) 6506 return; 6507 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6508 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6509 return; 6510 } 6511 case CutCommand: 6512 case PasteCommand: 6513 case ApplyCommand: 6514 case HalfSizeCommand: 6515 case OriginalSizeCommand: 6516 case DoubleSizeCommand: 6517 case ResizeCommand: 6518 case TrimCommand: 6519 case CropCommand: 6520 case ChopCommand: 6521 case FlipCommand: 6522 case FlopCommand: 6523 case RotateRightCommand: 6524 case RotateLeftCommand: 6525 case RotateCommand: 6526 case ShearCommand: 6527 case RollCommand: 6528 case NegateCommand: 6529 case ContrastStretchCommand: 6530 case SigmoidalContrastCommand: 6531 case NormalizeCommand: 6532 case EqualizeCommand: 6533 case HueCommand: 6534 case SaturationCommand: 6535 case BrightnessCommand: 6536 case GammaCommand: 6537 case SpiffCommand: 6538 case DullCommand: 6539 case GrayscaleCommand: 6540 case MapCommand: 6541 case QuantizeCommand: 6542 case DespeckleCommand: 6543 case EmbossCommand: 6544 case ReduceNoiseCommand: 6545 case AddNoiseCommand: 6546 case SharpenCommand: 6547 case BlurCommand: 6548 case ThresholdCommand: 6549 case EdgeDetectCommand: 6550 case SpreadCommand: 6551 case ShadeCommand: 6552 case RaiseCommand: 6553 case SegmentCommand: 6554 case SolarizeCommand: 6555 case SepiaToneCommand: 6556 case SwirlCommand: 6557 case ImplodeCommand: 6558 case VignetteCommand: 6559 case WaveCommand: 6560 case OilPaintCommand: 6561 case CharcoalDrawCommand: 6562 case AnnotateCommand: 6563 case AddBorderCommand: 6564 case AddFrameCommand: 6565 case CompositeCommand: 6566 case CommentCommand: 6567 case LaunchCommand: 6568 case RegionofInterestCommand: 6569 case SaveToUndoBufferCommand: 6570 case RedoCommand: 6571 { 6572 Image 6573 *previous_image; 6574 6575 ssize_t 6576 bytes; 6577 6578 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6579 if (undo_image != (Image *) NULL) 6580 { 6581 /* 6582 Ensure the undo cache has enough memory available. 6583 */ 6584 previous_image=undo_image; 6585 while (previous_image != (Image *) NULL) 6586 { 6587 bytes+=previous_image->list->columns*previous_image->list->rows* 6588 sizeof(PixelInfo); 6589 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6590 { 6591 previous_image=GetPreviousImageInList(previous_image); 6592 continue; 6593 } 6594 bytes-=previous_image->list->columns*previous_image->list->rows* 6595 sizeof(PixelInfo); 6596 if (previous_image == undo_image) 6597 undo_image=NewImageList(); 6598 else 6599 previous_image->next->previous=NewImageList(); 6600 break; 6601 } 6602 while (previous_image != (Image *) NULL) 6603 { 6604 /* 6605 Delete any excess memory from undo cache. 6606 */ 6607 cache_image=previous_image; 6608 previous_image=GetPreviousImageInList(previous_image); 6609 cache_image->list=DestroyImage(cache_image->list); 6610 cache_image=DestroyImage(cache_image); 6611 } 6612 } 6613 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6614 break; 6615 /* 6616 Save image before transformations are applied. 6617 */ 6618 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6619 if (cache_image == (Image *) NULL) 6620 break; 6621 XSetCursorState(display,windows,MagickTrue); 6622 XCheckRefreshWindows(display,windows); 6623 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6624 XSetCursorState(display,windows,MagickFalse); 6625 if (cache_image->list == (Image *) NULL) 6626 { 6627 cache_image=DestroyImage(cache_image); 6628 break; 6629 } 6630 cache_image->columns=(size_t) windows->image.ximage->width; 6631 cache_image->rows=(size_t) windows->image.ximage->height; 6632 cache_image->geometry=windows->image.crop_geometry; 6633 if (windows->image.crop_geometry != (char *) NULL) 6634 { 6635 cache_image->geometry=AcquireString((char *) NULL); 6636 (void) CopyMagickString(cache_image->geometry, 6637 windows->image.crop_geometry,MagickPathExtent); 6638 } 6639 if (undo_image == (Image *) NULL) 6640 { 6641 undo_image=cache_image; 6642 break; 6643 } 6644 undo_image->next=cache_image; 6645 undo_image->next->previous=undo_image; 6646 undo_image=undo_image->next; 6647 break; 6648 } 6649 default: 6650 break; 6651 } 6652 if (command == RedoCommand) 6653 { 6654 /* 6655 Redo the last image transformation. 6656 */ 6657 if (redo_image == (Image *) NULL) 6658 { 6659 (void) XBell(display,0); 6660 return; 6661 } 6662 windows->image.window_changes.width=(int) redo_image->columns; 6663 windows->image.window_changes.height=(int) redo_image->rows; 6664 if (windows->image.crop_geometry != (char *) NULL) 6665 windows->image.crop_geometry=(char *) 6666 RelinquishMagickMemory(windows->image.crop_geometry); 6667 windows->image.crop_geometry=redo_image->geometry; 6668 *image=DestroyImage(*image); 6669 *image=redo_image; 6670 redo_image=NewImageList(); 6671 if (windows->image.orphan != MagickFalse ) 6672 return; 6673 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6674 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6675 return; 6676 } 6677 if (command != InfoCommand) 6678 return; 6679 /* 6680 Display image info. 6681 */ 6682 XSetCursorState(display,windows,MagickTrue); 6683 XCheckRefreshWindows(display,windows); 6684 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6685 XSetCursorState(display,windows,MagickFalse); 6686 } 6687 6688 /* 6690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6691 % % 6692 % % 6693 % % 6694 + X I m a g e W i n d o w C o m m a n d % 6695 % % 6696 % % 6697 % % 6698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6699 % 6700 % XImageWindowCommand() makes a transform to the image or Image window as 6701 % specified by a user menu button or keyboard command. 6702 % 6703 % The format of the XImageWindowCommand method is: 6704 % 6705 % CommandType XImageWindowCommand(Display *display, 6706 % XResourceInfo *resource_info,XWindows *windows, 6707 % const MagickStatusType state,KeySym key_symbol,Image **image, 6708 % ExceptionInfo *exception) 6709 % 6710 % A description of each parameter follows: 6711 % 6712 % o nexus: Method XImageWindowCommand returns an image when the 6713 % user chooses 'Open Image' from the command menu. Otherwise a null 6714 % image is returned. 6715 % 6716 % o display: Specifies a connection to an X server; returned from 6717 % XOpenDisplay. 6718 % 6719 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6720 % 6721 % o windows: Specifies a pointer to a XWindows structure. 6722 % 6723 % o state: key mask. 6724 % 6725 % o key_symbol: Specifies a command to perform. 6726 % 6727 % o image: the image; XImageWIndowCommand may transform the image and 6728 % return a new image pointer. 6729 % 6730 % o exception: return any errors or warnings in this structure. 6731 % 6732 */ 6733 static CommandType XImageWindowCommand(Display *display, 6734 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6735 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6736 { 6737 static char 6738 delta[MagickPathExtent] = ""; 6739 6740 static const char 6741 Digits[] = "01234567890"; 6742 6743 static KeySym 6744 last_symbol = XK_0; 6745 6746 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6747 { 6748 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6749 { 6750 *delta='\0'; 6751 resource_info->quantum=1; 6752 } 6753 last_symbol=key_symbol; 6754 delta[strlen(delta)+1]='\0'; 6755 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6756 resource_info->quantum=StringToLong(delta); 6757 return(NullCommand); 6758 } 6759 last_symbol=key_symbol; 6760 if (resource_info->immutable) 6761 { 6762 /* 6763 Virtual image window has a restricted command set. 6764 */ 6765 switch (key_symbol) 6766 { 6767 case XK_question: 6768 return(InfoCommand); 6769 case XK_p: 6770 case XK_Print: 6771 return(PrintCommand); 6772 case XK_space: 6773 return(NextCommand); 6774 case XK_q: 6775 case XK_Escape: 6776 return(QuitCommand); 6777 default: 6778 break; 6779 } 6780 return(NullCommand); 6781 } 6782 switch ((int) key_symbol) 6783 { 6784 case XK_o: 6785 { 6786 if ((state & ControlMask) == 0) 6787 break; 6788 return(OpenCommand); 6789 } 6790 case XK_space: 6791 return(NextCommand); 6792 case XK_BackSpace: 6793 return(FormerCommand); 6794 case XK_s: 6795 { 6796 if ((state & Mod1Mask) != 0) 6797 return(SwirlCommand); 6798 if ((state & ControlMask) == 0) 6799 return(ShearCommand); 6800 return(SaveCommand); 6801 } 6802 case XK_p: 6803 case XK_Print: 6804 { 6805 if ((state & Mod1Mask) != 0) 6806 return(OilPaintCommand); 6807 if ((state & Mod4Mask) != 0) 6808 return(ColorCommand); 6809 if ((state & ControlMask) == 0) 6810 return(NullCommand); 6811 return(PrintCommand); 6812 } 6813 case XK_d: 6814 { 6815 if ((state & Mod4Mask) != 0) 6816 return(DrawCommand); 6817 if ((state & ControlMask) == 0) 6818 return(NullCommand); 6819 return(DeleteCommand); 6820 } 6821 case XK_Select: 6822 { 6823 if ((state & ControlMask) == 0) 6824 return(NullCommand); 6825 return(SelectCommand); 6826 } 6827 case XK_n: 6828 { 6829 if ((state & ControlMask) == 0) 6830 return(NullCommand); 6831 return(NewCommand); 6832 } 6833 case XK_q: 6834 case XK_Escape: 6835 return(QuitCommand); 6836 case XK_z: 6837 case XK_Undo: 6838 { 6839 if ((state & ControlMask) == 0) 6840 return(NullCommand); 6841 return(UndoCommand); 6842 } 6843 case XK_r: 6844 case XK_Redo: 6845 { 6846 if ((state & ControlMask) == 0) 6847 return(RollCommand); 6848 return(RedoCommand); 6849 } 6850 case XK_x: 6851 { 6852 if ((state & ControlMask) == 0) 6853 return(NullCommand); 6854 return(CutCommand); 6855 } 6856 case XK_c: 6857 { 6858 if ((state & Mod1Mask) != 0) 6859 return(CharcoalDrawCommand); 6860 if ((state & ControlMask) == 0) 6861 return(CropCommand); 6862 return(CopyCommand); 6863 } 6864 case XK_v: 6865 case XK_Insert: 6866 { 6867 if ((state & Mod4Mask) != 0) 6868 return(CompositeCommand); 6869 if ((state & ControlMask) == 0) 6870 return(FlipCommand); 6871 return(PasteCommand); 6872 } 6873 case XK_less: 6874 return(HalfSizeCommand); 6875 case XK_minus: 6876 return(OriginalSizeCommand); 6877 case XK_greater: 6878 return(DoubleSizeCommand); 6879 case XK_percent: 6880 return(ResizeCommand); 6881 case XK_at: 6882 return(RefreshCommand); 6883 case XK_bracketleft: 6884 return(ChopCommand); 6885 case XK_h: 6886 return(FlopCommand); 6887 case XK_slash: 6888 return(RotateRightCommand); 6889 case XK_backslash: 6890 return(RotateLeftCommand); 6891 case XK_asterisk: 6892 return(RotateCommand); 6893 case XK_t: 6894 return(TrimCommand); 6895 case XK_H: 6896 return(HueCommand); 6897 case XK_S: 6898 return(SaturationCommand); 6899 case XK_L: 6900 return(BrightnessCommand); 6901 case XK_G: 6902 return(GammaCommand); 6903 case XK_C: 6904 return(SpiffCommand); 6905 case XK_Z: 6906 return(DullCommand); 6907 case XK_N: 6908 return(NormalizeCommand); 6909 case XK_equal: 6910 return(EqualizeCommand); 6911 case XK_asciitilde: 6912 return(NegateCommand); 6913 case XK_period: 6914 return(GrayscaleCommand); 6915 case XK_numbersign: 6916 return(QuantizeCommand); 6917 case XK_F2: 6918 return(DespeckleCommand); 6919 case XK_F3: 6920 return(EmbossCommand); 6921 case XK_F4: 6922 return(ReduceNoiseCommand); 6923 case XK_F5: 6924 return(AddNoiseCommand); 6925 case XK_F6: 6926 return(SharpenCommand); 6927 case XK_F7: 6928 return(BlurCommand); 6929 case XK_F8: 6930 return(ThresholdCommand); 6931 case XK_F9: 6932 return(EdgeDetectCommand); 6933 case XK_F10: 6934 return(SpreadCommand); 6935 case XK_F11: 6936 return(ShadeCommand); 6937 case XK_F12: 6938 return(RaiseCommand); 6939 case XK_F13: 6940 return(SegmentCommand); 6941 case XK_i: 6942 { 6943 if ((state & Mod1Mask) == 0) 6944 return(NullCommand); 6945 return(ImplodeCommand); 6946 } 6947 case XK_w: 6948 { 6949 if ((state & Mod1Mask) == 0) 6950 return(NullCommand); 6951 return(WaveCommand); 6952 } 6953 case XK_m: 6954 { 6955 if ((state & Mod4Mask) == 0) 6956 return(NullCommand); 6957 return(MatteCommand); 6958 } 6959 case XK_b: 6960 { 6961 if ((state & Mod4Mask) == 0) 6962 return(NullCommand); 6963 return(AddBorderCommand); 6964 } 6965 case XK_f: 6966 { 6967 if ((state & Mod4Mask) == 0) 6968 return(NullCommand); 6969 return(AddFrameCommand); 6970 } 6971 case XK_exclam: 6972 { 6973 if ((state & Mod4Mask) == 0) 6974 return(NullCommand); 6975 return(CommentCommand); 6976 } 6977 case XK_a: 6978 { 6979 if ((state & Mod1Mask) != 0) 6980 return(ApplyCommand); 6981 if ((state & Mod4Mask) != 0) 6982 return(AnnotateCommand); 6983 if ((state & ControlMask) == 0) 6984 return(NullCommand); 6985 return(RegionofInterestCommand); 6986 } 6987 case XK_question: 6988 return(InfoCommand); 6989 case XK_plus: 6990 return(ZoomCommand); 6991 case XK_P: 6992 { 6993 if ((state & ShiftMask) == 0) 6994 return(NullCommand); 6995 return(ShowPreviewCommand); 6996 } 6997 case XK_Execute: 6998 return(LaunchCommand); 6999 case XK_F1: 7000 return(HelpCommand); 7001 case XK_Find: 7002 return(BrowseDocumentationCommand); 7003 case XK_Menu: 7004 { 7005 (void) XMapRaised(display,windows->command.id); 7006 return(NullCommand); 7007 } 7008 case XK_Next: 7009 case XK_Prior: 7010 case XK_Home: 7011 case XK_KP_Home: 7012 { 7013 XTranslateImage(display,windows,*image,key_symbol); 7014 return(NullCommand); 7015 } 7016 case XK_Up: 7017 case XK_KP_Up: 7018 case XK_Down: 7019 case XK_KP_Down: 7020 case XK_Left: 7021 case XK_KP_Left: 7022 case XK_Right: 7023 case XK_KP_Right: 7024 { 7025 if ((state & Mod1Mask) != 0) 7026 { 7027 RectangleInfo 7028 crop_info; 7029 7030 /* 7031 Trim one pixel from edge of image. 7032 */ 7033 crop_info.x=0; 7034 crop_info.y=0; 7035 crop_info.width=(size_t) windows->image.ximage->width; 7036 crop_info.height=(size_t) windows->image.ximage->height; 7037 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7038 { 7039 if (resource_info->quantum >= (int) crop_info.height) 7040 resource_info->quantum=(int) crop_info.height-1; 7041 crop_info.height-=resource_info->quantum; 7042 } 7043 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7044 { 7045 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7046 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7047 crop_info.y+=resource_info->quantum; 7048 crop_info.height-=resource_info->quantum; 7049 } 7050 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7051 { 7052 if (resource_info->quantum >= (int) crop_info.width) 7053 resource_info->quantum=(int) crop_info.width-1; 7054 crop_info.width-=resource_info->quantum; 7055 } 7056 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7057 { 7058 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7059 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7060 crop_info.x+=resource_info->quantum; 7061 crop_info.width-=resource_info->quantum; 7062 } 7063 if ((int) (windows->image.x+windows->image.width) > 7064 (int) crop_info.width) 7065 windows->image.x=(int) (crop_info.width-windows->image.width); 7066 if ((int) (windows->image.y+windows->image.height) > 7067 (int) crop_info.height) 7068 windows->image.y=(int) (crop_info.height-windows->image.height); 7069 XSetCropGeometry(display,windows,&crop_info,*image); 7070 windows->image.window_changes.width=(int) crop_info.width; 7071 windows->image.window_changes.height=(int) crop_info.height; 7072 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7073 (void) XConfigureImage(display,resource_info,windows,*image, 7074 exception); 7075 return(NullCommand); 7076 } 7077 XTranslateImage(display,windows,*image,key_symbol); 7078 return(NullCommand); 7079 } 7080 default: 7081 return(NullCommand); 7082 } 7083 return(NullCommand); 7084 } 7085 7086 /* 7088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7089 % % 7090 % % 7091 % % 7092 + X M a g i c k C o m m a n d % 7093 % % 7094 % % 7095 % % 7096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7097 % 7098 % XMagickCommand() makes a transform to the image or Image window as 7099 % specified by a user menu button or keyboard command. 7100 % 7101 % The format of the XMagickCommand method is: 7102 % 7103 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7104 % XWindows *windows,const CommandType command,Image **image, 7105 % ExceptionInfo *exception) 7106 % 7107 % A description of each parameter follows: 7108 % 7109 % o display: Specifies a connection to an X server; returned from 7110 % XOpenDisplay. 7111 % 7112 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7113 % 7114 % o windows: Specifies a pointer to a XWindows structure. 7115 % 7116 % o command: Specifies a command to perform. 7117 % 7118 % o image: the image; XMagickCommand may transform the image and return a 7119 % new image pointer. 7120 % 7121 % o exception: return any errors or warnings in this structure. 7122 % 7123 */ 7124 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7125 XWindows *windows,const CommandType command,Image **image, 7126 ExceptionInfo *exception) 7127 { 7128 char 7129 filename[MagickPathExtent], 7130 geometry[MagickPathExtent], 7131 modulate_factors[MagickPathExtent]; 7132 7133 GeometryInfo 7134 geometry_info; 7135 7136 Image 7137 *nexus; 7138 7139 ImageInfo 7140 *image_info; 7141 7142 int 7143 x, 7144 y; 7145 7146 MagickStatusType 7147 flags, 7148 status; 7149 7150 QuantizeInfo 7151 quantize_info; 7152 7153 RectangleInfo 7154 page_geometry; 7155 7156 register int 7157 i; 7158 7159 static char 7160 color[MagickPathExtent] = "gray"; 7161 7162 unsigned int 7163 height, 7164 width; 7165 7166 /* 7167 Process user command. 7168 */ 7169 XCheckRefreshWindows(display,windows); 7170 XImageCache(display,resource_info,windows,command,image,exception); 7171 nexus=NewImageList(); 7172 windows->image.window_changes.width=windows->image.ximage->width; 7173 windows->image.window_changes.height=windows->image.ximage->height; 7174 image_info=CloneImageInfo(resource_info->image_info); 7175 SetGeometryInfo(&geometry_info); 7176 GetQuantizeInfo(&quantize_info); 7177 switch (command) 7178 { 7179 case OpenCommand: 7180 { 7181 /* 7182 Load image. 7183 */ 7184 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7185 break; 7186 } 7187 case NextCommand: 7188 { 7189 /* 7190 Display next image. 7191 */ 7192 for (i=0; i < resource_info->quantum; i++) 7193 XClientMessage(display,windows->image.id,windows->im_protocols, 7194 windows->im_next_image,CurrentTime); 7195 break; 7196 } 7197 case FormerCommand: 7198 { 7199 /* 7200 Display former image. 7201 */ 7202 for (i=0; i < resource_info->quantum; i++) 7203 XClientMessage(display,windows->image.id,windows->im_protocols, 7204 windows->im_former_image,CurrentTime); 7205 break; 7206 } 7207 case SelectCommand: 7208 { 7209 int 7210 status; 7211 7212 /* 7213 Select image. 7214 */ 7215 if (*resource_info->home_directory == '\0') 7216 (void) CopyMagickString(resource_info->home_directory,".", 7217 MagickPathExtent); 7218 status=chdir(resource_info->home_directory); 7219 if (status == -1) 7220 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7221 "UnableToOpenFile","%s",resource_info->home_directory); 7222 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7223 break; 7224 } 7225 case SaveCommand: 7226 { 7227 /* 7228 Save image. 7229 */ 7230 status=XSaveImage(display,resource_info,windows,*image,exception); 7231 if (status == MagickFalse) 7232 { 7233 char 7234 message[MagickPathExtent]; 7235 7236 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s", 7237 exception->reason != (char *) NULL ? exception->reason : "", 7238 exception->description != (char *) NULL ? exception->description : 7239 ""); 7240 XNoticeWidget(display,windows,"Unable to save file:",message); 7241 break; 7242 } 7243 break; 7244 } 7245 case PrintCommand: 7246 { 7247 /* 7248 Print image. 7249 */ 7250 status=XPrintImage(display,resource_info,windows,*image,exception); 7251 if (status == MagickFalse) 7252 { 7253 char 7254 message[MagickPathExtent]; 7255 7256 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s", 7257 exception->reason != (char *) NULL ? exception->reason : "", 7258 exception->description != (char *) NULL ? exception->description : 7259 ""); 7260 XNoticeWidget(display,windows,"Unable to print file:",message); 7261 break; 7262 } 7263 break; 7264 } 7265 case DeleteCommand: 7266 { 7267 static char 7268 filename[MagickPathExtent] = "\0"; 7269 7270 /* 7271 Delete image file. 7272 */ 7273 XFileBrowserWidget(display,windows,"Delete",filename); 7274 if (*filename == '\0') 7275 break; 7276 status=ShredFile(filename); 7277 if (status != MagickFalse ) 7278 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7279 break; 7280 } 7281 case NewCommand: 7282 { 7283 int 7284 status; 7285 7286 static char 7287 color[MagickPathExtent] = "gray", 7288 geometry[MagickPathExtent] = "640x480"; 7289 7290 static const char 7291 *format = "gradient"; 7292 7293 /* 7294 Query user for canvas geometry. 7295 */ 7296 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7297 geometry); 7298 if (*geometry == '\0') 7299 break; 7300 if (status == 0) 7301 format="xc"; 7302 XColorBrowserWidget(display,windows,"Select",color); 7303 if (*color == '\0') 7304 break; 7305 /* 7306 Create canvas. 7307 */ 7308 (void) FormatLocaleString(image_info->filename,MagickPathExtent, 7309 "%s:%s",format,color); 7310 (void) CloneString(&image_info->size,geometry); 7311 nexus=ReadImage(image_info,exception); 7312 CatchException(exception); 7313 XClientMessage(display,windows->image.id,windows->im_protocols, 7314 windows->im_next_image,CurrentTime); 7315 break; 7316 } 7317 case VisualDirectoryCommand: 7318 { 7319 /* 7320 Visual Image directory. 7321 */ 7322 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7323 break; 7324 } 7325 case QuitCommand: 7326 { 7327 /* 7328 exit program. 7329 */ 7330 if (resource_info->confirm_exit == MagickFalse) 7331 XClientMessage(display,windows->image.id,windows->im_protocols, 7332 windows->im_exit,CurrentTime); 7333 else 7334 { 7335 int 7336 status; 7337 7338 /* 7339 Confirm program exit. 7340 */ 7341 status=XConfirmWidget(display,windows,"Do you really want to exit", 7342 resource_info->client_name); 7343 if (status > 0) 7344 XClientMessage(display,windows->image.id,windows->im_protocols, 7345 windows->im_exit,CurrentTime); 7346 } 7347 break; 7348 } 7349 case CutCommand: 7350 { 7351 /* 7352 Cut image. 7353 */ 7354 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7355 break; 7356 } 7357 case CopyCommand: 7358 { 7359 /* 7360 Copy image. 7361 */ 7362 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7363 exception); 7364 break; 7365 } 7366 case PasteCommand: 7367 { 7368 /* 7369 Paste image. 7370 */ 7371 status=XPasteImage(display,resource_info,windows,*image,exception); 7372 if (status == MagickFalse) 7373 { 7374 XNoticeWidget(display,windows,"Unable to paste X image", 7375 (*image)->filename); 7376 break; 7377 } 7378 break; 7379 } 7380 case HalfSizeCommand: 7381 { 7382 /* 7383 Half image size. 7384 */ 7385 windows->image.window_changes.width=windows->image.ximage->width/2; 7386 windows->image.window_changes.height=windows->image.ximage->height/2; 7387 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7388 break; 7389 } 7390 case OriginalSizeCommand: 7391 { 7392 /* 7393 Original image size. 7394 */ 7395 windows->image.window_changes.width=(int) (*image)->columns; 7396 windows->image.window_changes.height=(int) (*image)->rows; 7397 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7398 break; 7399 } 7400 case DoubleSizeCommand: 7401 { 7402 /* 7403 Double the image size. 7404 */ 7405 windows->image.window_changes.width=windows->image.ximage->width << 1; 7406 windows->image.window_changes.height=windows->image.ximage->height << 1; 7407 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7408 break; 7409 } 7410 case ResizeCommand: 7411 { 7412 int 7413 status; 7414 7415 size_t 7416 height, 7417 width; 7418 7419 ssize_t 7420 x, 7421 y; 7422 7423 /* 7424 Resize image. 7425 */ 7426 width=(size_t) windows->image.ximage->width; 7427 height=(size_t) windows->image.ximage->height; 7428 x=0; 7429 y=0; 7430 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0", 7431 (double) width,(double) height); 7432 status=XDialogWidget(display,windows,"Resize", 7433 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7434 if (*geometry == '\0') 7435 break; 7436 if (status == 0) 7437 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent); 7438 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7439 windows->image.window_changes.width=(int) width; 7440 windows->image.window_changes.height=(int) height; 7441 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7442 break; 7443 } 7444 case ApplyCommand: 7445 { 7446 char 7447 image_geometry[MagickPathExtent]; 7448 7449 if ((windows->image.crop_geometry == (char *) NULL) && 7450 ((int) (*image)->columns == windows->image.ximage->width) && 7451 ((int) (*image)->rows == windows->image.ximage->height)) 7452 break; 7453 /* 7454 Apply size transforms to image. 7455 */ 7456 XSetCursorState(display,windows,MagickTrue); 7457 XCheckRefreshWindows(display,windows); 7458 /* 7459 Crop and/or scale displayed image. 7460 */ 7461 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!", 7462 windows->image.ximage->width,windows->image.ximage->height); 7463 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7464 exception); 7465 if (windows->image.crop_geometry != (char *) NULL) 7466 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7467 windows->image.crop_geometry); 7468 windows->image.x=0; 7469 windows->image.y=0; 7470 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7471 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7472 break; 7473 } 7474 case RefreshCommand: 7475 { 7476 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7477 break; 7478 } 7479 case RestoreCommand: 7480 { 7481 /* 7482 Restore Image window to its original size. 7483 */ 7484 if ((windows->image.width == (unsigned int) (*image)->columns) && 7485 (windows->image.height == (unsigned int) (*image)->rows) && 7486 (windows->image.crop_geometry == (char *) NULL)) 7487 { 7488 (void) XBell(display,0); 7489 break; 7490 } 7491 windows->image.window_changes.width=(int) (*image)->columns; 7492 windows->image.window_changes.height=(int) (*image)->rows; 7493 if (windows->image.crop_geometry != (char *) NULL) 7494 { 7495 windows->image.crop_geometry=(char *) 7496 RelinquishMagickMemory(windows->image.crop_geometry); 7497 windows->image.crop_geometry=(char *) NULL; 7498 windows->image.x=0; 7499 windows->image.y=0; 7500 } 7501 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7502 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7503 break; 7504 } 7505 case CropCommand: 7506 { 7507 /* 7508 Crop image. 7509 */ 7510 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7511 exception); 7512 break; 7513 } 7514 case ChopCommand: 7515 { 7516 /* 7517 Chop image. 7518 */ 7519 status=XChopImage(display,resource_info,windows,image,exception); 7520 if (status == MagickFalse) 7521 { 7522 XNoticeWidget(display,windows,"Unable to cut X image", 7523 (*image)->filename); 7524 break; 7525 } 7526 break; 7527 } 7528 case FlopCommand: 7529 { 7530 Image 7531 *flop_image; 7532 7533 /* 7534 Flop image scanlines. 7535 */ 7536 XSetCursorState(display,windows,MagickTrue); 7537 XCheckRefreshWindows(display,windows); 7538 flop_image=FlopImage(*image,exception); 7539 if (flop_image != (Image *) NULL) 7540 { 7541 *image=DestroyImage(*image); 7542 *image=flop_image; 7543 } 7544 CatchException(exception); 7545 XSetCursorState(display,windows,MagickFalse); 7546 if (windows->image.crop_geometry != (char *) NULL) 7547 { 7548 /* 7549 Flop crop geometry. 7550 */ 7551 width=(unsigned int) (*image)->columns; 7552 height=(unsigned int) (*image)->rows; 7553 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7554 &width,&height); 7555 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 7556 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7557 } 7558 if (windows->image.orphan != MagickFalse ) 7559 break; 7560 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7561 break; 7562 } 7563 case FlipCommand: 7564 { 7565 Image 7566 *flip_image; 7567 7568 /* 7569 Flip image scanlines. 7570 */ 7571 XSetCursorState(display,windows,MagickTrue); 7572 XCheckRefreshWindows(display,windows); 7573 flip_image=FlipImage(*image,exception); 7574 if (flip_image != (Image *) NULL) 7575 { 7576 *image=DestroyImage(*image); 7577 *image=flip_image; 7578 } 7579 CatchException(exception); 7580 XSetCursorState(display,windows,MagickFalse); 7581 if (windows->image.crop_geometry != (char *) NULL) 7582 { 7583 /* 7584 Flip crop geometry. 7585 */ 7586 width=(unsigned int) (*image)->columns; 7587 height=(unsigned int) (*image)->rows; 7588 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7589 &width,&height); 7590 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 7591 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7592 } 7593 if (windows->image.orphan != MagickFalse ) 7594 break; 7595 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7596 break; 7597 } 7598 case RotateRightCommand: 7599 { 7600 /* 7601 Rotate image 90 degrees clockwise. 7602 */ 7603 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7604 if (status == MagickFalse) 7605 { 7606 XNoticeWidget(display,windows,"Unable to rotate X image", 7607 (*image)->filename); 7608 break; 7609 } 7610 break; 7611 } 7612 case RotateLeftCommand: 7613 { 7614 /* 7615 Rotate image 90 degrees counter-clockwise. 7616 */ 7617 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7618 if (status == MagickFalse) 7619 { 7620 XNoticeWidget(display,windows,"Unable to rotate X image", 7621 (*image)->filename); 7622 break; 7623 } 7624 break; 7625 } 7626 case RotateCommand: 7627 { 7628 /* 7629 Rotate image. 7630 */ 7631 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7632 if (status == MagickFalse) 7633 { 7634 XNoticeWidget(display,windows,"Unable to rotate X image", 7635 (*image)->filename); 7636 break; 7637 } 7638 break; 7639 } 7640 case ShearCommand: 7641 { 7642 Image 7643 *shear_image; 7644 7645 static char 7646 geometry[MagickPathExtent] = "45.0x45.0"; 7647 7648 /* 7649 Query user for shear color and geometry. 7650 */ 7651 XColorBrowserWidget(display,windows,"Select",color); 7652 if (*color == '\0') 7653 break; 7654 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7655 geometry); 7656 if (*geometry == '\0') 7657 break; 7658 /* 7659 Shear image. 7660 */ 7661 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7662 exception); 7663 XSetCursorState(display,windows,MagickTrue); 7664 XCheckRefreshWindows(display,windows); 7665 (void) QueryColorCompliance(color,AllCompliance, 7666 &(*image)->background_color,exception); 7667 flags=ParseGeometry(geometry,&geometry_info); 7668 if ((flags & SigmaValue) == 0) 7669 geometry_info.sigma=geometry_info.rho; 7670 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7671 exception); 7672 if (shear_image != (Image *) NULL) 7673 { 7674 *image=DestroyImage(*image); 7675 *image=shear_image; 7676 } 7677 CatchException(exception); 7678 XSetCursorState(display,windows,MagickFalse); 7679 if (windows->image.orphan != MagickFalse ) 7680 break; 7681 windows->image.window_changes.width=(int) (*image)->columns; 7682 windows->image.window_changes.height=(int) (*image)->rows; 7683 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7684 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7685 break; 7686 } 7687 case RollCommand: 7688 { 7689 Image 7690 *roll_image; 7691 7692 static char 7693 geometry[MagickPathExtent] = "+2+2"; 7694 7695 /* 7696 Query user for the roll geometry. 7697 */ 7698 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7699 geometry); 7700 if (*geometry == '\0') 7701 break; 7702 /* 7703 Roll image. 7704 */ 7705 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7706 exception); 7707 XSetCursorState(display,windows,MagickTrue); 7708 XCheckRefreshWindows(display,windows); 7709 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7710 exception); 7711 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7712 exception); 7713 if (roll_image != (Image *) NULL) 7714 { 7715 *image=DestroyImage(*image); 7716 *image=roll_image; 7717 } 7718 CatchException(exception); 7719 XSetCursorState(display,windows,MagickFalse); 7720 if (windows->image.orphan != MagickFalse ) 7721 break; 7722 windows->image.window_changes.width=(int) (*image)->columns; 7723 windows->image.window_changes.height=(int) (*image)->rows; 7724 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7725 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7726 break; 7727 } 7728 case TrimCommand: 7729 { 7730 static char 7731 fuzz[MagickPathExtent]; 7732 7733 /* 7734 Query user for the fuzz factor. 7735 */ 7736 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0* 7737 (*image)->fuzz/(QuantumRange+1.0)); 7738 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7739 if (*fuzz == '\0') 7740 break; 7741 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7742 /* 7743 Trim image. 7744 */ 7745 status=XTrimImage(display,resource_info,windows,*image,exception); 7746 if (status == MagickFalse) 7747 { 7748 XNoticeWidget(display,windows,"Unable to trim X image", 7749 (*image)->filename); 7750 break; 7751 } 7752 break; 7753 } 7754 case HueCommand: 7755 { 7756 static char 7757 hue_percent[MagickPathExtent] = "110"; 7758 7759 /* 7760 Query user for percent hue change. 7761 */ 7762 (void) XDialogWidget(display,windows,"Apply", 7763 "Enter percent change in image hue (0-200):",hue_percent); 7764 if (*hue_percent == '\0') 7765 break; 7766 /* 7767 Vary the image hue. 7768 */ 7769 XSetCursorState(display,windows,MagickTrue); 7770 XCheckRefreshWindows(display,windows); 7771 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent); 7772 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7773 MagickPathExtent); 7774 (void) ModulateImage(*image,modulate_factors,exception); 7775 XSetCursorState(display,windows,MagickFalse); 7776 if (windows->image.orphan != MagickFalse ) 7777 break; 7778 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7779 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7780 break; 7781 } 7782 case SaturationCommand: 7783 { 7784 static char 7785 saturation_percent[MagickPathExtent] = "110"; 7786 7787 /* 7788 Query user for percent saturation change. 7789 */ 7790 (void) XDialogWidget(display,windows,"Apply", 7791 "Enter percent change in color saturation (0-200):",saturation_percent); 7792 if (*saturation_percent == '\0') 7793 break; 7794 /* 7795 Vary color saturation. 7796 */ 7797 XSetCursorState(display,windows,MagickTrue); 7798 XCheckRefreshWindows(display,windows); 7799 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent); 7800 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7801 MagickPathExtent); 7802 (void) ModulateImage(*image,modulate_factors,exception); 7803 XSetCursorState(display,windows,MagickFalse); 7804 if (windows->image.orphan != MagickFalse ) 7805 break; 7806 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7807 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7808 break; 7809 } 7810 case BrightnessCommand: 7811 { 7812 static char 7813 brightness_percent[MagickPathExtent] = "110"; 7814 7815 /* 7816 Query user for percent brightness change. 7817 */ 7818 (void) XDialogWidget(display,windows,"Apply", 7819 "Enter percent change in color brightness (0-200):",brightness_percent); 7820 if (*brightness_percent == '\0') 7821 break; 7822 /* 7823 Vary the color brightness. 7824 */ 7825 XSetCursorState(display,windows,MagickTrue); 7826 XCheckRefreshWindows(display,windows); 7827 (void) CopyMagickString(modulate_factors,brightness_percent, 7828 MagickPathExtent); 7829 (void) ModulateImage(*image,modulate_factors,exception); 7830 XSetCursorState(display,windows,MagickFalse); 7831 if (windows->image.orphan != MagickFalse ) 7832 break; 7833 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7834 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7835 break; 7836 } 7837 case GammaCommand: 7838 { 7839 static char 7840 factor[MagickPathExtent] = "1.6"; 7841 7842 /* 7843 Query user for gamma value. 7844 */ 7845 (void) XDialogWidget(display,windows,"Gamma", 7846 "Enter gamma value (e.g. 1.2):",factor); 7847 if (*factor == '\0') 7848 break; 7849 /* 7850 Gamma correct image. 7851 */ 7852 XSetCursorState(display,windows,MagickTrue); 7853 XCheckRefreshWindows(display,windows); 7854 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception); 7855 XSetCursorState(display,windows,MagickFalse); 7856 if (windows->image.orphan != MagickFalse ) 7857 break; 7858 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7859 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7860 break; 7861 } 7862 case SpiffCommand: 7863 { 7864 /* 7865 Sharpen the image contrast. 7866 */ 7867 XSetCursorState(display,windows,MagickTrue); 7868 XCheckRefreshWindows(display,windows); 7869 (void) ContrastImage(*image,MagickTrue,exception); 7870 XSetCursorState(display,windows,MagickFalse); 7871 if (windows->image.orphan != MagickFalse ) 7872 break; 7873 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7874 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7875 break; 7876 } 7877 case DullCommand: 7878 { 7879 /* 7880 Dull the image contrast. 7881 */ 7882 XSetCursorState(display,windows,MagickTrue); 7883 XCheckRefreshWindows(display,windows); 7884 (void) ContrastImage(*image,MagickFalse,exception); 7885 XSetCursorState(display,windows,MagickFalse); 7886 if (windows->image.orphan != MagickFalse ) 7887 break; 7888 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7889 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7890 break; 7891 } 7892 case ContrastStretchCommand: 7893 { 7894 double 7895 black_point, 7896 white_point; 7897 7898 static char 7899 levels[MagickPathExtent] = "1%"; 7900 7901 /* 7902 Query user for gamma value. 7903 */ 7904 (void) XDialogWidget(display,windows,"Contrast Stretch", 7905 "Enter black and white points:",levels); 7906 if (*levels == '\0') 7907 break; 7908 /* 7909 Contrast stretch image. 7910 */ 7911 XSetCursorState(display,windows,MagickTrue); 7912 XCheckRefreshWindows(display,windows); 7913 flags=ParseGeometry(levels,&geometry_info); 7914 black_point=geometry_info.rho; 7915 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7916 if ((flags & PercentValue) != 0) 7917 { 7918 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7919 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7920 } 7921 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7922 (void) ContrastStretchImage(*image,black_point,white_point, 7923 exception); 7924 XSetCursorState(display,windows,MagickFalse); 7925 if (windows->image.orphan != MagickFalse ) 7926 break; 7927 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7928 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7929 break; 7930 } 7931 case SigmoidalContrastCommand: 7932 { 7933 GeometryInfo 7934 geometry_info; 7935 7936 MagickStatusType 7937 flags; 7938 7939 static char 7940 levels[MagickPathExtent] = "3x50%"; 7941 7942 /* 7943 Query user for gamma value. 7944 */ 7945 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7946 "Enter contrast and midpoint:",levels); 7947 if (*levels == '\0') 7948 break; 7949 /* 7950 Contrast stretch image. 7951 */ 7952 XSetCursorState(display,windows,MagickTrue); 7953 XCheckRefreshWindows(display,windows); 7954 flags=ParseGeometry(levels,&geometry_info); 7955 if ((flags & SigmaValue) == 0) 7956 geometry_info.sigma=1.0*QuantumRange/2.0; 7957 if ((flags & PercentValue) != 0) 7958 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7959 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7960 geometry_info.sigma,exception); 7961 XSetCursorState(display,windows,MagickFalse); 7962 if (windows->image.orphan != MagickFalse ) 7963 break; 7964 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7965 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7966 break; 7967 } 7968 case NormalizeCommand: 7969 { 7970 /* 7971 Perform histogram normalization on the image. 7972 */ 7973 XSetCursorState(display,windows,MagickTrue); 7974 XCheckRefreshWindows(display,windows); 7975 (void) NormalizeImage(*image,exception); 7976 XSetCursorState(display,windows,MagickFalse); 7977 if (windows->image.orphan != MagickFalse ) 7978 break; 7979 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7980 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7981 break; 7982 } 7983 case EqualizeCommand: 7984 { 7985 /* 7986 Perform histogram equalization on the image. 7987 */ 7988 XSetCursorState(display,windows,MagickTrue); 7989 XCheckRefreshWindows(display,windows); 7990 (void) EqualizeImage(*image,exception); 7991 XSetCursorState(display,windows,MagickFalse); 7992 if (windows->image.orphan != MagickFalse ) 7993 break; 7994 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7995 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7996 break; 7997 } 7998 case NegateCommand: 7999 { 8000 /* 8001 Negate colors in image. 8002 */ 8003 XSetCursorState(display,windows,MagickTrue); 8004 XCheckRefreshWindows(display,windows); 8005 (void) NegateImage(*image,MagickFalse,exception); 8006 XSetCursorState(display,windows,MagickFalse); 8007 if (windows->image.orphan != MagickFalse ) 8008 break; 8009 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8010 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8011 break; 8012 } 8013 case GrayscaleCommand: 8014 { 8015 /* 8016 Convert image to grayscale. 8017 */ 8018 XSetCursorState(display,windows,MagickTrue); 8019 XCheckRefreshWindows(display,windows); 8020 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ? 8021 GrayscaleType : GrayscaleAlphaType,exception); 8022 XSetCursorState(display,windows,MagickFalse); 8023 if (windows->image.orphan != MagickFalse ) 8024 break; 8025 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8026 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8027 break; 8028 } 8029 case MapCommand: 8030 { 8031 Image 8032 *affinity_image; 8033 8034 static char 8035 filename[MagickPathExtent] = "\0"; 8036 8037 /* 8038 Request image file name from user. 8039 */ 8040 XFileBrowserWidget(display,windows,"Map",filename); 8041 if (*filename == '\0') 8042 break; 8043 /* 8044 Map image. 8045 */ 8046 XSetCursorState(display,windows,MagickTrue); 8047 XCheckRefreshWindows(display,windows); 8048 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 8049 affinity_image=ReadImage(image_info,exception); 8050 if (affinity_image != (Image *) NULL) 8051 { 8052 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8053 affinity_image=DestroyImage(affinity_image); 8054 } 8055 CatchException(exception); 8056 XSetCursorState(display,windows,MagickFalse); 8057 if (windows->image.orphan != MagickFalse ) 8058 break; 8059 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8060 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8061 break; 8062 } 8063 case QuantizeCommand: 8064 { 8065 int 8066 status; 8067 8068 static char 8069 colors[MagickPathExtent] = "256"; 8070 8071 /* 8072 Query user for maximum number of colors. 8073 */ 8074 status=XDialogWidget(display,windows,"Quantize", 8075 "Maximum number of colors:",colors); 8076 if (*colors == '\0') 8077 break; 8078 /* 8079 Color reduce the image. 8080 */ 8081 XSetCursorState(display,windows,MagickTrue); 8082 XCheckRefreshWindows(display,windows); 8083 quantize_info.number_colors=StringToUnsignedLong(colors); 8084 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8085 NoDitherMethod; 8086 (void) QuantizeImage(&quantize_info,*image,exception); 8087 XSetCursorState(display,windows,MagickFalse); 8088 if (windows->image.orphan != MagickFalse ) 8089 break; 8090 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8091 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8092 break; 8093 } 8094 case DespeckleCommand: 8095 { 8096 Image 8097 *despeckle_image; 8098 8099 /* 8100 Despeckle image. 8101 */ 8102 XSetCursorState(display,windows,MagickTrue); 8103 XCheckRefreshWindows(display,windows); 8104 despeckle_image=DespeckleImage(*image,exception); 8105 if (despeckle_image != (Image *) NULL) 8106 { 8107 *image=DestroyImage(*image); 8108 *image=despeckle_image; 8109 } 8110 CatchException(exception); 8111 XSetCursorState(display,windows,MagickFalse); 8112 if (windows->image.orphan != MagickFalse ) 8113 break; 8114 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8115 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8116 break; 8117 } 8118 case EmbossCommand: 8119 { 8120 Image 8121 *emboss_image; 8122 8123 static char 8124 radius[MagickPathExtent] = "0.0x1.0"; 8125 8126 /* 8127 Query user for emboss radius. 8128 */ 8129 (void) XDialogWidget(display,windows,"Emboss", 8130 "Enter the emboss radius and standard deviation:",radius); 8131 if (*radius == '\0') 8132 break; 8133 /* 8134 Reduce noise in the image. 8135 */ 8136 XSetCursorState(display,windows,MagickTrue); 8137 XCheckRefreshWindows(display,windows); 8138 flags=ParseGeometry(radius,&geometry_info); 8139 if ((flags & SigmaValue) == 0) 8140 geometry_info.sigma=1.0; 8141 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8142 exception); 8143 if (emboss_image != (Image *) NULL) 8144 { 8145 *image=DestroyImage(*image); 8146 *image=emboss_image; 8147 } 8148 CatchException(exception); 8149 XSetCursorState(display,windows,MagickFalse); 8150 if (windows->image.orphan != MagickFalse ) 8151 break; 8152 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8153 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8154 break; 8155 } 8156 case ReduceNoiseCommand: 8157 { 8158 Image 8159 *noise_image; 8160 8161 static char 8162 radius[MagickPathExtent] = "0"; 8163 8164 /* 8165 Query user for noise radius. 8166 */ 8167 (void) XDialogWidget(display,windows,"Reduce Noise", 8168 "Enter the noise radius:",radius); 8169 if (*radius == '\0') 8170 break; 8171 /* 8172 Reduce noise in the image. 8173 */ 8174 XSetCursorState(display,windows,MagickTrue); 8175 XCheckRefreshWindows(display,windows); 8176 flags=ParseGeometry(radius,&geometry_info); 8177 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8178 geometry_info.rho,(size_t) geometry_info.rho,exception); 8179 if (noise_image != (Image *) NULL) 8180 { 8181 *image=DestroyImage(*image); 8182 *image=noise_image; 8183 } 8184 CatchException(exception); 8185 XSetCursorState(display,windows,MagickFalse); 8186 if (windows->image.orphan != MagickFalse ) 8187 break; 8188 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8189 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8190 break; 8191 } 8192 case AddNoiseCommand: 8193 { 8194 char 8195 **noises; 8196 8197 Image 8198 *noise_image; 8199 8200 static char 8201 noise_type[MagickPathExtent] = "Gaussian"; 8202 8203 /* 8204 Add noise to the image. 8205 */ 8206 noises=GetCommandOptions(MagickNoiseOptions); 8207 if (noises == (char **) NULL) 8208 break; 8209 XListBrowserWidget(display,windows,&windows->widget, 8210 (const char **) noises,"Add Noise", 8211 "Select a type of noise to add to your image:",noise_type); 8212 noises=DestroyStringList(noises); 8213 if (*noise_type == '\0') 8214 break; 8215 XSetCursorState(display,windows,MagickTrue); 8216 XCheckRefreshWindows(display,windows); 8217 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8218 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8219 if (noise_image != (Image *) NULL) 8220 { 8221 *image=DestroyImage(*image); 8222 *image=noise_image; 8223 } 8224 CatchException(exception); 8225 XSetCursorState(display,windows,MagickFalse); 8226 if (windows->image.orphan != MagickFalse ) 8227 break; 8228 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8229 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8230 break; 8231 } 8232 case SharpenCommand: 8233 { 8234 Image 8235 *sharp_image; 8236 8237 static char 8238 radius[MagickPathExtent] = "0.0x1.0"; 8239 8240 /* 8241 Query user for sharpen radius. 8242 */ 8243 (void) XDialogWidget(display,windows,"Sharpen", 8244 "Enter the sharpen radius and standard deviation:",radius); 8245 if (*radius == '\0') 8246 break; 8247 /* 8248 Sharpen image scanlines. 8249 */ 8250 XSetCursorState(display,windows,MagickTrue); 8251 XCheckRefreshWindows(display,windows); 8252 flags=ParseGeometry(radius,&geometry_info); 8253 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8254 exception); 8255 if (sharp_image != (Image *) NULL) 8256 { 8257 *image=DestroyImage(*image); 8258 *image=sharp_image; 8259 } 8260 CatchException(exception); 8261 XSetCursorState(display,windows,MagickFalse); 8262 if (windows->image.orphan != MagickFalse ) 8263 break; 8264 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8265 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8266 break; 8267 } 8268 case BlurCommand: 8269 { 8270 Image 8271 *blur_image; 8272 8273 static char 8274 radius[MagickPathExtent] = "0.0x1.0"; 8275 8276 /* 8277 Query user for blur radius. 8278 */ 8279 (void) XDialogWidget(display,windows,"Blur", 8280 "Enter the blur radius and standard deviation:",radius); 8281 if (*radius == '\0') 8282 break; 8283 /* 8284 Blur an image. 8285 */ 8286 XSetCursorState(display,windows,MagickTrue); 8287 XCheckRefreshWindows(display,windows); 8288 flags=ParseGeometry(radius,&geometry_info); 8289 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8290 exception); 8291 if (blur_image != (Image *) NULL) 8292 { 8293 *image=DestroyImage(*image); 8294 *image=blur_image; 8295 } 8296 CatchException(exception); 8297 XSetCursorState(display,windows,MagickFalse); 8298 if (windows->image.orphan != MagickFalse ) 8299 break; 8300 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8301 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8302 break; 8303 } 8304 case ThresholdCommand: 8305 { 8306 double 8307 threshold; 8308 8309 static char 8310 factor[MagickPathExtent] = "128"; 8311 8312 /* 8313 Query user for threshold value. 8314 */ 8315 (void) XDialogWidget(display,windows,"Threshold", 8316 "Enter threshold value:",factor); 8317 if (*factor == '\0') 8318 break; 8319 /* 8320 Gamma correct image. 8321 */ 8322 XSetCursorState(display,windows,MagickTrue); 8323 XCheckRefreshWindows(display,windows); 8324 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8325 (void) BilevelImage(*image,threshold,exception); 8326 XSetCursorState(display,windows,MagickFalse); 8327 if (windows->image.orphan != MagickFalse ) 8328 break; 8329 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8330 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8331 break; 8332 } 8333 case EdgeDetectCommand: 8334 { 8335 Image 8336 *edge_image; 8337 8338 static char 8339 radius[MagickPathExtent] = "0"; 8340 8341 /* 8342 Query user for edge factor. 8343 */ 8344 (void) XDialogWidget(display,windows,"Detect Edges", 8345 "Enter the edge detect radius:",radius); 8346 if (*radius == '\0') 8347 break; 8348 /* 8349 Detect edge in image. 8350 */ 8351 XSetCursorState(display,windows,MagickTrue); 8352 XCheckRefreshWindows(display,windows); 8353 flags=ParseGeometry(radius,&geometry_info); 8354 edge_image=EdgeImage(*image,geometry_info.rho,exception); 8355 if (edge_image != (Image *) NULL) 8356 { 8357 *image=DestroyImage(*image); 8358 *image=edge_image; 8359 } 8360 CatchException(exception); 8361 XSetCursorState(display,windows,MagickFalse); 8362 if (windows->image.orphan != MagickFalse ) 8363 break; 8364 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8365 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8366 break; 8367 } 8368 case SpreadCommand: 8369 { 8370 Image 8371 *spread_image; 8372 8373 static char 8374 amount[MagickPathExtent] = "2"; 8375 8376 /* 8377 Query user for spread amount. 8378 */ 8379 (void) XDialogWidget(display,windows,"Spread", 8380 "Enter the displacement amount:",amount); 8381 if (*amount == '\0') 8382 break; 8383 /* 8384 Displace image pixels by a random amount. 8385 */ 8386 XSetCursorState(display,windows,MagickTrue); 8387 XCheckRefreshWindows(display,windows); 8388 flags=ParseGeometry(amount,&geometry_info); 8389 spread_image=EdgeImage(*image,geometry_info.rho,exception); 8390 if (spread_image != (Image *) NULL) 8391 { 8392 *image=DestroyImage(*image); 8393 *image=spread_image; 8394 } 8395 CatchException(exception); 8396 XSetCursorState(display,windows,MagickFalse); 8397 if (windows->image.orphan != MagickFalse ) 8398 break; 8399 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8400 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8401 break; 8402 } 8403 case ShadeCommand: 8404 { 8405 Image 8406 *shade_image; 8407 8408 int 8409 status; 8410 8411 static char 8412 geometry[MagickPathExtent] = "30x30"; 8413 8414 /* 8415 Query user for the shade geometry. 8416 */ 8417 status=XDialogWidget(display,windows,"Shade", 8418 "Enter the azimuth and elevation of the light source:",geometry); 8419 if (*geometry == '\0') 8420 break; 8421 /* 8422 Shade image pixels. 8423 */ 8424 XSetCursorState(display,windows,MagickTrue); 8425 XCheckRefreshWindows(display,windows); 8426 flags=ParseGeometry(geometry,&geometry_info); 8427 if ((flags & SigmaValue) == 0) 8428 geometry_info.sigma=1.0; 8429 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse, 8430 geometry_info.rho,geometry_info.sigma,exception); 8431 if (shade_image != (Image *) NULL) 8432 { 8433 *image=DestroyImage(*image); 8434 *image=shade_image; 8435 } 8436 CatchException(exception); 8437 XSetCursorState(display,windows,MagickFalse); 8438 if (windows->image.orphan != MagickFalse ) 8439 break; 8440 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8441 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8442 break; 8443 } 8444 case RaiseCommand: 8445 { 8446 static char 8447 bevel_width[MagickPathExtent] = "10"; 8448 8449 /* 8450 Query user for bevel width. 8451 */ 8452 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8453 if (*bevel_width == '\0') 8454 break; 8455 /* 8456 Raise an image. 8457 */ 8458 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8459 exception); 8460 XSetCursorState(display,windows,MagickTrue); 8461 XCheckRefreshWindows(display,windows); 8462 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8463 exception); 8464 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8465 XSetCursorState(display,windows,MagickFalse); 8466 if (windows->image.orphan != MagickFalse ) 8467 break; 8468 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8469 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8470 break; 8471 } 8472 case SegmentCommand: 8473 { 8474 static char 8475 threshold[MagickPathExtent] = "1.0x1.5"; 8476 8477 /* 8478 Query user for smoothing threshold. 8479 */ 8480 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8481 threshold); 8482 if (*threshold == '\0') 8483 break; 8484 /* 8485 Segment an image. 8486 */ 8487 XSetCursorState(display,windows,MagickTrue); 8488 XCheckRefreshWindows(display,windows); 8489 flags=ParseGeometry(threshold,&geometry_info); 8490 if ((flags & SigmaValue) == 0) 8491 geometry_info.sigma=1.0; 8492 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8493 geometry_info.sigma,exception); 8494 XSetCursorState(display,windows,MagickFalse); 8495 if (windows->image.orphan != MagickFalse ) 8496 break; 8497 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8498 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8499 break; 8500 } 8501 case SepiaToneCommand: 8502 { 8503 double 8504 threshold; 8505 8506 Image 8507 *sepia_image; 8508 8509 static char 8510 factor[MagickPathExtent] = "80%"; 8511 8512 /* 8513 Query user for sepia-tone factor. 8514 */ 8515 (void) XDialogWidget(display,windows,"Sepia Tone", 8516 "Enter the sepia tone factor (0 - 99.9%):",factor); 8517 if (*factor == '\0') 8518 break; 8519 /* 8520 Sepia tone image pixels. 8521 */ 8522 XSetCursorState(display,windows,MagickTrue); 8523 XCheckRefreshWindows(display,windows); 8524 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8525 sepia_image=SepiaToneImage(*image,threshold,exception); 8526 if (sepia_image != (Image *) NULL) 8527 { 8528 *image=DestroyImage(*image); 8529 *image=sepia_image; 8530 } 8531 CatchException(exception); 8532 XSetCursorState(display,windows,MagickFalse); 8533 if (windows->image.orphan != MagickFalse ) 8534 break; 8535 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8536 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8537 break; 8538 } 8539 case SolarizeCommand: 8540 { 8541 double 8542 threshold; 8543 8544 static char 8545 factor[MagickPathExtent] = "60%"; 8546 8547 /* 8548 Query user for solarize factor. 8549 */ 8550 (void) XDialogWidget(display,windows,"Solarize", 8551 "Enter the solarize factor (0 - 99.9%):",factor); 8552 if (*factor == '\0') 8553 break; 8554 /* 8555 Solarize image pixels. 8556 */ 8557 XSetCursorState(display,windows,MagickTrue); 8558 XCheckRefreshWindows(display,windows); 8559 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8560 (void) SolarizeImage(*image,threshold,exception); 8561 XSetCursorState(display,windows,MagickFalse); 8562 if (windows->image.orphan != MagickFalse ) 8563 break; 8564 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8565 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8566 break; 8567 } 8568 case SwirlCommand: 8569 { 8570 Image 8571 *swirl_image; 8572 8573 static char 8574 degrees[MagickPathExtent] = "60"; 8575 8576 /* 8577 Query user for swirl angle. 8578 */ 8579 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8580 degrees); 8581 if (*degrees == '\0') 8582 break; 8583 /* 8584 Swirl image pixels about the center. 8585 */ 8586 XSetCursorState(display,windows,MagickTrue); 8587 XCheckRefreshWindows(display,windows); 8588 flags=ParseGeometry(degrees,&geometry_info); 8589 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8590 exception); 8591 if (swirl_image != (Image *) NULL) 8592 { 8593 *image=DestroyImage(*image); 8594 *image=swirl_image; 8595 } 8596 CatchException(exception); 8597 XSetCursorState(display,windows,MagickFalse); 8598 if (windows->image.orphan != MagickFalse ) 8599 break; 8600 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8601 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8602 break; 8603 } 8604 case ImplodeCommand: 8605 { 8606 Image 8607 *implode_image; 8608 8609 static char 8610 factor[MagickPathExtent] = "0.3"; 8611 8612 /* 8613 Query user for implode factor. 8614 */ 8615 (void) XDialogWidget(display,windows,"Implode", 8616 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8617 if (*factor == '\0') 8618 break; 8619 /* 8620 Implode image pixels about the center. 8621 */ 8622 XSetCursorState(display,windows,MagickTrue); 8623 XCheckRefreshWindows(display,windows); 8624 flags=ParseGeometry(factor,&geometry_info); 8625 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8626 exception); 8627 if (implode_image != (Image *) NULL) 8628 { 8629 *image=DestroyImage(*image); 8630 *image=implode_image; 8631 } 8632 CatchException(exception); 8633 XSetCursorState(display,windows,MagickFalse); 8634 if (windows->image.orphan != MagickFalse ) 8635 break; 8636 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8637 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8638 break; 8639 } 8640 case VignetteCommand: 8641 { 8642 Image 8643 *vignette_image; 8644 8645 static char 8646 geometry[MagickPathExtent] = "0x20"; 8647 8648 /* 8649 Query user for the vignette geometry. 8650 */ 8651 (void) XDialogWidget(display,windows,"Vignette", 8652 "Enter the radius, sigma, and x and y offsets:",geometry); 8653 if (*geometry == '\0') 8654 break; 8655 /* 8656 Soften the edges of the image in vignette style 8657 */ 8658 XSetCursorState(display,windows,MagickTrue); 8659 XCheckRefreshWindows(display,windows); 8660 flags=ParseGeometry(geometry,&geometry_info); 8661 if ((flags & SigmaValue) == 0) 8662 geometry_info.sigma=1.0; 8663 if ((flags & XiValue) == 0) 8664 geometry_info.xi=0.1*(*image)->columns; 8665 if ((flags & PsiValue) == 0) 8666 geometry_info.psi=0.1*(*image)->rows; 8667 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8668 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8669 exception); 8670 if (vignette_image != (Image *) NULL) 8671 { 8672 *image=DestroyImage(*image); 8673 *image=vignette_image; 8674 } 8675 CatchException(exception); 8676 XSetCursorState(display,windows,MagickFalse); 8677 if (windows->image.orphan != MagickFalse ) 8678 break; 8679 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8680 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8681 break; 8682 } 8683 case WaveCommand: 8684 { 8685 Image 8686 *wave_image; 8687 8688 static char 8689 geometry[MagickPathExtent] = "25x150"; 8690 8691 /* 8692 Query user for the wave geometry. 8693 */ 8694 (void) XDialogWidget(display,windows,"Wave", 8695 "Enter the amplitude and length of the wave:",geometry); 8696 if (*geometry == '\0') 8697 break; 8698 /* 8699 Alter an image along a sine wave. 8700 */ 8701 XSetCursorState(display,windows,MagickTrue); 8702 XCheckRefreshWindows(display,windows); 8703 flags=ParseGeometry(geometry,&geometry_info); 8704 if ((flags & SigmaValue) == 0) 8705 geometry_info.sigma=1.0; 8706 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8707 (*image)->interpolate,exception); 8708 if (wave_image != (Image *) NULL) 8709 { 8710 *image=DestroyImage(*image); 8711 *image=wave_image; 8712 } 8713 CatchException(exception); 8714 XSetCursorState(display,windows,MagickFalse); 8715 if (windows->image.orphan != MagickFalse ) 8716 break; 8717 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8718 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8719 break; 8720 } 8721 case OilPaintCommand: 8722 { 8723 Image 8724 *paint_image; 8725 8726 static char 8727 radius[MagickPathExtent] = "0"; 8728 8729 /* 8730 Query user for circular neighborhood radius. 8731 */ 8732 (void) XDialogWidget(display,windows,"Oil Paint", 8733 "Enter the mask radius:",radius); 8734 if (*radius == '\0') 8735 break; 8736 /* 8737 OilPaint image scanlines. 8738 */ 8739 XSetCursorState(display,windows,MagickTrue); 8740 XCheckRefreshWindows(display,windows); 8741 flags=ParseGeometry(radius,&geometry_info); 8742 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8743 exception); 8744 if (paint_image != (Image *) NULL) 8745 { 8746 *image=DestroyImage(*image); 8747 *image=paint_image; 8748 } 8749 CatchException(exception); 8750 XSetCursorState(display,windows,MagickFalse); 8751 if (windows->image.orphan != MagickFalse ) 8752 break; 8753 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8754 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8755 break; 8756 } 8757 case CharcoalDrawCommand: 8758 { 8759 Image 8760 *charcoal_image; 8761 8762 static char 8763 radius[MagickPathExtent] = "0x1"; 8764 8765 /* 8766 Query user for charcoal radius. 8767 */ 8768 (void) XDialogWidget(display,windows,"Charcoal Draw", 8769 "Enter the charcoal radius and sigma:",radius); 8770 if (*radius == '\0') 8771 break; 8772 /* 8773 Charcoal the image. 8774 */ 8775 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8776 exception); 8777 XSetCursorState(display,windows,MagickTrue); 8778 XCheckRefreshWindows(display,windows); 8779 flags=ParseGeometry(radius,&geometry_info); 8780 if ((flags & SigmaValue) == 0) 8781 geometry_info.sigma=geometry_info.rho; 8782 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8783 exception); 8784 if (charcoal_image != (Image *) NULL) 8785 { 8786 *image=DestroyImage(*image); 8787 *image=charcoal_image; 8788 } 8789 CatchException(exception); 8790 XSetCursorState(display,windows,MagickFalse); 8791 if (windows->image.orphan != MagickFalse ) 8792 break; 8793 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8794 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8795 break; 8796 } 8797 case AnnotateCommand: 8798 { 8799 /* 8800 Annotate the image with text. 8801 */ 8802 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8803 if (status == MagickFalse) 8804 { 8805 XNoticeWidget(display,windows,"Unable to annotate X image", 8806 (*image)->filename); 8807 break; 8808 } 8809 break; 8810 } 8811 case DrawCommand: 8812 { 8813 /* 8814 Draw image. 8815 */ 8816 status=XDrawEditImage(display,resource_info,windows,image,exception); 8817 if (status == MagickFalse) 8818 { 8819 XNoticeWidget(display,windows,"Unable to draw on the X image", 8820 (*image)->filename); 8821 break; 8822 } 8823 break; 8824 } 8825 case ColorCommand: 8826 { 8827 /* 8828 Color edit. 8829 */ 8830 status=XColorEditImage(display,resource_info,windows,image,exception); 8831 if (status == MagickFalse) 8832 { 8833 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8834 (*image)->filename); 8835 break; 8836 } 8837 break; 8838 } 8839 case MatteCommand: 8840 { 8841 /* 8842 Matte edit. 8843 */ 8844 status=XMatteEditImage(display,resource_info,windows,image,exception); 8845 if (status == MagickFalse) 8846 { 8847 XNoticeWidget(display,windows,"Unable to matte edit X image", 8848 (*image)->filename); 8849 break; 8850 } 8851 break; 8852 } 8853 case CompositeCommand: 8854 { 8855 /* 8856 Composite image. 8857 */ 8858 status=XCompositeImage(display,resource_info,windows,*image, 8859 exception); 8860 if (status == MagickFalse) 8861 { 8862 XNoticeWidget(display,windows,"Unable to composite X image", 8863 (*image)->filename); 8864 break; 8865 } 8866 break; 8867 } 8868 case AddBorderCommand: 8869 { 8870 Image 8871 *border_image; 8872 8873 static char 8874 geometry[MagickPathExtent] = "6x6"; 8875 8876 /* 8877 Query user for border color and geometry. 8878 */ 8879 XColorBrowserWidget(display,windows,"Select",color); 8880 if (*color == '\0') 8881 break; 8882 (void) XDialogWidget(display,windows,"Add Border", 8883 "Enter border geometry:",geometry); 8884 if (*geometry == '\0') 8885 break; 8886 /* 8887 Add a border to the image. 8888 */ 8889 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8890 exception); 8891 XSetCursorState(display,windows,MagickTrue); 8892 XCheckRefreshWindows(display,windows); 8893 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8894 exception); 8895 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8896 exception); 8897 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8898 exception); 8899 if (border_image != (Image *) NULL) 8900 { 8901 *image=DestroyImage(*image); 8902 *image=border_image; 8903 } 8904 CatchException(exception); 8905 XSetCursorState(display,windows,MagickFalse); 8906 if (windows->image.orphan != MagickFalse ) 8907 break; 8908 windows->image.window_changes.width=(int) (*image)->columns; 8909 windows->image.window_changes.height=(int) (*image)->rows; 8910 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8911 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8912 break; 8913 } 8914 case AddFrameCommand: 8915 { 8916 FrameInfo 8917 frame_info; 8918 8919 Image 8920 *frame_image; 8921 8922 static char 8923 geometry[MagickPathExtent] = "6x6"; 8924 8925 /* 8926 Query user for frame color and geometry. 8927 */ 8928 XColorBrowserWidget(display,windows,"Select",color); 8929 if (*color == '\0') 8930 break; 8931 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8932 geometry); 8933 if (*geometry == '\0') 8934 break; 8935 /* 8936 Surround image with an ornamental border. 8937 */ 8938 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8939 exception); 8940 XSetCursorState(display,windows,MagickTrue); 8941 XCheckRefreshWindows(display,windows); 8942 (void) QueryColorCompliance(color,AllCompliance,&(*image)->alpha_color, 8943 exception); 8944 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8945 exception); 8946 frame_info.width=page_geometry.width; 8947 frame_info.height=page_geometry.height; 8948 frame_info.outer_bevel=page_geometry.x; 8949 frame_info.inner_bevel=page_geometry.y; 8950 frame_info.x=(ssize_t) frame_info.width; 8951 frame_info.y=(ssize_t) frame_info.height; 8952 frame_info.width=(*image)->columns+2*frame_info.width; 8953 frame_info.height=(*image)->rows+2*frame_info.height; 8954 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8955 if (frame_image != (Image *) NULL) 8956 { 8957 *image=DestroyImage(*image); 8958 *image=frame_image; 8959 } 8960 CatchException(exception); 8961 XSetCursorState(display,windows,MagickFalse); 8962 if (windows->image.orphan != MagickFalse ) 8963 break; 8964 windows->image.window_changes.width=(int) (*image)->columns; 8965 windows->image.window_changes.height=(int) (*image)->rows; 8966 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8967 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8968 break; 8969 } 8970 case CommentCommand: 8971 { 8972 const char 8973 *value; 8974 8975 FILE 8976 *file; 8977 8978 int 8979 unique_file; 8980 8981 /* 8982 Edit image comment. 8983 */ 8984 unique_file=AcquireUniqueFileResource(image_info->filename); 8985 if (unique_file == -1) 8986 XNoticeWidget(display,windows,"Unable to edit image comment", 8987 image_info->filename); 8988 value=GetImageProperty(*image,"comment",exception); 8989 if (value == (char *) NULL) 8990 unique_file=close(unique_file)-1; 8991 else 8992 { 8993 register const char 8994 *p; 8995 8996 file=fdopen(unique_file,"w"); 8997 if (file == (FILE *) NULL) 8998 { 8999 XNoticeWidget(display,windows,"Unable to edit image comment", 9000 image_info->filename); 9001 break; 9002 } 9003 for (p=value; *p != '\0'; p++) 9004 (void) fputc((int) *p,file); 9005 (void) fputc('\n',file); 9006 (void) fclose(file); 9007 } 9008 XSetCursorState(display,windows,MagickTrue); 9009 XCheckRefreshWindows(display,windows); 9010 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9011 exception); 9012 if (status == MagickFalse) 9013 XNoticeWidget(display,windows,"Unable to edit image comment", 9014 (char *) NULL); 9015 else 9016 { 9017 char 9018 *comment; 9019 9020 comment=FileToString(image_info->filename,~0UL,exception); 9021 if (comment != (char *) NULL) 9022 { 9023 (void) SetImageProperty(*image,"comment",comment,exception); 9024 (*image)->taint=MagickTrue; 9025 } 9026 } 9027 (void) RelinquishUniqueFileResource(image_info->filename); 9028 XSetCursorState(display,windows,MagickFalse); 9029 break; 9030 } 9031 case LaunchCommand: 9032 { 9033 /* 9034 Launch program. 9035 */ 9036 XSetCursorState(display,windows,MagickTrue); 9037 XCheckRefreshWindows(display,windows); 9038 (void) AcquireUniqueFilename(filename); 9039 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s", 9040 filename); 9041 status=WriteImage(image_info,*image,exception); 9042 if (status == MagickFalse) 9043 XNoticeWidget(display,windows,"Unable to launch image editor", 9044 (char *) NULL); 9045 else 9046 { 9047 nexus=ReadImage(resource_info->image_info,exception); 9048 CatchException(exception); 9049 XClientMessage(display,windows->image.id,windows->im_protocols, 9050 windows->im_next_image,CurrentTime); 9051 } 9052 (void) RelinquishUniqueFileResource(filename); 9053 XSetCursorState(display,windows,MagickFalse); 9054 break; 9055 } 9056 case RegionofInterestCommand: 9057 { 9058 /* 9059 Apply an image processing technique to a region of interest. 9060 */ 9061 (void) XROIImage(display,resource_info,windows,image,exception); 9062 break; 9063 } 9064 case InfoCommand: 9065 break; 9066 case ZoomCommand: 9067 { 9068 /* 9069 Zoom image. 9070 */ 9071 if (windows->magnify.mapped != MagickFalse ) 9072 (void) XRaiseWindow(display,windows->magnify.id); 9073 else 9074 { 9075 /* 9076 Make magnify image. 9077 */ 9078 XSetCursorState(display,windows,MagickTrue); 9079 (void) XMapRaised(display,windows->magnify.id); 9080 XSetCursorState(display,windows,MagickFalse); 9081 } 9082 break; 9083 } 9084 case ShowPreviewCommand: 9085 { 9086 char 9087 **previews, 9088 value[MagickPathExtent]; 9089 9090 Image 9091 *preview_image; 9092 9093 PreviewType 9094 preview; 9095 9096 static char 9097 preview_type[MagickPathExtent] = "Gamma"; 9098 9099 /* 9100 Select preview type from menu. 9101 */ 9102 previews=GetCommandOptions(MagickPreviewOptions); 9103 if (previews == (char **) NULL) 9104 break; 9105 XListBrowserWidget(display,windows,&windows->widget, 9106 (const char **) previews,"Preview", 9107 "Select an enhancement, effect, or F/X:",preview_type); 9108 previews=DestroyStringList(previews); 9109 if (*preview_type == '\0') 9110 break; 9111 /* 9112 Show image preview. 9113 */ 9114 XSetCursorState(display,windows,MagickTrue); 9115 XCheckRefreshWindows(display,windows); 9116 preview=(PreviewType) ParseCommandOption(MagickPreviewOptions, 9117 MagickFalse,preview_type); 9118 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9119 windows->image.id); 9120 (void) SetImageProperty(*image,"group",value,exception); 9121 (void) DeleteImageProperty(*image,"label"); 9122 (void) SetImageProperty(*image,"label","Preview",exception); 9123 preview_image=PreviewImage(*image,preview,exception); 9124 if (preview_image == (Image *) NULL) 9125 break; 9126 (void) AcquireUniqueFilename(filename); 9127 (void) FormatLocaleString(preview_image->filename,MagickPathExtent, 9128 "show:%s",filename); 9129 status=WriteImage(image_info,preview_image,exception); 9130 (void) RelinquishUniqueFileResource(filename); 9131 preview_image=DestroyImage(preview_image); 9132 if (status == MagickFalse) 9133 XNoticeWidget(display,windows,"Unable to show image preview", 9134 (*image)->filename); 9135 XDelay(display,1500); 9136 XSetCursorState(display,windows,MagickFalse); 9137 break; 9138 } 9139 case ShowHistogramCommand: 9140 { 9141 char 9142 value[MagickPathExtent]; 9143 9144 Image 9145 *histogram_image; 9146 9147 /* 9148 Show image histogram. 9149 */ 9150 XSetCursorState(display,windows,MagickTrue); 9151 XCheckRefreshWindows(display,windows); 9152 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9153 windows->image.id); 9154 (void) SetImageProperty(*image,"group",value,exception); 9155 (void) DeleteImageProperty(*image,"label"); 9156 (void) SetImageProperty(*image,"label","Histogram",exception); 9157 (void) AcquireUniqueFilename(filename); 9158 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"histogram:%s", 9159 filename); 9160 status=WriteImage(image_info,*image,exception); 9161 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 9162 histogram_image=ReadImage(image_info,exception); 9163 (void) RelinquishUniqueFileResource(filename); 9164 if (histogram_image == (Image *) NULL) 9165 break; 9166 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent, 9167 "show:%s",filename); 9168 status=WriteImage(image_info,histogram_image,exception); 9169 histogram_image=DestroyImage(histogram_image); 9170 if (status == MagickFalse) 9171 XNoticeWidget(display,windows,"Unable to show histogram", 9172 (*image)->filename); 9173 XDelay(display,1500); 9174 XSetCursorState(display,windows,MagickFalse); 9175 break; 9176 } 9177 case ShowMatteCommand: 9178 { 9179 char 9180 value[MagickPathExtent]; 9181 9182 Image 9183 *matte_image; 9184 9185 if ((*image)->alpha_trait == UndefinedPixelTrait) 9186 { 9187 XNoticeWidget(display,windows, 9188 "Image does not have any matte information",(*image)->filename); 9189 break; 9190 } 9191 /* 9192 Show image matte. 9193 */ 9194 XSetCursorState(display,windows,MagickTrue); 9195 XCheckRefreshWindows(display,windows); 9196 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9197 windows->image.id); 9198 (void) SetImageProperty(*image,"group",value,exception); 9199 (void) DeleteImageProperty(*image,"label"); 9200 (void) SetImageProperty(*image,"label","Matte",exception); 9201 (void) AcquireUniqueFilename(filename); 9202 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s", 9203 filename); 9204 status=WriteImage(image_info,*image,exception); 9205 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 9206 matte_image=ReadImage(image_info,exception); 9207 (void) RelinquishUniqueFileResource(filename); 9208 if (matte_image == (Image *) NULL) 9209 break; 9210 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s", 9211 filename); 9212 status=WriteImage(image_info,matte_image,exception); 9213 matte_image=DestroyImage(matte_image); 9214 if (status == MagickFalse) 9215 XNoticeWidget(display,windows,"Unable to show matte", 9216 (*image)->filename); 9217 XDelay(display,1500); 9218 XSetCursorState(display,windows,MagickFalse); 9219 break; 9220 } 9221 case BackgroundCommand: 9222 { 9223 /* 9224 Background image. 9225 */ 9226 status=XBackgroundImage(display,resource_info,windows,image,exception); 9227 if (status == MagickFalse) 9228 break; 9229 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9230 if (nexus != (Image *) NULL) 9231 XClientMessage(display,windows->image.id,windows->im_protocols, 9232 windows->im_next_image,CurrentTime); 9233 break; 9234 } 9235 case SlideShowCommand: 9236 { 9237 static char 9238 delay[MagickPathExtent] = "5"; 9239 9240 /* 9241 Display next image after pausing. 9242 */ 9243 (void) XDialogWidget(display,windows,"Slide Show", 9244 "Pause how many 1/100ths of a second between images:",delay); 9245 if (*delay == '\0') 9246 break; 9247 resource_info->delay=StringToUnsignedLong(delay); 9248 XClientMessage(display,windows->image.id,windows->im_protocols, 9249 windows->im_next_image,CurrentTime); 9250 break; 9251 } 9252 case PreferencesCommand: 9253 { 9254 /* 9255 Set user preferences. 9256 */ 9257 status=XPreferencesWidget(display,resource_info,windows); 9258 if (status == MagickFalse) 9259 break; 9260 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9261 if (nexus != (Image *) NULL) 9262 XClientMessage(display,windows->image.id,windows->im_protocols, 9263 windows->im_next_image,CurrentTime); 9264 break; 9265 } 9266 case HelpCommand: 9267 { 9268 /* 9269 User requested help. 9270 */ 9271 XTextViewWidget(display,resource_info,windows,MagickFalse, 9272 "Help Viewer - Display",DisplayHelp); 9273 break; 9274 } 9275 case BrowseDocumentationCommand: 9276 { 9277 Atom 9278 mozilla_atom; 9279 9280 Window 9281 mozilla_window, 9282 root_window; 9283 9284 /* 9285 Browse the ImageMagick documentation. 9286 */ 9287 root_window=XRootWindow(display,XDefaultScreen(display)); 9288 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9289 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9290 if (mozilla_window != (Window) NULL) 9291 { 9292 char 9293 command[MagickPathExtent], 9294 *url; 9295 9296 /* 9297 Display documentation using Netscape remote control. 9298 */ 9299 url=GetMagickHomeURL(); 9300 (void) FormatLocaleString(command,MagickPathExtent, 9301 "openurl(%s,new-tab)",url); 9302 url=DestroyString(url); 9303 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9304 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9305 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9306 XSetCursorState(display,windows,MagickFalse); 9307 break; 9308 } 9309 XSetCursorState(display,windows,MagickTrue); 9310 XCheckRefreshWindows(display,windows); 9311 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9312 exception); 9313 if (status == MagickFalse) 9314 XNoticeWidget(display,windows,"Unable to browse documentation", 9315 (char *) NULL); 9316 XDelay(display,1500); 9317 XSetCursorState(display,windows,MagickFalse); 9318 break; 9319 } 9320 case VersionCommand: 9321 { 9322 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9323 GetMagickCopyright()); 9324 break; 9325 } 9326 case SaveToUndoBufferCommand: 9327 break; 9328 default: 9329 { 9330 (void) XBell(display,0); 9331 break; 9332 } 9333 } 9334 image_info=DestroyImageInfo(image_info); 9335 return(nexus); 9336 } 9337 9338 /* 9340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9341 % % 9342 % % 9343 % % 9344 + X M a g n i f y I m a g e % 9345 % % 9346 % % 9347 % % 9348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9349 % 9350 % XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9351 % The magnified portion is displayed in a separate window. 9352 % 9353 % The format of the XMagnifyImage method is: 9354 % 9355 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9356 % ExceptionInfo *exception) 9357 % 9358 % A description of each parameter follows: 9359 % 9360 % o display: Specifies a connection to an X server; returned from 9361 % XOpenDisplay. 9362 % 9363 % o windows: Specifies a pointer to a XWindows structure. 9364 % 9365 % o event: Specifies a pointer to a XEvent structure. If it is NULL, 9366 % the entire image is refreshed. 9367 % 9368 % o exception: return any errors or warnings in this structure. 9369 % 9370 */ 9371 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9372 ExceptionInfo *exception) 9373 { 9374 char 9375 text[MagickPathExtent]; 9376 9377 register int 9378 x, 9379 y; 9380 9381 size_t 9382 state; 9383 9384 /* 9385 Update magnified image until the mouse button is released. 9386 */ 9387 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9388 state=DefaultState; 9389 x=event->xbutton.x; 9390 y=event->xbutton.y; 9391 windows->magnify.x=(int) windows->image.x+x; 9392 windows->magnify.y=(int) windows->image.y+y; 9393 do 9394 { 9395 /* 9396 Map and unmap Info widget as text cursor crosses its boundaries. 9397 */ 9398 if (windows->info.mapped != MagickFalse ) 9399 { 9400 if ((x < (int) (windows->info.x+windows->info.width)) && 9401 (y < (int) (windows->info.y+windows->info.height))) 9402 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9403 } 9404 else 9405 if ((x > (int) (windows->info.x+windows->info.width)) || 9406 (y > (int) (windows->info.y+windows->info.height))) 9407 (void) XMapWindow(display,windows->info.id); 9408 if (windows->info.mapped != MagickFalse ) 9409 { 9410 /* 9411 Display pointer position. 9412 */ 9413 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 9414 windows->magnify.x,windows->magnify.y); 9415 XInfoWidget(display,windows,text); 9416 } 9417 /* 9418 Wait for next event. 9419 */ 9420 XScreenEvent(display,windows,event,exception); 9421 switch (event->type) 9422 { 9423 case ButtonPress: 9424 break; 9425 case ButtonRelease: 9426 { 9427 /* 9428 User has finished magnifying image. 9429 */ 9430 x=event->xbutton.x; 9431 y=event->xbutton.y; 9432 state|=ExitState; 9433 break; 9434 } 9435 case Expose: 9436 break; 9437 case MotionNotify: 9438 { 9439 x=event->xmotion.x; 9440 y=event->xmotion.y; 9441 break; 9442 } 9443 default: 9444 break; 9445 } 9446 /* 9447 Check boundary conditions. 9448 */ 9449 if (x < 0) 9450 x=0; 9451 else 9452 if (x >= (int) windows->image.width) 9453 x=(int) windows->image.width-1; 9454 if (y < 0) 9455 y=0; 9456 else 9457 if (y >= (int) windows->image.height) 9458 y=(int) windows->image.height-1; 9459 } while ((state & ExitState) == 0); 9460 /* 9461 Display magnified image. 9462 */ 9463 XSetCursorState(display,windows,MagickFalse); 9464 } 9465 9466 /* 9468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9469 % % 9470 % % 9471 % % 9472 + X M a g n i f y W i n d o w C o m m a n d % 9473 % % 9474 % % 9475 % % 9476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9477 % 9478 % XMagnifyWindowCommand() moves the image within an Magnify window by one 9479 % pixel as specified by the key symbol. 9480 % 9481 % The format of the XMagnifyWindowCommand method is: 9482 % 9483 % void XMagnifyWindowCommand(Display *display,XWindows *windows, 9484 % const MagickStatusType state,const KeySym key_symbol, 9485 % ExceptionInfo *exception) 9486 % 9487 % A description of each parameter follows: 9488 % 9489 % o display: Specifies a connection to an X server; returned from 9490 % XOpenDisplay. 9491 % 9492 % o windows: Specifies a pointer to a XWindows structure. 9493 % 9494 % o state: key mask. 9495 % 9496 % o key_symbol: Specifies a KeySym which indicates which side of the image 9497 % to trim. 9498 % 9499 % o exception: return any errors or warnings in this structure. 9500 % 9501 */ 9502 static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9503 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9504 { 9505 unsigned int 9506 quantum; 9507 9508 /* 9509 User specified a magnify factor or position. 9510 */ 9511 quantum=1; 9512 if ((state & Mod1Mask) != 0) 9513 quantum=10; 9514 switch ((int) key_symbol) 9515 { 9516 case QuitCommand: 9517 { 9518 (void) XWithdrawWindow(display,windows->magnify.id, 9519 windows->magnify.screen); 9520 break; 9521 } 9522 case XK_Home: 9523 case XK_KP_Home: 9524 { 9525 windows->magnify.x=(int) windows->image.width/2; 9526 windows->magnify.y=(int) windows->image.height/2; 9527 break; 9528 } 9529 case XK_Left: 9530 case XK_KP_Left: 9531 { 9532 if (windows->magnify.x > 0) 9533 windows->magnify.x-=quantum; 9534 break; 9535 } 9536 case XK_Up: 9537 case XK_KP_Up: 9538 { 9539 if (windows->magnify.y > 0) 9540 windows->magnify.y-=quantum; 9541 break; 9542 } 9543 case XK_Right: 9544 case XK_KP_Right: 9545 { 9546 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9547 windows->magnify.x+=quantum; 9548 break; 9549 } 9550 case XK_Down: 9551 case XK_KP_Down: 9552 { 9553 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9554 windows->magnify.y+=quantum; 9555 break; 9556 } 9557 case XK_0: 9558 case XK_1: 9559 case XK_2: 9560 case XK_3: 9561 case XK_4: 9562 case XK_5: 9563 case XK_6: 9564 case XK_7: 9565 case XK_8: 9566 case XK_9: 9567 { 9568 windows->magnify.data=(key_symbol-XK_0); 9569 break; 9570 } 9571 case XK_KP_0: 9572 case XK_KP_1: 9573 case XK_KP_2: 9574 case XK_KP_3: 9575 case XK_KP_4: 9576 case XK_KP_5: 9577 case XK_KP_6: 9578 case XK_KP_7: 9579 case XK_KP_8: 9580 case XK_KP_9: 9581 { 9582 windows->magnify.data=(key_symbol-XK_KP_0); 9583 break; 9584 } 9585 default: 9586 break; 9587 } 9588 XMakeMagnifyImage(display,windows,exception); 9589 } 9590 9591 /* 9593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9594 % % 9595 % % 9596 % % 9597 + X M a k e P a n I m a g e % 9598 % % 9599 % % 9600 % % 9601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9602 % 9603 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9604 % icon window. 9605 % 9606 % The format of the XMakePanImage method is: 9607 % 9608 % void XMakePanImage(Display *display,XResourceInfo *resource_info, 9609 % XWindows *windows,Image *image,ExceptionInfo *exception) 9610 % 9611 % A description of each parameter follows: 9612 % 9613 % o display: Specifies a connection to an X server; returned from 9614 % XOpenDisplay. 9615 % 9616 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9617 % 9618 % o windows: Specifies a pointer to a XWindows structure. 9619 % 9620 % o image: the image. 9621 % 9622 % o exception: return any errors or warnings in this structure. 9623 % 9624 */ 9625 static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9626 XWindows *windows,Image *image,ExceptionInfo *exception) 9627 { 9628 MagickStatusType 9629 status; 9630 9631 /* 9632 Create and display image for panning icon. 9633 */ 9634 XSetCursorState(display,windows,MagickTrue); 9635 XCheckRefreshWindows(display,windows); 9636 windows->pan.x=(int) windows->image.x; 9637 windows->pan.y=(int) windows->image.y; 9638 status=XMakeImage(display,resource_info,&windows->pan,image, 9639 windows->pan.width,windows->pan.height,exception); 9640 if (status == MagickFalse) 9641 ThrowXWindowException(ResourceLimitError, 9642 "MemoryAllocationFailed",image->filename); 9643 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9644 windows->pan.pixmap); 9645 (void) XClearWindow(display,windows->pan.id); 9646 XDrawPanRectangle(display,windows); 9647 XSetCursorState(display,windows,MagickFalse); 9648 } 9649 9650 /* 9652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9653 % % 9654 % % 9655 % % 9656 + X M a t t a E d i t I m a g e % 9657 % % 9658 % % 9659 % % 9660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9661 % 9662 % XMatteEditImage() allows the user to interactively change the Matte channel 9663 % of an image. If the image is PseudoClass it is promoted to DirectClass 9664 % before the matte information is stored. 9665 % 9666 % The format of the XMatteEditImage method is: 9667 % 9668 % MagickBooleanType XMatteEditImage(Display *display, 9669 % XResourceInfo *resource_info,XWindows *windows,Image **image, 9670 % ExceptionInfo *exception) 9671 % 9672 % A description of each parameter follows: 9673 % 9674 % o display: Specifies a connection to an X server; returned from 9675 % XOpenDisplay. 9676 % 9677 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9678 % 9679 % o windows: Specifies a pointer to a XWindows structure. 9680 % 9681 % o image: the image; returned from ReadImage. 9682 % 9683 % o exception: return any errors or warnings in this structure. 9684 % 9685 */ 9686 static MagickBooleanType XMatteEditImage(Display *display, 9687 XResourceInfo *resource_info,XWindows *windows,Image **image, 9688 ExceptionInfo *exception) 9689 { 9690 static char 9691 matte[MagickPathExtent] = "0"; 9692 9693 static const char 9694 *MatteEditMenu[] = 9695 { 9696 "Method", 9697 "Border Color", 9698 "Fuzz", 9699 "Matte Value", 9700 "Undo", 9701 "Help", 9702 "Dismiss", 9703 (char *) NULL 9704 }; 9705 9706 static const ModeType 9707 MatteEditCommands[] = 9708 { 9709 MatteEditMethod, 9710 MatteEditBorderCommand, 9711 MatteEditFuzzCommand, 9712 MatteEditValueCommand, 9713 MatteEditUndoCommand, 9714 MatteEditHelpCommand, 9715 MatteEditDismissCommand 9716 }; 9717 9718 static PaintMethod 9719 method = PointMethod; 9720 9721 static XColor 9722 border_color = { 0, 0, 0, 0, 0, 0 }; 9723 9724 char 9725 command[MagickPathExtent], 9726 text[MagickPathExtent]; 9727 9728 Cursor 9729 cursor; 9730 9731 int 9732 entry, 9733 id, 9734 x, 9735 x_offset, 9736 y, 9737 y_offset; 9738 9739 register int 9740 i; 9741 9742 register Quantum 9743 *q; 9744 9745 unsigned int 9746 height, 9747 width; 9748 9749 size_t 9750 state; 9751 9752 XEvent 9753 event; 9754 9755 /* 9756 Map Command widget. 9757 */ 9758 (void) CloneString(&windows->command.name,"Matte Edit"); 9759 windows->command.data=4; 9760 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9761 (void) XMapRaised(display,windows->command.id); 9762 XClientMessage(display,windows->image.id,windows->im_protocols, 9763 windows->im_update_widget,CurrentTime); 9764 /* 9765 Make cursor. 9766 */ 9767 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9768 resource_info->background_color,resource_info->foreground_color); 9769 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9770 /* 9771 Track pointer until button 1 is pressed. 9772 */ 9773 XQueryPosition(display,windows->image.id,&x,&y); 9774 (void) XSelectInput(display,windows->image.id, 9775 windows->image.attributes.event_mask | PointerMotionMask); 9776 state=DefaultState; 9777 do 9778 { 9779 if (windows->info.mapped != MagickFalse ) 9780 { 9781 /* 9782 Display pointer position. 9783 */ 9784 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 9785 x+windows->image.x,y+windows->image.y); 9786 XInfoWidget(display,windows,text); 9787 } 9788 /* 9789 Wait for next event. 9790 */ 9791 XScreenEvent(display,windows,&event,exception); 9792 if (event.xany.window == windows->command.id) 9793 { 9794 /* 9795 Select a command from the Command widget. 9796 */ 9797 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9798 if (id < 0) 9799 { 9800 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9801 continue; 9802 } 9803 switch (MatteEditCommands[id]) 9804 { 9805 case MatteEditMethod: 9806 { 9807 char 9808 **methods; 9809 9810 /* 9811 Select a method from the pop-up menu. 9812 */ 9813 methods=GetCommandOptions(MagickMethodOptions); 9814 if (methods == (char **) NULL) 9815 break; 9816 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9817 (const char **) methods,command); 9818 if (entry >= 0) 9819 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9820 MagickFalse,methods[entry]); 9821 methods=DestroyStringList(methods); 9822 break; 9823 } 9824 case MatteEditBorderCommand: 9825 { 9826 const char 9827 *ColorMenu[MaxNumberPens]; 9828 9829 int 9830 pen_number; 9831 9832 /* 9833 Initialize menu selections. 9834 */ 9835 for (i=0; i < (int) (MaxNumberPens-2); i++) 9836 ColorMenu[i]=resource_info->pen_colors[i]; 9837 ColorMenu[MaxNumberPens-2]="Browser..."; 9838 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9839 /* 9840 Select a pen color from the pop-up menu. 9841 */ 9842 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9843 (const char **) ColorMenu,command); 9844 if (pen_number < 0) 9845 break; 9846 if (pen_number == (MaxNumberPens-2)) 9847 { 9848 static char 9849 color_name[MagickPathExtent] = "gray"; 9850 9851 /* 9852 Select a pen color from a dialog. 9853 */ 9854 resource_info->pen_colors[pen_number]=color_name; 9855 XColorBrowserWidget(display,windows,"Select",color_name); 9856 if (*color_name == '\0') 9857 break; 9858 } 9859 /* 9860 Set border color. 9861 */ 9862 (void) XParseColor(display,windows->map_info->colormap, 9863 resource_info->pen_colors[pen_number],&border_color); 9864 break; 9865 } 9866 case MatteEditFuzzCommand: 9867 { 9868 static char 9869 fuzz[MagickPathExtent]; 9870 9871 static const char 9872 *FuzzMenu[] = 9873 { 9874 "0%", 9875 "2%", 9876 "5%", 9877 "10%", 9878 "15%", 9879 "Dialog...", 9880 (char *) NULL, 9881 }; 9882 9883 /* 9884 Select a command from the pop-up menu. 9885 */ 9886 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9887 command); 9888 if (entry < 0) 9889 break; 9890 if (entry != 5) 9891 { 9892 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9893 QuantumRange+1.0); 9894 break; 9895 } 9896 (void) CopyMagickString(fuzz,"20%",MagickPathExtent); 9897 (void) XDialogWidget(display,windows,"Ok", 9898 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9899 if (*fuzz == '\0') 9900 break; 9901 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent); 9902 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9903 1.0); 9904 break; 9905 } 9906 case MatteEditValueCommand: 9907 { 9908 static char 9909 message[MagickPathExtent]; 9910 9911 static const char 9912 *MatteMenu[] = 9913 { 9914 "Opaque", 9915 "Transparent", 9916 "Dialog...", 9917 (char *) NULL, 9918 }; 9919 9920 /* 9921 Select a command from the pop-up menu. 9922 */ 9923 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9924 command); 9925 if (entry < 0) 9926 break; 9927 if (entry != 2) 9928 { 9929 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat, 9930 OpaqueAlpha); 9931 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9932 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat, 9933 (Quantum) TransparentAlpha); 9934 break; 9935 } 9936 (void) FormatLocaleString(message,MagickPathExtent, 9937 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9938 QuantumRange); 9939 (void) XDialogWidget(display,windows,"Matte",message,matte); 9940 if (*matte == '\0') 9941 break; 9942 break; 9943 } 9944 case MatteEditUndoCommand: 9945 { 9946 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9947 image,exception); 9948 break; 9949 } 9950 case MatteEditHelpCommand: 9951 { 9952 XTextViewWidget(display,resource_info,windows,MagickFalse, 9953 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9954 break; 9955 } 9956 case MatteEditDismissCommand: 9957 { 9958 /* 9959 Prematurely exit. 9960 */ 9961 state|=EscapeState; 9962 state|=ExitState; 9963 break; 9964 } 9965 default: 9966 break; 9967 } 9968 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9969 continue; 9970 } 9971 switch (event.type) 9972 { 9973 case ButtonPress: 9974 { 9975 if (event.xbutton.button != Button1) 9976 break; 9977 if ((event.xbutton.window != windows->image.id) && 9978 (event.xbutton.window != windows->magnify.id)) 9979 break; 9980 /* 9981 Update matte data. 9982 */ 9983 x=event.xbutton.x; 9984 y=event.xbutton.y; 9985 (void) XMagickCommand(display,resource_info,windows, 9986 SaveToUndoBufferCommand,image,exception); 9987 state|=UpdateConfigurationState; 9988 break; 9989 } 9990 case ButtonRelease: 9991 { 9992 if (event.xbutton.button != Button1) 9993 break; 9994 if ((event.xbutton.window != windows->image.id) && 9995 (event.xbutton.window != windows->magnify.id)) 9996 break; 9997 /* 9998 Update colormap information. 9999 */ 10000 x=event.xbutton.x; 10001 y=event.xbutton.y; 10002 XConfigureImageColormap(display,resource_info,windows,*image,exception); 10003 (void) XConfigureImage(display,resource_info,windows,*image,exception); 10004 XInfoWidget(display,windows,text); 10005 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10006 state&=(~UpdateConfigurationState); 10007 break; 10008 } 10009 case Expose: 10010 break; 10011 case KeyPress: 10012 { 10013 char 10014 command[MagickPathExtent]; 10015 10016 KeySym 10017 key_symbol; 10018 10019 if (event.xkey.window == windows->magnify.id) 10020 { 10021 Window 10022 window; 10023 10024 window=windows->magnify.id; 10025 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10026 } 10027 if (event.xkey.window != windows->image.id) 10028 break; 10029 /* 10030 Respond to a user key press. 10031 */ 10032 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10033 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10034 switch ((int) key_symbol) 10035 { 10036 case XK_Escape: 10037 case XK_F20: 10038 { 10039 /* 10040 Prematurely exit. 10041 */ 10042 state|=ExitState; 10043 break; 10044 } 10045 case XK_F1: 10046 case XK_Help: 10047 { 10048 XTextViewWidget(display,resource_info,windows,MagickFalse, 10049 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10050 break; 10051 } 10052 default: 10053 { 10054 (void) XBell(display,0); 10055 break; 10056 } 10057 } 10058 break; 10059 } 10060 case MotionNotify: 10061 { 10062 /* 10063 Map and unmap Info widget as cursor crosses its boundaries. 10064 */ 10065 x=event.xmotion.x; 10066 y=event.xmotion.y; 10067 if (windows->info.mapped != MagickFalse ) 10068 { 10069 if ((x < (int) (windows->info.x+windows->info.width)) && 10070 (y < (int) (windows->info.y+windows->info.height))) 10071 (void) XWithdrawWindow(display,windows->info.id, 10072 windows->info.screen); 10073 } 10074 else 10075 if ((x > (int) (windows->info.x+windows->info.width)) || 10076 (y > (int) (windows->info.y+windows->info.height))) 10077 (void) XMapWindow(display,windows->info.id); 10078 break; 10079 } 10080 default: 10081 break; 10082 } 10083 if (event.xany.window == windows->magnify.id) 10084 { 10085 x=windows->magnify.x-windows->image.x; 10086 y=windows->magnify.y-windows->image.y; 10087 } 10088 x_offset=x; 10089 y_offset=y; 10090 if ((state & UpdateConfigurationState) != 0) 10091 { 10092 CacheView 10093 *image_view; 10094 10095 int 10096 x, 10097 y; 10098 10099 /* 10100 Matte edit is relative to image configuration. 10101 */ 10102 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10103 MagickTrue); 10104 XPutPixel(windows->image.ximage,x_offset,y_offset, 10105 windows->pixel_info->background_color.pixel); 10106 width=(unsigned int) (*image)->columns; 10107 height=(unsigned int) (*image)->rows; 10108 x=0; 10109 y=0; 10110 if (windows->image.crop_geometry != (char *) NULL) 10111 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10112 &height); 10113 x_offset=(int) (width*(windows->image.x+x_offset)/ 10114 windows->image.ximage->width+x); 10115 y_offset=(int) (height*(windows->image.y+y_offset)/ 10116 windows->image.ximage->height+y); 10117 if ((x_offset < 0) || (y_offset < 0)) 10118 continue; 10119 if ((x_offset >= (int) (*image)->columns) || 10120 (y_offset >= (int) (*image)->rows)) 10121 continue; 10122 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10123 return(MagickFalse); 10124 if ((*image)->alpha_trait == UndefinedPixelTrait) 10125 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10126 image_view=AcquireAuthenticCacheView(*image,exception); 10127 switch (method) 10128 { 10129 case PointMethod: 10130 default: 10131 { 10132 /* 10133 Update matte information using point algorithm. 10134 */ 10135 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10136 (ssize_t) y_offset,1,1,exception); 10137 if (q == (Quantum *) NULL) 10138 break; 10139 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10140 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10141 break; 10142 } 10143 case ReplaceMethod: 10144 { 10145 PixelInfo 10146 pixel, 10147 target; 10148 10149 /* 10150 Update matte information using replace algorithm. 10151 */ 10152 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10153 x_offset,(ssize_t) y_offset,&target,exception); 10154 for (y=0; y < (int) (*image)->rows; y++) 10155 { 10156 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10157 (*image)->columns,1,exception); 10158 if (q == (Quantum *) NULL) 10159 break; 10160 for (x=0; x < (int) (*image)->columns; x++) 10161 { 10162 GetPixelInfoPixel(*image,q,&pixel); 10163 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10164 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10165 q+=GetPixelChannels(*image); 10166 } 10167 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10168 break; 10169 } 10170 break; 10171 } 10172 case FloodfillMethod: 10173 case FillToBorderMethod: 10174 { 10175 ChannelType 10176 channel_mask; 10177 10178 DrawInfo 10179 *draw_info; 10180 10181 PixelInfo 10182 target; 10183 10184 /* 10185 Update matte information using floodfill algorithm. 10186 */ 10187 (void) GetOneVirtualPixelInfo(*image, 10188 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10189 y_offset,&target,exception); 10190 if (method == FillToBorderMethod) 10191 { 10192 target.red=(double) ScaleShortToQuantum( 10193 border_color.red); 10194 target.green=(double) ScaleShortToQuantum( 10195 border_color.green); 10196 target.blue=(double) ScaleShortToQuantum( 10197 border_color.blue); 10198 } 10199 draw_info=CloneDrawInfo(resource_info->image_info, 10200 (DrawInfo *) NULL); 10201 draw_info->fill.alpha=(double) ClampToQuantum( 10202 StringToDouble(matte,(char **) NULL)); 10203 channel_mask=SetImageChannelMask(*image,AlphaChannel); 10204 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10205 x_offset,(ssize_t) y_offset, 10206 method != FloodfillMethod ? MagickTrue : MagickFalse,exception); 10207 (void) SetPixelChannelMask(*image,channel_mask); 10208 draw_info=DestroyDrawInfo(draw_info); 10209 break; 10210 } 10211 case ResetMethod: 10212 { 10213 /* 10214 Update matte information using reset algorithm. 10215 */ 10216 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10217 return(MagickFalse); 10218 for (y=0; y < (int) (*image)->rows; y++) 10219 { 10220 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10221 (*image)->columns,1,exception); 10222 if (q == (Quantum *) NULL) 10223 break; 10224 for (x=0; x < (int) (*image)->columns; x++) 10225 { 10226 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10227 q+=GetPixelChannels(*image); 10228 } 10229 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10230 break; 10231 } 10232 if (StringToLong(matte) == (long) OpaqueAlpha) 10233 (*image)->alpha_trait=UndefinedPixelTrait; 10234 break; 10235 } 10236 } 10237 image_view=DestroyCacheView(image_view); 10238 state&=(~UpdateConfigurationState); 10239 } 10240 } while ((state & ExitState) == 0); 10241 (void) XSelectInput(display,windows->image.id, 10242 windows->image.attributes.event_mask); 10243 XSetCursorState(display,windows,MagickFalse); 10244 (void) XFreeCursor(display,cursor); 10245 return(MagickTrue); 10246 } 10247 10248 /* 10250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10251 % % 10252 % % 10253 % % 10254 + X O p e n I m a g e % 10255 % % 10256 % % 10257 % % 10258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10259 % 10260 % XOpenImage() loads an image from a file. 10261 % 10262 % The format of the XOpenImage method is: 10263 % 10264 % Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10265 % XWindows *windows,const unsigned int command) 10266 % 10267 % A description of each parameter follows: 10268 % 10269 % o display: Specifies a connection to an X server; returned from 10270 % XOpenDisplay. 10271 % 10272 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10273 % 10274 % o windows: Specifies a pointer to a XWindows structure. 10275 % 10276 % o command: A value other than zero indicates that the file is selected 10277 % from the command line argument list. 10278 % 10279 */ 10280 static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10281 XWindows *windows,const MagickBooleanType command) 10282 { 10283 const MagickInfo 10284 *magick_info; 10285 10286 ExceptionInfo 10287 *exception; 10288 10289 Image 10290 *nexus; 10291 10292 ImageInfo 10293 *image_info; 10294 10295 static char 10296 filename[MagickPathExtent] = "\0"; 10297 10298 /* 10299 Request file name from user. 10300 */ 10301 if (command == MagickFalse) 10302 XFileBrowserWidget(display,windows,"Open",filename); 10303 else 10304 { 10305 char 10306 **filelist, 10307 **files; 10308 10309 int 10310 count, 10311 status; 10312 10313 register int 10314 i, 10315 j; 10316 10317 /* 10318 Select next image from the command line. 10319 */ 10320 status=XGetCommand(display,windows->image.id,&files,&count); 10321 if (status == 0) 10322 { 10323 ThrowXWindowException(XServerError,"UnableToGetProperty","..."); 10324 return((Image *) NULL); 10325 } 10326 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10327 if (filelist == (char **) NULL) 10328 { 10329 ThrowXWindowException(ResourceLimitError, 10330 "MemoryAllocationFailed","..."); 10331 (void) XFreeStringList(files); 10332 return((Image *) NULL); 10333 } 10334 j=0; 10335 for (i=1; i < count; i++) 10336 if (*files[i] != '-') 10337 filelist[j++]=files[i]; 10338 filelist[j]=(char *) NULL; 10339 XListBrowserWidget(display,windows,&windows->widget, 10340 (const char **) filelist,"Load","Select Image to Load:",filename); 10341 filelist=(char **) RelinquishMagickMemory(filelist); 10342 (void) XFreeStringList(files); 10343 } 10344 if (*filename == '\0') 10345 return((Image *) NULL); 10346 image_info=CloneImageInfo(resource_info->image_info); 10347 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10348 (void *) NULL); 10349 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 10350 exception=AcquireExceptionInfo(); 10351 (void) SetImageInfo(image_info,0,exception); 10352 if (LocaleCompare(image_info->magick,"X") == 0) 10353 { 10354 char 10355 seconds[MagickPathExtent]; 10356 10357 /* 10358 User may want to delay the X server screen grab. 10359 */ 10360 (void) CopyMagickString(seconds,"0",MagickPathExtent); 10361 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10362 seconds); 10363 if (*seconds == '\0') 10364 return((Image *) NULL); 10365 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10366 } 10367 magick_info=GetMagickInfo(image_info->magick,exception); 10368 if ((magick_info != (const MagickInfo *) NULL) && 10369 GetMagickRawSupport(magick_info) == MagickTrue) 10370 { 10371 char 10372 geometry[MagickPathExtent]; 10373 10374 /* 10375 Request image size from the user. 10376 */ 10377 (void) CopyMagickString(geometry,"512x512",MagickPathExtent); 10378 if (image_info->size != (char *) NULL) 10379 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent); 10380 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10381 geometry); 10382 (void) CloneString(&image_info->size,geometry); 10383 } 10384 /* 10385 Load the image. 10386 */ 10387 XSetCursorState(display,windows,MagickTrue); 10388 XCheckRefreshWindows(display,windows); 10389 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 10390 nexus=ReadImage(image_info,exception); 10391 CatchException(exception); 10392 XSetCursorState(display,windows,MagickFalse); 10393 if (nexus != (Image *) NULL) 10394 XClientMessage(display,windows->image.id,windows->im_protocols, 10395 windows->im_next_image,CurrentTime); 10396 else 10397 { 10398 char 10399 *text, 10400 **textlist; 10401 10402 /* 10403 Unknown image format. 10404 */ 10405 text=FileToString(filename,~0UL,exception); 10406 if (text == (char *) NULL) 10407 return((Image *) NULL); 10408 textlist=StringToList(text); 10409 if (textlist != (char **) NULL) 10410 { 10411 char 10412 title[MagickPathExtent]; 10413 10414 register int 10415 i; 10416 10417 (void) FormatLocaleString(title,MagickPathExtent, 10418 "Unknown format: %s",filename); 10419 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10420 (const char **) textlist); 10421 for (i=0; textlist[i] != (char *) NULL; i++) 10422 textlist[i]=DestroyString(textlist[i]); 10423 textlist=(char **) RelinquishMagickMemory(textlist); 10424 } 10425 text=DestroyString(text); 10426 } 10427 exception=DestroyExceptionInfo(exception); 10428 image_info=DestroyImageInfo(image_info); 10429 return(nexus); 10430 } 10431 10432 /* 10434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10435 % % 10436 % % 10437 % % 10438 + X P a n I m a g e % 10439 % % 10440 % % 10441 % % 10442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10443 % 10444 % XPanImage() pans the image until the mouse button is released. 10445 % 10446 % The format of the XPanImage method is: 10447 % 10448 % void XPanImage(Display *display,XWindows *windows,XEvent *event, 10449 % ExceptionInfo *exception) 10450 % 10451 % A description of each parameter follows: 10452 % 10453 % o display: Specifies a connection to an X server; returned from 10454 % XOpenDisplay. 10455 % 10456 % o windows: Specifies a pointer to a XWindows structure. 10457 % 10458 % o event: Specifies a pointer to a XEvent structure. If it is NULL, 10459 % the entire image is refreshed. 10460 % 10461 % o exception: return any errors or warnings in this structure. 10462 % 10463 */ 10464 static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10465 ExceptionInfo *exception) 10466 { 10467 char 10468 text[MagickPathExtent]; 10469 10470 Cursor 10471 cursor; 10472 10473 double 10474 x_factor, 10475 y_factor; 10476 10477 RectangleInfo 10478 pan_info; 10479 10480 size_t 10481 state; 10482 10483 /* 10484 Define cursor. 10485 */ 10486 if ((windows->image.ximage->width > (int) windows->image.width) && 10487 (windows->image.ximage->height > (int) windows->image.height)) 10488 cursor=XCreateFontCursor(display,XC_fleur); 10489 else 10490 if (windows->image.ximage->width > (int) windows->image.width) 10491 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10492 else 10493 if (windows->image.ximage->height > (int) windows->image.height) 10494 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10495 else 10496 cursor=XCreateFontCursor(display,XC_arrow); 10497 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10498 /* 10499 Pan image as pointer moves until the mouse button is released. 10500 */ 10501 x_factor=(double) windows->image.ximage->width/windows->pan.width; 10502 y_factor=(double) windows->image.ximage->height/windows->pan.height; 10503 pan_info.width=windows->pan.width*windows->image.width/ 10504 windows->image.ximage->width; 10505 pan_info.height=windows->pan.height*windows->image.height/ 10506 windows->image.ximage->height; 10507 pan_info.x=0; 10508 pan_info.y=0; 10509 state=UpdateConfigurationState; 10510 do 10511 { 10512 switch (event->type) 10513 { 10514 case ButtonPress: 10515 { 10516 /* 10517 User choose an initial pan location. 10518 */ 10519 pan_info.x=(ssize_t) event->xbutton.x; 10520 pan_info.y=(ssize_t) event->xbutton.y; 10521 state|=UpdateConfigurationState; 10522 break; 10523 } 10524 case ButtonRelease: 10525 { 10526 /* 10527 User has finished panning the image. 10528 */ 10529 pan_info.x=(ssize_t) event->xbutton.x; 10530 pan_info.y=(ssize_t) event->xbutton.y; 10531 state|=UpdateConfigurationState | ExitState; 10532 break; 10533 } 10534 case MotionNotify: 10535 { 10536 pan_info.x=(ssize_t) event->xmotion.x; 10537 pan_info.y=(ssize_t) event->xmotion.y; 10538 state|=UpdateConfigurationState; 10539 } 10540 default: 10541 break; 10542 } 10543 if ((state & UpdateConfigurationState) != 0) 10544 { 10545 /* 10546 Check boundary conditions. 10547 */ 10548 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10549 pan_info.x=0; 10550 else 10551 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10552 if (pan_info.x < 0) 10553 pan_info.x=0; 10554 else 10555 if ((int) (pan_info.x+windows->image.width) > 10556 windows->image.ximage->width) 10557 pan_info.x=(ssize_t) 10558 (windows->image.ximage->width-windows->image.width); 10559 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10560 pan_info.y=0; 10561 else 10562 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10563 if (pan_info.y < 0) 10564 pan_info.y=0; 10565 else 10566 if ((int) (pan_info.y+windows->image.height) > 10567 windows->image.ximage->height) 10568 pan_info.y=(ssize_t) 10569 (windows->image.ximage->height-windows->image.height); 10570 if ((windows->image.x != (int) pan_info.x) || 10571 (windows->image.y != (int) pan_info.y)) 10572 { 10573 /* 10574 Display image pan offset. 10575 */ 10576 windows->image.x=(int) pan_info.x; 10577 windows->image.y=(int) pan_info.y; 10578 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ", 10579 windows->image.width,windows->image.height,windows->image.x, 10580 windows->image.y); 10581 XInfoWidget(display,windows,text); 10582 /* 10583 Refresh Image window. 10584 */ 10585 XDrawPanRectangle(display,windows); 10586 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10587 } 10588 state&=(~UpdateConfigurationState); 10589 } 10590 /* 10591 Wait for next event. 10592 */ 10593 if ((state & ExitState) == 0) 10594 XScreenEvent(display,windows,event,exception); 10595 } while ((state & ExitState) == 0); 10596 /* 10597 Restore cursor. 10598 */ 10599 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10600 (void) XFreeCursor(display,cursor); 10601 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10602 } 10603 10604 /* 10606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10607 % % 10608 % % 10609 % % 10610 + X P a s t e I m a g e % 10611 % % 10612 % % 10613 % % 10614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10615 % 10616 % XPasteImage() pastes an image previously saved with XCropImage in the X 10617 % window image at a location the user chooses with the pointer. 10618 % 10619 % The format of the XPasteImage method is: 10620 % 10621 % MagickBooleanType XPasteImage(Display *display, 10622 % XResourceInfo *resource_info,XWindows *windows,Image *image, 10623 % ExceptionInfo *exception) 10624 % 10625 % A description of each parameter follows: 10626 % 10627 % o display: Specifies a connection to an X server; returned from 10628 % XOpenDisplay. 10629 % 10630 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10631 % 10632 % o windows: Specifies a pointer to a XWindows structure. 10633 % 10634 % o image: the image; returned from ReadImage. 10635 % 10636 % o exception: return any errors or warnings in this structure. 10637 % 10638 */ 10639 static MagickBooleanType XPasteImage(Display *display, 10640 XResourceInfo *resource_info,XWindows *windows,Image *image, 10641 ExceptionInfo *exception) 10642 { 10643 static const char 10644 *PasteMenu[] = 10645 { 10646 "Operator", 10647 "Help", 10648 "Dismiss", 10649 (char *) NULL 10650 }; 10651 10652 static const ModeType 10653 PasteCommands[] = 10654 { 10655 PasteOperatorsCommand, 10656 PasteHelpCommand, 10657 PasteDismissCommand 10658 }; 10659 10660 static CompositeOperator 10661 compose = CopyCompositeOp; 10662 10663 char 10664 text[MagickPathExtent]; 10665 10666 Cursor 10667 cursor; 10668 10669 Image 10670 *paste_image; 10671 10672 int 10673 entry, 10674 id, 10675 x, 10676 y; 10677 10678 double 10679 scale_factor; 10680 10681 RectangleInfo 10682 highlight_info, 10683 paste_info; 10684 10685 unsigned int 10686 height, 10687 width; 10688 10689 size_t 10690 state; 10691 10692 XEvent 10693 event; 10694 10695 /* 10696 Copy image. 10697 */ 10698 if (resource_info->copy_image == (Image *) NULL) 10699 return(MagickFalse); 10700 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10701 /* 10702 Map Command widget. 10703 */ 10704 (void) CloneString(&windows->command.name,"Paste"); 10705 windows->command.data=1; 10706 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10707 (void) XMapRaised(display,windows->command.id); 10708 XClientMessage(display,windows->image.id,windows->im_protocols, 10709 windows->im_update_widget,CurrentTime); 10710 /* 10711 Track pointer until button 1 is pressed. 10712 */ 10713 XSetCursorState(display,windows,MagickFalse); 10714 XQueryPosition(display,windows->image.id,&x,&y); 10715 (void) XSelectInput(display,windows->image.id, 10716 windows->image.attributes.event_mask | PointerMotionMask); 10717 paste_info.x=(ssize_t) windows->image.x+x; 10718 paste_info.y=(ssize_t) windows->image.y+y; 10719 paste_info.width=0; 10720 paste_info.height=0; 10721 cursor=XCreateFontCursor(display,XC_ul_angle); 10722 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10723 state=DefaultState; 10724 do 10725 { 10726 if (windows->info.mapped != MagickFalse ) 10727 { 10728 /* 10729 Display pointer position. 10730 */ 10731 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 10732 (long) paste_info.x,(long) paste_info.y); 10733 XInfoWidget(display,windows,text); 10734 } 10735 highlight_info=paste_info; 10736 highlight_info.x=paste_info.x-windows->image.x; 10737 highlight_info.y=paste_info.y-windows->image.y; 10738 XHighlightRectangle(display,windows->image.id, 10739 windows->image.highlight_context,&highlight_info); 10740 /* 10741 Wait for next event. 10742 */ 10743 XScreenEvent(display,windows,&event,exception); 10744 XHighlightRectangle(display,windows->image.id, 10745 windows->image.highlight_context,&highlight_info); 10746 if (event.xany.window == windows->command.id) 10747 { 10748 /* 10749 Select a command from the Command widget. 10750 */ 10751 id=XCommandWidget(display,windows,PasteMenu,&event); 10752 if (id < 0) 10753 continue; 10754 switch (PasteCommands[id]) 10755 { 10756 case PasteOperatorsCommand: 10757 { 10758 char 10759 command[MagickPathExtent], 10760 **operators; 10761 10762 /* 10763 Select a command from the pop-up menu. 10764 */ 10765 operators=GetCommandOptions(MagickComposeOptions); 10766 if (operators == (char **) NULL) 10767 break; 10768 entry=XMenuWidget(display,windows,PasteMenu[id], 10769 (const char **) operators,command); 10770 if (entry >= 0) 10771 compose=(CompositeOperator) ParseCommandOption( 10772 MagickComposeOptions,MagickFalse,operators[entry]); 10773 operators=DestroyStringList(operators); 10774 break; 10775 } 10776 case PasteHelpCommand: 10777 { 10778 XTextViewWidget(display,resource_info,windows,MagickFalse, 10779 "Help Viewer - Image Composite",ImagePasteHelp); 10780 break; 10781 } 10782 case PasteDismissCommand: 10783 { 10784 /* 10785 Prematurely exit. 10786 */ 10787 state|=EscapeState; 10788 state|=ExitState; 10789 break; 10790 } 10791 default: 10792 break; 10793 } 10794 continue; 10795 } 10796 switch (event.type) 10797 { 10798 case ButtonPress: 10799 { 10800 if (image->debug != MagickFalse ) 10801 (void) LogMagickEvent(X11Event,GetMagickModule(), 10802 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10803 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10804 if (event.xbutton.button != Button1) 10805 break; 10806 if (event.xbutton.window != windows->image.id) 10807 break; 10808 /* 10809 Paste rectangle is relative to image configuration. 10810 */ 10811 width=(unsigned int) image->columns; 10812 height=(unsigned int) image->rows; 10813 x=0; 10814 y=0; 10815 if (windows->image.crop_geometry != (char *) NULL) 10816 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10817 &width,&height); 10818 scale_factor=(double) windows->image.ximage->width/width; 10819 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10820 scale_factor=(double) windows->image.ximage->height/height; 10821 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10822 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10823 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10824 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10825 break; 10826 } 10827 case ButtonRelease: 10828 { 10829 if (image->debug != MagickFalse ) 10830 (void) LogMagickEvent(X11Event,GetMagickModule(), 10831 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10832 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10833 if (event.xbutton.button != Button1) 10834 break; 10835 if (event.xbutton.window != windows->image.id) 10836 break; 10837 if ((paste_info.width != 0) && (paste_info.height != 0)) 10838 { 10839 /* 10840 User has selected the location of the paste image. 10841 */ 10842 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10843 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10844 state|=ExitState; 10845 } 10846 break; 10847 } 10848 case Expose: 10849 break; 10850 case KeyPress: 10851 { 10852 char 10853 command[MagickPathExtent]; 10854 10855 KeySym 10856 key_symbol; 10857 10858 int 10859 length; 10860 10861 if (event.xkey.window != windows->image.id) 10862 break; 10863 /* 10864 Respond to a user key press. 10865 */ 10866 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10867 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10868 *(command+length)='\0'; 10869 if (image->debug != MagickFalse ) 10870 (void) LogMagickEvent(X11Event,GetMagickModule(), 10871 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10872 switch ((int) key_symbol) 10873 { 10874 case XK_Escape: 10875 case XK_F20: 10876 { 10877 /* 10878 Prematurely exit. 10879 */ 10880 paste_image=DestroyImage(paste_image); 10881 state|=EscapeState; 10882 state|=ExitState; 10883 break; 10884 } 10885 case XK_F1: 10886 case XK_Help: 10887 { 10888 (void) XSetFunction(display,windows->image.highlight_context, 10889 GXcopy); 10890 XTextViewWidget(display,resource_info,windows,MagickFalse, 10891 "Help Viewer - Image Composite",ImagePasteHelp); 10892 (void) XSetFunction(display,windows->image.highlight_context, 10893 GXinvert); 10894 break; 10895 } 10896 default: 10897 { 10898 (void) XBell(display,0); 10899 break; 10900 } 10901 } 10902 break; 10903 } 10904 case MotionNotify: 10905 { 10906 /* 10907 Map and unmap Info widget as text cursor crosses its boundaries. 10908 */ 10909 x=event.xmotion.x; 10910 y=event.xmotion.y; 10911 if (windows->info.mapped != MagickFalse ) 10912 { 10913 if ((x < (int) (windows->info.x+windows->info.width)) && 10914 (y < (int) (windows->info.y+windows->info.height))) 10915 (void) XWithdrawWindow(display,windows->info.id, 10916 windows->info.screen); 10917 } 10918 else 10919 if ((x > (int) (windows->info.x+windows->info.width)) || 10920 (y > (int) (windows->info.y+windows->info.height))) 10921 (void) XMapWindow(display,windows->info.id); 10922 paste_info.x=(ssize_t) windows->image.x+x; 10923 paste_info.y=(ssize_t) windows->image.y+y; 10924 break; 10925 } 10926 default: 10927 { 10928 if (image->debug != MagickFalse ) 10929 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10930 event.type); 10931 break; 10932 } 10933 } 10934 } while ((state & ExitState) == 0); 10935 (void) XSelectInput(display,windows->image.id, 10936 windows->image.attributes.event_mask); 10937 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10938 XSetCursorState(display,windows,MagickFalse); 10939 (void) XFreeCursor(display,cursor); 10940 if ((state & EscapeState) != 0) 10941 return(MagickTrue); 10942 /* 10943 Image pasting is relative to image configuration. 10944 */ 10945 XSetCursorState(display,windows,MagickTrue); 10946 XCheckRefreshWindows(display,windows); 10947 width=(unsigned int) image->columns; 10948 height=(unsigned int) image->rows; 10949 x=0; 10950 y=0; 10951 if (windows->image.crop_geometry != (char *) NULL) 10952 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10953 scale_factor=(double) width/windows->image.ximage->width; 10954 paste_info.x+=x; 10955 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10956 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10957 scale_factor=(double) height/windows->image.ximage->height; 10958 paste_info.y+=y; 10959 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10960 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10961 /* 10962 Paste image with X Image window. 10963 */ 10964 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x, 10965 paste_info.y,exception); 10966 paste_image=DestroyImage(paste_image); 10967 XSetCursorState(display,windows,MagickFalse); 10968 /* 10969 Update image colormap. 10970 */ 10971 XConfigureImageColormap(display,resource_info,windows,image,exception); 10972 (void) XConfigureImage(display,resource_info,windows,image,exception); 10973 return(MagickTrue); 10974 } 10975 10976 /* 10978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10979 % % 10980 % % 10981 % % 10982 + X P r i n t I m a g e % 10983 % % 10984 % % 10985 % % 10986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10987 % 10988 % XPrintImage() prints an image to a Postscript printer. 10989 % 10990 % The format of the XPrintImage method is: 10991 % 10992 % MagickBooleanType XPrintImage(Display *display, 10993 % XResourceInfo *resource_info,XWindows *windows,Image *image, 10994 % ExceptionInfo *exception) 10995 % 10996 % A description of each parameter follows: 10997 % 10998 % o display: Specifies a connection to an X server; returned from 10999 % XOpenDisplay. 11000 % 11001 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11002 % 11003 % o windows: Specifies a pointer to a XWindows structure. 11004 % 11005 % o image: the image. 11006 % 11007 % o exception: return any errors or warnings in this structure. 11008 % 11009 */ 11010 static MagickBooleanType XPrintImage(Display *display, 11011 XResourceInfo *resource_info,XWindows *windows,Image *image, 11012 ExceptionInfo *exception) 11013 { 11014 char 11015 filename[MagickPathExtent], 11016 geometry[MagickPathExtent]; 11017 11018 Image 11019 *print_image; 11020 11021 ImageInfo 11022 *image_info; 11023 11024 MagickStatusType 11025 status; 11026 11027 /* 11028 Request Postscript page geometry from user. 11029 */ 11030 image_info=CloneImageInfo(resource_info->image_info); 11031 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter"); 11032 if (image_info->page != (char *) NULL) 11033 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent); 11034 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11035 "Select Postscript Page Geometry:",geometry); 11036 if (*geometry == '\0') 11037 return(MagickTrue); 11038 image_info->page=GetPageGeometry(geometry); 11039 /* 11040 Apply image transforms. 11041 */ 11042 XSetCursorState(display,windows,MagickTrue); 11043 XCheckRefreshWindows(display,windows); 11044 print_image=CloneImage(image,0,0,MagickTrue,exception); 11045 if (print_image == (Image *) NULL) 11046 return(MagickFalse); 11047 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!", 11048 windows->image.ximage->width,windows->image.ximage->height); 11049 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11050 exception); 11051 /* 11052 Print image. 11053 */ 11054 (void) AcquireUniqueFilename(filename); 11055 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s", 11056 filename); 11057 status=WriteImage(image_info,print_image,exception); 11058 (void) RelinquishUniqueFileResource(filename); 11059 print_image=DestroyImage(print_image); 11060 image_info=DestroyImageInfo(image_info); 11061 XSetCursorState(display,windows,MagickFalse); 11062 return(status != 0 ? MagickTrue : MagickFalse); 11063 } 11064 11065 /* 11067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11068 % % 11069 % % 11070 % % 11071 + X R O I I m a g e % 11072 % % 11073 % % 11074 % % 11075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11076 % 11077 % XROIImage() applies an image processing technique to a region of interest. 11078 % 11079 % The format of the XROIImage method is: 11080 % 11081 % MagickBooleanType XROIImage(Display *display, 11082 % XResourceInfo *resource_info,XWindows *windows,Image **image, 11083 % ExceptionInfo *exception) 11084 % 11085 % A description of each parameter follows: 11086 % 11087 % o display: Specifies a connection to an X server; returned from 11088 % XOpenDisplay. 11089 % 11090 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11091 % 11092 % o windows: Specifies a pointer to a XWindows structure. 11093 % 11094 % o image: the image; returned from ReadImage. 11095 % 11096 % o exception: return any errors or warnings in this structure. 11097 % 11098 */ 11099 static MagickBooleanType XROIImage(Display *display, 11100 XResourceInfo *resource_info,XWindows *windows,Image **image, 11101 ExceptionInfo *exception) 11102 { 11103 #define ApplyMenus 7 11104 11105 static const char 11106 *ROIMenu[] = 11107 { 11108 "Help", 11109 "Dismiss", 11110 (char *) NULL 11111 }, 11112 *ApplyMenu[] = 11113 { 11114 "File", 11115 "Edit", 11116 "Transform", 11117 "Enhance", 11118 "Effects", 11119 "F/X", 11120 "Miscellany", 11121 "Help", 11122 "Dismiss", 11123 (char *) NULL 11124 }, 11125 *FileMenu[] = 11126 { 11127 "Save...", 11128 "Print...", 11129 (char *) NULL 11130 }, 11131 *EditMenu[] = 11132 { 11133 "Undo", 11134 "Redo", 11135 (char *) NULL 11136 }, 11137 *TransformMenu[] = 11138 { 11139 "Flop", 11140 "Flip", 11141 "Rotate Right", 11142 "Rotate Left", 11143 (char *) NULL 11144 }, 11145 *EnhanceMenu[] = 11146 { 11147 "Hue...", 11148 "Saturation...", 11149 "Brightness...", 11150 "Gamma...", 11151 "Spiff", 11152 "Dull", 11153 "Contrast Stretch...", 11154 "Sigmoidal Contrast...", 11155 "Normalize", 11156 "Equalize", 11157 "Negate", 11158 "Grayscale", 11159 "Map...", 11160 "Quantize...", 11161 (char *) NULL 11162 }, 11163 *EffectsMenu[] = 11164 { 11165 "Despeckle", 11166 "Emboss", 11167 "Reduce Noise", 11168 "Add Noise", 11169 "Sharpen...", 11170 "Blur...", 11171 "Threshold...", 11172 "Edge Detect...", 11173 "Spread...", 11174 "Shade...", 11175 "Raise...", 11176 "Segment...", 11177 (char *) NULL 11178 }, 11179 *FXMenu[] = 11180 { 11181 "Solarize...", 11182 "Sepia Tone...", 11183 "Swirl...", 11184 "Implode...", 11185 "Vignette...", 11186 "Wave...", 11187 "Oil Paint...", 11188 "Charcoal Draw...", 11189 (char *) NULL 11190 }, 11191 *MiscellanyMenu[] = 11192 { 11193 "Image Info", 11194 "Zoom Image", 11195 "Show Preview...", 11196 "Show Histogram", 11197 "Show Matte", 11198 (char *) NULL 11199 }; 11200 11201 static const char 11202 **Menus[ApplyMenus] = 11203 { 11204 FileMenu, 11205 EditMenu, 11206 TransformMenu, 11207 EnhanceMenu, 11208 EffectsMenu, 11209 FXMenu, 11210 MiscellanyMenu 11211 }; 11212 11213 static const CommandType 11214 ApplyCommands[] = 11215 { 11216 NullCommand, 11217 NullCommand, 11218 NullCommand, 11219 NullCommand, 11220 NullCommand, 11221 NullCommand, 11222 NullCommand, 11223 HelpCommand, 11224 QuitCommand 11225 }, 11226 FileCommands[] = 11227 { 11228 SaveCommand, 11229 PrintCommand 11230 }, 11231 EditCommands[] = 11232 { 11233 UndoCommand, 11234 RedoCommand 11235 }, 11236 TransformCommands[] = 11237 { 11238 FlopCommand, 11239 FlipCommand, 11240 RotateRightCommand, 11241 RotateLeftCommand 11242 }, 11243 EnhanceCommands[] = 11244 { 11245 HueCommand, 11246 SaturationCommand, 11247 BrightnessCommand, 11248 GammaCommand, 11249 SpiffCommand, 11250 DullCommand, 11251 ContrastStretchCommand, 11252 SigmoidalContrastCommand, 11253 NormalizeCommand, 11254 EqualizeCommand, 11255 NegateCommand, 11256 GrayscaleCommand, 11257 MapCommand, 11258 QuantizeCommand 11259 }, 11260 EffectsCommands[] = 11261 { 11262 DespeckleCommand, 11263 EmbossCommand, 11264 ReduceNoiseCommand, 11265 AddNoiseCommand, 11266 SharpenCommand, 11267 BlurCommand, 11268 EdgeDetectCommand, 11269 SpreadCommand, 11270 ShadeCommand, 11271 RaiseCommand, 11272 SegmentCommand 11273 }, 11274 FXCommands[] = 11275 { 11276 SolarizeCommand, 11277 SepiaToneCommand, 11278 SwirlCommand, 11279 ImplodeCommand, 11280 VignetteCommand, 11281 WaveCommand, 11282 OilPaintCommand, 11283 CharcoalDrawCommand 11284 }, 11285 MiscellanyCommands[] = 11286 { 11287 InfoCommand, 11288 ZoomCommand, 11289 ShowPreviewCommand, 11290 ShowHistogramCommand, 11291 ShowMatteCommand 11292 }, 11293 ROICommands[] = 11294 { 11295 ROIHelpCommand, 11296 ROIDismissCommand 11297 }; 11298 11299 static const CommandType 11300 *Commands[ApplyMenus] = 11301 { 11302 FileCommands, 11303 EditCommands, 11304 TransformCommands, 11305 EnhanceCommands, 11306 EffectsCommands, 11307 FXCommands, 11308 MiscellanyCommands 11309 }; 11310 11311 char 11312 command[MagickPathExtent], 11313 text[MagickPathExtent]; 11314 11315 CommandType 11316 command_type; 11317 11318 Cursor 11319 cursor; 11320 11321 Image 11322 *roi_image; 11323 11324 int 11325 entry, 11326 id, 11327 x, 11328 y; 11329 11330 double 11331 scale_factor; 11332 11333 MagickProgressMonitor 11334 progress_monitor; 11335 11336 RectangleInfo 11337 crop_info, 11338 highlight_info, 11339 roi_info; 11340 11341 unsigned int 11342 height, 11343 width; 11344 11345 size_t 11346 state; 11347 11348 XEvent 11349 event; 11350 11351 /* 11352 Map Command widget. 11353 */ 11354 (void) CloneString(&windows->command.name,"ROI"); 11355 windows->command.data=0; 11356 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11357 (void) XMapRaised(display,windows->command.id); 11358 XClientMessage(display,windows->image.id,windows->im_protocols, 11359 windows->im_update_widget,CurrentTime); 11360 /* 11361 Track pointer until button 1 is pressed. 11362 */ 11363 XQueryPosition(display,windows->image.id,&x,&y); 11364 (void) XSelectInput(display,windows->image.id, 11365 windows->image.attributes.event_mask | PointerMotionMask); 11366 roi_info.x=(ssize_t) windows->image.x+x; 11367 roi_info.y=(ssize_t) windows->image.y+y; 11368 roi_info.width=0; 11369 roi_info.height=0; 11370 cursor=XCreateFontCursor(display,XC_fleur); 11371 state=DefaultState; 11372 do 11373 { 11374 if (windows->info.mapped != MagickFalse ) 11375 { 11376 /* 11377 Display pointer position. 11378 */ 11379 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 11380 (long) roi_info.x,(long) roi_info.y); 11381 XInfoWidget(display,windows,text); 11382 } 11383 /* 11384 Wait for next event. 11385 */ 11386 XScreenEvent(display,windows,&event,exception); 11387 if (event.xany.window == windows->command.id) 11388 { 11389 /* 11390 Select a command from the Command widget. 11391 */ 11392 id=XCommandWidget(display,windows,ROIMenu,&event); 11393 if (id < 0) 11394 continue; 11395 switch (ROICommands[id]) 11396 { 11397 case ROIHelpCommand: 11398 { 11399 XTextViewWidget(display,resource_info,windows,MagickFalse, 11400 "Help Viewer - Region of Interest",ImageROIHelp); 11401 break; 11402 } 11403 case ROIDismissCommand: 11404 { 11405 /* 11406 Prematurely exit. 11407 */ 11408 state|=EscapeState; 11409 state|=ExitState; 11410 break; 11411 } 11412 default: 11413 break; 11414 } 11415 continue; 11416 } 11417 switch (event.type) 11418 { 11419 case ButtonPress: 11420 { 11421 if (event.xbutton.button != Button1) 11422 break; 11423 if (event.xbutton.window != windows->image.id) 11424 break; 11425 /* 11426 Note first corner of region of interest rectangle-- exit loop. 11427 */ 11428 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11429 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11430 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11431 state|=ExitState; 11432 break; 11433 } 11434 case ButtonRelease: 11435 break; 11436 case Expose: 11437 break; 11438 case KeyPress: 11439 { 11440 KeySym 11441 key_symbol; 11442 11443 if (event.xkey.window != windows->image.id) 11444 break; 11445 /* 11446 Respond to a user key press. 11447 */ 11448 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11449 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11450 switch ((int) key_symbol) 11451 { 11452 case XK_Escape: 11453 case XK_F20: 11454 { 11455 /* 11456 Prematurely exit. 11457 */ 11458 state|=EscapeState; 11459 state|=ExitState; 11460 break; 11461 } 11462 case XK_F1: 11463 case XK_Help: 11464 { 11465 XTextViewWidget(display,resource_info,windows,MagickFalse, 11466 "Help Viewer - Region of Interest",ImageROIHelp); 11467 break; 11468 } 11469 default: 11470 { 11471 (void) XBell(display,0); 11472 break; 11473 } 11474 } 11475 break; 11476 } 11477 case MotionNotify: 11478 { 11479 /* 11480 Map and unmap Info widget as text cursor crosses its boundaries. 11481 */ 11482 x=event.xmotion.x; 11483 y=event.xmotion.y; 11484 if (windows->info.mapped != MagickFalse ) 11485 { 11486 if ((x < (int) (windows->info.x+windows->info.width)) && 11487 (y < (int) (windows->info.y+windows->info.height))) 11488 (void) XWithdrawWindow(display,windows->info.id, 11489 windows->info.screen); 11490 } 11491 else 11492 if ((x > (int) (windows->info.x+windows->info.width)) || 11493 (y > (int) (windows->info.y+windows->info.height))) 11494 (void) XMapWindow(display,windows->info.id); 11495 roi_info.x=(ssize_t) windows->image.x+x; 11496 roi_info.y=(ssize_t) windows->image.y+y; 11497 break; 11498 } 11499 default: 11500 break; 11501 } 11502 } while ((state & ExitState) == 0); 11503 (void) XSelectInput(display,windows->image.id, 11504 windows->image.attributes.event_mask); 11505 if ((state & EscapeState) != 0) 11506 { 11507 /* 11508 User want to exit without region of interest. 11509 */ 11510 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11511 (void) XFreeCursor(display,cursor); 11512 return(MagickTrue); 11513 } 11514 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11515 do 11516 { 11517 /* 11518 Size rectangle as pointer moves until the mouse button is released. 11519 */ 11520 x=(int) roi_info.x; 11521 y=(int) roi_info.y; 11522 roi_info.width=0; 11523 roi_info.height=0; 11524 state=DefaultState; 11525 do 11526 { 11527 highlight_info=roi_info; 11528 highlight_info.x=roi_info.x-windows->image.x; 11529 highlight_info.y=roi_info.y-windows->image.y; 11530 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11531 { 11532 /* 11533 Display info and draw region of interest rectangle. 11534 */ 11535 if (windows->info.mapped == MagickFalse) 11536 (void) XMapWindow(display,windows->info.id); 11537 (void) FormatLocaleString(text,MagickPathExtent, 11538 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11539 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11540 XInfoWidget(display,windows,text); 11541 XHighlightRectangle(display,windows->image.id, 11542 windows->image.highlight_context,&highlight_info); 11543 } 11544 else 11545 if (windows->info.mapped != MagickFalse ) 11546 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11547 /* 11548 Wait for next event. 11549 */ 11550 XScreenEvent(display,windows,&event,exception); 11551 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11552 XHighlightRectangle(display,windows->image.id, 11553 windows->image.highlight_context,&highlight_info); 11554 switch (event.type) 11555 { 11556 case ButtonPress: 11557 { 11558 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11559 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11560 break; 11561 } 11562 case ButtonRelease: 11563 { 11564 /* 11565 User has committed to region of interest rectangle. 11566 */ 11567 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11568 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11569 XSetCursorState(display,windows,MagickFalse); 11570 state|=ExitState; 11571 if (LocaleCompare(windows->command.name,"Apply") == 0) 11572 break; 11573 (void) CloneString(&windows->command.name,"Apply"); 11574 windows->command.data=ApplyMenus; 11575 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11576 break; 11577 } 11578 case Expose: 11579 break; 11580 case MotionNotify: 11581 { 11582 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11583 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11584 } 11585 default: 11586 break; 11587 } 11588 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11589 ((state & ExitState) != 0)) 11590 { 11591 /* 11592 Check boundary conditions. 11593 */ 11594 if (roi_info.x < 0) 11595 roi_info.x=0; 11596 else 11597 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11598 roi_info.x=(ssize_t) windows->image.ximage->width; 11599 if ((int) roi_info.x < x) 11600 roi_info.width=(unsigned int) (x-roi_info.x); 11601 else 11602 { 11603 roi_info.width=(unsigned int) (roi_info.x-x); 11604 roi_info.x=(ssize_t) x; 11605 } 11606 if (roi_info.y < 0) 11607 roi_info.y=0; 11608 else 11609 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11610 roi_info.y=(ssize_t) windows->image.ximage->height; 11611 if ((int) roi_info.y < y) 11612 roi_info.height=(unsigned int) (y-roi_info.y); 11613 else 11614 { 11615 roi_info.height=(unsigned int) (roi_info.y-y); 11616 roi_info.y=(ssize_t) y; 11617 } 11618 } 11619 } while ((state & ExitState) == 0); 11620 /* 11621 Wait for user to grab a corner of the rectangle or press return. 11622 */ 11623 state=DefaultState; 11624 command_type=NullCommand; 11625 crop_info.x=0; 11626 crop_info.y=0; 11627 (void) XMapWindow(display,windows->info.id); 11628 do 11629 { 11630 if (windows->info.mapped != MagickFalse ) 11631 { 11632 /* 11633 Display pointer position. 11634 */ 11635 (void) FormatLocaleString(text,MagickPathExtent, 11636 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11637 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11638 XInfoWidget(display,windows,text); 11639 } 11640 highlight_info=roi_info; 11641 highlight_info.x=roi_info.x-windows->image.x; 11642 highlight_info.y=roi_info.y-windows->image.y; 11643 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11644 { 11645 state|=EscapeState; 11646 state|=ExitState; 11647 break; 11648 } 11649 if ((state & UpdateRegionState) != 0) 11650 { 11651 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11652 switch (command_type) 11653 { 11654 case UndoCommand: 11655 case RedoCommand: 11656 { 11657 (void) XMagickCommand(display,resource_info,windows,command_type, 11658 image,exception); 11659 break; 11660 } 11661 default: 11662 { 11663 /* 11664 Region of interest is relative to image configuration. 11665 */ 11666 progress_monitor=SetImageProgressMonitor(*image, 11667 (MagickProgressMonitor) NULL,(*image)->client_data); 11668 crop_info=roi_info; 11669 width=(unsigned int) (*image)->columns; 11670 height=(unsigned int) (*image)->rows; 11671 x=0; 11672 y=0; 11673 if (windows->image.crop_geometry != (char *) NULL) 11674 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11675 &width,&height); 11676 scale_factor=(double) width/windows->image.ximage->width; 11677 crop_info.x+=x; 11678 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11679 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11680 scale_factor=(double) 11681 height/windows->image.ximage->height; 11682 crop_info.y+=y; 11683 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11684 crop_info.height=(unsigned int) 11685 (scale_factor*crop_info.height+0.5); 11686 roi_image=CropImage(*image,&crop_info,exception); 11687 (void) SetImageProgressMonitor(*image,progress_monitor, 11688 (*image)->client_data); 11689 if (roi_image == (Image *) NULL) 11690 continue; 11691 /* 11692 Apply image processing technique to the region of interest. 11693 */ 11694 windows->image.orphan=MagickTrue; 11695 (void) XMagickCommand(display,resource_info,windows,command_type, 11696 &roi_image,exception); 11697 progress_monitor=SetImageProgressMonitor(*image, 11698 (MagickProgressMonitor) NULL,(*image)->client_data); 11699 (void) XMagickCommand(display,resource_info,windows, 11700 SaveToUndoBufferCommand,image,exception); 11701 windows->image.orphan=MagickFalse; 11702 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11703 MagickTrue,crop_info.x,crop_info.y,exception); 11704 roi_image=DestroyImage(roi_image); 11705 (void) SetImageProgressMonitor(*image,progress_monitor, 11706 (*image)->client_data); 11707 break; 11708 } 11709 } 11710 if (command_type != InfoCommand) 11711 { 11712 XConfigureImageColormap(display,resource_info,windows,*image, 11713 exception); 11714 (void) XConfigureImage(display,resource_info,windows,*image, 11715 exception); 11716 } 11717 XCheckRefreshWindows(display,windows); 11718 XInfoWidget(display,windows,text); 11719 (void) XSetFunction(display,windows->image.highlight_context, 11720 GXinvert); 11721 state&=(~UpdateRegionState); 11722 } 11723 XHighlightRectangle(display,windows->image.id, 11724 windows->image.highlight_context,&highlight_info); 11725 XScreenEvent(display,windows,&event,exception); 11726 if (event.xany.window == windows->command.id) 11727 { 11728 /* 11729 Select a command from the Command widget. 11730 */ 11731 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11732 command_type=NullCommand; 11733 id=XCommandWidget(display,windows,ApplyMenu,&event); 11734 if (id >= 0) 11735 { 11736 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent); 11737 command_type=ApplyCommands[id]; 11738 if (id < ApplyMenus) 11739 { 11740 /* 11741 Select a command from a pop-up menu. 11742 */ 11743 entry=XMenuWidget(display,windows,ApplyMenu[id], 11744 (const char **) Menus[id],command); 11745 if (entry >= 0) 11746 { 11747 (void) CopyMagickString(command,Menus[id][entry], 11748 MagickPathExtent); 11749 command_type=Commands[id][entry]; 11750 } 11751 } 11752 } 11753 (void) XSetFunction(display,windows->image.highlight_context, 11754 GXinvert); 11755 XHighlightRectangle(display,windows->image.id, 11756 windows->image.highlight_context,&highlight_info); 11757 if (command_type == HelpCommand) 11758 { 11759 (void) XSetFunction(display,windows->image.highlight_context, 11760 GXcopy); 11761 XTextViewWidget(display,resource_info,windows,MagickFalse, 11762 "Help Viewer - Region of Interest",ImageROIHelp); 11763 (void) XSetFunction(display,windows->image.highlight_context, 11764 GXinvert); 11765 continue; 11766 } 11767 if (command_type == QuitCommand) 11768 { 11769 /* 11770 exit. 11771 */ 11772 state|=EscapeState; 11773 state|=ExitState; 11774 continue; 11775 } 11776 if (command_type != NullCommand) 11777 state|=UpdateRegionState; 11778 continue; 11779 } 11780 XHighlightRectangle(display,windows->image.id, 11781 windows->image.highlight_context,&highlight_info); 11782 switch (event.type) 11783 { 11784 case ButtonPress: 11785 { 11786 x=windows->image.x; 11787 y=windows->image.y; 11788 if (event.xbutton.button != Button1) 11789 break; 11790 if (event.xbutton.window != windows->image.id) 11791 break; 11792 x=windows->image.x+event.xbutton.x; 11793 y=windows->image.y+event.xbutton.y; 11794 if ((x < (int) (roi_info.x+RoiDelta)) && 11795 (x > (int) (roi_info.x-RoiDelta)) && 11796 (y < (int) (roi_info.y+RoiDelta)) && 11797 (y > (int) (roi_info.y-RoiDelta))) 11798 { 11799 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11800 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11801 state|=UpdateConfigurationState; 11802 break; 11803 } 11804 if ((x < (int) (roi_info.x+RoiDelta)) && 11805 (x > (int) (roi_info.x-RoiDelta)) && 11806 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11807 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11808 { 11809 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11810 state|=UpdateConfigurationState; 11811 break; 11812 } 11813 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11814 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11815 (y < (int) (roi_info.y+RoiDelta)) && 11816 (y > (int) (roi_info.y-RoiDelta))) 11817 { 11818 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11819 state|=UpdateConfigurationState; 11820 break; 11821 } 11822 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11823 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11824 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11825 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11826 { 11827 state|=UpdateConfigurationState; 11828 break; 11829 } 11830 } 11831 case ButtonRelease: 11832 { 11833 if (event.xbutton.window == windows->pan.id) 11834 if ((highlight_info.x != crop_info.x-windows->image.x) || 11835 (highlight_info.y != crop_info.y-windows->image.y)) 11836 XHighlightRectangle(display,windows->image.id, 11837 windows->image.highlight_context,&highlight_info); 11838 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11839 event.xbutton.time); 11840 break; 11841 } 11842 case Expose: 11843 { 11844 if (event.xexpose.window == windows->image.id) 11845 if (event.xexpose.count == 0) 11846 { 11847 event.xexpose.x=(int) highlight_info.x; 11848 event.xexpose.y=(int) highlight_info.y; 11849 event.xexpose.width=(int) highlight_info.width; 11850 event.xexpose.height=(int) highlight_info.height; 11851 XRefreshWindow(display,&windows->image,&event); 11852 } 11853 if (event.xexpose.window == windows->info.id) 11854 if (event.xexpose.count == 0) 11855 XInfoWidget(display,windows,text); 11856 break; 11857 } 11858 case KeyPress: 11859 { 11860 KeySym 11861 key_symbol; 11862 11863 if (event.xkey.window != windows->image.id) 11864 break; 11865 /* 11866 Respond to a user key press. 11867 */ 11868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11870 switch ((int) key_symbol) 11871 { 11872 case XK_Shift_L: 11873 case XK_Shift_R: 11874 break; 11875 case XK_Escape: 11876 case XK_F20: 11877 state|=EscapeState; 11878 case XK_Return: 11879 { 11880 state|=ExitState; 11881 break; 11882 } 11883 case XK_Home: 11884 case XK_KP_Home: 11885 { 11886 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11887 roi_info.y=(ssize_t) (windows->image.height/2L- 11888 roi_info.height/2L); 11889 break; 11890 } 11891 case XK_Left: 11892 case XK_KP_Left: 11893 { 11894 roi_info.x--; 11895 break; 11896 } 11897 case XK_Up: 11898 case XK_KP_Up: 11899 case XK_Next: 11900 { 11901 roi_info.y--; 11902 break; 11903 } 11904 case XK_Right: 11905 case XK_KP_Right: 11906 { 11907 roi_info.x++; 11908 break; 11909 } 11910 case XK_Prior: 11911 case XK_Down: 11912 case XK_KP_Down: 11913 { 11914 roi_info.y++; 11915 break; 11916 } 11917 case XK_F1: 11918 case XK_Help: 11919 { 11920 (void) XSetFunction(display,windows->image.highlight_context, 11921 GXcopy); 11922 XTextViewWidget(display,resource_info,windows,MagickFalse, 11923 "Help Viewer - Region of Interest",ImageROIHelp); 11924 (void) XSetFunction(display,windows->image.highlight_context, 11925 GXinvert); 11926 break; 11927 } 11928 default: 11929 { 11930 command_type=XImageWindowCommand(display,resource_info,windows, 11931 event.xkey.state,key_symbol,image,exception); 11932 if (command_type != NullCommand) 11933 state|=UpdateRegionState; 11934 break; 11935 } 11936 } 11937 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11938 event.xkey.time); 11939 break; 11940 } 11941 case KeyRelease: 11942 break; 11943 case MotionNotify: 11944 { 11945 if (event.xbutton.window != windows->image.id) 11946 break; 11947 /* 11948 Map and unmap Info widget as text cursor crosses its boundaries. 11949 */ 11950 x=event.xmotion.x; 11951 y=event.xmotion.y; 11952 if (windows->info.mapped != MagickFalse ) 11953 { 11954 if ((x < (int) (windows->info.x+windows->info.width)) && 11955 (y < (int) (windows->info.y+windows->info.height))) 11956 (void) XWithdrawWindow(display,windows->info.id, 11957 windows->info.screen); 11958 } 11959 else 11960 if ((x > (int) (windows->info.x+windows->info.width)) || 11961 (y > (int) (windows->info.y+windows->info.height))) 11962 (void) XMapWindow(display,windows->info.id); 11963 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11964 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11965 break; 11966 } 11967 case SelectionRequest: 11968 { 11969 XSelectionEvent 11970 notify; 11971 11972 XSelectionRequestEvent 11973 *request; 11974 11975 /* 11976 Set primary selection. 11977 */ 11978 (void) FormatLocaleString(text,MagickPathExtent, 11979 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11980 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11981 request=(&(event.xselectionrequest)); 11982 (void) XChangeProperty(request->display,request->requestor, 11983 request->property,request->target,8,PropModeReplace, 11984 (unsigned char *) text,(int) strlen(text)); 11985 notify.type=SelectionNotify; 11986 notify.display=request->display; 11987 notify.requestor=request->requestor; 11988 notify.selection=request->selection; 11989 notify.target=request->target; 11990 notify.time=request->time; 11991 if (request->property == None) 11992 notify.property=request->target; 11993 else 11994 notify.property=request->property; 11995 (void) XSendEvent(request->display,request->requestor,False,0, 11996 (XEvent *) ¬ify); 11997 } 11998 default: 11999 break; 12000 } 12001 if ((state & UpdateConfigurationState) != 0) 12002 { 12003 (void) XPutBackEvent(display,&event); 12004 (void) XCheckDefineCursor(display,windows->image.id,cursor); 12005 break; 12006 } 12007 } while ((state & ExitState) == 0); 12008 } while ((state & ExitState) == 0); 12009 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12010 XSetCursorState(display,windows,MagickFalse); 12011 if ((state & EscapeState) != 0) 12012 return(MagickTrue); 12013 return(MagickTrue); 12014 } 12015 12016 /* 12018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12019 % % 12020 % % 12021 % % 12022 + X R o t a t e I m a g e % 12023 % % 12024 % % 12025 % % 12026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12027 % 12028 % XRotateImage() rotates the X image. If the degrees parameter if zero, the 12029 % rotation angle is computed from the slope of a line drawn by the user. 12030 % 12031 % The format of the XRotateImage method is: 12032 % 12033 % MagickBooleanType XRotateImage(Display *display, 12034 % XResourceInfo *resource_info,XWindows *windows,double degrees, 12035 % Image **image,ExceptionInfo *exception) 12036 % 12037 % A description of each parameter follows: 12038 % 12039 % o display: Specifies a connection to an X server; returned from 12040 % XOpenDisplay. 12041 % 12042 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12043 % 12044 % o windows: Specifies a pointer to a XWindows structure. 12045 % 12046 % o degrees: Specifies the number of degrees to rotate the image. 12047 % 12048 % o image: the image. 12049 % 12050 % o exception: return any errors or warnings in this structure. 12051 % 12052 */ 12053 static MagickBooleanType XRotateImage(Display *display, 12054 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12055 ExceptionInfo *exception) 12056 { 12057 static const char 12058 *RotateMenu[] = 12059 { 12060 "Pixel Color", 12061 "Direction", 12062 "Help", 12063 "Dismiss", 12064 (char *) NULL 12065 }; 12066 12067 static ModeType 12068 direction = HorizontalRotateCommand; 12069 12070 static const ModeType 12071 DirectionCommands[] = 12072 { 12073 HorizontalRotateCommand, 12074 VerticalRotateCommand 12075 }, 12076 RotateCommands[] = 12077 { 12078 RotateColorCommand, 12079 RotateDirectionCommand, 12080 RotateHelpCommand, 12081 RotateDismissCommand 12082 }; 12083 12084 static unsigned int 12085 pen_id = 0; 12086 12087 char 12088 command[MagickPathExtent], 12089 text[MagickPathExtent]; 12090 12091 Image 12092 *rotate_image; 12093 12094 int 12095 id, 12096 x, 12097 y; 12098 12099 double 12100 normalized_degrees; 12101 12102 register int 12103 i; 12104 12105 unsigned int 12106 height, 12107 rotations, 12108 width; 12109 12110 if (degrees == 0.0) 12111 { 12112 unsigned int 12113 distance; 12114 12115 size_t 12116 state; 12117 12118 XEvent 12119 event; 12120 12121 XSegment 12122 rotate_info; 12123 12124 /* 12125 Map Command widget. 12126 */ 12127 (void) CloneString(&windows->command.name,"Rotate"); 12128 windows->command.data=2; 12129 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12130 (void) XMapRaised(display,windows->command.id); 12131 XClientMessage(display,windows->image.id,windows->im_protocols, 12132 windows->im_update_widget,CurrentTime); 12133 /* 12134 Wait for first button press. 12135 */ 12136 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12137 XQueryPosition(display,windows->image.id,&x,&y); 12138 rotate_info.x1=x; 12139 rotate_info.y1=y; 12140 rotate_info.x2=x; 12141 rotate_info.y2=y; 12142 state=DefaultState; 12143 do 12144 { 12145 XHighlightLine(display,windows->image.id, 12146 windows->image.highlight_context,&rotate_info); 12147 /* 12148 Wait for next event. 12149 */ 12150 XScreenEvent(display,windows,&event,exception); 12151 XHighlightLine(display,windows->image.id, 12152 windows->image.highlight_context,&rotate_info); 12153 if (event.xany.window == windows->command.id) 12154 { 12155 /* 12156 Select a command from the Command widget. 12157 */ 12158 id=XCommandWidget(display,windows,RotateMenu,&event); 12159 if (id < 0) 12160 continue; 12161 (void) XSetFunction(display,windows->image.highlight_context, 12162 GXcopy); 12163 switch (RotateCommands[id]) 12164 { 12165 case RotateColorCommand: 12166 { 12167 const char 12168 *ColorMenu[MaxNumberPens]; 12169 12170 int 12171 pen_number; 12172 12173 XColor 12174 color; 12175 12176 /* 12177 Initialize menu selections. 12178 */ 12179 for (i=0; i < (int) (MaxNumberPens-2); i++) 12180 ColorMenu[i]=resource_info->pen_colors[i]; 12181 ColorMenu[MaxNumberPens-2]="Browser..."; 12182 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12183 /* 12184 Select a pen color from the pop-up menu. 12185 */ 12186 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12187 (const char **) ColorMenu,command); 12188 if (pen_number < 0) 12189 break; 12190 if (pen_number == (MaxNumberPens-2)) 12191 { 12192 static char 12193 color_name[MagickPathExtent] = "gray"; 12194 12195 /* 12196 Select a pen color from a dialog. 12197 */ 12198 resource_info->pen_colors[pen_number]=color_name; 12199 XColorBrowserWidget(display,windows,"Select",color_name); 12200 if (*color_name == '\0') 12201 break; 12202 } 12203 /* 12204 Set pen color. 12205 */ 12206 (void) XParseColor(display,windows->map_info->colormap, 12207 resource_info->pen_colors[pen_number],&color); 12208 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12209 (unsigned int) MaxColors,&color); 12210 windows->pixel_info->pen_colors[pen_number]=color; 12211 pen_id=(unsigned int) pen_number; 12212 break; 12213 } 12214 case RotateDirectionCommand: 12215 { 12216 static const char 12217 *Directions[] = 12218 { 12219 "horizontal", 12220 "vertical", 12221 (char *) NULL, 12222 }; 12223 12224 /* 12225 Select a command from the pop-up menu. 12226 */ 12227 id=XMenuWidget(display,windows,RotateMenu[id], 12228 Directions,command); 12229 if (id >= 0) 12230 direction=DirectionCommands[id]; 12231 break; 12232 } 12233 case RotateHelpCommand: 12234 { 12235 XTextViewWidget(display,resource_info,windows,MagickFalse, 12236 "Help Viewer - Image Rotation",ImageRotateHelp); 12237 break; 12238 } 12239 case RotateDismissCommand: 12240 { 12241 /* 12242 Prematurely exit. 12243 */ 12244 state|=EscapeState; 12245 state|=ExitState; 12246 break; 12247 } 12248 default: 12249 break; 12250 } 12251 (void) XSetFunction(display,windows->image.highlight_context, 12252 GXinvert); 12253 continue; 12254 } 12255 switch (event.type) 12256 { 12257 case ButtonPress: 12258 { 12259 if (event.xbutton.button != Button1) 12260 break; 12261 if (event.xbutton.window != windows->image.id) 12262 break; 12263 /* 12264 exit loop. 12265 */ 12266 (void) XSetFunction(display,windows->image.highlight_context, 12267 GXcopy); 12268 rotate_info.x1=event.xbutton.x; 12269 rotate_info.y1=event.xbutton.y; 12270 state|=ExitState; 12271 break; 12272 } 12273 case ButtonRelease: 12274 break; 12275 case Expose: 12276 break; 12277 case KeyPress: 12278 { 12279 char 12280 command[MagickPathExtent]; 12281 12282 KeySym 12283 key_symbol; 12284 12285 if (event.xkey.window != windows->image.id) 12286 break; 12287 /* 12288 Respond to a user key press. 12289 */ 12290 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12291 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12292 switch ((int) key_symbol) 12293 { 12294 case XK_Escape: 12295 case XK_F20: 12296 { 12297 /* 12298 Prematurely exit. 12299 */ 12300 state|=EscapeState; 12301 state|=ExitState; 12302 break; 12303 } 12304 case XK_F1: 12305 case XK_Help: 12306 { 12307 (void) XSetFunction(display,windows->image.highlight_context, 12308 GXcopy); 12309 XTextViewWidget(display,resource_info,windows,MagickFalse, 12310 "Help Viewer - Image Rotation",ImageRotateHelp); 12311 (void) XSetFunction(display,windows->image.highlight_context, 12312 GXinvert); 12313 break; 12314 } 12315 default: 12316 { 12317 (void) XBell(display,0); 12318 break; 12319 } 12320 } 12321 break; 12322 } 12323 case MotionNotify: 12324 { 12325 rotate_info.x1=event.xmotion.x; 12326 rotate_info.y1=event.xmotion.y; 12327 } 12328 } 12329 rotate_info.x2=rotate_info.x1; 12330 rotate_info.y2=rotate_info.y1; 12331 if (direction == HorizontalRotateCommand) 12332 rotate_info.x2+=32; 12333 else 12334 rotate_info.y2-=32; 12335 } while ((state & ExitState) == 0); 12336 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12337 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12338 if ((state & EscapeState) != 0) 12339 return(MagickTrue); 12340 /* 12341 Draw line as pointer moves until the mouse button is released. 12342 */ 12343 distance=0; 12344 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12345 state=DefaultState; 12346 do 12347 { 12348 if (distance > 9) 12349 { 12350 /* 12351 Display info and draw rotation line. 12352 */ 12353 if (windows->info.mapped == MagickFalse) 12354 (void) XMapWindow(display,windows->info.id); 12355 (void) FormatLocaleString(text,MagickPathExtent," %g", 12356 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12357 XInfoWidget(display,windows,text); 12358 XHighlightLine(display,windows->image.id, 12359 windows->image.highlight_context,&rotate_info); 12360 } 12361 else 12362 if (windows->info.mapped != MagickFalse ) 12363 (void) XWithdrawWindow(display,windows->info.id, 12364 windows->info.screen); 12365 /* 12366 Wait for next event. 12367 */ 12368 XScreenEvent(display,windows,&event,exception); 12369 if (distance > 9) 12370 XHighlightLine(display,windows->image.id, 12371 windows->image.highlight_context,&rotate_info); 12372 switch (event.type) 12373 { 12374 case ButtonPress: 12375 break; 12376 case ButtonRelease: 12377 { 12378 /* 12379 User has committed to rotation line. 12380 */ 12381 rotate_info.x2=event.xbutton.x; 12382 rotate_info.y2=event.xbutton.y; 12383 state|=ExitState; 12384 break; 12385 } 12386 case Expose: 12387 break; 12388 case MotionNotify: 12389 { 12390 rotate_info.x2=event.xmotion.x; 12391 rotate_info.y2=event.xmotion.y; 12392 } 12393 default: 12394 break; 12395 } 12396 /* 12397 Check boundary conditions. 12398 */ 12399 if (rotate_info.x2 < 0) 12400 rotate_info.x2=0; 12401 else 12402 if (rotate_info.x2 > (int) windows->image.width) 12403 rotate_info.x2=(short) windows->image.width; 12404 if (rotate_info.y2 < 0) 12405 rotate_info.y2=0; 12406 else 12407 if (rotate_info.y2 > (int) windows->image.height) 12408 rotate_info.y2=(short) windows->image.height; 12409 /* 12410 Compute rotation angle from the slope of the line. 12411 */ 12412 degrees=0.0; 12413 distance=(unsigned int) 12414 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12415 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12416 if (distance > 9) 12417 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12418 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12419 } while ((state & ExitState) == 0); 12420 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12421 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12422 if (distance <= 9) 12423 return(MagickTrue); 12424 } 12425 if (direction == VerticalRotateCommand) 12426 degrees-=90.0; 12427 if (degrees == 0.0) 12428 return(MagickTrue); 12429 /* 12430 Rotate image. 12431 */ 12432 normalized_degrees=degrees; 12433 while (normalized_degrees < -45.0) 12434 normalized_degrees+=360.0; 12435 for (rotations=0; normalized_degrees > 45.0; rotations++) 12436 normalized_degrees-=90.0; 12437 if (normalized_degrees != 0.0) 12438 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12439 exception); 12440 XSetCursorState(display,windows,MagickTrue); 12441 XCheckRefreshWindows(display,windows); 12442 (*image)->background_color.red=(double) ScaleShortToQuantum( 12443 windows->pixel_info->pen_colors[pen_id].red); 12444 (*image)->background_color.green=(double) ScaleShortToQuantum( 12445 windows->pixel_info->pen_colors[pen_id].green); 12446 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12447 windows->pixel_info->pen_colors[pen_id].blue); 12448 rotate_image=RotateImage(*image,degrees,exception); 12449 XSetCursorState(display,windows,MagickFalse); 12450 if (rotate_image == (Image *) NULL) 12451 return(MagickFalse); 12452 *image=DestroyImage(*image); 12453 *image=rotate_image; 12454 if (windows->image.crop_geometry != (char *) NULL) 12455 { 12456 /* 12457 Rotate crop geometry. 12458 */ 12459 width=(unsigned int) (*image)->columns; 12460 height=(unsigned int) (*image)->rows; 12461 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12462 switch (rotations % 4) 12463 { 12464 default: 12465 case 0: 12466 break; 12467 case 1: 12468 { 12469 /* 12470 Rotate 90 degrees. 12471 */ 12472 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12473 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12474 (int) height-y,x); 12475 break; 12476 } 12477 case 2: 12478 { 12479 /* 12480 Rotate 180 degrees. 12481 */ 12482 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12483 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12484 break; 12485 } 12486 case 3: 12487 { 12488 /* 12489 Rotate 270 degrees. 12490 */ 12491 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12492 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12493 break; 12494 } 12495 } 12496 } 12497 if (windows->image.orphan != MagickFalse ) 12498 return(MagickTrue); 12499 if (normalized_degrees != 0.0) 12500 { 12501 /* 12502 Update image colormap. 12503 */ 12504 windows->image.window_changes.width=(int) (*image)->columns; 12505 windows->image.window_changes.height=(int) (*image)->rows; 12506 if (windows->image.crop_geometry != (char *) NULL) 12507 { 12508 /* 12509 Obtain dimensions of image from crop geometry. 12510 */ 12511 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12512 &width,&height); 12513 windows->image.window_changes.width=(int) width; 12514 windows->image.window_changes.height=(int) height; 12515 } 12516 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12517 } 12518 else 12519 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12520 { 12521 windows->image.window_changes.width=windows->image.ximage->height; 12522 windows->image.window_changes.height=windows->image.ximage->width; 12523 } 12524 /* 12525 Update image configuration. 12526 */ 12527 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12528 return(MagickTrue); 12529 } 12530 12531 /* 12533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12534 % % 12535 % % 12536 % % 12537 + X S a v e I m a g e % 12538 % % 12539 % % 12540 % % 12541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12542 % 12543 % XSaveImage() saves an image to a file. 12544 % 12545 % The format of the XSaveImage method is: 12546 % 12547 % MagickBooleanType XSaveImage(Display *display, 12548 % XResourceInfo *resource_info,XWindows *windows,Image *image, 12549 % ExceptionInfo *exception) 12550 % 12551 % A description of each parameter follows: 12552 % 12553 % o display: Specifies a connection to an X server; returned from 12554 % XOpenDisplay. 12555 % 12556 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12557 % 12558 % o windows: Specifies a pointer to a XWindows structure. 12559 % 12560 % o image: the image. 12561 % 12562 % o exception: return any errors or warnings in this structure. 12563 % 12564 */ 12565 static MagickBooleanType XSaveImage(Display *display, 12566 XResourceInfo *resource_info,XWindows *windows,Image *image, 12567 ExceptionInfo *exception) 12568 { 12569 char 12570 filename[MagickPathExtent], 12571 geometry[MagickPathExtent]; 12572 12573 Image 12574 *save_image; 12575 12576 ImageInfo 12577 *image_info; 12578 12579 MagickStatusType 12580 status; 12581 12582 /* 12583 Request file name from user. 12584 */ 12585 if (resource_info->write_filename != (char *) NULL) 12586 (void) CopyMagickString(filename,resource_info->write_filename, 12587 MagickPathExtent); 12588 else 12589 { 12590 char 12591 path[MagickPathExtent]; 12592 12593 int 12594 status; 12595 12596 GetPathComponent(image->filename,HeadPath,path); 12597 GetPathComponent(image->filename,TailPath,filename); 12598 if (*path != '\0') 12599 { 12600 status=chdir(path); 12601 if (status == -1) 12602 (void) ThrowMagickException(exception,GetMagickModule(), 12603 FileOpenError,"UnableToOpenFile","%s",path); 12604 } 12605 } 12606 XFileBrowserWidget(display,windows,"Save",filename); 12607 if (*filename == '\0') 12608 return(MagickTrue); 12609 if (IsPathAccessible(filename) != MagickFalse ) 12610 { 12611 int 12612 status; 12613 12614 /* 12615 File exists-- seek user's permission before overwriting. 12616 */ 12617 status=XConfirmWidget(display,windows,"Overwrite",filename); 12618 if (status <= 0) 12619 return(MagickTrue); 12620 } 12621 image_info=CloneImageInfo(resource_info->image_info); 12622 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 12623 (void) SetImageInfo(image_info,1,exception); 12624 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12625 (LocaleCompare(image_info->magick,"JPG") == 0)) 12626 { 12627 char 12628 quality[MagickPathExtent]; 12629 12630 int 12631 status; 12632 12633 /* 12634 Request JPEG quality from user. 12635 */ 12636 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double) 12637 image->quality); 12638 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12639 quality); 12640 if (*quality == '\0') 12641 return(MagickTrue); 12642 image->quality=StringToUnsignedLong(quality); 12643 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12644 } 12645 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12646 (LocaleCompare(image_info->magick,"PDF") == 0) || 12647 (LocaleCompare(image_info->magick,"PS") == 0) || 12648 (LocaleCompare(image_info->magick,"PS2") == 0)) 12649 { 12650 char 12651 geometry[MagickPathExtent]; 12652 12653 /* 12654 Request page geometry from user. 12655 */ 12656 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); 12657 if (LocaleCompare(image_info->magick,"PDF") == 0) 12658 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); 12659 if (image_info->page != (char *) NULL) 12660 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent); 12661 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12662 "Select page geometry:",geometry); 12663 if (*geometry != '\0') 12664 image_info->page=GetPageGeometry(geometry); 12665 } 12666 /* 12667 Apply image transforms. 12668 */ 12669 XSetCursorState(display,windows,MagickTrue); 12670 XCheckRefreshWindows(display,windows); 12671 save_image=CloneImage(image,0,0,MagickTrue,exception); 12672 if (save_image == (Image *) NULL) 12673 return(MagickFalse); 12674 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!", 12675 windows->image.ximage->width,windows->image.ximage->height); 12676 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12677 exception); 12678 /* 12679 Write image. 12680 */ 12681 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent); 12682 status=WriteImage(image_info,save_image,exception); 12683 if (status != MagickFalse ) 12684 image->taint=MagickFalse; 12685 save_image=DestroyImage(save_image); 12686 image_info=DestroyImageInfo(image_info); 12687 XSetCursorState(display,windows,MagickFalse); 12688 return(status != 0 ? MagickTrue : MagickFalse); 12689 } 12690 12691 /* 12693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12694 % % 12695 % % 12696 % % 12697 + X S c r e e n E v e n t % 12698 % % 12699 % % 12700 % % 12701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12702 % 12703 % XScreenEvent() handles global events associated with the Pan and Magnify 12704 % windows. 12705 % 12706 % The format of the XScreenEvent function is: 12707 % 12708 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12709 % ExceptionInfo *exception) 12710 % 12711 % A description of each parameter follows: 12712 % 12713 % o display: Specifies a pointer to the Display structure; returned from 12714 % XOpenDisplay. 12715 % 12716 % o windows: Specifies a pointer to a XWindows structure. 12717 % 12718 % o event: Specifies a pointer to a X11 XEvent structure. 12719 % 12720 % o exception: return any errors or warnings in this structure. 12721 % 12722 */ 12723 12724 #if defined(__cplusplus) || defined(c_plusplus) 12725 extern "C" { 12726 #endif 12727 12728 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12729 { 12730 register XWindows 12731 *windows; 12732 12733 windows=(XWindows *) data; 12734 if ((event->type == ClientMessage) && 12735 (event->xclient.window == windows->image.id)) 12736 return(MagickFalse); 12737 return(MagickTrue); 12738 } 12739 12740 #if defined(__cplusplus) || defined(c_plusplus) 12741 } 12742 #endif 12743 12744 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12745 ExceptionInfo *exception) 12746 { 12747 register int 12748 x, 12749 y; 12750 12751 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12752 if (event->xany.window == windows->command.id) 12753 return; 12754 switch (event->type) 12755 { 12756 case ButtonPress: 12757 case ButtonRelease: 12758 { 12759 if ((event->xbutton.button == Button3) && 12760 (event->xbutton.state & Mod1Mask)) 12761 { 12762 /* 12763 Convert Alt-Button3 to Button2. 12764 */ 12765 event->xbutton.button=Button2; 12766 event->xbutton.state&=(~Mod1Mask); 12767 } 12768 if (event->xbutton.window == windows->backdrop.id) 12769 { 12770 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12771 event->xbutton.time); 12772 break; 12773 } 12774 if (event->xbutton.window == windows->pan.id) 12775 { 12776 XPanImage(display,windows,event,exception); 12777 break; 12778 } 12779 if (event->xbutton.window == windows->image.id) 12780 if (event->xbutton.button == Button2) 12781 { 12782 /* 12783 Update magnified image. 12784 */ 12785 x=event->xbutton.x; 12786 y=event->xbutton.y; 12787 if (x < 0) 12788 x=0; 12789 else 12790 if (x >= (int) windows->image.width) 12791 x=(int) (windows->image.width-1); 12792 windows->magnify.x=(int) windows->image.x+x; 12793 if (y < 0) 12794 y=0; 12795 else 12796 if (y >= (int) windows->image.height) 12797 y=(int) (windows->image.height-1); 12798 windows->magnify.y=windows->image.y+y; 12799 if (windows->magnify.mapped == MagickFalse) 12800 (void) XMapRaised(display,windows->magnify.id); 12801 XMakeMagnifyImage(display,windows,exception); 12802 if (event->type == ButtonRelease) 12803 (void) XWithdrawWindow(display,windows->info.id, 12804 windows->info.screen); 12805 break; 12806 } 12807 break; 12808 } 12809 case ClientMessage: 12810 { 12811 /* 12812 If client window delete message, exit. 12813 */ 12814 if (event->xclient.message_type != windows->wm_protocols) 12815 break; 12816 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12817 break; 12818 if (event->xclient.window == windows->magnify.id) 12819 { 12820 (void) XWithdrawWindow(display,windows->magnify.id, 12821 windows->magnify.screen); 12822 break; 12823 } 12824 break; 12825 } 12826 case ConfigureNotify: 12827 { 12828 if (event->xconfigure.window == windows->magnify.id) 12829 { 12830 unsigned int 12831 magnify; 12832 12833 /* 12834 Magnify window has a new configuration. 12835 */ 12836 windows->magnify.width=(unsigned int) event->xconfigure.width; 12837 windows->magnify.height=(unsigned int) event->xconfigure.height; 12838 if (windows->magnify.mapped == MagickFalse) 12839 break; 12840 magnify=1; 12841 while ((int) magnify <= event->xconfigure.width) 12842 magnify<<=1; 12843 while ((int) magnify <= event->xconfigure.height) 12844 magnify<<=1; 12845 magnify>>=1; 12846 if (((int) magnify != event->xconfigure.width) || 12847 ((int) magnify != event->xconfigure.height)) 12848 { 12849 XWindowChanges 12850 window_changes; 12851 12852 window_changes.width=(int) magnify; 12853 window_changes.height=(int) magnify; 12854 (void) XReconfigureWMWindow(display,windows->magnify.id, 12855 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12856 &window_changes); 12857 break; 12858 } 12859 XMakeMagnifyImage(display,windows,exception); 12860 break; 12861 } 12862 break; 12863 } 12864 case Expose: 12865 { 12866 if (event->xexpose.window == windows->image.id) 12867 { 12868 XRefreshWindow(display,&windows->image,event); 12869 break; 12870 } 12871 if (event->xexpose.window == windows->pan.id) 12872 if (event->xexpose.count == 0) 12873 { 12874 XDrawPanRectangle(display,windows); 12875 break; 12876 } 12877 if (event->xexpose.window == windows->magnify.id) 12878 if (event->xexpose.count == 0) 12879 { 12880 XMakeMagnifyImage(display,windows,exception); 12881 break; 12882 } 12883 break; 12884 } 12885 case KeyPress: 12886 { 12887 char 12888 command[MagickPathExtent]; 12889 12890 KeySym 12891 key_symbol; 12892 12893 if (event->xkey.window != windows->magnify.id) 12894 break; 12895 /* 12896 Respond to a user key press. 12897 */ 12898 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12899 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12900 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12901 exception); 12902 break; 12903 } 12904 case MapNotify: 12905 { 12906 if (event->xmap.window == windows->magnify.id) 12907 { 12908 windows->magnify.mapped=MagickTrue; 12909 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12910 break; 12911 } 12912 if (event->xmap.window == windows->info.id) 12913 { 12914 windows->info.mapped=MagickTrue; 12915 break; 12916 } 12917 break; 12918 } 12919 case MotionNotify: 12920 { 12921 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12922 if (event->xmotion.window == windows->image.id) 12923 if (windows->magnify.mapped != MagickFalse ) 12924 { 12925 /* 12926 Update magnified image. 12927 */ 12928 x=event->xmotion.x; 12929 y=event->xmotion.y; 12930 if (x < 0) 12931 x=0; 12932 else 12933 if (x >= (int) windows->image.width) 12934 x=(int) (windows->image.width-1); 12935 windows->magnify.x=(int) windows->image.x+x; 12936 if (y < 0) 12937 y=0; 12938 else 12939 if (y >= (int) windows->image.height) 12940 y=(int) (windows->image.height-1); 12941 windows->magnify.y=windows->image.y+y; 12942 XMakeMagnifyImage(display,windows,exception); 12943 } 12944 break; 12945 } 12946 case UnmapNotify: 12947 { 12948 if (event->xunmap.window == windows->magnify.id) 12949 { 12950 windows->magnify.mapped=MagickFalse; 12951 break; 12952 } 12953 if (event->xunmap.window == windows->info.id) 12954 { 12955 windows->info.mapped=MagickFalse; 12956 break; 12957 } 12958 break; 12959 } 12960 default: 12961 break; 12962 } 12963 } 12964 12965 /* 12967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12968 % % 12969 % % 12970 % % 12971 + X S e t C r o p G e o m e t r y % 12972 % % 12973 % % 12974 % % 12975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12976 % 12977 % XSetCropGeometry() accepts a cropping geometry relative to the Image window 12978 % and translates it to a cropping geometry relative to the image. 12979 % 12980 % The format of the XSetCropGeometry method is: 12981 % 12982 % void XSetCropGeometry(Display *display,XWindows *windows, 12983 % RectangleInfo *crop_info,Image *image) 12984 % 12985 % A description of each parameter follows: 12986 % 12987 % o display: Specifies a connection to an X server; returned from 12988 % XOpenDisplay. 12989 % 12990 % o windows: Specifies a pointer to a XWindows structure. 12991 % 12992 % o crop_info: A pointer to a RectangleInfo that defines a region of the 12993 % Image window to crop. 12994 % 12995 % o image: the image. 12996 % 12997 */ 12998 static void XSetCropGeometry(Display *display,XWindows *windows, 12999 RectangleInfo *crop_info,Image *image) 13000 { 13001 char 13002 text[MagickPathExtent]; 13003 13004 int 13005 x, 13006 y; 13007 13008 double 13009 scale_factor; 13010 13011 unsigned int 13012 height, 13013 width; 13014 13015 if (windows->info.mapped != MagickFalse ) 13016 { 13017 /* 13018 Display info on cropping rectangle. 13019 */ 13020 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g", 13021 (double) crop_info->width,(double) crop_info->height,(double) 13022 crop_info->x,(double) crop_info->y); 13023 XInfoWidget(display,windows,text); 13024 } 13025 /* 13026 Cropping geometry is relative to any previous crop geometry. 13027 */ 13028 x=0; 13029 y=0; 13030 width=(unsigned int) image->columns; 13031 height=(unsigned int) image->rows; 13032 if (windows->image.crop_geometry != (char *) NULL) 13033 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13034 else 13035 windows->image.crop_geometry=AcquireString((char *) NULL); 13036 /* 13037 Define the crop geometry string from the cropping rectangle. 13038 */ 13039 scale_factor=(double) width/windows->image.ximage->width; 13040 if (crop_info->x > 0) 13041 x+=(int) (scale_factor*crop_info->x+0.5); 13042 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13043 if (width == 0) 13044 width=1; 13045 scale_factor=(double) height/windows->image.ximage->height; 13046 if (crop_info->y > 0) 13047 y+=(int) (scale_factor*crop_info->y+0.5); 13048 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13049 if (height == 0) 13050 height=1; 13051 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 13052 "%ux%u%+d%+d",width,height,x,y); 13053 } 13054 13055 /* 13057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13058 % % 13059 % % 13060 % % 13061 + X T i l e I m a g e % 13062 % % 13063 % % 13064 % % 13065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13066 % 13067 % XTileImage() loads or deletes a selected tile from a visual image directory. 13068 % The load or delete command is chosen from a menu. 13069 % 13070 % The format of the XTileImage method is: 13071 % 13072 % Image *XTileImage(Display *display,XResourceInfo *resource_info, 13073 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13074 % 13075 % A description of each parameter follows: 13076 % 13077 % o tile_image: XTileImage reads or deletes the tile image 13078 % and returns it. A null image is returned if an error occurs. 13079 % 13080 % o display: Specifies a connection to an X server; returned from 13081 % XOpenDisplay. 13082 % 13083 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13084 % 13085 % o windows: Specifies a pointer to a XWindows structure. 13086 % 13087 % o image: the image; returned from ReadImage. 13088 % 13089 % o event: Specifies a pointer to a XEvent structure. If it is NULL, 13090 % the entire image is refreshed. 13091 % 13092 % o exception: return any errors or warnings in this structure. 13093 % 13094 */ 13095 static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13096 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13097 { 13098 static const char 13099 *VerbMenu[] = 13100 { 13101 "Load", 13102 "Next", 13103 "Former", 13104 "Delete", 13105 "Update", 13106 (char *) NULL, 13107 }; 13108 13109 static const ModeType 13110 TileCommands[] = 13111 { 13112 TileLoadCommand, 13113 TileNextCommand, 13114 TileFormerCommand, 13115 TileDeleteCommand, 13116 TileUpdateCommand 13117 }; 13118 13119 char 13120 command[MagickPathExtent], 13121 filename[MagickPathExtent]; 13122 13123 Image 13124 *tile_image; 13125 13126 int 13127 id, 13128 status, 13129 tile, 13130 x, 13131 y; 13132 13133 double 13134 scale_factor; 13135 13136 register char 13137 *p, 13138 *q; 13139 13140 register int 13141 i; 13142 13143 unsigned int 13144 height, 13145 width; 13146 13147 /* 13148 Tile image is relative to montage image configuration. 13149 */ 13150 x=0; 13151 y=0; 13152 width=(unsigned int) image->columns; 13153 height=(unsigned int) image->rows; 13154 if (windows->image.crop_geometry != (char *) NULL) 13155 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13156 scale_factor=(double) width/windows->image.ximage->width; 13157 event->xbutton.x+=windows->image.x; 13158 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13159 scale_factor=(double) height/windows->image.ximage->height; 13160 event->xbutton.y+=windows->image.y; 13161 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13162 /* 13163 Determine size and location of each tile in the visual image directory. 13164 */ 13165 width=(unsigned int) image->columns; 13166 height=(unsigned int) image->rows; 13167 x=0; 13168 y=0; 13169 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13170 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13171 (event->xbutton.x-x)/width; 13172 if (tile < 0) 13173 { 13174 /* 13175 Button press is outside any tile. 13176 */ 13177 (void) XBell(display,0); 13178 return((Image *) NULL); 13179 } 13180 /* 13181 Determine file name from the tile directory. 13182 */ 13183 p=image->directory; 13184 for (i=tile; (i != 0) && (*p != '\0'); ) 13185 { 13186 if (*p == '\n') 13187 i--; 13188 p++; 13189 } 13190 if (*p == '\0') 13191 { 13192 /* 13193 Button press is outside any tile. 13194 */ 13195 (void) XBell(display,0); 13196 return((Image *) NULL); 13197 } 13198 /* 13199 Select a command from the pop-up menu. 13200 */ 13201 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13202 if (id < 0) 13203 return((Image *) NULL); 13204 q=p; 13205 while ((*q != '\n') && (*q != '\0')) 13206 q++; 13207 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13208 /* 13209 Perform command for the selected tile. 13210 */ 13211 XSetCursorState(display,windows,MagickTrue); 13212 XCheckRefreshWindows(display,windows); 13213 tile_image=NewImageList(); 13214 switch (TileCommands[id]) 13215 { 13216 case TileLoadCommand: 13217 { 13218 /* 13219 Load tile image. 13220 */ 13221 XCheckRefreshWindows(display,windows); 13222 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13223 MagickPathExtent); 13224 (void) CopyMagickString(resource_info->image_info->filename,filename, 13225 MagickPathExtent); 13226 tile_image=ReadImage(resource_info->image_info,exception); 13227 CatchException(exception); 13228 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13229 break; 13230 } 13231 case TileNextCommand: 13232 { 13233 /* 13234 Display next image. 13235 */ 13236 XClientMessage(display,windows->image.id,windows->im_protocols, 13237 windows->im_next_image,CurrentTime); 13238 break; 13239 } 13240 case TileFormerCommand: 13241 { 13242 /* 13243 Display former image. 13244 */ 13245 XClientMessage(display,windows->image.id,windows->im_protocols, 13246 windows->im_former_image,CurrentTime); 13247 break; 13248 } 13249 case TileDeleteCommand: 13250 { 13251 /* 13252 Delete tile image. 13253 */ 13254 if (IsPathAccessible(filename) == MagickFalse) 13255 { 13256 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13257 break; 13258 } 13259 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13260 if (status <= 0) 13261 break; 13262 status=ShredFile(filename); 13263 if (status != MagickFalse ) 13264 { 13265 XNoticeWidget(display,windows,"Unable to delete image file:", 13266 filename); 13267 break; 13268 } 13269 } 13270 case TileUpdateCommand: 13271 { 13272 int 13273 x_offset, 13274 y_offset; 13275 13276 PixelInfo 13277 pixel; 13278 13279 register int 13280 j; 13281 13282 register Quantum 13283 *s; 13284 13285 /* 13286 Ensure all the images exist. 13287 */ 13288 tile=0; 13289 GetPixelInfo(image,&pixel); 13290 for (p=image->directory; *p != '\0'; p++) 13291 { 13292 CacheView 13293 *image_view; 13294 13295 q=p; 13296 while ((*q != '\n') && (*q != '\0')) 13297 q++; 13298 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13299 p=q; 13300 if (IsPathAccessible(filename) != MagickFalse ) 13301 { 13302 tile++; 13303 continue; 13304 } 13305 /* 13306 Overwrite tile with background color. 13307 */ 13308 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13309 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13310 image_view=AcquireAuthenticCacheView(image,exception); 13311 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13312 for (i=0; i < (int) height; i++) 13313 { 13314 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13315 y_offset+i,width,1,exception); 13316 if (s == (Quantum *) NULL) 13317 break; 13318 for (j=0; j < (int) width; j++) 13319 { 13320 SetPixelViaPixelInfo(image,&pixel,s); 13321 s+=GetPixelChannels(image); 13322 } 13323 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13324 break; 13325 } 13326 image_view=DestroyCacheView(image_view); 13327 tile++; 13328 } 13329 windows->image.window_changes.width=(int) image->columns; 13330 windows->image.window_changes.height=(int) image->rows; 13331 XConfigureImageColormap(display,resource_info,windows,image,exception); 13332 (void) XConfigureImage(display,resource_info,windows,image,exception); 13333 break; 13334 } 13335 default: 13336 break; 13337 } 13338 XSetCursorState(display,windows,MagickFalse); 13339 return(tile_image); 13340 } 13341 13342 /* 13344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13345 % % 13346 % % 13347 % % 13348 + X T r a n s l a t e I m a g e % 13349 % % 13350 % % 13351 % % 13352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13353 % 13354 % XTranslateImage() translates the image within an Image window by one pixel 13355 % as specified by the key symbol. If the image has a montage string the 13356 % translation is respect to the width and height contained within the string. 13357 % 13358 % The format of the XTranslateImage method is: 13359 % 13360 % void XTranslateImage(Display *display,XWindows *windows, 13361 % Image *image,const KeySym key_symbol) 13362 % 13363 % A description of each parameter follows: 13364 % 13365 % o display: Specifies a connection to an X server; returned from 13366 % XOpenDisplay. 13367 % 13368 % o windows: Specifies a pointer to a XWindows structure. 13369 % 13370 % o image: the image. 13371 % 13372 % o key_symbol: Specifies a KeySym which indicates which side of the image 13373 % to trim. 13374 % 13375 */ 13376 static void XTranslateImage(Display *display,XWindows *windows, 13377 Image *image,const KeySym key_symbol) 13378 { 13379 char 13380 text[MagickPathExtent]; 13381 13382 int 13383 x, 13384 y; 13385 13386 unsigned int 13387 x_offset, 13388 y_offset; 13389 13390 /* 13391 User specified a pan position offset. 13392 */ 13393 x_offset=windows->image.width; 13394 y_offset=windows->image.height; 13395 if (image->montage != (char *) NULL) 13396 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13397 switch ((int) key_symbol) 13398 { 13399 case XK_Home: 13400 case XK_KP_Home: 13401 { 13402 windows->image.x=(int) windows->image.width/2; 13403 windows->image.y=(int) windows->image.height/2; 13404 break; 13405 } 13406 case XK_Left: 13407 case XK_KP_Left: 13408 { 13409 windows->image.x-=x_offset; 13410 break; 13411 } 13412 case XK_Next: 13413 case XK_Up: 13414 case XK_KP_Up: 13415 { 13416 windows->image.y-=y_offset; 13417 break; 13418 } 13419 case XK_Right: 13420 case XK_KP_Right: 13421 { 13422 windows->image.x+=x_offset; 13423 break; 13424 } 13425 case XK_Prior: 13426 case XK_Down: 13427 case XK_KP_Down: 13428 { 13429 windows->image.y+=y_offset; 13430 break; 13431 } 13432 default: 13433 return; 13434 } 13435 /* 13436 Check boundary conditions. 13437 */ 13438 if (windows->image.x < 0) 13439 windows->image.x=0; 13440 else 13441 if ((int) (windows->image.x+windows->image.width) > 13442 windows->image.ximage->width) 13443 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13444 if (windows->image.y < 0) 13445 windows->image.y=0; 13446 else 13447 if ((int) (windows->image.y+windows->image.height) > 13448 windows->image.ximage->height) 13449 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13450 /* 13451 Refresh Image window. 13452 */ 13453 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ", 13454 windows->image.width,windows->image.height,windows->image.x, 13455 windows->image.y); 13456 XInfoWidget(display,windows,text); 13457 XCheckRefreshWindows(display,windows); 13458 XDrawPanRectangle(display,windows); 13459 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13460 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13461 } 13462 13463 /* 13465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13466 % % 13467 % % 13468 % % 13469 + X T r i m I m a g e % 13470 % % 13471 % % 13472 % % 13473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13474 % 13475 % XTrimImage() trims the edges from the Image window. 13476 % 13477 % The format of the XTrimImage method is: 13478 % 13479 % MagickBooleanType XTrimImage(Display *display, 13480 % XResourceInfo *resource_info,XWindows *windows,Image *image, 13481 % ExceptionInfo *exception) 13482 % 13483 % A description of each parameter follows: 13484 % 13485 % o display: Specifies a connection to an X server; returned from 13486 % XOpenDisplay. 13487 % 13488 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13489 % 13490 % o windows: Specifies a pointer to a XWindows structure. 13491 % 13492 % o image: the image. 13493 % 13494 % o exception: return any errors or warnings in this structure. 13495 % 13496 */ 13497 static MagickBooleanType XTrimImage(Display *display, 13498 XResourceInfo *resource_info,XWindows *windows,Image *image, 13499 ExceptionInfo *exception) 13500 { 13501 RectangleInfo 13502 trim_info; 13503 13504 register int 13505 x, 13506 y; 13507 13508 size_t 13509 background, 13510 pixel; 13511 13512 /* 13513 Trim edges from image. 13514 */ 13515 XSetCursorState(display,windows,MagickTrue); 13516 XCheckRefreshWindows(display,windows); 13517 /* 13518 Crop the left edge. 13519 */ 13520 background=XGetPixel(windows->image.ximage,0,0); 13521 trim_info.width=(size_t) windows->image.ximage->width; 13522 for (x=0; x < windows->image.ximage->width; x++) 13523 { 13524 for (y=0; y < windows->image.ximage->height; y++) 13525 { 13526 pixel=XGetPixel(windows->image.ximage,x,y); 13527 if (pixel != background) 13528 break; 13529 } 13530 if (y < windows->image.ximage->height) 13531 break; 13532 } 13533 trim_info.x=(ssize_t) x; 13534 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13535 { 13536 XSetCursorState(display,windows,MagickFalse); 13537 return(MagickFalse); 13538 } 13539 /* 13540 Crop the right edge. 13541 */ 13542 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13543 for (x=windows->image.ximage->width-1; x != 0; x--) 13544 { 13545 for (y=0; y < windows->image.ximage->height; y++) 13546 { 13547 pixel=XGetPixel(windows->image.ximage,x,y); 13548 if (pixel != background) 13549 break; 13550 } 13551 if (y < windows->image.ximage->height) 13552 break; 13553 } 13554 trim_info.width=(size_t) (x-trim_info.x+1); 13555 /* 13556 Crop the top edge. 13557 */ 13558 background=XGetPixel(windows->image.ximage,0,0); 13559 trim_info.height=(size_t) windows->image.ximage->height; 13560 for (y=0; y < windows->image.ximage->height; y++) 13561 { 13562 for (x=0; x < windows->image.ximage->width; x++) 13563 { 13564 pixel=XGetPixel(windows->image.ximage,x,y); 13565 if (pixel != background) 13566 break; 13567 } 13568 if (x < windows->image.ximage->width) 13569 break; 13570 } 13571 trim_info.y=(ssize_t) y; 13572 /* 13573 Crop the bottom edge. 13574 */ 13575 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13576 for (y=windows->image.ximage->height-1; y != 0; y--) 13577 { 13578 for (x=0; x < windows->image.ximage->width; x++) 13579 { 13580 pixel=XGetPixel(windows->image.ximage,x,y); 13581 if (pixel != background) 13582 break; 13583 } 13584 if (x < windows->image.ximage->width) 13585 break; 13586 } 13587 trim_info.height=(size_t) y-trim_info.y+1; 13588 if (((unsigned int) trim_info.width != windows->image.width) || 13589 ((unsigned int) trim_info.height != windows->image.height)) 13590 { 13591 /* 13592 Reconfigure Image window as defined by the trimming rectangle. 13593 */ 13594 XSetCropGeometry(display,windows,&trim_info,image); 13595 windows->image.window_changes.width=(int) trim_info.width; 13596 windows->image.window_changes.height=(int) trim_info.height; 13597 (void) XConfigureImage(display,resource_info,windows,image,exception); 13598 } 13599 XSetCursorState(display,windows,MagickFalse); 13600 return(MagickTrue); 13601 } 13602 13603 /* 13605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13606 % % 13607 % % 13608 % % 13609 + X V i s u a l D i r e c t o r y I m a g e % 13610 % % 13611 % % 13612 % % 13613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13614 % 13615 % XVisualDirectoryImage() creates a Visual Image Directory. 13616 % 13617 % The format of the XVisualDirectoryImage method is: 13618 % 13619 % Image *XVisualDirectoryImage(Display *display, 13620 % XResourceInfo *resource_info,XWindows *windows, 13621 % ExceptionInfo *exception) 13622 % 13623 % A description of each parameter follows: 13624 % 13625 % o display: Specifies a connection to an X server; returned from 13626 % XOpenDisplay. 13627 % 13628 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13629 % 13630 % o windows: Specifies a pointer to a XWindows structure. 13631 % 13632 % o exception: return any errors or warnings in this structure. 13633 % 13634 */ 13635 static Image *XVisualDirectoryImage(Display *display, 13636 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13637 { 13638 #define TileImageTag "Scale/Image" 13639 #define XClientName "montage" 13640 13641 char 13642 **filelist; 13643 13644 Image 13645 *images, 13646 *montage_image, 13647 *next_image, 13648 *thumbnail_image; 13649 13650 ImageInfo 13651 *read_info; 13652 13653 int 13654 number_files; 13655 13656 MagickBooleanType 13657 backdrop; 13658 13659 MagickStatusType 13660 status; 13661 13662 MontageInfo 13663 *montage_info; 13664 13665 RectangleInfo 13666 geometry; 13667 13668 register int 13669 i; 13670 13671 static char 13672 filename[MagickPathExtent] = "\0", 13673 filenames[MagickPathExtent] = "*"; 13674 13675 XResourceInfo 13676 background_resources; 13677 13678 /* 13679 Request file name from user. 13680 */ 13681 XFileBrowserWidget(display,windows,"Directory",filenames); 13682 if (*filenames == '\0') 13683 return((Image *) NULL); 13684 /* 13685 Expand the filenames. 13686 */ 13687 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13688 if (filelist == (char **) NULL) 13689 { 13690 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13691 filenames); 13692 return((Image *) NULL); 13693 } 13694 number_files=1; 13695 filelist[0]=filenames; 13696 status=ExpandFilenames(&number_files,&filelist); 13697 if ((status == MagickFalse) || (number_files == 0)) 13698 { 13699 if (number_files == 0) 13700 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames) 13701 else 13702 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13703 filenames); 13704 return((Image *) NULL); 13705 } 13706 /* 13707 Set image background resources. 13708 */ 13709 background_resources=(*resource_info); 13710 background_resources.window_id=AcquireString(""); 13711 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent, 13712 "0x%lx",windows->image.id); 13713 background_resources.backdrop=MagickTrue; 13714 /* 13715 Read each image and convert them to a tile. 13716 */ 13717 backdrop=((windows->visual_info->klass == TrueColor) || 13718 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse; 13719 read_info=CloneImageInfo(resource_info->image_info); 13720 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13721 (void) CloneString(&read_info->size,DefaultTileGeometry); 13722 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13723 (void *) NULL); 13724 images=NewImageList(); 13725 XSetCursorState(display,windows,MagickTrue); 13726 XCheckRefreshWindows(display,windows); 13727 for (i=0; i < (int) number_files; i++) 13728 { 13729 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent); 13730 filelist[i]=DestroyString(filelist[i]); 13731 *read_info->magick='\0'; 13732 next_image=ReadImage(read_info,exception); 13733 CatchException(exception); 13734 if (next_image != (Image *) NULL) 13735 { 13736 (void) DeleteImageProperty(next_image,"label"); 13737 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13738 read_info,next_image,DefaultTileLabel,exception),exception); 13739 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13740 exception); 13741 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13742 geometry.height,exception); 13743 if (thumbnail_image != (Image *) NULL) 13744 { 13745 next_image=DestroyImage(next_image); 13746 next_image=thumbnail_image; 13747 } 13748 if (backdrop) 13749 { 13750 (void) XDisplayBackgroundImage(display,&background_resources, 13751 next_image,exception); 13752 XSetCursorState(display,windows,MagickTrue); 13753 } 13754 AppendImageToList(&images,next_image); 13755 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13756 { 13757 MagickBooleanType 13758 proceed; 13759 13760 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13761 (MagickSizeType) number_files); 13762 if (proceed == MagickFalse) 13763 break; 13764 } 13765 } 13766 } 13767 filelist=(char **) RelinquishMagickMemory(filelist); 13768 if (images == (Image *) NULL) 13769 { 13770 read_info=DestroyImageInfo(read_info); 13771 XSetCursorState(display,windows,MagickFalse); 13772 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); 13773 return((Image *) NULL); 13774 } 13775 /* 13776 Create the Visual Image Directory. 13777 */ 13778 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13779 montage_info->pointsize=10; 13780 if (resource_info->font != (char *) NULL) 13781 (void) CloneString(&montage_info->font,resource_info->font); 13782 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent); 13783 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13784 images),exception); 13785 images=DestroyImageList(images); 13786 montage_info=DestroyMontageInfo(montage_info); 13787 read_info=DestroyImageInfo(read_info); 13788 XSetCursorState(display,windows,MagickFalse); 13789 if (montage_image == (Image *) NULL) 13790 return(montage_image); 13791 XClientMessage(display,windows->image.id,windows->im_protocols, 13792 windows->im_next_image,CurrentTime); 13793 return(montage_image); 13794 } 13795 13796 /* 13798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13799 % % 13800 % % 13801 % % 13802 % X D i s p l a y B a c k g r o u n d I m a g e % 13803 % % 13804 % % 13805 % % 13806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13807 % 13808 % XDisplayBackgroundImage() displays an image in the background of a window. 13809 % 13810 % The format of the XDisplayBackgroundImage method is: 13811 % 13812 % MagickBooleanType XDisplayBackgroundImage(Display *display, 13813 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13814 % 13815 % A description of each parameter follows: 13816 % 13817 % o display: Specifies a connection to an X server; returned from 13818 % XOpenDisplay. 13819 % 13820 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13821 % 13822 % o image: the image. 13823 % 13824 % o exception: return any errors or warnings in this structure. 13825 % 13826 */ 13827 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13828 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13829 { 13830 char 13831 geometry[MagickPathExtent], 13832 visual_type[MagickPathExtent]; 13833 13834 int 13835 height, 13836 status, 13837 width; 13838 13839 RectangleInfo 13840 geometry_info; 13841 13842 static XPixelInfo 13843 pixel; 13844 13845 static XStandardColormap 13846 *map_info; 13847 13848 static XVisualInfo 13849 *visual_info = (XVisualInfo *) NULL; 13850 13851 static XWindowInfo 13852 window_info; 13853 13854 size_t 13855 delay; 13856 13857 Window 13858 root_window; 13859 13860 XGCValues 13861 context_values; 13862 13863 XResourceInfo 13864 resources; 13865 13866 XWindowAttributes 13867 window_attributes; 13868 13869 /* 13870 Determine target window. 13871 */ 13872 assert(image != (Image *) NULL); 13873 assert(image->signature == MagickCoreSignature); 13874 if (image->debug != MagickFalse ) 13875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13876 resources=(*resource_info); 13877 window_info.id=(Window) NULL; 13878 root_window=XRootWindow(display,XDefaultScreen(display)); 13879 if (LocaleCompare(resources.window_id,"root") == 0) 13880 window_info.id=root_window; 13881 else 13882 { 13883 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0) 13884 window_info.id=XWindowByID(display,root_window, 13885 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13886 if (window_info.id == (Window) NULL) 13887 window_info.id=XWindowByName(display,root_window,resources.window_id); 13888 } 13889 if (window_info.id == (Window) NULL) 13890 { 13891 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists", 13892 resources.window_id); 13893 return(MagickFalse); 13894 } 13895 /* 13896 Determine window visual id. 13897 */ 13898 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13899 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13900 (void) CopyMagickString(visual_type,"default",MagickPathExtent); 13901 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13902 if (status != 0) 13903 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx", 13904 XVisualIDFromVisual(window_attributes.visual)); 13905 if (visual_info == (XVisualInfo *) NULL) 13906 { 13907 /* 13908 Allocate standard colormap. 13909 */ 13910 map_info=XAllocStandardColormap(); 13911 if (map_info == (XStandardColormap *) NULL) 13912 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13913 image->filename); 13914 map_info->colormap=(Colormap) NULL; 13915 pixel.pixels=(unsigned long *) NULL; 13916 /* 13917 Initialize visual info. 13918 */ 13919 resources.map_type=(char *) NULL; 13920 resources.visual_type=visual_type; 13921 visual_info=XBestVisualInfo(display,map_info,&resources); 13922 if (visual_info == (XVisualInfo *) NULL) 13923 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13924 resources.visual_type); 13925 /* 13926 Initialize window info. 13927 */ 13928 window_info.ximage=(XImage *) NULL; 13929 window_info.matte_image=(XImage *) NULL; 13930 window_info.pixmap=(Pixmap) NULL; 13931 window_info.matte_pixmap=(Pixmap) NULL; 13932 } 13933 /* 13934 Free previous root colors. 13935 */ 13936 if (window_info.id == root_window) 13937 (void) XDestroyWindowColors(display,root_window); 13938 /* 13939 Initialize Standard Colormap. 13940 */ 13941 resources.colormap=SharedColormap; 13942 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13943 exception); 13944 /* 13945 Graphic context superclass. 13946 */ 13947 context_values.background=pixel.background_color.pixel; 13948 context_values.foreground=pixel.foreground_color.pixel; 13949 pixel.annotate_context=XCreateGC(display,window_info.id, 13950 (size_t) (GCBackground | GCForeground),&context_values); 13951 if (pixel.annotate_context == (GC) NULL) 13952 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13953 image->filename); 13954 /* 13955 Initialize Image window attributes. 13956 */ 13957 window_info.name=AcquireString("\0"); 13958 window_info.icon_name=AcquireString("\0"); 13959 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13960 &resources,&window_info); 13961 /* 13962 Create the X image. 13963 */ 13964 window_info.width=(unsigned int) image->columns; 13965 window_info.height=(unsigned int) image->rows; 13966 if ((image->columns != window_info.width) || 13967 (image->rows != window_info.height)) 13968 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13969 image->filename); 13970 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>", 13971 window_attributes.width,window_attributes.height); 13972 geometry_info.width=window_info.width; 13973 geometry_info.height=window_info.height; 13974 geometry_info.x=(ssize_t) window_info.x; 13975 geometry_info.y=(ssize_t) window_info.y; 13976 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13977 &geometry_info.width,&geometry_info.height); 13978 window_info.width=(unsigned int) geometry_info.width; 13979 window_info.height=(unsigned int) geometry_info.height; 13980 window_info.x=(int) geometry_info.x; 13981 window_info.y=(int) geometry_info.y; 13982 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13983 window_info.height,exception); 13984 if (status == MagickFalse) 13985 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13986 image->filename); 13987 window_info.x=0; 13988 window_info.y=0; 13989 if (image->debug != MagickFalse ) 13990 { 13991 (void) LogMagickEvent(X11Event,GetMagickModule(), 13992 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13993 (double) image->columns,(double) image->rows); 13994 if (image->colors != 0) 13995 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13996 image->colors); 13997 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13998 } 13999 /* 14000 Adjust image dimensions as specified by backdrop or geometry options. 14001 */ 14002 width=(int) window_info.width; 14003 height=(int) window_info.height; 14004 if (resources.backdrop != MagickFalse ) 14005 { 14006 /* 14007 Center image on window. 14008 */ 14009 window_info.x=(window_attributes.width/2)- 14010 (window_info.ximage->width/2); 14011 window_info.y=(window_attributes.height/2)- 14012 (window_info.ximage->height/2); 14013 width=window_attributes.width; 14014 height=window_attributes.height; 14015 } 14016 if ((resources.image_geometry != (char *) NULL) && 14017 (*resources.image_geometry != '\0')) 14018 { 14019 char 14020 default_geometry[MagickPathExtent]; 14021 14022 int 14023 flags, 14024 gravity; 14025 14026 XSizeHints 14027 *size_hints; 14028 14029 /* 14030 User specified geometry. 14031 */ 14032 size_hints=XAllocSizeHints(); 14033 if (size_hints == (XSizeHints *) NULL) 14034 ThrowXWindowFatalException(ResourceLimitFatalError, 14035 "MemoryAllocationFailed",image->filename); 14036 size_hints->flags=0L; 14037 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d", 14038 width,height); 14039 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14040 default_geometry,window_info.border_width,size_hints,&window_info.x, 14041 &window_info.y,&width,&height,&gravity); 14042 if (flags & (XValue | YValue)) 14043 { 14044 width=window_attributes.width; 14045 height=window_attributes.height; 14046 } 14047 (void) XFree((void *) size_hints); 14048 } 14049 /* 14050 Create the X pixmap. 14051 */ 14052 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14053 (unsigned int) height,window_info.depth); 14054 if (window_info.pixmap == (Pixmap) NULL) 14055 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14056 image->filename); 14057 /* 14058 Display pixmap on the window. 14059 */ 14060 if (((unsigned int) width > window_info.width) || 14061 ((unsigned int) height > window_info.height)) 14062 (void) XFillRectangle(display,window_info.pixmap, 14063 window_info.annotate_context,0,0,(unsigned int) width, 14064 (unsigned int) height); 14065 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14066 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14067 window_info.width,(unsigned int) window_info.height); 14068 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14069 (void) XClearWindow(display,window_info.id); 14070 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14071 XDelay(display,delay == 0UL ? 10UL : delay); 14072 (void) XSync(display,MagickFalse); 14073 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14074 } 14075 14076 /* 14078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14079 % % 14080 % % 14081 % % 14082 + X D i s p l a y I m a g e % 14083 % % 14084 % % 14085 % % 14086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14087 % 14088 % XDisplayImage() displays an image via X11. A new image is created and 14089 % returned if the user interactively transforms the displayed image. 14090 % 14091 % The format of the XDisplayImage method is: 14092 % 14093 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14094 % char **argv,int argc,Image **image,size_t *state, 14095 % ExceptionInfo *exception) 14096 % 14097 % A description of each parameter follows: 14098 % 14099 % o nexus: Method XDisplayImage returns an image when the 14100 % user chooses 'Open Image' from the command menu or picks a tile 14101 % from the image directory. Otherwise a null image is returned. 14102 % 14103 % o display: Specifies a connection to an X server; returned from 14104 % XOpenDisplay. 14105 % 14106 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14107 % 14108 % o argv: Specifies the application's argument list. 14109 % 14110 % o argc: Specifies the number of arguments. 14111 % 14112 % o image: Specifies an address to an address of an Image structure; 14113 % 14114 % o exception: return any errors or warnings in this structure. 14115 % 14116 */ 14117 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14118 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14119 { 14120 #define MagnifySize 256 /* must be a power of 2 */ 14121 #define MagickMenus 10 14122 #define MagickTitle "Commands" 14123 14124 static const char 14125 *CommandMenu[] = 14126 { 14127 "File", 14128 "Edit", 14129 "View", 14130 "Transform", 14131 "Enhance", 14132 "Effects", 14133 "F/X", 14134 "Image Edit", 14135 "Miscellany", 14136 "Help", 14137 (char *) NULL 14138 }, 14139 *FileMenu[] = 14140 { 14141 "Open...", 14142 "Next", 14143 "Former", 14144 "Select...", 14145 "Save...", 14146 "Print...", 14147 "Delete...", 14148 "New...", 14149 "Visual Directory...", 14150 "Quit", 14151 (char *) NULL 14152 }, 14153 *EditMenu[] = 14154 { 14155 "Undo", 14156 "Redo", 14157 "Cut", 14158 "Copy", 14159 "Paste", 14160 (char *) NULL 14161 }, 14162 *ViewMenu[] = 14163 { 14164 "Half Size", 14165 "Original Size", 14166 "Double Size", 14167 "Resize...", 14168 "Apply", 14169 "Refresh", 14170 "Restore", 14171 (char *) NULL 14172 }, 14173 *TransformMenu[] = 14174 { 14175 "Crop", 14176 "Chop", 14177 "Flop", 14178 "Flip", 14179 "Rotate Right", 14180 "Rotate Left", 14181 "Rotate...", 14182 "Shear...", 14183 "Roll...", 14184 "Trim Edges", 14185 (char *) NULL 14186 }, 14187 *EnhanceMenu[] = 14188 { 14189 "Hue...", 14190 "Saturation...", 14191 "Brightness...", 14192 "Gamma...", 14193 "Spiff", 14194 "Dull", 14195 "Contrast Stretch...", 14196 "Sigmoidal Contrast...", 14197 "Normalize", 14198 "Equalize", 14199 "Negate", 14200 "Grayscale", 14201 "Map...", 14202 "Quantize...", 14203 (char *) NULL 14204 }, 14205 *EffectsMenu[] = 14206 { 14207 "Despeckle", 14208 "Emboss", 14209 "Reduce Noise", 14210 "Add Noise...", 14211 "Sharpen...", 14212 "Blur...", 14213 "Threshold...", 14214 "Edge Detect...", 14215 "Spread...", 14216 "Shade...", 14217 "Raise...", 14218 "Segment...", 14219 (char *) NULL 14220 }, 14221 *FXMenu[] = 14222 { 14223 "Solarize...", 14224 "Sepia Tone...", 14225 "Swirl...", 14226 "Implode...", 14227 "Vignette...", 14228 "Wave...", 14229 "Oil Paint...", 14230 "Charcoal Draw...", 14231 (char *) NULL 14232 }, 14233 *ImageEditMenu[] = 14234 { 14235 "Annotate...", 14236 "Draw...", 14237 "Color...", 14238 "Matte...", 14239 "Composite...", 14240 "Add Border...", 14241 "Add Frame...", 14242 "Comment...", 14243 "Launch...", 14244 "Region of Interest...", 14245 (char *) NULL 14246 }, 14247 *MiscellanyMenu[] = 14248 { 14249 "Image Info", 14250 "Zoom Image", 14251 "Show Preview...", 14252 "Show Histogram", 14253 "Show Matte", 14254 "Background...", 14255 "Slide Show...", 14256 "Preferences...", 14257 (char *) NULL 14258 }, 14259 *HelpMenu[] = 14260 { 14261 "Overview", 14262 "Browse Documentation", 14263 "About Display", 14264 (char *) NULL 14265 }, 14266 *ShortCutsMenu[] = 14267 { 14268 "Next", 14269 "Former", 14270 "Open...", 14271 "Save...", 14272 "Print...", 14273 "Undo", 14274 "Restore", 14275 "Image Info", 14276 "Quit", 14277 (char *) NULL 14278 }, 14279 *VirtualMenu[] = 14280 { 14281 "Image Info", 14282 "Print", 14283 "Next", 14284 "Quit", 14285 (char *) NULL 14286 }; 14287 14288 static const char 14289 **Menus[MagickMenus] = 14290 { 14291 FileMenu, 14292 EditMenu, 14293 ViewMenu, 14294 TransformMenu, 14295 EnhanceMenu, 14296 EffectsMenu, 14297 FXMenu, 14298 ImageEditMenu, 14299 MiscellanyMenu, 14300 HelpMenu 14301 }; 14302 14303 static CommandType 14304 CommandMenus[] = 14305 { 14306 NullCommand, 14307 NullCommand, 14308 NullCommand, 14309 NullCommand, 14310 NullCommand, 14311 NullCommand, 14312 NullCommand, 14313 NullCommand, 14314 NullCommand, 14315 NullCommand, 14316 }, 14317 FileCommands[] = 14318 { 14319 OpenCommand, 14320 NextCommand, 14321 FormerCommand, 14322 SelectCommand, 14323 SaveCommand, 14324 PrintCommand, 14325 DeleteCommand, 14326 NewCommand, 14327 VisualDirectoryCommand, 14328 QuitCommand 14329 }, 14330 EditCommands[] = 14331 { 14332 UndoCommand, 14333 RedoCommand, 14334 CutCommand, 14335 CopyCommand, 14336 PasteCommand 14337 }, 14338 ViewCommands[] = 14339 { 14340 HalfSizeCommand, 14341 OriginalSizeCommand, 14342 DoubleSizeCommand, 14343 ResizeCommand, 14344 ApplyCommand, 14345 RefreshCommand, 14346 RestoreCommand 14347 }, 14348 TransformCommands[] = 14349 { 14350 CropCommand, 14351 ChopCommand, 14352 FlopCommand, 14353 FlipCommand, 14354 RotateRightCommand, 14355 RotateLeftCommand, 14356 RotateCommand, 14357 ShearCommand, 14358 RollCommand, 14359 TrimCommand 14360 }, 14361 EnhanceCommands[] = 14362 { 14363 HueCommand, 14364 SaturationCommand, 14365 BrightnessCommand, 14366 GammaCommand, 14367 SpiffCommand, 14368 DullCommand, 14369 ContrastStretchCommand, 14370 SigmoidalContrastCommand, 14371 NormalizeCommand, 14372 EqualizeCommand, 14373 NegateCommand, 14374 GrayscaleCommand, 14375 MapCommand, 14376 QuantizeCommand 14377 }, 14378 EffectsCommands[] = 14379 { 14380 DespeckleCommand, 14381 EmbossCommand, 14382 ReduceNoiseCommand, 14383 AddNoiseCommand, 14384 SharpenCommand, 14385 BlurCommand, 14386 ThresholdCommand, 14387 EdgeDetectCommand, 14388 SpreadCommand, 14389 ShadeCommand, 14390 RaiseCommand, 14391 SegmentCommand 14392 }, 14393 FXCommands[] = 14394 { 14395 SolarizeCommand, 14396 SepiaToneCommand, 14397 SwirlCommand, 14398 ImplodeCommand, 14399 VignetteCommand, 14400 WaveCommand, 14401 OilPaintCommand, 14402 CharcoalDrawCommand 14403 }, 14404 ImageEditCommands[] = 14405 { 14406 AnnotateCommand, 14407 DrawCommand, 14408 ColorCommand, 14409 MatteCommand, 14410 CompositeCommand, 14411 AddBorderCommand, 14412 AddFrameCommand, 14413 CommentCommand, 14414 LaunchCommand, 14415 RegionofInterestCommand 14416 }, 14417 MiscellanyCommands[] = 14418 { 14419 InfoCommand, 14420 ZoomCommand, 14421 ShowPreviewCommand, 14422 ShowHistogramCommand, 14423 ShowMatteCommand, 14424 BackgroundCommand, 14425 SlideShowCommand, 14426 PreferencesCommand 14427 }, 14428 HelpCommands[] = 14429 { 14430 HelpCommand, 14431 BrowseDocumentationCommand, 14432 VersionCommand 14433 }, 14434 ShortCutsCommands[] = 14435 { 14436 NextCommand, 14437 FormerCommand, 14438 OpenCommand, 14439 SaveCommand, 14440 PrintCommand, 14441 UndoCommand, 14442 RestoreCommand, 14443 InfoCommand, 14444 QuitCommand 14445 }, 14446 VirtualCommands[] = 14447 { 14448 InfoCommand, 14449 PrintCommand, 14450 NextCommand, 14451 QuitCommand 14452 }; 14453 14454 static CommandType 14455 *Commands[MagickMenus] = 14456 { 14457 FileCommands, 14458 EditCommands, 14459 ViewCommands, 14460 TransformCommands, 14461 EnhanceCommands, 14462 EffectsCommands, 14463 FXCommands, 14464 ImageEditCommands, 14465 MiscellanyCommands, 14466 HelpCommands 14467 }; 14468 14469 char 14470 command[MagickPathExtent], 14471 *directory, 14472 geometry[MagickPathExtent], 14473 resource_name[MagickPathExtent]; 14474 14475 CommandType 14476 command_type; 14477 14478 Image 14479 *display_image, 14480 *nexus; 14481 14482 int 14483 entry, 14484 id; 14485 14486 KeySym 14487 key_symbol; 14488 14489 MagickStatusType 14490 context_mask, 14491 status; 14492 14493 RectangleInfo 14494 geometry_info; 14495 14496 register int 14497 i; 14498 14499 static char 14500 working_directory[MagickPathExtent]; 14501 14502 static XPoint 14503 vid_info; 14504 14505 static XWindowInfo 14506 *magick_windows[MaxXWindows]; 14507 14508 static unsigned int 14509 number_windows; 14510 14511 struct stat 14512 attributes; 14513 14514 time_t 14515 timer, 14516 timestamp, 14517 update_time; 14518 14519 unsigned int 14520 height, 14521 width; 14522 14523 size_t 14524 delay; 14525 14526 WarningHandler 14527 warning_handler; 14528 14529 Window 14530 root_window; 14531 14532 XClassHint 14533 *class_hints; 14534 14535 XEvent 14536 event; 14537 14538 XFontStruct 14539 *font_info; 14540 14541 XGCValues 14542 context_values; 14543 14544 XPixelInfo 14545 *icon_pixel, 14546 *pixel; 14547 14548 XResourceInfo 14549 *icon_resources; 14550 14551 XStandardColormap 14552 *icon_map, 14553 *map_info; 14554 14555 XVisualInfo 14556 *icon_visual, 14557 *visual_info; 14558 14559 XWindowChanges 14560 window_changes; 14561 14562 XWindows 14563 *windows; 14564 14565 XWMHints 14566 *manager_hints; 14567 14568 assert(image != (Image **) NULL); 14569 assert((*image)->signature == MagickCoreSignature); 14570 if ((*image)->debug != MagickFalse ) 14571 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14572 display_image=(*image); 14573 warning_handler=(WarningHandler) NULL; 14574 windows=XSetWindows((XWindows *) ~0); 14575 if (windows != (XWindows *) NULL) 14576 { 14577 int 14578 status; 14579 14580 if (*working_directory == '\0') 14581 (void) CopyMagickString(working_directory,".",MagickPathExtent); 14582 status=chdir(working_directory); 14583 if (status == -1) 14584 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14585 "UnableToOpenFile","%s",working_directory); 14586 warning_handler=resource_info->display_warnings ? 14587 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14588 warning_handler=resource_info->display_warnings ? 14589 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14590 } 14591 else 14592 { 14593 /* 14594 Allocate windows structure. 14595 */ 14596 resource_info->colors=display_image->colors; 14597 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14598 if (windows == (XWindows *) NULL) 14599 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14600 (*image)->filename); 14601 /* 14602 Initialize window id's. 14603 */ 14604 number_windows=0; 14605 magick_windows[number_windows++]=(&windows->icon); 14606 magick_windows[number_windows++]=(&windows->backdrop); 14607 magick_windows[number_windows++]=(&windows->image); 14608 magick_windows[number_windows++]=(&windows->info); 14609 magick_windows[number_windows++]=(&windows->command); 14610 magick_windows[number_windows++]=(&windows->widget); 14611 magick_windows[number_windows++]=(&windows->popup); 14612 magick_windows[number_windows++]=(&windows->magnify); 14613 magick_windows[number_windows++]=(&windows->pan); 14614 for (i=0; i < (int) number_windows; i++) 14615 magick_windows[i]->id=(Window) NULL; 14616 vid_info.x=0; 14617 vid_info.y=0; 14618 } 14619 /* 14620 Initialize font info. 14621 */ 14622 if (windows->font_info != (XFontStruct *) NULL) 14623 (void) XFreeFont(display,windows->font_info); 14624 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14625 if (windows->font_info == (XFontStruct *) NULL) 14626 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14627 resource_info->font); 14628 /* 14629 Initialize Standard Colormap. 14630 */ 14631 map_info=windows->map_info; 14632 icon_map=windows->icon_map; 14633 visual_info=windows->visual_info; 14634 icon_visual=windows->icon_visual; 14635 pixel=windows->pixel_info; 14636 icon_pixel=windows->icon_pixel; 14637 font_info=windows->font_info; 14638 icon_resources=windows->icon_resources; 14639 class_hints=windows->class_hints; 14640 manager_hints=windows->manager_hints; 14641 root_window=XRootWindow(display,visual_info->screen); 14642 nexus=NewImageList(); 14643 if (display_image->debug != MagickFalse ) 14644 { 14645 (void) LogMagickEvent(X11Event,GetMagickModule(), 14646 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14647 (double) display_image->scene,(double) display_image->columns, 14648 (double) display_image->rows); 14649 if (display_image->colors != 0) 14650 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14651 display_image->colors); 14652 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14653 display_image->magick); 14654 } 14655 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14656 map_info,pixel,exception); 14657 display_image->taint=MagickFalse; 14658 /* 14659 Initialize graphic context. 14660 */ 14661 windows->context.id=(Window) NULL; 14662 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14663 resource_info,&windows->context); 14664 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14665 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14666 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14667 manager_hints->flags=InputHint | StateHint; 14668 manager_hints->input=MagickFalse; 14669 manager_hints->initial_state=WithdrawnState; 14670 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14671 &windows->context); 14672 if (display_image->debug != MagickFalse ) 14673 (void) LogMagickEvent(X11Event,GetMagickModule(), 14674 "Window id: 0x%lx (context)",windows->context.id); 14675 context_values.background=pixel->background_color.pixel; 14676 context_values.font=font_info->fid; 14677 context_values.foreground=pixel->foreground_color.pixel; 14678 context_values.graphics_exposures=MagickFalse; 14679 context_mask=(MagickStatusType) 14680 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14681 if (pixel->annotate_context != (GC) NULL) 14682 (void) XFreeGC(display,pixel->annotate_context); 14683 pixel->annotate_context=XCreateGC(display,windows->context.id, 14684 context_mask,&context_values); 14685 if (pixel->annotate_context == (GC) NULL) 14686 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14687 display_image->filename); 14688 context_values.background=pixel->depth_color.pixel; 14689 if (pixel->widget_context != (GC) NULL) 14690 (void) XFreeGC(display,pixel->widget_context); 14691 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14692 &context_values); 14693 if (pixel->widget_context == (GC) NULL) 14694 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14695 display_image->filename); 14696 context_values.background=pixel->foreground_color.pixel; 14697 context_values.foreground=pixel->background_color.pixel; 14698 context_values.plane_mask=context_values.background ^ 14699 context_values.foreground; 14700 if (pixel->highlight_context != (GC) NULL) 14701 (void) XFreeGC(display,pixel->highlight_context); 14702 pixel->highlight_context=XCreateGC(display,windows->context.id, 14703 (size_t) (context_mask | GCPlaneMask),&context_values); 14704 if (pixel->highlight_context == (GC) NULL) 14705 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14706 display_image->filename); 14707 (void) XDestroyWindow(display,windows->context.id); 14708 /* 14709 Initialize icon window. 14710 */ 14711 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14712 icon_resources,&windows->icon); 14713 windows->icon.geometry=resource_info->icon_geometry; 14714 XBestIconSize(display,&windows->icon,display_image); 14715 windows->icon.attributes.colormap=XDefaultColormap(display, 14716 icon_visual->screen); 14717 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14718 manager_hints->flags=InputHint | StateHint; 14719 manager_hints->input=MagickFalse; 14720 manager_hints->initial_state=IconicState; 14721 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14722 &windows->icon); 14723 if (display_image->debug != MagickFalse ) 14724 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14725 windows->icon.id); 14726 /* 14727 Initialize graphic context for icon window. 14728 */ 14729 if (icon_pixel->annotate_context != (GC) NULL) 14730 (void) XFreeGC(display,icon_pixel->annotate_context); 14731 context_values.background=icon_pixel->background_color.pixel; 14732 context_values.foreground=icon_pixel->foreground_color.pixel; 14733 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14734 (size_t) (GCBackground | GCForeground),&context_values); 14735 if (icon_pixel->annotate_context == (GC) NULL) 14736 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14737 display_image->filename); 14738 windows->icon.annotate_context=icon_pixel->annotate_context; 14739 /* 14740 Initialize Image window. 14741 */ 14742 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14743 &windows->image); 14744 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14745 if (resource_info->use_shared_memory == MagickFalse) 14746 windows->image.shared_memory=MagickFalse; 14747 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14748 { 14749 char 14750 *title; 14751 14752 title=InterpretImageProperties(resource_info->image_info,display_image, 14753 resource_info->title,exception); 14754 (void) CopyMagickString(windows->image.name,title,MagickPathExtent); 14755 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent); 14756 title=DestroyString(title); 14757 } 14758 else 14759 { 14760 char 14761 filename[MagickPathExtent]; 14762 14763 /* 14764 Window name is the base of the filename. 14765 */ 14766 GetPathComponent(display_image->magick_filename,TailPath,filename); 14767 if (display_image->scene == 0) 14768 (void) FormatLocaleString(windows->image.name,MagickPathExtent, 14769 "%s: %s",MagickPackageName,filename); 14770 else 14771 (void) FormatLocaleString(windows->image.name,MagickPathExtent, 14772 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14773 (double) display_image->scene,(double) GetImageListLength( 14774 display_image)); 14775 (void) CopyMagickString(windows->image.icon_name,filename,MagickPathExtent); 14776 } 14777 if (resource_info->immutable) 14778 windows->image.immutable=MagickTrue; 14779 windows->image.use_pixmap=resource_info->use_pixmap; 14780 windows->image.geometry=resource_info->image_geometry; 14781 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!", 14782 XDisplayWidth(display,visual_info->screen), 14783 XDisplayHeight(display,visual_info->screen)); 14784 geometry_info.width=display_image->columns; 14785 geometry_info.height=display_image->rows; 14786 geometry_info.x=0; 14787 geometry_info.y=0; 14788 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14789 &geometry_info.width,&geometry_info.height); 14790 windows->image.width=(unsigned int) geometry_info.width; 14791 windows->image.height=(unsigned int) geometry_info.height; 14792 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14793 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14794 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14795 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14796 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14797 resource_info,&windows->backdrop); 14798 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14799 { 14800 /* 14801 Initialize backdrop window. 14802 */ 14803 windows->backdrop.x=0; 14804 windows->backdrop.y=0; 14805 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14806 windows->backdrop.flags=(size_t) (USSize | USPosition); 14807 windows->backdrop.width=(unsigned int) 14808 XDisplayWidth(display,visual_info->screen); 14809 windows->backdrop.height=(unsigned int) 14810 XDisplayHeight(display,visual_info->screen); 14811 windows->backdrop.border_width=0; 14812 windows->backdrop.immutable=MagickTrue; 14813 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14814 ButtonReleaseMask; 14815 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14816 StructureNotifyMask; 14817 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14818 manager_hints->icon_window=windows->icon.id; 14819 manager_hints->input=MagickTrue; 14820 manager_hints->initial_state=resource_info->iconic ? IconicState : 14821 NormalState; 14822 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14823 &windows->backdrop); 14824 if (display_image->debug != MagickFalse ) 14825 (void) LogMagickEvent(X11Event,GetMagickModule(), 14826 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14827 (void) XMapWindow(display,windows->backdrop.id); 14828 (void) XClearWindow(display,windows->backdrop.id); 14829 if (windows->image.id != (Window) NULL) 14830 { 14831 (void) XDestroyWindow(display,windows->image.id); 14832 windows->image.id=(Window) NULL; 14833 } 14834 /* 14835 Position image in the center the backdrop. 14836 */ 14837 windows->image.flags|=USPosition; 14838 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14839 (windows->image.width/2); 14840 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14841 (windows->image.height/2); 14842 } 14843 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14844 manager_hints->icon_window=windows->icon.id; 14845 manager_hints->input=MagickTrue; 14846 manager_hints->initial_state=resource_info->iconic ? IconicState : 14847 NormalState; 14848 if (windows->group_leader.id != (Window) NULL) 14849 { 14850 /* 14851 Follow the leader. 14852 */ 14853 manager_hints->flags|=WindowGroupHint; 14854 manager_hints->window_group=windows->group_leader.id; 14855 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14856 if (display_image->debug != MagickFalse ) 14857 (void) LogMagickEvent(X11Event,GetMagickModule(), 14858 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14859 } 14860 XMakeWindow(display, 14861 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14862 argv,argc,class_hints,manager_hints,&windows->image); 14863 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14864 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14865 if (windows->group_leader.id != (Window) NULL) 14866 (void) XSetTransientForHint(display,windows->image.id, 14867 windows->group_leader.id); 14868 if (display_image->debug != MagickFalse ) 14869 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14870 windows->image.id); 14871 /* 14872 Initialize Info widget. 14873 */ 14874 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14875 &windows->info); 14876 (void) CloneString(&windows->info.name,"Info"); 14877 (void) CloneString(&windows->info.icon_name,"Info"); 14878 windows->info.border_width=1; 14879 windows->info.x=2; 14880 windows->info.y=2; 14881 windows->info.flags|=PPosition; 14882 windows->info.attributes.win_gravity=UnmapGravity; 14883 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14884 StructureNotifyMask; 14885 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14886 manager_hints->input=MagickFalse; 14887 manager_hints->initial_state=NormalState; 14888 manager_hints->window_group=windows->image.id; 14889 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14890 &windows->info); 14891 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14892 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14893 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14894 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14895 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14896 if (windows->image.mapped != MagickFalse ) 14897 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14898 if (display_image->debug != MagickFalse ) 14899 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14900 windows->info.id); 14901 /* 14902 Initialize Command widget. 14903 */ 14904 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14905 resource_info,&windows->command); 14906 windows->command.data=MagickMenus; 14907 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14908 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command", 14909 resource_info->client_name); 14910 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14911 resource_name,"geometry",(char *) NULL); 14912 (void) CloneString(&windows->command.name,MagickTitle); 14913 windows->command.border_width=0; 14914 windows->command.flags|=PPosition; 14915 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14916 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14917 OwnerGrabButtonMask | StructureNotifyMask; 14918 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14919 manager_hints->input=MagickTrue; 14920 manager_hints->initial_state=NormalState; 14921 manager_hints->window_group=windows->image.id; 14922 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14923 &windows->command); 14924 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14925 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14926 HighlightHeight); 14927 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14928 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14929 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14930 if (windows->command.mapped != MagickFalse ) 14931 (void) XMapRaised(display,windows->command.id); 14932 if (display_image->debug != MagickFalse ) 14933 (void) LogMagickEvent(X11Event,GetMagickModule(), 14934 "Window id: 0x%lx (command)",windows->command.id); 14935 /* 14936 Initialize Widget window. 14937 */ 14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14939 resource_info,&windows->widget); 14940 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget", 14941 resource_info->client_name); 14942 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14943 resource_name,"geometry",(char *) NULL); 14944 windows->widget.border_width=0; 14945 windows->widget.flags|=PPosition; 14946 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14947 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14948 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14949 StructureNotifyMask; 14950 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14951 manager_hints->input=MagickTrue; 14952 manager_hints->initial_state=NormalState; 14953 manager_hints->window_group=windows->image.id; 14954 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14955 &windows->widget); 14956 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14957 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14958 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14959 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14960 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14961 if (display_image->debug != MagickFalse ) 14962 (void) LogMagickEvent(X11Event,GetMagickModule(), 14963 "Window id: 0x%lx (widget)",windows->widget.id); 14964 /* 14965 Initialize popup window. 14966 */ 14967 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14968 resource_info,&windows->popup); 14969 windows->popup.border_width=0; 14970 windows->popup.flags|=PPosition; 14971 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14972 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14973 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14974 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14975 manager_hints->input=MagickTrue; 14976 manager_hints->initial_state=NormalState; 14977 manager_hints->window_group=windows->image.id; 14978 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14979 &windows->popup); 14980 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14981 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14982 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14983 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14984 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14985 if (display_image->debug != MagickFalse ) 14986 (void) LogMagickEvent(X11Event,GetMagickModule(), 14987 "Window id: 0x%lx (pop up)",windows->popup.id); 14988 /* 14989 Initialize Magnify window and cursor. 14990 */ 14991 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14992 resource_info,&windows->magnify); 14993 if (resource_info->use_shared_memory == MagickFalse) 14994 windows->magnify.shared_memory=MagickFalse; 14995 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify", 14996 resource_info->client_name); 14997 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14998 resource_name,"geometry",(char *) NULL); 14999 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,"Magnify %uX", 15000 resource_info->magnify); 15001 if (windows->magnify.cursor != (Cursor) NULL) 15002 (void) XFreeCursor(display,windows->magnify.cursor); 15003 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 15004 map_info->colormap,resource_info->background_color, 15005 resource_info->foreground_color); 15006 if (windows->magnify.cursor == (Cursor) NULL) 15007 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 15008 display_image->filename); 15009 windows->magnify.width=MagnifySize; 15010 windows->magnify.height=MagnifySize; 15011 windows->magnify.flags|=PPosition; 15012 windows->magnify.min_width=MagnifySize; 15013 windows->magnify.min_height=MagnifySize; 15014 windows->magnify.width_inc=MagnifySize; 15015 windows->magnify.height_inc=MagnifySize; 15016 windows->magnify.data=resource_info->magnify; 15017 windows->magnify.attributes.cursor=windows->magnify.cursor; 15018 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 15019 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 15020 StructureNotifyMask; 15021 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15022 manager_hints->input=MagickTrue; 15023 manager_hints->initial_state=NormalState; 15024 manager_hints->window_group=windows->image.id; 15025 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15026 &windows->magnify); 15027 if (display_image->debug != MagickFalse ) 15028 (void) LogMagickEvent(X11Event,GetMagickModule(), 15029 "Window id: 0x%lx (magnify)",windows->magnify.id); 15030 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 15031 /* 15032 Initialize panning window. 15033 */ 15034 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 15035 resource_info,&windows->pan); 15036 (void) CloneString(&windows->pan.name,"Pan Icon"); 15037 windows->pan.width=windows->icon.width; 15038 windows->pan.height=windows->icon.height; 15039 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan", 15040 resource_info->client_name); 15041 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15042 resource_name,"geometry",(char *) NULL); 15043 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15044 &windows->pan.width,&windows->pan.height); 15045 windows->pan.flags|=PPosition; 15046 windows->pan.immutable=MagickTrue; 15047 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15048 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15049 StructureNotifyMask; 15050 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15051 manager_hints->input=MagickFalse; 15052 manager_hints->initial_state=NormalState; 15053 manager_hints->window_group=windows->image.id; 15054 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15055 &windows->pan); 15056 if (display_image->debug != MagickFalse ) 15057 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15058 windows->pan.id); 15059 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15060 if (windows->info.mapped != MagickFalse ) 15061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15062 if ((windows->image.mapped == MagickFalse) || 15063 (windows->backdrop.id != (Window) NULL)) 15064 (void) XMapWindow(display,windows->image.id); 15065 /* 15066 Set our progress monitor and warning handlers. 15067 */ 15068 if (warning_handler == (WarningHandler) NULL) 15069 { 15070 warning_handler=resource_info->display_warnings ? 15071 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15072 warning_handler=resource_info->display_warnings ? 15073 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15074 } 15075 /* 15076 Initialize Image and Magnify X images. 15077 */ 15078 windows->image.x=0; 15079 windows->image.y=0; 15080 windows->magnify.shape=MagickFalse; 15081 width=(unsigned int) display_image->columns; 15082 height=(unsigned int) display_image->rows; 15083 if ((display_image->columns != width) || (display_image->rows != height)) 15084 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15085 display_image->filename); 15086 status=XMakeImage(display,resource_info,&windows->image,display_image, 15087 width,height,exception); 15088 if (status == MagickFalse) 15089 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15090 display_image->filename); 15091 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15092 windows->magnify.width,windows->magnify.height,exception); 15093 if (status == MagickFalse) 15094 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15095 display_image->filename); 15096 if (windows->magnify.mapped != MagickFalse ) 15097 (void) XMapRaised(display,windows->magnify.id); 15098 if (windows->pan.mapped != MagickFalse ) 15099 (void) XMapRaised(display,windows->pan.id); 15100 windows->image.window_changes.width=(int) display_image->columns; 15101 windows->image.window_changes.height=(int) display_image->rows; 15102 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15103 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15104 (void) XSync(display,MagickFalse); 15105 /* 15106 Respond to events. 15107 */ 15108 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15109 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15110 update_time=0; 15111 if (resource_info->update != MagickFalse ) 15112 { 15113 MagickBooleanType 15114 status; 15115 15116 /* 15117 Determine when file data was last modified. 15118 */ 15119 status=GetPathAttributes(display_image->filename,&attributes); 15120 if (status != MagickFalse ) 15121 update_time=attributes.st_mtime; 15122 } 15123 *state&=(~FormerImageState); 15124 *state&=(~MontageImageState); 15125 *state&=(~NextImageState); 15126 do 15127 { 15128 /* 15129 Handle a window event. 15130 */ 15131 if (windows->image.mapped != MagickFalse ) 15132 if ((display_image->delay != 0) || (resource_info->update != 0)) 15133 { 15134 if (timer < time((time_t *) NULL)) 15135 { 15136 if (resource_info->update == MagickFalse) 15137 *state|=NextImageState | ExitState; 15138 else 15139 { 15140 MagickBooleanType 15141 status; 15142 15143 /* 15144 Determine if image file was modified. 15145 */ 15146 status=GetPathAttributes(display_image->filename,&attributes); 15147 if (status != MagickFalse ) 15148 if (update_time != attributes.st_mtime) 15149 { 15150 /* 15151 Redisplay image. 15152 */ 15153 (void) FormatLocaleString( 15154 resource_info->image_info->filename,MagickPathExtent, 15155 "%s:%s",display_image->magick, 15156 display_image->filename); 15157 nexus=ReadImage(resource_info->image_info,exception); 15158 if (nexus != (Image *) NULL) 15159 *state|=NextImageState | ExitState; 15160 } 15161 delay=display_image->delay/MagickMax( 15162 display_image->ticks_per_second,1L); 15163 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15164 } 15165 } 15166 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15167 { 15168 /* 15169 Do not block if delay > 0. 15170 */ 15171 XDelay(display,SuspendTime << 2); 15172 continue; 15173 } 15174 } 15175 timestamp=time((time_t *) NULL); 15176 (void) XNextEvent(display,&event); 15177 if ((windows->image.stasis == MagickFalse) || 15178 (windows->magnify.stasis == MagickFalse)) 15179 { 15180 if ((time((time_t *) NULL)-timestamp) > 0) 15181 { 15182 windows->image.stasis=MagickTrue; 15183 windows->magnify.stasis=MagickTrue; 15184 } 15185 } 15186 if (event.xany.window == windows->command.id) 15187 { 15188 /* 15189 Select a command from the Command widget. 15190 */ 15191 id=XCommandWidget(display,windows,CommandMenu,&event); 15192 if (id < 0) 15193 continue; 15194 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent); 15195 command_type=CommandMenus[id]; 15196 if (id < MagickMenus) 15197 { 15198 /* 15199 Select a command from a pop-up menu. 15200 */ 15201 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15202 command); 15203 if (entry < 0) 15204 continue; 15205 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent); 15206 command_type=Commands[id][entry]; 15207 } 15208 if (command_type != NullCommand) 15209 nexus=XMagickCommand(display,resource_info,windows,command_type, 15210 &display_image,exception); 15211 continue; 15212 } 15213 switch (event.type) 15214 { 15215 case ButtonPress: 15216 { 15217 if (display_image->debug != MagickFalse ) 15218 (void) LogMagickEvent(X11Event,GetMagickModule(), 15219 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15220 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15221 if ((event.xbutton.button == Button3) && 15222 (event.xbutton.state & Mod1Mask)) 15223 { 15224 /* 15225 Convert Alt-Button3 to Button2. 15226 */ 15227 event.xbutton.button=Button2; 15228 event.xbutton.state&=(~Mod1Mask); 15229 } 15230 if (event.xbutton.window == windows->backdrop.id) 15231 { 15232 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15233 event.xbutton.time); 15234 break; 15235 } 15236 if (event.xbutton.window == windows->image.id) 15237 { 15238 switch (event.xbutton.button) 15239 { 15240 case Button1: 15241 { 15242 if (resource_info->immutable) 15243 { 15244 /* 15245 Select a command from the Virtual menu. 15246 */ 15247 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15248 command); 15249 if (entry >= 0) 15250 nexus=XMagickCommand(display,resource_info,windows, 15251 VirtualCommands[entry],&display_image,exception); 15252 break; 15253 } 15254 /* 15255 Map/unmap Command widget. 15256 */ 15257 if (windows->command.mapped != MagickFalse ) 15258 (void) XWithdrawWindow(display,windows->command.id, 15259 windows->command.screen); 15260 else 15261 { 15262 (void) XCommandWidget(display,windows,CommandMenu, 15263 (XEvent *) NULL); 15264 (void) XMapRaised(display,windows->command.id); 15265 } 15266 break; 15267 } 15268 case Button2: 15269 { 15270 /* 15271 User pressed the image magnify button. 15272 */ 15273 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15274 &display_image,exception); 15275 XMagnifyImage(display,windows,&event,exception); 15276 break; 15277 } 15278 case Button3: 15279 { 15280 if (resource_info->immutable) 15281 { 15282 /* 15283 Select a command from the Virtual menu. 15284 */ 15285 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15286 command); 15287 if (entry >= 0) 15288 nexus=XMagickCommand(display,resource_info,windows, 15289 VirtualCommands[entry],&display_image,exception); 15290 break; 15291 } 15292 if (display_image->montage != (char *) NULL) 15293 { 15294 /* 15295 Open or delete a tile from a visual image directory. 15296 */ 15297 nexus=XTileImage(display,resource_info,windows, 15298 display_image,&event,exception); 15299 if (nexus != (Image *) NULL) 15300 *state|=MontageImageState | NextImageState | ExitState; 15301 vid_info.x=(short int) windows->image.x; 15302 vid_info.y=(short int) windows->image.y; 15303 break; 15304 } 15305 /* 15306 Select a command from the Short Cuts menu. 15307 */ 15308 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15309 command); 15310 if (entry >= 0) 15311 nexus=XMagickCommand(display,resource_info,windows, 15312 ShortCutsCommands[entry],&display_image,exception); 15313 break; 15314 } 15315 case Button4: 15316 { 15317 /* 15318 Wheel up. 15319 */ 15320 XTranslateImage(display,windows,*image,XK_Up); 15321 break; 15322 } 15323 case Button5: 15324 { 15325 /* 15326 Wheel down. 15327 */ 15328 XTranslateImage(display,windows,*image,XK_Down); 15329 break; 15330 } 15331 default: 15332 break; 15333 } 15334 break; 15335 } 15336 if (event.xbutton.window == windows->magnify.id) 15337 { 15338 int 15339 factor; 15340 15341 static const char 15342 *MagnifyMenu[] = 15343 { 15344 "2", 15345 "4", 15346 "5", 15347 "6", 15348 "7", 15349 "8", 15350 "9", 15351 "3", 15352 (char *) NULL, 15353 }; 15354 15355 static KeySym 15356 MagnifyCommands[] = 15357 { 15358 XK_2, 15359 XK_4, 15360 XK_5, 15361 XK_6, 15362 XK_7, 15363 XK_8, 15364 XK_9, 15365 XK_3 15366 }; 15367 15368 /* 15369 Select a magnify factor from the pop-up menu. 15370 */ 15371 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15372 if (factor >= 0) 15373 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15374 exception); 15375 break; 15376 } 15377 if (event.xbutton.window == windows->pan.id) 15378 { 15379 switch (event.xbutton.button) 15380 { 15381 case Button4: 15382 { 15383 /* 15384 Wheel up. 15385 */ 15386 XTranslateImage(display,windows,*image,XK_Up); 15387 break; 15388 } 15389 case Button5: 15390 { 15391 /* 15392 Wheel down. 15393 */ 15394 XTranslateImage(display,windows,*image,XK_Down); 15395 break; 15396 } 15397 default: 15398 { 15399 XPanImage(display,windows,&event,exception); 15400 break; 15401 } 15402 } 15403 break; 15404 } 15405 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15406 1L); 15407 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15408 break; 15409 } 15410 case ButtonRelease: 15411 { 15412 if (display_image->debug != MagickFalse ) 15413 (void) LogMagickEvent(X11Event,GetMagickModule(), 15414 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15415 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15416 break; 15417 } 15418 case ClientMessage: 15419 { 15420 if (display_image->debug != MagickFalse ) 15421 (void) LogMagickEvent(X11Event,GetMagickModule(), 15422 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15423 event.xclient.message_type,event.xclient.format,(unsigned long) 15424 event.xclient.data.l[0]); 15425 if (event.xclient.message_type == windows->im_protocols) 15426 { 15427 if (*event.xclient.data.l == (long) windows->im_update_widget) 15428 { 15429 (void) CloneString(&windows->command.name,MagickTitle); 15430 windows->command.data=MagickMenus; 15431 (void) XCommandWidget(display,windows,CommandMenu, 15432 (XEvent *) NULL); 15433 break; 15434 } 15435 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15436 { 15437 /* 15438 Update graphic context and window colormap. 15439 */ 15440 for (i=0; i < (int) number_windows; i++) 15441 { 15442 if (magick_windows[i]->id == windows->icon.id) 15443 continue; 15444 context_values.background=pixel->background_color.pixel; 15445 context_values.foreground=pixel->foreground_color.pixel; 15446 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15447 context_mask,&context_values); 15448 (void) XChangeGC(display,magick_windows[i]->widget_context, 15449 context_mask,&context_values); 15450 context_values.background=pixel->foreground_color.pixel; 15451 context_values.foreground=pixel->background_color.pixel; 15452 context_values.plane_mask=context_values.background ^ 15453 context_values.foreground; 15454 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15455 (size_t) (context_mask | GCPlaneMask), 15456 &context_values); 15457 magick_windows[i]->attributes.background_pixel= 15458 pixel->background_color.pixel; 15459 magick_windows[i]->attributes.border_pixel= 15460 pixel->border_color.pixel; 15461 magick_windows[i]->attributes.colormap=map_info->colormap; 15462 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15463 (unsigned long) magick_windows[i]->mask, 15464 &magick_windows[i]->attributes); 15465 } 15466 if (windows->pan.mapped != MagickFalse ) 15467 { 15468 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15469 windows->pan.pixmap); 15470 (void) XClearWindow(display,windows->pan.id); 15471 XDrawPanRectangle(display,windows); 15472 } 15473 if (windows->backdrop.id != (Window) NULL) 15474 (void) XInstallColormap(display,map_info->colormap); 15475 break; 15476 } 15477 if (*event.xclient.data.l == (long) windows->im_former_image) 15478 { 15479 *state|=FormerImageState | ExitState; 15480 break; 15481 } 15482 if (*event.xclient.data.l == (long) windows->im_next_image) 15483 { 15484 *state|=NextImageState | ExitState; 15485 break; 15486 } 15487 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15488 { 15489 *state|=RetainColorsState; 15490 break; 15491 } 15492 if (*event.xclient.data.l == (long) windows->im_exit) 15493 { 15494 *state|=ExitState; 15495 break; 15496 } 15497 break; 15498 } 15499 if (event.xclient.message_type == windows->dnd_protocols) 15500 { 15501 Atom 15502 selection, 15503 type; 15504 15505 int 15506 format, 15507 status; 15508 15509 unsigned char 15510 *data; 15511 15512 unsigned long 15513 after, 15514 length; 15515 15516 /* 15517 Display image named by the Drag-and-Drop selection. 15518 */ 15519 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15520 break; 15521 selection=XInternAtom(display,"DndSelection",MagickFalse); 15522 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15523 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15524 &length,&after,&data); 15525 if ((status != Success) || (length == 0)) 15526 break; 15527 if (*event.xclient.data.l == 2) 15528 { 15529 /* 15530 Offix DND. 15531 */ 15532 (void) CopyMagickString(resource_info->image_info->filename, 15533 (char *) data,MagickPathExtent); 15534 } 15535 else 15536 { 15537 /* 15538 XDND. 15539 */ 15540 if (strncmp((char *) data, "file:", 5) != 0) 15541 { 15542 (void) XFree((void *) data); 15543 break; 15544 } 15545 (void) CopyMagickString(resource_info->image_info->filename, 15546 ((char *) data)+5,MagickPathExtent); 15547 } 15548 nexus=ReadImage(resource_info->image_info,exception); 15549 CatchException(exception); 15550 if (nexus != (Image *) NULL) 15551 *state|=NextImageState | ExitState; 15552 (void) XFree((void *) data); 15553 break; 15554 } 15555 /* 15556 If client window delete message, exit. 15557 */ 15558 if (event.xclient.message_type != windows->wm_protocols) 15559 break; 15560 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15561 break; 15562 (void) XWithdrawWindow(display,event.xclient.window, 15563 visual_info->screen); 15564 if (event.xclient.window == windows->image.id) 15565 { 15566 *state|=ExitState; 15567 break; 15568 } 15569 if (event.xclient.window == windows->pan.id) 15570 { 15571 /* 15572 Restore original image size when pan window is deleted. 15573 */ 15574 windows->image.window_changes.width=windows->image.ximage->width; 15575 windows->image.window_changes.height=windows->image.ximage->height; 15576 (void) XConfigureImage(display,resource_info,windows, 15577 display_image,exception); 15578 } 15579 break; 15580 } 15581 case ConfigureNotify: 15582 { 15583 if (display_image->debug != MagickFalse ) 15584 (void) LogMagickEvent(X11Event,GetMagickModule(), 15585 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15586 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15587 event.xconfigure.y,event.xconfigure.send_event); 15588 if (event.xconfigure.window == windows->image.id) 15589 { 15590 /* 15591 Image window has a new configuration. 15592 */ 15593 if (event.xconfigure.send_event != 0) 15594 { 15595 XWindowChanges 15596 window_changes; 15597 15598 /* 15599 Position the transient windows relative of the Image window. 15600 */ 15601 if (windows->command.geometry == (char *) NULL) 15602 if (windows->command.mapped == MagickFalse) 15603 { 15604 windows->command.x=event.xconfigure.x- 15605 windows->command.width-25; 15606 windows->command.y=event.xconfigure.y; 15607 XConstrainWindowPosition(display,&windows->command); 15608 window_changes.x=windows->command.x; 15609 window_changes.y=windows->command.y; 15610 (void) XReconfigureWMWindow(display,windows->command.id, 15611 windows->command.screen,(unsigned int) (CWX | CWY), 15612 &window_changes); 15613 } 15614 if (windows->widget.geometry == (char *) NULL) 15615 if (windows->widget.mapped == MagickFalse) 15616 { 15617 windows->widget.x=event.xconfigure.x+ 15618 event.xconfigure.width/10; 15619 windows->widget.y=event.xconfigure.y+ 15620 event.xconfigure.height/10; 15621 XConstrainWindowPosition(display,&windows->widget); 15622 window_changes.x=windows->widget.x; 15623 window_changes.y=windows->widget.y; 15624 (void) XReconfigureWMWindow(display,windows->widget.id, 15625 windows->widget.screen,(unsigned int) (CWX | CWY), 15626 &window_changes); 15627 } 15628 if (windows->magnify.geometry == (char *) NULL) 15629 if (windows->magnify.mapped == MagickFalse) 15630 { 15631 windows->magnify.x=event.xconfigure.x+ 15632 event.xconfigure.width+25; 15633 windows->magnify.y=event.xconfigure.y; 15634 XConstrainWindowPosition(display,&windows->magnify); 15635 window_changes.x=windows->magnify.x; 15636 window_changes.y=windows->magnify.y; 15637 (void) XReconfigureWMWindow(display,windows->magnify.id, 15638 windows->magnify.screen,(unsigned int) (CWX | CWY), 15639 &window_changes); 15640 } 15641 if (windows->pan.geometry == (char *) NULL) 15642 if (windows->pan.mapped == MagickFalse) 15643 { 15644 windows->pan.x=event.xconfigure.x+ 15645 event.xconfigure.width+25; 15646 windows->pan.y=event.xconfigure.y+ 15647 windows->magnify.height+50; 15648 XConstrainWindowPosition(display,&windows->pan); 15649 window_changes.x=windows->pan.x; 15650 window_changes.y=windows->pan.y; 15651 (void) XReconfigureWMWindow(display,windows->pan.id, 15652 windows->pan.screen,(unsigned int) (CWX | CWY), 15653 &window_changes); 15654 } 15655 } 15656 if ((event.xconfigure.width == (int) windows->image.width) && 15657 (event.xconfigure.height == (int) windows->image.height)) 15658 break; 15659 windows->image.width=(unsigned int) event.xconfigure.width; 15660 windows->image.height=(unsigned int) event.xconfigure.height; 15661 windows->image.x=0; 15662 windows->image.y=0; 15663 if (display_image->montage != (char *) NULL) 15664 { 15665 windows->image.x=vid_info.x; 15666 windows->image.y=vid_info.y; 15667 } 15668 if (windows->image.mapped != MagickFalse && 15669 windows->image.stasis != MagickFalse ) 15670 { 15671 /* 15672 Update image window configuration. 15673 */ 15674 windows->image.window_changes.width=event.xconfigure.width; 15675 windows->image.window_changes.height=event.xconfigure.height; 15676 (void) XConfigureImage(display,resource_info,windows, 15677 display_image,exception); 15678 } 15679 /* 15680 Update pan window configuration. 15681 */ 15682 if ((event.xconfigure.width < windows->image.ximage->width) || 15683 (event.xconfigure.height < windows->image.ximage->height)) 15684 { 15685 (void) XMapRaised(display,windows->pan.id); 15686 XDrawPanRectangle(display,windows); 15687 } 15688 else 15689 if (windows->pan.mapped != MagickFalse ) 15690 (void) XWithdrawWindow(display,windows->pan.id, 15691 windows->pan.screen); 15692 break; 15693 } 15694 if (event.xconfigure.window == windows->magnify.id) 15695 { 15696 unsigned int 15697 magnify; 15698 15699 /* 15700 Magnify window has a new configuration. 15701 */ 15702 windows->magnify.width=(unsigned int) event.xconfigure.width; 15703 windows->magnify.height=(unsigned int) event.xconfigure.height; 15704 if (windows->magnify.mapped == MagickFalse) 15705 break; 15706 magnify=1; 15707 while ((int) magnify <= event.xconfigure.width) 15708 magnify<<=1; 15709 while ((int) magnify <= event.xconfigure.height) 15710 magnify<<=1; 15711 magnify>>=1; 15712 if (((int) magnify != event.xconfigure.width) || 15713 ((int) magnify != event.xconfigure.height)) 15714 { 15715 window_changes.width=(int) magnify; 15716 window_changes.height=(int) magnify; 15717 (void) XReconfigureWMWindow(display,windows->magnify.id, 15718 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15719 &window_changes); 15720 break; 15721 } 15722 if (windows->magnify.mapped != MagickFalse && 15723 windows->magnify.stasis != MagickFalse ) 15724 { 15725 status=XMakeImage(display,resource_info,&windows->magnify, 15726 display_image,windows->magnify.width,windows->magnify.height, 15727 exception); 15728 XMakeMagnifyImage(display,windows,exception); 15729 } 15730 break; 15731 } 15732 if (windows->magnify.mapped != MagickFalse && 15733 (event.xconfigure.window == windows->pan.id)) 15734 { 15735 /* 15736 Pan icon window has a new configuration. 15737 */ 15738 if (event.xconfigure.send_event != 0) 15739 { 15740 windows->pan.x=event.xconfigure.x; 15741 windows->pan.y=event.xconfigure.y; 15742 } 15743 windows->pan.width=(unsigned int) event.xconfigure.width; 15744 windows->pan.height=(unsigned int) event.xconfigure.height; 15745 break; 15746 } 15747 if (event.xconfigure.window == windows->icon.id) 15748 { 15749 /* 15750 Icon window has a new configuration. 15751 */ 15752 windows->icon.width=(unsigned int) event.xconfigure.width; 15753 windows->icon.height=(unsigned int) event.xconfigure.height; 15754 break; 15755 } 15756 break; 15757 } 15758 case DestroyNotify: 15759 { 15760 /* 15761 Group leader has exited. 15762 */ 15763 if (display_image->debug != MagickFalse ) 15764 (void) LogMagickEvent(X11Event,GetMagickModule(), 15765 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15766 if (event.xdestroywindow.window == windows->group_leader.id) 15767 { 15768 *state|=ExitState; 15769 break; 15770 } 15771 break; 15772 } 15773 case EnterNotify: 15774 { 15775 /* 15776 Selectively install colormap. 15777 */ 15778 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15779 if (event.xcrossing.mode != NotifyUngrab) 15780 XInstallColormap(display,map_info->colormap); 15781 break; 15782 } 15783 case Expose: 15784 { 15785 if (display_image->debug != MagickFalse ) 15786 (void) LogMagickEvent(X11Event,GetMagickModule(), 15787 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15788 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15789 event.xexpose.y); 15790 /* 15791 Refresh windows that are now exposed. 15792 */ 15793 if ((event.xexpose.window == windows->image.id) && 15794 windows->image.mapped != MagickFalse ) 15795 { 15796 XRefreshWindow(display,&windows->image,&event); 15797 delay=display_image->delay/MagickMax( 15798 display_image->ticks_per_second,1L); 15799 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15800 break; 15801 } 15802 if ((event.xexpose.window == windows->magnify.id) && 15803 windows->magnify.mapped != MagickFalse) 15804 { 15805 XMakeMagnifyImage(display,windows,exception); 15806 break; 15807 } 15808 if (event.xexpose.window == windows->pan.id) 15809 { 15810 XDrawPanRectangle(display,windows); 15811 break; 15812 } 15813 if (event.xexpose.window == windows->icon.id) 15814 { 15815 XRefreshWindow(display,&windows->icon,&event); 15816 break; 15817 } 15818 break; 15819 } 15820 case KeyPress: 15821 { 15822 int 15823 length; 15824 15825 /* 15826 Respond to a user key press. 15827 */ 15828 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15829 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15830 *(command+length)='\0'; 15831 if (display_image->debug != MagickFalse ) 15832 (void) LogMagickEvent(X11Event,GetMagickModule(), 15833 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15834 key_symbol,command); 15835 if (event.xkey.window == windows->image.id) 15836 { 15837 command_type=XImageWindowCommand(display,resource_info,windows, 15838 event.xkey.state,key_symbol,&display_image,exception); 15839 if (command_type != NullCommand) 15840 nexus=XMagickCommand(display,resource_info,windows,command_type, 15841 &display_image,exception); 15842 } 15843 if (event.xkey.window == windows->magnify.id) 15844 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15845 exception); 15846 if (event.xkey.window == windows->pan.id) 15847 { 15848 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15849 (void) XWithdrawWindow(display,windows->pan.id, 15850 windows->pan.screen); 15851 else 15852 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15853 XTextViewWidget(display,resource_info,windows,MagickFalse, 15854 "Help Viewer - Image Pan",ImagePanHelp); 15855 else 15856 XTranslateImage(display,windows,*image,key_symbol); 15857 } 15858 delay=display_image->delay/MagickMax( 15859 display_image->ticks_per_second,1L); 15860 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15861 break; 15862 } 15863 case KeyRelease: 15864 { 15865 /* 15866 Respond to a user key release. 15867 */ 15868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15870 if (display_image->debug != MagickFalse ) 15871 (void) LogMagickEvent(X11Event,GetMagickModule(), 15872 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15873 break; 15874 } 15875 case LeaveNotify: 15876 { 15877 /* 15878 Selectively uninstall colormap. 15879 */ 15880 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15881 if (event.xcrossing.mode != NotifyUngrab) 15882 XUninstallColormap(display,map_info->colormap); 15883 break; 15884 } 15885 case MapNotify: 15886 { 15887 if (display_image->debug != MagickFalse ) 15888 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15889 event.xmap.window); 15890 if (event.xmap.window == windows->backdrop.id) 15891 { 15892 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15893 CurrentTime); 15894 windows->backdrop.mapped=MagickTrue; 15895 break; 15896 } 15897 if (event.xmap.window == windows->image.id) 15898 { 15899 if (windows->backdrop.id != (Window) NULL) 15900 (void) XInstallColormap(display,map_info->colormap); 15901 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15902 { 15903 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15904 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15905 } 15906 if (((int) windows->image.width < windows->image.ximage->width) || 15907 ((int) windows->image.height < windows->image.ximage->height)) 15908 (void) XMapRaised(display,windows->pan.id); 15909 windows->image.mapped=MagickTrue; 15910 break; 15911 } 15912 if (event.xmap.window == windows->magnify.id) 15913 { 15914 XMakeMagnifyImage(display,windows,exception); 15915 windows->magnify.mapped=MagickTrue; 15916 (void) XWithdrawWindow(display,windows->info.id, 15917 windows->info.screen); 15918 break; 15919 } 15920 if (event.xmap.window == windows->pan.id) 15921 { 15922 XMakePanImage(display,resource_info,windows,display_image, 15923 exception); 15924 windows->pan.mapped=MagickTrue; 15925 break; 15926 } 15927 if (event.xmap.window == windows->info.id) 15928 { 15929 windows->info.mapped=MagickTrue; 15930 break; 15931 } 15932 if (event.xmap.window == windows->icon.id) 15933 { 15934 MagickBooleanType 15935 taint; 15936 15937 /* 15938 Create an icon image. 15939 */ 15940 taint=display_image->taint; 15941 XMakeStandardColormap(display,icon_visual,icon_resources, 15942 display_image,icon_map,icon_pixel,exception); 15943 (void) XMakeImage(display,icon_resources,&windows->icon, 15944 display_image,windows->icon.width,windows->icon.height, 15945 exception); 15946 display_image->taint=taint; 15947 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15948 windows->icon.pixmap); 15949 (void) XClearWindow(display,windows->icon.id); 15950 (void) XWithdrawWindow(display,windows->info.id, 15951 windows->info.screen); 15952 windows->icon.mapped=MagickTrue; 15953 break; 15954 } 15955 if (event.xmap.window == windows->command.id) 15956 { 15957 windows->command.mapped=MagickTrue; 15958 break; 15959 } 15960 if (event.xmap.window == windows->popup.id) 15961 { 15962 windows->popup.mapped=MagickTrue; 15963 break; 15964 } 15965 if (event.xmap.window == windows->widget.id) 15966 { 15967 windows->widget.mapped=MagickTrue; 15968 break; 15969 } 15970 break; 15971 } 15972 case MappingNotify: 15973 { 15974 (void) XRefreshKeyboardMapping(&event.xmapping); 15975 break; 15976 } 15977 case NoExpose: 15978 break; 15979 case PropertyNotify: 15980 { 15981 Atom 15982 type; 15983 15984 int 15985 format, 15986 status; 15987 15988 unsigned char 15989 *data; 15990 15991 unsigned long 15992 after, 15993 length; 15994 15995 if (display_image->debug != MagickFalse ) 15996 (void) LogMagickEvent(X11Event,GetMagickModule(), 15997 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15998 event.xproperty.atom,event.xproperty.state); 15999 if (event.xproperty.atom != windows->im_remote_command) 16000 break; 16001 /* 16002 Display image named by the remote command protocol. 16003 */ 16004 status=XGetWindowProperty(display,event.xproperty.window, 16005 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom) 16006 AnyPropertyType,&type,&format,&length,&after,&data); 16007 if ((status != Success) || (length == 0)) 16008 break; 16009 if (LocaleCompare((char *) data,"-quit") == 0) 16010 { 16011 XClientMessage(display,windows->image.id,windows->im_protocols, 16012 windows->im_exit,CurrentTime); 16013 (void) XFree((void *) data); 16014 break; 16015 } 16016 (void) CopyMagickString(resource_info->image_info->filename, 16017 (char *) data,MagickPathExtent); 16018 (void) XFree((void *) data); 16019 nexus=ReadImage(resource_info->image_info,exception); 16020 CatchException(exception); 16021 if (nexus != (Image *) NULL) 16022 *state|=NextImageState | ExitState; 16023 break; 16024 } 16025 case ReparentNotify: 16026 { 16027 if (display_image->debug != MagickFalse ) 16028 (void) LogMagickEvent(X11Event,GetMagickModule(), 16029 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 16030 event.xreparent.window); 16031 break; 16032 } 16033 case UnmapNotify: 16034 { 16035 if (display_image->debug != MagickFalse ) 16036 (void) LogMagickEvent(X11Event,GetMagickModule(), 16037 "Unmap Notify: 0x%lx",event.xunmap.window); 16038 if (event.xunmap.window == windows->backdrop.id) 16039 { 16040 windows->backdrop.mapped=MagickFalse; 16041 break; 16042 } 16043 if (event.xunmap.window == windows->image.id) 16044 { 16045 windows->image.mapped=MagickFalse; 16046 break; 16047 } 16048 if (event.xunmap.window == windows->magnify.id) 16049 { 16050 windows->magnify.mapped=MagickFalse; 16051 break; 16052 } 16053 if (event.xunmap.window == windows->pan.id) 16054 { 16055 windows->pan.mapped=MagickFalse; 16056 break; 16057 } 16058 if (event.xunmap.window == windows->info.id) 16059 { 16060 windows->info.mapped=MagickFalse; 16061 break; 16062 } 16063 if (event.xunmap.window == windows->icon.id) 16064 { 16065 if (map_info->colormap == icon_map->colormap) 16066 XConfigureImageColormap(display,resource_info,windows, 16067 display_image,exception); 16068 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16069 icon_pixel); 16070 windows->icon.mapped=MagickFalse; 16071 break; 16072 } 16073 if (event.xunmap.window == windows->command.id) 16074 { 16075 windows->command.mapped=MagickFalse; 16076 break; 16077 } 16078 if (event.xunmap.window == windows->popup.id) 16079 { 16080 if (windows->backdrop.id != (Window) NULL) 16081 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16082 CurrentTime); 16083 windows->popup.mapped=MagickFalse; 16084 break; 16085 } 16086 if (event.xunmap.window == windows->widget.id) 16087 { 16088 if (windows->backdrop.id != (Window) NULL) 16089 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16090 CurrentTime); 16091 windows->widget.mapped=MagickFalse; 16092 break; 16093 } 16094 break; 16095 } 16096 default: 16097 { 16098 if (display_image->debug != MagickFalse ) 16099 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16100 event.type); 16101 break; 16102 } 16103 } 16104 } while (!(*state & ExitState)); 16105 if ((*state & ExitState) == 0) 16106 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16107 &display_image,exception); 16108 else 16109 if (resource_info->confirm_edit != MagickFalse ) 16110 { 16111 /* 16112 Query user if image has changed. 16113 */ 16114 if ((resource_info->immutable == MagickFalse) && 16115 display_image->taint != MagickFalse) 16116 { 16117 int 16118 status; 16119 16120 status=XConfirmWidget(display,windows,"Your image changed.", 16121 "Do you want to save it"); 16122 if (status == 0) 16123 *state&=(~ExitState); 16124 else 16125 if (status > 0) 16126 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16127 &display_image,exception); 16128 } 16129 } 16130 if ((windows->visual_info->klass == GrayScale) || 16131 (windows->visual_info->klass == PseudoColor) || 16132 (windows->visual_info->klass == DirectColor)) 16133 { 16134 /* 16135 Withdraw pan and Magnify window. 16136 */ 16137 if (windows->info.mapped != MagickFalse ) 16138 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16139 if (windows->magnify.mapped != MagickFalse ) 16140 (void) XWithdrawWindow(display,windows->magnify.id, 16141 windows->magnify.screen); 16142 if (windows->command.mapped != MagickFalse ) 16143 (void) XWithdrawWindow(display,windows->command.id, 16144 windows->command.screen); 16145 } 16146 if (windows->pan.mapped != MagickFalse ) 16147 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16148 if (resource_info->backdrop == MagickFalse) 16149 if (windows->backdrop.mapped) 16150 { 16151 (void) XWithdrawWindow(display,windows->backdrop.id, 16152 windows->backdrop.screen); 16153 (void) XDestroyWindow(display,windows->backdrop.id); 16154 windows->backdrop.id=(Window) NULL; 16155 (void) XWithdrawWindow(display,windows->image.id, 16156 windows->image.screen); 16157 (void) XDestroyWindow(display,windows->image.id); 16158 windows->image.id=(Window) NULL; 16159 } 16160 XSetCursorState(display,windows,MagickTrue); 16161 XCheckRefreshWindows(display,windows); 16162 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16163 *state&=(~ExitState); 16164 if (*state & ExitState) 16165 { 16166 /* 16167 Free Standard Colormap. 16168 */ 16169 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16170 if (resource_info->map_type == (char *) NULL) 16171 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16172 /* 16173 Free X resources. 16174 */ 16175 if (resource_info->copy_image != (Image *) NULL) 16176 { 16177 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16178 resource_info->copy_image=NewImageList(); 16179 } 16180 DestroyXResources(); 16181 } 16182 (void) XSync(display,MagickFalse); 16183 /* 16184 Restore our progress monitor and warning handlers. 16185 */ 16186 (void) SetErrorHandler(warning_handler); 16187 (void) SetWarningHandler(warning_handler); 16188 /* 16189 Change to home directory. 16190 */ 16191 directory=getcwd(working_directory,MagickPathExtent); 16192 (void) directory; 16193 { 16194 int 16195 status; 16196 16197 if (*resource_info->home_directory == '\0') 16198 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent); 16199 status=chdir(resource_info->home_directory); 16200 if (status == -1) 16201 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16202 "UnableToOpenFile","%s",resource_info->home_directory); 16203 } 16204 *image=display_image; 16205 return(nexus); 16206 } 16207 #else 16208 16209 /* 16211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16212 % % 16213 % % 16214 % % 16215 + D i s p l a y I m a g e s % 16216 % % 16217 % % 16218 % % 16219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16220 % 16221 % DisplayImages() displays an image sequence to any X window screen. It 16222 % returns a value other than 0 if successful. Check the exception member 16223 % of image to determine the reason for any failure. 16224 % 16225 % The format of the DisplayImages method is: 16226 % 16227 % MagickBooleanType DisplayImages(const ImageInfo *image_info, 16228 % Image *images,ExceptionInfo *exception) 16229 % 16230 % A description of each parameter follows: 16231 % 16232 % o image_info: the image info. 16233 % 16234 % o image: the image. 16235 % 16236 % o exception: return any errors or warnings in this structure. 16237 % 16238 */ 16239 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16240 Image *image,ExceptionInfo *exception) 16241 { 16242 assert(image_info != (const ImageInfo *) NULL); 16243 assert(image_info->signature == MagickCoreSignature); 16244 assert(image != (Image *) NULL); 16245 assert(image->signature == MagickCoreSignature); 16246 (void) image_info; 16247 if (image->debug != MagickFalse ) 16248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16249 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16250 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16251 return(MagickFalse); 16252 } 16253 16254 /* 16256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16257 % % 16258 % % 16259 % % 16260 + R e m o t e D i s p l a y C o m m a n d % 16261 % % 16262 % % 16263 % % 16264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16265 % 16266 % RemoteDisplayCommand() encourages a remote display program to display the 16267 % specified image filename. 16268 % 16269 % The format of the RemoteDisplayCommand method is: 16270 % 16271 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16272 % const char *window,const char *filename,ExceptionInfo *exception) 16273 % 16274 % A description of each parameter follows: 16275 % 16276 % o image_info: the image info. 16277 % 16278 % o window: Specifies the name or id of an X window. 16279 % 16280 % o filename: the name of the image filename to display. 16281 % 16282 % o exception: return any errors or warnings in this structure. 16283 % 16284 */ 16285 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16286 const char *window,const char *filename,ExceptionInfo *exception) 16287 { 16288 assert(image_info != (const ImageInfo *) NULL); 16289 assert(image_info->signature == MagickCoreSignature); 16290 assert(filename != (char *) NULL); 16291 (void) window; 16292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16293 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16294 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16295 return(MagickFalse); 16296 } 16297 #endif 16298