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