display.c revision 4c08aed51c5899665ade97263692328eea4af106
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/client.h" 47#include "MagickCore/color.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/composite.h" 50#include "MagickCore/constitute.h" 51#include "MagickCore/decorate.h" 52#include "MagickCore/delegate.h" 53#include "MagickCore/display.h" 54#include "MagickCore/display-private.h" 55#include "MagickCore/draw.h" 56#include "MagickCore/effect.h" 57#include "MagickCore/enhance.h" 58#include "MagickCore/exception.h" 59#include "MagickCore/exception-private.h" 60#include "MagickCore/fx.h" 61#include "MagickCore/geometry.h" 62#include "MagickCore/image.h" 63#include "MagickCore/image-private.h" 64#include "MagickCore/list.h" 65#include "MagickCore/log.h" 66#include "MagickCore/magick.h" 67#include "MagickCore/memory_.h" 68#include "MagickCore/monitor.h" 69#include "MagickCore/monitor-private.h" 70#include "MagickCore/montage.h" 71#include "MagickCore/option.h" 72#include "MagickCore/paint.h" 73#include "MagickCore/pixel.h" 74#include "MagickCore/pixel-accessor.h" 75#include "MagickCore/PreRvIcccm.h" 76#include "MagickCore/property.h" 77#include "MagickCore/quantum.h" 78#include "MagickCore/quantum-private.h" 79#include "MagickCore/resize.h" 80#include "MagickCore/resource_.h" 81#include "MagickCore/shear.h" 82#include "MagickCore/segment.h" 83#include "MagickCore/string_.h" 84#include "MagickCore/string-private.h" 85#include "MagickCore/transform.h" 86#include "MagickCore/threshold.h" 87#include "MagickCore/utility.h" 88#include "MagickCore/version.h" 89#include "MagickCore/widget.h" 90#include "MagickCore/xwindow-private.h" 91 92#if defined(MAGICKCORE_X11_DELEGATE) 93/* 94 Define declarations. 95*/ 96#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 97 98/* 99 Constant declarations. 100*/ 101static const unsigned char 102 HighlightBitmap[8] = 103 { 104 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 105 }, 106 OpaqueBitmap[8] = 107 { 108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 109 }, 110 ShadowBitmap[8] = 111 { 112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 113 }; 114 115static const char 116 *PageSizes[] = 117 { 118 "Letter", 119 "Tabloid", 120 "Ledger", 121 "Legal", 122 "Statement", 123 "Executive", 124 "A3", 125 "A4", 126 "A5", 127 "B4", 128 "B5", 129 "Folio", 130 "Quarto", 131 "10x14", 132 (char *) NULL 133 }; 134 135/* 136 Help widget declarations. 137*/ 138static const char 139 *ImageAnnotateHelp[] = 140 { 141 "In annotate mode, the Command widget has these options:", 142 "", 143 " Font Name", 144 " fixed", 145 " variable", 146 " 5x8", 147 " 6x10", 148 " 7x13bold", 149 " 8x13bold", 150 " 9x15bold", 151 " 10x20", 152 " 12x24", 153 " Browser...", 154 " Font Color", 155 " black", 156 " blue", 157 " cyan", 158 " green", 159 " gray", 160 " red", 161 " magenta", 162 " yellow", 163 " white", 164 " transparent", 165 " Browser...", 166 " Font Color", 167 " black", 168 " blue", 169 " cyan", 170 " green", 171 " gray", 172 " red", 173 " magenta", 174 " yellow", 175 " white", 176 " transparent", 177 " Browser...", 178 " Rotate Text", 179 " -90", 180 " -45", 181 " -30", 182 " 0", 183 " 30", 184 " 45", 185 " 90", 186 " 180", 187 " Dialog...", 188 " Help", 189 " Dismiss", 190 "", 191 "Choose a font name from the Font Name sub-menu. Additional", 192 "font names can be specified with the font browser. You can", 193 "change the menu names by setting the X resources font1", 194 "through font9.", 195 "", 196 "Choose a font color from the Font Color sub-menu.", 197 "Additional font colors can be specified with the color", 198 "browser. You can change the menu colors by setting the X", 199 "resources pen1 through pen9.", 200 "", 201 "If you select the color browser and press Grab, you can", 202 "choose the font color by moving the pointer to the desired", 203 "color on the screen and press any button.", 204 "", 205 "If you choose to rotate the text, choose Rotate Text from the", 206 "menu and select an angle. Typically you will only want to", 207 "rotate one line of text at a time. Depending on the angle you", 208 "choose, subsequent lines may end up overwriting each other.", 209 "", 210 "Choosing a font and its color is optional. The default font", 211 "is fixed and the default color is black. However, you must", 212 "choose a location to begin entering text and press button 1.", 213 "An underscore character will appear at the location of the", 214 "pointer. The cursor changes to a pencil to indicate you are", 215 "in text mode. To exit immediately, press Dismiss.", 216 "", 217 "In text mode, any key presses will display the character at", 218 "the location of the underscore and advance the underscore", 219 "cursor. Enter your text and once completed press Apply to", 220 "finish your image annotation. To correct errors press BACK", 221 "SPACE. To delete an entire line of text, press DELETE. Any", 222 "text that exceeds the boundaries of the image window is", 223 "automagically continued onto the next line.", 224 "", 225 "The actual color you request for the font is saved in the", 226 "image. However, the color that appears in your image window", 227 "may be different. For example, on a monochrome screen the", 228 "text will appear black or white even if you choose the color", 229 "red as the font color. However, the image saved to a file", 230 "with -write is written with red lettering. To assure the", 231 "correct color text in the final image, any PseudoClass image", 232 "is promoted to DirectClass (see miff(5)). To force a", 233 "PseudoClass image to remain PseudoClass, use -colors.", 234 (char *) NULL, 235 }, 236 *ImageChopHelp[] = 237 { 238 "In chop mode, the Command widget has these options:", 239 "", 240 " Direction", 241 " horizontal", 242 " vertical", 243 " Help", 244 " Dismiss", 245 "", 246 "If the you choose the horizontal direction (this the", 247 "default), the area of the image between the two horizontal", 248 "endpoints of the chop line is removed. Otherwise, the area", 249 "of the image between the two vertical endpoints of the chop", 250 "line is removed.", 251 "", 252 "Select a location within the image window to begin your chop,", 253 "press and hold any button. Next, move the pointer to", 254 "another location in the image. As you move a line will", 255 "connect the initial location and the pointer. When you", 256 "release the button, the area within the image to chop is", 257 "determined by which direction you choose from the Command", 258 "widget.", 259 "", 260 "To cancel the image chopping, move the pointer back to the", 261 "starting point of the line and release the button.", 262 (char *) NULL, 263 }, 264 *ImageColorEditHelp[] = 265 { 266 "In color edit mode, the Command widget has these options:", 267 "", 268 " Method", 269 " point", 270 " replace", 271 " floodfill", 272 " filltoborder", 273 " reset", 274 " Pixel Color", 275 " black", 276 " blue", 277 " cyan", 278 " green", 279 " gray", 280 " red", 281 " magenta", 282 " yellow", 283 " white", 284 " Browser...", 285 " Border Color", 286 " black", 287 " blue", 288 " cyan", 289 " green", 290 " gray", 291 " red", 292 " magenta", 293 " yellow", 294 " white", 295 " Browser...", 296 " Fuzz", 297 " 0%", 298 " 2%", 299 " 5%", 300 " 10%", 301 " 15%", 302 " Dialog...", 303 " Undo", 304 " Help", 305 " Dismiss", 306 "", 307 "Choose a color editing method from the Method sub-menu", 308 "of the Command widget. The point method recolors any pixel", 309 "selected with the pointer until the button is released. The", 310 "replace method recolors any pixel that matches the color of", 311 "the pixel you select with a button press. Floodfill recolors", 312 "any pixel that matches the color of the pixel you select with", 313 "a button press and is a neighbor. Whereas filltoborder recolors", 314 "any neighbor pixel that is not the border color. Finally reset", 315 "changes the entire image to the designated color.", 316 "", 317 "Next, choose a pixel color from the Pixel Color sub-menu.", 318 "Additional pixel colors can be specified with the color", 319 "browser. You can change the menu colors by setting the X", 320 "resources pen1 through pen9.", 321 "", 322 "Now press button 1 to select a pixel within the image window", 323 "to change its color. Additional pixels may be recolored as", 324 "prescribed by the method you choose.", 325 "", 326 "If the Magnify widget is mapped, it can be helpful in positioning", 327 "your pointer within the image (refer to button 2).", 328 "", 329 "The actual color you request for the pixels is saved in the", 330 "image. However, the color that appears in your image window", 331 "may be different. For example, on a monochrome screen the", 332 "pixel will appear black or white even if you choose the", 333 "color red as the pixel color. However, the image saved to a", 334 "file with -write is written with red pixels. To assure the", 335 "correct color text in the final image, any PseudoClass image", 336 "is promoted to DirectClass (see miff(5)). To force a", 337 "PseudoClass image to remain PseudoClass, use -colors.", 338 (char *) NULL, 339 }, 340 *ImageCompositeHelp[] = 341 { 342 "First a widget window is displayed requesting you to enter an", 343 "image name. Press Composite, Grab or type a file name.", 344 "Press Cancel if you choose not to create a composite image.", 345 "When you choose Grab, move the pointer to the desired window", 346 "and press any button.", 347 "", 348 "If the Composite image does not have any matte information,", 349 "you are informed and the file browser is displayed again.", 350 "Enter the name of a mask image. The image is typically", 351 "grayscale and the same size as the composite image. If the", 352 "image is not grayscale, it is converted to grayscale and the", 353 "resulting intensities are used as matte information.", 354 "", 355 "A small window appears showing the location of the cursor in", 356 "the image window. You are now in composite mode. To exit", 357 "immediately, press Dismiss. In composite mode, the Command", 358 "widget has these options:", 359 "", 360 " Operators", 361 " Over", 362 " In", 363 " Out", 364 " Atop", 365 " Xor", 366 " Plus", 367 " Minus", 368 " Add", 369 " Subtract", 370 " Difference", 371 " Multiply", 372 " Bumpmap", 373 " Copy", 374 " CopyRed", 375 " CopyGreen", 376 " CopyBlue", 377 " CopyOpacity", 378 " Clear", 379 " Dissolve", 380 " Displace", 381 " Help", 382 " Dismiss", 383 "", 384 "Choose a composite operation from the Operators sub-menu of", 385 "the Command widget. How each operator behaves is described", 386 "below. Image window is the image currently displayed on", 387 "your X server and image is the image obtained with the File", 388 "Browser widget.", 389 "", 390 "Over The result is the union of the two image shapes,", 391 " with image obscuring image window in the region of", 392 " overlap.", 393 "", 394 "In The result is simply image cut by the shape of", 395 " image window. None of the image data of image", 396 " window is in the result.", 397 "", 398 "Out The resulting image is image with the shape of", 399 " image window cut out.", 400 "", 401 "Atop The result is the same shape as image image window,", 402 " with image obscuring image window where the image", 403 " shapes overlap. Note this differs from over", 404 " because the portion of image outside image window's", 405 " shape does not appear in the result.", 406 "", 407 "Xor The result is the image data from both image and", 408 " image window that is outside the overlap region.", 409 " The overlap region is blank.", 410 "", 411 "Plus The result is just the sum of the image data.", 412 " Output values are cropped to QuantumRange (no overflow).", 413 "", 414 "Minus The result of image - image window, with underflow", 415 " cropped to zero.", 416 "", 417 "Add The result of image + image window, with overflow", 418 " wrapping around (mod 256).", 419 "", 420 "Subtract The result of image - image window, with underflow", 421 " wrapping around (mod 256). The add and subtract", 422 " operators can be used to perform reversible", 423 " transformations.", 424 "", 425 "Difference", 426 " The result of abs(image - image window). This", 427 " useful for comparing two very similar images.", 428 "", 429 "Multiply", 430 " The result of image * image window. This", 431 " useful for the creation of drop-shadows.", 432 "", 433 "Bumpmap The result of surface normals from image * image", 434 " window.", 435 "", 436 "Copy The resulting image is image window replaced with", 437 " image. Here the matte information is ignored.", 438 "", 439 "CopyRed The red layer of the image window is replace with", 440 " the red layer of the image. The other layers are", 441 " untouched.", 442 "", 443 "CopyGreen", 444 " The green layer of the image window is replace with", 445 " the green layer of the image. The other layers are", 446 " untouched.", 447 "", 448 "CopyBlue The blue layer of the image window is replace with", 449 " the blue layer of the image. The other layers are", 450 " untouched.", 451 "", 452 "CopyOpacity", 453 " The matte layer of the image window is replace with", 454 " the matte layer of the image. The other layers are", 455 " untouched.", 456 "", 457 "The image compositor requires a matte, or alpha channel in", 458 "the image for some operations. This extra channel usually", 459 "defines a mask which represents a sort of a cookie-cutter", 460 "for the image. This the case when matte is opaque (full", 461 "coverage) for pixels inside the shape, zero outside, and", 462 "between 0 and QuantumRange on the boundary. If image does not", 463 "have a matte channel, it is initialized with 0 for any pixel", 464 "matching in color to pixel location (0,0), otherwise QuantumRange.", 465 "", 466 "If you choose Dissolve, the composite operator becomes Over. The", 467 "image matte channel percent transparency is initialized to factor.", 468 "The image window is initialized to (100-factor). Where factor is the", 469 "value you specify in the Dialog widget.", 470 "", 471 "Displace shifts the image pixels as defined by a displacement", 472 "map. With this option, image is used as a displacement map.", 473 "Black, within the displacement map, is a maximum positive", 474 "displacement. White is a maximum negative displacement and", 475 "middle gray is neutral. The displacement is scaled to determine", 476 "the pixel shift. By default, the displacement applies in both the", 477 "horizontal and vertical directions. However, if you specify a mask,", 478 "image is the horizontal X displacement and mask the vertical Y", 479 "displacement.", 480 "", 481 "Note that matte information for image window is not retained", 482 "for colormapped X server visuals (e.g. StaticColor,", 483 "StaticColor, GrayScale, PseudoColor). Correct compositing", 484 "behavior may require a TrueColor or DirectColor visual or a", 485 "Standard Colormap.", 486 "", 487 "Choosing a composite operator is optional. The default", 488 "operator is replace. However, you must choose a location to", 489 "composite your image and press button 1. Press and hold the", 490 "button before releasing and an outline of the image will", 491 "appear to help you identify your location.", 492 "", 493 "The actual colors of the composite image is saved. However,", 494 "the color that appears in image window may be different.", 495 "For example, on a monochrome screen image window will appear", 496 "black or white even though your composited image may have", 497 "many colors. If the image is saved to a file it is written", 498 "with the correct colors. To assure the correct colors are", 499 "saved in the final image, any PseudoClass image is promoted", 500 "to DirectClass (see miff(5)). To force a PseudoClass image", 501 "to remain PseudoClass, use -colors.", 502 (char *) NULL, 503 }, 504 *ImageCutHelp[] = 505 { 506 "In cut mode, the Command widget has these options:", 507 "", 508 " Help", 509 " Dismiss", 510 "", 511 "To define a cut region, press button 1 and drag. The", 512 "cut region is defined by a highlighted rectangle that", 513 "expands or contracts as it follows the pointer. Once you", 514 "are satisfied with the cut region, release the button.", 515 "You are now in rectify mode. In rectify mode, the Command", 516 "widget has these options:", 517 "", 518 " Cut", 519 " Help", 520 " Dismiss", 521 "", 522 "You can make adjustments by moving the pointer to one of the", 523 "cut rectangle corners, pressing a button, and dragging.", 524 "Finally, press Cut to commit your copy region. To", 525 "exit without cutting the image, press Dismiss.", 526 (char *) NULL, 527 }, 528 *ImageCopyHelp[] = 529 { 530 "In copy mode, the Command widget has these options:", 531 "", 532 " Help", 533 " Dismiss", 534 "", 535 "To define a copy region, press button 1 and drag. The", 536 "copy region is defined by a highlighted rectangle that", 537 "expands or contracts as it follows the pointer. Once you", 538 "are satisfied with the copy region, release the button.", 539 "You are now in rectify mode. In rectify mode, the Command", 540 "widget has these options:", 541 "", 542 " Copy", 543 " Help", 544 " Dismiss", 545 "", 546 "You can make adjustments by moving the pointer to one of the", 547 "copy rectangle corners, pressing a button, and dragging.", 548 "Finally, press Copy to commit your copy region. To", 549 "exit without copying the image, press Dismiss.", 550 (char *) NULL, 551 }, 552 *ImageCropHelp[] = 553 { 554 "In crop mode, the Command widget has these options:", 555 "", 556 " Help", 557 " Dismiss", 558 "", 559 "To define a cropping region, press button 1 and drag. The", 560 "cropping region is defined by a highlighted rectangle that", 561 "expands or contracts as it follows the pointer. Once you", 562 "are satisfied with the cropping region, release the button.", 563 "You are now in rectify mode. In rectify mode, the Command", 564 "widget has these options:", 565 "", 566 " Crop", 567 " Help", 568 " Dismiss", 569 "", 570 "You can make adjustments by moving the pointer to one of the", 571 "cropping rectangle corners, pressing a button, and dragging.", 572 "Finally, press Crop to commit your cropping region. To", 573 "exit without cropping the image, press Dismiss.", 574 (char *) NULL, 575 }, 576 *ImageDrawHelp[] = 577 { 578 "The cursor changes to a crosshair to indicate you are in", 579 "draw mode. To exit immediately, press Dismiss. In draw mode,", 580 "the Command widget has these options:", 581 "", 582 " Element", 583 " point", 584 " line", 585 " rectangle", 586 " fill rectangle", 587 " circle", 588 " fill circle", 589 " ellipse", 590 " fill ellipse", 591 " polygon", 592 " fill polygon", 593 " Color", 594 " black", 595 " blue", 596 " cyan", 597 " green", 598 " gray", 599 " red", 600 " magenta", 601 " yellow", 602 " white", 603 " transparent", 604 " Browser...", 605 " Stipple", 606 " Brick", 607 " Diagonal", 608 " Scales", 609 " Vertical", 610 " Wavy", 611 " Translucent", 612 " Opaque", 613 " Open...", 614 " Width", 615 " 1", 616 " 2", 617 " 4", 618 " 8", 619 " 16", 620 " Dialog...", 621 " Undo", 622 " Help", 623 " Dismiss", 624 "", 625 "Choose a drawing primitive from the Element sub-menu.", 626 "", 627 "Choose a color from the Color sub-menu. Additional", 628 "colors can be specified with the color browser.", 629 "", 630 "If you choose the color browser and press Grab, you can", 631 "select the color by moving the pointer to the desired", 632 "color on the screen and press any button. The transparent", 633 "color updates the image matte channel and is useful for", 634 "image compositing.", 635 "", 636 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 637 "Additional stipples can be specified with the file browser.", 638 "Stipples obtained from the file browser must be on disk in the", 639 "X11 bitmap format.", 640 "", 641 "Choose a width, if appropriate, from the Width sub-menu. To", 642 "choose a specific width select the Dialog widget.", 643 "", 644 "Choose a point in the Image window and press button 1 and", 645 "hold. Next, move the pointer to another location in the", 646 "image. As you move, a line connects the initial location and", 647 "the pointer. When you release the button, the image is", 648 "updated with the primitive you just drew. For polygons, the", 649 "image is updated when you press and release the button without", 650 "moving the pointer.", 651 "", 652 "To cancel image drawing, move the pointer back to the", 653 "starting point of the line and release the button.", 654 (char *) NULL, 655 }, 656 *DisplayHelp[] = 657 { 658 "BUTTONS", 659 " The effects of each button press is described below. Three", 660 " buttons are required. If you have a two button mouse,", 661 " button 1 and 3 are returned. Press ALT and button 3 to", 662 " simulate button 2.", 663 "", 664 " 1 Press this button to map or unmap the Command widget.", 665 "", 666 " 2 Press and drag to define a region of the image to", 667 " magnify.", 668 "", 669 " 3 Press and drag to choose from a select set of commands.", 670 " This button behaves differently if the image being", 671 " displayed is a visual image directory. Here, choose a", 672 " particular tile of the directory and press this button and", 673 " drag to select a command from a pop-up menu. Choose from", 674 " these menu items:", 675 "", 676 " Open", 677 " Next", 678 " Former", 679 " Delete", 680 " Update", 681 "", 682 " If you choose Open, the image represented by the tile is", 683 " displayed. To return to the visual image directory, choose", 684 " Next from the Command widget. Next and Former moves to the", 685 " next or former image respectively. Choose Delete to delete", 686 " a particular image tile. Finally, choose Update to", 687 " synchronize all the image tiles with their respective", 688 " images.", 689 "", 690 "COMMAND WIDGET", 691 " The Command widget lists a number of sub-menus and commands.", 692 " They are", 693 "", 694 " File", 695 " Open...", 696 " Next", 697 " Former", 698 " Select...", 699 " Save...", 700 " Print...", 701 " Delete...", 702 " New...", 703 " Visual Directory...", 704 " Quit", 705 " Edit", 706 " Undo", 707 " Redo", 708 " Cut", 709 " Copy", 710 " Paste", 711 " View", 712 " Half Size", 713 " Original Size", 714 " Double Size", 715 " Resize...", 716 " Apply", 717 " Refresh", 718 " Restore", 719 " Transform", 720 " Crop", 721 " Chop", 722 " Flop", 723 " Flip", 724 " Rotate Right", 725 " Rotate Left", 726 " Rotate...", 727 " Shear...", 728 " Roll...", 729 " Trim Edges", 730 " Enhance", 731 " Brightness...", 732 " Saturation...", 733 " Hue...", 734 " Gamma...", 735 " Sharpen...", 736 " Dull", 737 " Contrast Stretch...", 738 " Sigmoidal Contrast...", 739 " Normalize", 740 " Equalize", 741 " Negate", 742 " Grayscale", 743 " Map...", 744 " Quantize...", 745 " Effects", 746 " Despeckle", 747 " Emboss", 748 " Reduce Noise", 749 " Add Noise", 750 " Sharpen...", 751 " Blur...", 752 " Threshold...", 753 " Edge Detect...", 754 " Spread...", 755 " Shade...", 756 " Painting...", 757 " Segment...", 758 " F/X", 759 " Solarize...", 760 " Sepia Tone...", 761 " Swirl...", 762 " Implode...", 763 " Vignette...", 764 " Wave...", 765 " Oil Painting...", 766 " Charcoal Drawing...", 767 " Image Edit", 768 " Annotate...", 769 " Draw...", 770 " Color...", 771 " Matte...", 772 " Composite...", 773 " Add Border...", 774 " Add Frame...", 775 " Comment...", 776 " Launch...", 777 " Region of Interest...", 778 " Miscellany", 779 " Image Info", 780 " Zoom Image", 781 " Show Preview...", 782 " Show Histogram", 783 " Show Matte", 784 " Background...", 785 " Slide Show", 786 " Preferences...", 787 " Help", 788 " Overview", 789 " Browse Documentation", 790 " About Display", 791 "", 792 " Menu items with a indented triangle have a sub-menu. They", 793 " are represented above as the indented items. To access a", 794 " sub-menu item, move the pointer to the appropriate menu and", 795 " press a button and drag. When you find the desired sub-menu", 796 " item, release the button and the command is executed. Move", 797 " the pointer away from the sub-menu if you decide not to", 798 " execute a particular command.", 799 "", 800 "KEYBOARD ACCELERATORS", 801 " Accelerators are one or two key presses that effect a", 802 " particular command. The keyboard accelerators that", 803 " display(1) understands is:", 804 "", 805 " Ctl+O Press to open an image from a file.", 806 "", 807 " space Press to display the next image.", 808 "", 809 " If the image is a multi-paged document such as a Postscript", 810 " document, you can skip ahead several pages by preceding", 811 " this command with a number. For example to display the", 812 " third page beyond the current page, press 3<space>.", 813 "", 814 " backspace Press to display the former image.", 815 "", 816 " If the image is a multi-paged document such as a Postscript", 817 " document, you can skip behind several pages by preceding", 818 " this command with a number. For example to display the", 819 " third page preceding the current page, press 3<backspace>.", 820 "", 821 " Ctl+S Press to write the image to a file.", 822 "", 823 " Ctl+P Press to print the image to a Postscript printer.", 824 "", 825 " Ctl+D Press to delete an image file.", 826 "", 827 " Ctl+N Press to create a blank canvas.", 828 "", 829 " Ctl+Q Press to discard all images and exit program.", 830 "", 831 " Ctl+Z Press to undo last image transformation.", 832 "", 833 " Ctl+R Press to redo last image transformation.", 834 "", 835 " Ctl+X Press to cut a region of the image.", 836 "", 837 " Ctl+C Press to copy a region of the image.", 838 "", 839 " Ctl+V Press to paste a region to the image.", 840 "", 841 " < Press to half the image size.", 842 "", 843 " - Press to return to the original image size.", 844 "", 845 " > Press to double the image size.", 846 "", 847 " % Press to resize the image to a width and height you", 848 " specify.", 849 "", 850 "Cmd-A Press to make any image transformations permanent." 851 "", 852 " By default, any image size transformations are applied", 853 " to the original image to create the image displayed on", 854 " the X server. However, the transformations are not", 855 " permanent (i.e. the original image does not change", 856 " size only the X image does). For example, if you", 857 " press > the X image will appear to double in size,", 858 " but the original image will in fact remain the same size.", 859 " To force the original image to double in size, press >", 860 " followed by Cmd-A.", 861 "", 862 " @ Press to refresh the image window.", 863 "", 864 " C Press to cut out a rectangular region of the image.", 865 "", 866 " [ Press to chop the image.", 867 "", 868 " H Press to flop image in the horizontal direction.", 869 "", 870 " V Press to flip image in the vertical direction.", 871 "", 872 " / Press to rotate the image 90 degrees clockwise.", 873 "", 874 " \\ Press to rotate the image 90 degrees counter-clockwise.", 875 "", 876 " * Press to rotate the image the number of degrees you", 877 " specify.", 878 "", 879 " S Press to shear the image the number of degrees you", 880 " specify.", 881 "", 882 " R Press to roll the image.", 883 "", 884 " T Press to trim the image edges.", 885 "", 886 " Shft-H Press to vary the image hue.", 887 "", 888 " Shft-S Press to vary the color saturation.", 889 "", 890 " Shft-L Press to vary the color brightness.", 891 "", 892 " Shft-G Press to gamma correct the image.", 893 "", 894 " Shft-C Press to sharpen the image contrast.", 895 "", 896 " Shft-Z Press to dull the image contrast.", 897 "", 898 " = Press to perform histogram equalization on the image.", 899 "", 900 " Shft-N Press to perform histogram normalization on the image.", 901 "", 902 " Shft-~ Press to negate the colors of the image.", 903 "", 904 " . Press to convert the image colors to gray.", 905 "", 906 " Shft-# Press to set the maximum number of unique colors in the", 907 " image.", 908 "", 909 " F2 Press to reduce the speckles in an image.", 910 "", 911 " F3 Press to eliminate peak noise from an image.", 912 "", 913 " F4 Press to add noise to an image.", 914 "", 915 " F5 Press to sharpen an image.", 916 "", 917 " F6 Press to delete an image file.", 918 "", 919 " F7 Press to threshold the image.", 920 "", 921 " F8 Press to detect edges within an image.", 922 "", 923 " F9 Press to emboss an image.", 924 "", 925 " F10 Press to displace pixels by a random amount.", 926 "", 927 " F11 Press to negate all pixels above the threshold level.", 928 "", 929 " F12 Press to shade the image using a distant light source.", 930 "", 931 " F13 Press to lighten or darken image edges to create a 3-D effect.", 932 "", 933 " F14 Press to segment the image by color.", 934 "", 935 " Meta-S Press to swirl image pixels about the center.", 936 "", 937 " Meta-I Press to implode image pixels about the center.", 938 "", 939 " Meta-W Press to alter an image along a sine wave.", 940 "", 941 " Meta-P Press to simulate an oil painting.", 942 "", 943 " Meta-C Press to simulate a charcoal drawing.", 944 "", 945 " Alt-A Press to annotate the image with text.", 946 "", 947 " Alt-D Press to draw on an image.", 948 "", 949 " Alt-P Press to edit an image pixel color.", 950 "", 951 " Alt-M Press to edit the image matte information.", 952 "", 953 " Alt-V Press to composite the image with another.", 954 "", 955 " Alt-B Press to add a border to the image.", 956 "", 957 " Alt-F Press to add an ornamental border to the image.", 958 "", 959 " Alt-Shft-!", 960 " Press to add an image comment.", 961 "", 962 " Ctl-A Press to apply image processing techniques to a region", 963 " of interest.", 964 "", 965 " Shft-? Press to display information about the image.", 966 "", 967 " Shft-+ Press to map the zoom image window.", 968 "", 969 " Shft-P Press to preview an image enhancement, effect, or f/x.", 970 "", 971 " F1 Press to display helpful information about display(1).", 972 "", 973 " Find Press to browse documentation about ImageMagick.", 974 "", 975 " 1-9 Press to change the level of magnification.", 976 "", 977 " Use the arrow keys to move the image one pixel up, down,", 978 " left, or right within the magnify window. Be sure to first", 979 " map the magnify window by pressing button 2.", 980 "", 981 " Press ALT and one of the arrow keys to trim off one pixel", 982 " from any side of the image.", 983 (char *) NULL, 984 }, 985 *ImageMatteEditHelp[] = 986 { 987 "Matte information within an image is useful for some", 988 "operations such as image compositing (See IMAGE", 989 "COMPOSITING). This extra channel usually defines a mask", 990 "which represents a sort of a cookie-cutter for the image.", 991 "This the case when matte is opaque (full coverage) for", 992 "pixels inside the shape, zero outside, and between 0 and", 993 "QuantumRange on the boundary.", 994 "", 995 "A small window appears showing the location of the cursor in", 996 "the image window. You are now in matte edit mode. To exit", 997 "immediately, press Dismiss. In matte edit mode, the Command", 998 "widget has these options:", 999 "", 1000 " Method", 1001 " point", 1002 " replace", 1003 " floodfill", 1004 " filltoborder", 1005 " reset", 1006 " Border Color", 1007 " black", 1008 " blue", 1009 " cyan", 1010 " green", 1011 " gray", 1012 " red", 1013 " magenta", 1014 " yellow", 1015 " white", 1016 " Browser...", 1017 " Fuzz", 1018 " 0%", 1019 " 2%", 1020 " 5%", 1021 " 10%", 1022 " 15%", 1023 " Dialog...", 1024 " Matte", 1025 " Opaque", 1026 " Transparent", 1027 " Dialog...", 1028 " Undo", 1029 " Help", 1030 " Dismiss", 1031 "", 1032 "Choose a matte editing method from the Method sub-menu of", 1033 "the Command widget. The point method changes the matte value", 1034 "of any pixel selected with the pointer until the button is", 1035 "is released. The replace method changes the matte value of", 1036 "any pixel that matches the color of the pixel you select with", 1037 "a button press. Floodfill changes the matte value of any pixel", 1038 "that matches the color of the pixel you select with a button", 1039 "press and is a neighbor. Whereas filltoborder changes the matte", 1040 "value any neighbor pixel that is not the border color. Finally", 1041 "reset changes the entire image to the designated matte value.", 1042 "", 1043 "Choose Matte Value and pick Opaque or Transarent. For other values", 1044 "select the Dialog entry. Here a dialog appears requesting a matte", 1045 "value. The value you select is assigned as the opacity value of the", 1046 "selected pixel or pixels.", 1047 "", 1048 "Now, press any button to select a pixel within the image", 1049 "window to change its matte value.", 1050 "", 1051 "If the Magnify widget is mapped, it can be helpful in positioning", 1052 "your pointer within the image (refer to button 2).", 1053 "", 1054 "Matte information is only valid in a DirectClass image.", 1055 "Therefore, any PseudoClass image is promoted to DirectClass", 1056 "(see miff(5)). Note that matte information for PseudoClass", 1057 "is not retained for colormapped X server visuals (e.g.", 1058 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1059 "immediately save your image to a file (refer to Write).", 1060 "Correct matte editing behavior may require a TrueColor or", 1061 "DirectColor visual or a Standard Colormap.", 1062 (char *) NULL, 1063 }, 1064 *ImagePanHelp[] = 1065 { 1066 "When an image exceeds the width or height of the X server", 1067 "screen, display maps a small panning icon. The rectangle", 1068 "within the panning icon shows the area that is currently", 1069 "displayed in the image window. To pan about the image,", 1070 "press any button and drag the pointer within the panning", 1071 "icon. The pan rectangle moves with the pointer and the", 1072 "image window is updated to reflect the location of the", 1073 "rectangle within the panning icon. When you have selected", 1074 "the area of the image you wish to view, release the button.", 1075 "", 1076 "Use the arrow keys to pan the image one pixel up, down,", 1077 "left, or right within the image window.", 1078 "", 1079 "The panning icon is withdrawn if the image becomes smaller", 1080 "than the dimensions of the X server screen.", 1081 (char *) NULL, 1082 }, 1083 *ImagePasteHelp[] = 1084 { 1085 "A small window appears showing the location of the cursor in", 1086 "the image window. You are now in paste mode. To exit", 1087 "immediately, press Dismiss. In paste mode, the Command", 1088 "widget has these options:", 1089 "", 1090 " Operators", 1091 " over", 1092 " in", 1093 " out", 1094 " atop", 1095 " xor", 1096 " plus", 1097 " minus", 1098 " add", 1099 " subtract", 1100 " difference", 1101 " replace", 1102 " Help", 1103 " Dismiss", 1104 "", 1105 "Choose a composite operation from the Operators sub-menu of", 1106 "the Command widget. How each operator behaves is described", 1107 "below. Image window is the image currently displayed on", 1108 "your X server and image is the image obtained with the File", 1109 "Browser widget.", 1110 "", 1111 "Over The result is the union of the two image shapes,", 1112 " with image obscuring image window in the region of", 1113 " overlap.", 1114 "", 1115 "In The result is simply image cut by the shape of", 1116 " image window. None of the image data of image", 1117 " window is in the result.", 1118 "", 1119 "Out The resulting image is image with the shape of", 1120 " image window cut out.", 1121 "", 1122 "Atop The result is the same shape as image image window,", 1123 " with image obscuring image window where the image", 1124 " shapes overlap. Note this differs from over", 1125 " because the portion of image outside image window's", 1126 " shape does not appear in the result.", 1127 "", 1128 "Xor The result is the image data from both image and", 1129 " image window that is outside the overlap region.", 1130 " The overlap region is blank.", 1131 "", 1132 "Plus The result is just the sum of the image data.", 1133 " Output values are cropped to QuantumRange (no overflow).", 1134 " This operation is independent of the matte", 1135 " channels.", 1136 "", 1137 "Minus The result of image - image window, with underflow", 1138 " cropped to zero.", 1139 "", 1140 "Add The result of image + image window, with overflow", 1141 " wrapping around (mod 256).", 1142 "", 1143 "Subtract The result of image - image window, with underflow", 1144 " wrapping around (mod 256). The add and subtract", 1145 " operators can be used to perform reversible", 1146 " transformations.", 1147 "", 1148 "Difference", 1149 " The result of abs(image - image window). This", 1150 " useful for comparing two very similar images.", 1151 "", 1152 "Copy The resulting image is image window replaced with", 1153 " image. Here the matte information is ignored.", 1154 "", 1155 "CopyRed The red layer of the image window is replace with", 1156 " the red layer of the image. The other layers are", 1157 " untouched.", 1158 "", 1159 "CopyGreen", 1160 " The green layer of the image window is replace with", 1161 " the green layer of the image. The other layers are", 1162 " untouched.", 1163 "", 1164 "CopyBlue The blue layer of the image window is replace with", 1165 " the blue layer of the image. The other layers are", 1166 " untouched.", 1167 "", 1168 "CopyOpacity", 1169 " The matte layer of the image window is replace with", 1170 " the matte layer of the image. The other layers are", 1171 " untouched.", 1172 "", 1173 "The image compositor requires a matte, or alpha channel in", 1174 "the image for some operations. This extra channel usually", 1175 "defines a mask which represents a sort of a cookie-cutter", 1176 "for the image. This the case when matte is opaque (full", 1177 "coverage) for pixels inside the shape, zero outside, and", 1178 "between 0 and QuantumRange on the boundary. If image does not", 1179 "have a matte channel, it is initialized with 0 for any pixel", 1180 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1181 "", 1182 "Note that matte information for image window is not retained", 1183 "for colormapped X server visuals (e.g. StaticColor,", 1184 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1185 "behavior may require a TrueColor or DirectColor visual or a", 1186 "Standard Colormap.", 1187 "", 1188 "Choosing a composite operator is optional. The default", 1189 "operator is replace. However, you must choose a location to", 1190 "paste your image and press button 1. Press and hold the", 1191 "button before releasing and an outline of the image will", 1192 "appear to help you identify your location.", 1193 "", 1194 "The actual colors of the pasted image is saved. However,", 1195 "the color that appears in image window may be different.", 1196 "For example, on a monochrome screen image window will appear", 1197 "black or white even though your pasted image may have", 1198 "many colors. If the image is saved to a file it is written", 1199 "with the correct colors. To assure the correct colors are", 1200 "saved in the final image, any PseudoClass image is promoted", 1201 "to DirectClass (see miff(5)). To force a PseudoClass image", 1202 "to remain PseudoClass, use -colors.", 1203 (char *) NULL, 1204 }, 1205 *ImageROIHelp[] = 1206 { 1207 "In region of interest mode, the Command widget has these", 1208 "options:", 1209 "", 1210 " Help", 1211 " Dismiss", 1212 "", 1213 "To define a region of interest, press button 1 and drag.", 1214 "The region of interest is defined by a highlighted rectangle", 1215 "that expands or contracts as it follows the pointer. Once", 1216 "you are satisfied with the region of interest, release the", 1217 "button. You are now in apply mode. In apply mode the", 1218 "Command widget has these options:", 1219 "", 1220 " File", 1221 " Save...", 1222 " Print...", 1223 " Edit", 1224 " Undo", 1225 " Redo", 1226 " Transform", 1227 " Flop", 1228 " Flip", 1229 " Rotate Right", 1230 " Rotate Left", 1231 " Enhance", 1232 " Hue...", 1233 " Saturation...", 1234 " Brightness...", 1235 " Gamma...", 1236 " Spiff", 1237 " Dull", 1238 " Contrast Stretch", 1239 " Sigmoidal Contrast...", 1240 " Normalize", 1241 " Equalize", 1242 " Negate", 1243 " Grayscale", 1244 " Map...", 1245 " Quantize...", 1246 " Effects", 1247 " Despeckle", 1248 " Emboss", 1249 " Reduce Noise", 1250 " Sharpen...", 1251 " Blur...", 1252 " Threshold...", 1253 " Edge Detect...", 1254 " Spread...", 1255 " Shade...", 1256 " Raise...", 1257 " Segment...", 1258 " F/X", 1259 " Solarize...", 1260 " Sepia Tone...", 1261 " Swirl...", 1262 " Implode...", 1263 " Vignette...", 1264 " Wave...", 1265 " Oil Painting...", 1266 " Charcoal Drawing...", 1267 " Miscellany", 1268 " Image Info", 1269 " Zoom Image", 1270 " Show Preview...", 1271 " Show Histogram", 1272 " Show Matte", 1273 " Help", 1274 " Dismiss", 1275 "", 1276 "You can make adjustments to the region of interest by moving", 1277 "the pointer to one of the rectangle corners, pressing a", 1278 "button, and dragging. Finally, choose an image processing", 1279 "technique from the Command widget. You can choose more than", 1280 "one image processing technique to apply to an area.", 1281 "Alternatively, you can move the region of interest before", 1282 "applying another image processing technique. To exit, press", 1283 "Dismiss.", 1284 (char *) NULL, 1285 }, 1286 *ImageRotateHelp[] = 1287 { 1288 "In rotate mode, the Command widget has these options:", 1289 "", 1290 " Pixel Color", 1291 " black", 1292 " blue", 1293 " cyan", 1294 " green", 1295 " gray", 1296 " red", 1297 " magenta", 1298 " yellow", 1299 " white", 1300 " Browser...", 1301 " Direction", 1302 " horizontal", 1303 " vertical", 1304 " Help", 1305 " Dismiss", 1306 "", 1307 "Choose a background color from the Pixel Color sub-menu.", 1308 "Additional background colors can be specified with the color", 1309 "browser. You can change the menu colors by setting the X", 1310 "resources pen1 through pen9.", 1311 "", 1312 "If you choose the color browser and press Grab, you can", 1313 "select the background color by moving the pointer to the", 1314 "desired color on the screen and press any button.", 1315 "", 1316 "Choose a point in the image window and press this button and", 1317 "hold. Next, move the pointer to another location in the", 1318 "image. As you move a line connects the initial location and", 1319 "the pointer. When you release the button, the degree of", 1320 "image rotation is determined by the slope of the line you", 1321 "just drew. The slope is relative to the direction you", 1322 "choose from the Direction sub-menu of the Command widget.", 1323 "", 1324 "To cancel the image rotation, move the pointer back to the", 1325 "starting point of the line and release the button.", 1326 (char *) NULL, 1327 }; 1328 1329/* 1330 Enumeration declarations. 1331*/ 1332typedef enum 1333{ 1334 CopyMode, 1335 CropMode, 1336 CutMode 1337} ClipboardMode; 1338 1339typedef enum 1340{ 1341 OpenCommand, 1342 NextCommand, 1343 FormerCommand, 1344 SelectCommand, 1345 SaveCommand, 1346 PrintCommand, 1347 DeleteCommand, 1348 NewCommand, 1349 VisualDirectoryCommand, 1350 QuitCommand, 1351 UndoCommand, 1352 RedoCommand, 1353 CutCommand, 1354 CopyCommand, 1355 PasteCommand, 1356 HalfSizeCommand, 1357 OriginalSizeCommand, 1358 DoubleSizeCommand, 1359 ResizeCommand, 1360 ApplyCommand, 1361 RefreshCommand, 1362 RestoreCommand, 1363 CropCommand, 1364 ChopCommand, 1365 FlopCommand, 1366 FlipCommand, 1367 RotateRightCommand, 1368 RotateLeftCommand, 1369 RotateCommand, 1370 ShearCommand, 1371 RollCommand, 1372 TrimCommand, 1373 HueCommand, 1374 SaturationCommand, 1375 BrightnessCommand, 1376 GammaCommand, 1377 SpiffCommand, 1378 DullCommand, 1379 ContrastStretchCommand, 1380 SigmoidalContrastCommand, 1381 NormalizeCommand, 1382 EqualizeCommand, 1383 NegateCommand, 1384 GrayscaleCommand, 1385 MapCommand, 1386 QuantizeCommand, 1387 DespeckleCommand, 1388 EmbossCommand, 1389 ReduceNoiseCommand, 1390 AddNoiseCommand, 1391 SharpenCommand, 1392 BlurCommand, 1393 ThresholdCommand, 1394 EdgeDetectCommand, 1395 SpreadCommand, 1396 ShadeCommand, 1397 RaiseCommand, 1398 SegmentCommand, 1399 SolarizeCommand, 1400 SepiaToneCommand, 1401 SwirlCommand, 1402 ImplodeCommand, 1403 VignetteCommand, 1404 WaveCommand, 1405 OilPaintCommand, 1406 CharcoalDrawCommand, 1407 AnnotateCommand, 1408 DrawCommand, 1409 ColorCommand, 1410 MatteCommand, 1411 CompositeCommand, 1412 AddBorderCommand, 1413 AddFrameCommand, 1414 CommentCommand, 1415 LaunchCommand, 1416 RegionofInterestCommand, 1417 ROIHelpCommand, 1418 ROIDismissCommand, 1419 InfoCommand, 1420 ZoomCommand, 1421 ShowPreviewCommand, 1422 ShowHistogramCommand, 1423 ShowMatteCommand, 1424 BackgroundCommand, 1425 SlideShowCommand, 1426 PreferencesCommand, 1427 HelpCommand, 1428 BrowseDocumentationCommand, 1429 VersionCommand, 1430 SaveToUndoBufferCommand, 1431 FreeBuffersCommand, 1432 NullCommand 1433} CommandType; 1434 1435typedef enum 1436{ 1437 AnnotateNameCommand, 1438 AnnotateFontColorCommand, 1439 AnnotateBackgroundColorCommand, 1440 AnnotateRotateCommand, 1441 AnnotateHelpCommand, 1442 AnnotateDismissCommand, 1443 TextHelpCommand, 1444 TextApplyCommand, 1445 ChopDirectionCommand, 1446 ChopHelpCommand, 1447 ChopDismissCommand, 1448 HorizontalChopCommand, 1449 VerticalChopCommand, 1450 ColorEditMethodCommand, 1451 ColorEditColorCommand, 1452 ColorEditBorderCommand, 1453 ColorEditFuzzCommand, 1454 ColorEditUndoCommand, 1455 ColorEditHelpCommand, 1456 ColorEditDismissCommand, 1457 CompositeOperatorsCommand, 1458 CompositeDissolveCommand, 1459 CompositeDisplaceCommand, 1460 CompositeHelpCommand, 1461 CompositeDismissCommand, 1462 CropHelpCommand, 1463 CropDismissCommand, 1464 RectifyCopyCommand, 1465 RectifyHelpCommand, 1466 RectifyDismissCommand, 1467 DrawElementCommand, 1468 DrawColorCommand, 1469 DrawStippleCommand, 1470 DrawWidthCommand, 1471 DrawUndoCommand, 1472 DrawHelpCommand, 1473 DrawDismissCommand, 1474 MatteEditMethod, 1475 MatteEditBorderCommand, 1476 MatteEditFuzzCommand, 1477 MatteEditValueCommand, 1478 MatteEditUndoCommand, 1479 MatteEditHelpCommand, 1480 MatteEditDismissCommand, 1481 PasteOperatorsCommand, 1482 PasteHelpCommand, 1483 PasteDismissCommand, 1484 RotateColorCommand, 1485 RotateDirectionCommand, 1486 RotateCropCommand, 1487 RotateSharpenCommand, 1488 RotateHelpCommand, 1489 RotateDismissCommand, 1490 HorizontalRotateCommand, 1491 VerticalRotateCommand, 1492 TileLoadCommand, 1493 TileNextCommand, 1494 TileFormerCommand, 1495 TileDeleteCommand, 1496 TileUpdateCommand 1497} ModeType; 1498 1499/* 1500 Stipples. 1501*/ 1502#define BricksWidth 20 1503#define BricksHeight 20 1504#define DiagonalWidth 16 1505#define DiagonalHeight 16 1506#define HighlightWidth 8 1507#define HighlightHeight 8 1508#define OpaqueWidth 8 1509#define OpaqueHeight 8 1510#define ScalesWidth 16 1511#define ScalesHeight 16 1512#define ShadowWidth 8 1513#define ShadowHeight 8 1514#define VerticalWidth 16 1515#define VerticalHeight 16 1516#define WavyWidth 16 1517#define WavyHeight 16 1518 1519/* 1520 Constant declaration. 1521*/ 1522static const int 1523 RoiDelta = 8; 1524 1525static const unsigned char 1526 BricksBitmap[] = 1527 { 1528 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1529 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1530 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1531 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1532 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1533 }, 1534 DiagonalBitmap[] = 1535 { 1536 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1537 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1538 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1539 }, 1540 ScalesBitmap[] = 1541 { 1542 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1543 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1544 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1545 }, 1546 VerticalBitmap[] = 1547 { 1548 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1549 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1550 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1551 }, 1552 WavyBitmap[] = 1553 { 1554 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1555 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1556 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1557 }; 1558 1559/* 1560 Function prototypes. 1561*/ 1562static CommandType 1563 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1564 const MagickStatusType,KeySym,Image **); 1565 1566static Image 1567 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1568 Image **), 1569 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1570 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *), 1571 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *); 1572 1573static MagickBooleanType 1574 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *), 1575 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1576 XChopImage(Display *,XResourceInfo *,XWindows *,Image **), 1577 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode), 1578 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **), 1579 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1580 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *), 1581 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *), 1582 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **), 1583 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *), 1584 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *), 1585 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **), 1586 XROIImage(Display *,XResourceInfo *,XWindows *,Image **), 1587 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *), 1588 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *); 1589 1590static void 1591 XDrawPanRectangle(Display *,XWindows *), 1592 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **), 1593 XMagnifyImage(Display *,XWindows *,XEvent *), 1594 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *), 1595 XPanImage(Display *,XWindows *,XEvent *), 1596 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1597 const KeySym), 1598 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1599 XScreenEvent(Display *,XWindows *,XEvent *), 1600 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1601 1602/* 1603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1604% % 1605% % 1606% % 1607% D i s p l a y I m a g e s % 1608% % 1609% % 1610% % 1611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1612% 1613% DisplayImages() displays an image sequence to any X window screen. It 1614% returns a value other than 0 if successful. Check the exception member 1615% of image to determine the reason for any failure. 1616% 1617% The format of the DisplayImages method is: 1618% 1619% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1620% Image *images) 1621% 1622% A description of each parameter follows: 1623% 1624% o image_info: the image info. 1625% 1626% o image: the image. 1627% 1628*/ 1629MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1630 Image *images) 1631{ 1632 char 1633 *argv[1]; 1634 1635 Display 1636 *display; 1637 1638 Image 1639 *image; 1640 1641 register ssize_t 1642 i; 1643 1644 size_t 1645 state; 1646 1647 XrmDatabase 1648 resource_database; 1649 1650 XResourceInfo 1651 resource_info; 1652 1653 assert(image_info != (const ImageInfo *) NULL); 1654 assert(image_info->signature == MagickSignature); 1655 assert(images != (Image *) NULL); 1656 assert(images->signature == MagickSignature); 1657 if (images->debug != MagickFalse) 1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1659 display=XOpenDisplay(image_info->server_name); 1660 if (display == (Display *) NULL) 1661 { 1662 (void) ThrowMagickException(&images->exception,GetMagickModule(), 1663 XServerError,"UnableToOpenXServer","`%s'",XDisplayName( 1664 image_info->server_name)); 1665 return(MagickFalse); 1666 } 1667 if (images->exception.severity != UndefinedException) 1668 CatchException(&images->exception); 1669 (void) XSetErrorHandler(XError); 1670 resource_database=XGetResourceDatabase(display,GetClientName()); 1671 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1672 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1673 if (image_info->page != (char *) NULL) 1674 resource_info.image_geometry=AcquireString(image_info->page); 1675 resource_info.immutable=MagickTrue; 1676 argv[0]=AcquireString(GetClientName()); 1677 state=DefaultState; 1678 for (i=0; (state & ExitState) == 0; i++) 1679 { 1680 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1681 break; 1682 image=GetImageFromList(images,i % GetImageListLength(images)); 1683 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state); 1684 } 1685 argv[0]=DestroyString(argv[0]); 1686 (void) XCloseDisplay(display); 1687 XDestroyResourceInfo(&resource_info); 1688 if (images->exception.severity != UndefinedException) 1689 return(MagickFalse); 1690 return(MagickTrue); 1691} 1692 1693/* 1694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1695% % 1696% % 1697% % 1698% R e m o t e D i s p l a y C o m m a n d % 1699% % 1700% % 1701% % 1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1703% 1704% RemoteDisplayCommand() encourages a remote display program to display the 1705% specified image filename. 1706% 1707% The format of the RemoteDisplayCommand method is: 1708% 1709% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1710% const char *window,const char *filename,ExceptionInfo *exception) 1711% 1712% A description of each parameter follows: 1713% 1714% o image_info: the image info. 1715% 1716% o window: Specifies the name or id of an X window. 1717% 1718% o filename: the name of the image filename to display. 1719% 1720% o exception: return any errors or warnings in this structure. 1721% 1722*/ 1723MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1724 const char *window,const char *filename,ExceptionInfo *exception) 1725{ 1726 Display 1727 *display; 1728 1729 MagickStatusType 1730 status; 1731 1732 assert(image_info != (const ImageInfo *) NULL); 1733 assert(image_info->signature == MagickSignature); 1734 assert(filename != (char *) NULL); 1735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1736 display=XOpenDisplay(image_info->server_name); 1737 if (display == (Display *) NULL) 1738 { 1739 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1740 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1741 return(MagickFalse); 1742 } 1743 (void) XSetErrorHandler(XError); 1744 status=XRemoteCommand(display,window,filename); 1745 (void) XCloseDisplay(display); 1746 return(status != 0 ? MagickTrue : MagickFalse); 1747} 1748 1749/* 1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1751% % 1752% % 1753% % 1754+ X A n n o t a t e E d i t I m a g e % 1755% % 1756% % 1757% % 1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1759% 1760% XAnnotateEditImage() annotates the image with text. 1761% 1762% The format of the XAnnotateEditImage method is: 1763% 1764% MagickBooleanType XAnnotateEditImage(Display *display, 1765% XResourceInfo *resource_info,XWindows *windows,Image *image) 1766% 1767% A description of each parameter follows: 1768% 1769% o display: Specifies a connection to an X server; returned from 1770% XOpenDisplay. 1771% 1772% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1773% 1774% o windows: Specifies a pointer to a XWindows structure. 1775% 1776% o image: the image; returned from ReadImage. 1777% 1778*/ 1779 1780static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1781{ 1782 if (x > y) 1783 return(x); 1784 return(y); 1785} 1786 1787static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1788{ 1789 if (x < y) 1790 return(x); 1791 return(y); 1792} 1793 1794static MagickBooleanType XAnnotateEditImage(Display *display, 1795 XResourceInfo *resource_info,XWindows *windows,Image *image) 1796{ 1797 static const char 1798 *AnnotateMenu[] = 1799 { 1800 "Font Name", 1801 "Font Color", 1802 "Box Color", 1803 "Rotate Text", 1804 "Help", 1805 "Dismiss", 1806 (char *) NULL 1807 }, 1808 *TextMenu[] = 1809 { 1810 "Help", 1811 "Apply", 1812 (char *) NULL 1813 }; 1814 1815 static const ModeType 1816 AnnotateCommands[] = 1817 { 1818 AnnotateNameCommand, 1819 AnnotateFontColorCommand, 1820 AnnotateBackgroundColorCommand, 1821 AnnotateRotateCommand, 1822 AnnotateHelpCommand, 1823 AnnotateDismissCommand 1824 }, 1825 TextCommands[] = 1826 { 1827 TextHelpCommand, 1828 TextApplyCommand 1829 }; 1830 1831 static MagickBooleanType 1832 transparent_box = MagickTrue, 1833 transparent_pen = MagickFalse; 1834 1835 static MagickRealType 1836 degrees = 0.0; 1837 1838 static unsigned int 1839 box_id = MaxNumberPens-2, 1840 font_id = 0, 1841 pen_id = 0; 1842 1843 char 1844 command[MaxTextExtent], 1845 text[MaxTextExtent]; 1846 1847 const char 1848 *ColorMenu[MaxNumberPens+1]; 1849 1850 Cursor 1851 cursor; 1852 1853 GC 1854 annotate_context; 1855 1856 int 1857 id, 1858 pen_number, 1859 status, 1860 x, 1861 y; 1862 1863 KeySym 1864 key_symbol; 1865 1866 register char 1867 *p; 1868 1869 register ssize_t 1870 i; 1871 1872 unsigned int 1873 height, 1874 width; 1875 1876 size_t 1877 state; 1878 1879 XAnnotateInfo 1880 *annotate_info, 1881 *previous_info; 1882 1883 XColor 1884 color; 1885 1886 XFontStruct 1887 *font_info; 1888 1889 XEvent 1890 event, 1891 text_event; 1892 1893 /* 1894 Map Command widget. 1895 */ 1896 (void) CloneString(&windows->command.name,"Annotate"); 1897 windows->command.data=4; 1898 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1899 (void) XMapRaised(display,windows->command.id); 1900 XClientMessage(display,windows->image.id,windows->im_protocols, 1901 windows->im_update_widget,CurrentTime); 1902 /* 1903 Track pointer until button 1 is pressed. 1904 */ 1905 XQueryPosition(display,windows->image.id,&x,&y); 1906 (void) XSelectInput(display,windows->image.id, 1907 windows->image.attributes.event_mask | PointerMotionMask); 1908 cursor=XCreateFontCursor(display,XC_left_side); 1909 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1910 state=DefaultState; 1911 do 1912 { 1913 if (windows->info.mapped != MagickFalse) 1914 { 1915 /* 1916 Display pointer position. 1917 */ 1918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1919 x+windows->image.x,y+windows->image.y); 1920 XInfoWidget(display,windows,text); 1921 } 1922 /* 1923 Wait for next event. 1924 */ 1925 XScreenEvent(display,windows,&event); 1926 if (event.xany.window == windows->command.id) 1927 { 1928 /* 1929 Select a command from the Command widget. 1930 */ 1931 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1933 if (id < 0) 1934 continue; 1935 switch (AnnotateCommands[id]) 1936 { 1937 case AnnotateNameCommand: 1938 { 1939 const char 1940 *FontMenu[MaxNumberFonts]; 1941 1942 int 1943 font_number; 1944 1945 /* 1946 Initialize menu selections. 1947 */ 1948 for (i=0; i < MaxNumberFonts; i++) 1949 FontMenu[i]=resource_info->font_name[i]; 1950 FontMenu[MaxNumberFonts-2]="Browser..."; 1951 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1952 /* 1953 Select a font name from the pop-up menu. 1954 */ 1955 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1956 (const char **) FontMenu,command); 1957 if (font_number < 0) 1958 break; 1959 if (font_number == (MaxNumberFonts-2)) 1960 { 1961 static char 1962 font_name[MaxTextExtent] = "fixed"; 1963 1964 /* 1965 Select a font name from a browser. 1966 */ 1967 resource_info->font_name[font_number]=font_name; 1968 XFontBrowserWidget(display,windows,"Select",font_name); 1969 if (*font_name == '\0') 1970 break; 1971 } 1972 /* 1973 Initialize font info. 1974 */ 1975 font_info=XLoadQueryFont(display,resource_info->font_name[ 1976 font_number]); 1977 if (font_info == (XFontStruct *) NULL) 1978 { 1979 XNoticeWidget(display,windows,"Unable to load font:", 1980 resource_info->font_name[font_number]); 1981 break; 1982 } 1983 font_id=(unsigned int) font_number; 1984 (void) XFreeFont(display,font_info); 1985 break; 1986 } 1987 case AnnotateFontColorCommand: 1988 { 1989 /* 1990 Initialize menu selections. 1991 */ 1992 for (i=0; i < (int) (MaxNumberPens-2); i++) 1993 ColorMenu[i]=resource_info->pen_colors[i]; 1994 ColorMenu[MaxNumberPens-2]="transparent"; 1995 ColorMenu[MaxNumberPens-1]="Browser..."; 1996 ColorMenu[MaxNumberPens]=(const char *) NULL; 1997 /* 1998 Select a pen color from the pop-up menu. 1999 */ 2000 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2001 (const char **) ColorMenu,command); 2002 if (pen_number < 0) 2003 break; 2004 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2005 MagickFalse; 2006 if (transparent_pen != MagickFalse) 2007 break; 2008 if (pen_number == (MaxNumberPens-1)) 2009 { 2010 static char 2011 color_name[MaxTextExtent] = "gray"; 2012 2013 /* 2014 Select a pen color from a dialog. 2015 */ 2016 resource_info->pen_colors[pen_number]=color_name; 2017 XColorBrowserWidget(display,windows,"Select",color_name); 2018 if (*color_name == '\0') 2019 break; 2020 } 2021 /* 2022 Set pen color. 2023 */ 2024 (void) XParseColor(display,windows->map_info->colormap, 2025 resource_info->pen_colors[pen_number],&color); 2026 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2027 (unsigned int) MaxColors,&color); 2028 windows->pixel_info->pen_colors[pen_number]=color; 2029 pen_id=(unsigned int) pen_number; 2030 break; 2031 } 2032 case AnnotateBackgroundColorCommand: 2033 { 2034 /* 2035 Initialize menu selections. 2036 */ 2037 for (i=0; i < (int) (MaxNumberPens-2); i++) 2038 ColorMenu[i]=resource_info->pen_colors[i]; 2039 ColorMenu[MaxNumberPens-2]="transparent"; 2040 ColorMenu[MaxNumberPens-1]="Browser..."; 2041 ColorMenu[MaxNumberPens]=(const char *) NULL; 2042 /* 2043 Select a pen color from the pop-up menu. 2044 */ 2045 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2046 (const char **) ColorMenu,command); 2047 if (pen_number < 0) 2048 break; 2049 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2050 MagickFalse; 2051 if (transparent_box != MagickFalse) 2052 break; 2053 if (pen_number == (MaxNumberPens-1)) 2054 { 2055 static char 2056 color_name[MaxTextExtent] = "gray"; 2057 2058 /* 2059 Select a pen color from a dialog. 2060 */ 2061 resource_info->pen_colors[pen_number]=color_name; 2062 XColorBrowserWidget(display,windows,"Select",color_name); 2063 if (*color_name == '\0') 2064 break; 2065 } 2066 /* 2067 Set pen color. 2068 */ 2069 (void) XParseColor(display,windows->map_info->colormap, 2070 resource_info->pen_colors[pen_number],&color); 2071 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2072 (unsigned int) MaxColors,&color); 2073 windows->pixel_info->pen_colors[pen_number]=color; 2074 box_id=(unsigned int) pen_number; 2075 break; 2076 } 2077 case AnnotateRotateCommand: 2078 { 2079 int 2080 entry; 2081 2082 static char 2083 angle[MaxTextExtent] = "30.0"; 2084 2085 static const char 2086 *RotateMenu[] = 2087 { 2088 "-90", 2089 "-45", 2090 "-30", 2091 "0", 2092 "30", 2093 "45", 2094 "90", 2095 "180", 2096 "Dialog...", 2097 (char *) NULL, 2098 }; 2099 2100 /* 2101 Select a command from the pop-up menu. 2102 */ 2103 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2104 command); 2105 if (entry < 0) 2106 break; 2107 if (entry != 8) 2108 { 2109 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL); 2110 break; 2111 } 2112 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2113 angle); 2114 if (*angle == '\0') 2115 break; 2116 degrees=InterpretLocaleValue(angle,(char **) NULL); 2117 break; 2118 } 2119 case AnnotateHelpCommand: 2120 { 2121 XTextViewWidget(display,resource_info,windows,MagickFalse, 2122 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2123 break; 2124 } 2125 case AnnotateDismissCommand: 2126 { 2127 /* 2128 Prematurely exit. 2129 */ 2130 state|=EscapeState; 2131 state|=ExitState; 2132 break; 2133 } 2134 default: 2135 break; 2136 } 2137 continue; 2138 } 2139 switch (event.type) 2140 { 2141 case ButtonPress: 2142 { 2143 if (event.xbutton.button != Button1) 2144 break; 2145 if (event.xbutton.window != windows->image.id) 2146 break; 2147 /* 2148 Change to text entering mode. 2149 */ 2150 x=event.xbutton.x; 2151 y=event.xbutton.y; 2152 state|=ExitState; 2153 break; 2154 } 2155 case ButtonRelease: 2156 break; 2157 case Expose: 2158 break; 2159 case KeyPress: 2160 { 2161 if (event.xkey.window != windows->image.id) 2162 break; 2163 /* 2164 Respond to a user key press. 2165 */ 2166 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2167 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2168 switch ((int) key_symbol) 2169 { 2170 case XK_Escape: 2171 case XK_F20: 2172 { 2173 /* 2174 Prematurely exit. 2175 */ 2176 state|=EscapeState; 2177 state|=ExitState; 2178 break; 2179 } 2180 case XK_F1: 2181 case XK_Help: 2182 { 2183 XTextViewWidget(display,resource_info,windows,MagickFalse, 2184 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2185 break; 2186 } 2187 default: 2188 { 2189 (void) XBell(display,0); 2190 break; 2191 } 2192 } 2193 break; 2194 } 2195 case MotionNotify: 2196 { 2197 /* 2198 Map and unmap Info widget as cursor crosses its boundaries. 2199 */ 2200 x=event.xmotion.x; 2201 y=event.xmotion.y; 2202 if (windows->info.mapped != MagickFalse) 2203 { 2204 if ((x < (int) (windows->info.x+windows->info.width)) && 2205 (y < (int) (windows->info.y+windows->info.height))) 2206 (void) XWithdrawWindow(display,windows->info.id, 2207 windows->info.screen); 2208 } 2209 else 2210 if ((x > (int) (windows->info.x+windows->info.width)) || 2211 (y > (int) (windows->info.y+windows->info.height))) 2212 (void) XMapWindow(display,windows->info.id); 2213 break; 2214 } 2215 default: 2216 break; 2217 } 2218 } while ((state & ExitState) == 0); 2219 (void) XSelectInput(display,windows->image.id, 2220 windows->image.attributes.event_mask); 2221 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2222 if ((state & EscapeState) != 0) 2223 return(MagickTrue); 2224 /* 2225 Set font info and check boundary conditions. 2226 */ 2227 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2228 if (font_info == (XFontStruct *) NULL) 2229 { 2230 XNoticeWidget(display,windows,"Unable to load font:", 2231 resource_info->font_name[font_id]); 2232 font_info=windows->font_info; 2233 } 2234 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2235 x=(int) windows->image.width-font_info->max_bounds.width; 2236 if (y < (int) (font_info->ascent+font_info->descent)) 2237 y=(int) font_info->ascent+font_info->descent; 2238 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2239 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2240 return(MagickFalse); 2241 /* 2242 Initialize annotate structure. 2243 */ 2244 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2245 if (annotate_info == (XAnnotateInfo *) NULL) 2246 return(MagickFalse); 2247 XGetAnnotateInfo(annotate_info); 2248 annotate_info->x=x; 2249 annotate_info->y=y; 2250 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2251 annotate_info->stencil=OpaqueStencil; 2252 else 2253 if (transparent_box == MagickFalse) 2254 annotate_info->stencil=BackgroundStencil; 2255 else 2256 annotate_info->stencil=ForegroundStencil; 2257 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2258 annotate_info->degrees=degrees; 2259 annotate_info->font_info=font_info; 2260 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2261 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2262 sizeof(*annotate_info->text)); 2263 if (annotate_info->text == (char *) NULL) 2264 return(MagickFalse); 2265 /* 2266 Create cursor and set graphic context. 2267 */ 2268 cursor=XCreateFontCursor(display,XC_pencil); 2269 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2270 annotate_context=windows->image.annotate_context; 2271 (void) XSetFont(display,annotate_context,font_info->fid); 2272 (void) XSetBackground(display,annotate_context, 2273 windows->pixel_info->pen_colors[box_id].pixel); 2274 (void) XSetForeground(display,annotate_context, 2275 windows->pixel_info->pen_colors[pen_id].pixel); 2276 /* 2277 Begin annotating the image with text. 2278 */ 2279 (void) CloneString(&windows->command.name,"Text"); 2280 windows->command.data=0; 2281 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2282 state=DefaultState; 2283 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2284 text_event.xexpose.width=(int) font_info->max_bounds.width; 2285 text_event.xexpose.height=font_info->max_bounds.ascent+ 2286 font_info->max_bounds.descent; 2287 p=annotate_info->text; 2288 do 2289 { 2290 /* 2291 Display text cursor. 2292 */ 2293 *p='\0'; 2294 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2295 /* 2296 Wait for next event. 2297 */ 2298 XScreenEvent(display,windows,&event); 2299 if (event.xany.window == windows->command.id) 2300 { 2301 /* 2302 Select a command from the Command widget. 2303 */ 2304 (void) XSetBackground(display,annotate_context, 2305 windows->pixel_info->background_color.pixel); 2306 (void) XSetForeground(display,annotate_context, 2307 windows->pixel_info->foreground_color.pixel); 2308 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2309 (void) XSetBackground(display,annotate_context, 2310 windows->pixel_info->pen_colors[box_id].pixel); 2311 (void) XSetForeground(display,annotate_context, 2312 windows->pixel_info->pen_colors[pen_id].pixel); 2313 if (id < 0) 2314 continue; 2315 switch (TextCommands[id]) 2316 { 2317 case TextHelpCommand: 2318 { 2319 XTextViewWidget(display,resource_info,windows,MagickFalse, 2320 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2321 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2322 break; 2323 } 2324 case TextApplyCommand: 2325 { 2326 /* 2327 Finished annotating. 2328 */ 2329 annotate_info->width=(unsigned int) XTextWidth(font_info, 2330 annotate_info->text,(int) strlen(annotate_info->text)); 2331 XRefreshWindow(display,&windows->image,&text_event); 2332 state|=ExitState; 2333 break; 2334 } 2335 default: 2336 break; 2337 } 2338 continue; 2339 } 2340 /* 2341 Erase text cursor. 2342 */ 2343 text_event.xexpose.x=x; 2344 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2345 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2346 (unsigned int) text_event.xexpose.width,(unsigned int) 2347 text_event.xexpose.height,MagickFalse); 2348 XRefreshWindow(display,&windows->image,&text_event); 2349 switch (event.type) 2350 { 2351 case ButtonPress: 2352 { 2353 if (event.xbutton.window != windows->image.id) 2354 break; 2355 if (event.xbutton.button == Button2) 2356 { 2357 /* 2358 Request primary selection. 2359 */ 2360 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2361 windows->image.id,CurrentTime); 2362 break; 2363 } 2364 break; 2365 } 2366 case Expose: 2367 { 2368 if (event.xexpose.count == 0) 2369 { 2370 XAnnotateInfo 2371 *text_info; 2372 2373 /* 2374 Refresh Image window. 2375 */ 2376 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2377 text_info=annotate_info; 2378 while (text_info != (XAnnotateInfo *) NULL) 2379 { 2380 if (annotate_info->stencil == ForegroundStencil) 2381 (void) XDrawString(display,windows->image.id,annotate_context, 2382 text_info->x,text_info->y,text_info->text, 2383 (int) strlen(text_info->text)); 2384 else 2385 (void) XDrawImageString(display,windows->image.id, 2386 annotate_context,text_info->x,text_info->y,text_info->text, 2387 (int) strlen(text_info->text)); 2388 text_info=text_info->previous; 2389 } 2390 (void) XDrawString(display,windows->image.id,annotate_context, 2391 x,y,"_",1); 2392 } 2393 break; 2394 } 2395 case KeyPress: 2396 { 2397 int 2398 length; 2399 2400 if (event.xkey.window != windows->image.id) 2401 break; 2402 /* 2403 Respond to a user key press. 2404 */ 2405 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2406 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2407 *(command+length)='\0'; 2408 if (((event.xkey.state & ControlMask) != 0) || 2409 ((event.xkey.state & Mod1Mask) != 0)) 2410 state|=ModifierState; 2411 if ((state & ModifierState) != 0) 2412 switch ((int) key_symbol) 2413 { 2414 case XK_u: 2415 case XK_U: 2416 { 2417 key_symbol=DeleteCommand; 2418 break; 2419 } 2420 default: 2421 break; 2422 } 2423 switch ((int) key_symbol) 2424 { 2425 case XK_BackSpace: 2426 { 2427 /* 2428 Erase one character. 2429 */ 2430 if (p == annotate_info->text) 2431 { 2432 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2433 break; 2434 else 2435 { 2436 /* 2437 Go to end of the previous line of text. 2438 */ 2439 annotate_info=annotate_info->previous; 2440 p=annotate_info->text; 2441 x=annotate_info->x+annotate_info->width; 2442 y=annotate_info->y; 2443 if (annotate_info->width != 0) 2444 p+=strlen(annotate_info->text); 2445 break; 2446 } 2447 } 2448 p--; 2449 x-=XTextWidth(font_info,p,1); 2450 text_event.xexpose.x=x; 2451 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2452 XRefreshWindow(display,&windows->image,&text_event); 2453 break; 2454 } 2455 case XK_bracketleft: 2456 { 2457 key_symbol=XK_Escape; 2458 break; 2459 } 2460 case DeleteCommand: 2461 { 2462 /* 2463 Erase the entire line of text. 2464 */ 2465 while (p != annotate_info->text) 2466 { 2467 p--; 2468 x-=XTextWidth(font_info,p,1); 2469 text_event.xexpose.x=x; 2470 XRefreshWindow(display,&windows->image,&text_event); 2471 } 2472 break; 2473 } 2474 case XK_Escape: 2475 case XK_F20: 2476 { 2477 /* 2478 Finished annotating. 2479 */ 2480 annotate_info->width=(unsigned int) XTextWidth(font_info, 2481 annotate_info->text,(int) strlen(annotate_info->text)); 2482 XRefreshWindow(display,&windows->image,&text_event); 2483 state|=ExitState; 2484 break; 2485 } 2486 default: 2487 { 2488 /* 2489 Draw a single character on the Image window. 2490 */ 2491 if ((state & ModifierState) != 0) 2492 break; 2493 if (*command == '\0') 2494 break; 2495 *p=(*command); 2496 if (annotate_info->stencil == ForegroundStencil) 2497 (void) XDrawString(display,windows->image.id,annotate_context, 2498 x,y,p,1); 2499 else 2500 (void) XDrawImageString(display,windows->image.id, 2501 annotate_context,x,y,p,1); 2502 x+=XTextWidth(font_info,p,1); 2503 p++; 2504 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2505 break; 2506 } 2507 case XK_Return: 2508 case XK_KP_Enter: 2509 { 2510 /* 2511 Advance to the next line of text. 2512 */ 2513 *p='\0'; 2514 annotate_info->width=(unsigned int) XTextWidth(font_info, 2515 annotate_info->text,(int) strlen(annotate_info->text)); 2516 if (annotate_info->next != (XAnnotateInfo *) NULL) 2517 { 2518 /* 2519 Line of text already exists. 2520 */ 2521 annotate_info=annotate_info->next; 2522 x=annotate_info->x; 2523 y=annotate_info->y; 2524 p=annotate_info->text; 2525 break; 2526 } 2527 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2528 sizeof(*annotate_info->next)); 2529 if (annotate_info->next == (XAnnotateInfo *) NULL) 2530 return(MagickFalse); 2531 *annotate_info->next=(*annotate_info); 2532 annotate_info->next->previous=annotate_info; 2533 annotate_info=annotate_info->next; 2534 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2535 windows->image.width/MagickMax((ssize_t) 2536 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2537 if (annotate_info->text == (char *) NULL) 2538 return(MagickFalse); 2539 annotate_info->y+=annotate_info->height; 2540 if (annotate_info->y > (int) windows->image.height) 2541 annotate_info->y=(int) annotate_info->height; 2542 annotate_info->next=(XAnnotateInfo *) NULL; 2543 x=annotate_info->x; 2544 y=annotate_info->y; 2545 p=annotate_info->text; 2546 break; 2547 } 2548 } 2549 break; 2550 } 2551 case KeyRelease: 2552 { 2553 /* 2554 Respond to a user key release. 2555 */ 2556 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2557 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2558 state&=(~ModifierState); 2559 break; 2560 } 2561 case SelectionNotify: 2562 { 2563 Atom 2564 type; 2565 2566 int 2567 format; 2568 2569 unsigned char 2570 *data; 2571 2572 unsigned long 2573 after, 2574 length; 2575 2576 /* 2577 Obtain response from primary selection. 2578 */ 2579 if (event.xselection.property == (Atom) None) 2580 break; 2581 status=XGetWindowProperty(display,event.xselection.requestor, 2582 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2583 &type,&format,&length,&after,&data); 2584 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2585 (length == 0)) 2586 break; 2587 /* 2588 Annotate Image window with primary selection. 2589 */ 2590 for (i=0; i < (ssize_t) length; i++) 2591 { 2592 if ((char) data[i] != '\n') 2593 { 2594 /* 2595 Draw a single character on the Image window. 2596 */ 2597 *p=(char) data[i]; 2598 (void) XDrawString(display,windows->image.id,annotate_context, 2599 x,y,p,1); 2600 x+=XTextWidth(font_info,p,1); 2601 p++; 2602 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2603 continue; 2604 } 2605 /* 2606 Advance to the next line of text. 2607 */ 2608 *p='\0'; 2609 annotate_info->width=(unsigned int) XTextWidth(font_info, 2610 annotate_info->text,(int) strlen(annotate_info->text)); 2611 if (annotate_info->next != (XAnnotateInfo *) NULL) 2612 { 2613 /* 2614 Line of text already exists. 2615 */ 2616 annotate_info=annotate_info->next; 2617 x=annotate_info->x; 2618 y=annotate_info->y; 2619 p=annotate_info->text; 2620 continue; 2621 } 2622 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2623 sizeof(*annotate_info->next)); 2624 if (annotate_info->next == (XAnnotateInfo *) NULL) 2625 return(MagickFalse); 2626 *annotate_info->next=(*annotate_info); 2627 annotate_info->next->previous=annotate_info; 2628 annotate_info=annotate_info->next; 2629 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2630 windows->image.width/MagickMax((ssize_t) 2631 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2632 if (annotate_info->text == (char *) NULL) 2633 return(MagickFalse); 2634 annotate_info->y+=annotate_info->height; 2635 if (annotate_info->y > (int) windows->image.height) 2636 annotate_info->y=(int) annotate_info->height; 2637 annotate_info->next=(XAnnotateInfo *) NULL; 2638 x=annotate_info->x; 2639 y=annotate_info->y; 2640 p=annotate_info->text; 2641 } 2642 (void) XFree((void *) data); 2643 break; 2644 } 2645 default: 2646 break; 2647 } 2648 } while ((state & ExitState) == 0); 2649 (void) XFreeCursor(display,cursor); 2650 /* 2651 Annotation is relative to image configuration. 2652 */ 2653 width=(unsigned int) image->columns; 2654 height=(unsigned int) image->rows; 2655 x=0; 2656 y=0; 2657 if (windows->image.crop_geometry != (char *) NULL) 2658 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2659 /* 2660 Initialize annotated image. 2661 */ 2662 XSetCursorState(display,windows,MagickTrue); 2663 XCheckRefreshWindows(display,windows); 2664 while (annotate_info != (XAnnotateInfo *) NULL) 2665 { 2666 if (annotate_info->width == 0) 2667 { 2668 /* 2669 No text on this line-- go to the next line of text. 2670 */ 2671 previous_info=annotate_info->previous; 2672 annotate_info->text=(char *) 2673 RelinquishMagickMemory(annotate_info->text); 2674 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2675 annotate_info=previous_info; 2676 continue; 2677 } 2678 /* 2679 Determine pixel index for box and pen color. 2680 */ 2681 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2682 if (windows->pixel_info->colors != 0) 2683 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2684 if (windows->pixel_info->pixels[i] == 2685 windows->pixel_info->pen_colors[box_id].pixel) 2686 { 2687 windows->pixel_info->box_index=(unsigned short) i; 2688 break; 2689 } 2690 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2691 if (windows->pixel_info->colors != 0) 2692 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2693 if (windows->pixel_info->pixels[i] == 2694 windows->pixel_info->pen_colors[pen_id].pixel) 2695 { 2696 windows->pixel_info->pen_index=(unsigned short) i; 2697 break; 2698 } 2699 /* 2700 Define the annotate geometry string. 2701 */ 2702 annotate_info->x=(int) 2703 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2704 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2705 windows->image.y)/windows->image.ximage->height; 2706 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2707 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2708 height*annotate_info->height/windows->image.ximage->height, 2709 annotate_info->x+x,annotate_info->y+y); 2710 /* 2711 Annotate image with text. 2712 */ 2713 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image); 2714 if (status == 0) 2715 return(MagickFalse); 2716 /* 2717 Free up memory. 2718 */ 2719 previous_info=annotate_info->previous; 2720 annotate_info->text=DestroyString(annotate_info->text); 2721 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2722 annotate_info=previous_info; 2723 } 2724 (void) XSetForeground(display,annotate_context, 2725 windows->pixel_info->foreground_color.pixel); 2726 (void) XSetBackground(display,annotate_context, 2727 windows->pixel_info->background_color.pixel); 2728 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2729 XSetCursorState(display,windows,MagickFalse); 2730 (void) XFreeFont(display,font_info); 2731 /* 2732 Update image configuration. 2733 */ 2734 XConfigureImageColormap(display,resource_info,windows,image); 2735 (void) XConfigureImage(display,resource_info,windows,image); 2736 return(MagickTrue); 2737} 2738 2739/* 2740%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2741% % 2742% % 2743% % 2744+ X B a c k g r o u n d I m a g e % 2745% % 2746% % 2747% % 2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2749% 2750% XBackgroundImage() displays the image in the background of a window. 2751% 2752% The format of the XBackgroundImage method is: 2753% 2754% MagickBooleanType XBackgroundImage(Display *display, 2755% XResourceInfo *resource_info,XWindows *windows,Image **image) 2756% 2757% A description of each parameter follows: 2758% 2759% o display: Specifies a connection to an X server; returned from 2760% XOpenDisplay. 2761% 2762% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2763% 2764% o windows: Specifies a pointer to a XWindows structure. 2765% 2766% o image: the image. 2767% 2768*/ 2769static MagickBooleanType XBackgroundImage(Display *display, 2770 XResourceInfo *resource_info,XWindows *windows,Image **image) 2771{ 2772#define BackgroundImageTag "Background/Image" 2773 2774 int 2775 status; 2776 2777 static char 2778 window_id[MaxTextExtent] = "root"; 2779 2780 XResourceInfo 2781 background_resources; 2782 2783 /* 2784 Put image in background. 2785 */ 2786 status=XDialogWidget(display,windows,"Background", 2787 "Enter window id (id 0x00 selects window with pointer):",window_id); 2788 if (*window_id == '\0') 2789 return(MagickFalse); 2790 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 2791 XInfoWidget(display,windows,BackgroundImageTag); 2792 XSetCursorState(display,windows,MagickTrue); 2793 XCheckRefreshWindows(display,windows); 2794 background_resources=(*resource_info); 2795 background_resources.window_id=window_id; 2796 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2797 status=XDisplayBackgroundImage(display,&background_resources,*image); 2798 if (status != MagickFalse) 2799 XClientMessage(display,windows->image.id,windows->im_protocols, 2800 windows->im_retain_colors,CurrentTime); 2801 XSetCursorState(display,windows,MagickFalse); 2802 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image); 2803 return(MagickTrue); 2804} 2805 2806/* 2807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2808% % 2809% % 2810% % 2811+ X C h o p I m a g e % 2812% % 2813% % 2814% % 2815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2816% 2817% XChopImage() chops the X image. 2818% 2819% The format of the XChopImage method is: 2820% 2821% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2822% XWindows *windows,Image **image) 2823% 2824% A description of each parameter follows: 2825% 2826% o display: Specifies a connection to an X server; returned from 2827% XOpenDisplay. 2828% 2829% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2830% 2831% o windows: Specifies a pointer to a XWindows structure. 2832% 2833% o image: the image. 2834% 2835*/ 2836static MagickBooleanType XChopImage(Display *display, 2837 XResourceInfo *resource_info,XWindows *windows,Image **image) 2838{ 2839 static const char 2840 *ChopMenu[] = 2841 { 2842 "Direction", 2843 "Help", 2844 "Dismiss", 2845 (char *) NULL 2846 }; 2847 2848 static ModeType 2849 direction = HorizontalChopCommand; 2850 2851 static const ModeType 2852 ChopCommands[] = 2853 { 2854 ChopDirectionCommand, 2855 ChopHelpCommand, 2856 ChopDismissCommand 2857 }, 2858 DirectionCommands[] = 2859 { 2860 HorizontalChopCommand, 2861 VerticalChopCommand 2862 }; 2863 2864 char 2865 text[MaxTextExtent]; 2866 2867 Image 2868 *chop_image; 2869 2870 int 2871 id, 2872 x, 2873 y; 2874 2875 MagickRealType 2876 scale_factor; 2877 2878 RectangleInfo 2879 chop_info; 2880 2881 unsigned int 2882 distance, 2883 height, 2884 width; 2885 2886 size_t 2887 state; 2888 2889 XEvent 2890 event; 2891 2892 XSegment 2893 segment_info; 2894 2895 /* 2896 Map Command widget. 2897 */ 2898 (void) CloneString(&windows->command.name,"Chop"); 2899 windows->command.data=1; 2900 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2901 (void) XMapRaised(display,windows->command.id); 2902 XClientMessage(display,windows->image.id,windows->im_protocols, 2903 windows->im_update_widget,CurrentTime); 2904 /* 2905 Track pointer until button 1 is pressed. 2906 */ 2907 XQueryPosition(display,windows->image.id,&x,&y); 2908 (void) XSelectInput(display,windows->image.id, 2909 windows->image.attributes.event_mask | PointerMotionMask); 2910 state=DefaultState; 2911 do 2912 { 2913 if (windows->info.mapped != MagickFalse) 2914 { 2915 /* 2916 Display pointer position. 2917 */ 2918 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2919 x+windows->image.x,y+windows->image.y); 2920 XInfoWidget(display,windows,text); 2921 } 2922 /* 2923 Wait for next event. 2924 */ 2925 XScreenEvent(display,windows,&event); 2926 if (event.xany.window == windows->command.id) 2927 { 2928 /* 2929 Select a command from the Command widget. 2930 */ 2931 id=XCommandWidget(display,windows,ChopMenu,&event); 2932 if (id < 0) 2933 continue; 2934 switch (ChopCommands[id]) 2935 { 2936 case ChopDirectionCommand: 2937 { 2938 char 2939 command[MaxTextExtent]; 2940 2941 static const char 2942 *Directions[] = 2943 { 2944 "horizontal", 2945 "vertical", 2946 (char *) NULL, 2947 }; 2948 2949 /* 2950 Select a command from the pop-up menu. 2951 */ 2952 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2953 if (id >= 0) 2954 direction=DirectionCommands[id]; 2955 break; 2956 } 2957 case ChopHelpCommand: 2958 { 2959 XTextViewWidget(display,resource_info,windows,MagickFalse, 2960 "Help Viewer - Image Chop",ImageChopHelp); 2961 break; 2962 } 2963 case ChopDismissCommand: 2964 { 2965 /* 2966 Prematurely exit. 2967 */ 2968 state|=EscapeState; 2969 state|=ExitState; 2970 break; 2971 } 2972 default: 2973 break; 2974 } 2975 continue; 2976 } 2977 switch (event.type) 2978 { 2979 case ButtonPress: 2980 { 2981 if (event.xbutton.button != Button1) 2982 break; 2983 if (event.xbutton.window != windows->image.id) 2984 break; 2985 /* 2986 User has committed to start point of chopping line. 2987 */ 2988 segment_info.x1=(short int) event.xbutton.x; 2989 segment_info.x2=(short int) event.xbutton.x; 2990 segment_info.y1=(short int) event.xbutton.y; 2991 segment_info.y2=(short int) event.xbutton.y; 2992 state|=ExitState; 2993 break; 2994 } 2995 case ButtonRelease: 2996 break; 2997 case Expose: 2998 break; 2999 case KeyPress: 3000 { 3001 char 3002 command[MaxTextExtent]; 3003 3004 KeySym 3005 key_symbol; 3006 3007 if (event.xkey.window != windows->image.id) 3008 break; 3009 /* 3010 Respond to a user key press. 3011 */ 3012 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3013 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3014 switch ((int) key_symbol) 3015 { 3016 case XK_Escape: 3017 case XK_F20: 3018 { 3019 /* 3020 Prematurely exit. 3021 */ 3022 state|=EscapeState; 3023 state|=ExitState; 3024 break; 3025 } 3026 case XK_F1: 3027 case XK_Help: 3028 { 3029 (void) XSetFunction(display,windows->image.highlight_context, 3030 GXcopy); 3031 XTextViewWidget(display,resource_info,windows,MagickFalse, 3032 "Help Viewer - Image Chop",ImageChopHelp); 3033 (void) XSetFunction(display,windows->image.highlight_context, 3034 GXinvert); 3035 break; 3036 } 3037 default: 3038 { 3039 (void) XBell(display,0); 3040 break; 3041 } 3042 } 3043 break; 3044 } 3045 case MotionNotify: 3046 { 3047 /* 3048 Map and unmap Info widget as text cursor crosses its boundaries. 3049 */ 3050 x=event.xmotion.x; 3051 y=event.xmotion.y; 3052 if (windows->info.mapped != MagickFalse) 3053 { 3054 if ((x < (int) (windows->info.x+windows->info.width)) && 3055 (y < (int) (windows->info.y+windows->info.height))) 3056 (void) XWithdrawWindow(display,windows->info.id, 3057 windows->info.screen); 3058 } 3059 else 3060 if ((x > (int) (windows->info.x+windows->info.width)) || 3061 (y > (int) (windows->info.y+windows->info.height))) 3062 (void) XMapWindow(display,windows->info.id); 3063 } 3064 } 3065 } while ((state & ExitState) == 0); 3066 (void) XSelectInput(display,windows->image.id, 3067 windows->image.attributes.event_mask); 3068 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3069 if ((state & EscapeState) != 0) 3070 return(MagickTrue); 3071 /* 3072 Draw line as pointer moves until the mouse button is released. 3073 */ 3074 chop_info.width=0; 3075 chop_info.height=0; 3076 chop_info.x=0; 3077 chop_info.y=0; 3078 distance=0; 3079 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3080 state=DefaultState; 3081 do 3082 { 3083 if (distance > 9) 3084 { 3085 /* 3086 Display info and draw chopping line. 3087 */ 3088 if (windows->info.mapped == MagickFalse) 3089 (void) XMapWindow(display,windows->info.id); 3090 (void) FormatLocaleString(text,MaxTextExtent, 3091 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3092 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3093 XInfoWidget(display,windows,text); 3094 XHighlightLine(display,windows->image.id, 3095 windows->image.highlight_context,&segment_info); 3096 } 3097 else 3098 if (windows->info.mapped != MagickFalse) 3099 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3100 /* 3101 Wait for next event. 3102 */ 3103 XScreenEvent(display,windows,&event); 3104 if (distance > 9) 3105 XHighlightLine(display,windows->image.id, 3106 windows->image.highlight_context,&segment_info); 3107 switch (event.type) 3108 { 3109 case ButtonPress: 3110 { 3111 segment_info.x2=(short int) event.xmotion.x; 3112 segment_info.y2=(short int) event.xmotion.y; 3113 break; 3114 } 3115 case ButtonRelease: 3116 { 3117 /* 3118 User has committed to chopping line. 3119 */ 3120 segment_info.x2=(short int) event.xbutton.x; 3121 segment_info.y2=(short int) event.xbutton.y; 3122 state|=ExitState; 3123 break; 3124 } 3125 case Expose: 3126 break; 3127 case MotionNotify: 3128 { 3129 segment_info.x2=(short int) event.xmotion.x; 3130 segment_info.y2=(short int) event.xmotion.y; 3131 } 3132 default: 3133 break; 3134 } 3135 /* 3136 Check boundary conditions. 3137 */ 3138 if (segment_info.x2 < 0) 3139 segment_info.x2=0; 3140 else 3141 if (segment_info.x2 > windows->image.ximage->width) 3142 segment_info.x2=windows->image.ximage->width; 3143 if (segment_info.y2 < 0) 3144 segment_info.y2=0; 3145 else 3146 if (segment_info.y2 > windows->image.ximage->height) 3147 segment_info.y2=windows->image.ximage->height; 3148 distance=(unsigned int) 3149 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3150 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3151 /* 3152 Compute chopping geometry. 3153 */ 3154 if (direction == HorizontalChopCommand) 3155 { 3156 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3157 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3158 chop_info.height=0; 3159 chop_info.y=0; 3160 if (segment_info.x1 > (int) segment_info.x2) 3161 { 3162 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3163 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3164 } 3165 } 3166 else 3167 { 3168 chop_info.width=0; 3169 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3170 chop_info.x=0; 3171 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3172 if (segment_info.y1 > segment_info.y2) 3173 { 3174 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3175 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3176 } 3177 } 3178 } while ((state & ExitState) == 0); 3179 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3180 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3181 if (distance <= 9) 3182 return(MagickTrue); 3183 /* 3184 Image chopping is relative to image configuration. 3185 */ 3186 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 3187 XSetCursorState(display,windows,MagickTrue); 3188 XCheckRefreshWindows(display,windows); 3189 windows->image.window_changes.width=windows->image.ximage->width- 3190 (unsigned int) chop_info.width; 3191 windows->image.window_changes.height=windows->image.ximage->height- 3192 (unsigned int) chop_info.height; 3193 width=(unsigned int) (*image)->columns; 3194 height=(unsigned int) (*image)->rows; 3195 x=0; 3196 y=0; 3197 if (windows->image.crop_geometry != (char *) NULL) 3198 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3199 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3200 chop_info.x+=x; 3201 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3202 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3203 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3204 chop_info.y+=y; 3205 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3206 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3207 /* 3208 Chop image. 3209 */ 3210 chop_image=ChopImage(*image,&chop_info,&(*image)->exception); 3211 XSetCursorState(display,windows,MagickFalse); 3212 if (chop_image == (Image *) NULL) 3213 return(MagickFalse); 3214 *image=DestroyImage(*image); 3215 *image=chop_image; 3216 /* 3217 Update image configuration. 3218 */ 3219 XConfigureImageColormap(display,resource_info,windows,*image); 3220 (void) XConfigureImage(display,resource_info,windows,*image); 3221 return(MagickTrue); 3222} 3223 3224/* 3225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3226% % 3227% % 3228% % 3229+ X C o l o r E d i t I m a g e % 3230% % 3231% % 3232% % 3233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3234% 3235% XColorEditImage() allows the user to interactively change the color of one 3236% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3237% 3238% The format of the XColorEditImage method is: 3239% 3240% MagickBooleanType XColorEditImage(Display *display, 3241% XResourceInfo *resource_info,XWindows *windows,Image **image) 3242% 3243% A description of each parameter follows: 3244% 3245% o display: Specifies a connection to an X server; returned from 3246% XOpenDisplay. 3247% 3248% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3249% 3250% o windows: Specifies a pointer to a XWindows structure. 3251% 3252% o image: the image; returned from ReadImage. 3253% 3254*/ 3255 3256 3257static MagickBooleanType XColorEditImage(Display *display, 3258 XResourceInfo *resource_info,XWindows *windows,Image **image) 3259{ 3260 static const char 3261 *ColorEditMenu[] = 3262 { 3263 "Method", 3264 "Pixel Color", 3265 "Border Color", 3266 "Fuzz", 3267 "Undo", 3268 "Help", 3269 "Dismiss", 3270 (char *) NULL 3271 }; 3272 3273 static const ModeType 3274 ColorEditCommands[] = 3275 { 3276 ColorEditMethodCommand, 3277 ColorEditColorCommand, 3278 ColorEditBorderCommand, 3279 ColorEditFuzzCommand, 3280 ColorEditUndoCommand, 3281 ColorEditHelpCommand, 3282 ColorEditDismissCommand 3283 }; 3284 3285 static PaintMethod 3286 method = PointMethod; 3287 3288 static unsigned int 3289 pen_id = 0; 3290 3291 static XColor 3292 border_color = { 0, 0, 0, 0, 0, 0 }; 3293 3294 char 3295 command[MaxTextExtent], 3296 text[MaxTextExtent]; 3297 3298 Cursor 3299 cursor; 3300 3301 ExceptionInfo 3302 *exception; 3303 3304 int 3305 entry, 3306 id, 3307 x, 3308 x_offset, 3309 y, 3310 y_offset; 3311 3312 register Quantum 3313 *q; 3314 3315 register ssize_t 3316 i; 3317 3318 unsigned int 3319 height, 3320 width; 3321 3322 size_t 3323 state; 3324 3325 XColor 3326 color; 3327 3328 XEvent 3329 event; 3330 3331 /* 3332 Map Command widget. 3333 */ 3334 (void) CloneString(&windows->command.name,"Color Edit"); 3335 windows->command.data=4; 3336 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3337 (void) XMapRaised(display,windows->command.id); 3338 XClientMessage(display,windows->image.id,windows->im_protocols, 3339 windows->im_update_widget,CurrentTime); 3340 /* 3341 Make cursor. 3342 */ 3343 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3344 resource_info->background_color,resource_info->foreground_color); 3345 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3346 /* 3347 Track pointer until button 1 is pressed. 3348 */ 3349 XQueryPosition(display,windows->image.id,&x,&y); 3350 (void) XSelectInput(display,windows->image.id, 3351 windows->image.attributes.event_mask | PointerMotionMask); 3352 state=DefaultState; 3353 do 3354 { 3355 if (windows->info.mapped != MagickFalse) 3356 { 3357 /* 3358 Display pointer position. 3359 */ 3360 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3361 x+windows->image.x,y+windows->image.y); 3362 XInfoWidget(display,windows,text); 3363 } 3364 /* 3365 Wait for next event. 3366 */ 3367 XScreenEvent(display,windows,&event); 3368 if (event.xany.window == windows->command.id) 3369 { 3370 /* 3371 Select a command from the Command widget. 3372 */ 3373 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3374 if (id < 0) 3375 { 3376 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3377 continue; 3378 } 3379 switch (ColorEditCommands[id]) 3380 { 3381 case ColorEditMethodCommand: 3382 { 3383 char 3384 **methods; 3385 3386 /* 3387 Select a method from the pop-up menu. 3388 */ 3389 methods=(char **) GetCommandOptions(MagickMethodOptions); 3390 if (methods == (char **) NULL) 3391 break; 3392 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3393 (const char **) methods,command); 3394 if (entry >= 0) 3395 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3396 MagickFalse,methods[entry]); 3397 methods=DestroyStringList(methods); 3398 break; 3399 } 3400 case ColorEditColorCommand: 3401 { 3402 const char 3403 *ColorMenu[MaxNumberPens]; 3404 3405 int 3406 pen_number; 3407 3408 /* 3409 Initialize menu selections. 3410 */ 3411 for (i=0; i < (int) (MaxNumberPens-2); i++) 3412 ColorMenu[i]=resource_info->pen_colors[i]; 3413 ColorMenu[MaxNumberPens-2]="Browser..."; 3414 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3415 /* 3416 Select a pen color from the pop-up menu. 3417 */ 3418 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3419 (const char **) ColorMenu,command); 3420 if (pen_number < 0) 3421 break; 3422 if (pen_number == (MaxNumberPens-2)) 3423 { 3424 static char 3425 color_name[MaxTextExtent] = "gray"; 3426 3427 /* 3428 Select a pen color from a dialog. 3429 */ 3430 resource_info->pen_colors[pen_number]=color_name; 3431 XColorBrowserWidget(display,windows,"Select",color_name); 3432 if (*color_name == '\0') 3433 break; 3434 } 3435 /* 3436 Set pen color. 3437 */ 3438 (void) XParseColor(display,windows->map_info->colormap, 3439 resource_info->pen_colors[pen_number],&color); 3440 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3441 (unsigned int) MaxColors,&color); 3442 windows->pixel_info->pen_colors[pen_number]=color; 3443 pen_id=(unsigned int) pen_number; 3444 break; 3445 } 3446 case ColorEditBorderCommand: 3447 { 3448 const char 3449 *ColorMenu[MaxNumberPens]; 3450 3451 int 3452 pen_number; 3453 3454 /* 3455 Initialize menu selections. 3456 */ 3457 for (i=0; i < (int) (MaxNumberPens-2); i++) 3458 ColorMenu[i]=resource_info->pen_colors[i]; 3459 ColorMenu[MaxNumberPens-2]="Browser..."; 3460 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3461 /* 3462 Select a pen color from the pop-up menu. 3463 */ 3464 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3465 (const char **) ColorMenu,command); 3466 if (pen_number < 0) 3467 break; 3468 if (pen_number == (MaxNumberPens-2)) 3469 { 3470 static char 3471 color_name[MaxTextExtent] = "gray"; 3472 3473 /* 3474 Select a pen color from a dialog. 3475 */ 3476 resource_info->pen_colors[pen_number]=color_name; 3477 XColorBrowserWidget(display,windows,"Select",color_name); 3478 if (*color_name == '\0') 3479 break; 3480 } 3481 /* 3482 Set border color. 3483 */ 3484 (void) XParseColor(display,windows->map_info->colormap, 3485 resource_info->pen_colors[pen_number],&border_color); 3486 break; 3487 } 3488 case ColorEditFuzzCommand: 3489 { 3490 static char 3491 fuzz[MaxTextExtent]; 3492 3493 static const char 3494 *FuzzMenu[] = 3495 { 3496 "0%", 3497 "2%", 3498 "5%", 3499 "10%", 3500 "15%", 3501 "Dialog...", 3502 (char *) NULL, 3503 }; 3504 3505 /* 3506 Select a command from the pop-up menu. 3507 */ 3508 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3509 command); 3510 if (entry < 0) 3511 break; 3512 if (entry != 5) 3513 { 3514 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 3515 QuantumRange+1.0); 3516 break; 3517 } 3518 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3519 (void) XDialogWidget(display,windows,"Ok", 3520 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3521 if (*fuzz == '\0') 3522 break; 3523 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3524 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 3525 break; 3526 } 3527 case ColorEditUndoCommand: 3528 { 3529 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3530 image); 3531 break; 3532 } 3533 case ColorEditHelpCommand: 3534 default: 3535 { 3536 XTextViewWidget(display,resource_info,windows,MagickFalse, 3537 "Help Viewer - Image Annotation",ImageColorEditHelp); 3538 break; 3539 } 3540 case ColorEditDismissCommand: 3541 { 3542 /* 3543 Prematurely exit. 3544 */ 3545 state|=EscapeState; 3546 state|=ExitState; 3547 break; 3548 } 3549 } 3550 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3551 continue; 3552 } 3553 switch (event.type) 3554 { 3555 case ButtonPress: 3556 { 3557 if (event.xbutton.button != Button1) 3558 break; 3559 if ((event.xbutton.window != windows->image.id) && 3560 (event.xbutton.window != windows->magnify.id)) 3561 break; 3562 /* 3563 exit loop. 3564 */ 3565 x=event.xbutton.x; 3566 y=event.xbutton.y; 3567 (void) XMagickCommand(display,resource_info,windows, 3568 SaveToUndoBufferCommand,image); 3569 state|=UpdateConfigurationState; 3570 break; 3571 } 3572 case ButtonRelease: 3573 { 3574 if (event.xbutton.button != Button1) 3575 break; 3576 if ((event.xbutton.window != windows->image.id) && 3577 (event.xbutton.window != windows->magnify.id)) 3578 break; 3579 /* 3580 Update colormap information. 3581 */ 3582 x=event.xbutton.x; 3583 y=event.xbutton.y; 3584 XConfigureImageColormap(display,resource_info,windows,*image); 3585 (void) XConfigureImage(display,resource_info,windows,*image); 3586 XInfoWidget(display,windows,text); 3587 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3588 state&=(~UpdateConfigurationState); 3589 break; 3590 } 3591 case Expose: 3592 break; 3593 case KeyPress: 3594 { 3595 KeySym 3596 key_symbol; 3597 3598 if (event.xkey.window == windows->magnify.id) 3599 { 3600 Window 3601 window; 3602 3603 window=windows->magnify.id; 3604 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3605 } 3606 if (event.xkey.window != windows->image.id) 3607 break; 3608 /* 3609 Respond to a user key press. 3610 */ 3611 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3612 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3613 switch ((int) key_symbol) 3614 { 3615 case XK_Escape: 3616 case XK_F20: 3617 { 3618 /* 3619 Prematurely exit. 3620 */ 3621 state|=ExitState; 3622 break; 3623 } 3624 case XK_F1: 3625 case XK_Help: 3626 { 3627 XTextViewWidget(display,resource_info,windows,MagickFalse, 3628 "Help Viewer - Image Annotation",ImageColorEditHelp); 3629 break; 3630 } 3631 default: 3632 { 3633 (void) XBell(display,0); 3634 break; 3635 } 3636 } 3637 break; 3638 } 3639 case MotionNotify: 3640 { 3641 /* 3642 Map and unmap Info widget as cursor crosses its boundaries. 3643 */ 3644 x=event.xmotion.x; 3645 y=event.xmotion.y; 3646 if (windows->info.mapped != MagickFalse) 3647 { 3648 if ((x < (int) (windows->info.x+windows->info.width)) && 3649 (y < (int) (windows->info.y+windows->info.height))) 3650 (void) XWithdrawWindow(display,windows->info.id, 3651 windows->info.screen); 3652 } 3653 else 3654 if ((x > (int) (windows->info.x+windows->info.width)) || 3655 (y > (int) (windows->info.y+windows->info.height))) 3656 (void) XMapWindow(display,windows->info.id); 3657 break; 3658 } 3659 default: 3660 break; 3661 } 3662 if (event.xany.window == windows->magnify.id) 3663 { 3664 x=windows->magnify.x-windows->image.x; 3665 y=windows->magnify.y-windows->image.y; 3666 } 3667 x_offset=x; 3668 y_offset=y; 3669 if ((state & UpdateConfigurationState) != 0) 3670 { 3671 CacheView 3672 *image_view; 3673 3674 int 3675 x, 3676 y; 3677 3678 /* 3679 Pixel edit is relative to image configuration. 3680 */ 3681 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3682 MagickTrue); 3683 color=windows->pixel_info->pen_colors[pen_id]; 3684 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3685 width=(unsigned int) (*image)->columns; 3686 height=(unsigned int) (*image)->rows; 3687 x=0; 3688 y=0; 3689 if (windows->image.crop_geometry != (char *) NULL) 3690 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3691 &width,&height); 3692 x_offset=(int) 3693 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3694 y_offset=(int) 3695 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3696 if ((x_offset < 0) || (y_offset < 0)) 3697 continue; 3698 if ((x_offset >= (int) (*image)->columns) || 3699 (y_offset >= (int) (*image)->rows)) 3700 continue; 3701 exception=(&(*image)->exception); 3702 image_view=AcquireCacheView(*image); 3703 switch (method) 3704 { 3705 case PointMethod: 3706 default: 3707 { 3708 /* 3709 Update color information using point algorithm. 3710 */ 3711 if (SetImageStorageClass(*image,DirectClass) == MagickFalse) 3712 return(MagickFalse); 3713 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3714 (ssize_t)y_offset,1,1,exception); 3715 if (q == (Quantum *) NULL) 3716 break; 3717 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3718 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3719 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3720 (void) SyncCacheViewAuthenticPixels(image_view, 3721 &(*image)->exception); 3722 break; 3723 } 3724 case ReplaceMethod: 3725 { 3726 PixelPacket 3727 pixel, 3728 target; 3729 3730 /* 3731 Update color information using replace algorithm. 3732 */ 3733 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3734 (ssize_t) y_offset,&target,&(*image)->exception); 3735 if ((*image)->storage_class == DirectClass) 3736 { 3737 for (y=0; y < (int) (*image)->rows; y++) 3738 { 3739 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3740 (*image)->columns,1,exception); 3741 if (q == (Quantum *) NULL) 3742 break; 3743 for (x=0; x < (int) (*image)->columns; x++) 3744 { 3745 GetPixelPacket(*image,q,&pixel); 3746 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 3747 { 3748 SetPixelRed(*image,ScaleShortToQuantum( 3749 color.red),q); 3750 SetPixelGreen(*image,ScaleShortToQuantum( 3751 color.green),q); 3752 SetPixelBlue(*image,ScaleShortToQuantum( 3753 color.blue),q); 3754 } 3755 q+=GetPixelChannels(*image); 3756 } 3757 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3758 break; 3759 } 3760 } 3761 else 3762 { 3763 for (i=0; i < (ssize_t) (*image)->colors; i++) 3764 if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target)) 3765 { 3766 (*image)->colormap[i].red=ScaleShortToQuantum( 3767 color.red); 3768 (*image)->colormap[i].green=ScaleShortToQuantum( 3769 color.green); 3770 (*image)->colormap[i].blue=ScaleShortToQuantum( 3771 color.blue); 3772 } 3773 (void) SyncImage(*image); 3774 } 3775 break; 3776 } 3777 case FloodfillMethod: 3778 case FillToBorderMethod: 3779 { 3780 DrawInfo 3781 *draw_info; 3782 3783 PixelInfo 3784 target; 3785 3786 /* 3787 Update color information using floodfill algorithm. 3788 */ 3789 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 3790 (ssize_t) y_offset,&target,exception); 3791 if (method == FillToBorderMethod) 3792 { 3793 target.red=(MagickRealType) 3794 ScaleShortToQuantum(border_color.red); 3795 target.green=(MagickRealType) 3796 ScaleShortToQuantum(border_color.green); 3797 target.blue=(MagickRealType) 3798 ScaleShortToQuantum(border_color.blue); 3799 } 3800 draw_info=CloneDrawInfo(resource_info->image_info, 3801 (DrawInfo *) NULL); 3802 (void) QueryColorDatabase(resource_info->pen_colors[pen_id], 3803 &draw_info->fill,exception); 3804 (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target, 3805 (ssize_t) x_offset,(ssize_t) y_offset, 3806 method == FloodfillMethod ? MagickFalse : MagickTrue); 3807 draw_info=DestroyDrawInfo(draw_info); 3808 break; 3809 } 3810 case ResetMethod: 3811 { 3812 /* 3813 Update color information using reset algorithm. 3814 */ 3815 if (SetImageStorageClass(*image,DirectClass) == MagickFalse) 3816 return(MagickFalse); 3817 for (y=0; y < (int) (*image)->rows; y++) 3818 { 3819 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3820 (*image)->columns,1,exception); 3821 if (q == (Quantum *) NULL) 3822 break; 3823 for (x=0; x < (int) (*image)->columns; x++) 3824 { 3825 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3826 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3827 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3828 q+=GetPixelChannels(*image); 3829 } 3830 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3831 break; 3832 } 3833 break; 3834 } 3835 } 3836 image_view=DestroyCacheView(image_view); 3837 state&=(~UpdateConfigurationState); 3838 } 3839 } while ((state & ExitState) == 0); 3840 (void) XSelectInput(display,windows->image.id, 3841 windows->image.attributes.event_mask); 3842 XSetCursorState(display,windows,MagickFalse); 3843 (void) XFreeCursor(display,cursor); 3844 return(MagickTrue); 3845} 3846 3847/* 3848%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3849% % 3850% % 3851% % 3852+ X C o m p o s i t e I m a g e % 3853% % 3854% % 3855% % 3856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3857% 3858% XCompositeImage() requests an image name from the user, reads the image and 3859% composites it with the X window image at a location the user chooses with 3860% the pointer. 3861% 3862% The format of the XCompositeImage method is: 3863% 3864% MagickBooleanType XCompositeImage(Display *display, 3865% XResourceInfo *resource_info,XWindows *windows,Image *image) 3866% 3867% A description of each parameter follows: 3868% 3869% o display: Specifies a connection to an X server; returned from 3870% XOpenDisplay. 3871% 3872% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3873% 3874% o windows: Specifies a pointer to a XWindows structure. 3875% 3876% o image: the image; returned from ReadImage. 3877% 3878*/ 3879static MagickBooleanType XCompositeImage(Display *display, 3880 XResourceInfo *resource_info,XWindows *windows,Image *image) 3881{ 3882 static char 3883 displacement_geometry[MaxTextExtent] = "30x30", 3884 filename[MaxTextExtent] = "\0"; 3885 3886 static const char 3887 *CompositeMenu[] = 3888 { 3889 "Operators", 3890 "Dissolve", 3891 "Displace", 3892 "Help", 3893 "Dismiss", 3894 (char *) NULL 3895 }; 3896 3897 static CompositeOperator 3898 compose = CopyCompositeOp; 3899 3900 static const ModeType 3901 CompositeCommands[] = 3902 { 3903 CompositeOperatorsCommand, 3904 CompositeDissolveCommand, 3905 CompositeDisplaceCommand, 3906 CompositeHelpCommand, 3907 CompositeDismissCommand 3908 }; 3909 3910 char 3911 text[MaxTextExtent]; 3912 3913 Cursor 3914 cursor; 3915 3916 Image 3917 *composite_image; 3918 3919 int 3920 entry, 3921 id, 3922 x, 3923 y; 3924 3925 MagickRealType 3926 blend, 3927 scale_factor; 3928 3929 RectangleInfo 3930 highlight_info, 3931 composite_info; 3932 3933 unsigned int 3934 height, 3935 width; 3936 3937 size_t 3938 state; 3939 3940 XEvent 3941 event; 3942 3943 /* 3944 Request image file name from user. 3945 */ 3946 XFileBrowserWidget(display,windows,"Composite",filename); 3947 if (*filename == '\0') 3948 return(MagickTrue); 3949 /* 3950 Read image. 3951 */ 3952 XSetCursorState(display,windows,MagickTrue); 3953 XCheckRefreshWindows(display,windows); 3954 (void) CopyMagickString(resource_info->image_info->filename,filename, 3955 MaxTextExtent); 3956 composite_image=ReadImage(resource_info->image_info,&image->exception); 3957 CatchException(&image->exception); 3958 XSetCursorState(display,windows,MagickFalse); 3959 if (composite_image == (Image *) NULL) 3960 return(MagickFalse); 3961 /* 3962 Map Command widget. 3963 */ 3964 (void) CloneString(&windows->command.name,"Composite"); 3965 windows->command.data=1; 3966 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 3967 (void) XMapRaised(display,windows->command.id); 3968 XClientMessage(display,windows->image.id,windows->im_protocols, 3969 windows->im_update_widget,CurrentTime); 3970 /* 3971 Track pointer until button 1 is pressed. 3972 */ 3973 XQueryPosition(display,windows->image.id,&x,&y); 3974 (void) XSelectInput(display,windows->image.id, 3975 windows->image.attributes.event_mask | PointerMotionMask); 3976 composite_info.x=(ssize_t) windows->image.x+x; 3977 composite_info.y=(ssize_t) windows->image.y+y; 3978 composite_info.width=0; 3979 composite_info.height=0; 3980 cursor=XCreateFontCursor(display,XC_ul_angle); 3981 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3982 blend=0.0; 3983 state=DefaultState; 3984 do 3985 { 3986 if (windows->info.mapped != MagickFalse) 3987 { 3988 /* 3989 Display pointer position. 3990 */ 3991 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 3992 (long) composite_info.x,(long) composite_info.y); 3993 XInfoWidget(display,windows,text); 3994 } 3995 highlight_info=composite_info; 3996 highlight_info.x=composite_info.x-windows->image.x; 3997 highlight_info.y=composite_info.y-windows->image.y; 3998 XHighlightRectangle(display,windows->image.id, 3999 windows->image.highlight_context,&highlight_info); 4000 /* 4001 Wait for next event. 4002 */ 4003 XScreenEvent(display,windows,&event); 4004 XHighlightRectangle(display,windows->image.id, 4005 windows->image.highlight_context,&highlight_info); 4006 if (event.xany.window == windows->command.id) 4007 { 4008 /* 4009 Select a command from the Command widget. 4010 */ 4011 id=XCommandWidget(display,windows,CompositeMenu,&event); 4012 if (id < 0) 4013 continue; 4014 switch (CompositeCommands[id]) 4015 { 4016 case CompositeOperatorsCommand: 4017 { 4018 char 4019 command[MaxTextExtent], 4020 **operators; 4021 4022 /* 4023 Select a command from the pop-up menu. 4024 */ 4025 operators=GetCommandOptions(MagickComposeOptions); 4026 if (operators == (char **) NULL) 4027 break; 4028 entry=XMenuWidget(display,windows,CompositeMenu[id], 4029 (const char **) operators,command); 4030 if (entry >= 0) 4031 compose=(CompositeOperator) ParseCommandOption( 4032 MagickComposeOptions,MagickFalse,operators[entry]); 4033 operators=DestroyStringList(operators); 4034 break; 4035 } 4036 case CompositeDissolveCommand: 4037 { 4038 static char 4039 factor[MaxTextExtent] = "20.0"; 4040 4041 /* 4042 Dissolve the two images a given percent. 4043 */ 4044 (void) XSetFunction(display,windows->image.highlight_context, 4045 GXcopy); 4046 (void) XDialogWidget(display,windows,"Dissolve", 4047 "Enter the blend factor (0.0 - 99.9%):",factor); 4048 (void) XSetFunction(display,windows->image.highlight_context, 4049 GXinvert); 4050 if (*factor == '\0') 4051 break; 4052 blend=InterpretLocaleValue(factor,(char **) NULL); 4053 compose=DissolveCompositeOp; 4054 break; 4055 } 4056 case CompositeDisplaceCommand: 4057 { 4058 /* 4059 Get horizontal and vertical scale displacement geometry. 4060 */ 4061 (void) XSetFunction(display,windows->image.highlight_context, 4062 GXcopy); 4063 (void) XDialogWidget(display,windows,"Displace", 4064 "Enter the horizontal and vertical scale:",displacement_geometry); 4065 (void) XSetFunction(display,windows->image.highlight_context, 4066 GXinvert); 4067 if (*displacement_geometry == '\0') 4068 break; 4069 compose=DisplaceCompositeOp; 4070 break; 4071 } 4072 case CompositeHelpCommand: 4073 { 4074 (void) XSetFunction(display,windows->image.highlight_context, 4075 GXcopy); 4076 XTextViewWidget(display,resource_info,windows,MagickFalse, 4077 "Help Viewer - Image Composite",ImageCompositeHelp); 4078 (void) XSetFunction(display,windows->image.highlight_context, 4079 GXinvert); 4080 break; 4081 } 4082 case CompositeDismissCommand: 4083 { 4084 /* 4085 Prematurely exit. 4086 */ 4087 state|=EscapeState; 4088 state|=ExitState; 4089 break; 4090 } 4091 default: 4092 break; 4093 } 4094 continue; 4095 } 4096 switch (event.type) 4097 { 4098 case ButtonPress: 4099 { 4100 if (image->debug != MagickFalse) 4101 (void) LogMagickEvent(X11Event,GetMagickModule(), 4102 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4103 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4104 if (event.xbutton.button != Button1) 4105 break; 4106 if (event.xbutton.window != windows->image.id) 4107 break; 4108 /* 4109 Change cursor. 4110 */ 4111 composite_info.width=composite_image->columns; 4112 composite_info.height=composite_image->rows; 4113 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4114 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4115 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4116 break; 4117 } 4118 case ButtonRelease: 4119 { 4120 if (image->debug != MagickFalse) 4121 (void) LogMagickEvent(X11Event,GetMagickModule(), 4122 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4123 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4124 if (event.xbutton.button != Button1) 4125 break; 4126 if (event.xbutton.window != windows->image.id) 4127 break; 4128 if ((composite_info.width != 0) && (composite_info.height != 0)) 4129 { 4130 /* 4131 User has selected the location of the composite image. 4132 */ 4133 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4134 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4135 state|=ExitState; 4136 } 4137 break; 4138 } 4139 case Expose: 4140 break; 4141 case KeyPress: 4142 { 4143 char 4144 command[MaxTextExtent]; 4145 4146 KeySym 4147 key_symbol; 4148 4149 int 4150 length; 4151 4152 if (event.xkey.window != windows->image.id) 4153 break; 4154 /* 4155 Respond to a user key press. 4156 */ 4157 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4158 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4159 *(command+length)='\0'; 4160 if (image->debug != MagickFalse) 4161 (void) LogMagickEvent(X11Event,GetMagickModule(), 4162 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4163 switch ((int) key_symbol) 4164 { 4165 case XK_Escape: 4166 case XK_F20: 4167 { 4168 /* 4169 Prematurely exit. 4170 */ 4171 composite_image=DestroyImage(composite_image); 4172 state|=EscapeState; 4173 state|=ExitState; 4174 break; 4175 } 4176 case XK_F1: 4177 case XK_Help: 4178 { 4179 (void) XSetFunction(display,windows->image.highlight_context, 4180 GXcopy); 4181 XTextViewWidget(display,resource_info,windows,MagickFalse, 4182 "Help Viewer - Image Composite",ImageCompositeHelp); 4183 (void) XSetFunction(display,windows->image.highlight_context, 4184 GXinvert); 4185 break; 4186 } 4187 default: 4188 { 4189 (void) XBell(display,0); 4190 break; 4191 } 4192 } 4193 break; 4194 } 4195 case MotionNotify: 4196 { 4197 /* 4198 Map and unmap Info widget as text cursor crosses its boundaries. 4199 */ 4200 x=event.xmotion.x; 4201 y=event.xmotion.y; 4202 if (windows->info.mapped != MagickFalse) 4203 { 4204 if ((x < (int) (windows->info.x+windows->info.width)) && 4205 (y < (int) (windows->info.y+windows->info.height))) 4206 (void) XWithdrawWindow(display,windows->info.id, 4207 windows->info.screen); 4208 } 4209 else 4210 if ((x > (int) (windows->info.x+windows->info.width)) || 4211 (y > (int) (windows->info.y+windows->info.height))) 4212 (void) XMapWindow(display,windows->info.id); 4213 composite_info.x=(ssize_t) windows->image.x+x; 4214 composite_info.y=(ssize_t) windows->image.y+y; 4215 break; 4216 } 4217 default: 4218 { 4219 if (image->debug != MagickFalse) 4220 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4221 event.type); 4222 break; 4223 } 4224 } 4225 } while ((state & ExitState) == 0); 4226 (void) XSelectInput(display,windows->image.id, 4227 windows->image.attributes.event_mask); 4228 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4229 XSetCursorState(display,windows,MagickFalse); 4230 (void) XFreeCursor(display,cursor); 4231 if ((state & EscapeState) != 0) 4232 return(MagickTrue); 4233 /* 4234 Image compositing is relative to image configuration. 4235 */ 4236 XSetCursorState(display,windows,MagickTrue); 4237 XCheckRefreshWindows(display,windows); 4238 width=(unsigned int) image->columns; 4239 height=(unsigned int) image->rows; 4240 x=0; 4241 y=0; 4242 if (windows->image.crop_geometry != (char *) NULL) 4243 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4244 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4245 composite_info.x+=x; 4246 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4247 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4248 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4249 composite_info.y+=y; 4250 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4251 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4252 if ((composite_info.width != composite_image->columns) || 4253 (composite_info.height != composite_image->rows)) 4254 { 4255 Image 4256 *resize_image; 4257 4258 /* 4259 Scale composite image. 4260 */ 4261 resize_image=ResizeImage(composite_image,composite_info.width, 4262 composite_info.height,composite_image->filter,composite_image->blur, 4263 &image->exception); 4264 composite_image=DestroyImage(composite_image); 4265 if (resize_image == (Image *) NULL) 4266 { 4267 XSetCursorState(display,windows,MagickFalse); 4268 return(MagickFalse); 4269 } 4270 composite_image=resize_image; 4271 } 4272 if (compose == DisplaceCompositeOp) 4273 (void) SetImageArtifact(composite_image,"compose:args", 4274 displacement_geometry); 4275 if (blend != 0.0) 4276 { 4277 CacheView 4278 *image_view; 4279 4280 ExceptionInfo 4281 *exception; 4282 4283 int 4284 y; 4285 4286 Quantum 4287 opacity; 4288 4289 register int 4290 x; 4291 4292 register Quantum 4293 *q; 4294 4295 /* 4296 Create mattes for blending. 4297 */ 4298 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel); 4299 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4300 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4301 if (SetImageStorageClass(image,DirectClass) == MagickFalse) 4302 return(MagickFalse); 4303 image->matte=MagickTrue; 4304 exception=(&image->exception); 4305 image_view=AcquireCacheView(image); 4306 for (y=0; y < (int) image->rows; y++) 4307 { 4308 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4309 exception); 4310 if (q == (Quantum *) NULL) 4311 break; 4312 for (x=0; x < (int) image->columns; x++) 4313 { 4314 SetPixelAlpha(image,opacity,q); 4315 q+=GetPixelChannels(image); 4316 } 4317 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4318 break; 4319 } 4320 image_view=DestroyCacheView(image_view); 4321 } 4322 /* 4323 Composite image with X Image window. 4324 */ 4325 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4326 composite_info.y); 4327 composite_image=DestroyImage(composite_image); 4328 XSetCursorState(display,windows,MagickFalse); 4329 /* 4330 Update image configuration. 4331 */ 4332 XConfigureImageColormap(display,resource_info,windows,image); 4333 (void) XConfigureImage(display,resource_info,windows,image); 4334 return(MagickTrue); 4335} 4336 4337/* 4338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4339% % 4340% % 4341% % 4342+ X C o n f i g u r e I m a g e % 4343% % 4344% % 4345% % 4346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4347% 4348% XConfigureImage() creates a new X image. It also notifies the window 4349% manager of the new image size and configures the transient widows. 4350% 4351% The format of the XConfigureImage method is: 4352% 4353% MagickBooleanType XConfigureImage(Display *display, 4354% XResourceInfo *resource_info,XWindows *windows,Image *image) 4355% 4356% A description of each parameter follows: 4357% 4358% o display: Specifies a connection to an X server; returned from 4359% XOpenDisplay. 4360% 4361% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4362% 4363% o windows: Specifies a pointer to a XWindows structure. 4364% 4365% o image: the image. 4366% 4367% 4368*/ 4369static MagickBooleanType XConfigureImage(Display *display, 4370 XResourceInfo *resource_info,XWindows *windows,Image *image) 4371{ 4372 char 4373 geometry[MaxTextExtent]; 4374 4375 MagickStatusType 4376 status; 4377 4378 size_t 4379 mask, 4380 height, 4381 width; 4382 4383 ssize_t 4384 x, 4385 y; 4386 4387 XSizeHints 4388 *size_hints; 4389 4390 XWindowChanges 4391 window_changes; 4392 4393 /* 4394 Dismiss if window dimensions are zero. 4395 */ 4396 width=(unsigned int) windows->image.window_changes.width; 4397 height=(unsigned int) windows->image.window_changes.height; 4398 if (image->debug != MagickFalse) 4399 (void) LogMagickEvent(X11Event,GetMagickModule(), 4400 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4401 windows->image.ximage->height,(double) width,(double) height); 4402 if ((width*height) == 0) 4403 return(MagickTrue); 4404 x=0; 4405 y=0; 4406 /* 4407 Resize image to fit Image window dimensions. 4408 */ 4409 XSetCursorState(display,windows,MagickTrue); 4410 (void) XFlush(display); 4411 if (((int) width != windows->image.ximage->width) || 4412 ((int) height != windows->image.ximage->height)) 4413 image->taint=MagickTrue; 4414 windows->magnify.x=(int) 4415 width*windows->magnify.x/windows->image.ximage->width; 4416 windows->magnify.y=(int) 4417 height*windows->magnify.y/windows->image.ximage->height; 4418 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4419 windows->image.y=(int) 4420 (height*windows->image.y/windows->image.ximage->height); 4421 status=XMakeImage(display,resource_info,&windows->image,image, 4422 (unsigned int) width,(unsigned int) height); 4423 if (status == MagickFalse) 4424 XNoticeWidget(display,windows,"Unable to configure X image:", 4425 windows->image.name); 4426 /* 4427 Notify window manager of the new configuration. 4428 */ 4429 if (resource_info->image_geometry != (char *) NULL) 4430 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4431 resource_info->image_geometry); 4432 else 4433 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4434 XDisplayWidth(display,windows->image.screen), 4435 XDisplayHeight(display,windows->image.screen)); 4436 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4437 window_changes.width=(int) width; 4438 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4439 window_changes.width=XDisplayWidth(display,windows->image.screen); 4440 window_changes.height=(int) height; 4441 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4442 window_changes.height=XDisplayHeight(display,windows->image.screen); 4443 mask=(size_t) (CWWidth | CWHeight); 4444 if (resource_info->backdrop) 4445 { 4446 mask|=CWX | CWY; 4447 window_changes.x=(int) 4448 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4449 window_changes.y=(int) 4450 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4451 } 4452 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4453 (unsigned int) mask,&window_changes); 4454 (void) XClearWindow(display,windows->image.id); 4455 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4456 /* 4457 Update Magnify window configuration. 4458 */ 4459 if (windows->magnify.mapped != MagickFalse) 4460 XMakeMagnifyImage(display,windows); 4461 windows->pan.crop_geometry=windows->image.crop_geometry; 4462 XBestIconSize(display,&windows->pan,image); 4463 while (((windows->pan.width << 1) < MaxIconSize) && 4464 ((windows->pan.height << 1) < MaxIconSize)) 4465 { 4466 windows->pan.width<<=1; 4467 windows->pan.height<<=1; 4468 } 4469 if (windows->pan.geometry != (char *) NULL) 4470 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4471 &windows->pan.width,&windows->pan.height); 4472 window_changes.width=(int) windows->pan.width; 4473 window_changes.height=(int) windows->pan.height; 4474 size_hints=XAllocSizeHints(); 4475 if (size_hints != (XSizeHints *) NULL) 4476 { 4477 /* 4478 Set new size hints. 4479 */ 4480 size_hints->flags=PSize | PMinSize | PMaxSize; 4481 size_hints->width=window_changes.width; 4482 size_hints->height=window_changes.height; 4483 size_hints->min_width=size_hints->width; 4484 size_hints->min_height=size_hints->height; 4485 size_hints->max_width=size_hints->width; 4486 size_hints->max_height=size_hints->height; 4487 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4488 (void) XFree((void *) size_hints); 4489 } 4490 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4491 (unsigned int) (CWWidth | CWHeight),&window_changes); 4492 /* 4493 Update icon window configuration. 4494 */ 4495 windows->icon.crop_geometry=windows->image.crop_geometry; 4496 XBestIconSize(display,&windows->icon,image); 4497 window_changes.width=(int) windows->icon.width; 4498 window_changes.height=(int) windows->icon.height; 4499 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4500 (unsigned int) (CWWidth | CWHeight),&window_changes); 4501 XSetCursorState(display,windows,MagickFalse); 4502 return(status != 0 ? MagickTrue : MagickFalse); 4503} 4504 4505/* 4506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4507% % 4508% % 4509% % 4510+ X C r o p I m a g e % 4511% % 4512% % 4513% % 4514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4515% 4516% XCropImage() allows the user to select a region of the image and crop, copy, 4517% or cut it. For copy or cut, the image can subsequently be composited onto 4518% the image with XPasteImage. 4519% 4520% The format of the XCropImage method is: 4521% 4522% MagickBooleanType XCropImage(Display *display, 4523% XResourceInfo *resource_info,XWindows *windows,Image *image, 4524% const ClipboardMode mode) 4525% 4526% A description of each parameter follows: 4527% 4528% o display: Specifies a connection to an X server; returned from 4529% XOpenDisplay. 4530% 4531% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4532% 4533% o windows: Specifies a pointer to a XWindows structure. 4534% 4535% o image: the image; returned from ReadImage. 4536% 4537% o mode: This unsigned value specified whether the image should be 4538% cropped, copied, or cut. 4539% 4540*/ 4541static MagickBooleanType XCropImage(Display *display, 4542 XResourceInfo *resource_info,XWindows *windows,Image *image, 4543 const ClipboardMode mode) 4544{ 4545 static const char 4546 *CropModeMenu[] = 4547 { 4548 "Help", 4549 "Dismiss", 4550 (char *) NULL 4551 }, 4552 *RectifyModeMenu[] = 4553 { 4554 "Crop", 4555 "Help", 4556 "Dismiss", 4557 (char *) NULL 4558 }; 4559 4560 static const ModeType 4561 CropCommands[] = 4562 { 4563 CropHelpCommand, 4564 CropDismissCommand 4565 }, 4566 RectifyCommands[] = 4567 { 4568 RectifyCopyCommand, 4569 RectifyHelpCommand, 4570 RectifyDismissCommand 4571 }; 4572 4573 CacheView 4574 *image_view; 4575 4576 char 4577 command[MaxTextExtent], 4578 text[MaxTextExtent]; 4579 4580 Cursor 4581 cursor; 4582 4583 ExceptionInfo 4584 *exception; 4585 4586 int 4587 id, 4588 x, 4589 y; 4590 4591 KeySym 4592 key_symbol; 4593 4594 Image 4595 *crop_image; 4596 4597 MagickRealType 4598 scale_factor; 4599 4600 RectangleInfo 4601 crop_info, 4602 highlight_info; 4603 4604 register Quantum 4605 *q; 4606 4607 unsigned int 4608 height, 4609 width; 4610 4611 size_t 4612 state; 4613 4614 XEvent 4615 event; 4616 4617 /* 4618 Map Command widget. 4619 */ 4620 switch (mode) 4621 { 4622 case CopyMode: 4623 { 4624 (void) CloneString(&windows->command.name,"Copy"); 4625 break; 4626 } 4627 case CropMode: 4628 { 4629 (void) CloneString(&windows->command.name,"Crop"); 4630 break; 4631 } 4632 case CutMode: 4633 { 4634 (void) CloneString(&windows->command.name,"Cut"); 4635 break; 4636 } 4637 } 4638 RectifyModeMenu[0]=windows->command.name; 4639 windows->command.data=0; 4640 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4641 (void) XMapRaised(display,windows->command.id); 4642 XClientMessage(display,windows->image.id,windows->im_protocols, 4643 windows->im_update_widget,CurrentTime); 4644 /* 4645 Track pointer until button 1 is pressed. 4646 */ 4647 XQueryPosition(display,windows->image.id,&x,&y); 4648 (void) XSelectInput(display,windows->image.id, 4649 windows->image.attributes.event_mask | PointerMotionMask); 4650 crop_info.x=(ssize_t) windows->image.x+x; 4651 crop_info.y=(ssize_t) windows->image.y+y; 4652 crop_info.width=0; 4653 crop_info.height=0; 4654 cursor=XCreateFontCursor(display,XC_fleur); 4655 state=DefaultState; 4656 do 4657 { 4658 if (windows->info.mapped != MagickFalse) 4659 { 4660 /* 4661 Display pointer position. 4662 */ 4663 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4664 (long) crop_info.x,(long) crop_info.y); 4665 XInfoWidget(display,windows,text); 4666 } 4667 /* 4668 Wait for next event. 4669 */ 4670 XScreenEvent(display,windows,&event); 4671 if (event.xany.window == windows->command.id) 4672 { 4673 /* 4674 Select a command from the Command widget. 4675 */ 4676 id=XCommandWidget(display,windows,CropModeMenu,&event); 4677 if (id < 0) 4678 continue; 4679 switch (CropCommands[id]) 4680 { 4681 case CropHelpCommand: 4682 { 4683 switch (mode) 4684 { 4685 case CopyMode: 4686 { 4687 XTextViewWidget(display,resource_info,windows,MagickFalse, 4688 "Help Viewer - Image Copy",ImageCopyHelp); 4689 break; 4690 } 4691 case CropMode: 4692 { 4693 XTextViewWidget(display,resource_info,windows,MagickFalse, 4694 "Help Viewer - Image Crop",ImageCropHelp); 4695 break; 4696 } 4697 case CutMode: 4698 { 4699 XTextViewWidget(display,resource_info,windows,MagickFalse, 4700 "Help Viewer - Image Cut",ImageCutHelp); 4701 break; 4702 } 4703 } 4704 break; 4705 } 4706 case CropDismissCommand: 4707 { 4708 /* 4709 Prematurely exit. 4710 */ 4711 state|=EscapeState; 4712 state|=ExitState; 4713 break; 4714 } 4715 default: 4716 break; 4717 } 4718 continue; 4719 } 4720 switch (event.type) 4721 { 4722 case ButtonPress: 4723 { 4724 if (event.xbutton.button != Button1) 4725 break; 4726 if (event.xbutton.window != windows->image.id) 4727 break; 4728 /* 4729 Note first corner of cropping rectangle-- exit loop. 4730 */ 4731 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4732 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4733 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4734 state|=ExitState; 4735 break; 4736 } 4737 case ButtonRelease: 4738 break; 4739 case Expose: 4740 break; 4741 case KeyPress: 4742 { 4743 if (event.xkey.window != windows->image.id) 4744 break; 4745 /* 4746 Respond to a user key press. 4747 */ 4748 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4749 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4750 switch ((int) key_symbol) 4751 { 4752 case XK_Escape: 4753 case XK_F20: 4754 { 4755 /* 4756 Prematurely exit. 4757 */ 4758 state|=EscapeState; 4759 state|=ExitState; 4760 break; 4761 } 4762 case XK_F1: 4763 case XK_Help: 4764 { 4765 switch (mode) 4766 { 4767 case CopyMode: 4768 { 4769 XTextViewWidget(display,resource_info,windows,MagickFalse, 4770 "Help Viewer - Image Copy",ImageCopyHelp); 4771 break; 4772 } 4773 case CropMode: 4774 { 4775 XTextViewWidget(display,resource_info,windows,MagickFalse, 4776 "Help Viewer - Image Crop",ImageCropHelp); 4777 break; 4778 } 4779 case CutMode: 4780 { 4781 XTextViewWidget(display,resource_info,windows,MagickFalse, 4782 "Help Viewer - Image Cut",ImageCutHelp); 4783 break; 4784 } 4785 } 4786 break; 4787 } 4788 default: 4789 { 4790 (void) XBell(display,0); 4791 break; 4792 } 4793 } 4794 break; 4795 } 4796 case MotionNotify: 4797 { 4798 if (event.xmotion.window != windows->image.id) 4799 break; 4800 /* 4801 Map and unmap Info widget as text cursor crosses its boundaries. 4802 */ 4803 x=event.xmotion.x; 4804 y=event.xmotion.y; 4805 if (windows->info.mapped != MagickFalse) 4806 { 4807 if ((x < (int) (windows->info.x+windows->info.width)) && 4808 (y < (int) (windows->info.y+windows->info.height))) 4809 (void) XWithdrawWindow(display,windows->info.id, 4810 windows->info.screen); 4811 } 4812 else 4813 if ((x > (int) (windows->info.x+windows->info.width)) || 4814 (y > (int) (windows->info.y+windows->info.height))) 4815 (void) XMapWindow(display,windows->info.id); 4816 crop_info.x=(ssize_t) windows->image.x+x; 4817 crop_info.y=(ssize_t) windows->image.y+y; 4818 break; 4819 } 4820 default: 4821 break; 4822 } 4823 } while ((state & ExitState) == 0); 4824 (void) XSelectInput(display,windows->image.id, 4825 windows->image.attributes.event_mask); 4826 if ((state & EscapeState) != 0) 4827 { 4828 /* 4829 User want to exit without cropping. 4830 */ 4831 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4832 (void) XFreeCursor(display,cursor); 4833 return(MagickTrue); 4834 } 4835 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4836 do 4837 { 4838 /* 4839 Size rectangle as pointer moves until the mouse button is released. 4840 */ 4841 x=(int) crop_info.x; 4842 y=(int) crop_info.y; 4843 crop_info.width=0; 4844 crop_info.height=0; 4845 state=DefaultState; 4846 do 4847 { 4848 highlight_info=crop_info; 4849 highlight_info.x=crop_info.x-windows->image.x; 4850 highlight_info.y=crop_info.y-windows->image.y; 4851 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4852 { 4853 /* 4854 Display info and draw cropping rectangle. 4855 */ 4856 if (windows->info.mapped == MagickFalse) 4857 (void) XMapWindow(display,windows->info.id); 4858 (void) FormatLocaleString(text,MaxTextExtent, 4859 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4860 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4861 XInfoWidget(display,windows,text); 4862 XHighlightRectangle(display,windows->image.id, 4863 windows->image.highlight_context,&highlight_info); 4864 } 4865 else 4866 if (windows->info.mapped != MagickFalse) 4867 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4868 /* 4869 Wait for next event. 4870 */ 4871 XScreenEvent(display,windows,&event); 4872 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4873 XHighlightRectangle(display,windows->image.id, 4874 windows->image.highlight_context,&highlight_info); 4875 switch (event.type) 4876 { 4877 case ButtonPress: 4878 { 4879 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4880 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4881 break; 4882 } 4883 case ButtonRelease: 4884 { 4885 /* 4886 User has committed to cropping rectangle. 4887 */ 4888 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4889 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4890 XSetCursorState(display,windows,MagickFalse); 4891 state|=ExitState; 4892 windows->command.data=0; 4893 (void) XCommandWidget(display,windows,RectifyModeMenu, 4894 (XEvent *) NULL); 4895 break; 4896 } 4897 case Expose: 4898 break; 4899 case MotionNotify: 4900 { 4901 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4902 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4903 } 4904 default: 4905 break; 4906 } 4907 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4908 ((state & ExitState) != 0)) 4909 { 4910 /* 4911 Check boundary conditions. 4912 */ 4913 if (crop_info.x < 0) 4914 crop_info.x=0; 4915 else 4916 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4917 crop_info.x=(ssize_t) windows->image.ximage->width; 4918 if ((int) crop_info.x < x) 4919 crop_info.width=(unsigned int) (x-crop_info.x); 4920 else 4921 { 4922 crop_info.width=(unsigned int) (crop_info.x-x); 4923 crop_info.x=(ssize_t) x; 4924 } 4925 if (crop_info.y < 0) 4926 crop_info.y=0; 4927 else 4928 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4929 crop_info.y=(ssize_t) windows->image.ximage->height; 4930 if ((int) crop_info.y < y) 4931 crop_info.height=(unsigned int) (y-crop_info.y); 4932 else 4933 { 4934 crop_info.height=(unsigned int) (crop_info.y-y); 4935 crop_info.y=(ssize_t) y; 4936 } 4937 } 4938 } while ((state & ExitState) == 0); 4939 /* 4940 Wait for user to grab a corner of the rectangle or press return. 4941 */ 4942 state=DefaultState; 4943 (void) XMapWindow(display,windows->info.id); 4944 do 4945 { 4946 if (windows->info.mapped != MagickFalse) 4947 { 4948 /* 4949 Display pointer position. 4950 */ 4951 (void) FormatLocaleString(text,MaxTextExtent, 4952 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4953 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4954 XInfoWidget(display,windows,text); 4955 } 4956 highlight_info=crop_info; 4957 highlight_info.x=crop_info.x-windows->image.x; 4958 highlight_info.y=crop_info.y-windows->image.y; 4959 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4960 { 4961 state|=EscapeState; 4962 state|=ExitState; 4963 break; 4964 } 4965 XHighlightRectangle(display,windows->image.id, 4966 windows->image.highlight_context,&highlight_info); 4967 XScreenEvent(display,windows,&event); 4968 if (event.xany.window == windows->command.id) 4969 { 4970 /* 4971 Select a command from the Command widget. 4972 */ 4973 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4974 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 4975 (void) XSetFunction(display,windows->image.highlight_context, 4976 GXinvert); 4977 XHighlightRectangle(display,windows->image.id, 4978 windows->image.highlight_context,&highlight_info); 4979 if (id >= 0) 4980 switch (RectifyCommands[id]) 4981 { 4982 case RectifyCopyCommand: 4983 { 4984 state|=ExitState; 4985 break; 4986 } 4987 case RectifyHelpCommand: 4988 { 4989 (void) XSetFunction(display,windows->image.highlight_context, 4990 GXcopy); 4991 switch (mode) 4992 { 4993 case CopyMode: 4994 { 4995 XTextViewWidget(display,resource_info,windows,MagickFalse, 4996 "Help Viewer - Image Copy",ImageCopyHelp); 4997 break; 4998 } 4999 case CropMode: 5000 { 5001 XTextViewWidget(display,resource_info,windows,MagickFalse, 5002 "Help Viewer - Image Crop",ImageCropHelp); 5003 break; 5004 } 5005 case CutMode: 5006 { 5007 XTextViewWidget(display,resource_info,windows,MagickFalse, 5008 "Help Viewer - Image Cut",ImageCutHelp); 5009 break; 5010 } 5011 } 5012 (void) XSetFunction(display,windows->image.highlight_context, 5013 GXinvert); 5014 break; 5015 } 5016 case RectifyDismissCommand: 5017 { 5018 /* 5019 Prematurely exit. 5020 */ 5021 state|=EscapeState; 5022 state|=ExitState; 5023 break; 5024 } 5025 default: 5026 break; 5027 } 5028 continue; 5029 } 5030 XHighlightRectangle(display,windows->image.id, 5031 windows->image.highlight_context,&highlight_info); 5032 switch (event.type) 5033 { 5034 case ButtonPress: 5035 { 5036 if (event.xbutton.button != Button1) 5037 break; 5038 if (event.xbutton.window != windows->image.id) 5039 break; 5040 x=windows->image.x+event.xbutton.x; 5041 y=windows->image.y+event.xbutton.y; 5042 if ((x < (int) (crop_info.x+RoiDelta)) && 5043 (x > (int) (crop_info.x-RoiDelta)) && 5044 (y < (int) (crop_info.y+RoiDelta)) && 5045 (y > (int) (crop_info.y-RoiDelta))) 5046 { 5047 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5048 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5049 state|=UpdateConfigurationState; 5050 break; 5051 } 5052 if ((x < (int) (crop_info.x+RoiDelta)) && 5053 (x > (int) (crop_info.x-RoiDelta)) && 5054 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5055 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5056 { 5057 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5058 state|=UpdateConfigurationState; 5059 break; 5060 } 5061 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5062 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5063 (y < (int) (crop_info.y+RoiDelta)) && 5064 (y > (int) (crop_info.y-RoiDelta))) 5065 { 5066 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5067 state|=UpdateConfigurationState; 5068 break; 5069 } 5070 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5071 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5072 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5073 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5074 { 5075 state|=UpdateConfigurationState; 5076 break; 5077 } 5078 } 5079 case ButtonRelease: 5080 { 5081 if (event.xbutton.window == windows->pan.id) 5082 if ((highlight_info.x != crop_info.x-windows->image.x) || 5083 (highlight_info.y != crop_info.y-windows->image.y)) 5084 XHighlightRectangle(display,windows->image.id, 5085 windows->image.highlight_context,&highlight_info); 5086 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5087 event.xbutton.time); 5088 break; 5089 } 5090 case Expose: 5091 { 5092 if (event.xexpose.window == windows->image.id) 5093 if (event.xexpose.count == 0) 5094 { 5095 event.xexpose.x=(int) highlight_info.x; 5096 event.xexpose.y=(int) highlight_info.y; 5097 event.xexpose.width=(int) highlight_info.width; 5098 event.xexpose.height=(int) highlight_info.height; 5099 XRefreshWindow(display,&windows->image,&event); 5100 } 5101 if (event.xexpose.window == windows->info.id) 5102 if (event.xexpose.count == 0) 5103 XInfoWidget(display,windows,text); 5104 break; 5105 } 5106 case KeyPress: 5107 { 5108 if (event.xkey.window != windows->image.id) 5109 break; 5110 /* 5111 Respond to a user key press. 5112 */ 5113 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5114 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5115 switch ((int) key_symbol) 5116 { 5117 case XK_Escape: 5118 case XK_F20: 5119 state|=EscapeState; 5120 case XK_Return: 5121 { 5122 state|=ExitState; 5123 break; 5124 } 5125 case XK_Home: 5126 case XK_KP_Home: 5127 { 5128 crop_info.x=(ssize_t) (windows->image.width/2L- 5129 crop_info.width/2L); 5130 crop_info.y=(ssize_t) (windows->image.height/2L- 5131 crop_info.height/2L); 5132 break; 5133 } 5134 case XK_Left: 5135 case XK_KP_Left: 5136 { 5137 crop_info.x--; 5138 break; 5139 } 5140 case XK_Up: 5141 case XK_KP_Up: 5142 case XK_Next: 5143 { 5144 crop_info.y--; 5145 break; 5146 } 5147 case XK_Right: 5148 case XK_KP_Right: 5149 { 5150 crop_info.x++; 5151 break; 5152 } 5153 case XK_Prior: 5154 case XK_Down: 5155 case XK_KP_Down: 5156 { 5157 crop_info.y++; 5158 break; 5159 } 5160 case XK_F1: 5161 case XK_Help: 5162 { 5163 (void) XSetFunction(display,windows->image.highlight_context, 5164 GXcopy); 5165 switch (mode) 5166 { 5167 case CopyMode: 5168 { 5169 XTextViewWidget(display,resource_info,windows,MagickFalse, 5170 "Help Viewer - Image Copy",ImageCopyHelp); 5171 break; 5172 } 5173 case CropMode: 5174 { 5175 XTextViewWidget(display,resource_info,windows,MagickFalse, 5176 "Help Viewer - Image Cropg",ImageCropHelp); 5177 break; 5178 } 5179 case CutMode: 5180 { 5181 XTextViewWidget(display,resource_info,windows,MagickFalse, 5182 "Help Viewer - Image Cutg",ImageCutHelp); 5183 break; 5184 } 5185 } 5186 (void) XSetFunction(display,windows->image.highlight_context, 5187 GXinvert); 5188 break; 5189 } 5190 default: 5191 { 5192 (void) XBell(display,0); 5193 break; 5194 } 5195 } 5196 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5197 event.xkey.time); 5198 break; 5199 } 5200 case KeyRelease: 5201 break; 5202 case MotionNotify: 5203 { 5204 if (event.xmotion.window != windows->image.id) 5205 break; 5206 /* 5207 Map and unmap Info widget as text cursor crosses its boundaries. 5208 */ 5209 x=event.xmotion.x; 5210 y=event.xmotion.y; 5211 if (windows->info.mapped != MagickFalse) 5212 { 5213 if ((x < (int) (windows->info.x+windows->info.width)) && 5214 (y < (int) (windows->info.y+windows->info.height))) 5215 (void) XWithdrawWindow(display,windows->info.id, 5216 windows->info.screen); 5217 } 5218 else 5219 if ((x > (int) (windows->info.x+windows->info.width)) || 5220 (y > (int) (windows->info.y+windows->info.height))) 5221 (void) XMapWindow(display,windows->info.id); 5222 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5223 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5224 break; 5225 } 5226 case SelectionRequest: 5227 { 5228 XSelectionEvent 5229 notify; 5230 5231 XSelectionRequestEvent 5232 *request; 5233 5234 /* 5235 Set primary selection. 5236 */ 5237 (void) FormatLocaleString(text,MaxTextExtent, 5238 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5239 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5240 request=(&(event.xselectionrequest)); 5241 (void) XChangeProperty(request->display,request->requestor, 5242 request->property,request->target,8,PropModeReplace, 5243 (unsigned char *) text,(int) strlen(text)); 5244 notify.type=SelectionNotify; 5245 notify.display=request->display; 5246 notify.requestor=request->requestor; 5247 notify.selection=request->selection; 5248 notify.target=request->target; 5249 notify.time=request->time; 5250 if (request->property == None) 5251 notify.property=request->target; 5252 else 5253 notify.property=request->property; 5254 (void) XSendEvent(request->display,request->requestor,False,0, 5255 (XEvent *) ¬ify); 5256 } 5257 default: 5258 break; 5259 } 5260 if ((state & UpdateConfigurationState) != 0) 5261 { 5262 (void) XPutBackEvent(display,&event); 5263 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5264 break; 5265 } 5266 } while ((state & ExitState) == 0); 5267 } while ((state & ExitState) == 0); 5268 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5269 XSetCursorState(display,windows,MagickFalse); 5270 if ((state & EscapeState) != 0) 5271 return(MagickTrue); 5272 if (mode == CropMode) 5273 if (((int) crop_info.width != windows->image.ximage->width) || 5274 ((int) crop_info.height != windows->image.ximage->height)) 5275 { 5276 /* 5277 Reconfigure Image window as defined by cropping rectangle. 5278 */ 5279 XSetCropGeometry(display,windows,&crop_info,image); 5280 windows->image.window_changes.width=(int) crop_info.width; 5281 windows->image.window_changes.height=(int) crop_info.height; 5282 (void) XConfigureImage(display,resource_info,windows,image); 5283 return(MagickTrue); 5284 } 5285 /* 5286 Copy image before applying image transforms. 5287 */ 5288 XSetCursorState(display,windows,MagickTrue); 5289 XCheckRefreshWindows(display,windows); 5290 width=(unsigned int) image->columns; 5291 height=(unsigned int) image->rows; 5292 x=0; 5293 y=0; 5294 if (windows->image.crop_geometry != (char *) NULL) 5295 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5296 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5297 crop_info.x+=x; 5298 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5299 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5300 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5301 crop_info.y+=y; 5302 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5303 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5304 crop_image=CropImage(image,&crop_info,&image->exception); 5305 XSetCursorState(display,windows,MagickFalse); 5306 if (crop_image == (Image *) NULL) 5307 return(MagickFalse); 5308 if (resource_info->copy_image != (Image *) NULL) 5309 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5310 resource_info->copy_image=crop_image; 5311 if (mode == CopyMode) 5312 { 5313 (void) XConfigureImage(display,resource_info,windows,image); 5314 return(MagickTrue); 5315 } 5316 /* 5317 Cut image. 5318 */ 5319 if (SetImageStorageClass(image,DirectClass) == MagickFalse) 5320 return(MagickFalse); 5321 image->matte=MagickTrue; 5322 exception=(&image->exception); 5323 image_view=AcquireCacheView(image); 5324 for (y=0; y < (int) crop_info.height; y++) 5325 { 5326 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5327 crop_info.width,1,exception); 5328 if (q == (Quantum *) NULL) 5329 break; 5330 for (x=0; x < (int) crop_info.width; x++) 5331 { 5332 SetPixelAlpha(image,TransparentAlpha,q); 5333 q+=GetPixelChannels(image); 5334 } 5335 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5336 break; 5337 } 5338 image_view=DestroyCacheView(image_view); 5339 /* 5340 Update image configuration. 5341 */ 5342 XConfigureImageColormap(display,resource_info,windows,image); 5343 (void) XConfigureImage(display,resource_info,windows,image); 5344 return(MagickTrue); 5345} 5346 5347/* 5348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5349% % 5350% % 5351% % 5352+ X D r a w I m a g e % 5353% % 5354% % 5355% % 5356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5357% 5358% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5359% the image. 5360% 5361% The format of the XDrawEditImage method is: 5362% 5363% MagickBooleanType XDrawEditImage(Display *display, 5364% XResourceInfo *resource_info,XWindows *windows,Image **image) 5365% 5366% A description of each parameter follows: 5367% 5368% o display: Specifies a connection to an X server; returned from 5369% XOpenDisplay. 5370% 5371% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5372% 5373% o windows: Specifies a pointer to a XWindows structure. 5374% 5375% o image: the image. 5376% 5377*/ 5378static MagickBooleanType XDrawEditImage(Display *display, 5379 XResourceInfo *resource_info,XWindows *windows,Image **image) 5380{ 5381 static const char 5382 *DrawMenu[] = 5383 { 5384 "Element", 5385 "Color", 5386 "Stipple", 5387 "Width", 5388 "Undo", 5389 "Help", 5390 "Dismiss", 5391 (char *) NULL 5392 }; 5393 5394 static ElementType 5395 element = PointElement; 5396 5397 static const ModeType 5398 DrawCommands[] = 5399 { 5400 DrawElementCommand, 5401 DrawColorCommand, 5402 DrawStippleCommand, 5403 DrawWidthCommand, 5404 DrawUndoCommand, 5405 DrawHelpCommand, 5406 DrawDismissCommand 5407 }; 5408 5409 static Pixmap 5410 stipple = (Pixmap) NULL; 5411 5412 static unsigned int 5413 pen_id = 0, 5414 line_width = 1; 5415 5416 char 5417 command[MaxTextExtent], 5418 text[MaxTextExtent]; 5419 5420 Cursor 5421 cursor; 5422 5423 int 5424 entry, 5425 id, 5426 number_coordinates, 5427 x, 5428 y; 5429 5430 MagickRealType 5431 degrees; 5432 5433 MagickStatusType 5434 status; 5435 5436 RectangleInfo 5437 rectangle_info; 5438 5439 register int 5440 i; 5441 5442 unsigned int 5443 distance, 5444 height, 5445 max_coordinates, 5446 width; 5447 5448 size_t 5449 state; 5450 5451 Window 5452 root_window; 5453 5454 XDrawInfo 5455 draw_info; 5456 5457 XEvent 5458 event; 5459 5460 XPoint 5461 *coordinate_info; 5462 5463 XSegment 5464 line_info; 5465 5466 /* 5467 Allocate polygon info. 5468 */ 5469 max_coordinates=2048; 5470 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5471 sizeof(*coordinate_info)); 5472 if (coordinate_info == (XPoint *) NULL) 5473 { 5474 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 5475 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5476 return(MagickFalse); 5477 } 5478 /* 5479 Map Command widget. 5480 */ 5481 (void) CloneString(&windows->command.name,"Draw"); 5482 windows->command.data=4; 5483 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5484 (void) XMapRaised(display,windows->command.id); 5485 XClientMessage(display,windows->image.id,windows->im_protocols, 5486 windows->im_update_widget,CurrentTime); 5487 /* 5488 Wait for first button press. 5489 */ 5490 root_window=XRootWindow(display,XDefaultScreen(display)); 5491 draw_info.stencil=OpaqueStencil; 5492 status=MagickTrue; 5493 cursor=XCreateFontCursor(display,XC_tcross); 5494 for ( ; ; ) 5495 { 5496 XQueryPosition(display,windows->image.id,&x,&y); 5497 (void) XSelectInput(display,windows->image.id, 5498 windows->image.attributes.event_mask | PointerMotionMask); 5499 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5500 state=DefaultState; 5501 do 5502 { 5503 if (windows->info.mapped != MagickFalse) 5504 { 5505 /* 5506 Display pointer position. 5507 */ 5508 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5509 x+windows->image.x,y+windows->image.y); 5510 XInfoWidget(display,windows,text); 5511 } 5512 /* 5513 Wait for next event. 5514 */ 5515 XScreenEvent(display,windows,&event); 5516 if (event.xany.window == windows->command.id) 5517 { 5518 /* 5519 Select a command from the Command widget. 5520 */ 5521 id=XCommandWidget(display,windows,DrawMenu,&event); 5522 if (id < 0) 5523 continue; 5524 switch (DrawCommands[id]) 5525 { 5526 case DrawElementCommand: 5527 { 5528 static const char 5529 *Elements[] = 5530 { 5531 "point", 5532 "line", 5533 "rectangle", 5534 "fill rectangle", 5535 "circle", 5536 "fill circle", 5537 "ellipse", 5538 "fill ellipse", 5539 "polygon", 5540 "fill polygon", 5541 (char *) NULL, 5542 }; 5543 5544 /* 5545 Select a command from the pop-up menu. 5546 */ 5547 element=(ElementType) (XMenuWidget(display,windows, 5548 DrawMenu[id],Elements,command)+1); 5549 break; 5550 } 5551 case DrawColorCommand: 5552 { 5553 const char 5554 *ColorMenu[MaxNumberPens+1]; 5555 5556 int 5557 pen_number; 5558 5559 MagickBooleanType 5560 transparent; 5561 5562 XColor 5563 color; 5564 5565 /* 5566 Initialize menu selections. 5567 */ 5568 for (i=0; i < (int) (MaxNumberPens-2); i++) 5569 ColorMenu[i]=resource_info->pen_colors[i]; 5570 ColorMenu[MaxNumberPens-2]="transparent"; 5571 ColorMenu[MaxNumberPens-1]="Browser..."; 5572 ColorMenu[MaxNumberPens]=(char *) NULL; 5573 /* 5574 Select a pen color from the pop-up menu. 5575 */ 5576 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5577 (const char **) ColorMenu,command); 5578 if (pen_number < 0) 5579 break; 5580 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5581 MagickFalse; 5582 if (transparent != MagickFalse) 5583 { 5584 draw_info.stencil=TransparentStencil; 5585 break; 5586 } 5587 if (pen_number == (MaxNumberPens-1)) 5588 { 5589 static char 5590 color_name[MaxTextExtent] = "gray"; 5591 5592 /* 5593 Select a pen color from a dialog. 5594 */ 5595 resource_info->pen_colors[pen_number]=color_name; 5596 XColorBrowserWidget(display,windows,"Select",color_name); 5597 if (*color_name == '\0') 5598 break; 5599 } 5600 /* 5601 Set pen color. 5602 */ 5603 (void) XParseColor(display,windows->map_info->colormap, 5604 resource_info->pen_colors[pen_number],&color); 5605 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5606 (unsigned int) MaxColors,&color); 5607 windows->pixel_info->pen_colors[pen_number]=color; 5608 pen_id=(unsigned int) pen_number; 5609 draw_info.stencil=OpaqueStencil; 5610 break; 5611 } 5612 case DrawStippleCommand: 5613 { 5614 Image 5615 *stipple_image; 5616 5617 ImageInfo 5618 *image_info; 5619 5620 int 5621 status; 5622 5623 static char 5624 filename[MaxTextExtent] = "\0"; 5625 5626 static const char 5627 *StipplesMenu[] = 5628 { 5629 "Brick", 5630 "Diagonal", 5631 "Scales", 5632 "Vertical", 5633 "Wavy", 5634 "Translucent", 5635 "Opaque", 5636 (char *) NULL, 5637 (char *) NULL, 5638 }; 5639 5640 /* 5641 Select a command from the pop-up menu. 5642 */ 5643 StipplesMenu[7]="Open..."; 5644 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5645 command); 5646 if (entry < 0) 5647 break; 5648 if (stipple != (Pixmap) NULL) 5649 (void) XFreePixmap(display,stipple); 5650 stipple=(Pixmap) NULL; 5651 if (entry != 7) 5652 { 5653 switch (entry) 5654 { 5655 case 0: 5656 { 5657 stipple=XCreateBitmapFromData(display,root_window, 5658 (char *) BricksBitmap,BricksWidth,BricksHeight); 5659 break; 5660 } 5661 case 1: 5662 { 5663 stipple=XCreateBitmapFromData(display,root_window, 5664 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5665 break; 5666 } 5667 case 2: 5668 { 5669 stipple=XCreateBitmapFromData(display,root_window, 5670 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5671 break; 5672 } 5673 case 3: 5674 { 5675 stipple=XCreateBitmapFromData(display,root_window, 5676 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5677 break; 5678 } 5679 case 4: 5680 { 5681 stipple=XCreateBitmapFromData(display,root_window, 5682 (char *) WavyBitmap,WavyWidth,WavyHeight); 5683 break; 5684 } 5685 case 5: 5686 { 5687 stipple=XCreateBitmapFromData(display,root_window, 5688 (char *) HighlightBitmap,HighlightWidth, 5689 HighlightHeight); 5690 break; 5691 } 5692 case 6: 5693 default: 5694 { 5695 stipple=XCreateBitmapFromData(display,root_window, 5696 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5697 break; 5698 } 5699 } 5700 break; 5701 } 5702 XFileBrowserWidget(display,windows,"Stipple",filename); 5703 if (*filename == '\0') 5704 break; 5705 /* 5706 Read image. 5707 */ 5708 XSetCursorState(display,windows,MagickTrue); 5709 XCheckRefreshWindows(display,windows); 5710 image_info=AcquireImageInfo(); 5711 (void) CopyMagickString(image_info->filename,filename, 5712 MaxTextExtent); 5713 stipple_image=ReadImage(image_info,&(*image)->exception); 5714 CatchException(&(*image)->exception); 5715 XSetCursorState(display,windows,MagickFalse); 5716 if (stipple_image == (Image *) NULL) 5717 break; 5718 (void) AcquireUniqueFileResource(filename); 5719 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5720 "xbm:%s",filename); 5721 (void) WriteImage(image_info,stipple_image); 5722 stipple_image=DestroyImage(stipple_image); 5723 image_info=DestroyImageInfo(image_info); 5724 status=XReadBitmapFile(display,root_window,filename,&width, 5725 &height,&stipple,&x,&y); 5726 (void) RelinquishUniqueFileResource(filename); 5727 if ((status != BitmapSuccess) != 0) 5728 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5729 filename); 5730 break; 5731 } 5732 case DrawWidthCommand: 5733 { 5734 static char 5735 width[MaxTextExtent] = "0"; 5736 5737 static const char 5738 *WidthsMenu[] = 5739 { 5740 "1", 5741 "2", 5742 "4", 5743 "8", 5744 "16", 5745 "Dialog...", 5746 (char *) NULL, 5747 }; 5748 5749 /* 5750 Select a command from the pop-up menu. 5751 */ 5752 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5753 command); 5754 if (entry < 0) 5755 break; 5756 if (entry != 5) 5757 { 5758 line_width=(unsigned int) StringToUnsignedLong( 5759 WidthsMenu[entry]); 5760 break; 5761 } 5762 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5763 width); 5764 if (*width == '\0') 5765 break; 5766 line_width=(unsigned int) StringToUnsignedLong(width); 5767 break; 5768 } 5769 case DrawUndoCommand: 5770 { 5771 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5772 image); 5773 break; 5774 } 5775 case DrawHelpCommand: 5776 { 5777 XTextViewWidget(display,resource_info,windows,MagickFalse, 5778 "Help Viewer - Image Rotation",ImageDrawHelp); 5779 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5780 break; 5781 } 5782 case DrawDismissCommand: 5783 { 5784 /* 5785 Prematurely exit. 5786 */ 5787 state|=EscapeState; 5788 state|=ExitState; 5789 break; 5790 } 5791 default: 5792 break; 5793 } 5794 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5795 continue; 5796 } 5797 switch (event.type) 5798 { 5799 case ButtonPress: 5800 { 5801 if (event.xbutton.button != Button1) 5802 break; 5803 if (event.xbutton.window != windows->image.id) 5804 break; 5805 /* 5806 exit loop. 5807 */ 5808 x=event.xbutton.x; 5809 y=event.xbutton.y; 5810 state|=ExitState; 5811 break; 5812 } 5813 case ButtonRelease: 5814 break; 5815 case Expose: 5816 break; 5817 case KeyPress: 5818 { 5819 KeySym 5820 key_symbol; 5821 5822 if (event.xkey.window != windows->image.id) 5823 break; 5824 /* 5825 Respond to a user key press. 5826 */ 5827 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5828 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5829 switch ((int) key_symbol) 5830 { 5831 case XK_Escape: 5832 case XK_F20: 5833 { 5834 /* 5835 Prematurely exit. 5836 */ 5837 state|=EscapeState; 5838 state|=ExitState; 5839 break; 5840 } 5841 case XK_F1: 5842 case XK_Help: 5843 { 5844 XTextViewWidget(display,resource_info,windows,MagickFalse, 5845 "Help Viewer - Image Rotation",ImageDrawHelp); 5846 break; 5847 } 5848 default: 5849 { 5850 (void) XBell(display,0); 5851 break; 5852 } 5853 } 5854 break; 5855 } 5856 case MotionNotify: 5857 { 5858 /* 5859 Map and unmap Info widget as text cursor crosses its boundaries. 5860 */ 5861 x=event.xmotion.x; 5862 y=event.xmotion.y; 5863 if (windows->info.mapped != MagickFalse) 5864 { 5865 if ((x < (int) (windows->info.x+windows->info.width)) && 5866 (y < (int) (windows->info.y+windows->info.height))) 5867 (void) XWithdrawWindow(display,windows->info.id, 5868 windows->info.screen); 5869 } 5870 else 5871 if ((x > (int) (windows->info.x+windows->info.width)) || 5872 (y > (int) (windows->info.y+windows->info.height))) 5873 (void) XMapWindow(display,windows->info.id); 5874 break; 5875 } 5876 } 5877 } while ((state & ExitState) == 0); 5878 (void) XSelectInput(display,windows->image.id, 5879 windows->image.attributes.event_mask); 5880 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5881 if ((state & EscapeState) != 0) 5882 break; 5883 /* 5884 Draw element as pointer moves until the button is released. 5885 */ 5886 distance=0; 5887 degrees=0.0; 5888 line_info.x1=x; 5889 line_info.y1=y; 5890 line_info.x2=x; 5891 line_info.y2=y; 5892 rectangle_info.x=(ssize_t) x; 5893 rectangle_info.y=(ssize_t) y; 5894 rectangle_info.width=0; 5895 rectangle_info.height=0; 5896 number_coordinates=1; 5897 coordinate_info->x=x; 5898 coordinate_info->y=y; 5899 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5900 state=DefaultState; 5901 do 5902 { 5903 switch (element) 5904 { 5905 case PointElement: 5906 default: 5907 { 5908 if (number_coordinates > 1) 5909 { 5910 (void) XDrawLines(display,windows->image.id, 5911 windows->image.highlight_context,coordinate_info, 5912 number_coordinates,CoordModeOrigin); 5913 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5914 coordinate_info[number_coordinates-1].x, 5915 coordinate_info[number_coordinates-1].y); 5916 XInfoWidget(display,windows,text); 5917 } 5918 break; 5919 } 5920 case LineElement: 5921 { 5922 if (distance > 9) 5923 { 5924 /* 5925 Display angle of the line. 5926 */ 5927 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5928 line_info.y1),(double) (line_info.x2-line_info.x1))); 5929 (void) FormatLocaleString(text,MaxTextExtent," %g", 5930 (double) degrees); 5931 XInfoWidget(display,windows,text); 5932 XHighlightLine(display,windows->image.id, 5933 windows->image.highlight_context,&line_info); 5934 } 5935 else 5936 if (windows->info.mapped != MagickFalse) 5937 (void) XWithdrawWindow(display,windows->info.id, 5938 windows->info.screen); 5939 break; 5940 } 5941 case RectangleElement: 5942 case FillRectangleElement: 5943 { 5944 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5945 { 5946 /* 5947 Display info and draw drawing rectangle. 5948 */ 5949 (void) FormatLocaleString(text,MaxTextExtent, 5950 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5951 (double) rectangle_info.height,(double) rectangle_info.x, 5952 (double) rectangle_info.y); 5953 XInfoWidget(display,windows,text); 5954 XHighlightRectangle(display,windows->image.id, 5955 windows->image.highlight_context,&rectangle_info); 5956 } 5957 else 5958 if (windows->info.mapped != MagickFalse) 5959 (void) XWithdrawWindow(display,windows->info.id, 5960 windows->info.screen); 5961 break; 5962 } 5963 case CircleElement: 5964 case FillCircleElement: 5965 case EllipseElement: 5966 case FillEllipseElement: 5967 { 5968 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5969 { 5970 /* 5971 Display info and draw drawing rectangle. 5972 */ 5973 (void) FormatLocaleString(text,MaxTextExtent, 5974 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5975 (double) rectangle_info.height,(double) rectangle_info.x, 5976 (double) rectangle_info.y); 5977 XInfoWidget(display,windows,text); 5978 XHighlightEllipse(display,windows->image.id, 5979 windows->image.highlight_context,&rectangle_info); 5980 } 5981 else 5982 if (windows->info.mapped != MagickFalse) 5983 (void) XWithdrawWindow(display,windows->info.id, 5984 windows->info.screen); 5985 break; 5986 } 5987 case PolygonElement: 5988 case FillPolygonElement: 5989 { 5990 if (number_coordinates > 1) 5991 (void) XDrawLines(display,windows->image.id, 5992 windows->image.highlight_context,coordinate_info, 5993 number_coordinates,CoordModeOrigin); 5994 if (distance > 9) 5995 { 5996 /* 5997 Display angle of the line. 5998 */ 5999 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6000 line_info.y1),(double) (line_info.x2-line_info.x1))); 6001 (void) FormatLocaleString(text,MaxTextExtent," %g", 6002 (double) degrees); 6003 XInfoWidget(display,windows,text); 6004 XHighlightLine(display,windows->image.id, 6005 windows->image.highlight_context,&line_info); 6006 } 6007 else 6008 if (windows->info.mapped != MagickFalse) 6009 (void) XWithdrawWindow(display,windows->info.id, 6010 windows->info.screen); 6011 break; 6012 } 6013 } 6014 /* 6015 Wait for next event. 6016 */ 6017 XScreenEvent(display,windows,&event); 6018 switch (element) 6019 { 6020 case PointElement: 6021 default: 6022 { 6023 if (number_coordinates > 1) 6024 (void) XDrawLines(display,windows->image.id, 6025 windows->image.highlight_context,coordinate_info, 6026 number_coordinates,CoordModeOrigin); 6027 break; 6028 } 6029 case LineElement: 6030 { 6031 if (distance > 9) 6032 XHighlightLine(display,windows->image.id, 6033 windows->image.highlight_context,&line_info); 6034 break; 6035 } 6036 case RectangleElement: 6037 case FillRectangleElement: 6038 { 6039 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6040 XHighlightRectangle(display,windows->image.id, 6041 windows->image.highlight_context,&rectangle_info); 6042 break; 6043 } 6044 case CircleElement: 6045 case FillCircleElement: 6046 case EllipseElement: 6047 case FillEllipseElement: 6048 { 6049 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6050 XHighlightEllipse(display,windows->image.id, 6051 windows->image.highlight_context,&rectangle_info); 6052 break; 6053 } 6054 case PolygonElement: 6055 case FillPolygonElement: 6056 { 6057 if (number_coordinates > 1) 6058 (void) XDrawLines(display,windows->image.id, 6059 windows->image.highlight_context,coordinate_info, 6060 number_coordinates,CoordModeOrigin); 6061 if (distance > 9) 6062 XHighlightLine(display,windows->image.id, 6063 windows->image.highlight_context,&line_info); 6064 break; 6065 } 6066 } 6067 switch (event.type) 6068 { 6069 case ButtonPress: 6070 break; 6071 case ButtonRelease: 6072 { 6073 /* 6074 User has committed to element. 6075 */ 6076 line_info.x2=event.xbutton.x; 6077 line_info.y2=event.xbutton.y; 6078 rectangle_info.x=(ssize_t) event.xbutton.x; 6079 rectangle_info.y=(ssize_t) event.xbutton.y; 6080 coordinate_info[number_coordinates].x=event.xbutton.x; 6081 coordinate_info[number_coordinates].y=event.xbutton.y; 6082 if (((element != PolygonElement) && 6083 (element != FillPolygonElement)) || (distance <= 9)) 6084 { 6085 state|=ExitState; 6086 break; 6087 } 6088 number_coordinates++; 6089 if (number_coordinates < (int) max_coordinates) 6090 { 6091 line_info.x1=event.xbutton.x; 6092 line_info.y1=event.xbutton.y; 6093 break; 6094 } 6095 max_coordinates<<=1; 6096 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6097 max_coordinates,sizeof(*coordinate_info)); 6098 if (coordinate_info == (XPoint *) NULL) 6099 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 6100 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6101 break; 6102 } 6103 case Expose: 6104 break; 6105 case MotionNotify: 6106 { 6107 if (event.xmotion.window != windows->image.id) 6108 break; 6109 if (element != PointElement) 6110 { 6111 line_info.x2=event.xmotion.x; 6112 line_info.y2=event.xmotion.y; 6113 rectangle_info.x=(ssize_t) event.xmotion.x; 6114 rectangle_info.y=(ssize_t) event.xmotion.y; 6115 break; 6116 } 6117 coordinate_info[number_coordinates].x=event.xbutton.x; 6118 coordinate_info[number_coordinates].y=event.xbutton.y; 6119 number_coordinates++; 6120 if (number_coordinates < (int) max_coordinates) 6121 break; 6122 max_coordinates<<=1; 6123 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6124 max_coordinates,sizeof(*coordinate_info)); 6125 if (coordinate_info == (XPoint *) NULL) 6126 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 6127 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6128 break; 6129 } 6130 default: 6131 break; 6132 } 6133 /* 6134 Check boundary conditions. 6135 */ 6136 if (line_info.x2 < 0) 6137 line_info.x2=0; 6138 else 6139 if (line_info.x2 > (int) windows->image.width) 6140 line_info.x2=(short) windows->image.width; 6141 if (line_info.y2 < 0) 6142 line_info.y2=0; 6143 else 6144 if (line_info.y2 > (int) windows->image.height) 6145 line_info.y2=(short) windows->image.height; 6146 distance=(unsigned int) 6147 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6148 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6149 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6150 ((state & ExitState) != 0)) 6151 { 6152 if (rectangle_info.x < 0) 6153 rectangle_info.x=0; 6154 else 6155 if (rectangle_info.x > (ssize_t) windows->image.width) 6156 rectangle_info.x=(ssize_t) windows->image.width; 6157 if ((int) rectangle_info.x < x) 6158 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6159 else 6160 { 6161 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6162 rectangle_info.x=(ssize_t) x; 6163 } 6164 if (rectangle_info.y < 0) 6165 rectangle_info.y=0; 6166 else 6167 if (rectangle_info.y > (ssize_t) windows->image.height) 6168 rectangle_info.y=(ssize_t) windows->image.height; 6169 if ((int) rectangle_info.y < y) 6170 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6171 else 6172 { 6173 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6174 rectangle_info.y=(ssize_t) y; 6175 } 6176 } 6177 } while ((state & ExitState) == 0); 6178 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6179 if ((element == PointElement) || (element == PolygonElement) || 6180 (element == FillPolygonElement)) 6181 { 6182 /* 6183 Determine polygon bounding box. 6184 */ 6185 rectangle_info.x=(ssize_t) coordinate_info->x; 6186 rectangle_info.y=(ssize_t) coordinate_info->y; 6187 x=coordinate_info->x; 6188 y=coordinate_info->y; 6189 for (i=1; i < number_coordinates; i++) 6190 { 6191 if (coordinate_info[i].x > x) 6192 x=coordinate_info[i].x; 6193 if (coordinate_info[i].y > y) 6194 y=coordinate_info[i].y; 6195 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6196 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6197 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6198 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6199 } 6200 rectangle_info.width=(size_t) (x-rectangle_info.x); 6201 rectangle_info.height=(size_t) (y-rectangle_info.y); 6202 for (i=0; i < number_coordinates; i++) 6203 { 6204 coordinate_info[i].x-=rectangle_info.x; 6205 coordinate_info[i].y-=rectangle_info.y; 6206 } 6207 } 6208 else 6209 if (distance <= 9) 6210 continue; 6211 else 6212 if ((element == RectangleElement) || 6213 (element == CircleElement) || (element == EllipseElement)) 6214 { 6215 rectangle_info.width--; 6216 rectangle_info.height--; 6217 } 6218 /* 6219 Drawing is relative to image configuration. 6220 */ 6221 draw_info.x=(int) rectangle_info.x; 6222 draw_info.y=(int) rectangle_info.y; 6223 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6224 image); 6225 width=(unsigned int) (*image)->columns; 6226 height=(unsigned int) (*image)->rows; 6227 x=0; 6228 y=0; 6229 if (windows->image.crop_geometry != (char *) NULL) 6230 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6231 draw_info.x+=windows->image.x-(line_width/2); 6232 if (draw_info.x < 0) 6233 draw_info.x=0; 6234 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6235 draw_info.y+=windows->image.y-(line_width/2); 6236 if (draw_info.y < 0) 6237 draw_info.y=0; 6238 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6239 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6240 if (draw_info.width > (unsigned int) (*image)->columns) 6241 draw_info.width=(unsigned int) (*image)->columns; 6242 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6243 if (draw_info.height > (unsigned int) (*image)->rows) 6244 draw_info.height=(unsigned int) (*image)->rows; 6245 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6246 width*draw_info.width/windows->image.ximage->width, 6247 height*draw_info.height/windows->image.ximage->height, 6248 draw_info.x+x,draw_info.y+y); 6249 /* 6250 Initialize drawing attributes. 6251 */ 6252 draw_info.degrees=0.0; 6253 draw_info.element=element; 6254 draw_info.stipple=stipple; 6255 draw_info.line_width=line_width; 6256 draw_info.line_info=line_info; 6257 if (line_info.x1 > (int) (line_width/2)) 6258 draw_info.line_info.x1=(short) line_width/2; 6259 if (line_info.y1 > (int) (line_width/2)) 6260 draw_info.line_info.y1=(short) line_width/2; 6261 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6262 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6263 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6264 { 6265 draw_info.line_info.x2=(-draw_info.line_info.x2); 6266 draw_info.line_info.y2=(-draw_info.line_info.y2); 6267 } 6268 if (draw_info.line_info.x2 < 0) 6269 { 6270 draw_info.line_info.x2=(-draw_info.line_info.x2); 6271 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6272 } 6273 if (draw_info.line_info.y2 < 0) 6274 { 6275 draw_info.line_info.y2=(-draw_info.line_info.y2); 6276 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6277 } 6278 draw_info.rectangle_info=rectangle_info; 6279 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6280 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6281 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6282 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6283 draw_info.number_coordinates=(unsigned int) number_coordinates; 6284 draw_info.coordinate_info=coordinate_info; 6285 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6286 /* 6287 Draw element on image. 6288 */ 6289 XSetCursorState(display,windows,MagickTrue); 6290 XCheckRefreshWindows(display,windows); 6291 status=XDrawImage(display,windows->pixel_info,&draw_info,*image); 6292 XSetCursorState(display,windows,MagickFalse); 6293 /* 6294 Update image colormap and return to image drawing. 6295 */ 6296 XConfigureImageColormap(display,resource_info,windows,*image); 6297 (void) XConfigureImage(display,resource_info,windows,*image); 6298 } 6299 XSetCursorState(display,windows,MagickFalse); 6300 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6301 return(status != 0 ? MagickTrue : MagickFalse); 6302} 6303 6304/* 6305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6306% % 6307% % 6308% % 6309+ X D r a w P a n R e c t a n g l e % 6310% % 6311% % 6312% % 6313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6314% 6315% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6316% displays a zoom image and the rectangle shows which portion of the image is 6317% displayed in the Image window. 6318% 6319% The format of the XDrawPanRectangle method is: 6320% 6321% XDrawPanRectangle(Display *display,XWindows *windows) 6322% 6323% A description of each parameter follows: 6324% 6325% o display: Specifies a connection to an X server; returned from 6326% XOpenDisplay. 6327% 6328% o windows: Specifies a pointer to a XWindows structure. 6329% 6330*/ 6331static void XDrawPanRectangle(Display *display,XWindows *windows) 6332{ 6333 MagickRealType 6334 scale_factor; 6335 6336 RectangleInfo 6337 highlight_info; 6338 6339 /* 6340 Determine dimensions of the panning rectangle. 6341 */ 6342 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6343 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6344 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6345 scale_factor=(MagickRealType) 6346 windows->pan.height/windows->image.ximage->height; 6347 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6348 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6349 /* 6350 Display the panning rectangle. 6351 */ 6352 (void) XClearWindow(display,windows->pan.id); 6353 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6354 &highlight_info); 6355} 6356 6357/* 6358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6359% % 6360% % 6361% % 6362+ X I m a g e C a c h e % 6363% % 6364% % 6365% % 6366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6367% 6368% XImageCache() handles the creation, manipulation, and destruction of the 6369% image cache (undo and redo buffers). 6370% 6371% The format of the XImageCache method is: 6372% 6373% void XImageCache(Display *display,XResourceInfo *resource_info, 6374% XWindows *windows,const CommandType command,Image **image) 6375% 6376% A description of each parameter follows: 6377% 6378% o display: Specifies a connection to an X server; returned from 6379% XOpenDisplay. 6380% 6381% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6382% 6383% o windows: Specifies a pointer to a XWindows structure. 6384% 6385% o command: Specifies a command to perform. 6386% 6387% o image: the image; XImageCache may transform the image and return a new 6388% image pointer. 6389% 6390*/ 6391static void XImageCache(Display *display,XResourceInfo *resource_info, 6392 XWindows *windows,const CommandType command,Image **image) 6393{ 6394 Image 6395 *cache_image; 6396 6397 static Image 6398 *redo_image = (Image *) NULL, 6399 *undo_image = (Image *) NULL; 6400 6401 switch (command) 6402 { 6403 case FreeBuffersCommand: 6404 { 6405 /* 6406 Free memory from the undo and redo cache. 6407 */ 6408 while (undo_image != (Image *) NULL) 6409 { 6410 cache_image=undo_image; 6411 undo_image=GetPreviousImageInList(undo_image); 6412 cache_image->list=DestroyImage(cache_image->list); 6413 cache_image=DestroyImage(cache_image); 6414 } 6415 undo_image=NewImageList(); 6416 if (redo_image != (Image *) NULL) 6417 redo_image=DestroyImage(redo_image); 6418 redo_image=NewImageList(); 6419 return; 6420 } 6421 case UndoCommand: 6422 { 6423 char 6424 image_geometry[MaxTextExtent]; 6425 6426 /* 6427 Undo the last image transformation. 6428 */ 6429 if (undo_image == (Image *) NULL) 6430 { 6431 (void) XBell(display,0); 6432 return; 6433 } 6434 cache_image=undo_image; 6435 undo_image=GetPreviousImageInList(undo_image); 6436 windows->image.window_changes.width=(int) cache_image->columns; 6437 windows->image.window_changes.height=(int) cache_image->rows; 6438 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6439 windows->image.ximage->width,windows->image.ximage->height); 6440 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 6441 if (windows->image.crop_geometry != (char *) NULL) 6442 windows->image.crop_geometry=(char *) 6443 RelinquishMagickMemory(windows->image.crop_geometry); 6444 windows->image.crop_geometry=cache_image->geometry; 6445 if (redo_image != (Image *) NULL) 6446 redo_image=DestroyImage(redo_image); 6447 redo_image=(*image); 6448 *image=cache_image->list; 6449 cache_image=DestroyImage(cache_image); 6450 if (windows->image.orphan != MagickFalse) 6451 return; 6452 XConfigureImageColormap(display,resource_info,windows,*image); 6453 (void) XConfigureImage(display,resource_info,windows,*image); 6454 return; 6455 } 6456 case CutCommand: 6457 case PasteCommand: 6458 case ApplyCommand: 6459 case HalfSizeCommand: 6460 case OriginalSizeCommand: 6461 case DoubleSizeCommand: 6462 case ResizeCommand: 6463 case TrimCommand: 6464 case CropCommand: 6465 case ChopCommand: 6466 case FlipCommand: 6467 case FlopCommand: 6468 case RotateRightCommand: 6469 case RotateLeftCommand: 6470 case RotateCommand: 6471 case ShearCommand: 6472 case RollCommand: 6473 case NegateCommand: 6474 case ContrastStretchCommand: 6475 case SigmoidalContrastCommand: 6476 case NormalizeCommand: 6477 case EqualizeCommand: 6478 case HueCommand: 6479 case SaturationCommand: 6480 case BrightnessCommand: 6481 case GammaCommand: 6482 case SpiffCommand: 6483 case DullCommand: 6484 case GrayscaleCommand: 6485 case MapCommand: 6486 case QuantizeCommand: 6487 case DespeckleCommand: 6488 case EmbossCommand: 6489 case ReduceNoiseCommand: 6490 case AddNoiseCommand: 6491 case SharpenCommand: 6492 case BlurCommand: 6493 case ThresholdCommand: 6494 case EdgeDetectCommand: 6495 case SpreadCommand: 6496 case ShadeCommand: 6497 case RaiseCommand: 6498 case SegmentCommand: 6499 case SolarizeCommand: 6500 case SepiaToneCommand: 6501 case SwirlCommand: 6502 case ImplodeCommand: 6503 case VignetteCommand: 6504 case WaveCommand: 6505 case OilPaintCommand: 6506 case CharcoalDrawCommand: 6507 case AnnotateCommand: 6508 case AddBorderCommand: 6509 case AddFrameCommand: 6510 case CompositeCommand: 6511 case CommentCommand: 6512 case LaunchCommand: 6513 case RegionofInterestCommand: 6514 case SaveToUndoBufferCommand: 6515 case RedoCommand: 6516 { 6517 Image 6518 *previous_image; 6519 6520 ssize_t 6521 bytes; 6522 6523 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket)); 6524 if (undo_image != (Image *) NULL) 6525 { 6526 /* 6527 Ensure the undo cache has enough memory available. 6528 */ 6529 previous_image=undo_image; 6530 while (previous_image != (Image *) NULL) 6531 { 6532 bytes+=previous_image->list->columns*previous_image->list->rows* 6533 sizeof(PixelPacket); 6534 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6535 { 6536 previous_image=GetPreviousImageInList(previous_image); 6537 continue; 6538 } 6539 bytes-=previous_image->list->columns*previous_image->list->rows* 6540 sizeof(PixelPacket); 6541 if (previous_image == undo_image) 6542 undo_image=NewImageList(); 6543 else 6544 previous_image->next->previous=NewImageList(); 6545 break; 6546 } 6547 while (previous_image != (Image *) NULL) 6548 { 6549 /* 6550 Delete any excess memory from undo cache. 6551 */ 6552 cache_image=previous_image; 6553 previous_image=GetPreviousImageInList(previous_image); 6554 cache_image->list=DestroyImage(cache_image->list); 6555 cache_image=DestroyImage(cache_image); 6556 } 6557 } 6558 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6559 break; 6560 /* 6561 Save image before transformations are applied. 6562 */ 6563 cache_image=AcquireImage((ImageInfo *) NULL); 6564 if (cache_image == (Image *) NULL) 6565 break; 6566 XSetCursorState(display,windows,MagickTrue); 6567 XCheckRefreshWindows(display,windows); 6568 cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 6569 XSetCursorState(display,windows,MagickFalse); 6570 if (cache_image->list == (Image *) NULL) 6571 { 6572 cache_image=DestroyImage(cache_image); 6573 break; 6574 } 6575 cache_image->columns=(size_t) windows->image.ximage->width; 6576 cache_image->rows=(size_t) windows->image.ximage->height; 6577 cache_image->geometry=windows->image.crop_geometry; 6578 if (windows->image.crop_geometry != (char *) NULL) 6579 { 6580 cache_image->geometry=AcquireString((char *) NULL); 6581 (void) CopyMagickString(cache_image->geometry, 6582 windows->image.crop_geometry,MaxTextExtent); 6583 } 6584 if (undo_image == (Image *) NULL) 6585 { 6586 undo_image=cache_image; 6587 break; 6588 } 6589 undo_image->next=cache_image; 6590 undo_image->next->previous=undo_image; 6591 undo_image=undo_image->next; 6592 break; 6593 } 6594 default: 6595 break; 6596 } 6597 if (command == RedoCommand) 6598 { 6599 /* 6600 Redo the last image transformation. 6601 */ 6602 if (redo_image == (Image *) NULL) 6603 { 6604 (void) XBell(display,0); 6605 return; 6606 } 6607 windows->image.window_changes.width=(int) redo_image->columns; 6608 windows->image.window_changes.height=(int) redo_image->rows; 6609 if (windows->image.crop_geometry != (char *) NULL) 6610 windows->image.crop_geometry=(char *) 6611 RelinquishMagickMemory(windows->image.crop_geometry); 6612 windows->image.crop_geometry=redo_image->geometry; 6613 *image=DestroyImage(*image); 6614 *image=redo_image; 6615 redo_image=NewImageList(); 6616 if (windows->image.orphan != MagickFalse) 6617 return; 6618 XConfigureImageColormap(display,resource_info,windows,*image); 6619 (void) XConfigureImage(display,resource_info,windows,*image); 6620 return; 6621 } 6622 if (command != InfoCommand) 6623 return; 6624 /* 6625 Display image info. 6626 */ 6627 XSetCursorState(display,windows,MagickTrue); 6628 XCheckRefreshWindows(display,windows); 6629 XDisplayImageInfo(display,resource_info,windows,undo_image,*image); 6630 XSetCursorState(display,windows,MagickFalse); 6631} 6632 6633/* 6634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6635% % 6636% % 6637% % 6638+ X I m a g e W i n d o w C o m m a n d % 6639% % 6640% % 6641% % 6642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6643% 6644% XImageWindowCommand() makes a transform to the image or Image window as 6645% specified by a user menu button or keyboard command. 6646% 6647% The format of the XMagickCommand method is: 6648% 6649% CommandType XImageWindowCommand(Display *display, 6650% XResourceInfo *resource_info,XWindows *windows, 6651% const MagickStatusType state,KeySym key_symbol,Image **image) 6652% 6653% A description of each parameter follows: 6654% 6655% o nexus: Method XImageWindowCommand returns an image when the 6656% user chooses 'Open Image' from the command menu. Otherwise a null 6657% image is returned. 6658% 6659% o display: Specifies a connection to an X server; returned from 6660% XOpenDisplay. 6661% 6662% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6663% 6664% o windows: Specifies a pointer to a XWindows structure. 6665% 6666% o state: key mask. 6667% 6668% o key_symbol: Specifies a command to perform. 6669% 6670% o image: the image; XImageWIndowCommand 6671% may transform the image and return a new image pointer. 6672% 6673*/ 6674static CommandType XImageWindowCommand(Display *display, 6675 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6676 KeySym key_symbol,Image **image) 6677{ 6678 static char 6679 delta[MaxTextExtent] = ""; 6680 6681 static const char 6682 Digits[] = "01234567890"; 6683 6684 static KeySym 6685 last_symbol = XK_0; 6686 6687 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6688 { 6689 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6690 { 6691 *delta='\0'; 6692 resource_info->quantum=1; 6693 } 6694 last_symbol=key_symbol; 6695 delta[strlen(delta)+1]='\0'; 6696 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6697 resource_info->quantum=StringToLong(delta); 6698 return(NullCommand); 6699 } 6700 last_symbol=key_symbol; 6701 if (resource_info->immutable) 6702 { 6703 /* 6704 Virtual image window has a restricted command set. 6705 */ 6706 switch (key_symbol) 6707 { 6708 case XK_question: 6709 return(InfoCommand); 6710 case XK_p: 6711 case XK_Print: 6712 return(PrintCommand); 6713 case XK_space: 6714 return(NextCommand); 6715 case XK_q: 6716 case XK_Escape: 6717 return(QuitCommand); 6718 default: 6719 break; 6720 } 6721 return(NullCommand); 6722 } 6723 switch ((int) key_symbol) 6724 { 6725 case XK_o: 6726 { 6727 if ((state & ControlMask) == 0) 6728 break; 6729 return(OpenCommand); 6730 } 6731 case XK_space: 6732 return(NextCommand); 6733 case XK_BackSpace: 6734 return(FormerCommand); 6735 case XK_s: 6736 { 6737 if ((state & Mod1Mask) != 0) 6738 return(SwirlCommand); 6739 if ((state & ControlMask) == 0) 6740 return(ShearCommand); 6741 return(SaveCommand); 6742 } 6743 case XK_p: 6744 case XK_Print: 6745 { 6746 if ((state & Mod1Mask) != 0) 6747 return(OilPaintCommand); 6748 if ((state & Mod4Mask) != 0) 6749 return(ColorCommand); 6750 if ((state & ControlMask) == 0) 6751 return(NullCommand); 6752 return(PrintCommand); 6753 } 6754 case XK_d: 6755 { 6756 if ((state & Mod4Mask) != 0) 6757 return(DrawCommand); 6758 if ((state & ControlMask) == 0) 6759 return(NullCommand); 6760 return(DeleteCommand); 6761 } 6762 case XK_Select: 6763 { 6764 if ((state & ControlMask) == 0) 6765 return(NullCommand); 6766 return(SelectCommand); 6767 } 6768 case XK_n: 6769 { 6770 if ((state & ControlMask) == 0) 6771 return(NullCommand); 6772 return(NewCommand); 6773 } 6774 case XK_q: 6775 case XK_Escape: 6776 return(QuitCommand); 6777 case XK_z: 6778 case XK_Undo: 6779 { 6780 if ((state & ControlMask) == 0) 6781 return(NullCommand); 6782 return(UndoCommand); 6783 } 6784 case XK_r: 6785 case XK_Redo: 6786 { 6787 if ((state & ControlMask) == 0) 6788 return(RollCommand); 6789 return(RedoCommand); 6790 } 6791 case XK_x: 6792 { 6793 if ((state & ControlMask) == 0) 6794 return(NullCommand); 6795 return(CutCommand); 6796 } 6797 case XK_c: 6798 { 6799 if ((state & Mod1Mask) != 0) 6800 return(CharcoalDrawCommand); 6801 if ((state & ControlMask) == 0) 6802 return(CropCommand); 6803 return(CopyCommand); 6804 } 6805 case XK_v: 6806 case XK_Insert: 6807 { 6808 if ((state & Mod4Mask) != 0) 6809 return(CompositeCommand); 6810 if ((state & ControlMask) == 0) 6811 return(FlipCommand); 6812 return(PasteCommand); 6813 } 6814 case XK_less: 6815 return(HalfSizeCommand); 6816 case XK_minus: 6817 return(OriginalSizeCommand); 6818 case XK_greater: 6819 return(DoubleSizeCommand); 6820 case XK_percent: 6821 return(ResizeCommand); 6822 case XK_at: 6823 return(RefreshCommand); 6824 case XK_bracketleft: 6825 return(ChopCommand); 6826 case XK_h: 6827 return(FlopCommand); 6828 case XK_slash: 6829 return(RotateRightCommand); 6830 case XK_backslash: 6831 return(RotateLeftCommand); 6832 case XK_asterisk: 6833 return(RotateCommand); 6834 case XK_t: 6835 return(TrimCommand); 6836 case XK_H: 6837 return(HueCommand); 6838 case XK_S: 6839 return(SaturationCommand); 6840 case XK_L: 6841 return(BrightnessCommand); 6842 case XK_G: 6843 return(GammaCommand); 6844 case XK_C: 6845 return(SpiffCommand); 6846 case XK_Z: 6847 return(DullCommand); 6848 case XK_N: 6849 return(NormalizeCommand); 6850 case XK_equal: 6851 return(EqualizeCommand); 6852 case XK_asciitilde: 6853 return(NegateCommand); 6854 case XK_period: 6855 return(GrayscaleCommand); 6856 case XK_numbersign: 6857 return(QuantizeCommand); 6858 case XK_F2: 6859 return(DespeckleCommand); 6860 case XK_F3: 6861 return(EmbossCommand); 6862 case XK_F4: 6863 return(ReduceNoiseCommand); 6864 case XK_F5: 6865 return(AddNoiseCommand); 6866 case XK_F6: 6867 return(SharpenCommand); 6868 case XK_F7: 6869 return(BlurCommand); 6870 case XK_F8: 6871 return(ThresholdCommand); 6872 case XK_F9: 6873 return(EdgeDetectCommand); 6874 case XK_F10: 6875 return(SpreadCommand); 6876 case XK_F11: 6877 return(ShadeCommand); 6878 case XK_F12: 6879 return(RaiseCommand); 6880 case XK_F13: 6881 return(SegmentCommand); 6882 case XK_i: 6883 { 6884 if ((state & Mod1Mask) == 0) 6885 return(NullCommand); 6886 return(ImplodeCommand); 6887 } 6888 case XK_w: 6889 { 6890 if ((state & Mod1Mask) == 0) 6891 return(NullCommand); 6892 return(WaveCommand); 6893 } 6894 case XK_m: 6895 { 6896 if ((state & Mod4Mask) == 0) 6897 return(NullCommand); 6898 return(MatteCommand); 6899 } 6900 case XK_b: 6901 { 6902 if ((state & Mod4Mask) == 0) 6903 return(NullCommand); 6904 return(AddBorderCommand); 6905 } 6906 case XK_f: 6907 { 6908 if ((state & Mod4Mask) == 0) 6909 return(NullCommand); 6910 return(AddFrameCommand); 6911 } 6912 case XK_exclam: 6913 { 6914 if ((state & Mod4Mask) == 0) 6915 return(NullCommand); 6916 return(CommentCommand); 6917 } 6918 case XK_a: 6919 { 6920 if ((state & Mod1Mask) != 0) 6921 return(ApplyCommand); 6922 if ((state & Mod4Mask) != 0) 6923 return(AnnotateCommand); 6924 if ((state & ControlMask) == 0) 6925 return(NullCommand); 6926 return(RegionofInterestCommand); 6927 } 6928 case XK_question: 6929 return(InfoCommand); 6930 case XK_plus: 6931 return(ZoomCommand); 6932 case XK_P: 6933 { 6934 if ((state & ShiftMask) == 0) 6935 return(NullCommand); 6936 return(ShowPreviewCommand); 6937 } 6938 case XK_Execute: 6939 return(LaunchCommand); 6940 case XK_F1: 6941 return(HelpCommand); 6942 case XK_Find: 6943 return(BrowseDocumentationCommand); 6944 case XK_Menu: 6945 { 6946 (void) XMapRaised(display,windows->command.id); 6947 return(NullCommand); 6948 } 6949 case XK_Next: 6950 case XK_Prior: 6951 case XK_Home: 6952 case XK_KP_Home: 6953 { 6954 XTranslateImage(display,windows,*image,key_symbol); 6955 return(NullCommand); 6956 } 6957 case XK_Up: 6958 case XK_KP_Up: 6959 case XK_Down: 6960 case XK_KP_Down: 6961 case XK_Left: 6962 case XK_KP_Left: 6963 case XK_Right: 6964 case XK_KP_Right: 6965 { 6966 if ((state & Mod1Mask) != 0) 6967 { 6968 RectangleInfo 6969 crop_info; 6970 6971 /* 6972 Trim one pixel from edge of image. 6973 */ 6974 crop_info.x=0; 6975 crop_info.y=0; 6976 crop_info.width=(size_t) windows->image.ximage->width; 6977 crop_info.height=(size_t) windows->image.ximage->height; 6978 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 6979 { 6980 if (resource_info->quantum >= (int) crop_info.height) 6981 resource_info->quantum=(int) crop_info.height-1; 6982 crop_info.height-=resource_info->quantum; 6983 } 6984 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 6985 { 6986 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 6987 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 6988 crop_info.y+=resource_info->quantum; 6989 crop_info.height-=resource_info->quantum; 6990 } 6991 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 6992 { 6993 if (resource_info->quantum >= (int) crop_info.width) 6994 resource_info->quantum=(int) crop_info.width-1; 6995 crop_info.width-=resource_info->quantum; 6996 } 6997 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 6998 { 6999 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7000 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7001 crop_info.x+=resource_info->quantum; 7002 crop_info.width-=resource_info->quantum; 7003 } 7004 if ((int) (windows->image.x+windows->image.width) > 7005 (int) crop_info.width) 7006 windows->image.x=(int) (crop_info.width-windows->image.width); 7007 if ((int) (windows->image.y+windows->image.height) > 7008 (int) crop_info.height) 7009 windows->image.y=(int) (crop_info.height-windows->image.height); 7010 XSetCropGeometry(display,windows,&crop_info,*image); 7011 windows->image.window_changes.width=(int) crop_info.width; 7012 windows->image.window_changes.height=(int) crop_info.height; 7013 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7014 (void) XConfigureImage(display,resource_info,windows,*image); 7015 return(NullCommand); 7016 } 7017 XTranslateImage(display,windows,*image,key_symbol); 7018 return(NullCommand); 7019 } 7020 default: 7021 return(NullCommand); 7022 } 7023 return(NullCommand); 7024} 7025 7026/* 7027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7028% % 7029% % 7030% % 7031+ X M a g i c k C o m m a n d % 7032% % 7033% % 7034% % 7035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7036% 7037% XMagickCommand() makes a transform to the image or Image window as 7038% specified by a user menu button or keyboard command. 7039% 7040% The format of the XMagickCommand method is: 7041% 7042% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7043% XWindows *windows,const CommandType command,Image **image) 7044% 7045% A description of each parameter follows: 7046% 7047% o nexus: Method XMagickCommand returns an image when the 7048% user chooses 'Load Image' from the command menu. Otherwise a null 7049% image is returned. 7050% 7051% o display: Specifies a connection to an X server; returned from 7052% XOpenDisplay. 7053% 7054% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7055% 7056% o windows: Specifies a pointer to a XWindows structure. 7057% 7058% o command: Specifies a command to perform. 7059% 7060% o image: the image; XMagickCommand 7061% may transform the image and return a new image pointer. 7062% 7063*/ 7064static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7065 XWindows *windows,const CommandType command,Image **image) 7066{ 7067 char 7068 filename[MaxTextExtent], 7069 geometry[MaxTextExtent], 7070 modulate_factors[MaxTextExtent]; 7071 7072 GeometryInfo 7073 geometry_info; 7074 7075 Image 7076 *nexus; 7077 7078 ImageInfo 7079 *image_info; 7080 7081 int 7082 x, 7083 y; 7084 7085 MagickStatusType 7086 flags, 7087 status; 7088 7089 QuantizeInfo 7090 quantize_info; 7091 7092 RectangleInfo 7093 page_geometry; 7094 7095 register int 7096 i; 7097 7098 static char 7099 color[MaxTextExtent] = "gray"; 7100 7101 unsigned int 7102 height, 7103 width; 7104 7105 /* 7106 Process user command. 7107 */ 7108 XCheckRefreshWindows(display,windows); 7109 XImageCache(display,resource_info,windows,command,image); 7110 nexus=NewImageList(); 7111 windows->image.window_changes.width=windows->image.ximage->width; 7112 windows->image.window_changes.height=windows->image.ximage->height; 7113 image_info=CloneImageInfo(resource_info->image_info); 7114 SetGeometryInfo(&geometry_info); 7115 GetQuantizeInfo(&quantize_info); 7116 switch (command) 7117 { 7118 case OpenCommand: 7119 { 7120 /* 7121 Load image. 7122 */ 7123 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7124 break; 7125 } 7126 case NextCommand: 7127 { 7128 /* 7129 Display next image. 7130 */ 7131 for (i=0; i < resource_info->quantum; i++) 7132 XClientMessage(display,windows->image.id,windows->im_protocols, 7133 windows->im_next_image,CurrentTime); 7134 break; 7135 } 7136 case FormerCommand: 7137 { 7138 /* 7139 Display former image. 7140 */ 7141 for (i=0; i < resource_info->quantum; i++) 7142 XClientMessage(display,windows->image.id,windows->im_protocols, 7143 windows->im_former_image,CurrentTime); 7144 break; 7145 } 7146 case SelectCommand: 7147 { 7148 int 7149 status; 7150 7151 /* 7152 Select image. 7153 */ 7154 status=chdir(resource_info->home_directory); 7155 if (status == -1) 7156 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 7157 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 7158 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7159 break; 7160 } 7161 case SaveCommand: 7162 { 7163 /* 7164 Save image. 7165 */ 7166 status=XSaveImage(display,resource_info,windows,*image); 7167 if (status == MagickFalse) 7168 { 7169 XNoticeWidget(display,windows,"Unable to write X image:", 7170 (*image)->filename); 7171 break; 7172 } 7173 break; 7174 } 7175 case PrintCommand: 7176 { 7177 /* 7178 Print image. 7179 */ 7180 status=XPrintImage(display,resource_info,windows,*image); 7181 if (status == MagickFalse) 7182 { 7183 XNoticeWidget(display,windows,"Unable to print X image:", 7184 (*image)->filename); 7185 break; 7186 } 7187 break; 7188 } 7189 case DeleteCommand: 7190 { 7191 static char 7192 filename[MaxTextExtent] = "\0"; 7193 7194 /* 7195 Delete image file. 7196 */ 7197 XFileBrowserWidget(display,windows,"Delete",filename); 7198 if (*filename == '\0') 7199 break; 7200 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 7201 if (status != MagickFalse) 7202 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7203 break; 7204 } 7205 case NewCommand: 7206 { 7207 int 7208 status; 7209 7210 static char 7211 color[MaxTextExtent] = "gray", 7212 geometry[MaxTextExtent] = "640x480"; 7213 7214 static const char 7215 *format = "gradient"; 7216 7217 /* 7218 Query user for canvas geometry. 7219 */ 7220 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7221 geometry); 7222 if (*geometry == '\0') 7223 break; 7224 if (status == 0) 7225 format="xc"; 7226 XColorBrowserWidget(display,windows,"Select",color); 7227 if (*color == '\0') 7228 break; 7229 /* 7230 Create canvas. 7231 */ 7232 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7233 "%s:%s",format,color); 7234 (void) CloneString(&image_info->size,geometry); 7235 nexus=ReadImage(image_info,&(*image)->exception); 7236 CatchException(&(*image)->exception); 7237 XClientMessage(display,windows->image.id,windows->im_protocols, 7238 windows->im_next_image,CurrentTime); 7239 break; 7240 } 7241 case VisualDirectoryCommand: 7242 { 7243 /* 7244 Visual Image directory. 7245 */ 7246 nexus=XVisualDirectoryImage(display,resource_info,windows); 7247 break; 7248 } 7249 case QuitCommand: 7250 { 7251 /* 7252 exit program. 7253 */ 7254 if (resource_info->confirm_exit == MagickFalse) 7255 XClientMessage(display,windows->image.id,windows->im_protocols, 7256 windows->im_exit,CurrentTime); 7257 else 7258 { 7259 int 7260 status; 7261 7262 /* 7263 Confirm program exit. 7264 */ 7265 status=XConfirmWidget(display,windows,"Do you really want to exit", 7266 resource_info->client_name); 7267 if (status > 0) 7268 XClientMessage(display,windows->image.id,windows->im_protocols, 7269 windows->im_exit,CurrentTime); 7270 } 7271 break; 7272 } 7273 case CutCommand: 7274 { 7275 /* 7276 Cut image. 7277 */ 7278 (void) XCropImage(display,resource_info,windows,*image,CutMode); 7279 break; 7280 } 7281 case CopyCommand: 7282 { 7283 /* 7284 Copy image. 7285 */ 7286 (void) XCropImage(display,resource_info,windows,*image,CopyMode); 7287 break; 7288 } 7289 case PasteCommand: 7290 { 7291 /* 7292 Paste image. 7293 */ 7294 status=XPasteImage(display,resource_info,windows,*image); 7295 if (status == MagickFalse) 7296 { 7297 XNoticeWidget(display,windows,"Unable to paste X image", 7298 (*image)->filename); 7299 break; 7300 } 7301 break; 7302 } 7303 case HalfSizeCommand: 7304 { 7305 /* 7306 Half image size. 7307 */ 7308 windows->image.window_changes.width=windows->image.ximage->width/2; 7309 windows->image.window_changes.height=windows->image.ximage->height/2; 7310 (void) XConfigureImage(display,resource_info,windows,*image); 7311 break; 7312 } 7313 case OriginalSizeCommand: 7314 { 7315 /* 7316 Original image size. 7317 */ 7318 windows->image.window_changes.width=(int) (*image)->columns; 7319 windows->image.window_changes.height=(int) (*image)->rows; 7320 (void) XConfigureImage(display,resource_info,windows,*image); 7321 break; 7322 } 7323 case DoubleSizeCommand: 7324 { 7325 /* 7326 Double the image size. 7327 */ 7328 windows->image.window_changes.width=windows->image.ximage->width << 1; 7329 windows->image.window_changes.height=windows->image.ximage->height << 1; 7330 (void) XConfigureImage(display,resource_info,windows,*image); 7331 break; 7332 } 7333 case ResizeCommand: 7334 { 7335 int 7336 status; 7337 7338 size_t 7339 height, 7340 width; 7341 7342 ssize_t 7343 x, 7344 y; 7345 7346 /* 7347 Resize image. 7348 */ 7349 width=(size_t) windows->image.ximage->width; 7350 height=(size_t) windows->image.ximage->height; 7351 x=0; 7352 y=0; 7353 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7354 (double) width,(double) height); 7355 status=XDialogWidget(display,windows,"Resize", 7356 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7357 if (*geometry == '\0') 7358 break; 7359 if (status == 0) 7360 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7361 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7362 windows->image.window_changes.width=(int) width; 7363 windows->image.window_changes.height=(int) height; 7364 (void) XConfigureImage(display,resource_info,windows,*image); 7365 break; 7366 } 7367 case ApplyCommand: 7368 { 7369 char 7370 image_geometry[MaxTextExtent]; 7371 7372 if ((windows->image.crop_geometry == (char *) NULL) && 7373 ((int) (*image)->columns == windows->image.ximage->width) && 7374 ((int) (*image)->rows == windows->image.ximage->height)) 7375 break; 7376 /* 7377 Apply size transforms to image. 7378 */ 7379 XSetCursorState(display,windows,MagickTrue); 7380 XCheckRefreshWindows(display,windows); 7381 /* 7382 Crop and/or scale displayed image. 7383 */ 7384 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7385 windows->image.ximage->width,windows->image.ximage->height); 7386 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 7387 if (windows->image.crop_geometry != (char *) NULL) 7388 windows->image.crop_geometry=(char *) 7389 RelinquishMagickMemory(windows->image.crop_geometry); 7390 windows->image.x=0; 7391 windows->image.y=0; 7392 XConfigureImageColormap(display,resource_info,windows,*image); 7393 (void) XConfigureImage(display,resource_info,windows,*image); 7394 break; 7395 } 7396 case RefreshCommand: 7397 { 7398 (void) XConfigureImage(display,resource_info,windows,*image); 7399 break; 7400 } 7401 case RestoreCommand: 7402 { 7403 /* 7404 Restore Image window to its original size. 7405 */ 7406 if ((windows->image.width == (unsigned int) (*image)->columns) && 7407 (windows->image.height == (unsigned int) (*image)->rows) && 7408 (windows->image.crop_geometry == (char *) NULL)) 7409 { 7410 (void) XBell(display,0); 7411 break; 7412 } 7413 windows->image.window_changes.width=(int) (*image)->columns; 7414 windows->image.window_changes.height=(int) (*image)->rows; 7415 if (windows->image.crop_geometry != (char *) NULL) 7416 { 7417 windows->image.crop_geometry=(char *) 7418 RelinquishMagickMemory(windows->image.crop_geometry); 7419 windows->image.crop_geometry=(char *) NULL; 7420 windows->image.x=0; 7421 windows->image.y=0; 7422 } 7423 XConfigureImageColormap(display,resource_info,windows,*image); 7424 (void) XConfigureImage(display,resource_info,windows,*image); 7425 break; 7426 } 7427 case CropCommand: 7428 { 7429 /* 7430 Crop image. 7431 */ 7432 (void) XCropImage(display,resource_info,windows,*image,CropMode); 7433 break; 7434 } 7435 case ChopCommand: 7436 { 7437 /* 7438 Chop image. 7439 */ 7440 status=XChopImage(display,resource_info,windows,image); 7441 if (status == MagickFalse) 7442 { 7443 XNoticeWidget(display,windows,"Unable to cut X image", 7444 (*image)->filename); 7445 break; 7446 } 7447 break; 7448 } 7449 case FlopCommand: 7450 { 7451 Image 7452 *flop_image; 7453 7454 /* 7455 Flop image scanlines. 7456 */ 7457 XSetCursorState(display,windows,MagickTrue); 7458 XCheckRefreshWindows(display,windows); 7459 flop_image=FlopImage(*image,&(*image)->exception); 7460 if (flop_image != (Image *) NULL) 7461 { 7462 *image=DestroyImage(*image); 7463 *image=flop_image; 7464 } 7465 CatchException(&(*image)->exception); 7466 XSetCursorState(display,windows,MagickFalse); 7467 if (windows->image.crop_geometry != (char *) NULL) 7468 { 7469 /* 7470 Flop crop geometry. 7471 */ 7472 width=(unsigned int) (*image)->columns; 7473 height=(unsigned int) (*image)->rows; 7474 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7475 &width,&height); 7476 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7477 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7478 } 7479 if (windows->image.orphan != MagickFalse) 7480 break; 7481 (void) XConfigureImage(display,resource_info,windows,*image); 7482 break; 7483 } 7484 case FlipCommand: 7485 { 7486 Image 7487 *flip_image; 7488 7489 /* 7490 Flip image scanlines. 7491 */ 7492 XSetCursorState(display,windows,MagickTrue); 7493 XCheckRefreshWindows(display,windows); 7494 flip_image=FlipImage(*image,&(*image)->exception); 7495 if (flip_image != (Image *) NULL) 7496 { 7497 *image=DestroyImage(*image); 7498 *image=flip_image; 7499 } 7500 CatchException(&(*image)->exception); 7501 XSetCursorState(display,windows,MagickFalse); 7502 if (windows->image.crop_geometry != (char *) NULL) 7503 { 7504 /* 7505 Flip crop geometry. 7506 */ 7507 width=(unsigned int) (*image)->columns; 7508 height=(unsigned int) (*image)->rows; 7509 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7510 &width,&height); 7511 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7512 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7513 } 7514 if (windows->image.orphan != MagickFalse) 7515 break; 7516 (void) XConfigureImage(display,resource_info,windows,*image); 7517 break; 7518 } 7519 case RotateRightCommand: 7520 { 7521 /* 7522 Rotate image 90 degrees clockwise. 7523 */ 7524 status=XRotateImage(display,resource_info,windows,90.0,image); 7525 if (status == MagickFalse) 7526 { 7527 XNoticeWidget(display,windows,"Unable to rotate X image", 7528 (*image)->filename); 7529 break; 7530 } 7531 break; 7532 } 7533 case RotateLeftCommand: 7534 { 7535 /* 7536 Rotate image 90 degrees counter-clockwise. 7537 */ 7538 status=XRotateImage(display,resource_info,windows,-90.0,image); 7539 if (status == MagickFalse) 7540 { 7541 XNoticeWidget(display,windows,"Unable to rotate X image", 7542 (*image)->filename); 7543 break; 7544 } 7545 break; 7546 } 7547 case RotateCommand: 7548 { 7549 /* 7550 Rotate image. 7551 */ 7552 status=XRotateImage(display,resource_info,windows,0.0,image); 7553 if (status == MagickFalse) 7554 { 7555 XNoticeWidget(display,windows,"Unable to rotate X image", 7556 (*image)->filename); 7557 break; 7558 } 7559 break; 7560 } 7561 case ShearCommand: 7562 { 7563 Image 7564 *shear_image; 7565 7566 static char 7567 geometry[MaxTextExtent] = "45.0x45.0"; 7568 7569 /* 7570 Query user for shear color and geometry. 7571 */ 7572 XColorBrowserWidget(display,windows,"Select",color); 7573 if (*color == '\0') 7574 break; 7575 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7576 geometry); 7577 if (*geometry == '\0') 7578 break; 7579 /* 7580 Shear image. 7581 */ 7582 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 7583 XSetCursorState(display,windows,MagickTrue); 7584 XCheckRefreshWindows(display,windows); 7585 (void) QueryColorDatabase(color,&(*image)->background_color, 7586 &(*image)->exception); 7587 flags=ParseGeometry(geometry,&geometry_info); 7588 if ((flags & SigmaValue) == 0) 7589 geometry_info.sigma=geometry_info.rho; 7590 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7591 &(*image)->exception); 7592 if (shear_image != (Image *) NULL) 7593 { 7594 *image=DestroyImage(*image); 7595 *image=shear_image; 7596 } 7597 CatchException(&(*image)->exception); 7598 XSetCursorState(display,windows,MagickFalse); 7599 if (windows->image.orphan != MagickFalse) 7600 break; 7601 windows->image.window_changes.width=(int) (*image)->columns; 7602 windows->image.window_changes.height=(int) (*image)->rows; 7603 XConfigureImageColormap(display,resource_info,windows,*image); 7604 (void) XConfigureImage(display,resource_info,windows,*image); 7605 break; 7606 } 7607 case RollCommand: 7608 { 7609 Image 7610 *roll_image; 7611 7612 static char 7613 geometry[MaxTextExtent] = "+2+2"; 7614 7615 /* 7616 Query user for the roll geometry. 7617 */ 7618 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7619 geometry); 7620 if (*geometry == '\0') 7621 break; 7622 /* 7623 Roll image. 7624 */ 7625 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 7626 XSetCursorState(display,windows,MagickTrue); 7627 XCheckRefreshWindows(display,windows); 7628 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7629 &(*image)->exception); 7630 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7631 &(*image)->exception); 7632 if (roll_image != (Image *) NULL) 7633 { 7634 *image=DestroyImage(*image); 7635 *image=roll_image; 7636 } 7637 CatchException(&(*image)->exception); 7638 XSetCursorState(display,windows,MagickFalse); 7639 if (windows->image.orphan != MagickFalse) 7640 break; 7641 windows->image.window_changes.width=(int) (*image)->columns; 7642 windows->image.window_changes.height=(int) (*image)->rows; 7643 XConfigureImageColormap(display,resource_info,windows,*image); 7644 (void) XConfigureImage(display,resource_info,windows,*image); 7645 break; 7646 } 7647 case TrimCommand: 7648 { 7649 static char 7650 fuzz[MaxTextExtent]; 7651 7652 /* 7653 Query user for the fuzz factor. 7654 */ 7655 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7656 (*image)->fuzz/(QuantumRange+1.0)); 7657 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7658 if (*fuzz == '\0') 7659 break; 7660 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7661 /* 7662 Trim image. 7663 */ 7664 status=XTrimImage(display,resource_info,windows,*image); 7665 if (status == MagickFalse) 7666 { 7667 XNoticeWidget(display,windows,"Unable to trim X image", 7668 (*image)->filename); 7669 break; 7670 } 7671 break; 7672 } 7673 case HueCommand: 7674 { 7675 static char 7676 hue_percent[MaxTextExtent] = "110"; 7677 7678 /* 7679 Query user for percent hue change. 7680 */ 7681 (void) XDialogWidget(display,windows,"Apply", 7682 "Enter percent change in image hue (0-200):",hue_percent); 7683 if (*hue_percent == '\0') 7684 break; 7685 /* 7686 Vary the image hue. 7687 */ 7688 XSetCursorState(display,windows,MagickTrue); 7689 XCheckRefreshWindows(display,windows); 7690 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7691 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7692 MaxTextExtent); 7693 (void) ModulateImage(*image,modulate_factors); 7694 XSetCursorState(display,windows,MagickFalse); 7695 if (windows->image.orphan != MagickFalse) 7696 break; 7697 XConfigureImageColormap(display,resource_info,windows,*image); 7698 (void) XConfigureImage(display,resource_info,windows,*image); 7699 break; 7700 } 7701 case SaturationCommand: 7702 { 7703 static char 7704 saturation_percent[MaxTextExtent] = "110"; 7705 7706 /* 7707 Query user for percent saturation change. 7708 */ 7709 (void) XDialogWidget(display,windows,"Apply", 7710 "Enter percent change in color saturation (0-200):",saturation_percent); 7711 if (*saturation_percent == '\0') 7712 break; 7713 /* 7714 Vary color saturation. 7715 */ 7716 XSetCursorState(display,windows,MagickTrue); 7717 XCheckRefreshWindows(display,windows); 7718 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7719 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7720 MaxTextExtent); 7721 (void) ModulateImage(*image,modulate_factors); 7722 XSetCursorState(display,windows,MagickFalse); 7723 if (windows->image.orphan != MagickFalse) 7724 break; 7725 XConfigureImageColormap(display,resource_info,windows,*image); 7726 (void) XConfigureImage(display,resource_info,windows,*image); 7727 break; 7728 } 7729 case BrightnessCommand: 7730 { 7731 static char 7732 brightness_percent[MaxTextExtent] = "110"; 7733 7734 /* 7735 Query user for percent brightness change. 7736 */ 7737 (void) XDialogWidget(display,windows,"Apply", 7738 "Enter percent change in color brightness (0-200):",brightness_percent); 7739 if (*brightness_percent == '\0') 7740 break; 7741 /* 7742 Vary the color brightness. 7743 */ 7744 XSetCursorState(display,windows,MagickTrue); 7745 XCheckRefreshWindows(display,windows); 7746 (void) CopyMagickString(modulate_factors,brightness_percent, 7747 MaxTextExtent); 7748 (void) ModulateImage(*image,modulate_factors); 7749 XSetCursorState(display,windows,MagickFalse); 7750 if (windows->image.orphan != MagickFalse) 7751 break; 7752 XConfigureImageColormap(display,resource_info,windows,*image); 7753 (void) XConfigureImage(display,resource_info,windows,*image); 7754 break; 7755 } 7756 case GammaCommand: 7757 { 7758 static char 7759 factor[MaxTextExtent] = "1.6"; 7760 7761 /* 7762 Query user for gamma value. 7763 */ 7764 (void) XDialogWidget(display,windows,"Gamma", 7765 "Enter gamma value (e.g. 1.0,1.0,1.6):",factor); 7766 if (*factor == '\0') 7767 break; 7768 /* 7769 Gamma correct image. 7770 */ 7771 XSetCursorState(display,windows,MagickTrue); 7772 XCheckRefreshWindows(display,windows); 7773 (void) GammaImage(*image,factor); 7774 XSetCursorState(display,windows,MagickFalse); 7775 if (windows->image.orphan != MagickFalse) 7776 break; 7777 XConfigureImageColormap(display,resource_info,windows,*image); 7778 (void) XConfigureImage(display,resource_info,windows,*image); 7779 break; 7780 } 7781 case SpiffCommand: 7782 { 7783 /* 7784 Sharpen the image contrast. 7785 */ 7786 XSetCursorState(display,windows,MagickTrue); 7787 XCheckRefreshWindows(display,windows); 7788 (void) ContrastImage(*image,MagickTrue); 7789 XSetCursorState(display,windows,MagickFalse); 7790 if (windows->image.orphan != MagickFalse) 7791 break; 7792 XConfigureImageColormap(display,resource_info,windows,*image); 7793 (void) XConfigureImage(display,resource_info,windows,*image); 7794 break; 7795 } 7796 case DullCommand: 7797 { 7798 /* 7799 Dull the image contrast. 7800 */ 7801 XSetCursorState(display,windows,MagickTrue); 7802 XCheckRefreshWindows(display,windows); 7803 (void) ContrastImage(*image,MagickFalse); 7804 XSetCursorState(display,windows,MagickFalse); 7805 if (windows->image.orphan != MagickFalse) 7806 break; 7807 XConfigureImageColormap(display,resource_info,windows,*image); 7808 (void) XConfigureImage(display,resource_info,windows,*image); 7809 break; 7810 } 7811 case ContrastStretchCommand: 7812 { 7813 double 7814 black_point, 7815 white_point; 7816 7817 static char 7818 levels[MaxTextExtent] = "1%"; 7819 7820 /* 7821 Query user for gamma value. 7822 */ 7823 (void) XDialogWidget(display,windows,"Contrast Stretch", 7824 "Enter black and white points:",levels); 7825 if (*levels == '\0') 7826 break; 7827 /* 7828 Contrast stretch image. 7829 */ 7830 XSetCursorState(display,windows,MagickTrue); 7831 XCheckRefreshWindows(display,windows); 7832 flags=ParseGeometry(levels,&geometry_info); 7833 black_point=geometry_info.rho; 7834 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7835 if ((flags & PercentValue) != 0) 7836 { 7837 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7838 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7839 } 7840 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7841 (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point, 7842 white_point); 7843 XSetCursorState(display,windows,MagickFalse); 7844 if (windows->image.orphan != MagickFalse) 7845 break; 7846 XConfigureImageColormap(display,resource_info,windows,*image); 7847 (void) XConfigureImage(display,resource_info,windows,*image); 7848 break; 7849 } 7850 case SigmoidalContrastCommand: 7851 { 7852 static char 7853 levels[MaxTextExtent] = "3x50%"; 7854 7855 /* 7856 Query user for gamma value. 7857 */ 7858 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7859 "Enter contrast and midpoint:",levels); 7860 if (*levels == '\0') 7861 break; 7862 /* 7863 Contrast stretch image. 7864 */ 7865 XSetCursorState(display,windows,MagickTrue); 7866 XCheckRefreshWindows(display,windows); 7867 (void) SigmoidalContrastImage(*image,MagickTrue,levels); 7868 XSetCursorState(display,windows,MagickFalse); 7869 if (windows->image.orphan != MagickFalse) 7870 break; 7871 XConfigureImageColormap(display,resource_info,windows,*image); 7872 (void) XConfigureImage(display,resource_info,windows,*image); 7873 break; 7874 } 7875 case NormalizeCommand: 7876 { 7877 /* 7878 Perform histogram normalization on the image. 7879 */ 7880 XSetCursorState(display,windows,MagickTrue); 7881 XCheckRefreshWindows(display,windows); 7882 (void) NormalizeImage(*image); 7883 XSetCursorState(display,windows,MagickFalse); 7884 if (windows->image.orphan != MagickFalse) 7885 break; 7886 XConfigureImageColormap(display,resource_info,windows,*image); 7887 (void) XConfigureImage(display,resource_info,windows,*image); 7888 break; 7889 } 7890 case EqualizeCommand: 7891 { 7892 /* 7893 Perform histogram equalization on the image. 7894 */ 7895 XSetCursorState(display,windows,MagickTrue); 7896 XCheckRefreshWindows(display,windows); 7897 (void) EqualizeImage(*image); 7898 XSetCursorState(display,windows,MagickFalse); 7899 if (windows->image.orphan != MagickFalse) 7900 break; 7901 XConfigureImageColormap(display,resource_info,windows,*image); 7902 (void) XConfigureImage(display,resource_info,windows,*image); 7903 break; 7904 } 7905 case NegateCommand: 7906 { 7907 /* 7908 Negate colors in image. 7909 */ 7910 XSetCursorState(display,windows,MagickTrue); 7911 XCheckRefreshWindows(display,windows); 7912 (void) NegateImage(*image,MagickFalse); 7913 XSetCursorState(display,windows,MagickFalse); 7914 if (windows->image.orphan != MagickFalse) 7915 break; 7916 XConfigureImageColormap(display,resource_info,windows,*image); 7917 (void) XConfigureImage(display,resource_info,windows,*image); 7918 break; 7919 } 7920 case GrayscaleCommand: 7921 { 7922 /* 7923 Convert image to grayscale. 7924 */ 7925 XSetCursorState(display,windows,MagickTrue); 7926 XCheckRefreshWindows(display,windows); 7927 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 7928 GrayscaleType : GrayscaleMatteType); 7929 XSetCursorState(display,windows,MagickFalse); 7930 if (windows->image.orphan != MagickFalse) 7931 break; 7932 XConfigureImageColormap(display,resource_info,windows,*image); 7933 (void) XConfigureImage(display,resource_info,windows,*image); 7934 break; 7935 } 7936 case MapCommand: 7937 { 7938 Image 7939 *affinity_image; 7940 7941 static char 7942 filename[MaxTextExtent] = "\0"; 7943 7944 /* 7945 Request image file name from user. 7946 */ 7947 XFileBrowserWidget(display,windows,"Map",filename); 7948 if (*filename == '\0') 7949 break; 7950 /* 7951 Map image. 7952 */ 7953 XSetCursorState(display,windows,MagickTrue); 7954 XCheckRefreshWindows(display,windows); 7955 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 7956 affinity_image=ReadImage(image_info,&(*image)->exception); 7957 if (affinity_image != (Image *) NULL) 7958 { 7959 (void) RemapImage(&quantize_info,*image,affinity_image); 7960 affinity_image=DestroyImage(affinity_image); 7961 } 7962 CatchException(&(*image)->exception); 7963 XSetCursorState(display,windows,MagickFalse); 7964 if (windows->image.orphan != MagickFalse) 7965 break; 7966 XConfigureImageColormap(display,resource_info,windows,*image); 7967 (void) XConfigureImage(display,resource_info,windows,*image); 7968 break; 7969 } 7970 case QuantizeCommand: 7971 { 7972 int 7973 status; 7974 7975 static char 7976 colors[MaxTextExtent] = "256"; 7977 7978 /* 7979 Query user for maximum number of colors. 7980 */ 7981 status=XDialogWidget(display,windows,"Quantize", 7982 "Maximum number of colors:",colors); 7983 if (*colors == '\0') 7984 break; 7985 /* 7986 Color reduce the image. 7987 */ 7988 XSetCursorState(display,windows,MagickTrue); 7989 XCheckRefreshWindows(display,windows); 7990 quantize_info.number_colors=StringToUnsignedLong(colors); 7991 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 7992 (void) QuantizeImage(&quantize_info,*image); 7993 XSetCursorState(display,windows,MagickFalse); 7994 if (windows->image.orphan != MagickFalse) 7995 break; 7996 XConfigureImageColormap(display,resource_info,windows,*image); 7997 (void) XConfigureImage(display,resource_info,windows,*image); 7998 break; 7999 } 8000 case DespeckleCommand: 8001 { 8002 Image 8003 *despeckle_image; 8004 8005 /* 8006 Despeckle image. 8007 */ 8008 XSetCursorState(display,windows,MagickTrue); 8009 XCheckRefreshWindows(display,windows); 8010 despeckle_image=DespeckleImage(*image,&(*image)->exception); 8011 if (despeckle_image != (Image *) NULL) 8012 { 8013 *image=DestroyImage(*image); 8014 *image=despeckle_image; 8015 } 8016 CatchException(&(*image)->exception); 8017 XSetCursorState(display,windows,MagickFalse); 8018 if (windows->image.orphan != MagickFalse) 8019 break; 8020 XConfigureImageColormap(display,resource_info,windows,*image); 8021 (void) XConfigureImage(display,resource_info,windows,*image); 8022 break; 8023 } 8024 case EmbossCommand: 8025 { 8026 Image 8027 *emboss_image; 8028 8029 static char 8030 radius[MaxTextExtent] = "0.0x1.0"; 8031 8032 /* 8033 Query user for emboss radius. 8034 */ 8035 (void) XDialogWidget(display,windows,"Emboss", 8036 "Enter the emboss radius and standard deviation:",radius); 8037 if (*radius == '\0') 8038 break; 8039 /* 8040 Reduce noise in the image. 8041 */ 8042 XSetCursorState(display,windows,MagickTrue); 8043 XCheckRefreshWindows(display,windows); 8044 flags=ParseGeometry(radius,&geometry_info); 8045 if ((flags & SigmaValue) == 0) 8046 geometry_info.sigma=1.0; 8047 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8048 &(*image)->exception); 8049 if (emboss_image != (Image *) NULL) 8050 { 8051 *image=DestroyImage(*image); 8052 *image=emboss_image; 8053 } 8054 CatchException(&(*image)->exception); 8055 XSetCursorState(display,windows,MagickFalse); 8056 if (windows->image.orphan != MagickFalse) 8057 break; 8058 XConfigureImageColormap(display,resource_info,windows,*image); 8059 (void) XConfigureImage(display,resource_info,windows,*image); 8060 break; 8061 } 8062 case ReduceNoiseCommand: 8063 { 8064 Image 8065 *noise_image; 8066 8067 static char 8068 radius[MaxTextExtent] = "0"; 8069 8070 /* 8071 Query user for noise radius. 8072 */ 8073 (void) XDialogWidget(display,windows,"Reduce Noise", 8074 "Enter the noise radius:",radius); 8075 if (*radius == '\0') 8076 break; 8077 /* 8078 Reduce noise in the image. 8079 */ 8080 XSetCursorState(display,windows,MagickTrue); 8081 XCheckRefreshWindows(display,windows); 8082 flags=ParseGeometry(radius,&geometry_info); 8083 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8084 geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception); 8085 if (noise_image != (Image *) NULL) 8086 { 8087 *image=DestroyImage(*image); 8088 *image=noise_image; 8089 } 8090 CatchException(&(*image)->exception); 8091 XSetCursorState(display,windows,MagickFalse); 8092 if (windows->image.orphan != MagickFalse) 8093 break; 8094 XConfigureImageColormap(display,resource_info,windows,*image); 8095 (void) XConfigureImage(display,resource_info,windows,*image); 8096 break; 8097 } 8098 case AddNoiseCommand: 8099 { 8100 char 8101 **noises; 8102 8103 Image 8104 *noise_image; 8105 8106 static char 8107 noise_type[MaxTextExtent] = "Gaussian"; 8108 8109 /* 8110 Add noise to the image. 8111 */ 8112 noises=GetCommandOptions(MagickNoiseOptions); 8113 if (noises == (char **) NULL) 8114 break; 8115 XListBrowserWidget(display,windows,&windows->widget, 8116 (const char **) noises,"Add Noise", 8117 "Select a type of noise to add to your image:",noise_type); 8118 noises=DestroyStringList(noises); 8119 if (*noise_type == '\0') 8120 break; 8121 XSetCursorState(display,windows,MagickTrue); 8122 XCheckRefreshWindows(display,windows); 8123 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8124 MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception); 8125 if (noise_image != (Image *) NULL) 8126 { 8127 *image=DestroyImage(*image); 8128 *image=noise_image; 8129 } 8130 CatchException(&(*image)->exception); 8131 XSetCursorState(display,windows,MagickFalse); 8132 if (windows->image.orphan != MagickFalse) 8133 break; 8134 XConfigureImageColormap(display,resource_info,windows,*image); 8135 (void) XConfigureImage(display,resource_info,windows,*image); 8136 break; 8137 } 8138 case SharpenCommand: 8139 { 8140 Image 8141 *sharp_image; 8142 8143 static char 8144 radius[MaxTextExtent] = "0.0x1.0"; 8145 8146 /* 8147 Query user for sharpen radius. 8148 */ 8149 (void) XDialogWidget(display,windows,"Sharpen", 8150 "Enter the sharpen radius and standard deviation:",radius); 8151 if (*radius == '\0') 8152 break; 8153 /* 8154 Sharpen image scanlines. 8155 */ 8156 XSetCursorState(display,windows,MagickTrue); 8157 XCheckRefreshWindows(display,windows); 8158 flags=ParseGeometry(radius,&geometry_info); 8159 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8160 &(*image)->exception); 8161 if (sharp_image != (Image *) NULL) 8162 { 8163 *image=DestroyImage(*image); 8164 *image=sharp_image; 8165 } 8166 CatchException(&(*image)->exception); 8167 XSetCursorState(display,windows,MagickFalse); 8168 if (windows->image.orphan != MagickFalse) 8169 break; 8170 XConfigureImageColormap(display,resource_info,windows,*image); 8171 (void) XConfigureImage(display,resource_info,windows,*image); 8172 break; 8173 } 8174 case BlurCommand: 8175 { 8176 Image 8177 *blur_image; 8178 8179 static char 8180 radius[MaxTextExtent] = "0.0x1.0"; 8181 8182 /* 8183 Query user for blur radius. 8184 */ 8185 (void) XDialogWidget(display,windows,"Blur", 8186 "Enter the blur radius and standard deviation:",radius); 8187 if (*radius == '\0') 8188 break; 8189 /* 8190 Blur an image. 8191 */ 8192 XSetCursorState(display,windows,MagickTrue); 8193 XCheckRefreshWindows(display,windows); 8194 flags=ParseGeometry(radius,&geometry_info); 8195 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8196 &(*image)->exception); 8197 if (blur_image != (Image *) NULL) 8198 { 8199 *image=DestroyImage(*image); 8200 *image=blur_image; 8201 } 8202 CatchException(&(*image)->exception); 8203 XSetCursorState(display,windows,MagickFalse); 8204 if (windows->image.orphan != MagickFalse) 8205 break; 8206 XConfigureImageColormap(display,resource_info,windows,*image); 8207 (void) XConfigureImage(display,resource_info,windows,*image); 8208 break; 8209 } 8210 case ThresholdCommand: 8211 { 8212 double 8213 threshold; 8214 8215 static char 8216 factor[MaxTextExtent] = "128"; 8217 8218 /* 8219 Query user for threshold value. 8220 */ 8221 (void) XDialogWidget(display,windows,"Threshold", 8222 "Enter threshold value:",factor); 8223 if (*factor == '\0') 8224 break; 8225 /* 8226 Gamma correct image. 8227 */ 8228 XSetCursorState(display,windows,MagickTrue); 8229 XCheckRefreshWindows(display,windows); 8230 threshold=SiPrefixToDouble(factor,QuantumRange); 8231 (void) BilevelImage(*image,threshold); 8232 XSetCursorState(display,windows,MagickFalse); 8233 if (windows->image.orphan != MagickFalse) 8234 break; 8235 XConfigureImageColormap(display,resource_info,windows,*image); 8236 (void) XConfigureImage(display,resource_info,windows,*image); 8237 break; 8238 } 8239 case EdgeDetectCommand: 8240 { 8241 Image 8242 *edge_image; 8243 8244 static char 8245 radius[MaxTextExtent] = "0"; 8246 8247 /* 8248 Query user for edge factor. 8249 */ 8250 (void) XDialogWidget(display,windows,"Detect Edges", 8251 "Enter the edge detect radius:",radius); 8252 if (*radius == '\0') 8253 break; 8254 /* 8255 Detect edge in image. 8256 */ 8257 XSetCursorState(display,windows,MagickTrue); 8258 XCheckRefreshWindows(display,windows); 8259 flags=ParseGeometry(radius,&geometry_info); 8260 edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception); 8261 if (edge_image != (Image *) NULL) 8262 { 8263 *image=DestroyImage(*image); 8264 *image=edge_image; 8265 } 8266 CatchException(&(*image)->exception); 8267 XSetCursorState(display,windows,MagickFalse); 8268 if (windows->image.orphan != MagickFalse) 8269 break; 8270 XConfigureImageColormap(display,resource_info,windows,*image); 8271 (void) XConfigureImage(display,resource_info,windows,*image); 8272 break; 8273 } 8274 case SpreadCommand: 8275 { 8276 Image 8277 *spread_image; 8278 8279 static char 8280 amount[MaxTextExtent] = "2"; 8281 8282 /* 8283 Query user for spread amount. 8284 */ 8285 (void) XDialogWidget(display,windows,"Spread", 8286 "Enter the displacement amount:",amount); 8287 if (*amount == '\0') 8288 break; 8289 /* 8290 Displace image pixels by a random amount. 8291 */ 8292 XSetCursorState(display,windows,MagickTrue); 8293 XCheckRefreshWindows(display,windows); 8294 flags=ParseGeometry(amount,&geometry_info); 8295 spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception); 8296 if (spread_image != (Image *) NULL) 8297 { 8298 *image=DestroyImage(*image); 8299 *image=spread_image; 8300 } 8301 CatchException(&(*image)->exception); 8302 XSetCursorState(display,windows,MagickFalse); 8303 if (windows->image.orphan != MagickFalse) 8304 break; 8305 XConfigureImageColormap(display,resource_info,windows,*image); 8306 (void) XConfigureImage(display,resource_info,windows,*image); 8307 break; 8308 } 8309 case ShadeCommand: 8310 { 8311 Image 8312 *shade_image; 8313 8314 int 8315 status; 8316 8317 static char 8318 geometry[MaxTextExtent] = "30x30"; 8319 8320 /* 8321 Query user for the shade geometry. 8322 */ 8323 status=XDialogWidget(display,windows,"Shade", 8324 "Enter the azimuth and elevation of the light source:",geometry); 8325 if (*geometry == '\0') 8326 break; 8327 /* 8328 Shade image pixels. 8329 */ 8330 XSetCursorState(display,windows,MagickTrue); 8331 XCheckRefreshWindows(display,windows); 8332 flags=ParseGeometry(geometry,&geometry_info); 8333 if ((flags & SigmaValue) == 0) 8334 geometry_info.sigma=1.0; 8335 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8336 geometry_info.rho,geometry_info.sigma,&(*image)->exception); 8337 if (shade_image != (Image *) NULL) 8338 { 8339 *image=DestroyImage(*image); 8340 *image=shade_image; 8341 } 8342 CatchException(&(*image)->exception); 8343 XSetCursorState(display,windows,MagickFalse); 8344 if (windows->image.orphan != MagickFalse) 8345 break; 8346 XConfigureImageColormap(display,resource_info,windows,*image); 8347 (void) XConfigureImage(display,resource_info,windows,*image); 8348 break; 8349 } 8350 case RaiseCommand: 8351 { 8352 static char 8353 bevel_width[MaxTextExtent] = "10"; 8354 8355 /* 8356 Query user for bevel width. 8357 */ 8358 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8359 if (*bevel_width == '\0') 8360 break; 8361 /* 8362 Raise an image. 8363 */ 8364 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8365 XSetCursorState(display,windows,MagickTrue); 8366 XCheckRefreshWindows(display,windows); 8367 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8368 &(*image)->exception); 8369 (void) RaiseImage(*image,&page_geometry,MagickTrue); 8370 XSetCursorState(display,windows,MagickFalse); 8371 if (windows->image.orphan != MagickFalse) 8372 break; 8373 XConfigureImageColormap(display,resource_info,windows,*image); 8374 (void) XConfigureImage(display,resource_info,windows,*image); 8375 break; 8376 } 8377 case SegmentCommand: 8378 { 8379 static char 8380 threshold[MaxTextExtent] = "1.0x1.5"; 8381 8382 /* 8383 Query user for smoothing threshold. 8384 */ 8385 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8386 threshold); 8387 if (*threshold == '\0') 8388 break; 8389 /* 8390 Segment an image. 8391 */ 8392 XSetCursorState(display,windows,MagickTrue); 8393 XCheckRefreshWindows(display,windows); 8394 flags=ParseGeometry(threshold,&geometry_info); 8395 if ((flags & SigmaValue) == 0) 8396 geometry_info.sigma=1.0; 8397 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8398 geometry_info.sigma); 8399 XSetCursorState(display,windows,MagickFalse); 8400 if (windows->image.orphan != MagickFalse) 8401 break; 8402 XConfigureImageColormap(display,resource_info,windows,*image); 8403 (void) XConfigureImage(display,resource_info,windows,*image); 8404 break; 8405 } 8406 case SepiaToneCommand: 8407 { 8408 double 8409 threshold; 8410 8411 Image 8412 *sepia_image; 8413 8414 static char 8415 factor[MaxTextExtent] = "80%"; 8416 8417 /* 8418 Query user for sepia-tone factor. 8419 */ 8420 (void) XDialogWidget(display,windows,"Sepia Tone", 8421 "Enter the sepia tone factor (0 - 99.9%):",factor); 8422 if (*factor == '\0') 8423 break; 8424 /* 8425 Sepia tone image pixels. 8426 */ 8427 XSetCursorState(display,windows,MagickTrue); 8428 XCheckRefreshWindows(display,windows); 8429 threshold=SiPrefixToDouble(factor,QuantumRange); 8430 sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception); 8431 if (sepia_image != (Image *) NULL) 8432 { 8433 *image=DestroyImage(*image); 8434 *image=sepia_image; 8435 } 8436 CatchException(&(*image)->exception); 8437 XSetCursorState(display,windows,MagickFalse); 8438 if (windows->image.orphan != MagickFalse) 8439 break; 8440 XConfigureImageColormap(display,resource_info,windows,*image); 8441 (void) XConfigureImage(display,resource_info,windows,*image); 8442 break; 8443 } 8444 case SolarizeCommand: 8445 { 8446 double 8447 threshold; 8448 8449 static char 8450 factor[MaxTextExtent] = "60%"; 8451 8452 /* 8453 Query user for solarize factor. 8454 */ 8455 (void) XDialogWidget(display,windows,"Solarize", 8456 "Enter the solarize factor (0 - 99.9%):",factor); 8457 if (*factor == '\0') 8458 break; 8459 /* 8460 Solarize image pixels. 8461 */ 8462 XSetCursorState(display,windows,MagickTrue); 8463 XCheckRefreshWindows(display,windows); 8464 threshold=SiPrefixToDouble(factor,QuantumRange); 8465 (void) SolarizeImage(*image,threshold); 8466 XSetCursorState(display,windows,MagickFalse); 8467 if (windows->image.orphan != MagickFalse) 8468 break; 8469 XConfigureImageColormap(display,resource_info,windows,*image); 8470 (void) XConfigureImage(display,resource_info,windows,*image); 8471 break; 8472 } 8473 case SwirlCommand: 8474 { 8475 Image 8476 *swirl_image; 8477 8478 static char 8479 degrees[MaxTextExtent] = "60"; 8480 8481 /* 8482 Query user for swirl angle. 8483 */ 8484 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8485 degrees); 8486 if (*degrees == '\0') 8487 break; 8488 /* 8489 Swirl image pixels about the center. 8490 */ 8491 XSetCursorState(display,windows,MagickTrue); 8492 XCheckRefreshWindows(display,windows); 8493 flags=ParseGeometry(degrees,&geometry_info); 8494 swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception); 8495 if (swirl_image != (Image *) NULL) 8496 { 8497 *image=DestroyImage(*image); 8498 *image=swirl_image; 8499 } 8500 CatchException(&(*image)->exception); 8501 XSetCursorState(display,windows,MagickFalse); 8502 if (windows->image.orphan != MagickFalse) 8503 break; 8504 XConfigureImageColormap(display,resource_info,windows,*image); 8505 (void) XConfigureImage(display,resource_info,windows,*image); 8506 break; 8507 } 8508 case ImplodeCommand: 8509 { 8510 Image 8511 *implode_image; 8512 8513 static char 8514 factor[MaxTextExtent] = "0.3"; 8515 8516 /* 8517 Query user for implode factor. 8518 */ 8519 (void) XDialogWidget(display,windows,"Implode", 8520 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8521 if (*factor == '\0') 8522 break; 8523 /* 8524 Implode image pixels about the center. 8525 */ 8526 XSetCursorState(display,windows,MagickTrue); 8527 XCheckRefreshWindows(display,windows); 8528 flags=ParseGeometry(factor,&geometry_info); 8529 implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception); 8530 if (implode_image != (Image *) NULL) 8531 { 8532 *image=DestroyImage(*image); 8533 *image=implode_image; 8534 } 8535 CatchException(&(*image)->exception); 8536 XSetCursorState(display,windows,MagickFalse); 8537 if (windows->image.orphan != MagickFalse) 8538 break; 8539 XConfigureImageColormap(display,resource_info,windows,*image); 8540 (void) XConfigureImage(display,resource_info,windows,*image); 8541 break; 8542 } 8543 case VignetteCommand: 8544 { 8545 Image 8546 *vignette_image; 8547 8548 static char 8549 geometry[MaxTextExtent] = "0x20"; 8550 8551 /* 8552 Query user for the vignette geometry. 8553 */ 8554 (void) XDialogWidget(display,windows,"Vignette", 8555 "Enter the radius, sigma, and x and y offsets:",geometry); 8556 if (*geometry == '\0') 8557 break; 8558 /* 8559 Soften the edges of the image in vignette style 8560 */ 8561 XSetCursorState(display,windows,MagickTrue); 8562 XCheckRefreshWindows(display,windows); 8563 flags=ParseGeometry(geometry,&geometry_info); 8564 if ((flags & SigmaValue) == 0) 8565 geometry_info.sigma=1.0; 8566 if ((flags & XiValue) == 0) 8567 geometry_info.xi=0.1*(*image)->columns; 8568 if ((flags & PsiValue) == 0) 8569 geometry_info.psi=0.1*(*image)->rows; 8570 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8571 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8572 0.5),&(*image)->exception); 8573 if (vignette_image != (Image *) NULL) 8574 { 8575 *image=DestroyImage(*image); 8576 *image=vignette_image; 8577 } 8578 CatchException(&(*image)->exception); 8579 XSetCursorState(display,windows,MagickFalse); 8580 if (windows->image.orphan != MagickFalse) 8581 break; 8582 XConfigureImageColormap(display,resource_info,windows,*image); 8583 (void) XConfigureImage(display,resource_info,windows,*image); 8584 break; 8585 } 8586 case WaveCommand: 8587 { 8588 Image 8589 *wave_image; 8590 8591 static char 8592 geometry[MaxTextExtent] = "25x150"; 8593 8594 /* 8595 Query user for the wave geometry. 8596 */ 8597 (void) XDialogWidget(display,windows,"Wave", 8598 "Enter the amplitude and length of the wave:",geometry); 8599 if (*geometry == '\0') 8600 break; 8601 /* 8602 Alter an image along a sine wave. 8603 */ 8604 XSetCursorState(display,windows,MagickTrue); 8605 XCheckRefreshWindows(display,windows); 8606 flags=ParseGeometry(geometry,&geometry_info); 8607 if ((flags & SigmaValue) == 0) 8608 geometry_info.sigma=1.0; 8609 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8610 &(*image)->exception); 8611 if (wave_image != (Image *) NULL) 8612 { 8613 *image=DestroyImage(*image); 8614 *image=wave_image; 8615 } 8616 CatchException(&(*image)->exception); 8617 XSetCursorState(display,windows,MagickFalse); 8618 if (windows->image.orphan != MagickFalse) 8619 break; 8620 XConfigureImageColormap(display,resource_info,windows,*image); 8621 (void) XConfigureImage(display,resource_info,windows,*image); 8622 break; 8623 } 8624 case OilPaintCommand: 8625 { 8626 Image 8627 *paint_image; 8628 8629 static char 8630 radius[MaxTextExtent] = "0"; 8631 8632 /* 8633 Query user for circular neighborhood radius. 8634 */ 8635 (void) XDialogWidget(display,windows,"Oil Paint", 8636 "Enter the mask radius:",radius); 8637 if (*radius == '\0') 8638 break; 8639 /* 8640 OilPaint image scanlines. 8641 */ 8642 XSetCursorState(display,windows,MagickTrue); 8643 XCheckRefreshWindows(display,windows); 8644 flags=ParseGeometry(radius,&geometry_info); 8645 paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception); 8646 if (paint_image != (Image *) NULL) 8647 { 8648 *image=DestroyImage(*image); 8649 *image=paint_image; 8650 } 8651 CatchException(&(*image)->exception); 8652 XSetCursorState(display,windows,MagickFalse); 8653 if (windows->image.orphan != MagickFalse) 8654 break; 8655 XConfigureImageColormap(display,resource_info,windows,*image); 8656 (void) XConfigureImage(display,resource_info,windows,*image); 8657 break; 8658 } 8659 case CharcoalDrawCommand: 8660 { 8661 Image 8662 *charcoal_image; 8663 8664 static char 8665 radius[MaxTextExtent] = "0x1"; 8666 8667 /* 8668 Query user for charcoal radius. 8669 */ 8670 (void) XDialogWidget(display,windows,"Charcoal Draw", 8671 "Enter the charcoal radius and sigma:",radius); 8672 if (*radius == '\0') 8673 break; 8674 /* 8675 Charcoal the image. 8676 */ 8677 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8678 XSetCursorState(display,windows,MagickTrue); 8679 XCheckRefreshWindows(display,windows); 8680 flags=ParseGeometry(radius,&geometry_info); 8681 if ((flags & SigmaValue) == 0) 8682 geometry_info.sigma=geometry_info.rho; 8683 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8684 &(*image)->exception); 8685 if (charcoal_image != (Image *) NULL) 8686 { 8687 *image=DestroyImage(*image); 8688 *image=charcoal_image; 8689 } 8690 CatchException(&(*image)->exception); 8691 XSetCursorState(display,windows,MagickFalse); 8692 if (windows->image.orphan != MagickFalse) 8693 break; 8694 XConfigureImageColormap(display,resource_info,windows,*image); 8695 (void) XConfigureImage(display,resource_info,windows,*image); 8696 break; 8697 } 8698 case AnnotateCommand: 8699 { 8700 /* 8701 Annotate the image with text. 8702 */ 8703 status=XAnnotateEditImage(display,resource_info,windows,*image); 8704 if (status == MagickFalse) 8705 { 8706 XNoticeWidget(display,windows,"Unable to annotate X image", 8707 (*image)->filename); 8708 break; 8709 } 8710 break; 8711 } 8712 case DrawCommand: 8713 { 8714 /* 8715 Draw image. 8716 */ 8717 status=XDrawEditImage(display,resource_info,windows,image); 8718 if (status == MagickFalse) 8719 { 8720 XNoticeWidget(display,windows,"Unable to draw on the X image", 8721 (*image)->filename); 8722 break; 8723 } 8724 break; 8725 } 8726 case ColorCommand: 8727 { 8728 /* 8729 Color edit. 8730 */ 8731 status=XColorEditImage(display,resource_info,windows,image); 8732 if (status == MagickFalse) 8733 { 8734 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8735 (*image)->filename); 8736 break; 8737 } 8738 break; 8739 } 8740 case MatteCommand: 8741 { 8742 /* 8743 Matte edit. 8744 */ 8745 status=XMatteEditImage(display,resource_info,windows,image); 8746 if (status == MagickFalse) 8747 { 8748 XNoticeWidget(display,windows,"Unable to matte edit X image", 8749 (*image)->filename); 8750 break; 8751 } 8752 break; 8753 } 8754 case CompositeCommand: 8755 { 8756 /* 8757 Composite image. 8758 */ 8759 status=XCompositeImage(display,resource_info,windows,*image); 8760 if (status == MagickFalse) 8761 { 8762 XNoticeWidget(display,windows,"Unable to composite X image", 8763 (*image)->filename); 8764 break; 8765 } 8766 break; 8767 } 8768 case AddBorderCommand: 8769 { 8770 Image 8771 *border_image; 8772 8773 static char 8774 geometry[MaxTextExtent] = "6x6"; 8775 8776 /* 8777 Query user for border color and geometry. 8778 */ 8779 XColorBrowserWidget(display,windows,"Select",color); 8780 if (*color == '\0') 8781 break; 8782 (void) XDialogWidget(display,windows,"Add Border", 8783 "Enter border geometry:",geometry); 8784 if (*geometry == '\0') 8785 break; 8786 /* 8787 Add a border to the image. 8788 */ 8789 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8790 XSetCursorState(display,windows,MagickTrue); 8791 XCheckRefreshWindows(display,windows); 8792 (void) QueryColorDatabase(color,&(*image)->border_color, 8793 &(*image)->exception); 8794 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8795 &(*image)->exception); 8796 border_image=BorderImage(*image,&page_geometry,&(*image)->exception); 8797 if (border_image != (Image *) NULL) 8798 { 8799 *image=DestroyImage(*image); 8800 *image=border_image; 8801 } 8802 CatchException(&(*image)->exception); 8803 XSetCursorState(display,windows,MagickFalse); 8804 if (windows->image.orphan != MagickFalse) 8805 break; 8806 windows->image.window_changes.width=(int) (*image)->columns; 8807 windows->image.window_changes.height=(int) (*image)->rows; 8808 XConfigureImageColormap(display,resource_info,windows,*image); 8809 (void) XConfigureImage(display,resource_info,windows,*image); 8810 break; 8811 } 8812 case AddFrameCommand: 8813 { 8814 FrameInfo 8815 frame_info; 8816 8817 Image 8818 *frame_image; 8819 8820 static char 8821 geometry[MaxTextExtent] = "6x6"; 8822 8823 /* 8824 Query user for frame color and geometry. 8825 */ 8826 XColorBrowserWidget(display,windows,"Select",color); 8827 if (*color == '\0') 8828 break; 8829 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8830 geometry); 8831 if (*geometry == '\0') 8832 break; 8833 /* 8834 Surround image with an ornamental border. 8835 */ 8836 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 8837 XSetCursorState(display,windows,MagickTrue); 8838 XCheckRefreshWindows(display,windows); 8839 (void) QueryColorDatabase(color,&(*image)->matte_color, 8840 &(*image)->exception); 8841 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8842 &(*image)->exception); 8843 frame_info.width=page_geometry.width; 8844 frame_info.height=page_geometry.height; 8845 frame_info.outer_bevel=page_geometry.x; 8846 frame_info.inner_bevel=page_geometry.y; 8847 frame_info.x=(ssize_t) frame_info.width; 8848 frame_info.y=(ssize_t) frame_info.height; 8849 frame_info.width=(*image)->columns+2*frame_info.width; 8850 frame_info.height=(*image)->rows+2*frame_info.height; 8851 frame_image=FrameImage(*image,&frame_info,&(*image)->exception); 8852 if (frame_image != (Image *) NULL) 8853 { 8854 *image=DestroyImage(*image); 8855 *image=frame_image; 8856 } 8857 CatchException(&(*image)->exception); 8858 XSetCursorState(display,windows,MagickFalse); 8859 if (windows->image.orphan != MagickFalse) 8860 break; 8861 windows->image.window_changes.width=(int) (*image)->columns; 8862 windows->image.window_changes.height=(int) (*image)->rows; 8863 XConfigureImageColormap(display,resource_info,windows,*image); 8864 (void) XConfigureImage(display,resource_info,windows,*image); 8865 break; 8866 } 8867 case CommentCommand: 8868 { 8869 const char 8870 *value; 8871 8872 FILE 8873 *file; 8874 8875 int 8876 unique_file; 8877 8878 /* 8879 Edit image comment. 8880 */ 8881 unique_file=AcquireUniqueFileResource(image_info->filename); 8882 if (unique_file == -1) 8883 XNoticeWidget(display,windows,"Unable to edit image comment", 8884 image_info->filename); 8885 value=GetImageProperty(*image,"comment"); 8886 if (value == (char *) NULL) 8887 unique_file=close(unique_file)-1; 8888 else 8889 { 8890 register const char 8891 *p; 8892 8893 file=fdopen(unique_file,"w"); 8894 if (file == (FILE *) NULL) 8895 { 8896 XNoticeWidget(display,windows,"Unable to edit image comment", 8897 image_info->filename); 8898 break; 8899 } 8900 for (p=value; *p != '\0'; p++) 8901 (void) fputc((int) *p,file); 8902 (void) fputc('\n',file); 8903 (void) fclose(file); 8904 } 8905 XSetCursorState(display,windows,MagickTrue); 8906 XCheckRefreshWindows(display,windows); 8907 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8908 &(*image)->exception); 8909 if (status == MagickFalse) 8910 XNoticeWidget(display,windows,"Unable to edit image comment", 8911 (char *) NULL); 8912 else 8913 { 8914 char 8915 *comment; 8916 8917 comment=FileToString(image_info->filename,~0UL,&(*image)->exception); 8918 if (comment != (char *) NULL) 8919 { 8920 (void) SetImageProperty(*image,"comment",comment); 8921 (*image)->taint=MagickTrue; 8922 } 8923 } 8924 (void) RelinquishUniqueFileResource(image_info->filename); 8925 XSetCursorState(display,windows,MagickFalse); 8926 break; 8927 } 8928 case LaunchCommand: 8929 { 8930 /* 8931 Launch program. 8932 */ 8933 XSetCursorState(display,windows,MagickTrue); 8934 XCheckRefreshWindows(display,windows); 8935 (void) AcquireUniqueFilename(filename); 8936 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 8937 filename); 8938 status=WriteImage(image_info,*image); 8939 if (status == MagickFalse) 8940 XNoticeWidget(display,windows,"Unable to launch image editor", 8941 (char *) NULL); 8942 else 8943 { 8944 nexus=ReadImage(resource_info->image_info,&(*image)->exception); 8945 CatchException(&(*image)->exception); 8946 XClientMessage(display,windows->image.id,windows->im_protocols, 8947 windows->im_next_image,CurrentTime); 8948 } 8949 (void) RelinquishUniqueFileResource(filename); 8950 XSetCursorState(display,windows,MagickFalse); 8951 break; 8952 } 8953 case RegionofInterestCommand: 8954 { 8955 /* 8956 Apply an image processing technique to a region of interest. 8957 */ 8958 (void) XROIImage(display,resource_info,windows,image); 8959 break; 8960 } 8961 case InfoCommand: 8962 break; 8963 case ZoomCommand: 8964 { 8965 /* 8966 Zoom image. 8967 */ 8968 if (windows->magnify.mapped != MagickFalse) 8969 (void) XRaiseWindow(display,windows->magnify.id); 8970 else 8971 { 8972 /* 8973 Make magnify image. 8974 */ 8975 XSetCursorState(display,windows,MagickTrue); 8976 (void) XMapRaised(display,windows->magnify.id); 8977 XSetCursorState(display,windows,MagickFalse); 8978 } 8979 break; 8980 } 8981 case ShowPreviewCommand: 8982 { 8983 char 8984 **previews; 8985 8986 Image 8987 *preview_image; 8988 8989 static char 8990 preview_type[MaxTextExtent] = "Gamma"; 8991 8992 /* 8993 Select preview type from menu. 8994 */ 8995 previews=GetCommandOptions(MagickPreviewOptions); 8996 if (previews == (char **) NULL) 8997 break; 8998 XListBrowserWidget(display,windows,&windows->widget, 8999 (const char **) previews,"Preview", 9000 "Select an enhancement, effect, or F/X:",preview_type); 9001 previews=DestroyStringList(previews); 9002 if (*preview_type == '\0') 9003 break; 9004 /* 9005 Show image preview. 9006 */ 9007 XSetCursorState(display,windows,MagickTrue); 9008 XCheckRefreshWindows(display,windows); 9009 image_info->preview_type=(PreviewType) 9010 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9011 image_info->group=(ssize_t) windows->image.id; 9012 (void) DeleteImageProperty(*image,"label"); 9013 (void) SetImageProperty(*image,"label","Preview"); 9014 (void) AcquireUniqueFilename(filename); 9015 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9016 filename); 9017 status=WriteImage(image_info,*image); 9018 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9019 preview_image=ReadImage(image_info,&(*image)->exception); 9020 (void) RelinquishUniqueFileResource(filename); 9021 if (preview_image == (Image *) NULL) 9022 break; 9023 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9024 filename); 9025 status=WriteImage(image_info,preview_image); 9026 preview_image=DestroyImage(preview_image); 9027 if (status == MagickFalse) 9028 XNoticeWidget(display,windows,"Unable to show image preview", 9029 (*image)->filename); 9030 XDelay(display,1500); 9031 XSetCursorState(display,windows,MagickFalse); 9032 break; 9033 } 9034 case ShowHistogramCommand: 9035 { 9036 Image 9037 *histogram_image; 9038 9039 /* 9040 Show image histogram. 9041 */ 9042 XSetCursorState(display,windows,MagickTrue); 9043 XCheckRefreshWindows(display,windows); 9044 image_info->group=(ssize_t) windows->image.id; 9045 (void) DeleteImageProperty(*image,"label"); 9046 (void) SetImageProperty(*image,"label","Histogram"); 9047 (void) AcquireUniqueFilename(filename); 9048 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9049 filename); 9050 status=WriteImage(image_info,*image); 9051 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9052 histogram_image=ReadImage(image_info,&(*image)->exception); 9053 (void) RelinquishUniqueFileResource(filename); 9054 if (histogram_image == (Image *) NULL) 9055 break; 9056 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9057 "show:%s",filename); 9058 status=WriteImage(image_info,histogram_image); 9059 histogram_image=DestroyImage(histogram_image); 9060 if (status == MagickFalse) 9061 XNoticeWidget(display,windows,"Unable to show histogram", 9062 (*image)->filename); 9063 XDelay(display,1500); 9064 XSetCursorState(display,windows,MagickFalse); 9065 break; 9066 } 9067 case ShowMatteCommand: 9068 { 9069 Image 9070 *matte_image; 9071 9072 if ((*image)->matte == MagickFalse) 9073 { 9074 XNoticeWidget(display,windows, 9075 "Image does not have any matte information",(*image)->filename); 9076 break; 9077 } 9078 /* 9079 Show image matte. 9080 */ 9081 XSetCursorState(display,windows,MagickTrue); 9082 XCheckRefreshWindows(display,windows); 9083 image_info->group=(ssize_t) windows->image.id; 9084 (void) DeleteImageProperty(*image,"label"); 9085 (void) SetImageProperty(*image,"label","Matte"); 9086 (void) AcquireUniqueFilename(filename); 9087 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9088 filename); 9089 status=WriteImage(image_info,*image); 9090 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9091 matte_image=ReadImage(image_info,&(*image)->exception); 9092 (void) RelinquishUniqueFileResource(filename); 9093 if (matte_image == (Image *) NULL) 9094 break; 9095 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9096 filename); 9097 status=WriteImage(image_info,matte_image); 9098 matte_image=DestroyImage(matte_image); 9099 if (status == MagickFalse) 9100 XNoticeWidget(display,windows,"Unable to show matte", 9101 (*image)->filename); 9102 XDelay(display,1500); 9103 XSetCursorState(display,windows,MagickFalse); 9104 break; 9105 } 9106 case BackgroundCommand: 9107 { 9108 /* 9109 Background image. 9110 */ 9111 status=XBackgroundImage(display,resource_info,windows,image); 9112 if (status == MagickFalse) 9113 break; 9114 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 9115 if (nexus != (Image *) NULL) 9116 XClientMessage(display,windows->image.id,windows->im_protocols, 9117 windows->im_next_image,CurrentTime); 9118 break; 9119 } 9120 case SlideShowCommand: 9121 { 9122 static char 9123 delay[MaxTextExtent] = "5"; 9124 9125 /* 9126 Display next image after pausing. 9127 */ 9128 (void) XDialogWidget(display,windows,"Slide Show", 9129 "Pause how many 1/100ths of a second between images:",delay); 9130 if (*delay == '\0') 9131 break; 9132 resource_info->delay=StringToUnsignedLong(delay); 9133 XClientMessage(display,windows->image.id,windows->im_protocols, 9134 windows->im_next_image,CurrentTime); 9135 break; 9136 } 9137 case PreferencesCommand: 9138 { 9139 /* 9140 Set user preferences. 9141 */ 9142 status=XPreferencesWidget(display,resource_info,windows); 9143 if (status == MagickFalse) 9144 break; 9145 nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); 9146 if (nexus != (Image *) NULL) 9147 XClientMessage(display,windows->image.id,windows->im_protocols, 9148 windows->im_next_image,CurrentTime); 9149 break; 9150 } 9151 case HelpCommand: 9152 { 9153 /* 9154 User requested help. 9155 */ 9156 XTextViewWidget(display,resource_info,windows,MagickFalse, 9157 "Help Viewer - Display",DisplayHelp); 9158 break; 9159 } 9160 case BrowseDocumentationCommand: 9161 { 9162 Atom 9163 mozilla_atom; 9164 9165 Window 9166 mozilla_window, 9167 root_window; 9168 9169 /* 9170 Browse the ImageMagick documentation. 9171 */ 9172 root_window=XRootWindow(display,XDefaultScreen(display)); 9173 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9174 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9175 if (mozilla_window != (Window) NULL) 9176 { 9177 char 9178 command[MaxTextExtent], 9179 *url; 9180 9181 /* 9182 Display documentation using Netscape remote control. 9183 */ 9184 url=GetMagickHomeURL(); 9185 (void) FormatLocaleString(command,MaxTextExtent, 9186 "openurl(%s,new-tab)",url); 9187 url=DestroyString(url); 9188 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9189 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9190 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9191 XSetCursorState(display,windows,MagickFalse); 9192 break; 9193 } 9194 XSetCursorState(display,windows,MagickTrue); 9195 XCheckRefreshWindows(display,windows); 9196 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9197 &(*image)->exception); 9198 if (status == MagickFalse) 9199 XNoticeWidget(display,windows,"Unable to browse documentation", 9200 (char *) NULL); 9201 XDelay(display,1500); 9202 XSetCursorState(display,windows,MagickFalse); 9203 break; 9204 } 9205 case VersionCommand: 9206 { 9207 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9208 GetMagickCopyright()); 9209 break; 9210 } 9211 case SaveToUndoBufferCommand: 9212 break; 9213 default: 9214 { 9215 (void) XBell(display,0); 9216 break; 9217 } 9218 } 9219 image_info=DestroyImageInfo(image_info); 9220 return(nexus); 9221} 9222 9223/* 9224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9225% % 9226% % 9227% % 9228+ X M a g n i f y I m a g e % 9229% % 9230% % 9231% % 9232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9233% 9234% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9235% The magnified portion is displayed in a separate window. 9236% 9237% The format of the XMagnifyImage method is: 9238% 9239% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9240% 9241% A description of each parameter follows: 9242% 9243% o display: Specifies a connection to an X server; returned from 9244% XOpenDisplay. 9245% 9246% o windows: Specifies a pointer to a XWindows structure. 9247% 9248% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9249% the entire image is refreshed. 9250% 9251*/ 9252static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9253{ 9254 char 9255 text[MaxTextExtent]; 9256 9257 register int 9258 x, 9259 y; 9260 9261 size_t 9262 state; 9263 9264 /* 9265 Update magnified image until the mouse button is released. 9266 */ 9267 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9268 state=DefaultState; 9269 x=event->xbutton.x; 9270 y=event->xbutton.y; 9271 windows->magnify.x=(int) windows->image.x+x; 9272 windows->magnify.y=(int) windows->image.y+y; 9273 do 9274 { 9275 /* 9276 Map and unmap Info widget as text cursor crosses its boundaries. 9277 */ 9278 if (windows->info.mapped != MagickFalse) 9279 { 9280 if ((x < (int) (windows->info.x+windows->info.width)) && 9281 (y < (int) (windows->info.y+windows->info.height))) 9282 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9283 } 9284 else 9285 if ((x > (int) (windows->info.x+windows->info.width)) || 9286 (y > (int) (windows->info.y+windows->info.height))) 9287 (void) XMapWindow(display,windows->info.id); 9288 if (windows->info.mapped != MagickFalse) 9289 { 9290 /* 9291 Display pointer position. 9292 */ 9293 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9294 windows->magnify.x,windows->magnify.y); 9295 XInfoWidget(display,windows,text); 9296 } 9297 /* 9298 Wait for next event. 9299 */ 9300 XScreenEvent(display,windows,event); 9301 switch (event->type) 9302 { 9303 case ButtonPress: 9304 break; 9305 case ButtonRelease: 9306 { 9307 /* 9308 User has finished magnifying image. 9309 */ 9310 x=event->xbutton.x; 9311 y=event->xbutton.y; 9312 state|=ExitState; 9313 break; 9314 } 9315 case Expose: 9316 break; 9317 case MotionNotify: 9318 { 9319 x=event->xmotion.x; 9320 y=event->xmotion.y; 9321 break; 9322 } 9323 default: 9324 break; 9325 } 9326 /* 9327 Check boundary conditions. 9328 */ 9329 if (x < 0) 9330 x=0; 9331 else 9332 if (x >= (int) windows->image.width) 9333 x=(int) windows->image.width-1; 9334 if (y < 0) 9335 y=0; 9336 else 9337 if (y >= (int) windows->image.height) 9338 y=(int) windows->image.height-1; 9339 } while ((state & ExitState) == 0); 9340 /* 9341 Display magnified image. 9342 */ 9343 XSetCursorState(display,windows,MagickFalse); 9344} 9345 9346/* 9347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9348% % 9349% % 9350% % 9351+ X M a g n i f y W i n d o w C o m m a n d % 9352% % 9353% % 9354% % 9355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9356% 9357% XMagnifyWindowCommand() moves the image within an Magnify window by one 9358% pixel as specified by the key symbol. 9359% 9360% The format of the XMagnifyWindowCommand method is: 9361% 9362% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9363% const MagickStatusType state,const KeySym key_symbol) 9364% 9365% A description of each parameter follows: 9366% 9367% o display: Specifies a connection to an X server; returned from 9368% XOpenDisplay. 9369% 9370% o windows: Specifies a pointer to a XWindows structure. 9371% 9372% o state: key mask. 9373% 9374% o key_symbol: Specifies a KeySym which indicates which side of the image 9375% to trim. 9376% 9377*/ 9378static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9379 const MagickStatusType state,const KeySym key_symbol) 9380{ 9381 unsigned int 9382 quantum; 9383 9384 /* 9385 User specified a magnify factor or position. 9386 */ 9387 quantum=1; 9388 if ((state & Mod1Mask) != 0) 9389 quantum=10; 9390 switch ((int) key_symbol) 9391 { 9392 case QuitCommand: 9393 { 9394 (void) XWithdrawWindow(display,windows->magnify.id, 9395 windows->magnify.screen); 9396 break; 9397 } 9398 case XK_Home: 9399 case XK_KP_Home: 9400 { 9401 windows->magnify.x=(int) windows->image.width/2; 9402 windows->magnify.y=(int) windows->image.height/2; 9403 break; 9404 } 9405 case XK_Left: 9406 case XK_KP_Left: 9407 { 9408 if (windows->magnify.x > 0) 9409 windows->magnify.x-=quantum; 9410 break; 9411 } 9412 case XK_Up: 9413 case XK_KP_Up: 9414 { 9415 if (windows->magnify.y > 0) 9416 windows->magnify.y-=quantum; 9417 break; 9418 } 9419 case XK_Right: 9420 case XK_KP_Right: 9421 { 9422 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9423 windows->magnify.x+=quantum; 9424 break; 9425 } 9426 case XK_Down: 9427 case XK_KP_Down: 9428 { 9429 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9430 windows->magnify.y+=quantum; 9431 break; 9432 } 9433 case XK_0: 9434 case XK_1: 9435 case XK_2: 9436 case XK_3: 9437 case XK_4: 9438 case XK_5: 9439 case XK_6: 9440 case XK_7: 9441 case XK_8: 9442 case XK_9: 9443 { 9444 windows->magnify.data=(key_symbol-XK_0); 9445 break; 9446 } 9447 case XK_KP_0: 9448 case XK_KP_1: 9449 case XK_KP_2: 9450 case XK_KP_3: 9451 case XK_KP_4: 9452 case XK_KP_5: 9453 case XK_KP_6: 9454 case XK_KP_7: 9455 case XK_KP_8: 9456 case XK_KP_9: 9457 { 9458 windows->magnify.data=(key_symbol-XK_KP_0); 9459 break; 9460 } 9461 default: 9462 break; 9463 } 9464 XMakeMagnifyImage(display,windows); 9465} 9466 9467/* 9468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9469% % 9470% % 9471% % 9472+ X M a k e P a n I m a g e % 9473% % 9474% % 9475% % 9476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9477% 9478% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9479% icon window. 9480% 9481% The format of the XMakePanImage method is: 9482% 9483% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9484% XWindows *windows,Image *image) 9485% 9486% A description of each parameter follows: 9487% 9488% o display: Specifies a connection to an X server; returned from 9489% XOpenDisplay. 9490% 9491% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9492% 9493% o windows: Specifies a pointer to a XWindows structure. 9494% 9495% o image: the image. 9496% 9497*/ 9498static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9499 XWindows *windows,Image *image) 9500{ 9501 MagickStatusType 9502 status; 9503 9504 /* 9505 Create and display image for panning icon. 9506 */ 9507 XSetCursorState(display,windows,MagickTrue); 9508 XCheckRefreshWindows(display,windows); 9509 windows->pan.x=(int) windows->image.x; 9510 windows->pan.y=(int) windows->image.y; 9511 status=XMakeImage(display,resource_info,&windows->pan,image, 9512 windows->pan.width,windows->pan.height); 9513 if (status == MagickFalse) 9514 ThrowXWindowFatalException(XServerError,image->exception.reason, 9515 image->exception.description); 9516 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9517 windows->pan.pixmap); 9518 (void) XClearWindow(display,windows->pan.id); 9519 XDrawPanRectangle(display,windows); 9520 XSetCursorState(display,windows,MagickFalse); 9521} 9522 9523/* 9524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9525% % 9526% % 9527% % 9528+ X M a t t a E d i t I m a g e % 9529% % 9530% % 9531% % 9532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9533% 9534% XMatteEditImage() allows the user to interactively change the Matte channel 9535% of an image. If the image is PseudoClass it is promoted to DirectClass 9536% before the matte information is stored. 9537% 9538% The format of the XMatteEditImage method is: 9539% 9540% MagickBooleanType XMatteEditImage(Display *display, 9541% XResourceInfo *resource_info,XWindows *windows,Image **image) 9542% 9543% A description of each parameter follows: 9544% 9545% o display: Specifies a connection to an X server; returned from 9546% XOpenDisplay. 9547% 9548% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9549% 9550% o windows: Specifies a pointer to a XWindows structure. 9551% 9552% o image: the image; returned from ReadImage. 9553% 9554*/ 9555static MagickBooleanType XMatteEditImage(Display *display, 9556 XResourceInfo *resource_info,XWindows *windows,Image **image) 9557{ 9558 static char 9559 matte[MaxTextExtent] = "0"; 9560 9561 static const char 9562 *MatteEditMenu[] = 9563 { 9564 "Method", 9565 "Border Color", 9566 "Fuzz", 9567 "Matte Value", 9568 "Undo", 9569 "Help", 9570 "Dismiss", 9571 (char *) NULL 9572 }; 9573 9574 static const ModeType 9575 MatteEditCommands[] = 9576 { 9577 MatteEditMethod, 9578 MatteEditBorderCommand, 9579 MatteEditFuzzCommand, 9580 MatteEditValueCommand, 9581 MatteEditUndoCommand, 9582 MatteEditHelpCommand, 9583 MatteEditDismissCommand 9584 }; 9585 9586 static PaintMethod 9587 method = PointMethod; 9588 9589 static XColor 9590 border_color = { 0, 0, 0, 0, 0, 0 }; 9591 9592 char 9593 command[MaxTextExtent], 9594 text[MaxTextExtent]; 9595 9596 Cursor 9597 cursor; 9598 9599 int 9600 entry, 9601 id, 9602 x, 9603 x_offset, 9604 y, 9605 y_offset; 9606 9607 register int 9608 i; 9609 9610 register Quantum 9611 *q; 9612 9613 unsigned int 9614 height, 9615 width; 9616 9617 size_t 9618 state; 9619 9620 XEvent 9621 event; 9622 9623 /* 9624 Map Command widget. 9625 */ 9626 (void) CloneString(&windows->command.name,"Matte Edit"); 9627 windows->command.data=4; 9628 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9629 (void) XMapRaised(display,windows->command.id); 9630 XClientMessage(display,windows->image.id,windows->im_protocols, 9631 windows->im_update_widget,CurrentTime); 9632 /* 9633 Make cursor. 9634 */ 9635 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9636 resource_info->background_color,resource_info->foreground_color); 9637 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9638 /* 9639 Track pointer until button 1 is pressed. 9640 */ 9641 XQueryPosition(display,windows->image.id,&x,&y); 9642 (void) XSelectInput(display,windows->image.id, 9643 windows->image.attributes.event_mask | PointerMotionMask); 9644 state=DefaultState; 9645 do 9646 { 9647 if (windows->info.mapped != MagickFalse) 9648 { 9649 /* 9650 Display pointer position. 9651 */ 9652 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9653 x+windows->image.x,y+windows->image.y); 9654 XInfoWidget(display,windows,text); 9655 } 9656 /* 9657 Wait for next event. 9658 */ 9659 XScreenEvent(display,windows,&event); 9660 if (event.xany.window == windows->command.id) 9661 { 9662 /* 9663 Select a command from the Command widget. 9664 */ 9665 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9666 if (id < 0) 9667 { 9668 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9669 continue; 9670 } 9671 switch (MatteEditCommands[id]) 9672 { 9673 case MatteEditMethod: 9674 { 9675 char 9676 **methods; 9677 9678 /* 9679 Select a method from the pop-up menu. 9680 */ 9681 methods=GetCommandOptions(MagickMethodOptions); 9682 if (methods == (char **) NULL) 9683 break; 9684 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9685 (const char **) methods,command); 9686 if (entry >= 0) 9687 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9688 MagickFalse,methods[entry]); 9689 methods=DestroyStringList(methods); 9690 break; 9691 } 9692 case MatteEditBorderCommand: 9693 { 9694 const char 9695 *ColorMenu[MaxNumberPens]; 9696 9697 int 9698 pen_number; 9699 9700 /* 9701 Initialize menu selections. 9702 */ 9703 for (i=0; i < (int) (MaxNumberPens-2); i++) 9704 ColorMenu[i]=resource_info->pen_colors[i]; 9705 ColorMenu[MaxNumberPens-2]="Browser..."; 9706 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9707 /* 9708 Select a pen color from the pop-up menu. 9709 */ 9710 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9711 (const char **) ColorMenu,command); 9712 if (pen_number < 0) 9713 break; 9714 if (pen_number == (MaxNumberPens-2)) 9715 { 9716 static char 9717 color_name[MaxTextExtent] = "gray"; 9718 9719 /* 9720 Select a pen color from a dialog. 9721 */ 9722 resource_info->pen_colors[pen_number]=color_name; 9723 XColorBrowserWidget(display,windows,"Select",color_name); 9724 if (*color_name == '\0') 9725 break; 9726 } 9727 /* 9728 Set border color. 9729 */ 9730 (void) XParseColor(display,windows->map_info->colormap, 9731 resource_info->pen_colors[pen_number],&border_color); 9732 break; 9733 } 9734 case MatteEditFuzzCommand: 9735 { 9736 static char 9737 fuzz[MaxTextExtent]; 9738 9739 static const char 9740 *FuzzMenu[] = 9741 { 9742 "0%", 9743 "2%", 9744 "5%", 9745 "10%", 9746 "15%", 9747 "Dialog...", 9748 (char *) NULL, 9749 }; 9750 9751 /* 9752 Select a command from the pop-up menu. 9753 */ 9754 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9755 command); 9756 if (entry < 0) 9757 break; 9758 if (entry != 5) 9759 { 9760 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 9761 QuantumRange+1.0); 9762 break; 9763 } 9764 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9765 (void) XDialogWidget(display,windows,"Ok", 9766 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9767 if (*fuzz == '\0') 9768 break; 9769 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9770 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 9771 break; 9772 } 9773 case MatteEditValueCommand: 9774 { 9775 static char 9776 message[MaxTextExtent]; 9777 9778 static const char 9779 *MatteMenu[] = 9780 { 9781 "Opaque", 9782 "Transparent", 9783 "Dialog...", 9784 (char *) NULL, 9785 }; 9786 9787 /* 9788 Select a command from the pop-up menu. 9789 */ 9790 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9791 command); 9792 if (entry < 0) 9793 break; 9794 if (entry != 2) 9795 { 9796 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9797 OpaqueAlpha); 9798 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9799 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9800 (Quantum) TransparentAlpha); 9801 break; 9802 } 9803 (void) FormatLocaleString(message,MaxTextExtent, 9804 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9805 QuantumRange); 9806 (void) XDialogWidget(display,windows,"Matte",message,matte); 9807 if (*matte == '\0') 9808 break; 9809 break; 9810 } 9811 case MatteEditUndoCommand: 9812 { 9813 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9814 image); 9815 break; 9816 } 9817 case MatteEditHelpCommand: 9818 { 9819 XTextViewWidget(display,resource_info,windows,MagickFalse, 9820 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9821 break; 9822 } 9823 case MatteEditDismissCommand: 9824 { 9825 /* 9826 Prematurely exit. 9827 */ 9828 state|=EscapeState; 9829 state|=ExitState; 9830 break; 9831 } 9832 default: 9833 break; 9834 } 9835 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9836 continue; 9837 } 9838 switch (event.type) 9839 { 9840 case ButtonPress: 9841 { 9842 if (event.xbutton.button != Button1) 9843 break; 9844 if ((event.xbutton.window != windows->image.id) && 9845 (event.xbutton.window != windows->magnify.id)) 9846 break; 9847 /* 9848 Update matte data. 9849 */ 9850 x=event.xbutton.x; 9851 y=event.xbutton.y; 9852 (void) XMagickCommand(display,resource_info,windows, 9853 SaveToUndoBufferCommand,image); 9854 state|=UpdateConfigurationState; 9855 break; 9856 } 9857 case ButtonRelease: 9858 { 9859 if (event.xbutton.button != Button1) 9860 break; 9861 if ((event.xbutton.window != windows->image.id) && 9862 (event.xbutton.window != windows->magnify.id)) 9863 break; 9864 /* 9865 Update colormap information. 9866 */ 9867 x=event.xbutton.x; 9868 y=event.xbutton.y; 9869 XConfigureImageColormap(display,resource_info,windows,*image); 9870 (void) XConfigureImage(display,resource_info,windows,*image); 9871 XInfoWidget(display,windows,text); 9872 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9873 state&=(~UpdateConfigurationState); 9874 break; 9875 } 9876 case Expose: 9877 break; 9878 case KeyPress: 9879 { 9880 char 9881 command[MaxTextExtent]; 9882 9883 KeySym 9884 key_symbol; 9885 9886 if (event.xkey.window == windows->magnify.id) 9887 { 9888 Window 9889 window; 9890 9891 window=windows->magnify.id; 9892 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9893 } 9894 if (event.xkey.window != windows->image.id) 9895 break; 9896 /* 9897 Respond to a user key press. 9898 */ 9899 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9900 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9901 switch ((int) key_symbol) 9902 { 9903 case XK_Escape: 9904 case XK_F20: 9905 { 9906 /* 9907 Prematurely exit. 9908 */ 9909 state|=ExitState; 9910 break; 9911 } 9912 case XK_F1: 9913 case XK_Help: 9914 { 9915 XTextViewWidget(display,resource_info,windows,MagickFalse, 9916 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9917 break; 9918 } 9919 default: 9920 { 9921 (void) XBell(display,0); 9922 break; 9923 } 9924 } 9925 break; 9926 } 9927 case MotionNotify: 9928 { 9929 /* 9930 Map and unmap Info widget as cursor crosses its boundaries. 9931 */ 9932 x=event.xmotion.x; 9933 y=event.xmotion.y; 9934 if (windows->info.mapped != MagickFalse) 9935 { 9936 if ((x < (int) (windows->info.x+windows->info.width)) && 9937 (y < (int) (windows->info.y+windows->info.height))) 9938 (void) XWithdrawWindow(display,windows->info.id, 9939 windows->info.screen); 9940 } 9941 else 9942 if ((x > (int) (windows->info.x+windows->info.width)) || 9943 (y > (int) (windows->info.y+windows->info.height))) 9944 (void) XMapWindow(display,windows->info.id); 9945 break; 9946 } 9947 default: 9948 break; 9949 } 9950 if (event.xany.window == windows->magnify.id) 9951 { 9952 x=windows->magnify.x-windows->image.x; 9953 y=windows->magnify.y-windows->image.y; 9954 } 9955 x_offset=x; 9956 y_offset=y; 9957 if ((state & UpdateConfigurationState) != 0) 9958 { 9959 CacheView 9960 *image_view; 9961 9962 ExceptionInfo 9963 *exception; 9964 9965 int 9966 x, 9967 y; 9968 9969 /* 9970 Matte edit is relative to image configuration. 9971 */ 9972 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 9973 MagickTrue); 9974 XPutPixel(windows->image.ximage,x_offset,y_offset, 9975 windows->pixel_info->background_color.pixel); 9976 width=(unsigned int) (*image)->columns; 9977 height=(unsigned int) (*image)->rows; 9978 x=0; 9979 y=0; 9980 if (windows->image.crop_geometry != (char *) NULL) 9981 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 9982 &height); 9983 x_offset=(int) (width*(windows->image.x+x_offset)/ 9984 windows->image.ximage->width+x); 9985 y_offset=(int) (height*(windows->image.y+y_offset)/ 9986 windows->image.ximage->height+y); 9987 if ((x_offset < 0) || (y_offset < 0)) 9988 continue; 9989 if ((x_offset >= (int) (*image)->columns) || 9990 (y_offset >= (int) (*image)->rows)) 9991 continue; 9992 if (SetImageStorageClass(*image,DirectClass) == MagickFalse) 9993 return(MagickFalse); 9994 (*image)->matte=MagickTrue; 9995 exception=(&(*image)->exception); 9996 image_view=AcquireCacheView(*image); 9997 switch (method) 9998 { 9999 case PointMethod: 10000 default: 10001 { 10002 /* 10003 Update matte information using point algorithm. 10004 */ 10005 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10006 (ssize_t) y_offset,1,1,exception); 10007 if (q == (Quantum *) NULL) 10008 break; 10009 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10010 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10011 break; 10012 } 10013 case ReplaceMethod: 10014 { 10015 PixelPacket 10016 pixel, 10017 target; 10018 10019 /* 10020 Update matte information using replace algorithm. 10021 */ 10022 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10023 (ssize_t) y_offset,&target,exception); 10024 for (y=0; y < (int) (*image)->rows; y++) 10025 { 10026 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10027 (*image)->columns,1,&(*image)->exception); 10028 if (q == (Quantum *) NULL) 10029 break; 10030 for (x=0; x < (int) (*image)->columns; x++) 10031 { 10032 GetPixelPacket(*image,q,&pixel); 10033 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 10034 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10035 q+=GetPixelChannels(*image); 10036 } 10037 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10038 break; 10039 } 10040 break; 10041 } 10042 case FloodfillMethod: 10043 case FillToBorderMethod: 10044 { 10045 DrawInfo 10046 *draw_info; 10047 10048 PixelInfo 10049 target; 10050 10051 /* 10052 Update matte information using floodfill algorithm. 10053 */ 10054 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10055 (ssize_t) y_offset,&target,exception); 10056 if (method == FillToBorderMethod) 10057 { 10058 target.red=(MagickRealType) ScaleShortToQuantum( 10059 border_color.red); 10060 target.green=(MagickRealType) ScaleShortToQuantum( 10061 border_color.green); 10062 target.blue=(MagickRealType) ScaleShortToQuantum( 10063 border_color.blue); 10064 } 10065 draw_info=CloneDrawInfo(resource_info->image_info, 10066 (DrawInfo *) NULL); 10067 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10068 (char **) NULL)); 10069 (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target, 10070 (ssize_t) x_offset,(ssize_t) y_offset, 10071 method == FloodfillMethod ? MagickFalse : MagickTrue); 10072 draw_info=DestroyDrawInfo(draw_info); 10073 break; 10074 } 10075 case ResetMethod: 10076 { 10077 /* 10078 Update matte information using reset algorithm. 10079 */ 10080 if (SetImageStorageClass(*image,DirectClass) == MagickFalse) 10081 return(MagickFalse); 10082 for (y=0; y < (int) (*image)->rows; y++) 10083 { 10084 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10085 (*image)->columns,1,exception); 10086 if (q == (Quantum *) NULL) 10087 break; 10088 for (x=0; x < (int) (*image)->columns; x++) 10089 { 10090 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10091 q+=GetPixelChannels(*image); 10092 } 10093 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10094 break; 10095 } 10096 if (StringToLong(matte) == (long) OpaqueAlpha) 10097 (*image)->matte=MagickFalse; 10098 break; 10099 } 10100 } 10101 image_view=DestroyCacheView(image_view); 10102 state&=(~UpdateConfigurationState); 10103 } 10104 } while ((state & ExitState) == 0); 10105 (void) XSelectInput(display,windows->image.id, 10106 windows->image.attributes.event_mask); 10107 XSetCursorState(display,windows,MagickFalse); 10108 (void) XFreeCursor(display,cursor); 10109 return(MagickTrue); 10110} 10111 10112/* 10113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10114% % 10115% % 10116% % 10117+ X O p e n I m a g e % 10118% % 10119% % 10120% % 10121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10122% 10123% XOpenImage() loads an image from a file. 10124% 10125% The format of the XOpenImage method is: 10126% 10127% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10128% XWindows *windows,const unsigned int command) 10129% 10130% A description of each parameter follows: 10131% 10132% o display: Specifies a connection to an X server; returned from 10133% XOpenDisplay. 10134% 10135% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10136% 10137% o windows: Specifies a pointer to a XWindows structure. 10138% 10139% o command: A value other than zero indicates that the file is selected 10140% from the command line argument list. 10141% 10142*/ 10143static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10144 XWindows *windows,const MagickBooleanType command) 10145{ 10146 const MagickInfo 10147 *magick_info; 10148 10149 ExceptionInfo 10150 *exception; 10151 10152 Image 10153 *nexus; 10154 10155 ImageInfo 10156 *image_info; 10157 10158 static char 10159 filename[MaxTextExtent] = "\0"; 10160 10161 /* 10162 Request file name from user. 10163 */ 10164 if (command == MagickFalse) 10165 XFileBrowserWidget(display,windows,"Open",filename); 10166 else 10167 { 10168 char 10169 **filelist, 10170 **files; 10171 10172 int 10173 count, 10174 status; 10175 10176 register int 10177 i, 10178 j; 10179 10180 /* 10181 Select next image from the command line. 10182 */ 10183 status=XGetCommand(display,windows->image.id,&files,&count); 10184 if (status == 0) 10185 { 10186 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10187 return((Image *) NULL); 10188 } 10189 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10190 if (filelist == (char **) NULL) 10191 { 10192 ThrowXWindowFatalException(ResourceLimitError, 10193 "MemoryAllocationFailed","..."); 10194 (void) XFreeStringList(files); 10195 return((Image *) NULL); 10196 } 10197 j=0; 10198 for (i=1; i < count; i++) 10199 if (*files[i] != '-') 10200 filelist[j++]=files[i]; 10201 filelist[j]=(char *) NULL; 10202 XListBrowserWidget(display,windows,&windows->widget, 10203 (const char **) filelist,"Load","Select Image to Load:",filename); 10204 filelist=(char **) RelinquishMagickMemory(filelist); 10205 (void) XFreeStringList(files); 10206 } 10207 if (*filename == '\0') 10208 return((Image *) NULL); 10209 image_info=CloneImageInfo(resource_info->image_info); 10210 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10211 (void *) NULL); 10212 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10213 exception=AcquireExceptionInfo(); 10214 (void) SetImageInfo(image_info,0,exception); 10215 if (LocaleCompare(image_info->magick,"X") == 0) 10216 { 10217 char 10218 seconds[MaxTextExtent]; 10219 10220 /* 10221 User may want to delay the X server screen grab. 10222 */ 10223 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10224 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10225 seconds); 10226 if (*seconds == '\0') 10227 return((Image *) NULL); 10228 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10229 } 10230 magick_info=GetMagickInfo(image_info->magick,exception); 10231 if ((magick_info != (const MagickInfo *) NULL) && 10232 (magick_info->raw != MagickFalse)) 10233 { 10234 char 10235 geometry[MaxTextExtent]; 10236 10237 /* 10238 Request image size from the user. 10239 */ 10240 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10241 if (image_info->size != (char *) NULL) 10242 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10243 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10244 geometry); 10245 (void) CloneString(&image_info->size,geometry); 10246 } 10247 /* 10248 Load the image. 10249 */ 10250 XSetCursorState(display,windows,MagickTrue); 10251 XCheckRefreshWindows(display,windows); 10252 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10253 nexus=ReadImage(image_info,exception); 10254 CatchException(exception); 10255 XSetCursorState(display,windows,MagickFalse); 10256 if (nexus != (Image *) NULL) 10257 XClientMessage(display,windows->image.id,windows->im_protocols, 10258 windows->im_next_image,CurrentTime); 10259 else 10260 { 10261 char 10262 *text, 10263 **textlist; 10264 10265 /* 10266 Unknown image format. 10267 */ 10268 text=FileToString(filename,~0,exception); 10269 if (text == (char *) NULL) 10270 return((Image *) NULL); 10271 textlist=StringToList(text); 10272 if (textlist != (char **) NULL) 10273 { 10274 char 10275 title[MaxTextExtent]; 10276 10277 register int 10278 i; 10279 10280 (void) FormatLocaleString(title,MaxTextExtent, 10281 "Unknown format: %s",filename); 10282 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10283 (const char **) textlist); 10284 for (i=0; textlist[i] != (char *) NULL; i++) 10285 textlist[i]=DestroyString(textlist[i]); 10286 textlist=(char **) RelinquishMagickMemory(textlist); 10287 } 10288 text=DestroyString(text); 10289 } 10290 exception=DestroyExceptionInfo(exception); 10291 image_info=DestroyImageInfo(image_info); 10292 return(nexus); 10293} 10294 10295/* 10296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10297% % 10298% % 10299% % 10300+ X P a n I m a g e % 10301% % 10302% % 10303% % 10304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10305% 10306% XPanImage() pans the image until the mouse button is released. 10307% 10308% The format of the XPanImage method is: 10309% 10310% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10311% 10312% A description of each parameter follows: 10313% 10314% o display: Specifies a connection to an X server; returned from 10315% XOpenDisplay. 10316% 10317% o windows: Specifies a pointer to a XWindows structure. 10318% 10319% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10320% the entire image is refreshed. 10321% 10322*/ 10323static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10324{ 10325 char 10326 text[MaxTextExtent]; 10327 10328 Cursor 10329 cursor; 10330 10331 MagickRealType 10332 x_factor, 10333 y_factor; 10334 10335 RectangleInfo 10336 pan_info; 10337 10338 size_t 10339 state; 10340 10341 /* 10342 Define cursor. 10343 */ 10344 if ((windows->image.ximage->width > (int) windows->image.width) && 10345 (windows->image.ximage->height > (int) windows->image.height)) 10346 cursor=XCreateFontCursor(display,XC_fleur); 10347 else 10348 if (windows->image.ximage->width > (int) windows->image.width) 10349 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10350 else 10351 if (windows->image.ximage->height > (int) windows->image.height) 10352 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10353 else 10354 cursor=XCreateFontCursor(display,XC_arrow); 10355 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10356 /* 10357 Pan image as pointer moves until the mouse button is released. 10358 */ 10359 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10360 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10361 pan_info.width=windows->pan.width*windows->image.width/ 10362 windows->image.ximage->width; 10363 pan_info.height=windows->pan.height*windows->image.height/ 10364 windows->image.ximage->height; 10365 pan_info.x=0; 10366 pan_info.y=0; 10367 state=UpdateConfigurationState; 10368 do 10369 { 10370 switch (event->type) 10371 { 10372 case ButtonPress: 10373 { 10374 /* 10375 User choose an initial pan location. 10376 */ 10377 pan_info.x=(ssize_t) event->xbutton.x; 10378 pan_info.y=(ssize_t) event->xbutton.y; 10379 state|=UpdateConfigurationState; 10380 break; 10381 } 10382 case ButtonRelease: 10383 { 10384 /* 10385 User has finished panning the image. 10386 */ 10387 pan_info.x=(ssize_t) event->xbutton.x; 10388 pan_info.y=(ssize_t) event->xbutton.y; 10389 state|=UpdateConfigurationState | ExitState; 10390 break; 10391 } 10392 case MotionNotify: 10393 { 10394 pan_info.x=(ssize_t) event->xmotion.x; 10395 pan_info.y=(ssize_t) event->xmotion.y; 10396 state|=UpdateConfigurationState; 10397 } 10398 default: 10399 break; 10400 } 10401 if ((state & UpdateConfigurationState) != 0) 10402 { 10403 /* 10404 Check boundary conditions. 10405 */ 10406 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10407 pan_info.x=0; 10408 else 10409 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10410 if (pan_info.x < 0) 10411 pan_info.x=0; 10412 else 10413 if ((int) (pan_info.x+windows->image.width) > 10414 windows->image.ximage->width) 10415 pan_info.x=(ssize_t) 10416 (windows->image.ximage->width-windows->image.width); 10417 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10418 pan_info.y=0; 10419 else 10420 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10421 if (pan_info.y < 0) 10422 pan_info.y=0; 10423 else 10424 if ((int) (pan_info.y+windows->image.height) > 10425 windows->image.ximage->height) 10426 pan_info.y=(ssize_t) 10427 (windows->image.ximage->height-windows->image.height); 10428 if ((windows->image.x != (int) pan_info.x) || 10429 (windows->image.y != (int) pan_info.y)) 10430 { 10431 /* 10432 Display image pan offset. 10433 */ 10434 windows->image.x=(int) pan_info.x; 10435 windows->image.y=(int) pan_info.y; 10436 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10437 windows->image.width,windows->image.height,windows->image.x, 10438 windows->image.y); 10439 XInfoWidget(display,windows,text); 10440 /* 10441 Refresh Image window. 10442 */ 10443 XDrawPanRectangle(display,windows); 10444 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10445 } 10446 state&=(~UpdateConfigurationState); 10447 } 10448 /* 10449 Wait for next event. 10450 */ 10451 if ((state & ExitState) == 0) 10452 XScreenEvent(display,windows,event); 10453 } while ((state & ExitState) == 0); 10454 /* 10455 Restore cursor. 10456 */ 10457 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10458 (void) XFreeCursor(display,cursor); 10459 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10460} 10461 10462/* 10463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10464% % 10465% % 10466% % 10467+ X P a s t e I m a g e % 10468% % 10469% % 10470% % 10471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10472% 10473% XPasteImage() pastes an image previously saved with XCropImage in the X 10474% window image at a location the user chooses with the pointer. 10475% 10476% The format of the XPasteImage method is: 10477% 10478% MagickBooleanType XPasteImage(Display *display, 10479% XResourceInfo *resource_info,XWindows *windows,Image *image) 10480% 10481% A description of each parameter follows: 10482% 10483% o display: Specifies a connection to an X server; returned from 10484% XOpenDisplay. 10485% 10486% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10487% 10488% o windows: Specifies a pointer to a XWindows structure. 10489% 10490% o image: the image; returned from ReadImage. 10491% 10492*/ 10493static MagickBooleanType XPasteImage(Display *display, 10494 XResourceInfo *resource_info,XWindows *windows,Image *image) 10495{ 10496 static const char 10497 *PasteMenu[] = 10498 { 10499 "Operator", 10500 "Help", 10501 "Dismiss", 10502 (char *) NULL 10503 }; 10504 10505 static const ModeType 10506 PasteCommands[] = 10507 { 10508 PasteOperatorsCommand, 10509 PasteHelpCommand, 10510 PasteDismissCommand 10511 }; 10512 10513 static CompositeOperator 10514 compose = CopyCompositeOp; 10515 10516 char 10517 text[MaxTextExtent]; 10518 10519 Cursor 10520 cursor; 10521 10522 Image 10523 *paste_image; 10524 10525 int 10526 entry, 10527 id, 10528 x, 10529 y; 10530 10531 MagickRealType 10532 scale_factor; 10533 10534 RectangleInfo 10535 highlight_info, 10536 paste_info; 10537 10538 unsigned int 10539 height, 10540 width; 10541 10542 size_t 10543 state; 10544 10545 XEvent 10546 event; 10547 10548 /* 10549 Copy image. 10550 */ 10551 if (resource_info->copy_image == (Image *) NULL) 10552 return(MagickFalse); 10553 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue, 10554 &image->exception); 10555 /* 10556 Map Command widget. 10557 */ 10558 (void) CloneString(&windows->command.name,"Paste"); 10559 windows->command.data=1; 10560 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10561 (void) XMapRaised(display,windows->command.id); 10562 XClientMessage(display,windows->image.id,windows->im_protocols, 10563 windows->im_update_widget,CurrentTime); 10564 /* 10565 Track pointer until button 1 is pressed. 10566 */ 10567 XSetCursorState(display,windows,MagickFalse); 10568 XQueryPosition(display,windows->image.id,&x,&y); 10569 (void) XSelectInput(display,windows->image.id, 10570 windows->image.attributes.event_mask | PointerMotionMask); 10571 paste_info.x=(ssize_t) windows->image.x+x; 10572 paste_info.y=(ssize_t) windows->image.y+y; 10573 paste_info.width=0; 10574 paste_info.height=0; 10575 cursor=XCreateFontCursor(display,XC_ul_angle); 10576 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10577 state=DefaultState; 10578 do 10579 { 10580 if (windows->info.mapped != MagickFalse) 10581 { 10582 /* 10583 Display pointer position. 10584 */ 10585 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10586 (long) paste_info.x,(long) paste_info.y); 10587 XInfoWidget(display,windows,text); 10588 } 10589 highlight_info=paste_info; 10590 highlight_info.x=paste_info.x-windows->image.x; 10591 highlight_info.y=paste_info.y-windows->image.y; 10592 XHighlightRectangle(display,windows->image.id, 10593 windows->image.highlight_context,&highlight_info); 10594 /* 10595 Wait for next event. 10596 */ 10597 XScreenEvent(display,windows,&event); 10598 XHighlightRectangle(display,windows->image.id, 10599 windows->image.highlight_context,&highlight_info); 10600 if (event.xany.window == windows->command.id) 10601 { 10602 /* 10603 Select a command from the Command widget. 10604 */ 10605 id=XCommandWidget(display,windows,PasteMenu,&event); 10606 if (id < 0) 10607 continue; 10608 switch (PasteCommands[id]) 10609 { 10610 case PasteOperatorsCommand: 10611 { 10612 char 10613 command[MaxTextExtent], 10614 **operators; 10615 10616 /* 10617 Select a command from the pop-up menu. 10618 */ 10619 operators=GetCommandOptions(MagickComposeOptions); 10620 if (operators == (char **) NULL) 10621 break; 10622 entry=XMenuWidget(display,windows,PasteMenu[id], 10623 (const char **) operators,command); 10624 if (entry >= 0) 10625 compose=(CompositeOperator) ParseCommandOption( 10626 MagickComposeOptions,MagickFalse,operators[entry]); 10627 operators=DestroyStringList(operators); 10628 break; 10629 } 10630 case PasteHelpCommand: 10631 { 10632 XTextViewWidget(display,resource_info,windows,MagickFalse, 10633 "Help Viewer - Image Composite",ImagePasteHelp); 10634 break; 10635 } 10636 case PasteDismissCommand: 10637 { 10638 /* 10639 Prematurely exit. 10640 */ 10641 state|=EscapeState; 10642 state|=ExitState; 10643 break; 10644 } 10645 default: 10646 break; 10647 } 10648 continue; 10649 } 10650 switch (event.type) 10651 { 10652 case ButtonPress: 10653 { 10654 if (image->debug != MagickFalse) 10655 (void) LogMagickEvent(X11Event,GetMagickModule(), 10656 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10657 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10658 if (event.xbutton.button != Button1) 10659 break; 10660 if (event.xbutton.window != windows->image.id) 10661 break; 10662 /* 10663 Paste rectangle is relative to image configuration. 10664 */ 10665 width=(unsigned int) image->columns; 10666 height=(unsigned int) image->rows; 10667 x=0; 10668 y=0; 10669 if (windows->image.crop_geometry != (char *) NULL) 10670 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10671 &width,&height); 10672 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10673 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10674 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10675 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10676 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10677 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10678 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10679 break; 10680 } 10681 case ButtonRelease: 10682 { 10683 if (image->debug != MagickFalse) 10684 (void) LogMagickEvent(X11Event,GetMagickModule(), 10685 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10686 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10687 if (event.xbutton.button != Button1) 10688 break; 10689 if (event.xbutton.window != windows->image.id) 10690 break; 10691 if ((paste_info.width != 0) && (paste_info.height != 0)) 10692 { 10693 /* 10694 User has selected the location of the paste image. 10695 */ 10696 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10697 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10698 state|=ExitState; 10699 } 10700 break; 10701 } 10702 case Expose: 10703 break; 10704 case KeyPress: 10705 { 10706 char 10707 command[MaxTextExtent]; 10708 10709 KeySym 10710 key_symbol; 10711 10712 int 10713 length; 10714 10715 if (event.xkey.window != windows->image.id) 10716 break; 10717 /* 10718 Respond to a user key press. 10719 */ 10720 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10721 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10722 *(command+length)='\0'; 10723 if (image->debug != MagickFalse) 10724 (void) LogMagickEvent(X11Event,GetMagickModule(), 10725 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10726 switch ((int) key_symbol) 10727 { 10728 case XK_Escape: 10729 case XK_F20: 10730 { 10731 /* 10732 Prematurely exit. 10733 */ 10734 paste_image=DestroyImage(paste_image); 10735 state|=EscapeState; 10736 state|=ExitState; 10737 break; 10738 } 10739 case XK_F1: 10740 case XK_Help: 10741 { 10742 (void) XSetFunction(display,windows->image.highlight_context, 10743 GXcopy); 10744 XTextViewWidget(display,resource_info,windows,MagickFalse, 10745 "Help Viewer - Image Composite",ImagePasteHelp); 10746 (void) XSetFunction(display,windows->image.highlight_context, 10747 GXinvert); 10748 break; 10749 } 10750 default: 10751 { 10752 (void) XBell(display,0); 10753 break; 10754 } 10755 } 10756 break; 10757 } 10758 case MotionNotify: 10759 { 10760 /* 10761 Map and unmap Info widget as text cursor crosses its boundaries. 10762 */ 10763 x=event.xmotion.x; 10764 y=event.xmotion.y; 10765 if (windows->info.mapped != MagickFalse) 10766 { 10767 if ((x < (int) (windows->info.x+windows->info.width)) && 10768 (y < (int) (windows->info.y+windows->info.height))) 10769 (void) XWithdrawWindow(display,windows->info.id, 10770 windows->info.screen); 10771 } 10772 else 10773 if ((x > (int) (windows->info.x+windows->info.width)) || 10774 (y > (int) (windows->info.y+windows->info.height))) 10775 (void) XMapWindow(display,windows->info.id); 10776 paste_info.x=(ssize_t) windows->image.x+x; 10777 paste_info.y=(ssize_t) windows->image.y+y; 10778 break; 10779 } 10780 default: 10781 { 10782 if (image->debug != MagickFalse) 10783 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10784 event.type); 10785 break; 10786 } 10787 } 10788 } while ((state & ExitState) == 0); 10789 (void) XSelectInput(display,windows->image.id, 10790 windows->image.attributes.event_mask); 10791 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10792 XSetCursorState(display,windows,MagickFalse); 10793 (void) XFreeCursor(display,cursor); 10794 if ((state & EscapeState) != 0) 10795 return(MagickTrue); 10796 /* 10797 Image pasting is relative to image configuration. 10798 */ 10799 XSetCursorState(display,windows,MagickTrue); 10800 XCheckRefreshWindows(display,windows); 10801 width=(unsigned int) image->columns; 10802 height=(unsigned int) image->rows; 10803 x=0; 10804 y=0; 10805 if (windows->image.crop_geometry != (char *) NULL) 10806 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10807 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10808 paste_info.x+=x; 10809 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10810 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10811 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10812 paste_info.y+=y; 10813 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10814 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10815 /* 10816 Paste image with X Image window. 10817 */ 10818 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y); 10819 paste_image=DestroyImage(paste_image); 10820 XSetCursorState(display,windows,MagickFalse); 10821 /* 10822 Update image colormap. 10823 */ 10824 XConfigureImageColormap(display,resource_info,windows,image); 10825 (void) XConfigureImage(display,resource_info,windows,image); 10826 return(MagickTrue); 10827} 10828 10829/* 10830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10831% % 10832% % 10833% % 10834+ X P r i n t I m a g e % 10835% % 10836% % 10837% % 10838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10839% 10840% XPrintImage() prints an image to a Postscript printer. 10841% 10842% The format of the XPrintImage method is: 10843% 10844% MagickBooleanType XPrintImage(Display *display, 10845% XResourceInfo *resource_info,XWindows *windows,Image *image) 10846% 10847% A description of each parameter follows: 10848% 10849% o display: Specifies a connection to an X server; returned from 10850% XOpenDisplay. 10851% 10852% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10853% 10854% o windows: Specifies a pointer to a XWindows structure. 10855% 10856% o image: the image. 10857% 10858*/ 10859static MagickBooleanType XPrintImage(Display *display, 10860 XResourceInfo *resource_info,XWindows *windows,Image *image) 10861{ 10862 char 10863 filename[MaxTextExtent], 10864 geometry[MaxTextExtent]; 10865 10866 Image 10867 *print_image; 10868 10869 ImageInfo 10870 *image_info; 10871 10872 MagickStatusType 10873 status; 10874 10875 /* 10876 Request Postscript page geometry from user. 10877 */ 10878 image_info=CloneImageInfo(resource_info->image_info); 10879 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10880 if (image_info->page != (char *) NULL) 10881 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10882 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10883 "Select Postscript Page Geometry:",geometry); 10884 if (*geometry == '\0') 10885 return(MagickTrue); 10886 image_info->page=GetPageGeometry(geometry); 10887 /* 10888 Apply image transforms. 10889 */ 10890 XSetCursorState(display,windows,MagickTrue); 10891 XCheckRefreshWindows(display,windows); 10892 print_image=CloneImage(image,0,0,MagickTrue,&image->exception); 10893 if (print_image == (Image *) NULL) 10894 return(MagickFalse); 10895 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 10896 windows->image.ximage->width,windows->image.ximage->height); 10897 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry); 10898 /* 10899 Print image. 10900 */ 10901 (void) AcquireUniqueFilename(filename); 10902 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 10903 filename); 10904 status=WriteImage(image_info,print_image); 10905 (void) RelinquishUniqueFileResource(filename); 10906 print_image=DestroyImage(print_image); 10907 image_info=DestroyImageInfo(image_info); 10908 XSetCursorState(display,windows,MagickFalse); 10909 return(status != 0 ? MagickTrue : MagickFalse); 10910} 10911 10912/* 10913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10914% % 10915% % 10916% % 10917+ X R O I I m a g e % 10918% % 10919% % 10920% % 10921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10922% 10923% XROIImage() applies an image processing technique to a region of interest. 10924% 10925% The format of the XROIImage method is: 10926% 10927% MagickBooleanType XROIImage(Display *display, 10928% XResourceInfo *resource_info,XWindows *windows,Image **image) 10929% 10930% A description of each parameter follows: 10931% 10932% o display: Specifies a connection to an X server; returned from 10933% XOpenDisplay. 10934% 10935% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10936% 10937% o windows: Specifies a pointer to a XWindows structure. 10938% 10939% o image: the image; returned from ReadImage. 10940% 10941*/ 10942static MagickBooleanType XROIImage(Display *display, 10943 XResourceInfo *resource_info,XWindows *windows,Image **image) 10944{ 10945#define ApplyMenus 7 10946 10947 static const char 10948 *ROIMenu[] = 10949 { 10950 "Help", 10951 "Dismiss", 10952 (char *) NULL 10953 }, 10954 *ApplyMenu[] = 10955 { 10956 "File", 10957 "Edit", 10958 "Transform", 10959 "Enhance", 10960 "Effects", 10961 "F/X", 10962 "Miscellany", 10963 "Help", 10964 "Dismiss", 10965 (char *) NULL 10966 }, 10967 *FileMenu[] = 10968 { 10969 "Save...", 10970 "Print...", 10971 (char *) NULL 10972 }, 10973 *EditMenu[] = 10974 { 10975 "Undo", 10976 "Redo", 10977 (char *) NULL 10978 }, 10979 *TransformMenu[] = 10980 { 10981 "Flop", 10982 "Flip", 10983 "Rotate Right", 10984 "Rotate Left", 10985 (char *) NULL 10986 }, 10987 *EnhanceMenu[] = 10988 { 10989 "Hue...", 10990 "Saturation...", 10991 "Brightness...", 10992 "Gamma...", 10993 "Spiff", 10994 "Dull", 10995 "Contrast Stretch...", 10996 "Sigmoidal Contrast...", 10997 "Normalize", 10998 "Equalize", 10999 "Negate", 11000 "Grayscale", 11001 "Map...", 11002 "Quantize...", 11003 (char *) NULL 11004 }, 11005 *EffectsMenu[] = 11006 { 11007 "Despeckle", 11008 "Emboss", 11009 "Reduce Noise", 11010 "Add Noise", 11011 "Sharpen...", 11012 "Blur...", 11013 "Threshold...", 11014 "Edge Detect...", 11015 "Spread...", 11016 "Shade...", 11017 "Raise...", 11018 "Segment...", 11019 (char *) NULL 11020 }, 11021 *FXMenu[] = 11022 { 11023 "Solarize...", 11024 "Sepia Tone...", 11025 "Swirl...", 11026 "Implode...", 11027 "Vignette...", 11028 "Wave...", 11029 "Oil Paint...", 11030 "Charcoal Draw...", 11031 (char *) NULL 11032 }, 11033 *MiscellanyMenu[] = 11034 { 11035 "Image Info", 11036 "Zoom Image", 11037 "Show Preview...", 11038 "Show Histogram", 11039 "Show Matte", 11040 (char *) NULL 11041 }; 11042 11043 static const char 11044 **Menus[ApplyMenus] = 11045 { 11046 FileMenu, 11047 EditMenu, 11048 TransformMenu, 11049 EnhanceMenu, 11050 EffectsMenu, 11051 FXMenu, 11052 MiscellanyMenu 11053 }; 11054 11055 static const CommandType 11056 ApplyCommands[] = 11057 { 11058 NullCommand, 11059 NullCommand, 11060 NullCommand, 11061 NullCommand, 11062 NullCommand, 11063 NullCommand, 11064 NullCommand, 11065 HelpCommand, 11066 QuitCommand 11067 }, 11068 FileCommands[] = 11069 { 11070 SaveCommand, 11071 PrintCommand 11072 }, 11073 EditCommands[] = 11074 { 11075 UndoCommand, 11076 RedoCommand 11077 }, 11078 TransformCommands[] = 11079 { 11080 FlopCommand, 11081 FlipCommand, 11082 RotateRightCommand, 11083 RotateLeftCommand 11084 }, 11085 EnhanceCommands[] = 11086 { 11087 HueCommand, 11088 SaturationCommand, 11089 BrightnessCommand, 11090 GammaCommand, 11091 SpiffCommand, 11092 DullCommand, 11093 ContrastStretchCommand, 11094 SigmoidalContrastCommand, 11095 NormalizeCommand, 11096 EqualizeCommand, 11097 NegateCommand, 11098 GrayscaleCommand, 11099 MapCommand, 11100 QuantizeCommand 11101 }, 11102 EffectsCommands[] = 11103 { 11104 DespeckleCommand, 11105 EmbossCommand, 11106 ReduceNoiseCommand, 11107 AddNoiseCommand, 11108 SharpenCommand, 11109 BlurCommand, 11110 EdgeDetectCommand, 11111 SpreadCommand, 11112 ShadeCommand, 11113 RaiseCommand, 11114 SegmentCommand 11115 }, 11116 FXCommands[] = 11117 { 11118 SolarizeCommand, 11119 SepiaToneCommand, 11120 SwirlCommand, 11121 ImplodeCommand, 11122 VignetteCommand, 11123 WaveCommand, 11124 OilPaintCommand, 11125 CharcoalDrawCommand 11126 }, 11127 MiscellanyCommands[] = 11128 { 11129 InfoCommand, 11130 ZoomCommand, 11131 ShowPreviewCommand, 11132 ShowHistogramCommand, 11133 ShowMatteCommand 11134 }, 11135 ROICommands[] = 11136 { 11137 ROIHelpCommand, 11138 ROIDismissCommand 11139 }; 11140 11141 static const CommandType 11142 *Commands[ApplyMenus] = 11143 { 11144 FileCommands, 11145 EditCommands, 11146 TransformCommands, 11147 EnhanceCommands, 11148 EffectsCommands, 11149 FXCommands, 11150 MiscellanyCommands 11151 }; 11152 11153 char 11154 command[MaxTextExtent], 11155 text[MaxTextExtent]; 11156 11157 CommandType 11158 command_type; 11159 11160 Cursor 11161 cursor; 11162 11163 Image 11164 *roi_image; 11165 11166 int 11167 entry, 11168 id, 11169 x, 11170 y; 11171 11172 MagickRealType 11173 scale_factor; 11174 11175 MagickProgressMonitor 11176 progress_monitor; 11177 11178 RectangleInfo 11179 crop_info, 11180 highlight_info, 11181 roi_info; 11182 11183 unsigned int 11184 height, 11185 width; 11186 11187 size_t 11188 state; 11189 11190 XEvent 11191 event; 11192 11193 /* 11194 Map Command widget. 11195 */ 11196 (void) CloneString(&windows->command.name,"ROI"); 11197 windows->command.data=0; 11198 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11199 (void) XMapRaised(display,windows->command.id); 11200 XClientMessage(display,windows->image.id,windows->im_protocols, 11201 windows->im_update_widget,CurrentTime); 11202 /* 11203 Track pointer until button 1 is pressed. 11204 */ 11205 XQueryPosition(display,windows->image.id,&x,&y); 11206 (void) XSelectInput(display,windows->image.id, 11207 windows->image.attributes.event_mask | PointerMotionMask); 11208 roi_info.x=(ssize_t) windows->image.x+x; 11209 roi_info.y=(ssize_t) windows->image.y+y; 11210 roi_info.width=0; 11211 roi_info.height=0; 11212 cursor=XCreateFontCursor(display,XC_fleur); 11213 state=DefaultState; 11214 do 11215 { 11216 if (windows->info.mapped != MagickFalse) 11217 { 11218 /* 11219 Display pointer position. 11220 */ 11221 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11222 (long) roi_info.x,(long) roi_info.y); 11223 XInfoWidget(display,windows,text); 11224 } 11225 /* 11226 Wait for next event. 11227 */ 11228 XScreenEvent(display,windows,&event); 11229 if (event.xany.window == windows->command.id) 11230 { 11231 /* 11232 Select a command from the Command widget. 11233 */ 11234 id=XCommandWidget(display,windows,ROIMenu,&event); 11235 if (id < 0) 11236 continue; 11237 switch (ROICommands[id]) 11238 { 11239 case ROIHelpCommand: 11240 { 11241 XTextViewWidget(display,resource_info,windows,MagickFalse, 11242 "Help Viewer - Region of Interest",ImageROIHelp); 11243 break; 11244 } 11245 case ROIDismissCommand: 11246 { 11247 /* 11248 Prematurely exit. 11249 */ 11250 state|=EscapeState; 11251 state|=ExitState; 11252 break; 11253 } 11254 default: 11255 break; 11256 } 11257 continue; 11258 } 11259 switch (event.type) 11260 { 11261 case ButtonPress: 11262 { 11263 if (event.xbutton.button != Button1) 11264 break; 11265 if (event.xbutton.window != windows->image.id) 11266 break; 11267 /* 11268 Note first corner of region of interest rectangle-- exit loop. 11269 */ 11270 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11271 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11272 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11273 state|=ExitState; 11274 break; 11275 } 11276 case ButtonRelease: 11277 break; 11278 case Expose: 11279 break; 11280 case KeyPress: 11281 { 11282 KeySym 11283 key_symbol; 11284 11285 if (event.xkey.window != windows->image.id) 11286 break; 11287 /* 11288 Respond to a user key press. 11289 */ 11290 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11291 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11292 switch ((int) key_symbol) 11293 { 11294 case XK_Escape: 11295 case XK_F20: 11296 { 11297 /* 11298 Prematurely exit. 11299 */ 11300 state|=EscapeState; 11301 state|=ExitState; 11302 break; 11303 } 11304 case XK_F1: 11305 case XK_Help: 11306 { 11307 XTextViewWidget(display,resource_info,windows,MagickFalse, 11308 "Help Viewer - Region of Interest",ImageROIHelp); 11309 break; 11310 } 11311 default: 11312 { 11313 (void) XBell(display,0); 11314 break; 11315 } 11316 } 11317 break; 11318 } 11319 case MotionNotify: 11320 { 11321 /* 11322 Map and unmap Info widget as text cursor crosses its boundaries. 11323 */ 11324 x=event.xmotion.x; 11325 y=event.xmotion.y; 11326 if (windows->info.mapped != MagickFalse) 11327 { 11328 if ((x < (int) (windows->info.x+windows->info.width)) && 11329 (y < (int) (windows->info.y+windows->info.height))) 11330 (void) XWithdrawWindow(display,windows->info.id, 11331 windows->info.screen); 11332 } 11333 else 11334 if ((x > (int) (windows->info.x+windows->info.width)) || 11335 (y > (int) (windows->info.y+windows->info.height))) 11336 (void) XMapWindow(display,windows->info.id); 11337 roi_info.x=(ssize_t) windows->image.x+x; 11338 roi_info.y=(ssize_t) windows->image.y+y; 11339 break; 11340 } 11341 default: 11342 break; 11343 } 11344 } while ((state & ExitState) == 0); 11345 (void) XSelectInput(display,windows->image.id, 11346 windows->image.attributes.event_mask); 11347 if ((state & EscapeState) != 0) 11348 { 11349 /* 11350 User want to exit without region of interest. 11351 */ 11352 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11353 (void) XFreeCursor(display,cursor); 11354 return(MagickTrue); 11355 } 11356 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11357 do 11358 { 11359 /* 11360 Size rectangle as pointer moves until the mouse button is released. 11361 */ 11362 x=(int) roi_info.x; 11363 y=(int) roi_info.y; 11364 roi_info.width=0; 11365 roi_info.height=0; 11366 state=DefaultState; 11367 do 11368 { 11369 highlight_info=roi_info; 11370 highlight_info.x=roi_info.x-windows->image.x; 11371 highlight_info.y=roi_info.y-windows->image.y; 11372 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11373 { 11374 /* 11375 Display info and draw region of interest rectangle. 11376 */ 11377 if (windows->info.mapped == MagickFalse) 11378 (void) XMapWindow(display,windows->info.id); 11379 (void) FormatLocaleString(text,MaxTextExtent, 11380 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11381 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11382 XInfoWidget(display,windows,text); 11383 XHighlightRectangle(display,windows->image.id, 11384 windows->image.highlight_context,&highlight_info); 11385 } 11386 else 11387 if (windows->info.mapped != MagickFalse) 11388 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11389 /* 11390 Wait for next event. 11391 */ 11392 XScreenEvent(display,windows,&event); 11393 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11394 XHighlightRectangle(display,windows->image.id, 11395 windows->image.highlight_context,&highlight_info); 11396 switch (event.type) 11397 { 11398 case ButtonPress: 11399 { 11400 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11401 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11402 break; 11403 } 11404 case ButtonRelease: 11405 { 11406 /* 11407 User has committed to region of interest rectangle. 11408 */ 11409 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11410 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11411 XSetCursorState(display,windows,MagickFalse); 11412 state|=ExitState; 11413 if (LocaleCompare(windows->command.name,"Apply") == 0) 11414 break; 11415 (void) CloneString(&windows->command.name,"Apply"); 11416 windows->command.data=ApplyMenus; 11417 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11418 break; 11419 } 11420 case Expose: 11421 break; 11422 case MotionNotify: 11423 { 11424 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11425 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11426 } 11427 default: 11428 break; 11429 } 11430 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11431 ((state & ExitState) != 0)) 11432 { 11433 /* 11434 Check boundary conditions. 11435 */ 11436 if (roi_info.x < 0) 11437 roi_info.x=0; 11438 else 11439 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11440 roi_info.x=(ssize_t) windows->image.ximage->width; 11441 if ((int) roi_info.x < x) 11442 roi_info.width=(unsigned int) (x-roi_info.x); 11443 else 11444 { 11445 roi_info.width=(unsigned int) (roi_info.x-x); 11446 roi_info.x=(ssize_t) x; 11447 } 11448 if (roi_info.y < 0) 11449 roi_info.y=0; 11450 else 11451 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11452 roi_info.y=(ssize_t) windows->image.ximage->height; 11453 if ((int) roi_info.y < y) 11454 roi_info.height=(unsigned int) (y-roi_info.y); 11455 else 11456 { 11457 roi_info.height=(unsigned int) (roi_info.y-y); 11458 roi_info.y=(ssize_t) y; 11459 } 11460 } 11461 } while ((state & ExitState) == 0); 11462 /* 11463 Wait for user to grab a corner of the rectangle or press return. 11464 */ 11465 state=DefaultState; 11466 command_type=NullCommand; 11467 (void) XMapWindow(display,windows->info.id); 11468 do 11469 { 11470 if (windows->info.mapped != MagickFalse) 11471 { 11472 /* 11473 Display pointer position. 11474 */ 11475 (void) FormatLocaleString(text,MaxTextExtent, 11476 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11477 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11478 XInfoWidget(display,windows,text); 11479 } 11480 highlight_info=roi_info; 11481 highlight_info.x=roi_info.x-windows->image.x; 11482 highlight_info.y=roi_info.y-windows->image.y; 11483 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11484 { 11485 state|=EscapeState; 11486 state|=ExitState; 11487 break; 11488 } 11489 if ((state & UpdateRegionState) != 0) 11490 { 11491 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11492 switch (command_type) 11493 { 11494 case UndoCommand: 11495 case RedoCommand: 11496 { 11497 (void) XMagickCommand(display,resource_info,windows,command_type, 11498 image); 11499 break; 11500 } 11501 default: 11502 { 11503 /* 11504 Region of interest is relative to image configuration. 11505 */ 11506 progress_monitor=SetImageProgressMonitor(*image, 11507 (MagickProgressMonitor) NULL,(*image)->client_data); 11508 crop_info=roi_info; 11509 width=(unsigned int) (*image)->columns; 11510 height=(unsigned int) (*image)->rows; 11511 x=0; 11512 y=0; 11513 if (windows->image.crop_geometry != (char *) NULL) 11514 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11515 &width,&height); 11516 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11517 crop_info.x+=x; 11518 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11519 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11520 scale_factor=(MagickRealType) 11521 height/windows->image.ximage->height; 11522 crop_info.y+=y; 11523 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11524 crop_info.height=(unsigned int) 11525 (scale_factor*crop_info.height+0.5); 11526 roi_image=CropImage(*image,&crop_info,&(*image)->exception); 11527 (void) SetImageProgressMonitor(*image,progress_monitor, 11528 (*image)->client_data); 11529 if (roi_image == (Image *) NULL) 11530 continue; 11531 /* 11532 Apply image processing technique to the region of interest. 11533 */ 11534 windows->image.orphan=MagickTrue; 11535 (void) XMagickCommand(display,resource_info,windows,command_type, 11536 &roi_image); 11537 progress_monitor=SetImageProgressMonitor(*image, 11538 (MagickProgressMonitor) NULL,(*image)->client_data); 11539 (void) XMagickCommand(display,resource_info,windows, 11540 SaveToUndoBufferCommand,image); 11541 windows->image.orphan=MagickFalse; 11542 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11543 crop_info.x,crop_info.y); 11544 roi_image=DestroyImage(roi_image); 11545 (void) SetImageProgressMonitor(*image,progress_monitor, 11546 (*image)->client_data); 11547 break; 11548 } 11549 } 11550 if (command_type != InfoCommand) 11551 { 11552 XConfigureImageColormap(display,resource_info,windows,*image); 11553 (void) XConfigureImage(display,resource_info,windows,*image); 11554 } 11555 XCheckRefreshWindows(display,windows); 11556 XInfoWidget(display,windows,text); 11557 (void) XSetFunction(display,windows->image.highlight_context, 11558 GXinvert); 11559 state&=(~UpdateRegionState); 11560 } 11561 XHighlightRectangle(display,windows->image.id, 11562 windows->image.highlight_context,&highlight_info); 11563 XScreenEvent(display,windows,&event); 11564 if (event.xany.window == windows->command.id) 11565 { 11566 /* 11567 Select a command from the Command widget. 11568 */ 11569 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11570 command_type=NullCommand; 11571 id=XCommandWidget(display,windows,ApplyMenu,&event); 11572 if (id >= 0) 11573 { 11574 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11575 command_type=ApplyCommands[id]; 11576 if (id < ApplyMenus) 11577 { 11578 /* 11579 Select a command from a pop-up menu. 11580 */ 11581 entry=XMenuWidget(display,windows,ApplyMenu[id], 11582 (const char **) Menus[id],command); 11583 if (entry >= 0) 11584 { 11585 (void) CopyMagickString(command,Menus[id][entry], 11586 MaxTextExtent); 11587 command_type=Commands[id][entry]; 11588 } 11589 } 11590 } 11591 (void) XSetFunction(display,windows->image.highlight_context, 11592 GXinvert); 11593 XHighlightRectangle(display,windows->image.id, 11594 windows->image.highlight_context,&highlight_info); 11595 if (command_type == HelpCommand) 11596 { 11597 (void) XSetFunction(display,windows->image.highlight_context, 11598 GXcopy); 11599 XTextViewWidget(display,resource_info,windows,MagickFalse, 11600 "Help Viewer - Region of Interest",ImageROIHelp); 11601 (void) XSetFunction(display,windows->image.highlight_context, 11602 GXinvert); 11603 continue; 11604 } 11605 if (command_type == QuitCommand) 11606 { 11607 /* 11608 exit. 11609 */ 11610 state|=EscapeState; 11611 state|=ExitState; 11612 continue; 11613 } 11614 if (command_type != NullCommand) 11615 state|=UpdateRegionState; 11616 continue; 11617 } 11618 XHighlightRectangle(display,windows->image.id, 11619 windows->image.highlight_context,&highlight_info); 11620 switch (event.type) 11621 { 11622 case ButtonPress: 11623 { 11624 x=windows->image.x; 11625 y=windows->image.y; 11626 if (event.xbutton.button != Button1) 11627 break; 11628 if (event.xbutton.window != windows->image.id) 11629 break; 11630 x=windows->image.x+event.xbutton.x; 11631 y=windows->image.y+event.xbutton.y; 11632 if ((x < (int) (roi_info.x+RoiDelta)) && 11633 (x > (int) (roi_info.x-RoiDelta)) && 11634 (y < (int) (roi_info.y+RoiDelta)) && 11635 (y > (int) (roi_info.y-RoiDelta))) 11636 { 11637 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11638 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11639 state|=UpdateConfigurationState; 11640 break; 11641 } 11642 if ((x < (int) (roi_info.x+RoiDelta)) && 11643 (x > (int) (roi_info.x-RoiDelta)) && 11644 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11645 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11646 { 11647 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11648 state|=UpdateConfigurationState; 11649 break; 11650 } 11651 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11652 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11653 (y < (int) (roi_info.y+RoiDelta)) && 11654 (y > (int) (roi_info.y-RoiDelta))) 11655 { 11656 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11657 state|=UpdateConfigurationState; 11658 break; 11659 } 11660 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11661 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11662 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11663 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11664 { 11665 state|=UpdateConfigurationState; 11666 break; 11667 } 11668 } 11669 case ButtonRelease: 11670 { 11671 if (event.xbutton.window == windows->pan.id) 11672 if ((highlight_info.x != crop_info.x-windows->image.x) || 11673 (highlight_info.y != crop_info.y-windows->image.y)) 11674 XHighlightRectangle(display,windows->image.id, 11675 windows->image.highlight_context,&highlight_info); 11676 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11677 event.xbutton.time); 11678 break; 11679 } 11680 case Expose: 11681 { 11682 if (event.xexpose.window == windows->image.id) 11683 if (event.xexpose.count == 0) 11684 { 11685 event.xexpose.x=(int) highlight_info.x; 11686 event.xexpose.y=(int) highlight_info.y; 11687 event.xexpose.width=(int) highlight_info.width; 11688 event.xexpose.height=(int) highlight_info.height; 11689 XRefreshWindow(display,&windows->image,&event); 11690 } 11691 if (event.xexpose.window == windows->info.id) 11692 if (event.xexpose.count == 0) 11693 XInfoWidget(display,windows,text); 11694 break; 11695 } 11696 case KeyPress: 11697 { 11698 KeySym 11699 key_symbol; 11700 11701 if (event.xkey.window != windows->image.id) 11702 break; 11703 /* 11704 Respond to a user key press. 11705 */ 11706 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11707 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11708 switch ((int) key_symbol) 11709 { 11710 case XK_Shift_L: 11711 case XK_Shift_R: 11712 break; 11713 case XK_Escape: 11714 case XK_F20: 11715 state|=EscapeState; 11716 case XK_Return: 11717 { 11718 state|=ExitState; 11719 break; 11720 } 11721 case XK_Home: 11722 case XK_KP_Home: 11723 { 11724 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11725 roi_info.y=(ssize_t) (windows->image.height/2L- 11726 roi_info.height/2L); 11727 break; 11728 } 11729 case XK_Left: 11730 case XK_KP_Left: 11731 { 11732 roi_info.x--; 11733 break; 11734 } 11735 case XK_Up: 11736 case XK_KP_Up: 11737 case XK_Next: 11738 { 11739 roi_info.y--; 11740 break; 11741 } 11742 case XK_Right: 11743 case XK_KP_Right: 11744 { 11745 roi_info.x++; 11746 break; 11747 } 11748 case XK_Prior: 11749 case XK_Down: 11750 case XK_KP_Down: 11751 { 11752 roi_info.y++; 11753 break; 11754 } 11755 case XK_F1: 11756 case XK_Help: 11757 { 11758 (void) XSetFunction(display,windows->image.highlight_context, 11759 GXcopy); 11760 XTextViewWidget(display,resource_info,windows,MagickFalse, 11761 "Help Viewer - Region of Interest",ImageROIHelp); 11762 (void) XSetFunction(display,windows->image.highlight_context, 11763 GXinvert); 11764 break; 11765 } 11766 default: 11767 { 11768 command_type=XImageWindowCommand(display,resource_info,windows, 11769 event.xkey.state,key_symbol,image); 11770 if (command_type != NullCommand) 11771 state|=UpdateRegionState; 11772 break; 11773 } 11774 } 11775 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11776 event.xkey.time); 11777 break; 11778 } 11779 case KeyRelease: 11780 break; 11781 case MotionNotify: 11782 { 11783 if (event.xbutton.window != windows->image.id) 11784 break; 11785 /* 11786 Map and unmap Info widget as text cursor crosses its boundaries. 11787 */ 11788 x=event.xmotion.x; 11789 y=event.xmotion.y; 11790 if (windows->info.mapped != MagickFalse) 11791 { 11792 if ((x < (int) (windows->info.x+windows->info.width)) && 11793 (y < (int) (windows->info.y+windows->info.height))) 11794 (void) XWithdrawWindow(display,windows->info.id, 11795 windows->info.screen); 11796 } 11797 else 11798 if ((x > (int) (windows->info.x+windows->info.width)) || 11799 (y > (int) (windows->info.y+windows->info.height))) 11800 (void) XMapWindow(display,windows->info.id); 11801 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11802 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11803 break; 11804 } 11805 case SelectionRequest: 11806 { 11807 XSelectionEvent 11808 notify; 11809 11810 XSelectionRequestEvent 11811 *request; 11812 11813 /* 11814 Set primary selection. 11815 */ 11816 (void) FormatLocaleString(text,MaxTextExtent, 11817 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11818 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11819 request=(&(event.xselectionrequest)); 11820 (void) XChangeProperty(request->display,request->requestor, 11821 request->property,request->target,8,PropModeReplace, 11822 (unsigned char *) text,(int) strlen(text)); 11823 notify.type=SelectionNotify; 11824 notify.display=request->display; 11825 notify.requestor=request->requestor; 11826 notify.selection=request->selection; 11827 notify.target=request->target; 11828 notify.time=request->time; 11829 if (request->property == None) 11830 notify.property=request->target; 11831 else 11832 notify.property=request->property; 11833 (void) XSendEvent(request->display,request->requestor,False,0, 11834 (XEvent *) ¬ify); 11835 } 11836 default: 11837 break; 11838 } 11839 if ((state & UpdateConfigurationState) != 0) 11840 { 11841 (void) XPutBackEvent(display,&event); 11842 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11843 break; 11844 } 11845 } while ((state & ExitState) == 0); 11846 } while ((state & ExitState) == 0); 11847 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11848 XSetCursorState(display,windows,MagickFalse); 11849 if ((state & EscapeState) != 0) 11850 return(MagickTrue); 11851 return(MagickTrue); 11852} 11853 11854/* 11855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11856% % 11857% % 11858% % 11859+ X R o t a t e I m a g e % 11860% % 11861% % 11862% % 11863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11864% 11865% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11866% rotation angle is computed from the slope of a line drawn by the user. 11867% 11868% The format of the XRotateImage method is: 11869% 11870% MagickBooleanType XRotateImage(Display *display, 11871% XResourceInfo *resource_info,XWindows *windows,double degrees, 11872% Image **image) 11873% 11874% A description of each parameter follows: 11875% 11876% o display: Specifies a connection to an X server; returned from 11877% XOpenDisplay. 11878% 11879% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11880% 11881% o windows: Specifies a pointer to a XWindows structure. 11882% 11883% o degrees: Specifies the number of degrees to rotate the image. 11884% 11885% o image: the image. 11886% 11887*/ 11888static MagickBooleanType XRotateImage(Display *display, 11889 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image) 11890{ 11891 static const char 11892 *RotateMenu[] = 11893 { 11894 "Pixel Color", 11895 "Direction", 11896 "Help", 11897 "Dismiss", 11898 (char *) NULL 11899 }; 11900 11901 static ModeType 11902 direction = HorizontalRotateCommand; 11903 11904 static const ModeType 11905 DirectionCommands[] = 11906 { 11907 HorizontalRotateCommand, 11908 VerticalRotateCommand 11909 }, 11910 RotateCommands[] = 11911 { 11912 RotateColorCommand, 11913 RotateDirectionCommand, 11914 RotateHelpCommand, 11915 RotateDismissCommand 11916 }; 11917 11918 static unsigned int 11919 pen_id = 0; 11920 11921 char 11922 command[MaxTextExtent], 11923 text[MaxTextExtent]; 11924 11925 Image 11926 *rotate_image; 11927 11928 int 11929 id, 11930 x, 11931 y; 11932 11933 MagickRealType 11934 normalized_degrees; 11935 11936 register int 11937 i; 11938 11939 unsigned int 11940 height, 11941 rotations, 11942 width; 11943 11944 if (degrees == 0.0) 11945 { 11946 unsigned int 11947 distance; 11948 11949 size_t 11950 state; 11951 11952 XEvent 11953 event; 11954 11955 XSegment 11956 rotate_info; 11957 11958 /* 11959 Map Command widget. 11960 */ 11961 (void) CloneString(&windows->command.name,"Rotate"); 11962 windows->command.data=2; 11963 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 11964 (void) XMapRaised(display,windows->command.id); 11965 XClientMessage(display,windows->image.id,windows->im_protocols, 11966 windows->im_update_widget,CurrentTime); 11967 /* 11968 Wait for first button press. 11969 */ 11970 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11971 XQueryPosition(display,windows->image.id,&x,&y); 11972 rotate_info.x1=x; 11973 rotate_info.y1=y; 11974 rotate_info.x2=x; 11975 rotate_info.y2=y; 11976 state=DefaultState; 11977 do 11978 { 11979 XHighlightLine(display,windows->image.id, 11980 windows->image.highlight_context,&rotate_info); 11981 /* 11982 Wait for next event. 11983 */ 11984 XScreenEvent(display,windows,&event); 11985 XHighlightLine(display,windows->image.id, 11986 windows->image.highlight_context,&rotate_info); 11987 if (event.xany.window == windows->command.id) 11988 { 11989 /* 11990 Select a command from the Command widget. 11991 */ 11992 id=XCommandWidget(display,windows,RotateMenu,&event); 11993 if (id < 0) 11994 continue; 11995 (void) XSetFunction(display,windows->image.highlight_context, 11996 GXcopy); 11997 switch (RotateCommands[id]) 11998 { 11999 case RotateColorCommand: 12000 { 12001 const char 12002 *ColorMenu[MaxNumberPens]; 12003 12004 int 12005 pen_number; 12006 12007 XColor 12008 color; 12009 12010 /* 12011 Initialize menu selections. 12012 */ 12013 for (i=0; i < (int) (MaxNumberPens-2); i++) 12014 ColorMenu[i]=resource_info->pen_colors[i]; 12015 ColorMenu[MaxNumberPens-2]="Browser..."; 12016 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12017 /* 12018 Select a pen color from the pop-up menu. 12019 */ 12020 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12021 (const char **) ColorMenu,command); 12022 if (pen_number < 0) 12023 break; 12024 if (pen_number == (MaxNumberPens-2)) 12025 { 12026 static char 12027 color_name[MaxTextExtent] = "gray"; 12028 12029 /* 12030 Select a pen color from a dialog. 12031 */ 12032 resource_info->pen_colors[pen_number]=color_name; 12033 XColorBrowserWidget(display,windows,"Select",color_name); 12034 if (*color_name == '\0') 12035 break; 12036 } 12037 /* 12038 Set pen color. 12039 */ 12040 (void) XParseColor(display,windows->map_info->colormap, 12041 resource_info->pen_colors[pen_number],&color); 12042 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12043 (unsigned int) MaxColors,&color); 12044 windows->pixel_info->pen_colors[pen_number]=color; 12045 pen_id=(unsigned int) pen_number; 12046 break; 12047 } 12048 case RotateDirectionCommand: 12049 { 12050 static const char 12051 *Directions[] = 12052 { 12053 "horizontal", 12054 "vertical", 12055 (char *) NULL, 12056 }; 12057 12058 /* 12059 Select a command from the pop-up menu. 12060 */ 12061 id=XMenuWidget(display,windows,RotateMenu[id], 12062 Directions,command); 12063 if (id >= 0) 12064 direction=DirectionCommands[id]; 12065 break; 12066 } 12067 case RotateHelpCommand: 12068 { 12069 XTextViewWidget(display,resource_info,windows,MagickFalse, 12070 "Help Viewer - Image Rotation",ImageRotateHelp); 12071 break; 12072 } 12073 case RotateDismissCommand: 12074 { 12075 /* 12076 Prematurely exit. 12077 */ 12078 state|=EscapeState; 12079 state|=ExitState; 12080 break; 12081 } 12082 default: 12083 break; 12084 } 12085 (void) XSetFunction(display,windows->image.highlight_context, 12086 GXinvert); 12087 continue; 12088 } 12089 switch (event.type) 12090 { 12091 case ButtonPress: 12092 { 12093 if (event.xbutton.button != Button1) 12094 break; 12095 if (event.xbutton.window != windows->image.id) 12096 break; 12097 /* 12098 exit loop. 12099 */ 12100 (void) XSetFunction(display,windows->image.highlight_context, 12101 GXcopy); 12102 rotate_info.x1=event.xbutton.x; 12103 rotate_info.y1=event.xbutton.y; 12104 state|=ExitState; 12105 break; 12106 } 12107 case ButtonRelease: 12108 break; 12109 case Expose: 12110 break; 12111 case KeyPress: 12112 { 12113 char 12114 command[MaxTextExtent]; 12115 12116 KeySym 12117 key_symbol; 12118 12119 if (event.xkey.window != windows->image.id) 12120 break; 12121 /* 12122 Respond to a user key press. 12123 */ 12124 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12125 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12126 switch ((int) key_symbol) 12127 { 12128 case XK_Escape: 12129 case XK_F20: 12130 { 12131 /* 12132 Prematurely exit. 12133 */ 12134 state|=EscapeState; 12135 state|=ExitState; 12136 break; 12137 } 12138 case XK_F1: 12139 case XK_Help: 12140 { 12141 (void) XSetFunction(display,windows->image.highlight_context, 12142 GXcopy); 12143 XTextViewWidget(display,resource_info,windows,MagickFalse, 12144 "Help Viewer - Image Rotation",ImageRotateHelp); 12145 (void) XSetFunction(display,windows->image.highlight_context, 12146 GXinvert); 12147 break; 12148 } 12149 default: 12150 { 12151 (void) XBell(display,0); 12152 break; 12153 } 12154 } 12155 break; 12156 } 12157 case MotionNotify: 12158 { 12159 rotate_info.x1=event.xmotion.x; 12160 rotate_info.y1=event.xmotion.y; 12161 } 12162 } 12163 rotate_info.x2=rotate_info.x1; 12164 rotate_info.y2=rotate_info.y1; 12165 if (direction == HorizontalRotateCommand) 12166 rotate_info.x2+=32; 12167 else 12168 rotate_info.y2-=32; 12169 } while ((state & ExitState) == 0); 12170 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12171 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12172 if ((state & EscapeState) != 0) 12173 return(MagickTrue); 12174 /* 12175 Draw line as pointer moves until the mouse button is released. 12176 */ 12177 distance=0; 12178 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12179 state=DefaultState; 12180 do 12181 { 12182 if (distance > 9) 12183 { 12184 /* 12185 Display info and draw rotation line. 12186 */ 12187 if (windows->info.mapped == MagickFalse) 12188 (void) XMapWindow(display,windows->info.id); 12189 (void) FormatLocaleString(text,MaxTextExtent," %g", 12190 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12191 XInfoWidget(display,windows,text); 12192 XHighlightLine(display,windows->image.id, 12193 windows->image.highlight_context,&rotate_info); 12194 } 12195 else 12196 if (windows->info.mapped != MagickFalse) 12197 (void) XWithdrawWindow(display,windows->info.id, 12198 windows->info.screen); 12199 /* 12200 Wait for next event. 12201 */ 12202 XScreenEvent(display,windows,&event); 12203 if (distance > 9) 12204 XHighlightLine(display,windows->image.id, 12205 windows->image.highlight_context,&rotate_info); 12206 switch (event.type) 12207 { 12208 case ButtonPress: 12209 break; 12210 case ButtonRelease: 12211 { 12212 /* 12213 User has committed to rotation line. 12214 */ 12215 rotate_info.x2=event.xbutton.x; 12216 rotate_info.y2=event.xbutton.y; 12217 state|=ExitState; 12218 break; 12219 } 12220 case Expose: 12221 break; 12222 case MotionNotify: 12223 { 12224 rotate_info.x2=event.xmotion.x; 12225 rotate_info.y2=event.xmotion.y; 12226 } 12227 default: 12228 break; 12229 } 12230 /* 12231 Check boundary conditions. 12232 */ 12233 if (rotate_info.x2 < 0) 12234 rotate_info.x2=0; 12235 else 12236 if (rotate_info.x2 > (int) windows->image.width) 12237 rotate_info.x2=(short) windows->image.width; 12238 if (rotate_info.y2 < 0) 12239 rotate_info.y2=0; 12240 else 12241 if (rotate_info.y2 > (int) windows->image.height) 12242 rotate_info.y2=(short) windows->image.height; 12243 /* 12244 Compute rotation angle from the slope of the line. 12245 */ 12246 degrees=0.0; 12247 distance=(unsigned int) 12248 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12249 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12250 if (distance > 9) 12251 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12252 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12253 } while ((state & ExitState) == 0); 12254 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12255 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12256 if (distance <= 9) 12257 return(MagickTrue); 12258 } 12259 if (direction == VerticalRotateCommand) 12260 degrees-=90.0; 12261 if (degrees == 0.0) 12262 return(MagickTrue); 12263 /* 12264 Rotate image. 12265 */ 12266 normalized_degrees=degrees; 12267 while (normalized_degrees < -45.0) 12268 normalized_degrees+=360.0; 12269 for (rotations=0; normalized_degrees > 45.0; rotations++) 12270 normalized_degrees-=90.0; 12271 if (normalized_degrees != 0.0) 12272 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image); 12273 XSetCursorState(display,windows,MagickTrue); 12274 XCheckRefreshWindows(display,windows); 12275 (*image)->background_color.red=ScaleShortToQuantum( 12276 windows->pixel_info->pen_colors[pen_id].red); 12277 (*image)->background_color.green=ScaleShortToQuantum( 12278 windows->pixel_info->pen_colors[pen_id].green); 12279 (*image)->background_color.blue=ScaleShortToQuantum( 12280 windows->pixel_info->pen_colors[pen_id].blue); 12281 rotate_image=RotateImage(*image,degrees,&(*image)->exception); 12282 XSetCursorState(display,windows,MagickFalse); 12283 if (rotate_image == (Image *) NULL) 12284 return(MagickFalse); 12285 *image=DestroyImage(*image); 12286 *image=rotate_image; 12287 if (windows->image.crop_geometry != (char *) NULL) 12288 { 12289 /* 12290 Rotate crop geometry. 12291 */ 12292 width=(unsigned int) (*image)->columns; 12293 height=(unsigned int) (*image)->rows; 12294 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12295 switch (rotations % 4) 12296 { 12297 default: 12298 case 0: 12299 break; 12300 case 1: 12301 { 12302 /* 12303 Rotate 90 degrees. 12304 */ 12305 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12306 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12307 (int) height-y,x); 12308 break; 12309 } 12310 case 2: 12311 { 12312 /* 12313 Rotate 180 degrees. 12314 */ 12315 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12316 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12317 break; 12318 } 12319 case 3: 12320 { 12321 /* 12322 Rotate 270 degrees. 12323 */ 12324 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12325 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12326 break; 12327 } 12328 } 12329 } 12330 if (windows->image.orphan != MagickFalse) 12331 return(MagickTrue); 12332 if (normalized_degrees != 0.0) 12333 { 12334 /* 12335 Update image colormap. 12336 */ 12337 windows->image.window_changes.width=(int) (*image)->columns; 12338 windows->image.window_changes.height=(int) (*image)->rows; 12339 if (windows->image.crop_geometry != (char *) NULL) 12340 { 12341 /* 12342 Obtain dimensions of image from crop geometry. 12343 */ 12344 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12345 &width,&height); 12346 windows->image.window_changes.width=(int) width; 12347 windows->image.window_changes.height=(int) height; 12348 } 12349 XConfigureImageColormap(display,resource_info,windows,*image); 12350 } 12351 else 12352 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12353 { 12354 windows->image.window_changes.width=windows->image.ximage->height; 12355 windows->image.window_changes.height=windows->image.ximage->width; 12356 } 12357 /* 12358 Update image configuration. 12359 */ 12360 (void) XConfigureImage(display,resource_info,windows,*image); 12361 return(MagickTrue); 12362} 12363 12364/* 12365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12366% % 12367% % 12368% % 12369+ X S a v e I m a g e % 12370% % 12371% % 12372% % 12373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12374% 12375% XSaveImage() saves an image to a file. 12376% 12377% The format of the XSaveImage method is: 12378% 12379% MagickBooleanType XSaveImage(Display *display, 12380% XResourceInfo *resource_info,XWindows *windows,Image *image) 12381% 12382% A description of each parameter follows: 12383% 12384% o display: Specifies a connection to an X server; returned from 12385% XOpenDisplay. 12386% 12387% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12388% 12389% o windows: Specifies a pointer to a XWindows structure. 12390% 12391% o image: the image. 12392% 12393*/ 12394static MagickBooleanType XSaveImage(Display *display, 12395 XResourceInfo *resource_info,XWindows *windows,Image *image) 12396{ 12397 char 12398 filename[MaxTextExtent], 12399 geometry[MaxTextExtent]; 12400 12401 Image 12402 *save_image; 12403 12404 ImageInfo 12405 *image_info; 12406 12407 MagickStatusType 12408 status; 12409 12410 /* 12411 Request file name from user. 12412 */ 12413 if (resource_info->write_filename != (char *) NULL) 12414 (void) CopyMagickString(filename,resource_info->write_filename, 12415 MaxTextExtent); 12416 else 12417 { 12418 char 12419 path[MaxTextExtent]; 12420 12421 int 12422 status; 12423 12424 GetPathComponent(image->filename,HeadPath,path); 12425 GetPathComponent(image->filename,TailPath,filename); 12426 status=chdir(path); 12427 if (status == -1) 12428 (void) ThrowMagickException(&image->exception,GetMagickModule(), 12429 FileOpenError,"UnableToOpenFile","%s",path); 12430 } 12431 XFileBrowserWidget(display,windows,"Save",filename); 12432 if (*filename == '\0') 12433 return(MagickTrue); 12434 if (IsPathAccessible(filename) != MagickFalse) 12435 { 12436 int 12437 status; 12438 12439 /* 12440 File exists-- seek user's permission before overwriting. 12441 */ 12442 status=XConfirmWidget(display,windows,"Overwrite",filename); 12443 if (status <= 0) 12444 return(MagickTrue); 12445 } 12446 image_info=CloneImageInfo(resource_info->image_info); 12447 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12448 (void) SetImageInfo(image_info,1,&image->exception); 12449 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12450 (LocaleCompare(image_info->magick,"JPG") == 0)) 12451 { 12452 char 12453 quality[MaxTextExtent]; 12454 12455 int 12456 status; 12457 12458 /* 12459 Request JPEG quality from user. 12460 */ 12461 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12462 image->quality); 12463 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12464 quality); 12465 if (*quality == '\0') 12466 return(MagickTrue); 12467 image->quality=StringToUnsignedLong(quality); 12468 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12469 } 12470 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12471 (LocaleCompare(image_info->magick,"PDF") == 0) || 12472 (LocaleCompare(image_info->magick,"PS") == 0) || 12473 (LocaleCompare(image_info->magick,"PS2") == 0)) 12474 { 12475 char 12476 geometry[MaxTextExtent]; 12477 12478 /* 12479 Request page geometry from user. 12480 */ 12481 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12482 if (LocaleCompare(image_info->magick,"PDF") == 0) 12483 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12484 if (image_info->page != (char *) NULL) 12485 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12486 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12487 "Select page geometry:",geometry); 12488 if (*geometry != '\0') 12489 image_info->page=GetPageGeometry(geometry); 12490 } 12491 /* 12492 Apply image transforms. 12493 */ 12494 XSetCursorState(display,windows,MagickTrue); 12495 XCheckRefreshWindows(display,windows); 12496 save_image=CloneImage(image,0,0,MagickTrue,&image->exception); 12497 if (save_image == (Image *) NULL) 12498 return(MagickFalse); 12499 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12500 windows->image.ximage->width,windows->image.ximage->height); 12501 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry); 12502 /* 12503 Write image. 12504 */ 12505 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12506 status=WriteImage(image_info,save_image); 12507 if (status != MagickFalse) 12508 image->taint=MagickFalse; 12509 save_image=DestroyImage(save_image); 12510 image_info=DestroyImageInfo(image_info); 12511 XSetCursorState(display,windows,MagickFalse); 12512 return(status != 0 ? MagickTrue : MagickFalse); 12513} 12514 12515/* 12516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12517% % 12518% % 12519% % 12520+ X S c r e e n E v e n t % 12521% % 12522% % 12523% % 12524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12525% 12526% XScreenEvent() handles global events associated with the Pan and Magnify 12527% windows. 12528% 12529% The format of the XScreenEvent function is: 12530% 12531% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12532% 12533% A description of each parameter follows: 12534% 12535% o display: Specifies a pointer to the Display structure; returned from 12536% XOpenDisplay. 12537% 12538% o windows: Specifies a pointer to a XWindows structure. 12539% 12540% o event: Specifies a pointer to a X11 XEvent structure. 12541% 12542% 12543*/ 12544 12545#if defined(__cplusplus) || defined(c_plusplus) 12546extern "C" { 12547#endif 12548 12549static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12550{ 12551 register XWindows 12552 *windows; 12553 12554 windows=(XWindows *) data; 12555 if ((event->type == ClientMessage) && 12556 (event->xclient.window == windows->image.id)) 12557 return(MagickFalse); 12558 return(MagickTrue); 12559} 12560 12561#if defined(__cplusplus) || defined(c_plusplus) 12562} 12563#endif 12564 12565static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12566{ 12567 register int 12568 x, 12569 y; 12570 12571 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12572 if (event->xany.window == windows->command.id) 12573 return; 12574 switch (event->type) 12575 { 12576 case ButtonPress: 12577 case ButtonRelease: 12578 { 12579 if ((event->xbutton.button == Button3) && 12580 (event->xbutton.state & Mod1Mask)) 12581 { 12582 /* 12583 Convert Alt-Button3 to Button2. 12584 */ 12585 event->xbutton.button=Button2; 12586 event->xbutton.state&=(~Mod1Mask); 12587 } 12588 if (event->xbutton.window == windows->backdrop.id) 12589 { 12590 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12591 event->xbutton.time); 12592 break; 12593 } 12594 if (event->xbutton.window == windows->pan.id) 12595 { 12596 XPanImage(display,windows,event); 12597 break; 12598 } 12599 if (event->xbutton.window == windows->image.id) 12600 if (event->xbutton.button == Button2) 12601 { 12602 /* 12603 Update magnified image. 12604 */ 12605 x=event->xbutton.x; 12606 y=event->xbutton.y; 12607 if (x < 0) 12608 x=0; 12609 else 12610 if (x >= (int) windows->image.width) 12611 x=(int) (windows->image.width-1); 12612 windows->magnify.x=(int) windows->image.x+x; 12613 if (y < 0) 12614 y=0; 12615 else 12616 if (y >= (int) windows->image.height) 12617 y=(int) (windows->image.height-1); 12618 windows->magnify.y=windows->image.y+y; 12619 if (windows->magnify.mapped == MagickFalse) 12620 (void) XMapRaised(display,windows->magnify.id); 12621 XMakeMagnifyImage(display,windows); 12622 if (event->type == ButtonRelease) 12623 (void) XWithdrawWindow(display,windows->info.id, 12624 windows->info.screen); 12625 break; 12626 } 12627 break; 12628 } 12629 case ClientMessage: 12630 { 12631 /* 12632 If client window delete message, exit. 12633 */ 12634 if (event->xclient.message_type != windows->wm_protocols) 12635 break; 12636 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12637 break; 12638 if (event->xclient.window == windows->magnify.id) 12639 { 12640 (void) XWithdrawWindow(display,windows->magnify.id, 12641 windows->magnify.screen); 12642 break; 12643 } 12644 break; 12645 } 12646 case ConfigureNotify: 12647 { 12648 if (event->xconfigure.window == windows->magnify.id) 12649 { 12650 unsigned int 12651 magnify; 12652 12653 /* 12654 Magnify window has a new configuration. 12655 */ 12656 windows->magnify.width=(unsigned int) event->xconfigure.width; 12657 windows->magnify.height=(unsigned int) event->xconfigure.height; 12658 if (windows->magnify.mapped == MagickFalse) 12659 break; 12660 magnify=1; 12661 while ((int) magnify <= event->xconfigure.width) 12662 magnify<<=1; 12663 while ((int) magnify <= event->xconfigure.height) 12664 magnify<<=1; 12665 magnify>>=1; 12666 if (((int) magnify != event->xconfigure.width) || 12667 ((int) magnify != event->xconfigure.height)) 12668 { 12669 XWindowChanges 12670 window_changes; 12671 12672 window_changes.width=(int) magnify; 12673 window_changes.height=(int) magnify; 12674 (void) XReconfigureWMWindow(display,windows->magnify.id, 12675 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12676 &window_changes); 12677 break; 12678 } 12679 XMakeMagnifyImage(display,windows); 12680 break; 12681 } 12682 break; 12683 } 12684 case Expose: 12685 { 12686 if (event->xexpose.window == windows->image.id) 12687 { 12688 XRefreshWindow(display,&windows->image,event); 12689 break; 12690 } 12691 if (event->xexpose.window == windows->pan.id) 12692 if (event->xexpose.count == 0) 12693 { 12694 XDrawPanRectangle(display,windows); 12695 break; 12696 } 12697 if (event->xexpose.window == windows->magnify.id) 12698 if (event->xexpose.count == 0) 12699 { 12700 XMakeMagnifyImage(display,windows); 12701 break; 12702 } 12703 break; 12704 } 12705 case KeyPress: 12706 { 12707 char 12708 command[MaxTextExtent]; 12709 12710 KeySym 12711 key_symbol; 12712 12713 if (event->xkey.window != windows->magnify.id) 12714 break; 12715 /* 12716 Respond to a user key press. 12717 */ 12718 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12719 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12720 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12721 break; 12722 } 12723 case MapNotify: 12724 { 12725 if (event->xmap.window == windows->magnify.id) 12726 { 12727 windows->magnify.mapped=MagickTrue; 12728 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12729 break; 12730 } 12731 if (event->xmap.window == windows->info.id) 12732 { 12733 windows->info.mapped=MagickTrue; 12734 break; 12735 } 12736 break; 12737 } 12738 case MotionNotify: 12739 { 12740 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12741 if (event->xmotion.window == windows->image.id) 12742 if (windows->magnify.mapped != MagickFalse) 12743 { 12744 /* 12745 Update magnified image. 12746 */ 12747 x=event->xmotion.x; 12748 y=event->xmotion.y; 12749 if (x < 0) 12750 x=0; 12751 else 12752 if (x >= (int) windows->image.width) 12753 x=(int) (windows->image.width-1); 12754 windows->magnify.x=(int) windows->image.x+x; 12755 if (y < 0) 12756 y=0; 12757 else 12758 if (y >= (int) windows->image.height) 12759 y=(int) (windows->image.height-1); 12760 windows->magnify.y=windows->image.y+y; 12761 XMakeMagnifyImage(display,windows); 12762 } 12763 break; 12764 } 12765 case UnmapNotify: 12766 { 12767 if (event->xunmap.window == windows->magnify.id) 12768 { 12769 windows->magnify.mapped=MagickFalse; 12770 break; 12771 } 12772 if (event->xunmap.window == windows->info.id) 12773 { 12774 windows->info.mapped=MagickFalse; 12775 break; 12776 } 12777 break; 12778 } 12779 default: 12780 break; 12781 } 12782} 12783 12784/* 12785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12786% % 12787% % 12788% % 12789+ X S e t C r o p G e o m e t r y % 12790% % 12791% % 12792% % 12793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12794% 12795% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12796% and translates it to a cropping geometry relative to the image. 12797% 12798% The format of the XSetCropGeometry method is: 12799% 12800% void XSetCropGeometry(Display *display,XWindows *windows, 12801% RectangleInfo *crop_info,Image *image) 12802% 12803% A description of each parameter follows: 12804% 12805% o display: Specifies a connection to an X server; returned from 12806% XOpenDisplay. 12807% 12808% o windows: Specifies a pointer to a XWindows structure. 12809% 12810% o crop_info: A pointer to a RectangleInfo that defines a region of the 12811% Image window to crop. 12812% 12813% o image: the image. 12814% 12815*/ 12816static void XSetCropGeometry(Display *display,XWindows *windows, 12817 RectangleInfo *crop_info,Image *image) 12818{ 12819 char 12820 text[MaxTextExtent]; 12821 12822 int 12823 x, 12824 y; 12825 12826 MagickRealType 12827 scale_factor; 12828 12829 unsigned int 12830 height, 12831 width; 12832 12833 if (windows->info.mapped != MagickFalse) 12834 { 12835 /* 12836 Display info on cropping rectangle. 12837 */ 12838 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12839 (double) crop_info->width,(double) crop_info->height,(double) 12840 crop_info->x,(double) crop_info->y); 12841 XInfoWidget(display,windows,text); 12842 } 12843 /* 12844 Cropping geometry is relative to any previous crop geometry. 12845 */ 12846 x=0; 12847 y=0; 12848 width=(unsigned int) image->columns; 12849 height=(unsigned int) image->rows; 12850 if (windows->image.crop_geometry != (char *) NULL) 12851 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12852 else 12853 windows->image.crop_geometry=AcquireString((char *) NULL); 12854 /* 12855 Define the crop geometry string from the cropping rectangle. 12856 */ 12857 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12858 if (crop_info->x > 0) 12859 x+=(int) (scale_factor*crop_info->x+0.5); 12860 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12861 if (width == 0) 12862 width=1; 12863 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12864 if (crop_info->y > 0) 12865 y+=(int) (scale_factor*crop_info->y+0.5); 12866 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12867 if (height == 0) 12868 height=1; 12869 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12870 "%ux%u%+d%+d",width,height,x,y); 12871} 12872 12873/* 12874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12875% % 12876% % 12877% % 12878+ X T i l e I m a g e % 12879% % 12880% % 12881% % 12882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12883% 12884% XTileImage() loads or deletes a selected tile from a visual image directory. 12885% The load or delete command is chosen from a menu. 12886% 12887% The format of the XTileImage method is: 12888% 12889% Image *XTileImage(Display *display,XResourceInfo *resource_info, 12890% XWindows *windows,Image *image,XEvent *event) 12891% 12892% A description of each parameter follows: 12893% 12894% o tile_image: XTileImage reads or deletes the tile image 12895% and returns it. A null image is returned if an error occurs. 12896% 12897% o display: Specifies a connection to an X server; returned from 12898% XOpenDisplay. 12899% 12900% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12901% 12902% o windows: Specifies a pointer to a XWindows structure. 12903% 12904% o image: the image; returned from ReadImage. 12905% 12906% o event: Specifies a pointer to a XEvent structure. If it is NULL, 12907% the entire image is refreshed. 12908% 12909*/ 12910static Image *XTileImage(Display *display,XResourceInfo *resource_info, 12911 XWindows *windows,Image *image,XEvent *event) 12912{ 12913 static const char 12914 *VerbMenu[] = 12915 { 12916 "Load", 12917 "Next", 12918 "Former", 12919 "Delete", 12920 "Update", 12921 (char *) NULL, 12922 }; 12923 12924 static const ModeType 12925 TileCommands[] = 12926 { 12927 TileLoadCommand, 12928 TileNextCommand, 12929 TileFormerCommand, 12930 TileDeleteCommand, 12931 TileUpdateCommand 12932 }; 12933 12934 char 12935 command[MaxTextExtent], 12936 filename[MaxTextExtent]; 12937 12938 Image 12939 *tile_image; 12940 12941 int 12942 id, 12943 status, 12944 tile, 12945 x, 12946 y; 12947 12948 MagickRealType 12949 scale_factor; 12950 12951 register char 12952 *p, 12953 *q; 12954 12955 register int 12956 i; 12957 12958 unsigned int 12959 height, 12960 width; 12961 12962 /* 12963 Tile image is relative to montage image configuration. 12964 */ 12965 x=0; 12966 y=0; 12967 width=(unsigned int) image->columns; 12968 height=(unsigned int) image->rows; 12969 if (windows->image.crop_geometry != (char *) NULL) 12970 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12971 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12972 event->xbutton.x+=windows->image.x; 12973 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 12974 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12975 event->xbutton.y+=windows->image.y; 12976 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 12977 /* 12978 Determine size and location of each tile in the visual image directory. 12979 */ 12980 width=(unsigned int) image->columns; 12981 height=(unsigned int) image->rows; 12982 x=0; 12983 y=0; 12984 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 12985 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 12986 (event->xbutton.x-x)/width; 12987 if (tile < 0) 12988 { 12989 /* 12990 Button press is outside any tile. 12991 */ 12992 (void) XBell(display,0); 12993 return((Image *) NULL); 12994 } 12995 /* 12996 Determine file name from the tile directory. 12997 */ 12998 p=image->directory; 12999 for (i=tile; (i != 0) && (*p != '\0'); ) 13000 { 13001 if (*p == '\n') 13002 i--; 13003 p++; 13004 } 13005 if (*p == '\0') 13006 { 13007 /* 13008 Button press is outside any tile. 13009 */ 13010 (void) XBell(display,0); 13011 return((Image *) NULL); 13012 } 13013 /* 13014 Select a command from the pop-up menu. 13015 */ 13016 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13017 if (id < 0) 13018 return((Image *) NULL); 13019 q=p; 13020 while ((*q != '\n') && (*q != '\0')) 13021 q++; 13022 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13023 /* 13024 Perform command for the selected tile. 13025 */ 13026 XSetCursorState(display,windows,MagickTrue); 13027 XCheckRefreshWindows(display,windows); 13028 tile_image=NewImageList(); 13029 switch (TileCommands[id]) 13030 { 13031 case TileLoadCommand: 13032 { 13033 /* 13034 Load tile image. 13035 */ 13036 XCheckRefreshWindows(display,windows); 13037 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13038 MaxTextExtent); 13039 (void) CopyMagickString(resource_info->image_info->filename,filename, 13040 MaxTextExtent); 13041 tile_image=ReadImage(resource_info->image_info,&image->exception); 13042 CatchException(&image->exception); 13043 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13044 break; 13045 } 13046 case TileNextCommand: 13047 { 13048 /* 13049 Display next image. 13050 */ 13051 XClientMessage(display,windows->image.id,windows->im_protocols, 13052 windows->im_next_image,CurrentTime); 13053 break; 13054 } 13055 case TileFormerCommand: 13056 { 13057 /* 13058 Display former image. 13059 */ 13060 XClientMessage(display,windows->image.id,windows->im_protocols, 13061 windows->im_former_image,CurrentTime); 13062 break; 13063 } 13064 case TileDeleteCommand: 13065 { 13066 /* 13067 Delete tile image. 13068 */ 13069 if (IsPathAccessible(filename) == MagickFalse) 13070 { 13071 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13072 break; 13073 } 13074 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13075 if (status <= 0) 13076 break; 13077 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 13078 if (status != MagickFalse) 13079 { 13080 XNoticeWidget(display,windows,"Unable to delete image file:", 13081 filename); 13082 break; 13083 } 13084 } 13085 case TileUpdateCommand: 13086 { 13087 ExceptionInfo 13088 *exception; 13089 13090 int 13091 x_offset, 13092 y_offset; 13093 13094 PixelPacket 13095 pixel; 13096 13097 register int 13098 j; 13099 13100 register Quantum 13101 *s; 13102 13103 /* 13104 Ensure all the images exist. 13105 */ 13106 tile=0; 13107 for (p=image->directory; *p != '\0'; p++) 13108 { 13109 CacheView 13110 *image_view; 13111 13112 q=p; 13113 while ((*q != '\n') && (*q != '\0')) 13114 q++; 13115 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13116 p=q; 13117 if (IsPathAccessible(filename) != MagickFalse) 13118 { 13119 tile++; 13120 continue; 13121 } 13122 /* 13123 Overwrite tile with background color. 13124 */ 13125 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13126 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13127 exception=(&image->exception); 13128 image_view=AcquireCacheView(image); 13129 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception); 13130 for (i=0; i < (int) height; i++) 13131 { 13132 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13133 y_offset+i,width,1,exception); 13134 if (s == (Quantum *) NULL) 13135 break; 13136 for (j=0; j < (int) width; j++) 13137 { 13138 SetPixelPacket(image,&pixel,s); 13139 s+=GetPixelChannels(image); 13140 } 13141 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13142 break; 13143 } 13144 image_view=DestroyCacheView(image_view); 13145 tile++; 13146 } 13147 windows->image.window_changes.width=(int) image->columns; 13148 windows->image.window_changes.height=(int) image->rows; 13149 XConfigureImageColormap(display,resource_info,windows,image); 13150 (void) XConfigureImage(display,resource_info,windows,image); 13151 break; 13152 } 13153 default: 13154 break; 13155 } 13156 XSetCursorState(display,windows,MagickFalse); 13157 return(tile_image); 13158} 13159 13160/* 13161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13162% % 13163% % 13164% % 13165+ X T r a n s l a t e I m a g e % 13166% % 13167% % 13168% % 13169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13170% 13171% XTranslateImage() translates the image within an Image window by one pixel 13172% as specified by the key symbol. If the image has a `montage string the 13173% translation is respect to the width and height contained within the string. 13174% 13175% The format of the XTranslateImage method is: 13176% 13177% void XTranslateImage(Display *display,XWindows *windows, 13178% Image *image,const KeySym key_symbol) 13179% 13180% A description of each parameter follows: 13181% 13182% o display: Specifies a connection to an X server; returned from 13183% XOpenDisplay. 13184% 13185% o windows: Specifies a pointer to a XWindows structure. 13186% 13187% o image: the image. 13188% 13189% o key_symbol: Specifies a KeySym which indicates which side of the image 13190% to trim. 13191% 13192*/ 13193static void XTranslateImage(Display *display,XWindows *windows, 13194 Image *image,const KeySym key_symbol) 13195{ 13196 char 13197 text[MaxTextExtent]; 13198 13199 int 13200 x, 13201 y; 13202 13203 unsigned int 13204 x_offset, 13205 y_offset; 13206 13207 /* 13208 User specified a pan position offset. 13209 */ 13210 x_offset=windows->image.width; 13211 y_offset=windows->image.height; 13212 if (image->montage != (char *) NULL) 13213 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13214 switch ((int) key_symbol) 13215 { 13216 case XK_Home: 13217 case XK_KP_Home: 13218 { 13219 windows->image.x=(int) windows->image.width/2; 13220 windows->image.y=(int) windows->image.height/2; 13221 break; 13222 } 13223 case XK_Left: 13224 case XK_KP_Left: 13225 { 13226 windows->image.x-=x_offset; 13227 break; 13228 } 13229 case XK_Next: 13230 case XK_Up: 13231 case XK_KP_Up: 13232 { 13233 windows->image.y-=y_offset; 13234 break; 13235 } 13236 case XK_Right: 13237 case XK_KP_Right: 13238 { 13239 windows->image.x+=x_offset; 13240 break; 13241 } 13242 case XK_Prior: 13243 case XK_Down: 13244 case XK_KP_Down: 13245 { 13246 windows->image.y+=y_offset; 13247 break; 13248 } 13249 default: 13250 return; 13251 } 13252 /* 13253 Check boundary conditions. 13254 */ 13255 if (windows->image.x < 0) 13256 windows->image.x=0; 13257 else 13258 if ((int) (windows->image.x+windows->image.width) > 13259 windows->image.ximage->width) 13260 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13261 if (windows->image.y < 0) 13262 windows->image.y=0; 13263 else 13264 if ((int) (windows->image.y+windows->image.height) > 13265 windows->image.ximage->height) 13266 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13267 /* 13268 Refresh Image window. 13269 */ 13270 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13271 windows->image.width,windows->image.height,windows->image.x, 13272 windows->image.y); 13273 XInfoWidget(display,windows,text); 13274 XCheckRefreshWindows(display,windows); 13275 XDrawPanRectangle(display,windows); 13276 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13277 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13278} 13279 13280/* 13281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13282% % 13283% % 13284% % 13285+ X T r i m I m a g e % 13286% % 13287% % 13288% % 13289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13290% 13291% XTrimImage() trims the edges from the Image window. 13292% 13293% The format of the XTrimImage method is: 13294% 13295% MagickBooleanType XTrimImage(Display *display, 13296% XResourceInfo *resource_info,XWindows *windows,Image *image) 13297% 13298% A description of each parameter follows: 13299% 13300% o display: Specifies a connection to an X server; returned from 13301% XOpenDisplay. 13302% 13303% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13304% 13305% o windows: Specifies a pointer to a XWindows structure. 13306% 13307% o image: the image. 13308% 13309*/ 13310static MagickBooleanType XTrimImage(Display *display, 13311 XResourceInfo *resource_info,XWindows *windows,Image *image) 13312{ 13313 RectangleInfo 13314 trim_info; 13315 13316 register int 13317 x, 13318 y; 13319 13320 size_t 13321 background, 13322 pixel; 13323 13324 /* 13325 Trim edges from image. 13326 */ 13327 XSetCursorState(display,windows,MagickTrue); 13328 XCheckRefreshWindows(display,windows); 13329 /* 13330 Crop the left edge. 13331 */ 13332 background=XGetPixel(windows->image.ximage,0,0); 13333 trim_info.width=(size_t) windows->image.ximage->width; 13334 for (x=0; x < windows->image.ximage->width; x++) 13335 { 13336 for (y=0; y < windows->image.ximage->height; y++) 13337 { 13338 pixel=XGetPixel(windows->image.ximage,x,y); 13339 if (pixel != background) 13340 break; 13341 } 13342 if (y < windows->image.ximage->height) 13343 break; 13344 } 13345 trim_info.x=(ssize_t) x; 13346 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13347 { 13348 XSetCursorState(display,windows,MagickFalse); 13349 return(MagickFalse); 13350 } 13351 /* 13352 Crop the right edge. 13353 */ 13354 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13355 for (x=windows->image.ximage->width-1; x != 0; x--) 13356 { 13357 for (y=0; y < windows->image.ximage->height; y++) 13358 { 13359 pixel=XGetPixel(windows->image.ximage,x,y); 13360 if (pixel != background) 13361 break; 13362 } 13363 if (y < windows->image.ximage->height) 13364 break; 13365 } 13366 trim_info.width=(size_t) (x-trim_info.x+1); 13367 /* 13368 Crop the top edge. 13369 */ 13370 background=XGetPixel(windows->image.ximage,0,0); 13371 trim_info.height=(size_t) windows->image.ximage->height; 13372 for (y=0; y < windows->image.ximage->height; y++) 13373 { 13374 for (x=0; x < windows->image.ximage->width; x++) 13375 { 13376 pixel=XGetPixel(windows->image.ximage,x,y); 13377 if (pixel != background) 13378 break; 13379 } 13380 if (x < windows->image.ximage->width) 13381 break; 13382 } 13383 trim_info.y=(ssize_t) y; 13384 /* 13385 Crop the bottom edge. 13386 */ 13387 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13388 for (y=windows->image.ximage->height-1; y != 0; y--) 13389 { 13390 for (x=0; x < windows->image.ximage->width; x++) 13391 { 13392 pixel=XGetPixel(windows->image.ximage,x,y); 13393 if (pixel != background) 13394 break; 13395 } 13396 if (x < windows->image.ximage->width) 13397 break; 13398 } 13399 trim_info.height=(size_t) y-trim_info.y+1; 13400 if (((unsigned int) trim_info.width != windows->image.width) || 13401 ((unsigned int) trim_info.height != windows->image.height)) 13402 { 13403 /* 13404 Reconfigure Image window as defined by the trimming rectangle. 13405 */ 13406 XSetCropGeometry(display,windows,&trim_info,image); 13407 windows->image.window_changes.width=(int) trim_info.width; 13408 windows->image.window_changes.height=(int) trim_info.height; 13409 (void) XConfigureImage(display,resource_info,windows,image); 13410 } 13411 XSetCursorState(display,windows,MagickFalse); 13412 return(MagickTrue); 13413} 13414 13415/* 13416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13417% % 13418% % 13419% % 13420+ X V i s u a l D i r e c t o r y I m a g e % 13421% % 13422% % 13423% % 13424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13425% 13426% XVisualDirectoryImage() creates a Visual Image Directory. 13427% 13428% The format of the XVisualDirectoryImage method is: 13429% 13430% Image *XVisualDirectoryImage(Display *display, 13431% XResourceInfo *resource_info,XWindows *windows) 13432% 13433% A description of each parameter follows: 13434% 13435% o nexus: Method XVisualDirectoryImage returns a visual image 13436% directory if it can be created successfully. Otherwise a null image 13437% is returned. 13438% 13439% o display: Specifies a connection to an X server; returned from 13440% XOpenDisplay. 13441% 13442% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13443% 13444% o windows: Specifies a pointer to a XWindows structure. 13445% 13446*/ 13447static Image *XVisualDirectoryImage(Display *display, 13448 XResourceInfo *resource_info,XWindows *windows) 13449{ 13450#define TileImageTag "Scale/Image" 13451#define XClientName "montage" 13452 13453 char 13454 **filelist; 13455 13456 ExceptionInfo 13457 *exception; 13458 13459 Image 13460 *images, 13461 *montage_image, 13462 *next_image, 13463 *thumbnail_image; 13464 13465 ImageInfo 13466 *read_info; 13467 13468 int 13469 number_files; 13470 13471 MagickBooleanType 13472 backdrop; 13473 13474 MagickStatusType 13475 status; 13476 13477 MontageInfo 13478 *montage_info; 13479 13480 RectangleInfo 13481 geometry; 13482 13483 register int 13484 i; 13485 13486 static char 13487 filename[MaxTextExtent] = "\0", 13488 filenames[MaxTextExtent] = "*"; 13489 13490 XResourceInfo 13491 background_resources; 13492 13493 /* 13494 Request file name from user. 13495 */ 13496 XFileBrowserWidget(display,windows,"Directory",filenames); 13497 if (*filenames == '\0') 13498 return((Image *) NULL); 13499 /* 13500 Expand the filenames. 13501 */ 13502 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13503 if (filelist == (char **) NULL) 13504 { 13505 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13506 filenames); 13507 return((Image *) NULL); 13508 } 13509 number_files=1; 13510 filelist[0]=filenames; 13511 status=ExpandFilenames(&number_files,&filelist); 13512 if ((status == MagickFalse) || (number_files == 0)) 13513 { 13514 if (number_files == 0) 13515 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13516 else 13517 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13518 filenames); 13519 return((Image *) NULL); 13520 } 13521 /* 13522 Set image background resources. 13523 */ 13524 background_resources=(*resource_info); 13525 background_resources.window_id=AcquireString(""); 13526 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13527 "0x%lx",windows->image.id); 13528 background_resources.backdrop=MagickTrue; 13529 /* 13530 Read each image and convert them to a tile. 13531 */ 13532 backdrop=(windows->visual_info->klass == TrueColor) || 13533 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13534 read_info=CloneImageInfo(resource_info->image_info); 13535 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13536 (void) CloneString(&read_info->size,DefaultTileGeometry); 13537 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13538 (void *) NULL); 13539 images=NewImageList(); 13540 exception=AcquireExceptionInfo(); 13541 XSetCursorState(display,windows,MagickTrue); 13542 XCheckRefreshWindows(display,windows); 13543 for (i=0; i < (int) number_files; i++) 13544 { 13545 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13546 filelist[i]=DestroyString(filelist[i]); 13547 *read_info->magick='\0'; 13548 next_image=ReadImage(read_info,exception); 13549 CatchException(exception); 13550 if (next_image != (Image *) NULL) 13551 { 13552 (void) DeleteImageProperty(next_image,"label"); 13553 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13554 read_info,next_image,DefaultTileLabel)); 13555 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13556 exception); 13557 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13558 geometry.height,exception); 13559 if (thumbnail_image != (Image *) NULL) 13560 { 13561 next_image=DestroyImage(next_image); 13562 next_image=thumbnail_image; 13563 } 13564 if (backdrop) 13565 { 13566 (void) XDisplayBackgroundImage(display,&background_resources, 13567 next_image); 13568 XSetCursorState(display,windows,MagickTrue); 13569 } 13570 AppendImageToList(&images,next_image); 13571 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13572 { 13573 MagickBooleanType 13574 proceed; 13575 13576 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13577 (MagickSizeType) number_files); 13578 if (proceed == MagickFalse) 13579 break; 13580 } 13581 } 13582 } 13583 exception=DestroyExceptionInfo(exception); 13584 filelist=(char **) RelinquishMagickMemory(filelist); 13585 if (images == (Image *) NULL) 13586 { 13587 read_info=DestroyImageInfo(read_info); 13588 XSetCursorState(display,windows,MagickFalse); 13589 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13590 return((Image *) NULL); 13591 } 13592 /* 13593 Create the Visual Image Directory. 13594 */ 13595 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13596 montage_info->pointsize=10; 13597 if (resource_info->font != (char *) NULL) 13598 (void) CloneString(&montage_info->font,resource_info->font); 13599 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13600 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13601 images),&images->exception); 13602 images=DestroyImageList(images); 13603 montage_info=DestroyMontageInfo(montage_info); 13604 read_info=DestroyImageInfo(read_info); 13605 XSetCursorState(display,windows,MagickFalse); 13606 if (montage_image == (Image *) NULL) 13607 return(montage_image); 13608 XClientMessage(display,windows->image.id,windows->im_protocols, 13609 windows->im_next_image,CurrentTime); 13610 return(montage_image); 13611} 13612 13613/* 13614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13615% % 13616% % 13617% % 13618% X D i s p l a y B a c k g r o u n d I m a g e % 13619% % 13620% % 13621% % 13622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13623% 13624% XDisplayBackgroundImage() displays an image in the background of a window. 13625% 13626% The format of the XDisplayBackgroundImage method is: 13627% 13628% MagickBooleanType XDisplayBackgroundImage(Display *display, 13629% XResourceInfo *resource_info,Image *image) 13630% 13631% A description of each parameter follows: 13632% 13633% o display: Specifies a connection to an X server; returned from 13634% XOpenDisplay. 13635% 13636% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13637% 13638% o image: the image. 13639% 13640*/ 13641MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13642 XResourceInfo *resource_info,Image *image) 13643{ 13644 char 13645 geometry[MaxTextExtent], 13646 visual_type[MaxTextExtent]; 13647 13648 int 13649 height, 13650 status, 13651 width; 13652 13653 RectangleInfo 13654 geometry_info; 13655 13656 static XPixelInfo 13657 pixel; 13658 13659 static XStandardColormap 13660 *map_info; 13661 13662 static XVisualInfo 13663 *visual_info = (XVisualInfo *) NULL; 13664 13665 static XWindowInfo 13666 window_info; 13667 13668 size_t 13669 delay; 13670 13671 Window 13672 root_window; 13673 13674 XGCValues 13675 context_values; 13676 13677 XResourceInfo 13678 resources; 13679 13680 XWindowAttributes 13681 window_attributes; 13682 13683 /* 13684 Determine target window. 13685 */ 13686 assert(image != (Image *) NULL); 13687 assert(image->signature == MagickSignature); 13688 if (image->debug != MagickFalse) 13689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13690 resources=(*resource_info); 13691 window_info.id=(Window) NULL; 13692 root_window=XRootWindow(display,XDefaultScreen(display)); 13693 if (LocaleCompare(resources.window_id,"root") == 0) 13694 window_info.id=root_window; 13695 else 13696 { 13697 if (isdigit((unsigned char) *resources.window_id) != 0) 13698 window_info.id=XWindowByID(display,root_window, 13699 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13700 if (window_info.id == (Window) NULL) 13701 window_info.id=XWindowByName(display,root_window,resources.window_id); 13702 } 13703 if (window_info.id == (Window) NULL) 13704 { 13705 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13706 resources.window_id); 13707 return(MagickFalse); 13708 } 13709 /* 13710 Determine window visual id. 13711 */ 13712 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13713 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13714 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13715 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13716 if (status != 0) 13717 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13718 XVisualIDFromVisual(window_attributes.visual)); 13719 if (visual_info == (XVisualInfo *) NULL) 13720 { 13721 /* 13722 Allocate standard colormap. 13723 */ 13724 map_info=XAllocStandardColormap(); 13725 if (map_info == (XStandardColormap *) NULL) 13726 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13727 image->filename); 13728 map_info->colormap=(Colormap) NULL; 13729 pixel.pixels=(unsigned long *) NULL; 13730 /* 13731 Initialize visual info. 13732 */ 13733 resources.map_type=(char *) NULL; 13734 resources.visual_type=visual_type; 13735 visual_info=XBestVisualInfo(display,map_info,&resources); 13736 if (visual_info == (XVisualInfo *) NULL) 13737 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13738 resources.visual_type); 13739 /* 13740 Initialize window info. 13741 */ 13742 window_info.ximage=(XImage *) NULL; 13743 window_info.matte_image=(XImage *) NULL; 13744 window_info.pixmap=(Pixmap) NULL; 13745 window_info.matte_pixmap=(Pixmap) NULL; 13746 } 13747 /* 13748 Free previous root colors. 13749 */ 13750 if (window_info.id == root_window) 13751 (void) XDestroyWindowColors(display,root_window); 13752 /* 13753 Initialize Standard Colormap. 13754 */ 13755 resources.colormap=SharedColormap; 13756 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13757 /* 13758 Graphic context superclass. 13759 */ 13760 context_values.background=pixel.background_color.pixel; 13761 context_values.foreground=pixel.foreground_color.pixel; 13762 pixel.annotate_context=XCreateGC(display,window_info.id, 13763 (size_t) (GCBackground | GCForeground),&context_values); 13764 if (pixel.annotate_context == (GC) NULL) 13765 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13766 image->filename); 13767 /* 13768 Initialize Image window attributes. 13769 */ 13770 window_info.name=AcquireString("\0"); 13771 window_info.icon_name=AcquireString("\0"); 13772 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13773 &resources,&window_info); 13774 /* 13775 Create the X image. 13776 */ 13777 window_info.width=(unsigned int) image->columns; 13778 window_info.height=(unsigned int) image->rows; 13779 if ((image->columns != window_info.width) || 13780 (image->rows != window_info.height)) 13781 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13782 image->filename); 13783 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13784 window_attributes.width,window_attributes.height); 13785 geometry_info.width=window_info.width; 13786 geometry_info.height=window_info.height; 13787 geometry_info.x=(ssize_t) window_info.x; 13788 geometry_info.y=(ssize_t) window_info.y; 13789 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13790 &geometry_info.width,&geometry_info.height); 13791 window_info.width=(unsigned int) geometry_info.width; 13792 window_info.height=(unsigned int) geometry_info.height; 13793 window_info.x=(int) geometry_info.x; 13794 window_info.y=(int) geometry_info.y; 13795 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13796 window_info.height); 13797 if (status == MagickFalse) 13798 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13799 image->filename); 13800 window_info.x=0; 13801 window_info.y=0; 13802 if (image->debug != MagickFalse) 13803 { 13804 (void) LogMagickEvent(X11Event,GetMagickModule(), 13805 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13806 (double) image->columns,(double) image->rows); 13807 if (image->colors != 0) 13808 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13809 image->colors); 13810 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13811 } 13812 /* 13813 Adjust image dimensions as specified by backdrop or geometry options. 13814 */ 13815 width=(int) window_info.width; 13816 height=(int) window_info.height; 13817 if (resources.backdrop != MagickFalse) 13818 { 13819 /* 13820 Center image on window. 13821 */ 13822 window_info.x=(window_attributes.width/2)- 13823 (window_info.ximage->width/2); 13824 window_info.y=(window_attributes.height/2)- 13825 (window_info.ximage->height/2); 13826 width=window_attributes.width; 13827 height=window_attributes.height; 13828 } 13829 if ((resources.image_geometry != (char *) NULL) && 13830 (*resources.image_geometry != '\0')) 13831 { 13832 char 13833 default_geometry[MaxTextExtent]; 13834 13835 int 13836 flags, 13837 gravity; 13838 13839 XSizeHints 13840 *size_hints; 13841 13842 /* 13843 User specified geometry. 13844 */ 13845 size_hints=XAllocSizeHints(); 13846 if (size_hints == (XSizeHints *) NULL) 13847 ThrowXWindowFatalException(ResourceLimitFatalError, 13848 "MemoryAllocationFailed",image->filename); 13849 size_hints->flags=0L; 13850 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13851 width,height); 13852 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13853 default_geometry,window_info.border_width,size_hints,&window_info.x, 13854 &window_info.y,&width,&height,&gravity); 13855 if (flags & (XValue | YValue)) 13856 { 13857 width=window_attributes.width; 13858 height=window_attributes.height; 13859 } 13860 (void) XFree((void *) size_hints); 13861 } 13862 /* 13863 Create the X pixmap. 13864 */ 13865 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 13866 (unsigned int) height,window_info.depth); 13867 if (window_info.pixmap == (Pixmap) NULL) 13868 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 13869 image->filename); 13870 /* 13871 Display pixmap on the window. 13872 */ 13873 if (((unsigned int) width > window_info.width) || 13874 ((unsigned int) height > window_info.height)) 13875 (void) XFillRectangle(display,window_info.pixmap, 13876 window_info.annotate_context,0,0,(unsigned int) width, 13877 (unsigned int) height); 13878 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 13879 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 13880 window_info.width,(unsigned int) window_info.height); 13881 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 13882 (void) XClearWindow(display,window_info.id); 13883 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 13884 XDelay(display,delay == 0UL ? 10UL : delay); 13885 (void) XSync(display,MagickFalse); 13886 return(window_info.id == root_window ? MagickTrue : MagickFalse); 13887} 13888 13889/* 13890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13891% % 13892% % 13893% % 13894+ X D i s p l a y I m a g e % 13895% % 13896% % 13897% % 13898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13899% 13900% XDisplayImage() displays an image via X11. A new image is created and 13901% returned if the user interactively transforms the displayed image. 13902% 13903% The format of the XDisplayImage method is: 13904% 13905% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 13906% char **argv,int argc,Image **image,size_t *state) 13907% 13908% A description of each parameter follows: 13909% 13910% o nexus: Method XDisplayImage returns an image when the 13911% user chooses 'Open Image' from the command menu or picks a tile 13912% from the image directory. Otherwise a null image is returned. 13913% 13914% o display: Specifies a connection to an X server; returned from 13915% XOpenDisplay. 13916% 13917% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13918% 13919% o argv: Specifies the application's argument list. 13920% 13921% o argc: Specifies the number of arguments. 13922% 13923% o image: Specifies an address to an address of an Image structure; 13924% 13925*/ 13926MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 13927 char **argv,int argc,Image **image,size_t *state) 13928{ 13929#define MagnifySize 256 /* must be a power of 2 */ 13930#define MagickMenus 10 13931#define MagickTitle "Commands" 13932 13933 static const char 13934 *CommandMenu[] = 13935 { 13936 "File", 13937 "Edit", 13938 "View", 13939 "Transform", 13940 "Enhance", 13941 "Effects", 13942 "F/X", 13943 "Image Edit", 13944 "Miscellany", 13945 "Help", 13946 (char *) NULL 13947 }, 13948 *FileMenu[] = 13949 { 13950 "Open...", 13951 "Next", 13952 "Former", 13953 "Select...", 13954 "Save...", 13955 "Print...", 13956 "Delete...", 13957 "New...", 13958 "Visual Directory...", 13959 "Quit", 13960 (char *) NULL 13961 }, 13962 *EditMenu[] = 13963 { 13964 "Undo", 13965 "Redo", 13966 "Cut", 13967 "Copy", 13968 "Paste", 13969 (char *) NULL 13970 }, 13971 *ViewMenu[] = 13972 { 13973 "Half Size", 13974 "Original Size", 13975 "Double Size", 13976 "Resize...", 13977 "Apply", 13978 "Refresh", 13979 "Restore", 13980 (char *) NULL 13981 }, 13982 *TransformMenu[] = 13983 { 13984 "Crop", 13985 "Chop", 13986 "Flop", 13987 "Flip", 13988 "Rotate Right", 13989 "Rotate Left", 13990 "Rotate...", 13991 "Shear...", 13992 "Roll...", 13993 "Trim Edges", 13994 (char *) NULL 13995 }, 13996 *EnhanceMenu[] = 13997 { 13998 "Hue...", 13999 "Saturation...", 14000 "Brightness...", 14001 "Gamma...", 14002 "Spiff", 14003 "Dull", 14004 "Contrast Stretch...", 14005 "Sigmoidal Contrast...", 14006 "Normalize", 14007 "Equalize", 14008 "Negate", 14009 "Grayscale", 14010 "Map...", 14011 "Quantize...", 14012 (char *) NULL 14013 }, 14014 *EffectsMenu[] = 14015 { 14016 "Despeckle", 14017 "Emboss", 14018 "Reduce Noise", 14019 "Add Noise...", 14020 "Sharpen...", 14021 "Blur...", 14022 "Threshold...", 14023 "Edge Detect...", 14024 "Spread...", 14025 "Shade...", 14026 "Raise...", 14027 "Segment...", 14028 (char *) NULL 14029 }, 14030 *FXMenu[] = 14031 { 14032 "Solarize...", 14033 "Sepia Tone...", 14034 "Swirl...", 14035 "Implode...", 14036 "Vignette...", 14037 "Wave...", 14038 "Oil Paint...", 14039 "Charcoal Draw...", 14040 (char *) NULL 14041 }, 14042 *ImageEditMenu[] = 14043 { 14044 "Annotate...", 14045 "Draw...", 14046 "Color...", 14047 "Matte...", 14048 "Composite...", 14049 "Add Border...", 14050 "Add Frame...", 14051 "Comment...", 14052 "Launch...", 14053 "Region of Interest...", 14054 (char *) NULL 14055 }, 14056 *MiscellanyMenu[] = 14057 { 14058 "Image Info", 14059 "Zoom Image", 14060 "Show Preview...", 14061 "Show Histogram", 14062 "Show Matte", 14063 "Background...", 14064 "Slide Show...", 14065 "Preferences...", 14066 (char *) NULL 14067 }, 14068 *HelpMenu[] = 14069 { 14070 "Overview", 14071 "Browse Documentation", 14072 "About Display", 14073 (char *) NULL 14074 }, 14075 *ShortCutsMenu[] = 14076 { 14077 "Next", 14078 "Former", 14079 "Open...", 14080 "Save...", 14081 "Print...", 14082 "Undo", 14083 "Restore", 14084 "Image Info", 14085 "Quit", 14086 (char *) NULL 14087 }, 14088 *VirtualMenu[] = 14089 { 14090 "Image Info", 14091 "Print", 14092 "Next", 14093 "Quit", 14094 (char *) NULL 14095 }; 14096 14097 static const char 14098 **Menus[MagickMenus] = 14099 { 14100 FileMenu, 14101 EditMenu, 14102 ViewMenu, 14103 TransformMenu, 14104 EnhanceMenu, 14105 EffectsMenu, 14106 FXMenu, 14107 ImageEditMenu, 14108 MiscellanyMenu, 14109 HelpMenu 14110 }; 14111 14112 static CommandType 14113 CommandMenus[] = 14114 { 14115 NullCommand, 14116 NullCommand, 14117 NullCommand, 14118 NullCommand, 14119 NullCommand, 14120 NullCommand, 14121 NullCommand, 14122 NullCommand, 14123 NullCommand, 14124 NullCommand, 14125 }, 14126 FileCommands[] = 14127 { 14128 OpenCommand, 14129 NextCommand, 14130 FormerCommand, 14131 SelectCommand, 14132 SaveCommand, 14133 PrintCommand, 14134 DeleteCommand, 14135 NewCommand, 14136 VisualDirectoryCommand, 14137 QuitCommand 14138 }, 14139 EditCommands[] = 14140 { 14141 UndoCommand, 14142 RedoCommand, 14143 CutCommand, 14144 CopyCommand, 14145 PasteCommand 14146 }, 14147 ViewCommands[] = 14148 { 14149 HalfSizeCommand, 14150 OriginalSizeCommand, 14151 DoubleSizeCommand, 14152 ResizeCommand, 14153 ApplyCommand, 14154 RefreshCommand, 14155 RestoreCommand 14156 }, 14157 TransformCommands[] = 14158 { 14159 CropCommand, 14160 ChopCommand, 14161 FlopCommand, 14162 FlipCommand, 14163 RotateRightCommand, 14164 RotateLeftCommand, 14165 RotateCommand, 14166 ShearCommand, 14167 RollCommand, 14168 TrimCommand 14169 }, 14170 EnhanceCommands[] = 14171 { 14172 HueCommand, 14173 SaturationCommand, 14174 BrightnessCommand, 14175 GammaCommand, 14176 SpiffCommand, 14177 DullCommand, 14178 ContrastStretchCommand, 14179 SigmoidalContrastCommand, 14180 NormalizeCommand, 14181 EqualizeCommand, 14182 NegateCommand, 14183 GrayscaleCommand, 14184 MapCommand, 14185 QuantizeCommand 14186 }, 14187 EffectsCommands[] = 14188 { 14189 DespeckleCommand, 14190 EmbossCommand, 14191 ReduceNoiseCommand, 14192 AddNoiseCommand, 14193 SharpenCommand, 14194 BlurCommand, 14195 ThresholdCommand, 14196 EdgeDetectCommand, 14197 SpreadCommand, 14198 ShadeCommand, 14199 RaiseCommand, 14200 SegmentCommand 14201 }, 14202 FXCommands[] = 14203 { 14204 SolarizeCommand, 14205 SepiaToneCommand, 14206 SwirlCommand, 14207 ImplodeCommand, 14208 VignetteCommand, 14209 WaveCommand, 14210 OilPaintCommand, 14211 CharcoalDrawCommand 14212 }, 14213 ImageEditCommands[] = 14214 { 14215 AnnotateCommand, 14216 DrawCommand, 14217 ColorCommand, 14218 MatteCommand, 14219 CompositeCommand, 14220 AddBorderCommand, 14221 AddFrameCommand, 14222 CommentCommand, 14223 LaunchCommand, 14224 RegionofInterestCommand 14225 }, 14226 MiscellanyCommands[] = 14227 { 14228 InfoCommand, 14229 ZoomCommand, 14230 ShowPreviewCommand, 14231 ShowHistogramCommand, 14232 ShowMatteCommand, 14233 BackgroundCommand, 14234 SlideShowCommand, 14235 PreferencesCommand 14236 }, 14237 HelpCommands[] = 14238 { 14239 HelpCommand, 14240 BrowseDocumentationCommand, 14241 VersionCommand 14242 }, 14243 ShortCutsCommands[] = 14244 { 14245 NextCommand, 14246 FormerCommand, 14247 OpenCommand, 14248 SaveCommand, 14249 PrintCommand, 14250 UndoCommand, 14251 RestoreCommand, 14252 InfoCommand, 14253 QuitCommand 14254 }, 14255 VirtualCommands[] = 14256 { 14257 InfoCommand, 14258 PrintCommand, 14259 NextCommand, 14260 QuitCommand 14261 }; 14262 14263 static CommandType 14264 *Commands[MagickMenus] = 14265 { 14266 FileCommands, 14267 EditCommands, 14268 ViewCommands, 14269 TransformCommands, 14270 EnhanceCommands, 14271 EffectsCommands, 14272 FXCommands, 14273 ImageEditCommands, 14274 MiscellanyCommands, 14275 HelpCommands 14276 }; 14277 14278 char 14279 command[MaxTextExtent], 14280 *directory, 14281 geometry[MaxTextExtent], 14282 resource_name[MaxTextExtent]; 14283 14284 CommandType 14285 command_type; 14286 14287 Image 14288 *display_image, 14289 *nexus; 14290 14291 int 14292 entry, 14293 id; 14294 14295 KeySym 14296 key_symbol; 14297 14298 MagickStatusType 14299 context_mask, 14300 status; 14301 14302 RectangleInfo 14303 geometry_info; 14304 14305 register int 14306 i; 14307 14308 static char 14309 working_directory[MaxTextExtent]; 14310 14311 static XPoint 14312 vid_info; 14313 14314 static XWindowInfo 14315 *magick_windows[MaxXWindows]; 14316 14317 static unsigned int 14318 number_windows; 14319 14320 struct stat 14321 attributes; 14322 14323 time_t 14324 timer, 14325 timestamp, 14326 update_time; 14327 14328 unsigned int 14329 height, 14330 width; 14331 14332 size_t 14333 delay; 14334 14335 WarningHandler 14336 warning_handler; 14337 14338 Window 14339 root_window; 14340 14341 XClassHint 14342 *class_hints; 14343 14344 XEvent 14345 event; 14346 14347 XFontStruct 14348 *font_info; 14349 14350 XGCValues 14351 context_values; 14352 14353 XPixelInfo 14354 *icon_pixel, 14355 *pixel; 14356 14357 XResourceInfo 14358 *icon_resources; 14359 14360 XStandardColormap 14361 *icon_map, 14362 *map_info; 14363 14364 XVisualInfo 14365 *icon_visual, 14366 *visual_info; 14367 14368 XWindowChanges 14369 window_changes; 14370 14371 XWindows 14372 *windows; 14373 14374 XWMHints 14375 *manager_hints; 14376 14377 assert(image != (Image **) NULL); 14378 assert((*image)->signature == MagickSignature); 14379 if ((*image)->debug != MagickFalse) 14380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14381 display_image=(*image); 14382 warning_handler=(WarningHandler) NULL; 14383 windows=XSetWindows((XWindows *) ~0); 14384 if (windows != (XWindows *) NULL) 14385 { 14386 int 14387 status; 14388 14389 status=chdir(working_directory); 14390 if (status == -1) 14391 (void) ThrowMagickException(&(*image)->exception,GetMagickModule(), 14392 FileOpenError,"UnableToOpenFile","%s",working_directory); 14393 warning_handler=resource_info->display_warnings ? 14394 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14395 warning_handler=resource_info->display_warnings ? 14396 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14397 } 14398 else 14399 { 14400 /* 14401 Allocate windows structure. 14402 */ 14403 resource_info->colors=display_image->colors; 14404 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14405 if (windows == (XWindows *) NULL) 14406 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14407 (*image)->filename); 14408 /* 14409 Initialize window id's. 14410 */ 14411 number_windows=0; 14412 magick_windows[number_windows++]=(&windows->icon); 14413 magick_windows[number_windows++]=(&windows->backdrop); 14414 magick_windows[number_windows++]=(&windows->image); 14415 magick_windows[number_windows++]=(&windows->info); 14416 magick_windows[number_windows++]=(&windows->command); 14417 magick_windows[number_windows++]=(&windows->widget); 14418 magick_windows[number_windows++]=(&windows->popup); 14419 magick_windows[number_windows++]=(&windows->magnify); 14420 magick_windows[number_windows++]=(&windows->pan); 14421 for (i=0; i < (int) number_windows; i++) 14422 magick_windows[i]->id=(Window) NULL; 14423 vid_info.x=0; 14424 vid_info.y=0; 14425 } 14426 /* 14427 Initialize font info. 14428 */ 14429 if (windows->font_info != (XFontStruct *) NULL) 14430 (void) XFreeFont(display,windows->font_info); 14431 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14432 if (windows->font_info == (XFontStruct *) NULL) 14433 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14434 resource_info->font); 14435 /* 14436 Initialize Standard Colormap. 14437 */ 14438 map_info=windows->map_info; 14439 icon_map=windows->icon_map; 14440 visual_info=windows->visual_info; 14441 icon_visual=windows->icon_visual; 14442 pixel=windows->pixel_info; 14443 icon_pixel=windows->icon_pixel; 14444 font_info=windows->font_info; 14445 icon_resources=windows->icon_resources; 14446 class_hints=windows->class_hints; 14447 manager_hints=windows->manager_hints; 14448 root_window=XRootWindow(display,visual_info->screen); 14449 nexus=NewImageList(); 14450 if (display_image->debug != MagickFalse) 14451 { 14452 (void) LogMagickEvent(X11Event,GetMagickModule(), 14453 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14454 (double) display_image->scene,(double) display_image->columns, 14455 (double) display_image->rows); 14456 if (display_image->colors != 0) 14457 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14458 display_image->colors); 14459 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14460 display_image->magick); 14461 } 14462 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14463 map_info,pixel); 14464 display_image->taint=MagickFalse; 14465 /* 14466 Initialize graphic context. 14467 */ 14468 windows->context.id=(Window) NULL; 14469 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14470 resource_info,&windows->context); 14471 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14472 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14473 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14474 manager_hints->flags=InputHint | StateHint; 14475 manager_hints->input=MagickFalse; 14476 manager_hints->initial_state=WithdrawnState; 14477 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14478 &windows->context); 14479 if (display_image->debug != MagickFalse) 14480 (void) LogMagickEvent(X11Event,GetMagickModule(), 14481 "Window id: 0x%lx (context)",windows->context.id); 14482 context_values.background=pixel->background_color.pixel; 14483 context_values.font=font_info->fid; 14484 context_values.foreground=pixel->foreground_color.pixel; 14485 context_values.graphics_exposures=MagickFalse; 14486 context_mask=(MagickStatusType) 14487 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14488 if (pixel->annotate_context != (GC) NULL) 14489 (void) XFreeGC(display,pixel->annotate_context); 14490 pixel->annotate_context=XCreateGC(display,windows->context.id, 14491 context_mask,&context_values); 14492 if (pixel->annotate_context == (GC) NULL) 14493 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14494 display_image->filename); 14495 context_values.background=pixel->depth_color.pixel; 14496 if (pixel->widget_context != (GC) NULL) 14497 (void) XFreeGC(display,pixel->widget_context); 14498 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14499 &context_values); 14500 if (pixel->widget_context == (GC) NULL) 14501 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14502 display_image->filename); 14503 context_values.background=pixel->foreground_color.pixel; 14504 context_values.foreground=pixel->background_color.pixel; 14505 context_values.plane_mask=context_values.background ^ 14506 context_values.foreground; 14507 if (pixel->highlight_context != (GC) NULL) 14508 (void) XFreeGC(display,pixel->highlight_context); 14509 pixel->highlight_context=XCreateGC(display,windows->context.id, 14510 (size_t) (context_mask | GCPlaneMask),&context_values); 14511 if (pixel->highlight_context == (GC) NULL) 14512 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14513 display_image->filename); 14514 (void) XDestroyWindow(display,windows->context.id); 14515 /* 14516 Initialize icon window. 14517 */ 14518 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14519 icon_resources,&windows->icon); 14520 windows->icon.geometry=resource_info->icon_geometry; 14521 XBestIconSize(display,&windows->icon,display_image); 14522 windows->icon.attributes.colormap=XDefaultColormap(display, 14523 icon_visual->screen); 14524 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14525 manager_hints->flags=InputHint | StateHint; 14526 manager_hints->input=MagickFalse; 14527 manager_hints->initial_state=IconicState; 14528 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14529 &windows->icon); 14530 if (display_image->debug != MagickFalse) 14531 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14532 windows->icon.id); 14533 /* 14534 Initialize graphic context for icon window. 14535 */ 14536 if (icon_pixel->annotate_context != (GC) NULL) 14537 (void) XFreeGC(display,icon_pixel->annotate_context); 14538 context_values.background=icon_pixel->background_color.pixel; 14539 context_values.foreground=icon_pixel->foreground_color.pixel; 14540 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14541 (size_t) (GCBackground | GCForeground),&context_values); 14542 if (icon_pixel->annotate_context == (GC) NULL) 14543 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14544 display_image->filename); 14545 windows->icon.annotate_context=icon_pixel->annotate_context; 14546 /* 14547 Initialize Image window. 14548 */ 14549 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14550 &windows->image); 14551 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14552 if (resource_info->use_shared_memory == MagickFalse) 14553 windows->image.shared_memory=MagickFalse; 14554 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14555 { 14556 char 14557 *title; 14558 14559 title=InterpretImageProperties(resource_info->image_info,display_image, 14560 resource_info->title); 14561 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14562 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14563 title=DestroyString(title); 14564 } 14565 else 14566 { 14567 char 14568 filename[MaxTextExtent]; 14569 14570 /* 14571 Window name is the base of the filename. 14572 */ 14573 GetPathComponent(display_image->magick_filename,TailPath,filename); 14574 if (GetImageListLength(display_image) == 1) 14575 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14576 "%s: %s",MagickPackageName,filename); 14577 else 14578 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14579 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14580 (double) display_image->scene,(double) GetImageListLength( 14581 display_image)); 14582 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14583 } 14584 if (resource_info->immutable) 14585 windows->image.immutable=MagickTrue; 14586 windows->image.use_pixmap=resource_info->use_pixmap; 14587 windows->image.geometry=resource_info->image_geometry; 14588 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14589 XDisplayWidth(display,visual_info->screen), 14590 XDisplayHeight(display,visual_info->screen)); 14591 geometry_info.width=display_image->columns; 14592 geometry_info.height=display_image->rows; 14593 geometry_info.x=0; 14594 geometry_info.y=0; 14595 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14596 &geometry_info.width,&geometry_info.height); 14597 windows->image.width=(unsigned int) geometry_info.width; 14598 windows->image.height=(unsigned int) geometry_info.height; 14599 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14600 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14601 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14602 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14603 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14604 resource_info,&windows->backdrop); 14605 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14606 { 14607 /* 14608 Initialize backdrop window. 14609 */ 14610 windows->backdrop.x=0; 14611 windows->backdrop.y=0; 14612 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14613 windows->backdrop.flags=(size_t) (USSize | USPosition); 14614 windows->backdrop.width=(unsigned int) 14615 XDisplayWidth(display,visual_info->screen); 14616 windows->backdrop.height=(unsigned int) 14617 XDisplayHeight(display,visual_info->screen); 14618 windows->backdrop.border_width=0; 14619 windows->backdrop.immutable=MagickTrue; 14620 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14621 ButtonReleaseMask; 14622 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14623 StructureNotifyMask; 14624 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14625 manager_hints->icon_window=windows->icon.id; 14626 manager_hints->input=MagickTrue; 14627 manager_hints->initial_state=resource_info->iconic ? IconicState : 14628 NormalState; 14629 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14630 &windows->backdrop); 14631 if (display_image->debug != MagickFalse) 14632 (void) LogMagickEvent(X11Event,GetMagickModule(), 14633 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14634 (void) XMapWindow(display,windows->backdrop.id); 14635 (void) XClearWindow(display,windows->backdrop.id); 14636 if (windows->image.id != (Window) NULL) 14637 { 14638 (void) XDestroyWindow(display,windows->image.id); 14639 windows->image.id=(Window) NULL; 14640 } 14641 /* 14642 Position image in the center the backdrop. 14643 */ 14644 windows->image.flags|=USPosition; 14645 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14646 (windows->image.width/2); 14647 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14648 (windows->image.height/2); 14649 } 14650 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14651 manager_hints->icon_window=windows->icon.id; 14652 manager_hints->input=MagickTrue; 14653 manager_hints->initial_state=resource_info->iconic ? IconicState : 14654 NormalState; 14655 if (windows->group_leader.id != (Window) NULL) 14656 { 14657 /* 14658 Follow the leader. 14659 */ 14660 manager_hints->flags|=WindowGroupHint; 14661 manager_hints->window_group=windows->group_leader.id; 14662 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14663 if (display_image->debug != MagickFalse) 14664 (void) LogMagickEvent(X11Event,GetMagickModule(), 14665 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14666 } 14667 XMakeWindow(display, 14668 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14669 argv,argc,class_hints,manager_hints,&windows->image); 14670 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14671 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14672 if (windows->group_leader.id != (Window) NULL) 14673 (void) XSetTransientForHint(display,windows->image.id, 14674 windows->group_leader.id); 14675 if (display_image->debug != MagickFalse) 14676 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14677 windows->image.id); 14678 /* 14679 Initialize Info widget. 14680 */ 14681 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14682 &windows->info); 14683 (void) CloneString(&windows->info.name,"Info"); 14684 (void) CloneString(&windows->info.icon_name,"Info"); 14685 windows->info.border_width=1; 14686 windows->info.x=2; 14687 windows->info.y=2; 14688 windows->info.flags|=PPosition; 14689 windows->info.attributes.win_gravity=UnmapGravity; 14690 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14691 StructureNotifyMask; 14692 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14693 manager_hints->input=MagickFalse; 14694 manager_hints->initial_state=NormalState; 14695 manager_hints->window_group=windows->image.id; 14696 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14697 &windows->info); 14698 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14699 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14700 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14701 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14702 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14703 if (windows->image.mapped != MagickFalse) 14704 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14705 if (display_image->debug != MagickFalse) 14706 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14707 windows->info.id); 14708 /* 14709 Initialize Command widget. 14710 */ 14711 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14712 resource_info,&windows->command); 14713 windows->command.data=MagickMenus; 14714 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14715 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14716 resource_info->client_name); 14717 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14718 resource_name,"geometry",(char *) NULL); 14719 (void) CloneString(&windows->command.name,MagickTitle); 14720 windows->command.border_width=0; 14721 windows->command.flags|=PPosition; 14722 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14723 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14724 OwnerGrabButtonMask | StructureNotifyMask; 14725 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14726 manager_hints->input=MagickTrue; 14727 manager_hints->initial_state=NormalState; 14728 manager_hints->window_group=windows->image.id; 14729 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14730 &windows->command); 14731 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14732 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14733 HighlightHeight); 14734 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14735 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14736 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14737 if (windows->command.mapped != MagickFalse) 14738 (void) XMapRaised(display,windows->command.id); 14739 if (display_image->debug != MagickFalse) 14740 (void) LogMagickEvent(X11Event,GetMagickModule(), 14741 "Window id: 0x%lx (command)",windows->command.id); 14742 /* 14743 Initialize Widget window. 14744 */ 14745 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14746 resource_info,&windows->widget); 14747 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14748 resource_info->client_name); 14749 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14750 resource_name,"geometry",(char *) NULL); 14751 windows->widget.border_width=0; 14752 windows->widget.flags|=PPosition; 14753 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14754 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14755 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14756 StructureNotifyMask; 14757 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14758 manager_hints->input=MagickTrue; 14759 manager_hints->initial_state=NormalState; 14760 manager_hints->window_group=windows->image.id; 14761 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14762 &windows->widget); 14763 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14764 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14765 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14766 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14767 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14768 if (display_image->debug != MagickFalse) 14769 (void) LogMagickEvent(X11Event,GetMagickModule(), 14770 "Window id: 0x%lx (widget)",windows->widget.id); 14771 /* 14772 Initialize popup window. 14773 */ 14774 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14775 resource_info,&windows->popup); 14776 windows->popup.border_width=0; 14777 windows->popup.flags|=PPosition; 14778 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14779 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14780 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14781 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14782 manager_hints->input=MagickTrue; 14783 manager_hints->initial_state=NormalState; 14784 manager_hints->window_group=windows->image.id; 14785 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14786 &windows->popup); 14787 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14788 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14789 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14790 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14791 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14792 if (display_image->debug != MagickFalse) 14793 (void) LogMagickEvent(X11Event,GetMagickModule(), 14794 "Window id: 0x%lx (pop up)",windows->popup.id); 14795 /* 14796 Initialize Magnify window and cursor. 14797 */ 14798 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14799 resource_info,&windows->magnify); 14800 if (resource_info->use_shared_memory == MagickFalse) 14801 windows->magnify.shared_memory=MagickFalse; 14802 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14803 resource_info->client_name); 14804 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14805 resource_name,"geometry",(char *) NULL); 14806 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14807 resource_info->magnify); 14808 if (windows->magnify.cursor != (Cursor) NULL) 14809 (void) XFreeCursor(display,windows->magnify.cursor); 14810 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14811 map_info->colormap,resource_info->background_color, 14812 resource_info->foreground_color); 14813 if (windows->magnify.cursor == (Cursor) NULL) 14814 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14815 display_image->filename); 14816 windows->magnify.width=MagnifySize; 14817 windows->magnify.height=MagnifySize; 14818 windows->magnify.flags|=PPosition; 14819 windows->magnify.min_width=MagnifySize; 14820 windows->magnify.min_height=MagnifySize; 14821 windows->magnify.width_inc=MagnifySize; 14822 windows->magnify.height_inc=MagnifySize; 14823 windows->magnify.data=resource_info->magnify; 14824 windows->magnify.attributes.cursor=windows->magnify.cursor; 14825 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14826 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14827 StructureNotifyMask; 14828 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14829 manager_hints->input=MagickTrue; 14830 manager_hints->initial_state=NormalState; 14831 manager_hints->window_group=windows->image.id; 14832 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14833 &windows->magnify); 14834 if (display_image->debug != MagickFalse) 14835 (void) LogMagickEvent(X11Event,GetMagickModule(), 14836 "Window id: 0x%lx (magnify)",windows->magnify.id); 14837 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14838 /* 14839 Initialize panning window. 14840 */ 14841 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14842 resource_info,&windows->pan); 14843 (void) CloneString(&windows->pan.name,"Pan Icon"); 14844 windows->pan.width=windows->icon.width; 14845 windows->pan.height=windows->icon.height; 14846 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14847 resource_info->client_name); 14848 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14849 resource_name,"geometry",(char *) NULL); 14850 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14851 &windows->pan.width,&windows->pan.height); 14852 windows->pan.flags|=PPosition; 14853 windows->pan.immutable=MagickTrue; 14854 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14855 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14856 StructureNotifyMask; 14857 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14858 manager_hints->input=MagickFalse; 14859 manager_hints->initial_state=NormalState; 14860 manager_hints->window_group=windows->image.id; 14861 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14862 &windows->pan); 14863 if (display_image->debug != MagickFalse) 14864 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 14865 windows->pan.id); 14866 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 14867 if (windows->info.mapped != MagickFalse) 14868 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14869 if ((windows->image.mapped == MagickFalse) || 14870 (windows->backdrop.id != (Window) NULL)) 14871 (void) XMapWindow(display,windows->image.id); 14872 /* 14873 Set our progress monitor and warning handlers. 14874 */ 14875 if (warning_handler == (WarningHandler) NULL) 14876 { 14877 warning_handler=resource_info->display_warnings ? 14878 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14879 warning_handler=resource_info->display_warnings ? 14880 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14881 } 14882 /* 14883 Initialize Image and Magnify X images. 14884 */ 14885 windows->image.x=0; 14886 windows->image.y=0; 14887 windows->magnify.shape=MagickFalse; 14888 width=(unsigned int) display_image->columns; 14889 height=(unsigned int) display_image->rows; 14890 if ((display_image->columns != width) || (display_image->rows != height)) 14891 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14892 display_image->filename); 14893 status=XMakeImage(display,resource_info,&windows->image,display_image, 14894 width,height); 14895 if (status == MagickFalse) 14896 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14897 display_image->filename); 14898 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 14899 windows->magnify.width,windows->magnify.height); 14900 if (status == MagickFalse) 14901 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14902 display_image->filename); 14903 if (windows->magnify.mapped != MagickFalse) 14904 (void) XMapRaised(display,windows->magnify.id); 14905 if (windows->pan.mapped != MagickFalse) 14906 (void) XMapRaised(display,windows->pan.id); 14907 windows->image.window_changes.width=(int) display_image->columns; 14908 windows->image.window_changes.height=(int) display_image->rows; 14909 (void) XConfigureImage(display,resource_info,windows,display_image); 14910 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14911 (void) XSync(display,MagickFalse); 14912 /* 14913 Respond to events. 14914 */ 14915 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 14916 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 14917 update_time=0; 14918 if (resource_info->update != MagickFalse) 14919 { 14920 MagickBooleanType 14921 status; 14922 14923 /* 14924 Determine when file data was last modified. 14925 */ 14926 status=GetPathAttributes(display_image->filename,&attributes); 14927 if (status != MagickFalse) 14928 update_time=attributes.st_mtime; 14929 } 14930 *state&=(~FormerImageState); 14931 *state&=(~MontageImageState); 14932 *state&=(~NextImageState); 14933 do 14934 { 14935 /* 14936 Handle a window event. 14937 */ 14938 if (windows->image.mapped != MagickFalse) 14939 if ((display_image->delay != 0) || (resource_info->update != 0)) 14940 { 14941 if (timer < time((time_t *) NULL)) 14942 { 14943 if (resource_info->update == MagickFalse) 14944 *state|=NextImageState | ExitState; 14945 else 14946 { 14947 MagickBooleanType 14948 status; 14949 14950 /* 14951 Determine if image file was modified. 14952 */ 14953 status=GetPathAttributes(display_image->filename,&attributes); 14954 if (status != MagickFalse) 14955 if (update_time != attributes.st_mtime) 14956 { 14957 /* 14958 Redisplay image. 14959 */ 14960 (void) FormatLocaleString( 14961 resource_info->image_info->filename,MaxTextExtent, 14962 "%s:%s",display_image->magick, 14963 display_image->filename); 14964 nexus=ReadImage(resource_info->image_info, 14965 &display_image->exception); 14966 if (nexus != (Image *) NULL) 14967 { 14968 nexus=DestroyImage(nexus); 14969 *state|=NextImageState | ExitState; 14970 } 14971 } 14972 delay=display_image->delay/MagickMax( 14973 display_image->ticks_per_second,1L); 14974 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 14975 } 14976 } 14977 if (XEventsQueued(display,QueuedAfterFlush) == 0) 14978 { 14979 /* 14980 Do not block if delay > 0. 14981 */ 14982 XDelay(display,SuspendTime << 2); 14983 continue; 14984 } 14985 } 14986 timestamp=time((time_t *) NULL); 14987 (void) XNextEvent(display,&event); 14988 if (windows->image.stasis == MagickFalse) 14989 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 14990 MagickTrue : MagickFalse; 14991 if (windows->magnify.stasis == MagickFalse) 14992 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 14993 MagickTrue : MagickFalse; 14994 if (event.xany.window == windows->command.id) 14995 { 14996 /* 14997 Select a command from the Command widget. 14998 */ 14999 id=XCommandWidget(display,windows,CommandMenu,&event); 15000 if (id < 0) 15001 continue; 15002 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15003 command_type=CommandMenus[id]; 15004 if (id < MagickMenus) 15005 { 15006 /* 15007 Select a command from a pop-up menu. 15008 */ 15009 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15010 command); 15011 if (entry < 0) 15012 continue; 15013 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15014 command_type=Commands[id][entry]; 15015 } 15016 if (command_type != NullCommand) 15017 nexus=XMagickCommand(display,resource_info,windows,command_type, 15018 &display_image); 15019 continue; 15020 } 15021 switch (event.type) 15022 { 15023 case ButtonPress: 15024 { 15025 if (display_image->debug != MagickFalse) 15026 (void) LogMagickEvent(X11Event,GetMagickModule(), 15027 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15028 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15029 if ((event.xbutton.button == Button3) && 15030 (event.xbutton.state & Mod1Mask)) 15031 { 15032 /* 15033 Convert Alt-Button3 to Button2. 15034 */ 15035 event.xbutton.button=Button2; 15036 event.xbutton.state&=(~Mod1Mask); 15037 } 15038 if (event.xbutton.window == windows->backdrop.id) 15039 { 15040 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15041 event.xbutton.time); 15042 break; 15043 } 15044 if (event.xbutton.window == windows->image.id) 15045 { 15046 switch (event.xbutton.button) 15047 { 15048 case Button1: 15049 { 15050 if (resource_info->immutable) 15051 { 15052 /* 15053 Select a command from the Virtual menu. 15054 */ 15055 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15056 command); 15057 if (entry >= 0) 15058 nexus=XMagickCommand(display,resource_info,windows, 15059 VirtualCommands[entry],&display_image); 15060 break; 15061 } 15062 /* 15063 Map/unmap Command widget. 15064 */ 15065 if (windows->command.mapped != MagickFalse) 15066 (void) XWithdrawWindow(display,windows->command.id, 15067 windows->command.screen); 15068 else 15069 { 15070 (void) XCommandWidget(display,windows,CommandMenu, 15071 (XEvent *) NULL); 15072 (void) XMapRaised(display,windows->command.id); 15073 } 15074 break; 15075 } 15076 case Button2: 15077 { 15078 /* 15079 User pressed the image magnify button. 15080 */ 15081 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15082 &display_image); 15083 XMagnifyImage(display,windows,&event); 15084 break; 15085 } 15086 case Button3: 15087 { 15088 if (resource_info->immutable) 15089 { 15090 /* 15091 Select a command from the Virtual menu. 15092 */ 15093 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15094 command); 15095 if (entry >= 0) 15096 nexus=XMagickCommand(display,resource_info,windows, 15097 VirtualCommands[entry],&display_image); 15098 break; 15099 } 15100 if (display_image->montage != (char *) NULL) 15101 { 15102 /* 15103 Open or delete a tile from a visual image directory. 15104 */ 15105 nexus=XTileImage(display,resource_info,windows, 15106 display_image,&event); 15107 if (nexus != (Image *) NULL) 15108 *state|=MontageImageState | NextImageState | ExitState; 15109 vid_info.x=(short int) windows->image.x; 15110 vid_info.y=(short int) windows->image.y; 15111 break; 15112 } 15113 /* 15114 Select a command from the Short Cuts menu. 15115 */ 15116 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15117 command); 15118 if (entry >= 0) 15119 nexus=XMagickCommand(display,resource_info,windows, 15120 ShortCutsCommands[entry],&display_image); 15121 break; 15122 } 15123 case Button4: 15124 { 15125 /* 15126 Wheel up. 15127 */ 15128 XTranslateImage(display,windows,*image,XK_Up); 15129 break; 15130 } 15131 case Button5: 15132 { 15133 /* 15134 Wheel down. 15135 */ 15136 XTranslateImage(display,windows,*image,XK_Down); 15137 break; 15138 } 15139 default: 15140 break; 15141 } 15142 break; 15143 } 15144 if (event.xbutton.window == windows->magnify.id) 15145 { 15146 int 15147 factor; 15148 15149 static const char 15150 *MagnifyMenu[] = 15151 { 15152 "2", 15153 "4", 15154 "5", 15155 "6", 15156 "7", 15157 "8", 15158 "9", 15159 "3", 15160 (char *) NULL, 15161 }; 15162 15163 static KeySym 15164 MagnifyCommands[] = 15165 { 15166 XK_2, 15167 XK_4, 15168 XK_5, 15169 XK_6, 15170 XK_7, 15171 XK_8, 15172 XK_9, 15173 XK_3 15174 }; 15175 15176 /* 15177 Select a magnify factor from the pop-up menu. 15178 */ 15179 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15180 if (factor >= 0) 15181 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15182 break; 15183 } 15184 if (event.xbutton.window == windows->pan.id) 15185 { 15186 switch (event.xbutton.button) 15187 { 15188 case Button4: 15189 { 15190 /* 15191 Wheel up. 15192 */ 15193 XTranslateImage(display,windows,*image,XK_Up); 15194 break; 15195 } 15196 case Button5: 15197 { 15198 /* 15199 Wheel down. 15200 */ 15201 XTranslateImage(display,windows,*image,XK_Down); 15202 break; 15203 } 15204 default: 15205 { 15206 XPanImage(display,windows,&event); 15207 break; 15208 } 15209 } 15210 break; 15211 } 15212 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15213 1L); 15214 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15215 break; 15216 } 15217 case ButtonRelease: 15218 { 15219 if (display_image->debug != MagickFalse) 15220 (void) LogMagickEvent(X11Event,GetMagickModule(), 15221 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15222 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15223 break; 15224 } 15225 case ClientMessage: 15226 { 15227 if (display_image->debug != MagickFalse) 15228 (void) LogMagickEvent(X11Event,GetMagickModule(), 15229 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15230 event.xclient.message_type,event.xclient.format,(unsigned long) 15231 event.xclient.data.l[0]); 15232 if (event.xclient.message_type == windows->im_protocols) 15233 { 15234 if (*event.xclient.data.l == (long) windows->im_update_widget) 15235 { 15236 (void) CloneString(&windows->command.name,MagickTitle); 15237 windows->command.data=MagickMenus; 15238 (void) XCommandWidget(display,windows,CommandMenu, 15239 (XEvent *) NULL); 15240 break; 15241 } 15242 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15243 { 15244 /* 15245 Update graphic context and window colormap. 15246 */ 15247 for (i=0; i < (int) number_windows; i++) 15248 { 15249 if (magick_windows[i]->id == windows->icon.id) 15250 continue; 15251 context_values.background=pixel->background_color.pixel; 15252 context_values.foreground=pixel->foreground_color.pixel; 15253 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15254 context_mask,&context_values); 15255 (void) XChangeGC(display,magick_windows[i]->widget_context, 15256 context_mask,&context_values); 15257 context_values.background=pixel->foreground_color.pixel; 15258 context_values.foreground=pixel->background_color.pixel; 15259 context_values.plane_mask=context_values.background ^ 15260 context_values.foreground; 15261 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15262 (size_t) (context_mask | GCPlaneMask), 15263 &context_values); 15264 magick_windows[i]->attributes.background_pixel= 15265 pixel->background_color.pixel; 15266 magick_windows[i]->attributes.border_pixel= 15267 pixel->border_color.pixel; 15268 magick_windows[i]->attributes.colormap=map_info->colormap; 15269 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15270 (unsigned long) magick_windows[i]->mask, 15271 &magick_windows[i]->attributes); 15272 } 15273 if (windows->pan.mapped != MagickFalse) 15274 { 15275 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15276 windows->pan.pixmap); 15277 (void) XClearWindow(display,windows->pan.id); 15278 XDrawPanRectangle(display,windows); 15279 } 15280 if (windows->backdrop.id != (Window) NULL) 15281 (void) XInstallColormap(display,map_info->colormap); 15282 break; 15283 } 15284 if (*event.xclient.data.l == (long) windows->im_former_image) 15285 { 15286 *state|=FormerImageState | ExitState; 15287 break; 15288 } 15289 if (*event.xclient.data.l == (long) windows->im_next_image) 15290 { 15291 *state|=NextImageState | ExitState; 15292 break; 15293 } 15294 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15295 { 15296 *state|=RetainColorsState; 15297 break; 15298 } 15299 if (*event.xclient.data.l == (long) windows->im_exit) 15300 { 15301 *state|=ExitState; 15302 break; 15303 } 15304 break; 15305 } 15306 if (event.xclient.message_type == windows->dnd_protocols) 15307 { 15308 Atom 15309 selection, 15310 type; 15311 15312 int 15313 format, 15314 status; 15315 15316 unsigned char 15317 *data; 15318 15319 unsigned long 15320 after, 15321 length; 15322 15323 /* 15324 Display image named by the Drag-and-Drop selection. 15325 */ 15326 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15327 break; 15328 selection=XInternAtom(display,"DndSelection",MagickFalse); 15329 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15330 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15331 &length,&after,&data); 15332 if ((status != Success) || (length == 0)) 15333 break; 15334 if (*event.xclient.data.l == 2) 15335 { 15336 /* 15337 Offix DND. 15338 */ 15339 (void) CopyMagickString(resource_info->image_info->filename, 15340 (char *) data,MaxTextExtent); 15341 } 15342 else 15343 { 15344 /* 15345 XDND. 15346 */ 15347 if (strncmp((char *) data, "file:", 5) != 0) 15348 { 15349 (void) XFree((void *) data); 15350 break; 15351 } 15352 (void) CopyMagickString(resource_info->image_info->filename, 15353 ((char *) data)+5,MaxTextExtent); 15354 } 15355 nexus=ReadImage(resource_info->image_info, 15356 &display_image->exception); 15357 CatchException(&display_image->exception); 15358 if (nexus != (Image *) NULL) 15359 *state|=NextImageState | ExitState; 15360 (void) XFree((void *) data); 15361 break; 15362 } 15363 /* 15364 If client window delete message, exit. 15365 */ 15366 if (event.xclient.message_type != windows->wm_protocols) 15367 break; 15368 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15369 break; 15370 (void) XWithdrawWindow(display,event.xclient.window, 15371 visual_info->screen); 15372 if (event.xclient.window == windows->image.id) 15373 { 15374 *state|=ExitState; 15375 break; 15376 } 15377 if (event.xclient.window == windows->pan.id) 15378 { 15379 /* 15380 Restore original image size when pan window is deleted. 15381 */ 15382 windows->image.window_changes.width=windows->image.ximage->width; 15383 windows->image.window_changes.height=windows->image.ximage->height; 15384 (void) XConfigureImage(display,resource_info,windows, 15385 display_image); 15386 } 15387 break; 15388 } 15389 case ConfigureNotify: 15390 { 15391 if (display_image->debug != MagickFalse) 15392 (void) LogMagickEvent(X11Event,GetMagickModule(), 15393 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15394 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15395 event.xconfigure.y,event.xconfigure.send_event); 15396 if (event.xconfigure.window == windows->image.id) 15397 { 15398 /* 15399 Image window has a new configuration. 15400 */ 15401 if (event.xconfigure.send_event != 0) 15402 { 15403 XWindowChanges 15404 window_changes; 15405 15406 /* 15407 Position the transient windows relative of the Image window. 15408 */ 15409 if (windows->command.geometry == (char *) NULL) 15410 if (windows->command.mapped == MagickFalse) 15411 { 15412 windows->command.x=event.xconfigure.x- 15413 windows->command.width-25; 15414 windows->command.y=event.xconfigure.y; 15415 XConstrainWindowPosition(display,&windows->command); 15416 window_changes.x=windows->command.x; 15417 window_changes.y=windows->command.y; 15418 (void) XReconfigureWMWindow(display,windows->command.id, 15419 windows->command.screen,(unsigned int) (CWX | CWY), 15420 &window_changes); 15421 } 15422 if (windows->widget.geometry == (char *) NULL) 15423 if (windows->widget.mapped == MagickFalse) 15424 { 15425 windows->widget.x=event.xconfigure.x+ 15426 event.xconfigure.width/10; 15427 windows->widget.y=event.xconfigure.y+ 15428 event.xconfigure.height/10; 15429 XConstrainWindowPosition(display,&windows->widget); 15430 window_changes.x=windows->widget.x; 15431 window_changes.y=windows->widget.y; 15432 (void) XReconfigureWMWindow(display,windows->widget.id, 15433 windows->widget.screen,(unsigned int) (CWX | CWY), 15434 &window_changes); 15435 } 15436 if (windows->magnify.geometry == (char *) NULL) 15437 if (windows->magnify.mapped == MagickFalse) 15438 { 15439 windows->magnify.x=event.xconfigure.x+ 15440 event.xconfigure.width+25; 15441 windows->magnify.y=event.xconfigure.y; 15442 XConstrainWindowPosition(display,&windows->magnify); 15443 window_changes.x=windows->magnify.x; 15444 window_changes.y=windows->magnify.y; 15445 (void) XReconfigureWMWindow(display,windows->magnify.id, 15446 windows->magnify.screen,(unsigned int) (CWX | CWY), 15447 &window_changes); 15448 } 15449 if (windows->pan.geometry == (char *) NULL) 15450 if (windows->pan.mapped == MagickFalse) 15451 { 15452 windows->pan.x=event.xconfigure.x+ 15453 event.xconfigure.width+25; 15454 windows->pan.y=event.xconfigure.y+ 15455 windows->magnify.height+50; 15456 XConstrainWindowPosition(display,&windows->pan); 15457 window_changes.x=windows->pan.x; 15458 window_changes.y=windows->pan.y; 15459 (void) XReconfigureWMWindow(display,windows->pan.id, 15460 windows->pan.screen,(unsigned int) (CWX | CWY), 15461 &window_changes); 15462 } 15463 } 15464 if ((event.xconfigure.width == (int) windows->image.width) && 15465 (event.xconfigure.height == (int) windows->image.height)) 15466 break; 15467 windows->image.width=(unsigned int) event.xconfigure.width; 15468 windows->image.height=(unsigned int) event.xconfigure.height; 15469 windows->image.x=0; 15470 windows->image.y=0; 15471 if (display_image->montage != (char *) NULL) 15472 { 15473 windows->image.x=vid_info.x; 15474 windows->image.y=vid_info.y; 15475 } 15476 if ((windows->image.mapped != MagickFalse) && 15477 (windows->image.stasis != MagickFalse)) 15478 { 15479 /* 15480 Update image window configuration. 15481 */ 15482 windows->image.window_changes.width=event.xconfigure.width; 15483 windows->image.window_changes.height=event.xconfigure.height; 15484 (void) XConfigureImage(display,resource_info,windows, 15485 display_image); 15486 } 15487 /* 15488 Update pan window configuration. 15489 */ 15490 if ((event.xconfigure.width < windows->image.ximage->width) || 15491 (event.xconfigure.height < windows->image.ximage->height)) 15492 { 15493 (void) XMapRaised(display,windows->pan.id); 15494 XDrawPanRectangle(display,windows); 15495 } 15496 else 15497 if (windows->pan.mapped != MagickFalse) 15498 (void) XWithdrawWindow(display,windows->pan.id, 15499 windows->pan.screen); 15500 break; 15501 } 15502 if (event.xconfigure.window == windows->magnify.id) 15503 { 15504 unsigned int 15505 magnify; 15506 15507 /* 15508 Magnify window has a new configuration. 15509 */ 15510 windows->magnify.width=(unsigned int) event.xconfigure.width; 15511 windows->magnify.height=(unsigned int) event.xconfigure.height; 15512 if (windows->magnify.mapped == MagickFalse) 15513 break; 15514 magnify=1; 15515 while ((int) magnify <= event.xconfigure.width) 15516 magnify<<=1; 15517 while ((int) magnify <= event.xconfigure.height) 15518 magnify<<=1; 15519 magnify>>=1; 15520 if (((int) magnify != event.xconfigure.width) || 15521 ((int) magnify != event.xconfigure.height)) 15522 { 15523 window_changes.width=(int) magnify; 15524 window_changes.height=(int) magnify; 15525 (void) XReconfigureWMWindow(display,windows->magnify.id, 15526 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15527 &window_changes); 15528 break; 15529 } 15530 if ((windows->magnify.mapped != MagickFalse) && 15531 (windows->magnify.stasis != MagickFalse)) 15532 { 15533 status=XMakeImage(display,resource_info,&windows->magnify, 15534 display_image,windows->magnify.width,windows->magnify.height); 15535 XMakeMagnifyImage(display,windows); 15536 } 15537 break; 15538 } 15539 if ((windows->magnify.mapped != MagickFalse) && 15540 (event.xconfigure.window == windows->pan.id)) 15541 { 15542 /* 15543 Pan icon window has a new configuration. 15544 */ 15545 if (event.xconfigure.send_event != 0) 15546 { 15547 windows->pan.x=event.xconfigure.x; 15548 windows->pan.y=event.xconfigure.y; 15549 } 15550 windows->pan.width=(unsigned int) event.xconfigure.width; 15551 windows->pan.height=(unsigned int) event.xconfigure.height; 15552 break; 15553 } 15554 if (event.xconfigure.window == windows->icon.id) 15555 { 15556 /* 15557 Icon window has a new configuration. 15558 */ 15559 windows->icon.width=(unsigned int) event.xconfigure.width; 15560 windows->icon.height=(unsigned int) event.xconfigure.height; 15561 break; 15562 } 15563 break; 15564 } 15565 case DestroyNotify: 15566 { 15567 /* 15568 Group leader has exited. 15569 */ 15570 if (display_image->debug != MagickFalse) 15571 (void) LogMagickEvent(X11Event,GetMagickModule(), 15572 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15573 if (event.xdestroywindow.window == windows->group_leader.id) 15574 { 15575 *state|=ExitState; 15576 break; 15577 } 15578 break; 15579 } 15580 case EnterNotify: 15581 { 15582 /* 15583 Selectively install colormap. 15584 */ 15585 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15586 if (event.xcrossing.mode != NotifyUngrab) 15587 XInstallColormap(display,map_info->colormap); 15588 break; 15589 } 15590 case Expose: 15591 { 15592 if (display_image->debug != MagickFalse) 15593 (void) LogMagickEvent(X11Event,GetMagickModule(), 15594 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15595 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15596 event.xexpose.y); 15597 /* 15598 Refresh windows that are now exposed. 15599 */ 15600 if ((event.xexpose.window == windows->image.id) && 15601 (windows->image.mapped != MagickFalse)) 15602 { 15603 XRefreshWindow(display,&windows->image,&event); 15604 delay=display_image->delay/MagickMax( 15605 display_image->ticks_per_second,1L); 15606 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15607 break; 15608 } 15609 if ((event.xexpose.window == windows->magnify.id) && 15610 (windows->magnify.mapped != MagickFalse)) 15611 { 15612 XMakeMagnifyImage(display,windows); 15613 break; 15614 } 15615 if (event.xexpose.window == windows->pan.id) 15616 { 15617 XDrawPanRectangle(display,windows); 15618 break; 15619 } 15620 if (event.xexpose.window == windows->icon.id) 15621 { 15622 XRefreshWindow(display,&windows->icon,&event); 15623 break; 15624 } 15625 break; 15626 } 15627 case KeyPress: 15628 { 15629 int 15630 length; 15631 15632 /* 15633 Respond to a user key press. 15634 */ 15635 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15636 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15637 *(command+length)='\0'; 15638 if (display_image->debug != MagickFalse) 15639 (void) LogMagickEvent(X11Event,GetMagickModule(), 15640 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15641 key_symbol,command); 15642 if (event.xkey.window == windows->image.id) 15643 { 15644 command_type=XImageWindowCommand(display,resource_info,windows, 15645 event.xkey.state,key_symbol,&display_image); 15646 if (command_type != NullCommand) 15647 nexus=XMagickCommand(display,resource_info,windows,command_type, 15648 &display_image); 15649 } 15650 if (event.xkey.window == windows->magnify.id) 15651 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15652 if (event.xkey.window == windows->pan.id) 15653 { 15654 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15655 (void) XWithdrawWindow(display,windows->pan.id, 15656 windows->pan.screen); 15657 else 15658 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15659 XTextViewWidget(display,resource_info,windows,MagickFalse, 15660 "Help Viewer - Image Pan",ImagePanHelp); 15661 else 15662 XTranslateImage(display,windows,*image,key_symbol); 15663 } 15664 delay=display_image->delay/MagickMax( 15665 display_image->ticks_per_second,1L); 15666 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15667 break; 15668 } 15669 case KeyRelease: 15670 { 15671 /* 15672 Respond to a user key release. 15673 */ 15674 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15675 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15676 if (display_image->debug != MagickFalse) 15677 (void) LogMagickEvent(X11Event,GetMagickModule(), 15678 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15679 break; 15680 } 15681 case LeaveNotify: 15682 { 15683 /* 15684 Selectively uninstall colormap. 15685 */ 15686 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15687 if (event.xcrossing.mode != NotifyUngrab) 15688 XUninstallColormap(display,map_info->colormap); 15689 break; 15690 } 15691 case MapNotify: 15692 { 15693 if (display_image->debug != MagickFalse) 15694 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15695 event.xmap.window); 15696 if (event.xmap.window == windows->backdrop.id) 15697 { 15698 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15699 CurrentTime); 15700 windows->backdrop.mapped=MagickTrue; 15701 break; 15702 } 15703 if (event.xmap.window == windows->image.id) 15704 { 15705 if (windows->backdrop.id != (Window) NULL) 15706 (void) XInstallColormap(display,map_info->colormap); 15707 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15708 { 15709 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15710 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15711 } 15712 if (((int) windows->image.width < windows->image.ximage->width) || 15713 ((int) windows->image.height < windows->image.ximage->height)) 15714 (void) XMapRaised(display,windows->pan.id); 15715 windows->image.mapped=MagickTrue; 15716 break; 15717 } 15718 if (event.xmap.window == windows->magnify.id) 15719 { 15720 XMakeMagnifyImage(display,windows); 15721 windows->magnify.mapped=MagickTrue; 15722 (void) XWithdrawWindow(display,windows->info.id, 15723 windows->info.screen); 15724 break; 15725 } 15726 if (event.xmap.window == windows->pan.id) 15727 { 15728 XMakePanImage(display,resource_info,windows,display_image); 15729 windows->pan.mapped=MagickTrue; 15730 break; 15731 } 15732 if (event.xmap.window == windows->info.id) 15733 { 15734 windows->info.mapped=MagickTrue; 15735 break; 15736 } 15737 if (event.xmap.window == windows->icon.id) 15738 { 15739 MagickBooleanType 15740 taint; 15741 15742 /* 15743 Create an icon image. 15744 */ 15745 taint=display_image->taint; 15746 XMakeStandardColormap(display,icon_visual,icon_resources, 15747 display_image,icon_map,icon_pixel); 15748 (void) XMakeImage(display,icon_resources,&windows->icon, 15749 display_image,windows->icon.width,windows->icon.height); 15750 display_image->taint=taint; 15751 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15752 windows->icon.pixmap); 15753 (void) XClearWindow(display,windows->icon.id); 15754 (void) XWithdrawWindow(display,windows->info.id, 15755 windows->info.screen); 15756 windows->icon.mapped=MagickTrue; 15757 break; 15758 } 15759 if (event.xmap.window == windows->command.id) 15760 { 15761 windows->command.mapped=MagickTrue; 15762 break; 15763 } 15764 if (event.xmap.window == windows->popup.id) 15765 { 15766 windows->popup.mapped=MagickTrue; 15767 break; 15768 } 15769 if (event.xmap.window == windows->widget.id) 15770 { 15771 windows->widget.mapped=MagickTrue; 15772 break; 15773 } 15774 break; 15775 } 15776 case MappingNotify: 15777 { 15778 (void) XRefreshKeyboardMapping(&event.xmapping); 15779 break; 15780 } 15781 case NoExpose: 15782 break; 15783 case PropertyNotify: 15784 { 15785 Atom 15786 type; 15787 15788 int 15789 format, 15790 status; 15791 15792 unsigned char 15793 *data; 15794 15795 unsigned long 15796 after, 15797 length; 15798 15799 if (display_image->debug != MagickFalse) 15800 (void) LogMagickEvent(X11Event,GetMagickModule(), 15801 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15802 event.xproperty.atom,event.xproperty.state); 15803 if (event.xproperty.atom != windows->im_remote_command) 15804 break; 15805 /* 15806 Display image named by the remote command protocol. 15807 */ 15808 status=XGetWindowProperty(display,event.xproperty.window, 15809 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15810 AnyPropertyType,&type,&format,&length,&after,&data); 15811 if ((status != Success) || (length == 0)) 15812 break; 15813 if (LocaleCompare((char *) data,"-quit") == 0) 15814 { 15815 XClientMessage(display,windows->image.id,windows->im_protocols, 15816 windows->im_exit,CurrentTime); 15817 (void) XFree((void *) data); 15818 break; 15819 } 15820 (void) CopyMagickString(resource_info->image_info->filename, 15821 (char *) data,MaxTextExtent); 15822 (void) XFree((void *) data); 15823 nexus=ReadImage(resource_info->image_info,&display_image->exception); 15824 CatchException(&display_image->exception); 15825 if (nexus != (Image *) NULL) 15826 *state|=NextImageState | ExitState; 15827 break; 15828 } 15829 case ReparentNotify: 15830 { 15831 if (display_image->debug != MagickFalse) 15832 (void) LogMagickEvent(X11Event,GetMagickModule(), 15833 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15834 event.xreparent.window); 15835 break; 15836 } 15837 case UnmapNotify: 15838 { 15839 if (display_image->debug != MagickFalse) 15840 (void) LogMagickEvent(X11Event,GetMagickModule(), 15841 "Unmap Notify: 0x%lx",event.xunmap.window); 15842 if (event.xunmap.window == windows->backdrop.id) 15843 { 15844 windows->backdrop.mapped=MagickFalse; 15845 break; 15846 } 15847 if (event.xunmap.window == windows->image.id) 15848 { 15849 windows->image.mapped=MagickFalse; 15850 break; 15851 } 15852 if (event.xunmap.window == windows->magnify.id) 15853 { 15854 windows->magnify.mapped=MagickFalse; 15855 break; 15856 } 15857 if (event.xunmap.window == windows->pan.id) 15858 { 15859 windows->pan.mapped=MagickFalse; 15860 break; 15861 } 15862 if (event.xunmap.window == windows->info.id) 15863 { 15864 windows->info.mapped=MagickFalse; 15865 break; 15866 } 15867 if (event.xunmap.window == windows->icon.id) 15868 { 15869 if (map_info->colormap == icon_map->colormap) 15870 XConfigureImageColormap(display,resource_info,windows, 15871 display_image); 15872 (void) XFreeStandardColormap(display,icon_visual,icon_map, 15873 icon_pixel); 15874 windows->icon.mapped=MagickFalse; 15875 break; 15876 } 15877 if (event.xunmap.window == windows->command.id) 15878 { 15879 windows->command.mapped=MagickFalse; 15880 break; 15881 } 15882 if (event.xunmap.window == windows->popup.id) 15883 { 15884 if (windows->backdrop.id != (Window) NULL) 15885 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15886 CurrentTime); 15887 windows->popup.mapped=MagickFalse; 15888 break; 15889 } 15890 if (event.xunmap.window == windows->widget.id) 15891 { 15892 if (windows->backdrop.id != (Window) NULL) 15893 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15894 CurrentTime); 15895 windows->widget.mapped=MagickFalse; 15896 break; 15897 } 15898 break; 15899 } 15900 default: 15901 { 15902 if (display_image->debug != MagickFalse) 15903 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 15904 event.type); 15905 break; 15906 } 15907 } 15908 } while (!(*state & ExitState)); 15909 if ((*state & ExitState) == 0) 15910 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 15911 &display_image); 15912 else 15913 if (resource_info->confirm_edit != MagickFalse) 15914 { 15915 /* 15916 Query user if image has changed. 15917 */ 15918 if ((resource_info->immutable == MagickFalse) && 15919 (display_image->taint != MagickFalse)) 15920 { 15921 int 15922 status; 15923 15924 status=XConfirmWidget(display,windows,"Your image changed.", 15925 "Do you want to save it"); 15926 if (status == 0) 15927 *state&=(~ExitState); 15928 else 15929 if (status > 0) 15930 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 15931 &display_image); 15932 } 15933 } 15934 if ((windows->visual_info->klass == GrayScale) || 15935 (windows->visual_info->klass == PseudoColor) || 15936 (windows->visual_info->klass == DirectColor)) 15937 { 15938 /* 15939 Withdraw pan and Magnify window. 15940 */ 15941 if (windows->info.mapped != MagickFalse) 15942 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15943 if (windows->magnify.mapped != MagickFalse) 15944 (void) XWithdrawWindow(display,windows->magnify.id, 15945 windows->magnify.screen); 15946 if (windows->command.mapped != MagickFalse) 15947 (void) XWithdrawWindow(display,windows->command.id, 15948 windows->command.screen); 15949 } 15950 if (windows->pan.mapped != MagickFalse) 15951 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 15952 if (resource_info->backdrop == MagickFalse) 15953 if (windows->backdrop.mapped) 15954 { 15955 (void) XWithdrawWindow(display,windows->backdrop.id, 15956 windows->backdrop.screen); 15957 (void) XDestroyWindow(display,windows->backdrop.id); 15958 windows->backdrop.id=(Window) NULL; 15959 (void) XWithdrawWindow(display,windows->image.id, 15960 windows->image.screen); 15961 (void) XDestroyWindow(display,windows->image.id); 15962 windows->image.id=(Window) NULL; 15963 } 15964 XSetCursorState(display,windows,MagickTrue); 15965 XCheckRefreshWindows(display,windows); 15966 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 15967 *state&=(~ExitState); 15968 if (*state & ExitState) 15969 { 15970 /* 15971 Free Standard Colormap. 15972 */ 15973 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 15974 if (resource_info->map_type == (char *) NULL) 15975 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 15976 /* 15977 Free X resources. 15978 */ 15979 if (resource_info->copy_image != (Image *) NULL) 15980 { 15981 resource_info->copy_image=DestroyImage(resource_info->copy_image); 15982 resource_info->copy_image=NewImageList(); 15983 } 15984 DestroyXResources(); 15985 } 15986 (void) XSync(display,MagickFalse); 15987 /* 15988 Restore our progress monitor and warning handlers. 15989 */ 15990 (void) SetErrorHandler(warning_handler); 15991 (void) SetWarningHandler(warning_handler); 15992 /* 15993 Change to home directory. 15994 */ 15995 directory=getcwd(working_directory,MaxTextExtent); 15996 (void) directory; 15997 { 15998 int 15999 status; 16000 16001 status=chdir(resource_info->home_directory); 16002 if (status == -1) 16003 (void) ThrowMagickException(&display_image->exception,GetMagickModule(), 16004 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 16005 } 16006 *image=display_image; 16007 return(nexus); 16008} 16009#else 16010 16011/* 16012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16013% % 16014% % 16015% % 16016+ D i s p l a y I m a g e s % 16017% % 16018% % 16019% % 16020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16021% 16022% DisplayImages() displays an image sequence to any X window screen. It 16023% returns a value other than 0 if successful. Check the exception member 16024% of image to determine the reason for any failure. 16025% 16026% The format of the DisplayImages method is: 16027% 16028% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16029% Image *images) 16030% 16031% A description of each parameter follows: 16032% 16033% o image_info: the image info. 16034% 16035% o image: the image. 16036% 16037*/ 16038MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16039 Image *image) 16040{ 16041 assert(image_info != (const ImageInfo *) NULL); 16042 assert(image_info->signature == MagickSignature); 16043 assert(image != (Image *) NULL); 16044 assert(image->signature == MagickSignature); 16045 if (image->debug != MagickFalse) 16046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16047 (void) ThrowMagickException(&image->exception,GetMagickModule(), 16048 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)", 16049 image->filename); 16050 return(MagickFalse); 16051} 16052 16053/* 16054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16055% % 16056% % 16057% % 16058+ R e m o t e D i s p l a y C o m m a n d % 16059% % 16060% % 16061% % 16062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16063% 16064% RemoteDisplayCommand() encourages a remote display program to display the 16065% specified image filename. 16066% 16067% The format of the RemoteDisplayCommand method is: 16068% 16069% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16070% const char *window,const char *filename,ExceptionInfo *exception) 16071% 16072% A description of each parameter follows: 16073% 16074% o image_info: the image info. 16075% 16076% o window: Specifies the name or id of an X window. 16077% 16078% o filename: the name of the image filename to display. 16079% 16080% o exception: return any errors or warnings in this structure. 16081% 16082*/ 16083MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16084 const char *window,const char *filename,ExceptionInfo *exception) 16085{ 16086 assert(image_info != (const ImageInfo *) NULL); 16087 assert(image_info->signature == MagickSignature); 16088 assert(filename != (char *) NULL); 16089 (void) window; 16090 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16091 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16092 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16093 return(MagickFalse); 16094} 16095#endif 16096