display.c revision f05d4947caf1bc27fbec041eb37c474a80c83c0b
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-2012 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/cache-private.h" 47#include "MagickCore/client.h" 48#include "MagickCore/color.h" 49#include "MagickCore/colorspace.h" 50#include "MagickCore/composite.h" 51#include "MagickCore/constitute.h" 52#include "MagickCore/decorate.h" 53#include "MagickCore/delegate.h" 54#include "MagickCore/display.h" 55#include "MagickCore/display-private.h" 56#include "MagickCore/distort.h" 57#include "MagickCore/draw.h" 58#include "MagickCore/effect.h" 59#include "MagickCore/enhance.h" 60#include "MagickCore/exception.h" 61#include "MagickCore/exception-private.h" 62#include "MagickCore/fx.h" 63#include "MagickCore/geometry.h" 64#include "MagickCore/image.h" 65#include "MagickCore/image-private.h" 66#include "MagickCore/list.h" 67#include "MagickCore/log.h" 68#include "MagickCore/magick.h" 69#include "MagickCore/memory_.h" 70#include "MagickCore/monitor.h" 71#include "MagickCore/monitor-private.h" 72#include "MagickCore/montage.h" 73#include "MagickCore/option.h" 74#include "MagickCore/paint.h" 75#include "MagickCore/pixel.h" 76#include "MagickCore/pixel-accessor.h" 77#include "MagickCore/PreRvIcccm.h" 78#include "MagickCore/property.h" 79#include "MagickCore/quantum.h" 80#include "MagickCore/quantum-private.h" 81#include "MagickCore/resize.h" 82#include "MagickCore/resource_.h" 83#include "MagickCore/shear.h" 84#include "MagickCore/segment.h" 85#include "MagickCore/statistic.h" 86#include "MagickCore/string_.h" 87#include "MagickCore/string-private.h" 88#include "MagickCore/transform.h" 89#include "MagickCore/threshold.h" 90#include "MagickCore/utility.h" 91#include "MagickCore/utility-private.h" 92#include "MagickCore/version.h" 93#include "MagickCore/widget.h" 94#include "MagickCore/widget-private.h" 95#include "MagickCore/xwindow.h" 96#include "MagickCore/xwindow-private.h" 97 98#if defined(MAGICKCORE_X11_DELEGATE) 99/* 100 Define declarations. 101*/ 102#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 103 104/* 105 Constant declarations. 106*/ 107static const unsigned char 108 HighlightBitmap[8] = 109 { 110 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 111 }, 112 OpaqueBitmap[8] = 113 { 114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 115 }, 116 ShadowBitmap[8] = 117 { 118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 119 }; 120 121static const char 122 *PageSizes[] = 123 { 124 "Letter", 125 "Tabloid", 126 "Ledger", 127 "Legal", 128 "Statement", 129 "Executive", 130 "A3", 131 "A4", 132 "A5", 133 "B4", 134 "B5", 135 "Folio", 136 "Quarto", 137 "10x14", 138 (char *) NULL 139 }; 140 141/* 142 Help widget declarations. 143*/ 144static const char 145 *ImageAnnotateHelp[] = 146 { 147 "In annotate mode, the Command widget has these options:", 148 "", 149 " Font Name", 150 " fixed", 151 " variable", 152 " 5x8", 153 " 6x10", 154 " 7x13bold", 155 " 8x13bold", 156 " 9x15bold", 157 " 10x20", 158 " 12x24", 159 " Browser...", 160 " Font Color", 161 " black", 162 " blue", 163 " cyan", 164 " green", 165 " gray", 166 " red", 167 " magenta", 168 " yellow", 169 " white", 170 " transparent", 171 " Browser...", 172 " Font Color", 173 " black", 174 " blue", 175 " cyan", 176 " green", 177 " gray", 178 " red", 179 " magenta", 180 " yellow", 181 " white", 182 " transparent", 183 " Browser...", 184 " Rotate Text", 185 " -90", 186 " -45", 187 " -30", 188 " 0", 189 " 30", 190 " 45", 191 " 90", 192 " 180", 193 " Dialog...", 194 " Help", 195 " Dismiss", 196 "", 197 "Choose a font name from the Font Name sub-menu. Additional", 198 "font names can be specified with the font browser. You can", 199 "change the menu names by setting the X resources font1", 200 "through font9.", 201 "", 202 "Choose a font color from the Font Color sub-menu.", 203 "Additional font colors can be specified with the color", 204 "browser. You can change the menu colors by setting the X", 205 "resources pen1 through pen9.", 206 "", 207 "If you select the color browser and press Grab, you can", 208 "choose the font color by moving the pointer to the desired", 209 "color on the screen and press any button.", 210 "", 211 "If you choose to rotate the text, choose Rotate Text from the", 212 "menu and select an angle. Typically you will only want to", 213 "rotate one line of text at a time. Depending on the angle you", 214 "choose, subsequent lines may end up overwriting each other.", 215 "", 216 "Choosing a font and its color is optional. The default font", 217 "is fixed and the default color is black. However, you must", 218 "choose a location to begin entering text and press button 1.", 219 "An underscore character will appear at the location of the", 220 "pointer. The cursor changes to a pencil to indicate you are", 221 "in text mode. To exit immediately, press Dismiss.", 222 "", 223 "In text mode, any key presses will display the character at", 224 "the location of the underscore and advance the underscore", 225 "cursor. Enter your text and once completed press Apply to", 226 "finish your image annotation. To correct errors press BACK", 227 "SPACE. To delete an entire line of text, press DELETE. Any", 228 "text that exceeds the boundaries of the image window is", 229 "automagically continued onto the next line.", 230 "", 231 "The actual color you request for the font is saved in the", 232 "image. However, the color that appears in your image window", 233 "may be different. For example, on a monochrome screen the", 234 "text will appear black or white even if you choose the color", 235 "red as the font color. However, the image saved to a file", 236 "with -write is written with red lettering. To assure the", 237 "correct color text in the final image, any PseudoClass image", 238 "is promoted to DirectClass (see miff(5)). To force a", 239 "PseudoClass image to remain PseudoClass, use -colors.", 240 (char *) NULL, 241 }, 242 *ImageChopHelp[] = 243 { 244 "In chop mode, the Command widget has these options:", 245 "", 246 " Direction", 247 " horizontal", 248 " vertical", 249 " Help", 250 " Dismiss", 251 "", 252 "If the you choose the horizontal direction (this the", 253 "default), the area of the image between the two horizontal", 254 "endpoints of the chop line is removed. Otherwise, the area", 255 "of the image between the two vertical endpoints of the chop", 256 "line is removed.", 257 "", 258 "Select a location within the image window to begin your chop,", 259 "press and hold any button. Next, move the pointer to", 260 "another location in the image. As you move a line will", 261 "connect the initial location and the pointer. When you", 262 "release the button, the area within the image to chop is", 263 "determined by which direction you choose from the Command", 264 "widget.", 265 "", 266 "To cancel the image chopping, move the pointer back to the", 267 "starting point of the line and release the button.", 268 (char *) NULL, 269 }, 270 *ImageColorEditHelp[] = 271 { 272 "In color edit mode, the Command widget has these options:", 273 "", 274 " Method", 275 " point", 276 " replace", 277 " floodfill", 278 " filltoborder", 279 " reset", 280 " Pixel Color", 281 " black", 282 " blue", 283 " cyan", 284 " green", 285 " gray", 286 " red", 287 " magenta", 288 " yellow", 289 " white", 290 " Browser...", 291 " Border Color", 292 " black", 293 " blue", 294 " cyan", 295 " green", 296 " gray", 297 " red", 298 " magenta", 299 " yellow", 300 " white", 301 " Browser...", 302 " Fuzz", 303 " 0%", 304 " 2%", 305 " 5%", 306 " 10%", 307 " 15%", 308 " Dialog...", 309 " Undo", 310 " Help", 311 " Dismiss", 312 "", 313 "Choose a color editing method from the Method sub-menu", 314 "of the Command widget. The point method recolors any pixel", 315 "selected with the pointer until the button is released. The", 316 "replace method recolors any pixel that matches the color of", 317 "the pixel you select with a button press. Floodfill recolors", 318 "any pixel that matches the color of the pixel you select with", 319 "a button press and is a neighbor. Whereas filltoborder recolors", 320 "any neighbor pixel that is not the border color. Finally reset", 321 "changes the entire image to the designated color.", 322 "", 323 "Next, choose a pixel color from the Pixel Color sub-menu.", 324 "Additional pixel colors can be specified with the color", 325 "browser. You can change the menu colors by setting the X", 326 "resources pen1 through pen9.", 327 "", 328 "Now press button 1 to select a pixel within the image window", 329 "to change its color. Additional pixels may be recolored as", 330 "prescribed by the method you choose.", 331 "", 332 "If the Magnify widget is mapped, it can be helpful in positioning", 333 "your pointer within the image (refer to button 2).", 334 "", 335 "The actual color you request for the pixels is saved in the", 336 "image. However, the color that appears in your image window", 337 "may be different. For example, on a monochrome screen the", 338 "pixel will appear black or white even if you choose the", 339 "color red as the pixel color. However, the image saved to a", 340 "file with -write is written with red pixels. To assure the", 341 "correct color text in the final image, any PseudoClass image", 342 "is promoted to DirectClass (see miff(5)). To force a", 343 "PseudoClass image to remain PseudoClass, use -colors.", 344 (char *) NULL, 345 }, 346 *ImageCompositeHelp[] = 347 { 348 "First a widget window is displayed requesting you to enter an", 349 "image name. Press Composite, Grab or type a file name.", 350 "Press Cancel if you choose not to create a composite image.", 351 "When you choose Grab, move the pointer to the desired window", 352 "and press any button.", 353 "", 354 "If the Composite image does not have any matte information,", 355 "you are informed and the file browser is displayed again.", 356 "Enter the name of a mask image. The image is typically", 357 "grayscale and the same size as the composite image. If the", 358 "image is not grayscale, it is converted to grayscale and the", 359 "resulting intensities are used as matte information.", 360 "", 361 "A small window appears showing the location of the cursor in", 362 "the image window. You are now in composite mode. To exit", 363 "immediately, press Dismiss. In composite mode, the Command", 364 "widget has these options:", 365 "", 366 " Operators", 367 " Over", 368 " In", 369 " Out", 370 " Atop", 371 " Xor", 372 " Plus", 373 " Minus", 374 " Add", 375 " Subtract", 376 " Difference", 377 " Multiply", 378 " Bumpmap", 379 " Copy", 380 " CopyRed", 381 " CopyGreen", 382 " CopyBlue", 383 " CopyOpacity", 384 " Clear", 385 " Dissolve", 386 " Displace", 387 " Help", 388 " Dismiss", 389 "", 390 "Choose a composite operation from the Operators sub-menu of", 391 "the Command widget. How each operator behaves is described", 392 "below. Image window is the image currently displayed on", 393 "your X server and image is the image obtained with the File", 394 "Browser widget.", 395 "", 396 "Over The result is the union of the two image shapes,", 397 " with image obscuring image window in the region of", 398 " overlap.", 399 "", 400 "In The result is simply image cut by the shape of", 401 " image window. None of the image data of image", 402 " window is in the result.", 403 "", 404 "Out The resulting image is image with the shape of", 405 " image window cut out.", 406 "", 407 "Atop The result is the same shape as image image window,", 408 " with image obscuring image window where the image", 409 " shapes overlap. Note this differs from over", 410 " because the portion of image outside image window's", 411 " shape does not appear in the result.", 412 "", 413 "Xor The result is the image data from both image and", 414 " image window that is outside the overlap region.", 415 " The overlap region is blank.", 416 "", 417 "Plus The result is just the sum of the image data.", 418 " Output values are cropped to QuantumRange (no overflow).", 419 "", 420 "Minus The result of image - image window, with underflow", 421 " cropped to zero.", 422 "", 423 "Add The result of image + image window, with overflow", 424 " wrapping around (mod 256).", 425 "", 426 "Subtract The result of image - image window, with underflow", 427 " wrapping around (mod 256). The add and subtract", 428 " operators can be used to perform reversible", 429 " transformations.", 430 "", 431 "Difference", 432 " The result of abs(image - image window). This", 433 " useful for comparing two very similar images.", 434 "", 435 "Multiply", 436 " The result of image * image window. This", 437 " useful for the creation of drop-shadows.", 438 "", 439 "Bumpmap The result of surface normals from image * image", 440 " window.", 441 "", 442 "Copy The resulting image is image window replaced with", 443 " image. Here the matte information is ignored.", 444 "", 445 "CopyRed The red layer of the image window is replace with", 446 " the red layer of the image. The other layers are", 447 " untouched.", 448 "", 449 "CopyGreen", 450 " The green layer of the image window is replace with", 451 " the green layer of the image. The other layers are", 452 " untouched.", 453 "", 454 "CopyBlue The blue layer of the image window is replace with", 455 " the blue layer of the image. The other layers are", 456 " untouched.", 457 "", 458 "CopyOpacity", 459 " The matte layer of the image window is replace with", 460 " the matte layer of the image. The other layers are", 461 " untouched.", 462 "", 463 "The image compositor requires a matte, or alpha channel in", 464 "the image for some operations. This extra channel usually", 465 "defines a mask which represents a sort of a cookie-cutter", 466 "for the image. This the case when matte is opaque (full", 467 "coverage) for pixels inside the shape, zero outside, and", 468 "between 0 and QuantumRange on the boundary. If image does not", 469 "have a matte channel, it is initialized with 0 for any pixel", 470 "matching in color to pixel location (0,0), otherwise QuantumRange.", 471 "", 472 "If you choose Dissolve, the composite operator becomes Over. The", 473 "image matte channel percent transparency is initialized to factor.", 474 "The image window is initialized to (100-factor). Where factor is the", 475 "value you specify in the Dialog widget.", 476 "", 477 "Displace shifts the image pixels as defined by a displacement", 478 "map. With this option, image is used as a displacement map.", 479 "Black, within the displacement map, is a maximum positive", 480 "displacement. White is a maximum negative displacement and", 481 "middle gray is neutral. The displacement is scaled to determine", 482 "the pixel shift. By default, the displacement applies in both the", 483 "horizontal and vertical directions. However, if you specify a mask,", 484 "image is the horizontal X displacement and mask the vertical Y", 485 "displacement.", 486 "", 487 "Note that matte information for image window is not retained", 488 "for colormapped X server visuals (e.g. StaticColor,", 489 "StaticColor, GrayScale, PseudoColor). Correct compositing", 490 "behavior may require a TrueColor or DirectColor visual or a", 491 "Standard Colormap.", 492 "", 493 "Choosing a composite operator is optional. The default", 494 "operator is replace. However, you must choose a location to", 495 "composite your image and press button 1. Press and hold the", 496 "button before releasing and an outline of the image will", 497 "appear to help you identify your location.", 498 "", 499 "The actual colors of the composite image is saved. However,", 500 "the color that appears in image window may be different.", 501 "For example, on a monochrome screen image window will appear", 502 "black or white even though your composited image may have", 503 "many colors. If the image is saved to a file it is written", 504 "with the correct colors. To assure the correct colors are", 505 "saved in the final image, any PseudoClass image is promoted", 506 "to DirectClass (see miff(5)). To force a PseudoClass image", 507 "to remain PseudoClass, use -colors.", 508 (char *) NULL, 509 }, 510 *ImageCutHelp[] = 511 { 512 "In cut mode, the Command widget has these options:", 513 "", 514 " Help", 515 " Dismiss", 516 "", 517 "To define a cut region, press button 1 and drag. The", 518 "cut region is defined by a highlighted rectangle that", 519 "expands or contracts as it follows the pointer. Once you", 520 "are satisfied with the cut region, release the button.", 521 "You are now in rectify mode. In rectify mode, the Command", 522 "widget has these options:", 523 "", 524 " Cut", 525 " Help", 526 " Dismiss", 527 "", 528 "You can make adjustments by moving the pointer to one of the", 529 "cut rectangle corners, pressing a button, and dragging.", 530 "Finally, press Cut to commit your copy region. To", 531 "exit without cutting the image, press Dismiss.", 532 (char *) NULL, 533 }, 534 *ImageCopyHelp[] = 535 { 536 "In copy mode, the Command widget has these options:", 537 "", 538 " Help", 539 " Dismiss", 540 "", 541 "To define a copy region, press button 1 and drag. The", 542 "copy region is defined by a highlighted rectangle that", 543 "expands or contracts as it follows the pointer. Once you", 544 "are satisfied with the copy region, release the button.", 545 "You are now in rectify mode. In rectify mode, the Command", 546 "widget has these options:", 547 "", 548 " Copy", 549 " Help", 550 " Dismiss", 551 "", 552 "You can make adjustments by moving the pointer to one of the", 553 "copy rectangle corners, pressing a button, and dragging.", 554 "Finally, press Copy to commit your copy region. To", 555 "exit without copying the image, press Dismiss.", 556 (char *) NULL, 557 }, 558 *ImageCropHelp[] = 559 { 560 "In crop mode, the Command widget has these options:", 561 "", 562 " Help", 563 " Dismiss", 564 "", 565 "To define a cropping region, press button 1 and drag. The", 566 "cropping region is defined by a highlighted rectangle that", 567 "expands or contracts as it follows the pointer. Once you", 568 "are satisfied with the cropping region, release the button.", 569 "You are now in rectify mode. In rectify mode, the Command", 570 "widget has these options:", 571 "", 572 " Crop", 573 " Help", 574 " Dismiss", 575 "", 576 "You can make adjustments by moving the pointer to one of the", 577 "cropping rectangle corners, pressing a button, and dragging.", 578 "Finally, press Crop to commit your cropping region. To", 579 "exit without cropping the image, press Dismiss.", 580 (char *) NULL, 581 }, 582 *ImageDrawHelp[] = 583 { 584 "The cursor changes to a crosshair to indicate you are in", 585 "draw mode. To exit immediately, press Dismiss. In draw mode,", 586 "the Command widget has these options:", 587 "", 588 " Element", 589 " point", 590 " line", 591 " rectangle", 592 " fill rectangle", 593 " circle", 594 " fill circle", 595 " ellipse", 596 " fill ellipse", 597 " polygon", 598 " fill polygon", 599 " Color", 600 " black", 601 " blue", 602 " cyan", 603 " green", 604 " gray", 605 " red", 606 " magenta", 607 " yellow", 608 " white", 609 " transparent", 610 " Browser...", 611 " Stipple", 612 " Brick", 613 " Diagonal", 614 " Scales", 615 " Vertical", 616 " Wavy", 617 " Translucent", 618 " Opaque", 619 " Open...", 620 " Width", 621 " 1", 622 " 2", 623 " 4", 624 " 8", 625 " 16", 626 " Dialog...", 627 " Undo", 628 " Help", 629 " Dismiss", 630 "", 631 "Choose a drawing primitive from the Element sub-menu.", 632 "", 633 "Choose a color from the Color sub-menu. Additional", 634 "colors can be specified with the color browser.", 635 "", 636 "If you choose the color browser and press Grab, you can", 637 "select the color by moving the pointer to the desired", 638 "color on the screen and press any button. The transparent", 639 "color updates the image matte channel and is useful for", 640 "image compositing.", 641 "", 642 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 643 "Additional stipples can be specified with the file browser.", 644 "Stipples obtained from the file browser must be on disk in the", 645 "X11 bitmap format.", 646 "", 647 "Choose a width, if appropriate, from the Width sub-menu. To", 648 "choose a specific width select the Dialog widget.", 649 "", 650 "Choose a point in the Image window and press button 1 and", 651 "hold. Next, move the pointer to another location in the", 652 "image. As you move, a line connects the initial location and", 653 "the pointer. When you release the button, the image is", 654 "updated with the primitive you just drew. For polygons, the", 655 "image is updated when you press and release the button without", 656 "moving the pointer.", 657 "", 658 "To cancel image drawing, move the pointer back to the", 659 "starting point of the line and release the button.", 660 (char *) NULL, 661 }, 662 *DisplayHelp[] = 663 { 664 "BUTTONS", 665 " The effects of each button press is described below. Three", 666 " buttons are required. If you have a two button mouse,", 667 " button 1 and 3 are returned. Press ALT and button 3 to", 668 " simulate button 2.", 669 "", 670 " 1 Press this button to map or unmap the Command widget.", 671 "", 672 " 2 Press and drag to define a region of the image to", 673 " magnify.", 674 "", 675 " 3 Press and drag to choose from a select set of commands.", 676 " This button behaves differently if the image being", 677 " displayed is a visual image directory. Here, choose a", 678 " particular tile of the directory and press this button and", 679 " drag to select a command from a pop-up menu. Choose from", 680 " these menu items:", 681 "", 682 " Open", 683 " Next", 684 " Former", 685 " Delete", 686 " Update", 687 "", 688 " If you choose Open, the image represented by the tile is", 689 " displayed. To return to the visual image directory, choose", 690 " Next from the Command widget. Next and Former moves to the", 691 " next or former image respectively. Choose Delete to delete", 692 " a particular image tile. Finally, choose Update to", 693 " synchronize all the image tiles with their respective", 694 " images.", 695 "", 696 "COMMAND WIDGET", 697 " The Command widget lists a number of sub-menus and commands.", 698 " They are", 699 "", 700 " File", 701 " Open...", 702 " Next", 703 " Former", 704 " Select...", 705 " Save...", 706 " Print...", 707 " Delete...", 708 " New...", 709 " Visual Directory...", 710 " Quit", 711 " Edit", 712 " Undo", 713 " Redo", 714 " Cut", 715 " Copy", 716 " Paste", 717 " View", 718 " Half Size", 719 " Original Size", 720 " Double Size", 721 " Resize...", 722 " Apply", 723 " Refresh", 724 " Restore", 725 " Transform", 726 " Crop", 727 " Chop", 728 " Flop", 729 " Flip", 730 " Rotate Right", 731 " Rotate Left", 732 " Rotate...", 733 " Shear...", 734 " Roll...", 735 " Trim Edges", 736 " Enhance", 737 " Brightness...", 738 " Saturation...", 739 " Hue...", 740 " Gamma...", 741 " Sharpen...", 742 " Dull", 743 " Contrast Stretch...", 744 " Sigmoidal Contrast...", 745 " Normalize", 746 " Equalize", 747 " Negate", 748 " Grayscale", 749 " Map...", 750 " Quantize...", 751 " Effects", 752 " Despeckle", 753 " Emboss", 754 " Reduce Noise", 755 " Add Noise", 756 " Sharpen...", 757 " Blur...", 758 " Threshold...", 759 " Edge Detect...", 760 " Spread...", 761 " Shade...", 762 " Painting...", 763 " Segment...", 764 " F/X", 765 " Solarize...", 766 " Sepia Tone...", 767 " Swirl...", 768 " Implode...", 769 " Vignette...", 770 " Wave...", 771 " Oil Painting...", 772 " Charcoal Drawing...", 773 " Image Edit", 774 " Annotate...", 775 " Draw...", 776 " Color...", 777 " Matte...", 778 " Composite...", 779 " Add Border...", 780 " Add Frame...", 781 " Comment...", 782 " Launch...", 783 " Region of Interest...", 784 " Miscellany", 785 " Image Info", 786 " Zoom Image", 787 " Show Preview...", 788 " Show Histogram", 789 " Show Matte", 790 " Background...", 791 " Slide Show", 792 " Preferences...", 793 " Help", 794 " Overview", 795 " Browse Documentation", 796 " About Display", 797 "", 798 " Menu items with a indented triangle have a sub-menu. They", 799 " are represented above as the indented items. To access a", 800 " sub-menu item, move the pointer to the appropriate menu and", 801 " press a button and drag. When you find the desired sub-menu", 802 " item, release the button and the command is executed. Move", 803 " the pointer away from the sub-menu if you decide not to", 804 " execute a particular command.", 805 "", 806 "KEYBOARD ACCELERATORS", 807 " Accelerators are one or two key presses that effect a", 808 " particular command. The keyboard accelerators that", 809 " display(1) understands is:", 810 "", 811 " Ctl+O Press to open an image from a file.", 812 "", 813 " space Press to display the next image.", 814 "", 815 " If the image is a multi-paged document such as a Postscript", 816 " document, you can skip ahead several pages by preceding", 817 " this command with a number. For example to display the", 818 " third page beyond the current page, press 3<space>.", 819 "", 820 " backspace Press to display the former image.", 821 "", 822 " If the image is a multi-paged document such as a Postscript", 823 " document, you can skip behind several pages by preceding", 824 " this command with a number. For example to display the", 825 " third page preceding the current page, press 3<backspace>.", 826 "", 827 " Ctl+S Press to write the image to a file.", 828 "", 829 " Ctl+P Press to print the image to a Postscript printer.", 830 "", 831 " Ctl+D Press to delete an image file.", 832 "", 833 " Ctl+N Press to create a blank canvas.", 834 "", 835 " Ctl+Q Press to discard all images and exit program.", 836 "", 837 " Ctl+Z Press to undo last image transformation.", 838 "", 839 " Ctl+R Press to redo last image transformation.", 840 "", 841 " Ctl+X Press to cut a region of the image.", 842 "", 843 " Ctl+C Press to copy a region of the image.", 844 "", 845 " Ctl+V Press to paste a region to the image.", 846 "", 847 " < Press to half the image size.", 848 "", 849 " - Press to return to the original image size.", 850 "", 851 " > Press to double the image size.", 852 "", 853 " % Press to resize the image to a width and height you", 854 " specify.", 855 "", 856 "Cmd-A Press to make any image transformations permanent." 857 "", 858 " By default, any image size transformations are applied", 859 " to the original image to create the image displayed on", 860 " the X server. However, the transformations are not", 861 " permanent (i.e. the original image does not change", 862 " size only the X image does). For example, if you", 863 " press > the X image will appear to double in size,", 864 " but the original image will in fact remain the same size.", 865 " To force the original image to double in size, press >", 866 " followed by Cmd-A.", 867 "", 868 " @ Press to refresh the image window.", 869 "", 870 " C Press to cut out a rectangular region of the image.", 871 "", 872 " [ Press to chop the image.", 873 "", 874 " H Press to flop image in the horizontal direction.", 875 "", 876 " V Press to flip image in the vertical direction.", 877 "", 878 " / Press to rotate the image 90 degrees clockwise.", 879 "", 880 " \\ Press to rotate the image 90 degrees counter-clockwise.", 881 "", 882 " * Press to rotate the image the number of degrees you", 883 " specify.", 884 "", 885 " S Press to shear the image the number of degrees you", 886 " specify.", 887 "", 888 " R Press to roll the image.", 889 "", 890 " T Press to trim the image edges.", 891 "", 892 " Shft-H Press to vary the image hue.", 893 "", 894 " Shft-S Press to vary the color saturation.", 895 "", 896 " Shft-L Press to vary the color brightness.", 897 "", 898 " Shft-G Press to gamma correct the image.", 899 "", 900 " Shft-C Press to sharpen the image contrast.", 901 "", 902 " Shft-Z Press to dull the image contrast.", 903 "", 904 " = Press to perform histogram equalization on the image.", 905 "", 906 " Shft-N Press to perform histogram normalization on the image.", 907 "", 908 " Shft-~ Press to negate the colors of the image.", 909 "", 910 " . Press to convert the image colors to gray.", 911 "", 912 " Shft-# Press to set the maximum number of unique colors in the", 913 " image.", 914 "", 915 " F2 Press to reduce the speckles in an image.", 916 "", 917 " F3 Press to eliminate peak noise from an image.", 918 "", 919 " F4 Press to add noise to an image.", 920 "", 921 " F5 Press to sharpen an image.", 922 "", 923 " F6 Press to delete an image file.", 924 "", 925 " F7 Press to threshold the image.", 926 "", 927 " F8 Press to detect edges within an image.", 928 "", 929 " F9 Press to emboss an image.", 930 "", 931 " F10 Press to displace pixels by a random amount.", 932 "", 933 " F11 Press to negate all pixels above the threshold level.", 934 "", 935 " F12 Press to shade the image using a distant light source.", 936 "", 937 " F13 Press to lighten or darken image edges to create a 3-D effect.", 938 "", 939 " F14 Press to segment the image by color.", 940 "", 941 " Meta-S Press to swirl image pixels about the center.", 942 "", 943 " Meta-I Press to implode image pixels about the center.", 944 "", 945 " Meta-W Press to alter an image along a sine wave.", 946 "", 947 " Meta-P Press to simulate an oil painting.", 948 "", 949 " Meta-C Press to simulate a charcoal drawing.", 950 "", 951 " Alt-A Press to annotate the image with text.", 952 "", 953 " Alt-D Press to draw on an image.", 954 "", 955 " Alt-P Press to edit an image pixel color.", 956 "", 957 " Alt-M Press to edit the image matte information.", 958 "", 959 " Alt-V Press to composite the image with another.", 960 "", 961 " Alt-B Press to add a border to the image.", 962 "", 963 " Alt-F Press to add an ornamental border to the image.", 964 "", 965 " Alt-Shft-!", 966 " Press to add an image comment.", 967 "", 968 " Ctl-A Press to apply image processing techniques to a region", 969 " of interest.", 970 "", 971 " Shft-? Press to display information about the image.", 972 "", 973 " Shft-+ Press to map the zoom image window.", 974 "", 975 " Shft-P Press to preview an image enhancement, effect, or f/x.", 976 "", 977 " F1 Press to display helpful information about display(1).", 978 "", 979 " Find Press to browse documentation about ImageMagick.", 980 "", 981 " 1-9 Press to change the level of magnification.", 982 "", 983 " Use the arrow keys to move the image one pixel up, down,", 984 " left, or right within the magnify window. Be sure to first", 985 " map the magnify window by pressing button 2.", 986 "", 987 " Press ALT and one of the arrow keys to trim off one pixel", 988 " from any side of the image.", 989 (char *) NULL, 990 }, 991 *ImageMatteEditHelp[] = 992 { 993 "Matte information within an image is useful for some", 994 "operations such as image compositing (See IMAGE", 995 "COMPOSITING). This extra channel usually defines a mask", 996 "which represents a sort of a cookie-cutter for the image.", 997 "This the case when matte is opaque (full coverage) for", 998 "pixels inside the shape, zero outside, and between 0 and", 999 "QuantumRange on the boundary.", 1000 "", 1001 "A small window appears showing the location of the cursor in", 1002 "the image window. You are now in matte edit mode. To exit", 1003 "immediately, press Dismiss. In matte edit mode, the Command", 1004 "widget has these options:", 1005 "", 1006 " Method", 1007 " point", 1008 " replace", 1009 " floodfill", 1010 " filltoborder", 1011 " reset", 1012 " Border Color", 1013 " black", 1014 " blue", 1015 " cyan", 1016 " green", 1017 " gray", 1018 " red", 1019 " magenta", 1020 " yellow", 1021 " white", 1022 " Browser...", 1023 " Fuzz", 1024 " 0%", 1025 " 2%", 1026 " 5%", 1027 " 10%", 1028 " 15%", 1029 " Dialog...", 1030 " Matte", 1031 " Opaque", 1032 " Transparent", 1033 " Dialog...", 1034 " Undo", 1035 " Help", 1036 " Dismiss", 1037 "", 1038 "Choose a matte editing method from the Method sub-menu of", 1039 "the Command widget. The point method changes the matte value", 1040 "of any pixel selected with the pointer until the button is", 1041 "is released. The replace method changes the matte value of", 1042 "any pixel that matches the color of the pixel you select with", 1043 "a button press. Floodfill changes the matte value of any pixel", 1044 "that matches the color of the pixel you select with a button", 1045 "press and is a neighbor. Whereas filltoborder changes the matte", 1046 "value any neighbor pixel that is not the border color. Finally", 1047 "reset changes the entire image to the designated matte value.", 1048 "", 1049 "Choose Matte Value and pick Opaque or Transarent. For other values", 1050 "select the Dialog entry. Here a dialog appears requesting a matte", 1051 "value. The value you select is assigned as the opacity value of the", 1052 "selected pixel or pixels.", 1053 "", 1054 "Now, press any button to select a pixel within the image", 1055 "window to change its matte value.", 1056 "", 1057 "If the Magnify widget is mapped, it can be helpful in positioning", 1058 "your pointer within the image (refer to button 2).", 1059 "", 1060 "Matte information is only valid in a DirectClass image.", 1061 "Therefore, any PseudoClass image is promoted to DirectClass", 1062 "(see miff(5)). Note that matte information for PseudoClass", 1063 "is not retained for colormapped X server visuals (e.g.", 1064 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1065 "immediately save your image to a file (refer to Write).", 1066 "Correct matte editing behavior may require a TrueColor or", 1067 "DirectColor visual or a Standard Colormap.", 1068 (char *) NULL, 1069 }, 1070 *ImagePanHelp[] = 1071 { 1072 "When an image exceeds the width or height of the X server", 1073 "screen, display maps a small panning icon. The rectangle", 1074 "within the panning icon shows the area that is currently", 1075 "displayed in the image window. To pan about the image,", 1076 "press any button and drag the pointer within the panning", 1077 "icon. The pan rectangle moves with the pointer and the", 1078 "image window is updated to reflect the location of the", 1079 "rectangle within the panning icon. When you have selected", 1080 "the area of the image you wish to view, release the button.", 1081 "", 1082 "Use the arrow keys to pan the image one pixel up, down,", 1083 "left, or right within the image window.", 1084 "", 1085 "The panning icon is withdrawn if the image becomes smaller", 1086 "than the dimensions of the X server screen.", 1087 (char *) NULL, 1088 }, 1089 *ImagePasteHelp[] = 1090 { 1091 "A small window appears showing the location of the cursor in", 1092 "the image window. You are now in paste mode. To exit", 1093 "immediately, press Dismiss. In paste mode, the Command", 1094 "widget has these options:", 1095 "", 1096 " Operators", 1097 " over", 1098 " in", 1099 " out", 1100 " atop", 1101 " xor", 1102 " plus", 1103 " minus", 1104 " add", 1105 " subtract", 1106 " difference", 1107 " replace", 1108 " Help", 1109 " Dismiss", 1110 "", 1111 "Choose a composite operation from the Operators sub-menu of", 1112 "the Command widget. How each operator behaves is described", 1113 "below. Image window is the image currently displayed on", 1114 "your X server and image is the image obtained with the File", 1115 "Browser widget.", 1116 "", 1117 "Over The result is the union of the two image shapes,", 1118 " with image obscuring image window in the region of", 1119 " overlap.", 1120 "", 1121 "In The result is simply image cut by the shape of", 1122 " image window. None of the image data of image", 1123 " window is in the result.", 1124 "", 1125 "Out The resulting image is image with the shape of", 1126 " image window cut out.", 1127 "", 1128 "Atop The result is the same shape as image image window,", 1129 " with image obscuring image window where the image", 1130 " shapes overlap. Note this differs from over", 1131 " because the portion of image outside image window's", 1132 " shape does not appear in the result.", 1133 "", 1134 "Xor The result is the image data from both image and", 1135 " image window that is outside the overlap region.", 1136 " The overlap region is blank.", 1137 "", 1138 "Plus The result is just the sum of the image data.", 1139 " Output values are cropped to QuantumRange (no overflow).", 1140 " This operation is independent of the matte", 1141 " channels.", 1142 "", 1143 "Minus The result of image - image window, with underflow", 1144 " cropped to zero.", 1145 "", 1146 "Add The result of image + image window, with overflow", 1147 " wrapping around (mod 256).", 1148 "", 1149 "Subtract The result of image - image window, with underflow", 1150 " wrapping around (mod 256). The add and subtract", 1151 " operators can be used to perform reversible", 1152 " transformations.", 1153 "", 1154 "Difference", 1155 " The result of abs(image - image window). This", 1156 " useful for comparing two very similar images.", 1157 "", 1158 "Copy The resulting image is image window replaced with", 1159 " image. Here the matte information is ignored.", 1160 "", 1161 "CopyRed The red layer of the image window is replace with", 1162 " the red layer of the image. The other layers are", 1163 " untouched.", 1164 "", 1165 "CopyGreen", 1166 " The green layer of the image window is replace with", 1167 " the green layer of the image. The other layers are", 1168 " untouched.", 1169 "", 1170 "CopyBlue The blue layer of the image window is replace with", 1171 " the blue layer of the image. The other layers are", 1172 " untouched.", 1173 "", 1174 "CopyOpacity", 1175 " The matte layer of the image window is replace with", 1176 " the matte layer of the image. The other layers are", 1177 " untouched.", 1178 "", 1179 "The image compositor requires a matte, or alpha channel in", 1180 "the image for some operations. This extra channel usually", 1181 "defines a mask which represents a sort of a cookie-cutter", 1182 "for the image. This the case when matte is opaque (full", 1183 "coverage) for pixels inside the shape, zero outside, and", 1184 "between 0 and QuantumRange on the boundary. If image does not", 1185 "have a matte channel, it is initialized with 0 for any pixel", 1186 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1187 "", 1188 "Note that matte information for image window is not retained", 1189 "for colormapped X server visuals (e.g. StaticColor,", 1190 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1191 "behavior may require a TrueColor or DirectColor visual or a", 1192 "Standard Colormap.", 1193 "", 1194 "Choosing a composite operator is optional. The default", 1195 "operator is replace. However, you must choose a location to", 1196 "paste your image and press button 1. Press and hold the", 1197 "button before releasing and an outline of the image will", 1198 "appear to help you identify your location.", 1199 "", 1200 "The actual colors of the pasted image is saved. However,", 1201 "the color that appears in image window may be different.", 1202 "For example, on a monochrome screen image window will appear", 1203 "black or white even though your pasted image may have", 1204 "many colors. If the image is saved to a file it is written", 1205 "with the correct colors. To assure the correct colors are", 1206 "saved in the final image, any PseudoClass image is promoted", 1207 "to DirectClass (see miff(5)). To force a PseudoClass image", 1208 "to remain PseudoClass, use -colors.", 1209 (char *) NULL, 1210 }, 1211 *ImageROIHelp[] = 1212 { 1213 "In region of interest mode, the Command widget has these", 1214 "options:", 1215 "", 1216 " Help", 1217 " Dismiss", 1218 "", 1219 "To define a region of interest, press button 1 and drag.", 1220 "The region of interest is defined by a highlighted rectangle", 1221 "that expands or contracts as it follows the pointer. Once", 1222 "you are satisfied with the region of interest, release the", 1223 "button. You are now in apply mode. In apply mode the", 1224 "Command widget has these options:", 1225 "", 1226 " File", 1227 " Save...", 1228 " Print...", 1229 " Edit", 1230 " Undo", 1231 " Redo", 1232 " Transform", 1233 " Flop", 1234 " Flip", 1235 " Rotate Right", 1236 " Rotate Left", 1237 " Enhance", 1238 " Hue...", 1239 " Saturation...", 1240 " Brightness...", 1241 " Gamma...", 1242 " Spiff", 1243 " Dull", 1244 " Contrast Stretch", 1245 " Sigmoidal Contrast...", 1246 " Normalize", 1247 " Equalize", 1248 " Negate", 1249 " Grayscale", 1250 " Map...", 1251 " Quantize...", 1252 " Effects", 1253 " Despeckle", 1254 " Emboss", 1255 " Reduce Noise", 1256 " Sharpen...", 1257 " Blur...", 1258 " Threshold...", 1259 " Edge Detect...", 1260 " Spread...", 1261 " Shade...", 1262 " Raise...", 1263 " Segment...", 1264 " F/X", 1265 " Solarize...", 1266 " Sepia Tone...", 1267 " Swirl...", 1268 " Implode...", 1269 " Vignette...", 1270 " Wave...", 1271 " Oil Painting...", 1272 " Charcoal Drawing...", 1273 " Miscellany", 1274 " Image Info", 1275 " Zoom Image", 1276 " Show Preview...", 1277 " Show Histogram", 1278 " Show Matte", 1279 " Help", 1280 " Dismiss", 1281 "", 1282 "You can make adjustments to the region of interest by moving", 1283 "the pointer to one of the rectangle corners, pressing a", 1284 "button, and dragging. Finally, choose an image processing", 1285 "technique from the Command widget. You can choose more than", 1286 "one image processing technique to apply to an area.", 1287 "Alternatively, you can move the region of interest before", 1288 "applying another image processing technique. To exit, press", 1289 "Dismiss.", 1290 (char *) NULL, 1291 }, 1292 *ImageRotateHelp[] = 1293 { 1294 "In rotate mode, the Command widget has these options:", 1295 "", 1296 " Pixel Color", 1297 " black", 1298 " blue", 1299 " cyan", 1300 " green", 1301 " gray", 1302 " red", 1303 " magenta", 1304 " yellow", 1305 " white", 1306 " Browser...", 1307 " Direction", 1308 " horizontal", 1309 " vertical", 1310 " Help", 1311 " Dismiss", 1312 "", 1313 "Choose a background color from the Pixel Color sub-menu.", 1314 "Additional background colors can be specified with the color", 1315 "browser. You can change the menu colors by setting the X", 1316 "resources pen1 through pen9.", 1317 "", 1318 "If you choose the color browser and press Grab, you can", 1319 "select the background color by moving the pointer to the", 1320 "desired color on the screen and press any button.", 1321 "", 1322 "Choose a point in the image window and press this button and", 1323 "hold. Next, move the pointer to another location in the", 1324 "image. As you move a line connects the initial location and", 1325 "the pointer. When you release the button, the degree of", 1326 "image rotation is determined by the slope of the line you", 1327 "just drew. The slope is relative to the direction you", 1328 "choose from the Direction sub-menu of the Command widget.", 1329 "", 1330 "To cancel the image rotation, move the pointer back to the", 1331 "starting point of the line and release the button.", 1332 (char *) NULL, 1333 }; 1334 1335/* 1336 Enumeration declarations. 1337*/ 1338typedef enum 1339{ 1340 CopyMode, 1341 CropMode, 1342 CutMode 1343} ClipboardMode; 1344 1345typedef enum 1346{ 1347 OpenCommand, 1348 NextCommand, 1349 FormerCommand, 1350 SelectCommand, 1351 SaveCommand, 1352 PrintCommand, 1353 DeleteCommand, 1354 NewCommand, 1355 VisualDirectoryCommand, 1356 QuitCommand, 1357 UndoCommand, 1358 RedoCommand, 1359 CutCommand, 1360 CopyCommand, 1361 PasteCommand, 1362 HalfSizeCommand, 1363 OriginalSizeCommand, 1364 DoubleSizeCommand, 1365 ResizeCommand, 1366 ApplyCommand, 1367 RefreshCommand, 1368 RestoreCommand, 1369 CropCommand, 1370 ChopCommand, 1371 FlopCommand, 1372 FlipCommand, 1373 RotateRightCommand, 1374 RotateLeftCommand, 1375 RotateCommand, 1376 ShearCommand, 1377 RollCommand, 1378 TrimCommand, 1379 HueCommand, 1380 SaturationCommand, 1381 BrightnessCommand, 1382 GammaCommand, 1383 SpiffCommand, 1384 DullCommand, 1385 ContrastStretchCommand, 1386 SigmoidalContrastCommand, 1387 NormalizeCommand, 1388 EqualizeCommand, 1389 NegateCommand, 1390 GrayscaleCommand, 1391 MapCommand, 1392 QuantizeCommand, 1393 DespeckleCommand, 1394 EmbossCommand, 1395 ReduceNoiseCommand, 1396 AddNoiseCommand, 1397 SharpenCommand, 1398 BlurCommand, 1399 ThresholdCommand, 1400 EdgeDetectCommand, 1401 SpreadCommand, 1402 ShadeCommand, 1403 RaiseCommand, 1404 SegmentCommand, 1405 SolarizeCommand, 1406 SepiaToneCommand, 1407 SwirlCommand, 1408 ImplodeCommand, 1409 VignetteCommand, 1410 WaveCommand, 1411 OilPaintCommand, 1412 CharcoalDrawCommand, 1413 AnnotateCommand, 1414 DrawCommand, 1415 ColorCommand, 1416 MatteCommand, 1417 CompositeCommand, 1418 AddBorderCommand, 1419 AddFrameCommand, 1420 CommentCommand, 1421 LaunchCommand, 1422 RegionofInterestCommand, 1423 ROIHelpCommand, 1424 ROIDismissCommand, 1425 InfoCommand, 1426 ZoomCommand, 1427 ShowPreviewCommand, 1428 ShowHistogramCommand, 1429 ShowMatteCommand, 1430 BackgroundCommand, 1431 SlideShowCommand, 1432 PreferencesCommand, 1433 HelpCommand, 1434 BrowseDocumentationCommand, 1435 VersionCommand, 1436 SaveToUndoBufferCommand, 1437 FreeBuffersCommand, 1438 NullCommand 1439} CommandType; 1440 1441typedef enum 1442{ 1443 AnnotateNameCommand, 1444 AnnotateFontColorCommand, 1445 AnnotateBackgroundColorCommand, 1446 AnnotateRotateCommand, 1447 AnnotateHelpCommand, 1448 AnnotateDismissCommand, 1449 TextHelpCommand, 1450 TextApplyCommand, 1451 ChopDirectionCommand, 1452 ChopHelpCommand, 1453 ChopDismissCommand, 1454 HorizontalChopCommand, 1455 VerticalChopCommand, 1456 ColorEditMethodCommand, 1457 ColorEditColorCommand, 1458 ColorEditBorderCommand, 1459 ColorEditFuzzCommand, 1460 ColorEditUndoCommand, 1461 ColorEditHelpCommand, 1462 ColorEditDismissCommand, 1463 CompositeOperatorsCommand, 1464 CompositeDissolveCommand, 1465 CompositeDisplaceCommand, 1466 CompositeHelpCommand, 1467 CompositeDismissCommand, 1468 CropHelpCommand, 1469 CropDismissCommand, 1470 RectifyCopyCommand, 1471 RectifyHelpCommand, 1472 RectifyDismissCommand, 1473 DrawElementCommand, 1474 DrawColorCommand, 1475 DrawStippleCommand, 1476 DrawWidthCommand, 1477 DrawUndoCommand, 1478 DrawHelpCommand, 1479 DrawDismissCommand, 1480 MatteEditMethod, 1481 MatteEditBorderCommand, 1482 MatteEditFuzzCommand, 1483 MatteEditValueCommand, 1484 MatteEditUndoCommand, 1485 MatteEditHelpCommand, 1486 MatteEditDismissCommand, 1487 PasteOperatorsCommand, 1488 PasteHelpCommand, 1489 PasteDismissCommand, 1490 RotateColorCommand, 1491 RotateDirectionCommand, 1492 RotateCropCommand, 1493 RotateSharpenCommand, 1494 RotateHelpCommand, 1495 RotateDismissCommand, 1496 HorizontalRotateCommand, 1497 VerticalRotateCommand, 1498 TileLoadCommand, 1499 TileNextCommand, 1500 TileFormerCommand, 1501 TileDeleteCommand, 1502 TileUpdateCommand 1503} ModeType; 1504 1505/* 1506 Stipples. 1507*/ 1508#define BricksWidth 20 1509#define BricksHeight 20 1510#define DiagonalWidth 16 1511#define DiagonalHeight 16 1512#define HighlightWidth 8 1513#define HighlightHeight 8 1514#define OpaqueWidth 8 1515#define OpaqueHeight 8 1516#define ScalesWidth 16 1517#define ScalesHeight 16 1518#define ShadowWidth 8 1519#define ShadowHeight 8 1520#define VerticalWidth 16 1521#define VerticalHeight 16 1522#define WavyWidth 16 1523#define WavyHeight 16 1524 1525/* 1526 Constant declaration. 1527*/ 1528static const int 1529 RoiDelta = 8; 1530 1531static const unsigned char 1532 BricksBitmap[] = 1533 { 1534 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1535 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1537 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1538 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1539 }, 1540 DiagonalBitmap[] = 1541 { 1542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1543 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1544 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1545 }, 1546 ScalesBitmap[] = 1547 { 1548 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1549 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1550 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1551 }, 1552 VerticalBitmap[] = 1553 { 1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1557 }, 1558 WavyBitmap[] = 1559 { 1560 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1561 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1562 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1563 }; 1564 1565/* 1566 Function prototypes. 1567*/ 1568static CommandType 1569 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1570 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1571 1572static Image 1573 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1574 Image **,ExceptionInfo *), 1575 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1576 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1577 ExceptionInfo *), 1578 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1579 ExceptionInfo *); 1580 1581static MagickBooleanType 1582 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1583 ExceptionInfo *), 1584 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1585 ExceptionInfo *), 1586 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1587 ExceptionInfo *), 1588 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1589 ExceptionInfo *), 1590 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1591 ExceptionInfo *), 1592 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1593 ExceptionInfo *), 1594 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1595 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1596 ExceptionInfo *), 1597 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1598 ExceptionInfo *), 1599 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1600 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1601 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1602 ExceptionInfo *), 1603 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1604 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1605 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1606 1607static void 1608 XDrawPanRectangle(Display *,XWindows *), 1609 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1610 ExceptionInfo *), 1611 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1612 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1613 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1614 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1615 const KeySym,ExceptionInfo *), 1616 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1617 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1618 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1619 1620/* 1621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1622% % 1623% % 1624% % 1625% D i s p l a y I m a g e s % 1626% % 1627% % 1628% % 1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1630% 1631% DisplayImages() displays an image sequence to any X window screen. It 1632% returns a value other than 0 if successful. Check the exception member 1633% of image to determine the reason for any failure. 1634% 1635% The format of the DisplayImages method is: 1636% 1637% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1638% Image *images,ExceptionInfo *exception) 1639% 1640% A description of each parameter follows: 1641% 1642% o image_info: the image info. 1643% 1644% o image: the image. 1645% 1646% o exception: return any errors or warnings in this structure. 1647% 1648*/ 1649MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1650 Image *images,ExceptionInfo *exception) 1651{ 1652 char 1653 *argv[1]; 1654 1655 Display 1656 *display; 1657 1658 Image 1659 *image; 1660 1661 register ssize_t 1662 i; 1663 1664 size_t 1665 state; 1666 1667 XrmDatabase 1668 resource_database; 1669 1670 XResourceInfo 1671 resource_info; 1672 1673 assert(image_info != (const ImageInfo *) NULL); 1674 assert(image_info->signature == MagickSignature); 1675 assert(images != (Image *) NULL); 1676 assert(images->signature == MagickSignature); 1677 if (images->debug != MagickFalse) 1678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1679 display=XOpenDisplay(image_info->server_name); 1680 if (display == (Display *) NULL) 1681 { 1682 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1683 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1684 return(MagickFalse); 1685 } 1686 if (exception->severity != UndefinedException) 1687 CatchException(exception); 1688 (void) XSetErrorHandler(XError); 1689 resource_database=XGetResourceDatabase(display,GetClientName()); 1690 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1691 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1692 if (image_info->page != (char *) NULL) 1693 resource_info.image_geometry=AcquireString(image_info->page); 1694 resource_info.immutable=MagickTrue; 1695 argv[0]=AcquireString(GetClientName()); 1696 state=DefaultState; 1697 for (i=0; (state & ExitState) == 0; i++) 1698 { 1699 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1700 break; 1701 image=GetImageFromList(images,i % GetImageListLength(images)); 1702 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1703 } 1704 (void) SetErrorHandler((ErrorHandler) NULL); 1705 (void) SetWarningHandler((WarningHandler) NULL); 1706 argv[0]=DestroyString(argv[0]); 1707 (void) XCloseDisplay(display); 1708 XDestroyResourceInfo(&resource_info); 1709 if (exception->severity != UndefinedException) 1710 return(MagickFalse); 1711 return(MagickTrue); 1712} 1713 1714/* 1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1716% % 1717% % 1718% % 1719% R e m o t e D i s p l a y C o m m a n d % 1720% % 1721% % 1722% % 1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1724% 1725% RemoteDisplayCommand() encourages a remote display program to display the 1726% specified image filename. 1727% 1728% The format of the RemoteDisplayCommand method is: 1729% 1730% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1731% const char *window,const char *filename,ExceptionInfo *exception) 1732% 1733% A description of each parameter follows: 1734% 1735% o image_info: the image info. 1736% 1737% o window: Specifies the name or id of an X window. 1738% 1739% o filename: the name of the image filename to display. 1740% 1741% o exception: return any errors or warnings in this structure. 1742% 1743*/ 1744MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1745 const char *window,const char *filename,ExceptionInfo *exception) 1746{ 1747 Display 1748 *display; 1749 1750 MagickStatusType 1751 status; 1752 1753 assert(image_info != (const ImageInfo *) NULL); 1754 assert(image_info->signature == MagickSignature); 1755 assert(filename != (char *) NULL); 1756 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1757 display=XOpenDisplay(image_info->server_name); 1758 if (display == (Display *) NULL) 1759 { 1760 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1761 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1762 return(MagickFalse); 1763 } 1764 (void) XSetErrorHandler(XError); 1765 status=XRemoteCommand(display,window,filename); 1766 (void) XCloseDisplay(display); 1767 return(status != 0 ? MagickTrue : MagickFalse); 1768} 1769 1770/* 1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1772% % 1773% % 1774% % 1775+ X A n n o t a t e E d i t I m a g e % 1776% % 1777% % 1778% % 1779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1780% 1781% XAnnotateEditImage() annotates the image with text. 1782% 1783% The format of the XAnnotateEditImage method is: 1784% 1785% MagickBooleanType XAnnotateEditImage(Display *display, 1786% XResourceInfo *resource_info,XWindows *windows,Image *image, 1787% ExceptionInfo *exception) 1788% 1789% A description of each parameter follows: 1790% 1791% o display: Specifies a connection to an X server; returned from 1792% XOpenDisplay. 1793% 1794% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1795% 1796% o windows: Specifies a pointer to a XWindows structure. 1797% 1798% o image: the image; returned from ReadImage. 1799% 1800*/ 1801 1802static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1803{ 1804 if (x > y) 1805 return(x); 1806 return(y); 1807} 1808 1809static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1810{ 1811 if (x < y) 1812 return(x); 1813 return(y); 1814} 1815 1816static MagickBooleanType XAnnotateEditImage(Display *display, 1817 XResourceInfo *resource_info,XWindows *windows,Image *image, 1818 ExceptionInfo *exception) 1819{ 1820 static const char 1821 *AnnotateMenu[] = 1822 { 1823 "Font Name", 1824 "Font Color", 1825 "Box Color", 1826 "Rotate Text", 1827 "Help", 1828 "Dismiss", 1829 (char *) NULL 1830 }, 1831 *TextMenu[] = 1832 { 1833 "Help", 1834 "Apply", 1835 (char *) NULL 1836 }; 1837 1838 static const ModeType 1839 AnnotateCommands[] = 1840 { 1841 AnnotateNameCommand, 1842 AnnotateFontColorCommand, 1843 AnnotateBackgroundColorCommand, 1844 AnnotateRotateCommand, 1845 AnnotateHelpCommand, 1846 AnnotateDismissCommand 1847 }, 1848 TextCommands[] = 1849 { 1850 TextHelpCommand, 1851 TextApplyCommand 1852 }; 1853 1854 static MagickBooleanType 1855 transparent_box = MagickTrue, 1856 transparent_pen = MagickFalse; 1857 1858 static MagickRealType 1859 degrees = 0.0; 1860 1861 static unsigned int 1862 box_id = MaxNumberPens-2, 1863 font_id = 0, 1864 pen_id = 0; 1865 1866 char 1867 command[MaxTextExtent], 1868 text[MaxTextExtent]; 1869 1870 const char 1871 *ColorMenu[MaxNumberPens+1]; 1872 1873 Cursor 1874 cursor; 1875 1876 GC 1877 annotate_context; 1878 1879 int 1880 id, 1881 pen_number, 1882 status, 1883 x, 1884 y; 1885 1886 KeySym 1887 key_symbol; 1888 1889 register char 1890 *p; 1891 1892 register ssize_t 1893 i; 1894 1895 unsigned int 1896 height, 1897 width; 1898 1899 size_t 1900 state; 1901 1902 XAnnotateInfo 1903 *annotate_info, 1904 *previous_info; 1905 1906 XColor 1907 color; 1908 1909 XFontStruct 1910 *font_info; 1911 1912 XEvent 1913 event, 1914 text_event; 1915 1916 /* 1917 Map Command widget. 1918 */ 1919 (void) CloneString(&windows->command.name,"Annotate"); 1920 windows->command.data=4; 1921 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1922 (void) XMapRaised(display,windows->command.id); 1923 XClientMessage(display,windows->image.id,windows->im_protocols, 1924 windows->im_update_widget,CurrentTime); 1925 /* 1926 Track pointer until button 1 is pressed. 1927 */ 1928 XQueryPosition(display,windows->image.id,&x,&y); 1929 (void) XSelectInput(display,windows->image.id, 1930 windows->image.attributes.event_mask | PointerMotionMask); 1931 cursor=XCreateFontCursor(display,XC_left_side); 1932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1933 state=DefaultState; 1934 do 1935 { 1936 if (windows->info.mapped != MagickFalse) 1937 { 1938 /* 1939 Display pointer position. 1940 */ 1941 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1942 x+windows->image.x,y+windows->image.y); 1943 XInfoWidget(display,windows,text); 1944 } 1945 /* 1946 Wait for next event. 1947 */ 1948 XScreenEvent(display,windows,&event,exception); 1949 if (event.xany.window == windows->command.id) 1950 { 1951 /* 1952 Select a command from the Command widget. 1953 */ 1954 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1955 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1956 if (id < 0) 1957 continue; 1958 switch (AnnotateCommands[id]) 1959 { 1960 case AnnotateNameCommand: 1961 { 1962 const char 1963 *FontMenu[MaxNumberFonts]; 1964 1965 int 1966 font_number; 1967 1968 /* 1969 Initialize menu selections. 1970 */ 1971 for (i=0; i < MaxNumberFonts; i++) 1972 FontMenu[i]=resource_info->font_name[i]; 1973 FontMenu[MaxNumberFonts-2]="Browser..."; 1974 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1975 /* 1976 Select a font name from the pop-up menu. 1977 */ 1978 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1979 (const char **) FontMenu,command); 1980 if (font_number < 0) 1981 break; 1982 if (font_number == (MaxNumberFonts-2)) 1983 { 1984 static char 1985 font_name[MaxTextExtent] = "fixed"; 1986 1987 /* 1988 Select a font name from a browser. 1989 */ 1990 resource_info->font_name[font_number]=font_name; 1991 XFontBrowserWidget(display,windows,"Select",font_name); 1992 if (*font_name == '\0') 1993 break; 1994 } 1995 /* 1996 Initialize font info. 1997 */ 1998 font_info=XLoadQueryFont(display,resource_info->font_name[ 1999 font_number]); 2000 if (font_info == (XFontStruct *) NULL) 2001 { 2002 XNoticeWidget(display,windows,"Unable to load font:", 2003 resource_info->font_name[font_number]); 2004 break; 2005 } 2006 font_id=(unsigned int) font_number; 2007 (void) XFreeFont(display,font_info); 2008 break; 2009 } 2010 case AnnotateFontColorCommand: 2011 { 2012 /* 2013 Initialize menu selections. 2014 */ 2015 for (i=0; i < (int) (MaxNumberPens-2); i++) 2016 ColorMenu[i]=resource_info->pen_colors[i]; 2017 ColorMenu[MaxNumberPens-2]="transparent"; 2018 ColorMenu[MaxNumberPens-1]="Browser..."; 2019 ColorMenu[MaxNumberPens]=(const char *) NULL; 2020 /* 2021 Select a pen color from the pop-up menu. 2022 */ 2023 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2024 (const char **) ColorMenu,command); 2025 if (pen_number < 0) 2026 break; 2027 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2028 MagickFalse; 2029 if (transparent_pen != MagickFalse) 2030 break; 2031 if (pen_number == (MaxNumberPens-1)) 2032 { 2033 static char 2034 color_name[MaxTextExtent] = "gray"; 2035 2036 /* 2037 Select a pen color from a dialog. 2038 */ 2039 resource_info->pen_colors[pen_number]=color_name; 2040 XColorBrowserWidget(display,windows,"Select",color_name); 2041 if (*color_name == '\0') 2042 break; 2043 } 2044 /* 2045 Set pen color. 2046 */ 2047 (void) XParseColor(display,windows->map_info->colormap, 2048 resource_info->pen_colors[pen_number],&color); 2049 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2050 (unsigned int) MaxColors,&color); 2051 windows->pixel_info->pen_colors[pen_number]=color; 2052 pen_id=(unsigned int) pen_number; 2053 break; 2054 } 2055 case AnnotateBackgroundColorCommand: 2056 { 2057 /* 2058 Initialize menu selections. 2059 */ 2060 for (i=0; i < (int) (MaxNumberPens-2); i++) 2061 ColorMenu[i]=resource_info->pen_colors[i]; 2062 ColorMenu[MaxNumberPens-2]="transparent"; 2063 ColorMenu[MaxNumberPens-1]="Browser..."; 2064 ColorMenu[MaxNumberPens]=(const char *) NULL; 2065 /* 2066 Select a pen color from the pop-up menu. 2067 */ 2068 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2069 (const char **) ColorMenu,command); 2070 if (pen_number < 0) 2071 break; 2072 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2073 MagickFalse; 2074 if (transparent_box != MagickFalse) 2075 break; 2076 if (pen_number == (MaxNumberPens-1)) 2077 { 2078 static char 2079 color_name[MaxTextExtent] = "gray"; 2080 2081 /* 2082 Select a pen color from a dialog. 2083 */ 2084 resource_info->pen_colors[pen_number]=color_name; 2085 XColorBrowserWidget(display,windows,"Select",color_name); 2086 if (*color_name == '\0') 2087 break; 2088 } 2089 /* 2090 Set pen color. 2091 */ 2092 (void) XParseColor(display,windows->map_info->colormap, 2093 resource_info->pen_colors[pen_number],&color); 2094 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2095 (unsigned int) MaxColors,&color); 2096 windows->pixel_info->pen_colors[pen_number]=color; 2097 box_id=(unsigned int) pen_number; 2098 break; 2099 } 2100 case AnnotateRotateCommand: 2101 { 2102 int 2103 entry; 2104 2105 static char 2106 angle[MaxTextExtent] = "30.0"; 2107 2108 static const char 2109 *RotateMenu[] = 2110 { 2111 "-90", 2112 "-45", 2113 "-30", 2114 "0", 2115 "30", 2116 "45", 2117 "90", 2118 "180", 2119 "Dialog...", 2120 (char *) NULL, 2121 }; 2122 2123 /* 2124 Select a command from the pop-up menu. 2125 */ 2126 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2127 command); 2128 if (entry < 0) 2129 break; 2130 if (entry != 8) 2131 { 2132 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2133 break; 2134 } 2135 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2136 angle); 2137 if (*angle == '\0') 2138 break; 2139 degrees=StringToDouble(angle,(char **) NULL); 2140 break; 2141 } 2142 case AnnotateHelpCommand: 2143 { 2144 XTextViewWidget(display,resource_info,windows,MagickFalse, 2145 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2146 break; 2147 } 2148 case AnnotateDismissCommand: 2149 { 2150 /* 2151 Prematurely exit. 2152 */ 2153 state|=EscapeState; 2154 state|=ExitState; 2155 break; 2156 } 2157 default: 2158 break; 2159 } 2160 continue; 2161 } 2162 switch (event.type) 2163 { 2164 case ButtonPress: 2165 { 2166 if (event.xbutton.button != Button1) 2167 break; 2168 if (event.xbutton.window != windows->image.id) 2169 break; 2170 /* 2171 Change to text entering mode. 2172 */ 2173 x=event.xbutton.x; 2174 y=event.xbutton.y; 2175 state|=ExitState; 2176 break; 2177 } 2178 case ButtonRelease: 2179 break; 2180 case Expose: 2181 break; 2182 case KeyPress: 2183 { 2184 if (event.xkey.window != windows->image.id) 2185 break; 2186 /* 2187 Respond to a user key press. 2188 */ 2189 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2190 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2191 switch ((int) key_symbol) 2192 { 2193 case XK_Escape: 2194 case XK_F20: 2195 { 2196 /* 2197 Prematurely exit. 2198 */ 2199 state|=EscapeState; 2200 state|=ExitState; 2201 break; 2202 } 2203 case XK_F1: 2204 case XK_Help: 2205 { 2206 XTextViewWidget(display,resource_info,windows,MagickFalse, 2207 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2208 break; 2209 } 2210 default: 2211 { 2212 (void) XBell(display,0); 2213 break; 2214 } 2215 } 2216 break; 2217 } 2218 case MotionNotify: 2219 { 2220 /* 2221 Map and unmap Info widget as cursor crosses its boundaries. 2222 */ 2223 x=event.xmotion.x; 2224 y=event.xmotion.y; 2225 if (windows->info.mapped != MagickFalse) 2226 { 2227 if ((x < (int) (windows->info.x+windows->info.width)) && 2228 (y < (int) (windows->info.y+windows->info.height))) 2229 (void) XWithdrawWindow(display,windows->info.id, 2230 windows->info.screen); 2231 } 2232 else 2233 if ((x > (int) (windows->info.x+windows->info.width)) || 2234 (y > (int) (windows->info.y+windows->info.height))) 2235 (void) XMapWindow(display,windows->info.id); 2236 break; 2237 } 2238 default: 2239 break; 2240 } 2241 } while ((state & ExitState) == 0); 2242 (void) XSelectInput(display,windows->image.id, 2243 windows->image.attributes.event_mask); 2244 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2245 if ((state & EscapeState) != 0) 2246 return(MagickTrue); 2247 /* 2248 Set font info and check boundary conditions. 2249 */ 2250 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2251 if (font_info == (XFontStruct *) NULL) 2252 { 2253 XNoticeWidget(display,windows,"Unable to load font:", 2254 resource_info->font_name[font_id]); 2255 font_info=windows->font_info; 2256 } 2257 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2258 x=(int) windows->image.width-font_info->max_bounds.width; 2259 if (y < (int) (font_info->ascent+font_info->descent)) 2260 y=(int) font_info->ascent+font_info->descent; 2261 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2262 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2263 return(MagickFalse); 2264 /* 2265 Initialize annotate structure. 2266 */ 2267 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2268 if (annotate_info == (XAnnotateInfo *) NULL) 2269 return(MagickFalse); 2270 XGetAnnotateInfo(annotate_info); 2271 annotate_info->x=x; 2272 annotate_info->y=y; 2273 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2274 annotate_info->stencil=OpaqueStencil; 2275 else 2276 if (transparent_box == MagickFalse) 2277 annotate_info->stencil=BackgroundStencil; 2278 else 2279 annotate_info->stencil=ForegroundStencil; 2280 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2281 annotate_info->degrees=degrees; 2282 annotate_info->font_info=font_info; 2283 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2284 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2285 sizeof(*annotate_info->text)); 2286 if (annotate_info->text == (char *) NULL) 2287 return(MagickFalse); 2288 /* 2289 Create cursor and set graphic context. 2290 */ 2291 cursor=XCreateFontCursor(display,XC_pencil); 2292 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2293 annotate_context=windows->image.annotate_context; 2294 (void) XSetFont(display,annotate_context,font_info->fid); 2295 (void) XSetBackground(display,annotate_context, 2296 windows->pixel_info->pen_colors[box_id].pixel); 2297 (void) XSetForeground(display,annotate_context, 2298 windows->pixel_info->pen_colors[pen_id].pixel); 2299 /* 2300 Begin annotating the image with text. 2301 */ 2302 (void) CloneString(&windows->command.name,"Text"); 2303 windows->command.data=0; 2304 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2305 state=DefaultState; 2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2307 text_event.xexpose.width=(int) font_info->max_bounds.width; 2308 text_event.xexpose.height=font_info->max_bounds.ascent+ 2309 font_info->max_bounds.descent; 2310 p=annotate_info->text; 2311 do 2312 { 2313 /* 2314 Display text cursor. 2315 */ 2316 *p='\0'; 2317 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2318 /* 2319 Wait for next event. 2320 */ 2321 XScreenEvent(display,windows,&event,exception); 2322 if (event.xany.window == windows->command.id) 2323 { 2324 /* 2325 Select a command from the Command widget. 2326 */ 2327 (void) XSetBackground(display,annotate_context, 2328 windows->pixel_info->background_color.pixel); 2329 (void) XSetForeground(display,annotate_context, 2330 windows->pixel_info->foreground_color.pixel); 2331 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2332 (void) XSetBackground(display,annotate_context, 2333 windows->pixel_info->pen_colors[box_id].pixel); 2334 (void) XSetForeground(display,annotate_context, 2335 windows->pixel_info->pen_colors[pen_id].pixel); 2336 if (id < 0) 2337 continue; 2338 switch (TextCommands[id]) 2339 { 2340 case TextHelpCommand: 2341 { 2342 XTextViewWidget(display,resource_info,windows,MagickFalse, 2343 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2344 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2345 break; 2346 } 2347 case TextApplyCommand: 2348 { 2349 /* 2350 Finished annotating. 2351 */ 2352 annotate_info->width=(unsigned int) XTextWidth(font_info, 2353 annotate_info->text,(int) strlen(annotate_info->text)); 2354 XRefreshWindow(display,&windows->image,&text_event); 2355 state|=ExitState; 2356 break; 2357 } 2358 default: 2359 break; 2360 } 2361 continue; 2362 } 2363 /* 2364 Erase text cursor. 2365 */ 2366 text_event.xexpose.x=x; 2367 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2368 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2369 (unsigned int) text_event.xexpose.width,(unsigned int) 2370 text_event.xexpose.height,MagickFalse); 2371 XRefreshWindow(display,&windows->image,&text_event); 2372 switch (event.type) 2373 { 2374 case ButtonPress: 2375 { 2376 if (event.xbutton.window != windows->image.id) 2377 break; 2378 if (event.xbutton.button == Button2) 2379 { 2380 /* 2381 Request primary selection. 2382 */ 2383 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2384 windows->image.id,CurrentTime); 2385 break; 2386 } 2387 break; 2388 } 2389 case Expose: 2390 { 2391 if (event.xexpose.count == 0) 2392 { 2393 XAnnotateInfo 2394 *text_info; 2395 2396 /* 2397 Refresh Image window. 2398 */ 2399 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2400 text_info=annotate_info; 2401 while (text_info != (XAnnotateInfo *) NULL) 2402 { 2403 if (annotate_info->stencil == ForegroundStencil) 2404 (void) XDrawString(display,windows->image.id,annotate_context, 2405 text_info->x,text_info->y,text_info->text, 2406 (int) strlen(text_info->text)); 2407 else 2408 (void) XDrawImageString(display,windows->image.id, 2409 annotate_context,text_info->x,text_info->y,text_info->text, 2410 (int) strlen(text_info->text)); 2411 text_info=text_info->previous; 2412 } 2413 (void) XDrawString(display,windows->image.id,annotate_context, 2414 x,y,"_",1); 2415 } 2416 break; 2417 } 2418 case KeyPress: 2419 { 2420 int 2421 length; 2422 2423 if (event.xkey.window != windows->image.id) 2424 break; 2425 /* 2426 Respond to a user key press. 2427 */ 2428 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2429 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2430 *(command+length)='\0'; 2431 if (((event.xkey.state & ControlMask) != 0) || 2432 ((event.xkey.state & Mod1Mask) != 0)) 2433 state|=ModifierState; 2434 if ((state & ModifierState) != 0) 2435 switch ((int) key_symbol) 2436 { 2437 case XK_u: 2438 case XK_U: 2439 { 2440 key_symbol=DeleteCommand; 2441 break; 2442 } 2443 default: 2444 break; 2445 } 2446 switch ((int) key_symbol) 2447 { 2448 case XK_BackSpace: 2449 { 2450 /* 2451 Erase one character. 2452 */ 2453 if (p == annotate_info->text) 2454 { 2455 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2456 break; 2457 else 2458 { 2459 /* 2460 Go to end of the previous line of text. 2461 */ 2462 annotate_info=annotate_info->previous; 2463 p=annotate_info->text; 2464 x=annotate_info->x+annotate_info->width; 2465 y=annotate_info->y; 2466 if (annotate_info->width != 0) 2467 p+=strlen(annotate_info->text); 2468 break; 2469 } 2470 } 2471 p--; 2472 x-=XTextWidth(font_info,p,1); 2473 text_event.xexpose.x=x; 2474 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2475 XRefreshWindow(display,&windows->image,&text_event); 2476 break; 2477 } 2478 case XK_bracketleft: 2479 { 2480 key_symbol=XK_Escape; 2481 break; 2482 } 2483 case DeleteCommand: 2484 { 2485 /* 2486 Erase the entire line of text. 2487 */ 2488 while (p != annotate_info->text) 2489 { 2490 p--; 2491 x-=XTextWidth(font_info,p,1); 2492 text_event.xexpose.x=x; 2493 XRefreshWindow(display,&windows->image,&text_event); 2494 } 2495 break; 2496 } 2497 case XK_Escape: 2498 case XK_F20: 2499 { 2500 /* 2501 Finished annotating. 2502 */ 2503 annotate_info->width=(unsigned int) XTextWidth(font_info, 2504 annotate_info->text,(int) strlen(annotate_info->text)); 2505 XRefreshWindow(display,&windows->image,&text_event); 2506 state|=ExitState; 2507 break; 2508 } 2509 default: 2510 { 2511 /* 2512 Draw a single character on the Image window. 2513 */ 2514 if ((state & ModifierState) != 0) 2515 break; 2516 if (*command == '\0') 2517 break; 2518 *p=(*command); 2519 if (annotate_info->stencil == ForegroundStencil) 2520 (void) XDrawString(display,windows->image.id,annotate_context, 2521 x,y,p,1); 2522 else 2523 (void) XDrawImageString(display,windows->image.id, 2524 annotate_context,x,y,p,1); 2525 x+=XTextWidth(font_info,p,1); 2526 p++; 2527 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2528 break; 2529 } 2530 case XK_Return: 2531 case XK_KP_Enter: 2532 { 2533 /* 2534 Advance to the next line of text. 2535 */ 2536 *p='\0'; 2537 annotate_info->width=(unsigned int) XTextWidth(font_info, 2538 annotate_info->text,(int) strlen(annotate_info->text)); 2539 if (annotate_info->next != (XAnnotateInfo *) NULL) 2540 { 2541 /* 2542 Line of text already exists. 2543 */ 2544 annotate_info=annotate_info->next; 2545 x=annotate_info->x; 2546 y=annotate_info->y; 2547 p=annotate_info->text; 2548 break; 2549 } 2550 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2551 sizeof(*annotate_info->next)); 2552 if (annotate_info->next == (XAnnotateInfo *) NULL) 2553 return(MagickFalse); 2554 *annotate_info->next=(*annotate_info); 2555 annotate_info->next->previous=annotate_info; 2556 annotate_info=annotate_info->next; 2557 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2558 windows->image.width/MagickMax((ssize_t) 2559 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2560 if (annotate_info->text == (char *) NULL) 2561 return(MagickFalse); 2562 annotate_info->y+=annotate_info->height; 2563 if (annotate_info->y > (int) windows->image.height) 2564 annotate_info->y=(int) annotate_info->height; 2565 annotate_info->next=(XAnnotateInfo *) NULL; 2566 x=annotate_info->x; 2567 y=annotate_info->y; 2568 p=annotate_info->text; 2569 break; 2570 } 2571 } 2572 break; 2573 } 2574 case KeyRelease: 2575 { 2576 /* 2577 Respond to a user key release. 2578 */ 2579 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2580 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2581 state&=(~ModifierState); 2582 break; 2583 } 2584 case SelectionNotify: 2585 { 2586 Atom 2587 type; 2588 2589 int 2590 format; 2591 2592 unsigned char 2593 *data; 2594 2595 unsigned long 2596 after, 2597 length; 2598 2599 /* 2600 Obtain response from primary selection. 2601 */ 2602 if (event.xselection.property == (Atom) None) 2603 break; 2604 status=XGetWindowProperty(display,event.xselection.requestor, 2605 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2606 &type,&format,&length,&after,&data); 2607 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2608 (length == 0)) 2609 break; 2610 /* 2611 Annotate Image window with primary selection. 2612 */ 2613 for (i=0; i < (ssize_t) length; i++) 2614 { 2615 if ((char) data[i] != '\n') 2616 { 2617 /* 2618 Draw a single character on the Image window. 2619 */ 2620 *p=(char) data[i]; 2621 (void) XDrawString(display,windows->image.id,annotate_context, 2622 x,y,p,1); 2623 x+=XTextWidth(font_info,p,1); 2624 p++; 2625 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2626 continue; 2627 } 2628 /* 2629 Advance to the next line of text. 2630 */ 2631 *p='\0'; 2632 annotate_info->width=(unsigned int) XTextWidth(font_info, 2633 annotate_info->text,(int) strlen(annotate_info->text)); 2634 if (annotate_info->next != (XAnnotateInfo *) NULL) 2635 { 2636 /* 2637 Line of text already exists. 2638 */ 2639 annotate_info=annotate_info->next; 2640 x=annotate_info->x; 2641 y=annotate_info->y; 2642 p=annotate_info->text; 2643 continue; 2644 } 2645 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2646 sizeof(*annotate_info->next)); 2647 if (annotate_info->next == (XAnnotateInfo *) NULL) 2648 return(MagickFalse); 2649 *annotate_info->next=(*annotate_info); 2650 annotate_info->next->previous=annotate_info; 2651 annotate_info=annotate_info->next; 2652 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2653 windows->image.width/MagickMax((ssize_t) 2654 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2655 if (annotate_info->text == (char *) NULL) 2656 return(MagickFalse); 2657 annotate_info->y+=annotate_info->height; 2658 if (annotate_info->y > (int) windows->image.height) 2659 annotate_info->y=(int) annotate_info->height; 2660 annotate_info->next=(XAnnotateInfo *) NULL; 2661 x=annotate_info->x; 2662 y=annotate_info->y; 2663 p=annotate_info->text; 2664 } 2665 (void) XFree((void *) data); 2666 break; 2667 } 2668 default: 2669 break; 2670 } 2671 } while ((state & ExitState) == 0); 2672 (void) XFreeCursor(display,cursor); 2673 /* 2674 Annotation is relative to image configuration. 2675 */ 2676 width=(unsigned int) image->columns; 2677 height=(unsigned int) image->rows; 2678 x=0; 2679 y=0; 2680 if (windows->image.crop_geometry != (char *) NULL) 2681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2682 /* 2683 Initialize annotated image. 2684 */ 2685 XSetCursorState(display,windows,MagickTrue); 2686 XCheckRefreshWindows(display,windows); 2687 while (annotate_info != (XAnnotateInfo *) NULL) 2688 { 2689 if (annotate_info->width == 0) 2690 { 2691 /* 2692 No text on this line-- go to the next line of text. 2693 */ 2694 previous_info=annotate_info->previous; 2695 annotate_info->text=(char *) 2696 RelinquishMagickMemory(annotate_info->text); 2697 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2698 annotate_info=previous_info; 2699 continue; 2700 } 2701 /* 2702 Determine pixel index for box and pen color. 2703 */ 2704 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2705 if (windows->pixel_info->colors != 0) 2706 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2707 if (windows->pixel_info->pixels[i] == 2708 windows->pixel_info->pen_colors[box_id].pixel) 2709 { 2710 windows->pixel_info->box_index=(unsigned short) i; 2711 break; 2712 } 2713 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2714 if (windows->pixel_info->colors != 0) 2715 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2716 if (windows->pixel_info->pixels[i] == 2717 windows->pixel_info->pen_colors[pen_id].pixel) 2718 { 2719 windows->pixel_info->pen_index=(unsigned short) i; 2720 break; 2721 } 2722 /* 2723 Define the annotate geometry string. 2724 */ 2725 annotate_info->x=(int) 2726 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2727 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2728 windows->image.y)/windows->image.ximage->height; 2729 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2730 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2731 height*annotate_info->height/windows->image.ximage->height, 2732 annotate_info->x+x,annotate_info->y+y); 2733 /* 2734 Annotate image with text. 2735 */ 2736 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2737 exception); 2738 if (status == 0) 2739 return(MagickFalse); 2740 /* 2741 Free up memory. 2742 */ 2743 previous_info=annotate_info->previous; 2744 annotate_info->text=DestroyString(annotate_info->text); 2745 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2746 annotate_info=previous_info; 2747 } 2748 (void) XSetForeground(display,annotate_context, 2749 windows->pixel_info->foreground_color.pixel); 2750 (void) XSetBackground(display,annotate_context, 2751 windows->pixel_info->background_color.pixel); 2752 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2753 XSetCursorState(display,windows,MagickFalse); 2754 (void) XFreeFont(display,font_info); 2755 /* 2756 Update image configuration. 2757 */ 2758 XConfigureImageColormap(display,resource_info,windows,image,exception); 2759 (void) XConfigureImage(display,resource_info,windows,image,exception); 2760 return(MagickTrue); 2761} 2762 2763/* 2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2765% % 2766% % 2767% % 2768+ X B a c k g r o u n d I m a g e % 2769% % 2770% % 2771% % 2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2773% 2774% XBackgroundImage() displays the image in the background of a window. 2775% 2776% The format of the XBackgroundImage method is: 2777% 2778% MagickBooleanType XBackgroundImage(Display *display, 2779% XResourceInfo *resource_info,XWindows *windows,Image **image, 2780% ExceptionInfo *exception) 2781% 2782% A description of each parameter follows: 2783% 2784% o display: Specifies a connection to an X server; returned from 2785% XOpenDisplay. 2786% 2787% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2788% 2789% o windows: Specifies a pointer to a XWindows structure. 2790% 2791% o image: the image. 2792% 2793% o exception: return any errors or warnings in this structure. 2794% 2795*/ 2796static MagickBooleanType XBackgroundImage(Display *display, 2797 XResourceInfo *resource_info,XWindows *windows,Image **image, 2798 ExceptionInfo *exception) 2799{ 2800#define BackgroundImageTag "Background/Image" 2801 2802 int 2803 status; 2804 2805 static char 2806 window_id[MaxTextExtent] = "root"; 2807 2808 XResourceInfo 2809 background_resources; 2810 2811 /* 2812 Put image in background. 2813 */ 2814 status=XDialogWidget(display,windows,"Background", 2815 "Enter window id (id 0x00 selects window with pointer):",window_id); 2816 if (*window_id == '\0') 2817 return(MagickFalse); 2818 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2819 exception); 2820 XInfoWidget(display,windows,BackgroundImageTag); 2821 XSetCursorState(display,windows,MagickTrue); 2822 XCheckRefreshWindows(display,windows); 2823 background_resources=(*resource_info); 2824 background_resources.window_id=window_id; 2825 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2826 status=XDisplayBackgroundImage(display,&background_resources,*image, 2827 exception); 2828 if (status != MagickFalse) 2829 XClientMessage(display,windows->image.id,windows->im_protocols, 2830 windows->im_retain_colors,CurrentTime); 2831 XSetCursorState(display,windows,MagickFalse); 2832 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2833 exception); 2834 return(MagickTrue); 2835} 2836 2837/* 2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2839% % 2840% % 2841% % 2842+ X C h o p I m a g e % 2843% % 2844% % 2845% % 2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2847% 2848% XChopImage() chops the X image. 2849% 2850% The format of the XChopImage method is: 2851% 2852% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2853% XWindows *windows,Image **image,ExceptionInfo *exception) 2854% 2855% A description of each parameter follows: 2856% 2857% o display: Specifies a connection to an X server; returned from 2858% XOpenDisplay. 2859% 2860% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2861% 2862% o windows: Specifies a pointer to a XWindows structure. 2863% 2864% o image: the image. 2865% 2866% o exception: return any errors or warnings in this structure. 2867% 2868*/ 2869static MagickBooleanType XChopImage(Display *display, 2870 XResourceInfo *resource_info,XWindows *windows,Image **image, 2871 ExceptionInfo *exception) 2872{ 2873 static const char 2874 *ChopMenu[] = 2875 { 2876 "Direction", 2877 "Help", 2878 "Dismiss", 2879 (char *) NULL 2880 }; 2881 2882 static ModeType 2883 direction = HorizontalChopCommand; 2884 2885 static const ModeType 2886 ChopCommands[] = 2887 { 2888 ChopDirectionCommand, 2889 ChopHelpCommand, 2890 ChopDismissCommand 2891 }, 2892 DirectionCommands[] = 2893 { 2894 HorizontalChopCommand, 2895 VerticalChopCommand 2896 }; 2897 2898 char 2899 text[MaxTextExtent]; 2900 2901 Image 2902 *chop_image; 2903 2904 int 2905 id, 2906 x, 2907 y; 2908 2909 MagickRealType 2910 scale_factor; 2911 2912 RectangleInfo 2913 chop_info; 2914 2915 unsigned int 2916 distance, 2917 height, 2918 width; 2919 2920 size_t 2921 state; 2922 2923 XEvent 2924 event; 2925 2926 XSegment 2927 segment_info; 2928 2929 /* 2930 Map Command widget. 2931 */ 2932 (void) CloneString(&windows->command.name,"Chop"); 2933 windows->command.data=1; 2934 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2935 (void) XMapRaised(display,windows->command.id); 2936 XClientMessage(display,windows->image.id,windows->im_protocols, 2937 windows->im_update_widget,CurrentTime); 2938 /* 2939 Track pointer until button 1 is pressed. 2940 */ 2941 XQueryPosition(display,windows->image.id,&x,&y); 2942 (void) XSelectInput(display,windows->image.id, 2943 windows->image.attributes.event_mask | PointerMotionMask); 2944 state=DefaultState; 2945 do 2946 { 2947 if (windows->info.mapped != MagickFalse) 2948 { 2949 /* 2950 Display pointer position. 2951 */ 2952 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2953 x+windows->image.x,y+windows->image.y); 2954 XInfoWidget(display,windows,text); 2955 } 2956 /* 2957 Wait for next event. 2958 */ 2959 XScreenEvent(display,windows,&event,exception); 2960 if (event.xany.window == windows->command.id) 2961 { 2962 /* 2963 Select a command from the Command widget. 2964 */ 2965 id=XCommandWidget(display,windows,ChopMenu,&event); 2966 if (id < 0) 2967 continue; 2968 switch (ChopCommands[id]) 2969 { 2970 case ChopDirectionCommand: 2971 { 2972 char 2973 command[MaxTextExtent]; 2974 2975 static const char 2976 *Directions[] = 2977 { 2978 "horizontal", 2979 "vertical", 2980 (char *) NULL, 2981 }; 2982 2983 /* 2984 Select a command from the pop-up menu. 2985 */ 2986 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2987 if (id >= 0) 2988 direction=DirectionCommands[id]; 2989 break; 2990 } 2991 case ChopHelpCommand: 2992 { 2993 XTextViewWidget(display,resource_info,windows,MagickFalse, 2994 "Help Viewer - Image Chop",ImageChopHelp); 2995 break; 2996 } 2997 case ChopDismissCommand: 2998 { 2999 /* 3000 Prematurely exit. 3001 */ 3002 state|=EscapeState; 3003 state|=ExitState; 3004 break; 3005 } 3006 default: 3007 break; 3008 } 3009 continue; 3010 } 3011 switch (event.type) 3012 { 3013 case ButtonPress: 3014 { 3015 if (event.xbutton.button != Button1) 3016 break; 3017 if (event.xbutton.window != windows->image.id) 3018 break; 3019 /* 3020 User has committed to start point of chopping line. 3021 */ 3022 segment_info.x1=(short int) event.xbutton.x; 3023 segment_info.x2=(short int) event.xbutton.x; 3024 segment_info.y1=(short int) event.xbutton.y; 3025 segment_info.y2=(short int) event.xbutton.y; 3026 state|=ExitState; 3027 break; 3028 } 3029 case ButtonRelease: 3030 break; 3031 case Expose: 3032 break; 3033 case KeyPress: 3034 { 3035 char 3036 command[MaxTextExtent]; 3037 3038 KeySym 3039 key_symbol; 3040 3041 if (event.xkey.window != windows->image.id) 3042 break; 3043 /* 3044 Respond to a user key press. 3045 */ 3046 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3047 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3048 switch ((int) key_symbol) 3049 { 3050 case XK_Escape: 3051 case XK_F20: 3052 { 3053 /* 3054 Prematurely exit. 3055 */ 3056 state|=EscapeState; 3057 state|=ExitState; 3058 break; 3059 } 3060 case XK_F1: 3061 case XK_Help: 3062 { 3063 (void) XSetFunction(display,windows->image.highlight_context, 3064 GXcopy); 3065 XTextViewWidget(display,resource_info,windows,MagickFalse, 3066 "Help Viewer - Image Chop",ImageChopHelp); 3067 (void) XSetFunction(display,windows->image.highlight_context, 3068 GXinvert); 3069 break; 3070 } 3071 default: 3072 { 3073 (void) XBell(display,0); 3074 break; 3075 } 3076 } 3077 break; 3078 } 3079 case MotionNotify: 3080 { 3081 /* 3082 Map and unmap Info widget as text cursor crosses its boundaries. 3083 */ 3084 x=event.xmotion.x; 3085 y=event.xmotion.y; 3086 if (windows->info.mapped != MagickFalse) 3087 { 3088 if ((x < (int) (windows->info.x+windows->info.width)) && 3089 (y < (int) (windows->info.y+windows->info.height))) 3090 (void) XWithdrawWindow(display,windows->info.id, 3091 windows->info.screen); 3092 } 3093 else 3094 if ((x > (int) (windows->info.x+windows->info.width)) || 3095 (y > (int) (windows->info.y+windows->info.height))) 3096 (void) XMapWindow(display,windows->info.id); 3097 } 3098 } 3099 } while ((state & ExitState) == 0); 3100 (void) XSelectInput(display,windows->image.id, 3101 windows->image.attributes.event_mask); 3102 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3103 if ((state & EscapeState) != 0) 3104 return(MagickTrue); 3105 /* 3106 Draw line as pointer moves until the mouse button is released. 3107 */ 3108 chop_info.width=0; 3109 chop_info.height=0; 3110 chop_info.x=0; 3111 chop_info.y=0; 3112 distance=0; 3113 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3114 state=DefaultState; 3115 do 3116 { 3117 if (distance > 9) 3118 { 3119 /* 3120 Display info and draw chopping line. 3121 */ 3122 if (windows->info.mapped == MagickFalse) 3123 (void) XMapWindow(display,windows->info.id); 3124 (void) FormatLocaleString(text,MaxTextExtent, 3125 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3126 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3127 XInfoWidget(display,windows,text); 3128 XHighlightLine(display,windows->image.id, 3129 windows->image.highlight_context,&segment_info); 3130 } 3131 else 3132 if (windows->info.mapped != MagickFalse) 3133 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3134 /* 3135 Wait for next event. 3136 */ 3137 XScreenEvent(display,windows,&event,exception); 3138 if (distance > 9) 3139 XHighlightLine(display,windows->image.id, 3140 windows->image.highlight_context,&segment_info); 3141 switch (event.type) 3142 { 3143 case ButtonPress: 3144 { 3145 segment_info.x2=(short int) event.xmotion.x; 3146 segment_info.y2=(short int) event.xmotion.y; 3147 break; 3148 } 3149 case ButtonRelease: 3150 { 3151 /* 3152 User has committed to chopping line. 3153 */ 3154 segment_info.x2=(short int) event.xbutton.x; 3155 segment_info.y2=(short int) event.xbutton.y; 3156 state|=ExitState; 3157 break; 3158 } 3159 case Expose: 3160 break; 3161 case MotionNotify: 3162 { 3163 segment_info.x2=(short int) event.xmotion.x; 3164 segment_info.y2=(short int) event.xmotion.y; 3165 } 3166 default: 3167 break; 3168 } 3169 /* 3170 Check boundary conditions. 3171 */ 3172 if (segment_info.x2 < 0) 3173 segment_info.x2=0; 3174 else 3175 if (segment_info.x2 > windows->image.ximage->width) 3176 segment_info.x2=windows->image.ximage->width; 3177 if (segment_info.y2 < 0) 3178 segment_info.y2=0; 3179 else 3180 if (segment_info.y2 > windows->image.ximage->height) 3181 segment_info.y2=windows->image.ximage->height; 3182 distance=(unsigned int) 3183 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3184 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3185 /* 3186 Compute chopping geometry. 3187 */ 3188 if (direction == HorizontalChopCommand) 3189 { 3190 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3191 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3192 chop_info.height=0; 3193 chop_info.y=0; 3194 if (segment_info.x1 > (int) segment_info.x2) 3195 { 3196 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3197 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3198 } 3199 } 3200 else 3201 { 3202 chop_info.width=0; 3203 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3204 chop_info.x=0; 3205 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3206 if (segment_info.y1 > segment_info.y2) 3207 { 3208 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3209 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3210 } 3211 } 3212 } while ((state & ExitState) == 0); 3213 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3215 if (distance <= 9) 3216 return(MagickTrue); 3217 /* 3218 Image chopping is relative to image configuration. 3219 */ 3220 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3221 exception); 3222 XSetCursorState(display,windows,MagickTrue); 3223 XCheckRefreshWindows(display,windows); 3224 windows->image.window_changes.width=windows->image.ximage->width- 3225 (unsigned int) chop_info.width; 3226 windows->image.window_changes.height=windows->image.ximage->height- 3227 (unsigned int) chop_info.height; 3228 width=(unsigned int) (*image)->columns; 3229 height=(unsigned int) (*image)->rows; 3230 x=0; 3231 y=0; 3232 if (windows->image.crop_geometry != (char *) NULL) 3233 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3234 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3235 chop_info.x+=x; 3236 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3237 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3238 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3239 chop_info.y+=y; 3240 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3241 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3242 /* 3243 Chop image. 3244 */ 3245 chop_image=ChopImage(*image,&chop_info,exception); 3246 XSetCursorState(display,windows,MagickFalse); 3247 if (chop_image == (Image *) NULL) 3248 return(MagickFalse); 3249 *image=DestroyImage(*image); 3250 *image=chop_image; 3251 /* 3252 Update image configuration. 3253 */ 3254 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3255 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3256 return(MagickTrue); 3257} 3258 3259/* 3260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3261% % 3262% % 3263% % 3264+ X C o l o r E d i t I m a g e % 3265% % 3266% % 3267% % 3268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3269% 3270% XColorEditImage() allows the user to interactively change the color of one 3271% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3272% 3273% The format of the XColorEditImage method is: 3274% 3275% MagickBooleanType XColorEditImage(Display *display, 3276% XResourceInfo *resource_info,XWindows *windows,Image **image, 3277% ExceptionInfo *exception) 3278% 3279% A description of each parameter follows: 3280% 3281% o display: Specifies a connection to an X server; returned from 3282% XOpenDisplay. 3283% 3284% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3285% 3286% o windows: Specifies a pointer to a XWindows structure. 3287% 3288% o image: the image; returned from ReadImage. 3289% 3290% o exception: return any errors or warnings in this structure. 3291% 3292*/ 3293static MagickBooleanType XColorEditImage(Display *display, 3294 XResourceInfo *resource_info,XWindows *windows,Image **image, 3295 ExceptionInfo *exception) 3296{ 3297 static const char 3298 *ColorEditMenu[] = 3299 { 3300 "Method", 3301 "Pixel Color", 3302 "Border Color", 3303 "Fuzz", 3304 "Undo", 3305 "Help", 3306 "Dismiss", 3307 (char *) NULL 3308 }; 3309 3310 static const ModeType 3311 ColorEditCommands[] = 3312 { 3313 ColorEditMethodCommand, 3314 ColorEditColorCommand, 3315 ColorEditBorderCommand, 3316 ColorEditFuzzCommand, 3317 ColorEditUndoCommand, 3318 ColorEditHelpCommand, 3319 ColorEditDismissCommand 3320 }; 3321 3322 static PaintMethod 3323 method = PointMethod; 3324 3325 static unsigned int 3326 pen_id = 0; 3327 3328 static XColor 3329 border_color = { 0, 0, 0, 0, 0, 0 }; 3330 3331 char 3332 command[MaxTextExtent], 3333 text[MaxTextExtent]; 3334 3335 Cursor 3336 cursor; 3337 3338 int 3339 entry, 3340 id, 3341 x, 3342 x_offset, 3343 y, 3344 y_offset; 3345 3346 register Quantum 3347 *q; 3348 3349 register ssize_t 3350 i; 3351 3352 unsigned int 3353 height, 3354 width; 3355 3356 size_t 3357 state; 3358 3359 XColor 3360 color; 3361 3362 XEvent 3363 event; 3364 3365 /* 3366 Map Command widget. 3367 */ 3368 (void) CloneString(&windows->command.name,"Color Edit"); 3369 windows->command.data=4; 3370 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3371 (void) XMapRaised(display,windows->command.id); 3372 XClientMessage(display,windows->image.id,windows->im_protocols, 3373 windows->im_update_widget,CurrentTime); 3374 /* 3375 Make cursor. 3376 */ 3377 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3378 resource_info->background_color,resource_info->foreground_color); 3379 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3380 /* 3381 Track pointer until button 1 is pressed. 3382 */ 3383 XQueryPosition(display,windows->image.id,&x,&y); 3384 (void) XSelectInput(display,windows->image.id, 3385 windows->image.attributes.event_mask | PointerMotionMask); 3386 state=DefaultState; 3387 do 3388 { 3389 if (windows->info.mapped != MagickFalse) 3390 { 3391 /* 3392 Display pointer position. 3393 */ 3394 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3395 x+windows->image.x,y+windows->image.y); 3396 XInfoWidget(display,windows,text); 3397 } 3398 /* 3399 Wait for next event. 3400 */ 3401 XScreenEvent(display,windows,&event,exception); 3402 if (event.xany.window == windows->command.id) 3403 { 3404 /* 3405 Select a command from the Command widget. 3406 */ 3407 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3408 if (id < 0) 3409 { 3410 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3411 continue; 3412 } 3413 switch (ColorEditCommands[id]) 3414 { 3415 case ColorEditMethodCommand: 3416 { 3417 char 3418 **methods; 3419 3420 /* 3421 Select a method from the pop-up menu. 3422 */ 3423 methods=(char **) GetCommandOptions(MagickMethodOptions); 3424 if (methods == (char **) NULL) 3425 break; 3426 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3427 (const char **) methods,command); 3428 if (entry >= 0) 3429 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3430 MagickFalse,methods[entry]); 3431 methods=DestroyStringList(methods); 3432 break; 3433 } 3434 case ColorEditColorCommand: 3435 { 3436 const char 3437 *ColorMenu[MaxNumberPens]; 3438 3439 int 3440 pen_number; 3441 3442 /* 3443 Initialize menu selections. 3444 */ 3445 for (i=0; i < (int) (MaxNumberPens-2); i++) 3446 ColorMenu[i]=resource_info->pen_colors[i]; 3447 ColorMenu[MaxNumberPens-2]="Browser..."; 3448 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3449 /* 3450 Select a pen color from the pop-up menu. 3451 */ 3452 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3453 (const char **) ColorMenu,command); 3454 if (pen_number < 0) 3455 break; 3456 if (pen_number == (MaxNumberPens-2)) 3457 { 3458 static char 3459 color_name[MaxTextExtent] = "gray"; 3460 3461 /* 3462 Select a pen color from a dialog. 3463 */ 3464 resource_info->pen_colors[pen_number]=color_name; 3465 XColorBrowserWidget(display,windows,"Select",color_name); 3466 if (*color_name == '\0') 3467 break; 3468 } 3469 /* 3470 Set pen color. 3471 */ 3472 (void) XParseColor(display,windows->map_info->colormap, 3473 resource_info->pen_colors[pen_number],&color); 3474 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3475 (unsigned int) MaxColors,&color); 3476 windows->pixel_info->pen_colors[pen_number]=color; 3477 pen_id=(unsigned int) pen_number; 3478 break; 3479 } 3480 case ColorEditBorderCommand: 3481 { 3482 const char 3483 *ColorMenu[MaxNumberPens]; 3484 3485 int 3486 pen_number; 3487 3488 /* 3489 Initialize menu selections. 3490 */ 3491 for (i=0; i < (int) (MaxNumberPens-2); i++) 3492 ColorMenu[i]=resource_info->pen_colors[i]; 3493 ColorMenu[MaxNumberPens-2]="Browser..."; 3494 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3495 /* 3496 Select a pen color from the pop-up menu. 3497 */ 3498 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3499 (const char **) ColorMenu,command); 3500 if (pen_number < 0) 3501 break; 3502 if (pen_number == (MaxNumberPens-2)) 3503 { 3504 static char 3505 color_name[MaxTextExtent] = "gray"; 3506 3507 /* 3508 Select a pen color from a dialog. 3509 */ 3510 resource_info->pen_colors[pen_number]=color_name; 3511 XColorBrowserWidget(display,windows,"Select",color_name); 3512 if (*color_name == '\0') 3513 break; 3514 } 3515 /* 3516 Set border color. 3517 */ 3518 (void) XParseColor(display,windows->map_info->colormap, 3519 resource_info->pen_colors[pen_number],&border_color); 3520 break; 3521 } 3522 case ColorEditFuzzCommand: 3523 { 3524 static char 3525 fuzz[MaxTextExtent]; 3526 3527 static const char 3528 *FuzzMenu[] = 3529 { 3530 "0%", 3531 "2%", 3532 "5%", 3533 "10%", 3534 "15%", 3535 "Dialog...", 3536 (char *) NULL, 3537 }; 3538 3539 /* 3540 Select a command from the pop-up menu. 3541 */ 3542 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3543 command); 3544 if (entry < 0) 3545 break; 3546 if (entry != 5) 3547 { 3548 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3549 QuantumRange+1.0); 3550 break; 3551 } 3552 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3553 (void) XDialogWidget(display,windows,"Ok", 3554 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3555 if (*fuzz == '\0') 3556 break; 3557 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3558 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3559 1.0); 3560 break; 3561 } 3562 case ColorEditUndoCommand: 3563 { 3564 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3565 image,exception); 3566 break; 3567 } 3568 case ColorEditHelpCommand: 3569 default: 3570 { 3571 XTextViewWidget(display,resource_info,windows,MagickFalse, 3572 "Help Viewer - Image Annotation",ImageColorEditHelp); 3573 break; 3574 } 3575 case ColorEditDismissCommand: 3576 { 3577 /* 3578 Prematurely exit. 3579 */ 3580 state|=EscapeState; 3581 state|=ExitState; 3582 break; 3583 } 3584 } 3585 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3586 continue; 3587 } 3588 switch (event.type) 3589 { 3590 case ButtonPress: 3591 { 3592 if (event.xbutton.button != Button1) 3593 break; 3594 if ((event.xbutton.window != windows->image.id) && 3595 (event.xbutton.window != windows->magnify.id)) 3596 break; 3597 /* 3598 exit loop. 3599 */ 3600 x=event.xbutton.x; 3601 y=event.xbutton.y; 3602 (void) XMagickCommand(display,resource_info,windows, 3603 SaveToUndoBufferCommand,image,exception); 3604 state|=UpdateConfigurationState; 3605 break; 3606 } 3607 case ButtonRelease: 3608 { 3609 if (event.xbutton.button != Button1) 3610 break; 3611 if ((event.xbutton.window != windows->image.id) && 3612 (event.xbutton.window != windows->magnify.id)) 3613 break; 3614 /* 3615 Update colormap information. 3616 */ 3617 x=event.xbutton.x; 3618 y=event.xbutton.y; 3619 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3620 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3621 XInfoWidget(display,windows,text); 3622 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3623 state&=(~UpdateConfigurationState); 3624 break; 3625 } 3626 case Expose: 3627 break; 3628 case KeyPress: 3629 { 3630 KeySym 3631 key_symbol; 3632 3633 if (event.xkey.window == windows->magnify.id) 3634 { 3635 Window 3636 window; 3637 3638 window=windows->magnify.id; 3639 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3640 } 3641 if (event.xkey.window != windows->image.id) 3642 break; 3643 /* 3644 Respond to a user key press. 3645 */ 3646 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3647 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3648 switch ((int) key_symbol) 3649 { 3650 case XK_Escape: 3651 case XK_F20: 3652 { 3653 /* 3654 Prematurely exit. 3655 */ 3656 state|=ExitState; 3657 break; 3658 } 3659 case XK_F1: 3660 case XK_Help: 3661 { 3662 XTextViewWidget(display,resource_info,windows,MagickFalse, 3663 "Help Viewer - Image Annotation",ImageColorEditHelp); 3664 break; 3665 } 3666 default: 3667 { 3668 (void) XBell(display,0); 3669 break; 3670 } 3671 } 3672 break; 3673 } 3674 case MotionNotify: 3675 { 3676 /* 3677 Map and unmap Info widget as cursor crosses its boundaries. 3678 */ 3679 x=event.xmotion.x; 3680 y=event.xmotion.y; 3681 if (windows->info.mapped != MagickFalse) 3682 { 3683 if ((x < (int) (windows->info.x+windows->info.width)) && 3684 (y < (int) (windows->info.y+windows->info.height))) 3685 (void) XWithdrawWindow(display,windows->info.id, 3686 windows->info.screen); 3687 } 3688 else 3689 if ((x > (int) (windows->info.x+windows->info.width)) || 3690 (y > (int) (windows->info.y+windows->info.height))) 3691 (void) XMapWindow(display,windows->info.id); 3692 break; 3693 } 3694 default: 3695 break; 3696 } 3697 if (event.xany.window == windows->magnify.id) 3698 { 3699 x=windows->magnify.x-windows->image.x; 3700 y=windows->magnify.y-windows->image.y; 3701 } 3702 x_offset=x; 3703 y_offset=y; 3704 if ((state & UpdateConfigurationState) != 0) 3705 { 3706 CacheView 3707 *image_view; 3708 3709 int 3710 x, 3711 y; 3712 3713 /* 3714 Pixel edit is relative to image configuration. 3715 */ 3716 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3717 MagickTrue); 3718 color=windows->pixel_info->pen_colors[pen_id]; 3719 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3720 width=(unsigned int) (*image)->columns; 3721 height=(unsigned int) (*image)->rows; 3722 x=0; 3723 y=0; 3724 if (windows->image.crop_geometry != (char *) NULL) 3725 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3726 &width,&height); 3727 x_offset=(int) 3728 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3729 y_offset=(int) 3730 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3731 if ((x_offset < 0) || (y_offset < 0)) 3732 continue; 3733 if ((x_offset >= (int) (*image)->columns) || 3734 (y_offset >= (int) (*image)->rows)) 3735 continue; 3736 image_view=AcquireCacheView(*image); 3737 switch (method) 3738 { 3739 case PointMethod: 3740 default: 3741 { 3742 /* 3743 Update color information using point algorithm. 3744 */ 3745 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3746 return(MagickFalse); 3747 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3748 (ssize_t) y_offset,1,1,exception); 3749 if (q == (Quantum *) NULL) 3750 break; 3751 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3752 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3753 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3754 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3755 break; 3756 } 3757 case ReplaceMethod: 3758 { 3759 PixelInfo 3760 pixel, 3761 target; 3762 3763 /* 3764 Update color information using replace algorithm. 3765 */ 3766 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3767 x_offset,(ssize_t) y_offset,&target,exception); 3768 if ((*image)->storage_class == DirectClass) 3769 { 3770 for (y=0; y < (int) (*image)->rows; y++) 3771 { 3772 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3773 (*image)->columns,1,exception); 3774 if (q == (Quantum *) NULL) 3775 break; 3776 for (x=0; x < (int) (*image)->columns; x++) 3777 { 3778 GetPixelInfoPixel(*image,q,&pixel); 3779 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3780 { 3781 SetPixelRed(*image,ScaleShortToQuantum( 3782 color.red),q); 3783 SetPixelGreen(*image,ScaleShortToQuantum( 3784 color.green),q); 3785 SetPixelBlue(*image,ScaleShortToQuantum( 3786 color.blue),q); 3787 } 3788 q+=GetPixelChannels(*image); 3789 } 3790 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3791 break; 3792 } 3793 } 3794 else 3795 { 3796 for (i=0; i < (ssize_t) (*image)->colors; i++) 3797 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3798 { 3799 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3800 color.red); 3801 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3802 color.green); 3803 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3804 color.blue); 3805 } 3806 (void) SyncImage(*image,exception); 3807 } 3808 break; 3809 } 3810 case FloodfillMethod: 3811 case FillToBorderMethod: 3812 { 3813 DrawInfo 3814 *draw_info; 3815 3816 PixelInfo 3817 target; 3818 3819 /* 3820 Update color information using floodfill algorithm. 3821 */ 3822 (void) GetOneVirtualPixelInfo(*image, 3823 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3824 y_offset,&target,exception); 3825 if (method == FillToBorderMethod) 3826 { 3827 target.red=(MagickRealType) 3828 ScaleShortToQuantum(border_color.red); 3829 target.green=(MagickRealType) 3830 ScaleShortToQuantum(border_color.green); 3831 target.blue=(MagickRealType) 3832 ScaleShortToQuantum(border_color.blue); 3833 } 3834 draw_info=CloneDrawInfo(resource_info->image_info, 3835 (DrawInfo *) NULL); 3836 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3837 AllCompliance,&draw_info->fill,exception); 3838 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3839 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3840 MagickFalse : MagickTrue,exception); 3841 draw_info=DestroyDrawInfo(draw_info); 3842 break; 3843 } 3844 case ResetMethod: 3845 { 3846 /* 3847 Update color information using reset algorithm. 3848 */ 3849 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3850 return(MagickFalse); 3851 for (y=0; y < (int) (*image)->rows; y++) 3852 { 3853 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3854 (*image)->columns,1,exception); 3855 if (q == (Quantum *) NULL) 3856 break; 3857 for (x=0; x < (int) (*image)->columns; x++) 3858 { 3859 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3860 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3861 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3862 q+=GetPixelChannels(*image); 3863 } 3864 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3865 break; 3866 } 3867 break; 3868 } 3869 } 3870 image_view=DestroyCacheView(image_view); 3871 state&=(~UpdateConfigurationState); 3872 } 3873 } while ((state & ExitState) == 0); 3874 (void) XSelectInput(display,windows->image.id, 3875 windows->image.attributes.event_mask); 3876 XSetCursorState(display,windows,MagickFalse); 3877 (void) XFreeCursor(display,cursor); 3878 return(MagickTrue); 3879} 3880 3881/* 3882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3883% % 3884% % 3885% % 3886+ X C o m p o s i t e I m a g e % 3887% % 3888% % 3889% % 3890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3891% 3892% XCompositeImage() requests an image name from the user, reads the image and 3893% composites it with the X window image at a location the user chooses with 3894% the pointer. 3895% 3896% The format of the XCompositeImage method is: 3897% 3898% MagickBooleanType XCompositeImage(Display *display, 3899% XResourceInfo *resource_info,XWindows *windows,Image *image, 3900% ExceptionInfo *exception) 3901% 3902% A description of each parameter follows: 3903% 3904% o display: Specifies a connection to an X server; returned from 3905% XOpenDisplay. 3906% 3907% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3908% 3909% o windows: Specifies a pointer to a XWindows structure. 3910% 3911% o image: the image; returned from ReadImage. 3912% 3913% o exception: return any errors or warnings in this structure. 3914% 3915*/ 3916static MagickBooleanType XCompositeImage(Display *display, 3917 XResourceInfo *resource_info,XWindows *windows,Image *image, 3918 ExceptionInfo *exception) 3919{ 3920 static char 3921 displacement_geometry[MaxTextExtent] = "30x30", 3922 filename[MaxTextExtent] = "\0"; 3923 3924 static const char 3925 *CompositeMenu[] = 3926 { 3927 "Operators", 3928 "Dissolve", 3929 "Displace", 3930 "Help", 3931 "Dismiss", 3932 (char *) NULL 3933 }; 3934 3935 static CompositeOperator 3936 compose = CopyCompositeOp; 3937 3938 static const ModeType 3939 CompositeCommands[] = 3940 { 3941 CompositeOperatorsCommand, 3942 CompositeDissolveCommand, 3943 CompositeDisplaceCommand, 3944 CompositeHelpCommand, 3945 CompositeDismissCommand 3946 }; 3947 3948 char 3949 text[MaxTextExtent]; 3950 3951 Cursor 3952 cursor; 3953 3954 Image 3955 *composite_image; 3956 3957 int 3958 entry, 3959 id, 3960 x, 3961 y; 3962 3963 MagickRealType 3964 blend, 3965 scale_factor; 3966 3967 RectangleInfo 3968 highlight_info, 3969 composite_info; 3970 3971 unsigned int 3972 height, 3973 width; 3974 3975 size_t 3976 state; 3977 3978 XEvent 3979 event; 3980 3981 /* 3982 Request image file name from user. 3983 */ 3984 XFileBrowserWidget(display,windows,"Composite",filename); 3985 if (*filename == '\0') 3986 return(MagickTrue); 3987 /* 3988 Read image. 3989 */ 3990 XSetCursorState(display,windows,MagickTrue); 3991 XCheckRefreshWindows(display,windows); 3992 (void) CopyMagickString(resource_info->image_info->filename,filename, 3993 MaxTextExtent); 3994 composite_image=ReadImage(resource_info->image_info,exception); 3995 CatchException(exception); 3996 XSetCursorState(display,windows,MagickFalse); 3997 if (composite_image == (Image *) NULL) 3998 return(MagickFalse); 3999 /* 4000 Map Command widget. 4001 */ 4002 (void) CloneString(&windows->command.name,"Composite"); 4003 windows->command.data=1; 4004 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4005 (void) XMapRaised(display,windows->command.id); 4006 XClientMessage(display,windows->image.id,windows->im_protocols, 4007 windows->im_update_widget,CurrentTime); 4008 /* 4009 Track pointer until button 1 is pressed. 4010 */ 4011 XQueryPosition(display,windows->image.id,&x,&y); 4012 (void) XSelectInput(display,windows->image.id, 4013 windows->image.attributes.event_mask | PointerMotionMask); 4014 composite_info.x=(ssize_t) windows->image.x+x; 4015 composite_info.y=(ssize_t) windows->image.y+y; 4016 composite_info.width=0; 4017 composite_info.height=0; 4018 cursor=XCreateFontCursor(display,XC_ul_angle); 4019 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4020 blend=0.0; 4021 state=DefaultState; 4022 do 4023 { 4024 if (windows->info.mapped != MagickFalse) 4025 { 4026 /* 4027 Display pointer position. 4028 */ 4029 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4030 (long) composite_info.x,(long) composite_info.y); 4031 XInfoWidget(display,windows,text); 4032 } 4033 highlight_info=composite_info; 4034 highlight_info.x=composite_info.x-windows->image.x; 4035 highlight_info.y=composite_info.y-windows->image.y; 4036 XHighlightRectangle(display,windows->image.id, 4037 windows->image.highlight_context,&highlight_info); 4038 /* 4039 Wait for next event. 4040 */ 4041 XScreenEvent(display,windows,&event,exception); 4042 XHighlightRectangle(display,windows->image.id, 4043 windows->image.highlight_context,&highlight_info); 4044 if (event.xany.window == windows->command.id) 4045 { 4046 /* 4047 Select a command from the Command widget. 4048 */ 4049 id=XCommandWidget(display,windows,CompositeMenu,&event); 4050 if (id < 0) 4051 continue; 4052 switch (CompositeCommands[id]) 4053 { 4054 case CompositeOperatorsCommand: 4055 { 4056 char 4057 command[MaxTextExtent], 4058 **operators; 4059 4060 /* 4061 Select a command from the pop-up menu. 4062 */ 4063 operators=GetCommandOptions(MagickComposeOptions); 4064 if (operators == (char **) NULL) 4065 break; 4066 entry=XMenuWidget(display,windows,CompositeMenu[id], 4067 (const char **) operators,command); 4068 if (entry >= 0) 4069 compose=(CompositeOperator) ParseCommandOption( 4070 MagickComposeOptions,MagickFalse,operators[entry]); 4071 operators=DestroyStringList(operators); 4072 break; 4073 } 4074 case CompositeDissolveCommand: 4075 { 4076 static char 4077 factor[MaxTextExtent] = "20.0"; 4078 4079 /* 4080 Dissolve the two images a given percent. 4081 */ 4082 (void) XSetFunction(display,windows->image.highlight_context, 4083 GXcopy); 4084 (void) XDialogWidget(display,windows,"Dissolve", 4085 "Enter the blend factor (0.0 - 99.9%):",factor); 4086 (void) XSetFunction(display,windows->image.highlight_context, 4087 GXinvert); 4088 if (*factor == '\0') 4089 break; 4090 blend=StringToDouble(factor,(char **) NULL); 4091 compose=DissolveCompositeOp; 4092 break; 4093 } 4094 case CompositeDisplaceCommand: 4095 { 4096 /* 4097 Get horizontal and vertical scale displacement geometry. 4098 */ 4099 (void) XSetFunction(display,windows->image.highlight_context, 4100 GXcopy); 4101 (void) XDialogWidget(display,windows,"Displace", 4102 "Enter the horizontal and vertical scale:",displacement_geometry); 4103 (void) XSetFunction(display,windows->image.highlight_context, 4104 GXinvert); 4105 if (*displacement_geometry == '\0') 4106 break; 4107 compose=DisplaceCompositeOp; 4108 break; 4109 } 4110 case CompositeHelpCommand: 4111 { 4112 (void) XSetFunction(display,windows->image.highlight_context, 4113 GXcopy); 4114 XTextViewWidget(display,resource_info,windows,MagickFalse, 4115 "Help Viewer - Image Composite",ImageCompositeHelp); 4116 (void) XSetFunction(display,windows->image.highlight_context, 4117 GXinvert); 4118 break; 4119 } 4120 case CompositeDismissCommand: 4121 { 4122 /* 4123 Prematurely exit. 4124 */ 4125 state|=EscapeState; 4126 state|=ExitState; 4127 break; 4128 } 4129 default: 4130 break; 4131 } 4132 continue; 4133 } 4134 switch (event.type) 4135 { 4136 case ButtonPress: 4137 { 4138 if (image->debug != MagickFalse) 4139 (void) LogMagickEvent(X11Event,GetMagickModule(), 4140 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4141 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4142 if (event.xbutton.button != Button1) 4143 break; 4144 if (event.xbutton.window != windows->image.id) 4145 break; 4146 /* 4147 Change cursor. 4148 */ 4149 composite_info.width=composite_image->columns; 4150 composite_info.height=composite_image->rows; 4151 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4152 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4153 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4154 break; 4155 } 4156 case ButtonRelease: 4157 { 4158 if (image->debug != MagickFalse) 4159 (void) LogMagickEvent(X11Event,GetMagickModule(), 4160 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4161 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4162 if (event.xbutton.button != Button1) 4163 break; 4164 if (event.xbutton.window != windows->image.id) 4165 break; 4166 if ((composite_info.width != 0) && (composite_info.height != 0)) 4167 { 4168 /* 4169 User has selected the location of the composite image. 4170 */ 4171 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4172 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4173 state|=ExitState; 4174 } 4175 break; 4176 } 4177 case Expose: 4178 break; 4179 case KeyPress: 4180 { 4181 char 4182 command[MaxTextExtent]; 4183 4184 KeySym 4185 key_symbol; 4186 4187 int 4188 length; 4189 4190 if (event.xkey.window != windows->image.id) 4191 break; 4192 /* 4193 Respond to a user key press. 4194 */ 4195 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4196 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4197 *(command+length)='\0'; 4198 if (image->debug != MagickFalse) 4199 (void) LogMagickEvent(X11Event,GetMagickModule(), 4200 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4201 switch ((int) key_symbol) 4202 { 4203 case XK_Escape: 4204 case XK_F20: 4205 { 4206 /* 4207 Prematurely exit. 4208 */ 4209 composite_image=DestroyImage(composite_image); 4210 state|=EscapeState; 4211 state|=ExitState; 4212 break; 4213 } 4214 case XK_F1: 4215 case XK_Help: 4216 { 4217 (void) XSetFunction(display,windows->image.highlight_context, 4218 GXcopy); 4219 XTextViewWidget(display,resource_info,windows,MagickFalse, 4220 "Help Viewer - Image Composite",ImageCompositeHelp); 4221 (void) XSetFunction(display,windows->image.highlight_context, 4222 GXinvert); 4223 break; 4224 } 4225 default: 4226 { 4227 (void) XBell(display,0); 4228 break; 4229 } 4230 } 4231 break; 4232 } 4233 case MotionNotify: 4234 { 4235 /* 4236 Map and unmap Info widget as text cursor crosses its boundaries. 4237 */ 4238 x=event.xmotion.x; 4239 y=event.xmotion.y; 4240 if (windows->info.mapped != MagickFalse) 4241 { 4242 if ((x < (int) (windows->info.x+windows->info.width)) && 4243 (y < (int) (windows->info.y+windows->info.height))) 4244 (void) XWithdrawWindow(display,windows->info.id, 4245 windows->info.screen); 4246 } 4247 else 4248 if ((x > (int) (windows->info.x+windows->info.width)) || 4249 (y > (int) (windows->info.y+windows->info.height))) 4250 (void) XMapWindow(display,windows->info.id); 4251 composite_info.x=(ssize_t) windows->image.x+x; 4252 composite_info.y=(ssize_t) windows->image.y+y; 4253 break; 4254 } 4255 default: 4256 { 4257 if (image->debug != MagickFalse) 4258 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4259 event.type); 4260 break; 4261 } 4262 } 4263 } while ((state & ExitState) == 0); 4264 (void) XSelectInput(display,windows->image.id, 4265 windows->image.attributes.event_mask); 4266 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4267 XSetCursorState(display,windows,MagickFalse); 4268 (void) XFreeCursor(display,cursor); 4269 if ((state & EscapeState) != 0) 4270 return(MagickTrue); 4271 /* 4272 Image compositing is relative to image configuration. 4273 */ 4274 XSetCursorState(display,windows,MagickTrue); 4275 XCheckRefreshWindows(display,windows); 4276 width=(unsigned int) image->columns; 4277 height=(unsigned int) image->rows; 4278 x=0; 4279 y=0; 4280 if (windows->image.crop_geometry != (char *) NULL) 4281 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4282 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4283 composite_info.x+=x; 4284 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4285 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4286 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4287 composite_info.y+=y; 4288 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4289 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4290 if ((composite_info.width != composite_image->columns) || 4291 (composite_info.height != composite_image->rows)) 4292 { 4293 Image 4294 *resize_image; 4295 4296 /* 4297 Scale composite image. 4298 */ 4299 resize_image=ResizeImage(composite_image,composite_info.width, 4300 composite_info.height,composite_image->filter,composite_image->blur, 4301 exception); 4302 composite_image=DestroyImage(composite_image); 4303 if (resize_image == (Image *) NULL) 4304 { 4305 XSetCursorState(display,windows,MagickFalse); 4306 return(MagickFalse); 4307 } 4308 composite_image=resize_image; 4309 } 4310 if (compose == DisplaceCompositeOp) 4311 (void) SetImageArtifact(composite_image,"compose:args", 4312 displacement_geometry); 4313 if (blend != 0.0) 4314 { 4315 CacheView 4316 *image_view; 4317 4318 int 4319 y; 4320 4321 Quantum 4322 opacity; 4323 4324 register int 4325 x; 4326 4327 register Quantum 4328 *q; 4329 4330 /* 4331 Create mattes for blending. 4332 */ 4333 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4334 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4335 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4336 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4337 return(MagickFalse); 4338 image->matte=MagickTrue; 4339 image_view=AcquireCacheView(image); 4340 for (y=0; y < (int) image->rows; y++) 4341 { 4342 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4343 exception); 4344 if (q == (Quantum *) NULL) 4345 break; 4346 for (x=0; x < (int) image->columns; x++) 4347 { 4348 SetPixelAlpha(image,opacity,q); 4349 q+=GetPixelChannels(image); 4350 } 4351 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4352 break; 4353 } 4354 image_view=DestroyCacheView(image_view); 4355 } 4356 /* 4357 Composite image with X Image window. 4358 */ 4359 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4360 composite_info.y,exception); 4361 composite_image=DestroyImage(composite_image); 4362 XSetCursorState(display,windows,MagickFalse); 4363 /* 4364 Update image configuration. 4365 */ 4366 XConfigureImageColormap(display,resource_info,windows,image,exception); 4367 (void) XConfigureImage(display,resource_info,windows,image,exception); 4368 return(MagickTrue); 4369} 4370 4371/* 4372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4373% % 4374% % 4375% % 4376+ X C o n f i g u r e I m a g e % 4377% % 4378% % 4379% % 4380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4381% 4382% XConfigureImage() creates a new X image. It also notifies the window 4383% manager of the new image size and configures the transient widows. 4384% 4385% The format of the XConfigureImage method is: 4386% 4387% MagickBooleanType XConfigureImage(Display *display, 4388% XResourceInfo *resource_info,XWindows *windows,Image *image, 4389% ExceptionInfo *exception) 4390% 4391% A description of each parameter follows: 4392% 4393% o display: Specifies a connection to an X server; returned from 4394% XOpenDisplay. 4395% 4396% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4397% 4398% o windows: Specifies a pointer to a XWindows structure. 4399% 4400% o image: the image. 4401% 4402% o exception: return any errors or warnings in this structure. 4403% 4404% o exception: return any errors or warnings in this structure. 4405% 4406*/ 4407static MagickBooleanType XConfigureImage(Display *display, 4408 XResourceInfo *resource_info,XWindows *windows,Image *image, 4409 ExceptionInfo *exception) 4410{ 4411 char 4412 geometry[MaxTextExtent]; 4413 4414 MagickStatusType 4415 status; 4416 4417 size_t 4418 mask, 4419 height, 4420 width; 4421 4422 ssize_t 4423 x, 4424 y; 4425 4426 XSizeHints 4427 *size_hints; 4428 4429 XWindowChanges 4430 window_changes; 4431 4432 /* 4433 Dismiss if window dimensions are zero. 4434 */ 4435 width=(unsigned int) windows->image.window_changes.width; 4436 height=(unsigned int) windows->image.window_changes.height; 4437 if (image->debug != MagickFalse) 4438 (void) LogMagickEvent(X11Event,GetMagickModule(), 4439 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4440 windows->image.ximage->height,(double) width,(double) height); 4441 if ((width*height) == 0) 4442 return(MagickTrue); 4443 x=0; 4444 y=0; 4445 /* 4446 Resize image to fit Image window dimensions. 4447 */ 4448 XSetCursorState(display,windows,MagickTrue); 4449 (void) XFlush(display); 4450 if (((int) width != windows->image.ximage->width) || 4451 ((int) height != windows->image.ximage->height)) 4452 image->taint=MagickTrue; 4453 windows->magnify.x=(int) 4454 width*windows->magnify.x/windows->image.ximage->width; 4455 windows->magnify.y=(int) 4456 height*windows->magnify.y/windows->image.ximage->height; 4457 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4458 windows->image.y=(int) 4459 (height*windows->image.y/windows->image.ximage->height); 4460 status=XMakeImage(display,resource_info,&windows->image,image, 4461 (unsigned int) width,(unsigned int) height,exception); 4462 if (status == MagickFalse) 4463 XNoticeWidget(display,windows,"Unable to configure X image:", 4464 windows->image.name); 4465 /* 4466 Notify window manager of the new configuration. 4467 */ 4468 if (resource_info->image_geometry != (char *) NULL) 4469 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4470 resource_info->image_geometry); 4471 else 4472 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4473 XDisplayWidth(display,windows->image.screen), 4474 XDisplayHeight(display,windows->image.screen)); 4475 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4476 window_changes.width=(int) width; 4477 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4478 window_changes.width=XDisplayWidth(display,windows->image.screen); 4479 window_changes.height=(int) height; 4480 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4481 window_changes.height=XDisplayHeight(display,windows->image.screen); 4482 mask=(size_t) (CWWidth | CWHeight); 4483 if (resource_info->backdrop) 4484 { 4485 mask|=CWX | CWY; 4486 window_changes.x=(int) 4487 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4488 window_changes.y=(int) 4489 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4490 } 4491 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4492 (unsigned int) mask,&window_changes); 4493 (void) XClearWindow(display,windows->image.id); 4494 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4495 /* 4496 Update Magnify window configuration. 4497 */ 4498 if (windows->magnify.mapped != MagickFalse) 4499 XMakeMagnifyImage(display,windows,exception); 4500 windows->pan.crop_geometry=windows->image.crop_geometry; 4501 XBestIconSize(display,&windows->pan,image); 4502 while (((windows->pan.width << 1) < MaxIconSize) && 4503 ((windows->pan.height << 1) < MaxIconSize)) 4504 { 4505 windows->pan.width<<=1; 4506 windows->pan.height<<=1; 4507 } 4508 if (windows->pan.geometry != (char *) NULL) 4509 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4510 &windows->pan.width,&windows->pan.height); 4511 window_changes.width=(int) windows->pan.width; 4512 window_changes.height=(int) windows->pan.height; 4513 size_hints=XAllocSizeHints(); 4514 if (size_hints != (XSizeHints *) NULL) 4515 { 4516 /* 4517 Set new size hints. 4518 */ 4519 size_hints->flags=PSize | PMinSize | PMaxSize; 4520 size_hints->width=window_changes.width; 4521 size_hints->height=window_changes.height; 4522 size_hints->min_width=size_hints->width; 4523 size_hints->min_height=size_hints->height; 4524 size_hints->max_width=size_hints->width; 4525 size_hints->max_height=size_hints->height; 4526 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4527 (void) XFree((void *) size_hints); 4528 } 4529 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4530 (unsigned int) (CWWidth | CWHeight),&window_changes); 4531 /* 4532 Update icon window configuration. 4533 */ 4534 windows->icon.crop_geometry=windows->image.crop_geometry; 4535 XBestIconSize(display,&windows->icon,image); 4536 window_changes.width=(int) windows->icon.width; 4537 window_changes.height=(int) windows->icon.height; 4538 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4539 (unsigned int) (CWWidth | CWHeight),&window_changes); 4540 XSetCursorState(display,windows,MagickFalse); 4541 return(status != 0 ? MagickTrue : MagickFalse); 4542} 4543 4544/* 4545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4546% % 4547% % 4548% % 4549+ X C r o p I m a g e % 4550% % 4551% % 4552% % 4553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4554% 4555% XCropImage() allows the user to select a region of the image and crop, copy, 4556% or cut it. For copy or cut, the image can subsequently be composited onto 4557% the image with XPasteImage. 4558% 4559% The format of the XCropImage method is: 4560% 4561% MagickBooleanType XCropImage(Display *display, 4562% XResourceInfo *resource_info,XWindows *windows,Image *image, 4563% const ClipboardMode mode,ExceptionInfo *exception) 4564% 4565% A description of each parameter follows: 4566% 4567% o display: Specifies a connection to an X server; returned from 4568% XOpenDisplay. 4569% 4570% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4571% 4572% o windows: Specifies a pointer to a XWindows structure. 4573% 4574% o image: the image; returned from ReadImage. 4575% 4576% o mode: This unsigned value specified whether the image should be 4577% cropped, copied, or cut. 4578% 4579% o exception: return any errors or warnings in this structure. 4580% 4581*/ 4582static MagickBooleanType XCropImage(Display *display, 4583 XResourceInfo *resource_info,XWindows *windows,Image *image, 4584 const ClipboardMode mode,ExceptionInfo *exception) 4585{ 4586 static const char 4587 *CropModeMenu[] = 4588 { 4589 "Help", 4590 "Dismiss", 4591 (char *) NULL 4592 }, 4593 *RectifyModeMenu[] = 4594 { 4595 "Crop", 4596 "Help", 4597 "Dismiss", 4598 (char *) NULL 4599 }; 4600 4601 static const ModeType 4602 CropCommands[] = 4603 { 4604 CropHelpCommand, 4605 CropDismissCommand 4606 }, 4607 RectifyCommands[] = 4608 { 4609 RectifyCopyCommand, 4610 RectifyHelpCommand, 4611 RectifyDismissCommand 4612 }; 4613 4614 CacheView 4615 *image_view; 4616 4617 char 4618 command[MaxTextExtent], 4619 text[MaxTextExtent]; 4620 4621 Cursor 4622 cursor; 4623 4624 int 4625 id, 4626 x, 4627 y; 4628 4629 KeySym 4630 key_symbol; 4631 4632 Image 4633 *crop_image; 4634 4635 MagickRealType 4636 scale_factor; 4637 4638 RectangleInfo 4639 crop_info, 4640 highlight_info; 4641 4642 register Quantum 4643 *q; 4644 4645 unsigned int 4646 height, 4647 width; 4648 4649 size_t 4650 state; 4651 4652 XEvent 4653 event; 4654 4655 /* 4656 Map Command widget. 4657 */ 4658 switch (mode) 4659 { 4660 case CopyMode: 4661 { 4662 (void) CloneString(&windows->command.name,"Copy"); 4663 break; 4664 } 4665 case CropMode: 4666 { 4667 (void) CloneString(&windows->command.name,"Crop"); 4668 break; 4669 } 4670 case CutMode: 4671 { 4672 (void) CloneString(&windows->command.name,"Cut"); 4673 break; 4674 } 4675 } 4676 RectifyModeMenu[0]=windows->command.name; 4677 windows->command.data=0; 4678 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4679 (void) XMapRaised(display,windows->command.id); 4680 XClientMessage(display,windows->image.id,windows->im_protocols, 4681 windows->im_update_widget,CurrentTime); 4682 /* 4683 Track pointer until button 1 is pressed. 4684 */ 4685 XQueryPosition(display,windows->image.id,&x,&y); 4686 (void) XSelectInput(display,windows->image.id, 4687 windows->image.attributes.event_mask | PointerMotionMask); 4688 crop_info.x=(ssize_t) windows->image.x+x; 4689 crop_info.y=(ssize_t) windows->image.y+y; 4690 crop_info.width=0; 4691 crop_info.height=0; 4692 cursor=XCreateFontCursor(display,XC_fleur); 4693 state=DefaultState; 4694 do 4695 { 4696 if (windows->info.mapped != MagickFalse) 4697 { 4698 /* 4699 Display pointer position. 4700 */ 4701 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4702 (long) crop_info.x,(long) crop_info.y); 4703 XInfoWidget(display,windows,text); 4704 } 4705 /* 4706 Wait for next event. 4707 */ 4708 XScreenEvent(display,windows,&event,exception); 4709 if (event.xany.window == windows->command.id) 4710 { 4711 /* 4712 Select a command from the Command widget. 4713 */ 4714 id=XCommandWidget(display,windows,CropModeMenu,&event); 4715 if (id < 0) 4716 continue; 4717 switch (CropCommands[id]) 4718 { 4719 case CropHelpCommand: 4720 { 4721 switch (mode) 4722 { 4723 case CopyMode: 4724 { 4725 XTextViewWidget(display,resource_info,windows,MagickFalse, 4726 "Help Viewer - Image Copy",ImageCopyHelp); 4727 break; 4728 } 4729 case CropMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Crop",ImageCropHelp); 4733 break; 4734 } 4735 case CutMode: 4736 { 4737 XTextViewWidget(display,resource_info,windows,MagickFalse, 4738 "Help Viewer - Image Cut",ImageCutHelp); 4739 break; 4740 } 4741 } 4742 break; 4743 } 4744 case CropDismissCommand: 4745 { 4746 /* 4747 Prematurely exit. 4748 */ 4749 state|=EscapeState; 4750 state|=ExitState; 4751 break; 4752 } 4753 default: 4754 break; 4755 } 4756 continue; 4757 } 4758 switch (event.type) 4759 { 4760 case ButtonPress: 4761 { 4762 if (event.xbutton.button != Button1) 4763 break; 4764 if (event.xbutton.window != windows->image.id) 4765 break; 4766 /* 4767 Note first corner of cropping rectangle-- exit loop. 4768 */ 4769 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4770 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4771 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4772 state|=ExitState; 4773 break; 4774 } 4775 case ButtonRelease: 4776 break; 4777 case Expose: 4778 break; 4779 case KeyPress: 4780 { 4781 if (event.xkey.window != windows->image.id) 4782 break; 4783 /* 4784 Respond to a user key press. 4785 */ 4786 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4787 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4788 switch ((int) key_symbol) 4789 { 4790 case XK_Escape: 4791 case XK_F20: 4792 { 4793 /* 4794 Prematurely exit. 4795 */ 4796 state|=EscapeState; 4797 state|=ExitState; 4798 break; 4799 } 4800 case XK_F1: 4801 case XK_Help: 4802 { 4803 switch (mode) 4804 { 4805 case CopyMode: 4806 { 4807 XTextViewWidget(display,resource_info,windows,MagickFalse, 4808 "Help Viewer - Image Copy",ImageCopyHelp); 4809 break; 4810 } 4811 case CropMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Crop",ImageCropHelp); 4815 break; 4816 } 4817 case CutMode: 4818 { 4819 XTextViewWidget(display,resource_info,windows,MagickFalse, 4820 "Help Viewer - Image Cut",ImageCutHelp); 4821 break; 4822 } 4823 } 4824 break; 4825 } 4826 default: 4827 { 4828 (void) XBell(display,0); 4829 break; 4830 } 4831 } 4832 break; 4833 } 4834 case MotionNotify: 4835 { 4836 if (event.xmotion.window != windows->image.id) 4837 break; 4838 /* 4839 Map and unmap Info widget as text cursor crosses its boundaries. 4840 */ 4841 x=event.xmotion.x; 4842 y=event.xmotion.y; 4843 if (windows->info.mapped != MagickFalse) 4844 { 4845 if ((x < (int) (windows->info.x+windows->info.width)) && 4846 (y < (int) (windows->info.y+windows->info.height))) 4847 (void) XWithdrawWindow(display,windows->info.id, 4848 windows->info.screen); 4849 } 4850 else 4851 if ((x > (int) (windows->info.x+windows->info.width)) || 4852 (y > (int) (windows->info.y+windows->info.height))) 4853 (void) XMapWindow(display,windows->info.id); 4854 crop_info.x=(ssize_t) windows->image.x+x; 4855 crop_info.y=(ssize_t) windows->image.y+y; 4856 break; 4857 } 4858 default: 4859 break; 4860 } 4861 } while ((state & ExitState) == 0); 4862 (void) XSelectInput(display,windows->image.id, 4863 windows->image.attributes.event_mask); 4864 if ((state & EscapeState) != 0) 4865 { 4866 /* 4867 User want to exit without cropping. 4868 */ 4869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4870 (void) XFreeCursor(display,cursor); 4871 return(MagickTrue); 4872 } 4873 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4874 do 4875 { 4876 /* 4877 Size rectangle as pointer moves until the mouse button is released. 4878 */ 4879 x=(int) crop_info.x; 4880 y=(int) crop_info.y; 4881 crop_info.width=0; 4882 crop_info.height=0; 4883 state=DefaultState; 4884 do 4885 { 4886 highlight_info=crop_info; 4887 highlight_info.x=crop_info.x-windows->image.x; 4888 highlight_info.y=crop_info.y-windows->image.y; 4889 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4890 { 4891 /* 4892 Display info and draw cropping rectangle. 4893 */ 4894 if (windows->info.mapped == MagickFalse) 4895 (void) XMapWindow(display,windows->info.id); 4896 (void) FormatLocaleString(text,MaxTextExtent, 4897 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4898 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4899 XInfoWidget(display,windows,text); 4900 XHighlightRectangle(display,windows->image.id, 4901 windows->image.highlight_context,&highlight_info); 4902 } 4903 else 4904 if (windows->info.mapped != MagickFalse) 4905 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4906 /* 4907 Wait for next event. 4908 */ 4909 XScreenEvent(display,windows,&event,exception); 4910 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4911 XHighlightRectangle(display,windows->image.id, 4912 windows->image.highlight_context,&highlight_info); 4913 switch (event.type) 4914 { 4915 case ButtonPress: 4916 { 4917 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4918 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4919 break; 4920 } 4921 case ButtonRelease: 4922 { 4923 /* 4924 User has committed to cropping rectangle. 4925 */ 4926 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4927 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4928 XSetCursorState(display,windows,MagickFalse); 4929 state|=ExitState; 4930 windows->command.data=0; 4931 (void) XCommandWidget(display,windows,RectifyModeMenu, 4932 (XEvent *) NULL); 4933 break; 4934 } 4935 case Expose: 4936 break; 4937 case MotionNotify: 4938 { 4939 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4940 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4941 } 4942 default: 4943 break; 4944 } 4945 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4946 ((state & ExitState) != 0)) 4947 { 4948 /* 4949 Check boundary conditions. 4950 */ 4951 if (crop_info.x < 0) 4952 crop_info.x=0; 4953 else 4954 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4955 crop_info.x=(ssize_t) windows->image.ximage->width; 4956 if ((int) crop_info.x < x) 4957 crop_info.width=(unsigned int) (x-crop_info.x); 4958 else 4959 { 4960 crop_info.width=(unsigned int) (crop_info.x-x); 4961 crop_info.x=(ssize_t) x; 4962 } 4963 if (crop_info.y < 0) 4964 crop_info.y=0; 4965 else 4966 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4967 crop_info.y=(ssize_t) windows->image.ximage->height; 4968 if ((int) crop_info.y < y) 4969 crop_info.height=(unsigned int) (y-crop_info.y); 4970 else 4971 { 4972 crop_info.height=(unsigned int) (crop_info.y-y); 4973 crop_info.y=(ssize_t) y; 4974 } 4975 } 4976 } while ((state & ExitState) == 0); 4977 /* 4978 Wait for user to grab a corner of the rectangle or press return. 4979 */ 4980 state=DefaultState; 4981 (void) XMapWindow(display,windows->info.id); 4982 do 4983 { 4984 if (windows->info.mapped != MagickFalse) 4985 { 4986 /* 4987 Display pointer position. 4988 */ 4989 (void) FormatLocaleString(text,MaxTextExtent, 4990 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4991 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4992 XInfoWidget(display,windows,text); 4993 } 4994 highlight_info=crop_info; 4995 highlight_info.x=crop_info.x-windows->image.x; 4996 highlight_info.y=crop_info.y-windows->image.y; 4997 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4998 { 4999 state|=EscapeState; 5000 state|=ExitState; 5001 break; 5002 } 5003 XHighlightRectangle(display,windows->image.id, 5004 windows->image.highlight_context,&highlight_info); 5005 XScreenEvent(display,windows,&event,exception); 5006 if (event.xany.window == windows->command.id) 5007 { 5008 /* 5009 Select a command from the Command widget. 5010 */ 5011 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5012 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5013 (void) XSetFunction(display,windows->image.highlight_context, 5014 GXinvert); 5015 XHighlightRectangle(display,windows->image.id, 5016 windows->image.highlight_context,&highlight_info); 5017 if (id >= 0) 5018 switch (RectifyCommands[id]) 5019 { 5020 case RectifyCopyCommand: 5021 { 5022 state|=ExitState; 5023 break; 5024 } 5025 case RectifyHelpCommand: 5026 { 5027 (void) XSetFunction(display,windows->image.highlight_context, 5028 GXcopy); 5029 switch (mode) 5030 { 5031 case CopyMode: 5032 { 5033 XTextViewWidget(display,resource_info,windows,MagickFalse, 5034 "Help Viewer - Image Copy",ImageCopyHelp); 5035 break; 5036 } 5037 case CropMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Crop",ImageCropHelp); 5041 break; 5042 } 5043 case CutMode: 5044 { 5045 XTextViewWidget(display,resource_info,windows,MagickFalse, 5046 "Help Viewer - Image Cut",ImageCutHelp); 5047 break; 5048 } 5049 } 5050 (void) XSetFunction(display,windows->image.highlight_context, 5051 GXinvert); 5052 break; 5053 } 5054 case RectifyDismissCommand: 5055 { 5056 /* 5057 Prematurely exit. 5058 */ 5059 state|=EscapeState; 5060 state|=ExitState; 5061 break; 5062 } 5063 default: 5064 break; 5065 } 5066 continue; 5067 } 5068 XHighlightRectangle(display,windows->image.id, 5069 windows->image.highlight_context,&highlight_info); 5070 switch (event.type) 5071 { 5072 case ButtonPress: 5073 { 5074 if (event.xbutton.button != Button1) 5075 break; 5076 if (event.xbutton.window != windows->image.id) 5077 break; 5078 x=windows->image.x+event.xbutton.x; 5079 y=windows->image.y+event.xbutton.y; 5080 if ((x < (int) (crop_info.x+RoiDelta)) && 5081 (x > (int) (crop_info.x-RoiDelta)) && 5082 (y < (int) (crop_info.y+RoiDelta)) && 5083 (y > (int) (crop_info.y-RoiDelta))) 5084 { 5085 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5086 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5087 state|=UpdateConfigurationState; 5088 break; 5089 } 5090 if ((x < (int) (crop_info.x+RoiDelta)) && 5091 (x > (int) (crop_info.x-RoiDelta)) && 5092 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5093 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5094 { 5095 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5096 state|=UpdateConfigurationState; 5097 break; 5098 } 5099 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5100 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5101 (y < (int) (crop_info.y+RoiDelta)) && 5102 (y > (int) (crop_info.y-RoiDelta))) 5103 { 5104 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5105 state|=UpdateConfigurationState; 5106 break; 5107 } 5108 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5109 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5110 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5111 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5112 { 5113 state|=UpdateConfigurationState; 5114 break; 5115 } 5116 } 5117 case ButtonRelease: 5118 { 5119 if (event.xbutton.window == windows->pan.id) 5120 if ((highlight_info.x != crop_info.x-windows->image.x) || 5121 (highlight_info.y != crop_info.y-windows->image.y)) 5122 XHighlightRectangle(display,windows->image.id, 5123 windows->image.highlight_context,&highlight_info); 5124 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5125 event.xbutton.time); 5126 break; 5127 } 5128 case Expose: 5129 { 5130 if (event.xexpose.window == windows->image.id) 5131 if (event.xexpose.count == 0) 5132 { 5133 event.xexpose.x=(int) highlight_info.x; 5134 event.xexpose.y=(int) highlight_info.y; 5135 event.xexpose.width=(int) highlight_info.width; 5136 event.xexpose.height=(int) highlight_info.height; 5137 XRefreshWindow(display,&windows->image,&event); 5138 } 5139 if (event.xexpose.window == windows->info.id) 5140 if (event.xexpose.count == 0) 5141 XInfoWidget(display,windows,text); 5142 break; 5143 } 5144 case KeyPress: 5145 { 5146 if (event.xkey.window != windows->image.id) 5147 break; 5148 /* 5149 Respond to a user key press. 5150 */ 5151 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5152 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5153 switch ((int) key_symbol) 5154 { 5155 case XK_Escape: 5156 case XK_F20: 5157 state|=EscapeState; 5158 case XK_Return: 5159 { 5160 state|=ExitState; 5161 break; 5162 } 5163 case XK_Home: 5164 case XK_KP_Home: 5165 { 5166 crop_info.x=(ssize_t) (windows->image.width/2L- 5167 crop_info.width/2L); 5168 crop_info.y=(ssize_t) (windows->image.height/2L- 5169 crop_info.height/2L); 5170 break; 5171 } 5172 case XK_Left: 5173 case XK_KP_Left: 5174 { 5175 crop_info.x--; 5176 break; 5177 } 5178 case XK_Up: 5179 case XK_KP_Up: 5180 case XK_Next: 5181 { 5182 crop_info.y--; 5183 break; 5184 } 5185 case XK_Right: 5186 case XK_KP_Right: 5187 { 5188 crop_info.x++; 5189 break; 5190 } 5191 case XK_Prior: 5192 case XK_Down: 5193 case XK_KP_Down: 5194 { 5195 crop_info.y++; 5196 break; 5197 } 5198 case XK_F1: 5199 case XK_Help: 5200 { 5201 (void) XSetFunction(display,windows->image.highlight_context, 5202 GXcopy); 5203 switch (mode) 5204 { 5205 case CopyMode: 5206 { 5207 XTextViewWidget(display,resource_info,windows,MagickFalse, 5208 "Help Viewer - Image Copy",ImageCopyHelp); 5209 break; 5210 } 5211 case CropMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Cropg",ImageCropHelp); 5215 break; 5216 } 5217 case CutMode: 5218 { 5219 XTextViewWidget(display,resource_info,windows,MagickFalse, 5220 "Help Viewer - Image Cutg",ImageCutHelp); 5221 break; 5222 } 5223 } 5224 (void) XSetFunction(display,windows->image.highlight_context, 5225 GXinvert); 5226 break; 5227 } 5228 default: 5229 { 5230 (void) XBell(display,0); 5231 break; 5232 } 5233 } 5234 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5235 event.xkey.time); 5236 break; 5237 } 5238 case KeyRelease: 5239 break; 5240 case MotionNotify: 5241 { 5242 if (event.xmotion.window != windows->image.id) 5243 break; 5244 /* 5245 Map and unmap Info widget as text cursor crosses its boundaries. 5246 */ 5247 x=event.xmotion.x; 5248 y=event.xmotion.y; 5249 if (windows->info.mapped != MagickFalse) 5250 { 5251 if ((x < (int) (windows->info.x+windows->info.width)) && 5252 (y < (int) (windows->info.y+windows->info.height))) 5253 (void) XWithdrawWindow(display,windows->info.id, 5254 windows->info.screen); 5255 } 5256 else 5257 if ((x > (int) (windows->info.x+windows->info.width)) || 5258 (y > (int) (windows->info.y+windows->info.height))) 5259 (void) XMapWindow(display,windows->info.id); 5260 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5261 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5262 break; 5263 } 5264 case SelectionRequest: 5265 { 5266 XSelectionEvent 5267 notify; 5268 5269 XSelectionRequestEvent 5270 *request; 5271 5272 /* 5273 Set primary selection. 5274 */ 5275 (void) FormatLocaleString(text,MaxTextExtent, 5276 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5277 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5278 request=(&(event.xselectionrequest)); 5279 (void) XChangeProperty(request->display,request->requestor, 5280 request->property,request->target,8,PropModeReplace, 5281 (unsigned char *) text,(int) strlen(text)); 5282 notify.type=SelectionNotify; 5283 notify.display=request->display; 5284 notify.requestor=request->requestor; 5285 notify.selection=request->selection; 5286 notify.target=request->target; 5287 notify.time=request->time; 5288 if (request->property == None) 5289 notify.property=request->target; 5290 else 5291 notify.property=request->property; 5292 (void) XSendEvent(request->display,request->requestor,False,0, 5293 (XEvent *) ¬ify); 5294 } 5295 default: 5296 break; 5297 } 5298 if ((state & UpdateConfigurationState) != 0) 5299 { 5300 (void) XPutBackEvent(display,&event); 5301 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5302 break; 5303 } 5304 } while ((state & ExitState) == 0); 5305 } while ((state & ExitState) == 0); 5306 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5307 XSetCursorState(display,windows,MagickFalse); 5308 if ((state & EscapeState) != 0) 5309 return(MagickTrue); 5310 if (mode == CropMode) 5311 if (((int) crop_info.width != windows->image.ximage->width) || 5312 ((int) crop_info.height != windows->image.ximage->height)) 5313 { 5314 /* 5315 Reconfigure Image window as defined by cropping rectangle. 5316 */ 5317 XSetCropGeometry(display,windows,&crop_info,image); 5318 windows->image.window_changes.width=(int) crop_info.width; 5319 windows->image.window_changes.height=(int) crop_info.height; 5320 (void) XConfigureImage(display,resource_info,windows,image,exception); 5321 return(MagickTrue); 5322 } 5323 /* 5324 Copy image before applying image transforms. 5325 */ 5326 XSetCursorState(display,windows,MagickTrue); 5327 XCheckRefreshWindows(display,windows); 5328 width=(unsigned int) image->columns; 5329 height=(unsigned int) image->rows; 5330 x=0; 5331 y=0; 5332 if (windows->image.crop_geometry != (char *) NULL) 5333 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5334 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5335 crop_info.x+=x; 5336 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5337 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5338 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5339 crop_info.y+=y; 5340 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5341 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5342 crop_image=CropImage(image,&crop_info,exception); 5343 XSetCursorState(display,windows,MagickFalse); 5344 if (crop_image == (Image *) NULL) 5345 return(MagickFalse); 5346 if (resource_info->copy_image != (Image *) NULL) 5347 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5348 resource_info->copy_image=crop_image; 5349 if (mode == CopyMode) 5350 { 5351 (void) XConfigureImage(display,resource_info,windows,image,exception); 5352 return(MagickTrue); 5353 } 5354 /* 5355 Cut image. 5356 */ 5357 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5358 return(MagickFalse); 5359 image->matte=MagickTrue; 5360 image_view=AcquireCacheView(image); 5361 for (y=0; y < (int) crop_info.height; y++) 5362 { 5363 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5364 crop_info.width,1,exception); 5365 if (q == (Quantum *) NULL) 5366 break; 5367 for (x=0; x < (int) crop_info.width; x++) 5368 { 5369 SetPixelAlpha(image,TransparentAlpha,q); 5370 q+=GetPixelChannels(image); 5371 } 5372 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5373 break; 5374 } 5375 image_view=DestroyCacheView(image_view); 5376 /* 5377 Update image configuration. 5378 */ 5379 XConfigureImageColormap(display,resource_info,windows,image,exception); 5380 (void) XConfigureImage(display,resource_info,windows,image,exception); 5381 return(MagickTrue); 5382} 5383 5384/* 5385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5386% % 5387% % 5388% % 5389+ X D r a w I m a g e % 5390% % 5391% % 5392% % 5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5394% 5395% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5396% the image. 5397% 5398% The format of the XDrawEditImage method is: 5399% 5400% MagickBooleanType XDrawEditImage(Display *display, 5401% XResourceInfo *resource_info,XWindows *windows,Image **image, 5402% ExceptionInfo *exception) 5403% 5404% A description of each parameter follows: 5405% 5406% o display: Specifies a connection to an X server; returned from 5407% XOpenDisplay. 5408% 5409% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5410% 5411% o windows: Specifies a pointer to a XWindows structure. 5412% 5413% o image: the image. 5414% 5415% o exception: return any errors or warnings in this structure. 5416% 5417*/ 5418static MagickBooleanType XDrawEditImage(Display *display, 5419 XResourceInfo *resource_info,XWindows *windows,Image **image, 5420 ExceptionInfo *exception) 5421{ 5422 static const char 5423 *DrawMenu[] = 5424 { 5425 "Element", 5426 "Color", 5427 "Stipple", 5428 "Width", 5429 "Undo", 5430 "Help", 5431 "Dismiss", 5432 (char *) NULL 5433 }; 5434 5435 static ElementType 5436 element = PointElement; 5437 5438 static const ModeType 5439 DrawCommands[] = 5440 { 5441 DrawElementCommand, 5442 DrawColorCommand, 5443 DrawStippleCommand, 5444 DrawWidthCommand, 5445 DrawUndoCommand, 5446 DrawHelpCommand, 5447 DrawDismissCommand 5448 }; 5449 5450 static Pixmap 5451 stipple = (Pixmap) NULL; 5452 5453 static unsigned int 5454 pen_id = 0, 5455 line_width = 1; 5456 5457 char 5458 command[MaxTextExtent], 5459 text[MaxTextExtent]; 5460 5461 Cursor 5462 cursor; 5463 5464 int 5465 entry, 5466 id, 5467 number_coordinates, 5468 x, 5469 y; 5470 5471 MagickRealType 5472 degrees; 5473 5474 MagickStatusType 5475 status; 5476 5477 RectangleInfo 5478 rectangle_info; 5479 5480 register int 5481 i; 5482 5483 unsigned int 5484 distance, 5485 height, 5486 max_coordinates, 5487 width; 5488 5489 size_t 5490 state; 5491 5492 Window 5493 root_window; 5494 5495 XDrawInfo 5496 draw_info; 5497 5498 XEvent 5499 event; 5500 5501 XPoint 5502 *coordinate_info; 5503 5504 XSegment 5505 line_info; 5506 5507 /* 5508 Allocate polygon info. 5509 */ 5510 max_coordinates=2048; 5511 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5512 sizeof(*coordinate_info)); 5513 if (coordinate_info == (XPoint *) NULL) 5514 { 5515 (void) ThrowMagickException(exception,GetMagickModule(), 5516 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5517 return(MagickFalse); 5518 } 5519 /* 5520 Map Command widget. 5521 */ 5522 (void) CloneString(&windows->command.name,"Draw"); 5523 windows->command.data=4; 5524 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5525 (void) XMapRaised(display,windows->command.id); 5526 XClientMessage(display,windows->image.id,windows->im_protocols, 5527 windows->im_update_widget,CurrentTime); 5528 /* 5529 Wait for first button press. 5530 */ 5531 root_window=XRootWindow(display,XDefaultScreen(display)); 5532 draw_info.stencil=OpaqueStencil; 5533 status=MagickTrue; 5534 cursor=XCreateFontCursor(display,XC_tcross); 5535 for ( ; ; ) 5536 { 5537 XQueryPosition(display,windows->image.id,&x,&y); 5538 (void) XSelectInput(display,windows->image.id, 5539 windows->image.attributes.event_mask | PointerMotionMask); 5540 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5541 state=DefaultState; 5542 do 5543 { 5544 if (windows->info.mapped != MagickFalse) 5545 { 5546 /* 5547 Display pointer position. 5548 */ 5549 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5550 x+windows->image.x,y+windows->image.y); 5551 XInfoWidget(display,windows,text); 5552 } 5553 /* 5554 Wait for next event. 5555 */ 5556 XScreenEvent(display,windows,&event,exception); 5557 if (event.xany.window == windows->command.id) 5558 { 5559 /* 5560 Select a command from the Command widget. 5561 */ 5562 id=XCommandWidget(display,windows,DrawMenu,&event); 5563 if (id < 0) 5564 continue; 5565 switch (DrawCommands[id]) 5566 { 5567 case DrawElementCommand: 5568 { 5569 static const char 5570 *Elements[] = 5571 { 5572 "point", 5573 "line", 5574 "rectangle", 5575 "fill rectangle", 5576 "circle", 5577 "fill circle", 5578 "ellipse", 5579 "fill ellipse", 5580 "polygon", 5581 "fill polygon", 5582 (char *) NULL, 5583 }; 5584 5585 /* 5586 Select a command from the pop-up menu. 5587 */ 5588 element=(ElementType) (XMenuWidget(display,windows, 5589 DrawMenu[id],Elements,command)+1); 5590 break; 5591 } 5592 case DrawColorCommand: 5593 { 5594 const char 5595 *ColorMenu[MaxNumberPens+1]; 5596 5597 int 5598 pen_number; 5599 5600 MagickBooleanType 5601 transparent; 5602 5603 XColor 5604 color; 5605 5606 /* 5607 Initialize menu selections. 5608 */ 5609 for (i=0; i < (int) (MaxNumberPens-2); i++) 5610 ColorMenu[i]=resource_info->pen_colors[i]; 5611 ColorMenu[MaxNumberPens-2]="transparent"; 5612 ColorMenu[MaxNumberPens-1]="Browser..."; 5613 ColorMenu[MaxNumberPens]=(char *) NULL; 5614 /* 5615 Select a pen color from the pop-up menu. 5616 */ 5617 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5618 (const char **) ColorMenu,command); 5619 if (pen_number < 0) 5620 break; 5621 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5622 MagickFalse; 5623 if (transparent != MagickFalse) 5624 { 5625 draw_info.stencil=TransparentStencil; 5626 break; 5627 } 5628 if (pen_number == (MaxNumberPens-1)) 5629 { 5630 static char 5631 color_name[MaxTextExtent] = "gray"; 5632 5633 /* 5634 Select a pen color from a dialog. 5635 */ 5636 resource_info->pen_colors[pen_number]=color_name; 5637 XColorBrowserWidget(display,windows,"Select",color_name); 5638 if (*color_name == '\0') 5639 break; 5640 } 5641 /* 5642 Set pen color. 5643 */ 5644 (void) XParseColor(display,windows->map_info->colormap, 5645 resource_info->pen_colors[pen_number],&color); 5646 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5647 (unsigned int) MaxColors,&color); 5648 windows->pixel_info->pen_colors[pen_number]=color; 5649 pen_id=(unsigned int) pen_number; 5650 draw_info.stencil=OpaqueStencil; 5651 break; 5652 } 5653 case DrawStippleCommand: 5654 { 5655 Image 5656 *stipple_image; 5657 5658 ImageInfo 5659 *image_info; 5660 5661 int 5662 status; 5663 5664 static char 5665 filename[MaxTextExtent] = "\0"; 5666 5667 static const char 5668 *StipplesMenu[] = 5669 { 5670 "Brick", 5671 "Diagonal", 5672 "Scales", 5673 "Vertical", 5674 "Wavy", 5675 "Translucent", 5676 "Opaque", 5677 (char *) NULL, 5678 (char *) NULL, 5679 }; 5680 5681 /* 5682 Select a command from the pop-up menu. 5683 */ 5684 StipplesMenu[7]="Open..."; 5685 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5686 command); 5687 if (entry < 0) 5688 break; 5689 if (stipple != (Pixmap) NULL) 5690 (void) XFreePixmap(display,stipple); 5691 stipple=(Pixmap) NULL; 5692 if (entry != 7) 5693 { 5694 switch (entry) 5695 { 5696 case 0: 5697 { 5698 stipple=XCreateBitmapFromData(display,root_window, 5699 (char *) BricksBitmap,BricksWidth,BricksHeight); 5700 break; 5701 } 5702 case 1: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5706 break; 5707 } 5708 case 2: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5712 break; 5713 } 5714 case 3: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5718 break; 5719 } 5720 case 4: 5721 { 5722 stipple=XCreateBitmapFromData(display,root_window, 5723 (char *) WavyBitmap,WavyWidth,WavyHeight); 5724 break; 5725 } 5726 case 5: 5727 { 5728 stipple=XCreateBitmapFromData(display,root_window, 5729 (char *) HighlightBitmap,HighlightWidth, 5730 HighlightHeight); 5731 break; 5732 } 5733 case 6: 5734 default: 5735 { 5736 stipple=XCreateBitmapFromData(display,root_window, 5737 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5738 break; 5739 } 5740 } 5741 break; 5742 } 5743 XFileBrowserWidget(display,windows,"Stipple",filename); 5744 if (*filename == '\0') 5745 break; 5746 /* 5747 Read image. 5748 */ 5749 XSetCursorState(display,windows,MagickTrue); 5750 XCheckRefreshWindows(display,windows); 5751 image_info=AcquireImageInfo(); 5752 (void) CopyMagickString(image_info->filename,filename, 5753 MaxTextExtent); 5754 stipple_image=ReadImage(image_info,exception); 5755 CatchException(exception); 5756 XSetCursorState(display,windows,MagickFalse); 5757 if (stipple_image == (Image *) NULL) 5758 break; 5759 (void) AcquireUniqueFileResource(filename); 5760 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5761 "xbm:%s",filename); 5762 (void) WriteImage(image_info,stipple_image,exception); 5763 stipple_image=DestroyImage(stipple_image); 5764 image_info=DestroyImageInfo(image_info); 5765 status=XReadBitmapFile(display,root_window,filename,&width, 5766 &height,&stipple,&x,&y); 5767 (void) RelinquishUniqueFileResource(filename); 5768 if ((status != BitmapSuccess) != 0) 5769 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5770 filename); 5771 break; 5772 } 5773 case DrawWidthCommand: 5774 { 5775 static char 5776 width[MaxTextExtent] = "0"; 5777 5778 static const char 5779 *WidthsMenu[] = 5780 { 5781 "1", 5782 "2", 5783 "4", 5784 "8", 5785 "16", 5786 "Dialog...", 5787 (char *) NULL, 5788 }; 5789 5790 /* 5791 Select a command from the pop-up menu. 5792 */ 5793 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5794 command); 5795 if (entry < 0) 5796 break; 5797 if (entry != 5) 5798 { 5799 line_width=(unsigned int) StringToUnsignedLong( 5800 WidthsMenu[entry]); 5801 break; 5802 } 5803 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5804 width); 5805 if (*width == '\0') 5806 break; 5807 line_width=(unsigned int) StringToUnsignedLong(width); 5808 break; 5809 } 5810 case DrawUndoCommand: 5811 { 5812 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5813 image,exception); 5814 break; 5815 } 5816 case DrawHelpCommand: 5817 { 5818 XTextViewWidget(display,resource_info,windows,MagickFalse, 5819 "Help Viewer - Image Rotation",ImageDrawHelp); 5820 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5821 break; 5822 } 5823 case DrawDismissCommand: 5824 { 5825 /* 5826 Prematurely exit. 5827 */ 5828 state|=EscapeState; 5829 state|=ExitState; 5830 break; 5831 } 5832 default: 5833 break; 5834 } 5835 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5836 continue; 5837 } 5838 switch (event.type) 5839 { 5840 case ButtonPress: 5841 { 5842 if (event.xbutton.button != Button1) 5843 break; 5844 if (event.xbutton.window != windows->image.id) 5845 break; 5846 /* 5847 exit loop. 5848 */ 5849 x=event.xbutton.x; 5850 y=event.xbutton.y; 5851 state|=ExitState; 5852 break; 5853 } 5854 case ButtonRelease: 5855 break; 5856 case Expose: 5857 break; 5858 case KeyPress: 5859 { 5860 KeySym 5861 key_symbol; 5862 5863 if (event.xkey.window != windows->image.id) 5864 break; 5865 /* 5866 Respond to a user key press. 5867 */ 5868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5870 switch ((int) key_symbol) 5871 { 5872 case XK_Escape: 5873 case XK_F20: 5874 { 5875 /* 5876 Prematurely exit. 5877 */ 5878 state|=EscapeState; 5879 state|=ExitState; 5880 break; 5881 } 5882 case XK_F1: 5883 case XK_Help: 5884 { 5885 XTextViewWidget(display,resource_info,windows,MagickFalse, 5886 "Help Viewer - Image Rotation",ImageDrawHelp); 5887 break; 5888 } 5889 default: 5890 { 5891 (void) XBell(display,0); 5892 break; 5893 } 5894 } 5895 break; 5896 } 5897 case MotionNotify: 5898 { 5899 /* 5900 Map and unmap Info widget as text cursor crosses its boundaries. 5901 */ 5902 x=event.xmotion.x; 5903 y=event.xmotion.y; 5904 if (windows->info.mapped != MagickFalse) 5905 { 5906 if ((x < (int) (windows->info.x+windows->info.width)) && 5907 (y < (int) (windows->info.y+windows->info.height))) 5908 (void) XWithdrawWindow(display,windows->info.id, 5909 windows->info.screen); 5910 } 5911 else 5912 if ((x > (int) (windows->info.x+windows->info.width)) || 5913 (y > (int) (windows->info.y+windows->info.height))) 5914 (void) XMapWindow(display,windows->info.id); 5915 break; 5916 } 5917 } 5918 } while ((state & ExitState) == 0); 5919 (void) XSelectInput(display,windows->image.id, 5920 windows->image.attributes.event_mask); 5921 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5922 if ((state & EscapeState) != 0) 5923 break; 5924 /* 5925 Draw element as pointer moves until the button is released. 5926 */ 5927 distance=0; 5928 degrees=0.0; 5929 line_info.x1=x; 5930 line_info.y1=y; 5931 line_info.x2=x; 5932 line_info.y2=y; 5933 rectangle_info.x=(ssize_t) x; 5934 rectangle_info.y=(ssize_t) y; 5935 rectangle_info.width=0; 5936 rectangle_info.height=0; 5937 number_coordinates=1; 5938 coordinate_info->x=x; 5939 coordinate_info->y=y; 5940 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5941 state=DefaultState; 5942 do 5943 { 5944 switch (element) 5945 { 5946 case PointElement: 5947 default: 5948 { 5949 if (number_coordinates > 1) 5950 { 5951 (void) XDrawLines(display,windows->image.id, 5952 windows->image.highlight_context,coordinate_info, 5953 number_coordinates,CoordModeOrigin); 5954 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5955 coordinate_info[number_coordinates-1].x, 5956 coordinate_info[number_coordinates-1].y); 5957 XInfoWidget(display,windows,text); 5958 } 5959 break; 5960 } 5961 case LineElement: 5962 { 5963 if (distance > 9) 5964 { 5965 /* 5966 Display angle of the line. 5967 */ 5968 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5969 line_info.y1),(double) (line_info.x2-line_info.x1))); 5970 (void) FormatLocaleString(text,MaxTextExtent," %g", 5971 (double) degrees); 5972 XInfoWidget(display,windows,text); 5973 XHighlightLine(display,windows->image.id, 5974 windows->image.highlight_context,&line_info); 5975 } 5976 else 5977 if (windows->info.mapped != MagickFalse) 5978 (void) XWithdrawWindow(display,windows->info.id, 5979 windows->info.screen); 5980 break; 5981 } 5982 case RectangleElement: 5983 case FillRectangleElement: 5984 { 5985 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5986 { 5987 /* 5988 Display info and draw drawing rectangle. 5989 */ 5990 (void) FormatLocaleString(text,MaxTextExtent, 5991 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5992 (double) rectangle_info.height,(double) rectangle_info.x, 5993 (double) rectangle_info.y); 5994 XInfoWidget(display,windows,text); 5995 XHighlightRectangle(display,windows->image.id, 5996 windows->image.highlight_context,&rectangle_info); 5997 } 5998 else 5999 if (windows->info.mapped != MagickFalse) 6000 (void) XWithdrawWindow(display,windows->info.id, 6001 windows->info.screen); 6002 break; 6003 } 6004 case CircleElement: 6005 case FillCircleElement: 6006 case EllipseElement: 6007 case FillEllipseElement: 6008 { 6009 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6010 { 6011 /* 6012 Display info and draw drawing rectangle. 6013 */ 6014 (void) FormatLocaleString(text,MaxTextExtent, 6015 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6016 (double) rectangle_info.height,(double) rectangle_info.x, 6017 (double) rectangle_info.y); 6018 XInfoWidget(display,windows,text); 6019 XHighlightEllipse(display,windows->image.id, 6020 windows->image.highlight_context,&rectangle_info); 6021 } 6022 else 6023 if (windows->info.mapped != MagickFalse) 6024 (void) XWithdrawWindow(display,windows->info.id, 6025 windows->info.screen); 6026 break; 6027 } 6028 case PolygonElement: 6029 case FillPolygonElement: 6030 { 6031 if (number_coordinates > 1) 6032 (void) XDrawLines(display,windows->image.id, 6033 windows->image.highlight_context,coordinate_info, 6034 number_coordinates,CoordModeOrigin); 6035 if (distance > 9) 6036 { 6037 /* 6038 Display angle of the line. 6039 */ 6040 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6041 line_info.y1),(double) (line_info.x2-line_info.x1))); 6042 (void) FormatLocaleString(text,MaxTextExtent," %g", 6043 (double) degrees); 6044 XInfoWidget(display,windows,text); 6045 XHighlightLine(display,windows->image.id, 6046 windows->image.highlight_context,&line_info); 6047 } 6048 else 6049 if (windows->info.mapped != MagickFalse) 6050 (void) XWithdrawWindow(display,windows->info.id, 6051 windows->info.screen); 6052 break; 6053 } 6054 } 6055 /* 6056 Wait for next event. 6057 */ 6058 XScreenEvent(display,windows,&event,exception); 6059 switch (element) 6060 { 6061 case PointElement: 6062 default: 6063 { 6064 if (number_coordinates > 1) 6065 (void) XDrawLines(display,windows->image.id, 6066 windows->image.highlight_context,coordinate_info, 6067 number_coordinates,CoordModeOrigin); 6068 break; 6069 } 6070 case LineElement: 6071 { 6072 if (distance > 9) 6073 XHighlightLine(display,windows->image.id, 6074 windows->image.highlight_context,&line_info); 6075 break; 6076 } 6077 case RectangleElement: 6078 case FillRectangleElement: 6079 { 6080 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6081 XHighlightRectangle(display,windows->image.id, 6082 windows->image.highlight_context,&rectangle_info); 6083 break; 6084 } 6085 case CircleElement: 6086 case FillCircleElement: 6087 case EllipseElement: 6088 case FillEllipseElement: 6089 { 6090 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6091 XHighlightEllipse(display,windows->image.id, 6092 windows->image.highlight_context,&rectangle_info); 6093 break; 6094 } 6095 case PolygonElement: 6096 case FillPolygonElement: 6097 { 6098 if (number_coordinates > 1) 6099 (void) XDrawLines(display,windows->image.id, 6100 windows->image.highlight_context,coordinate_info, 6101 number_coordinates,CoordModeOrigin); 6102 if (distance > 9) 6103 XHighlightLine(display,windows->image.id, 6104 windows->image.highlight_context,&line_info); 6105 break; 6106 } 6107 } 6108 switch (event.type) 6109 { 6110 case ButtonPress: 6111 break; 6112 case ButtonRelease: 6113 { 6114 /* 6115 User has committed to element. 6116 */ 6117 line_info.x2=event.xbutton.x; 6118 line_info.y2=event.xbutton.y; 6119 rectangle_info.x=(ssize_t) event.xbutton.x; 6120 rectangle_info.y=(ssize_t) event.xbutton.y; 6121 coordinate_info[number_coordinates].x=event.xbutton.x; 6122 coordinate_info[number_coordinates].y=event.xbutton.y; 6123 if (((element != PolygonElement) && 6124 (element != FillPolygonElement)) || (distance <= 9)) 6125 { 6126 state|=ExitState; 6127 break; 6128 } 6129 number_coordinates++; 6130 if (number_coordinates < (int) max_coordinates) 6131 { 6132 line_info.x1=event.xbutton.x; 6133 line_info.y1=event.xbutton.y; 6134 break; 6135 } 6136 max_coordinates<<=1; 6137 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6138 max_coordinates,sizeof(*coordinate_info)); 6139 if (coordinate_info == (XPoint *) NULL) 6140 (void) ThrowMagickException(exception,GetMagickModule(), 6141 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6142 break; 6143 } 6144 case Expose: 6145 break; 6146 case MotionNotify: 6147 { 6148 if (event.xmotion.window != windows->image.id) 6149 break; 6150 if (element != PointElement) 6151 { 6152 line_info.x2=event.xmotion.x; 6153 line_info.y2=event.xmotion.y; 6154 rectangle_info.x=(ssize_t) event.xmotion.x; 6155 rectangle_info.y=(ssize_t) event.xmotion.y; 6156 break; 6157 } 6158 coordinate_info[number_coordinates].x=event.xbutton.x; 6159 coordinate_info[number_coordinates].y=event.xbutton.y; 6160 number_coordinates++; 6161 if (number_coordinates < (int) max_coordinates) 6162 break; 6163 max_coordinates<<=1; 6164 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6165 max_coordinates,sizeof(*coordinate_info)); 6166 if (coordinate_info == (XPoint *) NULL) 6167 (void) ThrowMagickException(exception,GetMagickModule(), 6168 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6169 break; 6170 } 6171 default: 6172 break; 6173 } 6174 /* 6175 Check boundary conditions. 6176 */ 6177 if (line_info.x2 < 0) 6178 line_info.x2=0; 6179 else 6180 if (line_info.x2 > (int) windows->image.width) 6181 line_info.x2=(short) windows->image.width; 6182 if (line_info.y2 < 0) 6183 line_info.y2=0; 6184 else 6185 if (line_info.y2 > (int) windows->image.height) 6186 line_info.y2=(short) windows->image.height; 6187 distance=(unsigned int) 6188 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6189 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6190 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6191 ((state & ExitState) != 0)) 6192 { 6193 if (rectangle_info.x < 0) 6194 rectangle_info.x=0; 6195 else 6196 if (rectangle_info.x > (ssize_t) windows->image.width) 6197 rectangle_info.x=(ssize_t) windows->image.width; 6198 if ((int) rectangle_info.x < x) 6199 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6200 else 6201 { 6202 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6203 rectangle_info.x=(ssize_t) x; 6204 } 6205 if (rectangle_info.y < 0) 6206 rectangle_info.y=0; 6207 else 6208 if (rectangle_info.y > (ssize_t) windows->image.height) 6209 rectangle_info.y=(ssize_t) windows->image.height; 6210 if ((int) rectangle_info.y < y) 6211 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6212 else 6213 { 6214 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6215 rectangle_info.y=(ssize_t) y; 6216 } 6217 } 6218 } while ((state & ExitState) == 0); 6219 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6220 if ((element == PointElement) || (element == PolygonElement) || 6221 (element == FillPolygonElement)) 6222 { 6223 /* 6224 Determine polygon bounding box. 6225 */ 6226 rectangle_info.x=(ssize_t) coordinate_info->x; 6227 rectangle_info.y=(ssize_t) coordinate_info->y; 6228 x=coordinate_info->x; 6229 y=coordinate_info->y; 6230 for (i=1; i < number_coordinates; i++) 6231 { 6232 if (coordinate_info[i].x > x) 6233 x=coordinate_info[i].x; 6234 if (coordinate_info[i].y > y) 6235 y=coordinate_info[i].y; 6236 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6237 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6238 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6239 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6240 } 6241 rectangle_info.width=(size_t) (x-rectangle_info.x); 6242 rectangle_info.height=(size_t) (y-rectangle_info.y); 6243 for (i=0; i < number_coordinates; i++) 6244 { 6245 coordinate_info[i].x-=rectangle_info.x; 6246 coordinate_info[i].y-=rectangle_info.y; 6247 } 6248 } 6249 else 6250 if (distance <= 9) 6251 continue; 6252 else 6253 if ((element == RectangleElement) || 6254 (element == CircleElement) || (element == EllipseElement)) 6255 { 6256 rectangle_info.width--; 6257 rectangle_info.height--; 6258 } 6259 /* 6260 Drawing is relative to image configuration. 6261 */ 6262 draw_info.x=(int) rectangle_info.x; 6263 draw_info.y=(int) rectangle_info.y; 6264 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6265 image,exception); 6266 width=(unsigned int) (*image)->columns; 6267 height=(unsigned int) (*image)->rows; 6268 x=0; 6269 y=0; 6270 if (windows->image.crop_geometry != (char *) NULL) 6271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6272 draw_info.x+=windows->image.x-(line_width/2); 6273 if (draw_info.x < 0) 6274 draw_info.x=0; 6275 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6276 draw_info.y+=windows->image.y-(line_width/2); 6277 if (draw_info.y < 0) 6278 draw_info.y=0; 6279 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6280 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6281 if (draw_info.width > (unsigned int) (*image)->columns) 6282 draw_info.width=(unsigned int) (*image)->columns; 6283 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6284 if (draw_info.height > (unsigned int) (*image)->rows) 6285 draw_info.height=(unsigned int) (*image)->rows; 6286 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6287 width*draw_info.width/windows->image.ximage->width, 6288 height*draw_info.height/windows->image.ximage->height, 6289 draw_info.x+x,draw_info.y+y); 6290 /* 6291 Initialize drawing attributes. 6292 */ 6293 draw_info.degrees=0.0; 6294 draw_info.element=element; 6295 draw_info.stipple=stipple; 6296 draw_info.line_width=line_width; 6297 draw_info.line_info=line_info; 6298 if (line_info.x1 > (int) (line_width/2)) 6299 draw_info.line_info.x1=(short) line_width/2; 6300 if (line_info.y1 > (int) (line_width/2)) 6301 draw_info.line_info.y1=(short) line_width/2; 6302 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6303 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6304 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6305 { 6306 draw_info.line_info.x2=(-draw_info.line_info.x2); 6307 draw_info.line_info.y2=(-draw_info.line_info.y2); 6308 } 6309 if (draw_info.line_info.x2 < 0) 6310 { 6311 draw_info.line_info.x2=(-draw_info.line_info.x2); 6312 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6313 } 6314 if (draw_info.line_info.y2 < 0) 6315 { 6316 draw_info.line_info.y2=(-draw_info.line_info.y2); 6317 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6318 } 6319 draw_info.rectangle_info=rectangle_info; 6320 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6321 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6322 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6323 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6324 draw_info.number_coordinates=(unsigned int) number_coordinates; 6325 draw_info.coordinate_info=coordinate_info; 6326 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6327 /* 6328 Draw element on image. 6329 */ 6330 XSetCursorState(display,windows,MagickTrue); 6331 XCheckRefreshWindows(display,windows); 6332 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6333 XSetCursorState(display,windows,MagickFalse); 6334 /* 6335 Update image colormap and return to image drawing. 6336 */ 6337 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6338 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6339 } 6340 XSetCursorState(display,windows,MagickFalse); 6341 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6342 return(status != 0 ? MagickTrue : MagickFalse); 6343} 6344 6345/* 6346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6347% % 6348% % 6349% % 6350+ X D r a w P a n R e c t a n g l e % 6351% % 6352% % 6353% % 6354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6355% 6356% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6357% displays a zoom image and the rectangle shows which portion of the image is 6358% displayed in the Image window. 6359% 6360% The format of the XDrawPanRectangle method is: 6361% 6362% XDrawPanRectangle(Display *display,XWindows *windows) 6363% 6364% A description of each parameter follows: 6365% 6366% o display: Specifies a connection to an X server; returned from 6367% XOpenDisplay. 6368% 6369% o windows: Specifies a pointer to a XWindows structure. 6370% 6371*/ 6372static void XDrawPanRectangle(Display *display,XWindows *windows) 6373{ 6374 MagickRealType 6375 scale_factor; 6376 6377 RectangleInfo 6378 highlight_info; 6379 6380 /* 6381 Determine dimensions of the panning rectangle. 6382 */ 6383 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6384 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6385 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6386 scale_factor=(MagickRealType) 6387 windows->pan.height/windows->image.ximage->height; 6388 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6389 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6390 /* 6391 Display the panning rectangle. 6392 */ 6393 (void) XClearWindow(display,windows->pan.id); 6394 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6395 &highlight_info); 6396} 6397 6398/* 6399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6400% % 6401% % 6402% % 6403+ X I m a g e C a c h e % 6404% % 6405% % 6406% % 6407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6408% 6409% XImageCache() handles the creation, manipulation, and destruction of the 6410% image cache (undo and redo buffers). 6411% 6412% The format of the XImageCache method is: 6413% 6414% void XImageCache(Display *display,XResourceInfo *resource_info, 6415% XWindows *windows,const CommandType command,Image **image, 6416% ExceptionInfo *exception) 6417% 6418% A description of each parameter follows: 6419% 6420% o display: Specifies a connection to an X server; returned from 6421% XOpenDisplay. 6422% 6423% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6424% 6425% o windows: Specifies a pointer to a XWindows structure. 6426% 6427% o command: Specifies a command to perform. 6428% 6429% o image: the image; XImageCache may transform the image and return a new 6430% image pointer. 6431% 6432% o exception: return any errors or warnings in this structure. 6433% 6434*/ 6435static void XImageCache(Display *display,XResourceInfo *resource_info, 6436 XWindows *windows,const CommandType command,Image **image, 6437 ExceptionInfo *exception) 6438{ 6439 Image 6440 *cache_image; 6441 6442 static Image 6443 *redo_image = (Image *) NULL, 6444 *undo_image = (Image *) NULL; 6445 6446 switch (command) 6447 { 6448 case FreeBuffersCommand: 6449 { 6450 /* 6451 Free memory from the undo and redo cache. 6452 */ 6453 while (undo_image != (Image *) NULL) 6454 { 6455 cache_image=undo_image; 6456 undo_image=GetPreviousImageInList(undo_image); 6457 cache_image->list=DestroyImage(cache_image->list); 6458 cache_image=DestroyImage(cache_image); 6459 } 6460 undo_image=NewImageList(); 6461 if (redo_image != (Image *) NULL) 6462 redo_image=DestroyImage(redo_image); 6463 redo_image=NewImageList(); 6464 return; 6465 } 6466 case UndoCommand: 6467 { 6468 char 6469 image_geometry[MaxTextExtent]; 6470 6471 /* 6472 Undo the last image transformation. 6473 */ 6474 if (undo_image == (Image *) NULL) 6475 { 6476 (void) XBell(display,0); 6477 return; 6478 } 6479 cache_image=undo_image; 6480 undo_image=GetPreviousImageInList(undo_image); 6481 windows->image.window_changes.width=(int) cache_image->columns; 6482 windows->image.window_changes.height=(int) cache_image->rows; 6483 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6484 windows->image.ximage->width,windows->image.ximage->height); 6485 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6486 exception); 6487 if (windows->image.crop_geometry != (char *) NULL) 6488 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6489 windows->image.crop_geometry); 6490 windows->image.crop_geometry=cache_image->geometry; 6491 if (redo_image != (Image *) NULL) 6492 redo_image=DestroyImage(redo_image); 6493 redo_image=(*image); 6494 *image=cache_image->list; 6495 cache_image=DestroyImage(cache_image); 6496 if (windows->image.orphan != MagickFalse) 6497 return; 6498 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6499 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6500 return; 6501 } 6502 case CutCommand: 6503 case PasteCommand: 6504 case ApplyCommand: 6505 case HalfSizeCommand: 6506 case OriginalSizeCommand: 6507 case DoubleSizeCommand: 6508 case ResizeCommand: 6509 case TrimCommand: 6510 case CropCommand: 6511 case ChopCommand: 6512 case FlipCommand: 6513 case FlopCommand: 6514 case RotateRightCommand: 6515 case RotateLeftCommand: 6516 case RotateCommand: 6517 case ShearCommand: 6518 case RollCommand: 6519 case NegateCommand: 6520 case ContrastStretchCommand: 6521 case SigmoidalContrastCommand: 6522 case NormalizeCommand: 6523 case EqualizeCommand: 6524 case HueCommand: 6525 case SaturationCommand: 6526 case BrightnessCommand: 6527 case GammaCommand: 6528 case SpiffCommand: 6529 case DullCommand: 6530 case GrayscaleCommand: 6531 case MapCommand: 6532 case QuantizeCommand: 6533 case DespeckleCommand: 6534 case EmbossCommand: 6535 case ReduceNoiseCommand: 6536 case AddNoiseCommand: 6537 case SharpenCommand: 6538 case BlurCommand: 6539 case ThresholdCommand: 6540 case EdgeDetectCommand: 6541 case SpreadCommand: 6542 case ShadeCommand: 6543 case RaiseCommand: 6544 case SegmentCommand: 6545 case SolarizeCommand: 6546 case SepiaToneCommand: 6547 case SwirlCommand: 6548 case ImplodeCommand: 6549 case VignetteCommand: 6550 case WaveCommand: 6551 case OilPaintCommand: 6552 case CharcoalDrawCommand: 6553 case AnnotateCommand: 6554 case AddBorderCommand: 6555 case AddFrameCommand: 6556 case CompositeCommand: 6557 case CommentCommand: 6558 case LaunchCommand: 6559 case RegionofInterestCommand: 6560 case SaveToUndoBufferCommand: 6561 case RedoCommand: 6562 { 6563 Image 6564 *previous_image; 6565 6566 ssize_t 6567 bytes; 6568 6569 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6570 if (undo_image != (Image *) NULL) 6571 { 6572 /* 6573 Ensure the undo cache has enough memory available. 6574 */ 6575 previous_image=undo_image; 6576 while (previous_image != (Image *) NULL) 6577 { 6578 bytes+=previous_image->list->columns*previous_image->list->rows* 6579 sizeof(PixelInfo); 6580 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6581 { 6582 previous_image=GetPreviousImageInList(previous_image); 6583 continue; 6584 } 6585 bytes-=previous_image->list->columns*previous_image->list->rows* 6586 sizeof(PixelInfo); 6587 if (previous_image == undo_image) 6588 undo_image=NewImageList(); 6589 else 6590 previous_image->next->previous=NewImageList(); 6591 break; 6592 } 6593 while (previous_image != (Image *) NULL) 6594 { 6595 /* 6596 Delete any excess memory from undo cache. 6597 */ 6598 cache_image=previous_image; 6599 previous_image=GetPreviousImageInList(previous_image); 6600 cache_image->list=DestroyImage(cache_image->list); 6601 cache_image=DestroyImage(cache_image); 6602 } 6603 } 6604 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6605 break; 6606 /* 6607 Save image before transformations are applied. 6608 */ 6609 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6610 if (cache_image == (Image *) NULL) 6611 break; 6612 XSetCursorState(display,windows,MagickTrue); 6613 XCheckRefreshWindows(display,windows); 6614 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6615 XSetCursorState(display,windows,MagickFalse); 6616 if (cache_image->list == (Image *) NULL) 6617 { 6618 cache_image=DestroyImage(cache_image); 6619 break; 6620 } 6621 cache_image->columns=(size_t) windows->image.ximage->width; 6622 cache_image->rows=(size_t) windows->image.ximage->height; 6623 cache_image->geometry=windows->image.crop_geometry; 6624 if (windows->image.crop_geometry != (char *) NULL) 6625 { 6626 cache_image->geometry=AcquireString((char *) NULL); 6627 (void) CopyMagickString(cache_image->geometry, 6628 windows->image.crop_geometry,MaxTextExtent); 6629 } 6630 if (undo_image == (Image *) NULL) 6631 { 6632 undo_image=cache_image; 6633 break; 6634 } 6635 undo_image->next=cache_image; 6636 undo_image->next->previous=undo_image; 6637 undo_image=undo_image->next; 6638 break; 6639 } 6640 default: 6641 break; 6642 } 6643 if (command == RedoCommand) 6644 { 6645 /* 6646 Redo the last image transformation. 6647 */ 6648 if (redo_image == (Image *) NULL) 6649 { 6650 (void) XBell(display,0); 6651 return; 6652 } 6653 windows->image.window_changes.width=(int) redo_image->columns; 6654 windows->image.window_changes.height=(int) redo_image->rows; 6655 if (windows->image.crop_geometry != (char *) NULL) 6656 windows->image.crop_geometry=(char *) 6657 RelinquishMagickMemory(windows->image.crop_geometry); 6658 windows->image.crop_geometry=redo_image->geometry; 6659 *image=DestroyImage(*image); 6660 *image=redo_image; 6661 redo_image=NewImageList(); 6662 if (windows->image.orphan != MagickFalse) 6663 return; 6664 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6665 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6666 return; 6667 } 6668 if (command != InfoCommand) 6669 return; 6670 /* 6671 Display image info. 6672 */ 6673 XSetCursorState(display,windows,MagickTrue); 6674 XCheckRefreshWindows(display,windows); 6675 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6676 XSetCursorState(display,windows,MagickFalse); 6677} 6678 6679/* 6680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6681% % 6682% % 6683% % 6684+ X I m a g e W i n d o w C o m m a n d % 6685% % 6686% % 6687% % 6688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6689% 6690% XImageWindowCommand() makes a transform to the image or Image window as 6691% specified by a user menu button or keyboard command. 6692% 6693% The format of the XImageWindowCommand method is: 6694% 6695% CommandType XImageWindowCommand(Display *display, 6696% XResourceInfo *resource_info,XWindows *windows, 6697% const MagickStatusType state,KeySym key_symbol,Image **image, 6698% ExceptionInfo *exception) 6699% 6700% A description of each parameter follows: 6701% 6702% o nexus: Method XImageWindowCommand returns an image when the 6703% user chooses 'Open Image' from the command menu. Otherwise a null 6704% image is returned. 6705% 6706% o display: Specifies a connection to an X server; returned from 6707% XOpenDisplay. 6708% 6709% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6710% 6711% o windows: Specifies a pointer to a XWindows structure. 6712% 6713% o state: key mask. 6714% 6715% o key_symbol: Specifies a command to perform. 6716% 6717% o image: the image; XImageWIndowCommand may transform the image and 6718% return a new image pointer. 6719% 6720% o exception: return any errors or warnings in this structure. 6721% 6722*/ 6723static CommandType XImageWindowCommand(Display *display, 6724 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6725 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6726{ 6727 static char 6728 delta[MaxTextExtent] = ""; 6729 6730 static const char 6731 Digits[] = "01234567890"; 6732 6733 static KeySym 6734 last_symbol = XK_0; 6735 6736 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6737 { 6738 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6739 { 6740 *delta='\0'; 6741 resource_info->quantum=1; 6742 } 6743 last_symbol=key_symbol; 6744 delta[strlen(delta)+1]='\0'; 6745 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6746 resource_info->quantum=StringToLong(delta); 6747 return(NullCommand); 6748 } 6749 last_symbol=key_symbol; 6750 if (resource_info->immutable) 6751 { 6752 /* 6753 Virtual image window has a restricted command set. 6754 */ 6755 switch (key_symbol) 6756 { 6757 case XK_question: 6758 return(InfoCommand); 6759 case XK_p: 6760 case XK_Print: 6761 return(PrintCommand); 6762 case XK_space: 6763 return(NextCommand); 6764 case XK_q: 6765 case XK_Escape: 6766 return(QuitCommand); 6767 default: 6768 break; 6769 } 6770 return(NullCommand); 6771 } 6772 switch ((int) key_symbol) 6773 { 6774 case XK_o: 6775 { 6776 if ((state & ControlMask) == 0) 6777 break; 6778 return(OpenCommand); 6779 } 6780 case XK_space: 6781 return(NextCommand); 6782 case XK_BackSpace: 6783 return(FormerCommand); 6784 case XK_s: 6785 { 6786 if ((state & Mod1Mask) != 0) 6787 return(SwirlCommand); 6788 if ((state & ControlMask) == 0) 6789 return(ShearCommand); 6790 return(SaveCommand); 6791 } 6792 case XK_p: 6793 case XK_Print: 6794 { 6795 if ((state & Mod1Mask) != 0) 6796 return(OilPaintCommand); 6797 if ((state & Mod4Mask) != 0) 6798 return(ColorCommand); 6799 if ((state & ControlMask) == 0) 6800 return(NullCommand); 6801 return(PrintCommand); 6802 } 6803 case XK_d: 6804 { 6805 if ((state & Mod4Mask) != 0) 6806 return(DrawCommand); 6807 if ((state & ControlMask) == 0) 6808 return(NullCommand); 6809 return(DeleteCommand); 6810 } 6811 case XK_Select: 6812 { 6813 if ((state & ControlMask) == 0) 6814 return(NullCommand); 6815 return(SelectCommand); 6816 } 6817 case XK_n: 6818 { 6819 if ((state & ControlMask) == 0) 6820 return(NullCommand); 6821 return(NewCommand); 6822 } 6823 case XK_q: 6824 case XK_Escape: 6825 return(QuitCommand); 6826 case XK_z: 6827 case XK_Undo: 6828 { 6829 if ((state & ControlMask) == 0) 6830 return(NullCommand); 6831 return(UndoCommand); 6832 } 6833 case XK_r: 6834 case XK_Redo: 6835 { 6836 if ((state & ControlMask) == 0) 6837 return(RollCommand); 6838 return(RedoCommand); 6839 } 6840 case XK_x: 6841 { 6842 if ((state & ControlMask) == 0) 6843 return(NullCommand); 6844 return(CutCommand); 6845 } 6846 case XK_c: 6847 { 6848 if ((state & Mod1Mask) != 0) 6849 return(CharcoalDrawCommand); 6850 if ((state & ControlMask) == 0) 6851 return(CropCommand); 6852 return(CopyCommand); 6853 } 6854 case XK_v: 6855 case XK_Insert: 6856 { 6857 if ((state & Mod4Mask) != 0) 6858 return(CompositeCommand); 6859 if ((state & ControlMask) == 0) 6860 return(FlipCommand); 6861 return(PasteCommand); 6862 } 6863 case XK_less: 6864 return(HalfSizeCommand); 6865 case XK_minus: 6866 return(OriginalSizeCommand); 6867 case XK_greater: 6868 return(DoubleSizeCommand); 6869 case XK_percent: 6870 return(ResizeCommand); 6871 case XK_at: 6872 return(RefreshCommand); 6873 case XK_bracketleft: 6874 return(ChopCommand); 6875 case XK_h: 6876 return(FlopCommand); 6877 case XK_slash: 6878 return(RotateRightCommand); 6879 case XK_backslash: 6880 return(RotateLeftCommand); 6881 case XK_asterisk: 6882 return(RotateCommand); 6883 case XK_t: 6884 return(TrimCommand); 6885 case XK_H: 6886 return(HueCommand); 6887 case XK_S: 6888 return(SaturationCommand); 6889 case XK_L: 6890 return(BrightnessCommand); 6891 case XK_G: 6892 return(GammaCommand); 6893 case XK_C: 6894 return(SpiffCommand); 6895 case XK_Z: 6896 return(DullCommand); 6897 case XK_N: 6898 return(NormalizeCommand); 6899 case XK_equal: 6900 return(EqualizeCommand); 6901 case XK_asciitilde: 6902 return(NegateCommand); 6903 case XK_period: 6904 return(GrayscaleCommand); 6905 case XK_numbersign: 6906 return(QuantizeCommand); 6907 case XK_F2: 6908 return(DespeckleCommand); 6909 case XK_F3: 6910 return(EmbossCommand); 6911 case XK_F4: 6912 return(ReduceNoiseCommand); 6913 case XK_F5: 6914 return(AddNoiseCommand); 6915 case XK_F6: 6916 return(SharpenCommand); 6917 case XK_F7: 6918 return(BlurCommand); 6919 case XK_F8: 6920 return(ThresholdCommand); 6921 case XK_F9: 6922 return(EdgeDetectCommand); 6923 case XK_F10: 6924 return(SpreadCommand); 6925 case XK_F11: 6926 return(ShadeCommand); 6927 case XK_F12: 6928 return(RaiseCommand); 6929 case XK_F13: 6930 return(SegmentCommand); 6931 case XK_i: 6932 { 6933 if ((state & Mod1Mask) == 0) 6934 return(NullCommand); 6935 return(ImplodeCommand); 6936 } 6937 case XK_w: 6938 { 6939 if ((state & Mod1Mask) == 0) 6940 return(NullCommand); 6941 return(WaveCommand); 6942 } 6943 case XK_m: 6944 { 6945 if ((state & Mod4Mask) == 0) 6946 return(NullCommand); 6947 return(MatteCommand); 6948 } 6949 case XK_b: 6950 { 6951 if ((state & Mod4Mask) == 0) 6952 return(NullCommand); 6953 return(AddBorderCommand); 6954 } 6955 case XK_f: 6956 { 6957 if ((state & Mod4Mask) == 0) 6958 return(NullCommand); 6959 return(AddFrameCommand); 6960 } 6961 case XK_exclam: 6962 { 6963 if ((state & Mod4Mask) == 0) 6964 return(NullCommand); 6965 return(CommentCommand); 6966 } 6967 case XK_a: 6968 { 6969 if ((state & Mod1Mask) != 0) 6970 return(ApplyCommand); 6971 if ((state & Mod4Mask) != 0) 6972 return(AnnotateCommand); 6973 if ((state & ControlMask) == 0) 6974 return(NullCommand); 6975 return(RegionofInterestCommand); 6976 } 6977 case XK_question: 6978 return(InfoCommand); 6979 case XK_plus: 6980 return(ZoomCommand); 6981 case XK_P: 6982 { 6983 if ((state & ShiftMask) == 0) 6984 return(NullCommand); 6985 return(ShowPreviewCommand); 6986 } 6987 case XK_Execute: 6988 return(LaunchCommand); 6989 case XK_F1: 6990 return(HelpCommand); 6991 case XK_Find: 6992 return(BrowseDocumentationCommand); 6993 case XK_Menu: 6994 { 6995 (void) XMapRaised(display,windows->command.id); 6996 return(NullCommand); 6997 } 6998 case XK_Next: 6999 case XK_Prior: 7000 case XK_Home: 7001 case XK_KP_Home: 7002 { 7003 XTranslateImage(display,windows,*image,key_symbol); 7004 return(NullCommand); 7005 } 7006 case XK_Up: 7007 case XK_KP_Up: 7008 case XK_Down: 7009 case XK_KP_Down: 7010 case XK_Left: 7011 case XK_KP_Left: 7012 case XK_Right: 7013 case XK_KP_Right: 7014 { 7015 if ((state & Mod1Mask) != 0) 7016 { 7017 RectangleInfo 7018 crop_info; 7019 7020 /* 7021 Trim one pixel from edge of image. 7022 */ 7023 crop_info.x=0; 7024 crop_info.y=0; 7025 crop_info.width=(size_t) windows->image.ximage->width; 7026 crop_info.height=(size_t) windows->image.ximage->height; 7027 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7028 { 7029 if (resource_info->quantum >= (int) crop_info.height) 7030 resource_info->quantum=(int) crop_info.height-1; 7031 crop_info.height-=resource_info->quantum; 7032 } 7033 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7034 { 7035 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7036 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7037 crop_info.y+=resource_info->quantum; 7038 crop_info.height-=resource_info->quantum; 7039 } 7040 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7041 { 7042 if (resource_info->quantum >= (int) crop_info.width) 7043 resource_info->quantum=(int) crop_info.width-1; 7044 crop_info.width-=resource_info->quantum; 7045 } 7046 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7047 { 7048 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7049 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7050 crop_info.x+=resource_info->quantum; 7051 crop_info.width-=resource_info->quantum; 7052 } 7053 if ((int) (windows->image.x+windows->image.width) > 7054 (int) crop_info.width) 7055 windows->image.x=(int) (crop_info.width-windows->image.width); 7056 if ((int) (windows->image.y+windows->image.height) > 7057 (int) crop_info.height) 7058 windows->image.y=(int) (crop_info.height-windows->image.height); 7059 XSetCropGeometry(display,windows,&crop_info,*image); 7060 windows->image.window_changes.width=(int) crop_info.width; 7061 windows->image.window_changes.height=(int) crop_info.height; 7062 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7063 (void) XConfigureImage(display,resource_info,windows,*image, 7064 exception); 7065 return(NullCommand); 7066 } 7067 XTranslateImage(display,windows,*image,key_symbol); 7068 return(NullCommand); 7069 } 7070 default: 7071 return(NullCommand); 7072 } 7073 return(NullCommand); 7074} 7075 7076/* 7077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7078% % 7079% % 7080% % 7081+ X M a g i c k C o m m a n d % 7082% % 7083% % 7084% % 7085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7086% 7087% XMagickCommand() makes a transform to the image or Image window as 7088% specified by a user menu button or keyboard command. 7089% 7090% The format of the XMagickCommand method is: 7091% 7092% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7093% XWindows *windows,const CommandType command,Image **image, 7094% ExceptionInfo *exception) 7095% 7096% A description of each parameter follows: 7097% 7098% o display: Specifies a connection to an X server; returned from 7099% XOpenDisplay. 7100% 7101% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7102% 7103% o windows: Specifies a pointer to a XWindows structure. 7104% 7105% o command: Specifies a command to perform. 7106% 7107% o image: the image; XMagickCommand may transform the image and return a 7108% new image pointer. 7109% 7110% o exception: return any errors or warnings in this structure. 7111% 7112*/ 7113static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7114 XWindows *windows,const CommandType command,Image **image, 7115 ExceptionInfo *exception) 7116{ 7117 char 7118 filename[MaxTextExtent], 7119 geometry[MaxTextExtent], 7120 modulate_factors[MaxTextExtent]; 7121 7122 GeometryInfo 7123 geometry_info; 7124 7125 Image 7126 *nexus; 7127 7128 ImageInfo 7129 *image_info; 7130 7131 int 7132 x, 7133 y; 7134 7135 MagickStatusType 7136 flags, 7137 status; 7138 7139 QuantizeInfo 7140 quantize_info; 7141 7142 RectangleInfo 7143 page_geometry; 7144 7145 register int 7146 i; 7147 7148 static char 7149 color[MaxTextExtent] = "gray"; 7150 7151 unsigned int 7152 height, 7153 width; 7154 7155 /* 7156 Process user command. 7157 */ 7158 XCheckRefreshWindows(display,windows); 7159 XImageCache(display,resource_info,windows,command,image,exception); 7160 nexus=NewImageList(); 7161 windows->image.window_changes.width=windows->image.ximage->width; 7162 windows->image.window_changes.height=windows->image.ximage->height; 7163 image_info=CloneImageInfo(resource_info->image_info); 7164 SetGeometryInfo(&geometry_info); 7165 GetQuantizeInfo(&quantize_info); 7166 switch (command) 7167 { 7168 case OpenCommand: 7169 { 7170 /* 7171 Load image. 7172 */ 7173 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7174 break; 7175 } 7176 case NextCommand: 7177 { 7178 /* 7179 Display next image. 7180 */ 7181 for (i=0; i < resource_info->quantum; i++) 7182 XClientMessage(display,windows->image.id,windows->im_protocols, 7183 windows->im_next_image,CurrentTime); 7184 break; 7185 } 7186 case FormerCommand: 7187 { 7188 /* 7189 Display former image. 7190 */ 7191 for (i=0; i < resource_info->quantum; i++) 7192 XClientMessage(display,windows->image.id,windows->im_protocols, 7193 windows->im_former_image,CurrentTime); 7194 break; 7195 } 7196 case SelectCommand: 7197 { 7198 int 7199 status; 7200 7201 /* 7202 Select image. 7203 */ 7204 status=chdir(resource_info->home_directory); 7205 if (status == -1) 7206 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7207 "UnableToOpenFile","%s",resource_info->home_directory); 7208 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7209 break; 7210 } 7211 case SaveCommand: 7212 { 7213 /* 7214 Save image. 7215 */ 7216 status=XSaveImage(display,resource_info,windows,*image,exception); 7217 if (status == MagickFalse) 7218 { 7219 char 7220 message[MaxTextExtent]; 7221 7222 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7223 exception->reason != (char *) NULL ? exception->reason : "", 7224 exception->description != (char *) NULL ? exception->description : 7225 ""); 7226 XNoticeWidget(display,windows,"Unable to save file:",message); 7227 break; 7228 } 7229 break; 7230 } 7231 case PrintCommand: 7232 { 7233 /* 7234 Print image. 7235 */ 7236 status=XPrintImage(display,resource_info,windows,*image,exception); 7237 if (status == MagickFalse) 7238 { 7239 char 7240 message[MaxTextExtent]; 7241 7242 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7243 exception->reason != (char *) NULL ? exception->reason : "", 7244 exception->description != (char *) NULL ? exception->description : 7245 ""); 7246 XNoticeWidget(display,windows,"Unable to print file:",message); 7247 break; 7248 } 7249 break; 7250 } 7251 case DeleteCommand: 7252 { 7253 static char 7254 filename[MaxTextExtent] = "\0"; 7255 7256 /* 7257 Delete image file. 7258 */ 7259 XFileBrowserWidget(display,windows,"Delete",filename); 7260 if (*filename == '\0') 7261 break; 7262 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7263 if (status != MagickFalse) 7264 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7265 break; 7266 } 7267 case NewCommand: 7268 { 7269 int 7270 status; 7271 7272 static char 7273 color[MaxTextExtent] = "gray", 7274 geometry[MaxTextExtent] = "640x480"; 7275 7276 static const char 7277 *format = "gradient"; 7278 7279 /* 7280 Query user for canvas geometry. 7281 */ 7282 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7283 geometry); 7284 if (*geometry == '\0') 7285 break; 7286 if (status == 0) 7287 format="xc"; 7288 XColorBrowserWidget(display,windows,"Select",color); 7289 if (*color == '\0') 7290 break; 7291 /* 7292 Create canvas. 7293 */ 7294 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7295 "%s:%s",format,color); 7296 (void) CloneString(&image_info->size,geometry); 7297 nexus=ReadImage(image_info,exception); 7298 CatchException(exception); 7299 XClientMessage(display,windows->image.id,windows->im_protocols, 7300 windows->im_next_image,CurrentTime); 7301 break; 7302 } 7303 case VisualDirectoryCommand: 7304 { 7305 /* 7306 Visual Image directory. 7307 */ 7308 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7309 break; 7310 } 7311 case QuitCommand: 7312 { 7313 /* 7314 exit program. 7315 */ 7316 if (resource_info->confirm_exit == MagickFalse) 7317 XClientMessage(display,windows->image.id,windows->im_protocols, 7318 windows->im_exit,CurrentTime); 7319 else 7320 { 7321 int 7322 status; 7323 7324 /* 7325 Confirm program exit. 7326 */ 7327 status=XConfirmWidget(display,windows,"Do you really want to exit", 7328 resource_info->client_name); 7329 if (status > 0) 7330 XClientMessage(display,windows->image.id,windows->im_protocols, 7331 windows->im_exit,CurrentTime); 7332 } 7333 break; 7334 } 7335 case CutCommand: 7336 { 7337 /* 7338 Cut image. 7339 */ 7340 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7341 break; 7342 } 7343 case CopyCommand: 7344 { 7345 /* 7346 Copy image. 7347 */ 7348 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7349 exception); 7350 break; 7351 } 7352 case PasteCommand: 7353 { 7354 /* 7355 Paste image. 7356 */ 7357 status=XPasteImage(display,resource_info,windows,*image,exception); 7358 if (status == MagickFalse) 7359 { 7360 XNoticeWidget(display,windows,"Unable to paste X image", 7361 (*image)->filename); 7362 break; 7363 } 7364 break; 7365 } 7366 case HalfSizeCommand: 7367 { 7368 /* 7369 Half image size. 7370 */ 7371 windows->image.window_changes.width=windows->image.ximage->width/2; 7372 windows->image.window_changes.height=windows->image.ximage->height/2; 7373 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7374 break; 7375 } 7376 case OriginalSizeCommand: 7377 { 7378 /* 7379 Original image size. 7380 */ 7381 windows->image.window_changes.width=(int) (*image)->columns; 7382 windows->image.window_changes.height=(int) (*image)->rows; 7383 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7384 break; 7385 } 7386 case DoubleSizeCommand: 7387 { 7388 /* 7389 Double the image size. 7390 */ 7391 windows->image.window_changes.width=windows->image.ximage->width << 1; 7392 windows->image.window_changes.height=windows->image.ximage->height << 1; 7393 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7394 break; 7395 } 7396 case ResizeCommand: 7397 { 7398 int 7399 status; 7400 7401 size_t 7402 height, 7403 width; 7404 7405 ssize_t 7406 x, 7407 y; 7408 7409 /* 7410 Resize image. 7411 */ 7412 width=(size_t) windows->image.ximage->width; 7413 height=(size_t) windows->image.ximage->height; 7414 x=0; 7415 y=0; 7416 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7417 (double) width,(double) height); 7418 status=XDialogWidget(display,windows,"Resize", 7419 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7420 if (*geometry == '\0') 7421 break; 7422 if (status == 0) 7423 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7424 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7425 windows->image.window_changes.width=(int) width; 7426 windows->image.window_changes.height=(int) height; 7427 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7428 break; 7429 } 7430 case ApplyCommand: 7431 { 7432 char 7433 image_geometry[MaxTextExtent]; 7434 7435 if ((windows->image.crop_geometry == (char *) NULL) && 7436 ((int) (*image)->columns == windows->image.ximage->width) && 7437 ((int) (*image)->rows == windows->image.ximage->height)) 7438 break; 7439 /* 7440 Apply size transforms to image. 7441 */ 7442 XSetCursorState(display,windows,MagickTrue); 7443 XCheckRefreshWindows(display,windows); 7444 /* 7445 Crop and/or scale displayed image. 7446 */ 7447 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7448 windows->image.ximage->width,windows->image.ximage->height); 7449 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7450 exception); 7451 if (windows->image.crop_geometry != (char *) NULL) 7452 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7453 windows->image.crop_geometry); 7454 windows->image.x=0; 7455 windows->image.y=0; 7456 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7457 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7458 break; 7459 } 7460 case RefreshCommand: 7461 { 7462 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7463 break; 7464 } 7465 case RestoreCommand: 7466 { 7467 /* 7468 Restore Image window to its original size. 7469 */ 7470 if ((windows->image.width == (unsigned int) (*image)->columns) && 7471 (windows->image.height == (unsigned int) (*image)->rows) && 7472 (windows->image.crop_geometry == (char *) NULL)) 7473 { 7474 (void) XBell(display,0); 7475 break; 7476 } 7477 windows->image.window_changes.width=(int) (*image)->columns; 7478 windows->image.window_changes.height=(int) (*image)->rows; 7479 if (windows->image.crop_geometry != (char *) NULL) 7480 { 7481 windows->image.crop_geometry=(char *) 7482 RelinquishMagickMemory(windows->image.crop_geometry); 7483 windows->image.crop_geometry=(char *) NULL; 7484 windows->image.x=0; 7485 windows->image.y=0; 7486 } 7487 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7488 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7489 break; 7490 } 7491 case CropCommand: 7492 { 7493 /* 7494 Crop image. 7495 */ 7496 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7497 exception); 7498 break; 7499 } 7500 case ChopCommand: 7501 { 7502 /* 7503 Chop image. 7504 */ 7505 status=XChopImage(display,resource_info,windows,image,exception); 7506 if (status == MagickFalse) 7507 { 7508 XNoticeWidget(display,windows,"Unable to cut X image", 7509 (*image)->filename); 7510 break; 7511 } 7512 break; 7513 } 7514 case FlopCommand: 7515 { 7516 Image 7517 *flop_image; 7518 7519 /* 7520 Flop image scanlines. 7521 */ 7522 XSetCursorState(display,windows,MagickTrue); 7523 XCheckRefreshWindows(display,windows); 7524 flop_image=FlopImage(*image,exception); 7525 if (flop_image != (Image *) NULL) 7526 { 7527 *image=DestroyImage(*image); 7528 *image=flop_image; 7529 } 7530 CatchException(exception); 7531 XSetCursorState(display,windows,MagickFalse); 7532 if (windows->image.crop_geometry != (char *) NULL) 7533 { 7534 /* 7535 Flop crop geometry. 7536 */ 7537 width=(unsigned int) (*image)->columns; 7538 height=(unsigned int) (*image)->rows; 7539 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7540 &width,&height); 7541 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7542 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7543 } 7544 if (windows->image.orphan != MagickFalse) 7545 break; 7546 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7547 break; 7548 } 7549 case FlipCommand: 7550 { 7551 Image 7552 *flip_image; 7553 7554 /* 7555 Flip image scanlines. 7556 */ 7557 XSetCursorState(display,windows,MagickTrue); 7558 XCheckRefreshWindows(display,windows); 7559 flip_image=FlipImage(*image,exception); 7560 if (flip_image != (Image *) NULL) 7561 { 7562 *image=DestroyImage(*image); 7563 *image=flip_image; 7564 } 7565 CatchException(exception); 7566 XSetCursorState(display,windows,MagickFalse); 7567 if (windows->image.crop_geometry != (char *) NULL) 7568 { 7569 /* 7570 Flip crop geometry. 7571 */ 7572 width=(unsigned int) (*image)->columns; 7573 height=(unsigned int) (*image)->rows; 7574 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7575 &width,&height); 7576 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7577 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7578 } 7579 if (windows->image.orphan != MagickFalse) 7580 break; 7581 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7582 break; 7583 } 7584 case RotateRightCommand: 7585 { 7586 /* 7587 Rotate image 90 degrees clockwise. 7588 */ 7589 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7590 if (status == MagickFalse) 7591 { 7592 XNoticeWidget(display,windows,"Unable to rotate X image", 7593 (*image)->filename); 7594 break; 7595 } 7596 break; 7597 } 7598 case RotateLeftCommand: 7599 { 7600 /* 7601 Rotate image 90 degrees counter-clockwise. 7602 */ 7603 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7604 if (status == MagickFalse) 7605 { 7606 XNoticeWidget(display,windows,"Unable to rotate X image", 7607 (*image)->filename); 7608 break; 7609 } 7610 break; 7611 } 7612 case RotateCommand: 7613 { 7614 /* 7615 Rotate image. 7616 */ 7617 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7618 if (status == MagickFalse) 7619 { 7620 XNoticeWidget(display,windows,"Unable to rotate X image", 7621 (*image)->filename); 7622 break; 7623 } 7624 break; 7625 } 7626 case ShearCommand: 7627 { 7628 Image 7629 *shear_image; 7630 7631 static char 7632 geometry[MaxTextExtent] = "45.0x45.0"; 7633 7634 /* 7635 Query user for shear color and geometry. 7636 */ 7637 XColorBrowserWidget(display,windows,"Select",color); 7638 if (*color == '\0') 7639 break; 7640 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7641 geometry); 7642 if (*geometry == '\0') 7643 break; 7644 /* 7645 Shear image. 7646 */ 7647 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7648 exception); 7649 XSetCursorState(display,windows,MagickTrue); 7650 XCheckRefreshWindows(display,windows); 7651 (void) QueryColorCompliance(color,AllCompliance, 7652 &(*image)->background_color,exception); 7653 flags=ParseGeometry(geometry,&geometry_info); 7654 if ((flags & SigmaValue) == 0) 7655 geometry_info.sigma=geometry_info.rho; 7656 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7657 exception); 7658 if (shear_image != (Image *) NULL) 7659 { 7660 *image=DestroyImage(*image); 7661 *image=shear_image; 7662 } 7663 CatchException(exception); 7664 XSetCursorState(display,windows,MagickFalse); 7665 if (windows->image.orphan != MagickFalse) 7666 break; 7667 windows->image.window_changes.width=(int) (*image)->columns; 7668 windows->image.window_changes.height=(int) (*image)->rows; 7669 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7670 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7671 break; 7672 } 7673 case RollCommand: 7674 { 7675 Image 7676 *roll_image; 7677 7678 static char 7679 geometry[MaxTextExtent] = "+2+2"; 7680 7681 /* 7682 Query user for the roll geometry. 7683 */ 7684 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7685 geometry); 7686 if (*geometry == '\0') 7687 break; 7688 /* 7689 Roll image. 7690 */ 7691 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7692 exception); 7693 XSetCursorState(display,windows,MagickTrue); 7694 XCheckRefreshWindows(display,windows); 7695 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7696 exception); 7697 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7698 exception); 7699 if (roll_image != (Image *) NULL) 7700 { 7701 *image=DestroyImage(*image); 7702 *image=roll_image; 7703 } 7704 CatchException(exception); 7705 XSetCursorState(display,windows,MagickFalse); 7706 if (windows->image.orphan != MagickFalse) 7707 break; 7708 windows->image.window_changes.width=(int) (*image)->columns; 7709 windows->image.window_changes.height=(int) (*image)->rows; 7710 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7711 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7712 break; 7713 } 7714 case TrimCommand: 7715 { 7716 static char 7717 fuzz[MaxTextExtent]; 7718 7719 /* 7720 Query user for the fuzz factor. 7721 */ 7722 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7723 (*image)->fuzz/(QuantumRange+1.0)); 7724 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7725 if (*fuzz == '\0') 7726 break; 7727 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7728 /* 7729 Trim image. 7730 */ 7731 status=XTrimImage(display,resource_info,windows,*image,exception); 7732 if (status == MagickFalse) 7733 { 7734 XNoticeWidget(display,windows,"Unable to trim X image", 7735 (*image)->filename); 7736 break; 7737 } 7738 break; 7739 } 7740 case HueCommand: 7741 { 7742 static char 7743 hue_percent[MaxTextExtent] = "110"; 7744 7745 /* 7746 Query user for percent hue change. 7747 */ 7748 (void) XDialogWidget(display,windows,"Apply", 7749 "Enter percent change in image hue (0-200):",hue_percent); 7750 if (*hue_percent == '\0') 7751 break; 7752 /* 7753 Vary the image hue. 7754 */ 7755 XSetCursorState(display,windows,MagickTrue); 7756 XCheckRefreshWindows(display,windows); 7757 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7758 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7759 MaxTextExtent); 7760 (void) ModulateImage(*image,modulate_factors,exception); 7761 XSetCursorState(display,windows,MagickFalse); 7762 if (windows->image.orphan != MagickFalse) 7763 break; 7764 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7765 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7766 break; 7767 } 7768 case SaturationCommand: 7769 { 7770 static char 7771 saturation_percent[MaxTextExtent] = "110"; 7772 7773 /* 7774 Query user for percent saturation change. 7775 */ 7776 (void) XDialogWidget(display,windows,"Apply", 7777 "Enter percent change in color saturation (0-200):",saturation_percent); 7778 if (*saturation_percent == '\0') 7779 break; 7780 /* 7781 Vary color saturation. 7782 */ 7783 XSetCursorState(display,windows,MagickTrue); 7784 XCheckRefreshWindows(display,windows); 7785 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7786 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7787 MaxTextExtent); 7788 (void) ModulateImage(*image,modulate_factors,exception); 7789 XSetCursorState(display,windows,MagickFalse); 7790 if (windows->image.orphan != MagickFalse) 7791 break; 7792 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7793 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7794 break; 7795 } 7796 case BrightnessCommand: 7797 { 7798 static char 7799 brightness_percent[MaxTextExtent] = "110"; 7800 7801 /* 7802 Query user for percent brightness change. 7803 */ 7804 (void) XDialogWidget(display,windows,"Apply", 7805 "Enter percent change in color brightness (0-200):",brightness_percent); 7806 if (*brightness_percent == '\0') 7807 break; 7808 /* 7809 Vary the color brightness. 7810 */ 7811 XSetCursorState(display,windows,MagickTrue); 7812 XCheckRefreshWindows(display,windows); 7813 (void) CopyMagickString(modulate_factors,brightness_percent, 7814 MaxTextExtent); 7815 (void) ModulateImage(*image,modulate_factors,exception); 7816 XSetCursorState(display,windows,MagickFalse); 7817 if (windows->image.orphan != MagickFalse) 7818 break; 7819 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7820 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7821 break; 7822 } 7823 case GammaCommand: 7824 { 7825 static char 7826 factor[MaxTextExtent] = "1.6"; 7827 7828 /* 7829 Query user for gamma value. 7830 */ 7831 (void) XDialogWidget(display,windows,"Gamma", 7832 "Enter gamma value (e.g. 1.2):",factor); 7833 if (*factor == '\0') 7834 break; 7835 /* 7836 Gamma correct image. 7837 */ 7838 XSetCursorState(display,windows,MagickTrue); 7839 XCheckRefreshWindows(display,windows); 7840 (void) GammaImage(*image,atof(factor),exception); 7841 XSetCursorState(display,windows,MagickFalse); 7842 if (windows->image.orphan != MagickFalse) 7843 break; 7844 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7845 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7846 break; 7847 } 7848 case SpiffCommand: 7849 { 7850 /* 7851 Sharpen the image contrast. 7852 */ 7853 XSetCursorState(display,windows,MagickTrue); 7854 XCheckRefreshWindows(display,windows); 7855 (void) ContrastImage(*image,MagickTrue,exception); 7856 XSetCursorState(display,windows,MagickFalse); 7857 if (windows->image.orphan != MagickFalse) 7858 break; 7859 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7860 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7861 break; 7862 } 7863 case DullCommand: 7864 { 7865 /* 7866 Dull the image contrast. 7867 */ 7868 XSetCursorState(display,windows,MagickTrue); 7869 XCheckRefreshWindows(display,windows); 7870 (void) ContrastImage(*image,MagickFalse,exception); 7871 XSetCursorState(display,windows,MagickFalse); 7872 if (windows->image.orphan != MagickFalse) 7873 break; 7874 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7875 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7876 break; 7877 } 7878 case ContrastStretchCommand: 7879 { 7880 double 7881 black_point, 7882 white_point; 7883 7884 static char 7885 levels[MaxTextExtent] = "1%"; 7886 7887 /* 7888 Query user for gamma value. 7889 */ 7890 (void) XDialogWidget(display,windows,"Contrast Stretch", 7891 "Enter black and white points:",levels); 7892 if (*levels == '\0') 7893 break; 7894 /* 7895 Contrast stretch image. 7896 */ 7897 XSetCursorState(display,windows,MagickTrue); 7898 XCheckRefreshWindows(display,windows); 7899 flags=ParseGeometry(levels,&geometry_info); 7900 black_point=geometry_info.rho; 7901 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7902 if ((flags & PercentValue) != 0) 7903 { 7904 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7905 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7906 } 7907 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7908 (void) ContrastStretchImage(*image,black_point,white_point, 7909 exception); 7910 XSetCursorState(display,windows,MagickFalse); 7911 if (windows->image.orphan != MagickFalse) 7912 break; 7913 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7914 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7915 break; 7916 } 7917 case SigmoidalContrastCommand: 7918 { 7919 GeometryInfo 7920 geometry_info; 7921 7922 MagickStatusType 7923 flags; 7924 7925 static char 7926 levels[MaxTextExtent] = "3x50%"; 7927 7928 /* 7929 Query user for gamma value. 7930 */ 7931 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7932 "Enter contrast and midpoint:",levels); 7933 if (*levels == '\0') 7934 break; 7935 /* 7936 Contrast stretch image. 7937 */ 7938 XSetCursorState(display,windows,MagickTrue); 7939 XCheckRefreshWindows(display,windows); 7940 flags=ParseGeometry(levels,&geometry_info); 7941 if ((flags & SigmaValue) == 0) 7942 geometry_info.sigma=1.0*QuantumRange/2.0; 7943 if ((flags & PercentValue) != 0) 7944 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7945 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7946 geometry_info.sigma,exception); 7947 XSetCursorState(display,windows,MagickFalse); 7948 if (windows->image.orphan != MagickFalse) 7949 break; 7950 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7951 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7952 break; 7953 } 7954 case NormalizeCommand: 7955 { 7956 /* 7957 Perform histogram normalization on the image. 7958 */ 7959 XSetCursorState(display,windows,MagickTrue); 7960 XCheckRefreshWindows(display,windows); 7961 (void) NormalizeImage(*image,exception); 7962 XSetCursorState(display,windows,MagickFalse); 7963 if (windows->image.orphan != MagickFalse) 7964 break; 7965 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7966 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7967 break; 7968 } 7969 case EqualizeCommand: 7970 { 7971 /* 7972 Perform histogram equalization on the image. 7973 */ 7974 XSetCursorState(display,windows,MagickTrue); 7975 XCheckRefreshWindows(display,windows); 7976 (void) EqualizeImage(*image,exception); 7977 XSetCursorState(display,windows,MagickFalse); 7978 if (windows->image.orphan != MagickFalse) 7979 break; 7980 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7981 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7982 break; 7983 } 7984 case NegateCommand: 7985 { 7986 /* 7987 Negate colors in image. 7988 */ 7989 XSetCursorState(display,windows,MagickTrue); 7990 XCheckRefreshWindows(display,windows); 7991 (void) NegateImage(*image,MagickFalse,exception); 7992 XSetCursorState(display,windows,MagickFalse); 7993 if (windows->image.orphan != MagickFalse) 7994 break; 7995 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7996 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7997 break; 7998 } 7999 case GrayscaleCommand: 8000 { 8001 /* 8002 Convert image to grayscale. 8003 */ 8004 XSetCursorState(display,windows,MagickTrue); 8005 XCheckRefreshWindows(display,windows); 8006 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8007 GrayscaleType : GrayscaleMatteType,exception); 8008 XSetCursorState(display,windows,MagickFalse); 8009 if (windows->image.orphan != MagickFalse) 8010 break; 8011 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8012 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8013 break; 8014 } 8015 case MapCommand: 8016 { 8017 Image 8018 *affinity_image; 8019 8020 static char 8021 filename[MaxTextExtent] = "\0"; 8022 8023 /* 8024 Request image file name from user. 8025 */ 8026 XFileBrowserWidget(display,windows,"Map",filename); 8027 if (*filename == '\0') 8028 break; 8029 /* 8030 Map image. 8031 */ 8032 XSetCursorState(display,windows,MagickTrue); 8033 XCheckRefreshWindows(display,windows); 8034 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8035 affinity_image=ReadImage(image_info,exception); 8036 if (affinity_image != (Image *) NULL) 8037 { 8038 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8039 affinity_image=DestroyImage(affinity_image); 8040 } 8041 CatchException(exception); 8042 XSetCursorState(display,windows,MagickFalse); 8043 if (windows->image.orphan != MagickFalse) 8044 break; 8045 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8046 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8047 break; 8048 } 8049 case QuantizeCommand: 8050 { 8051 int 8052 status; 8053 8054 static char 8055 colors[MaxTextExtent] = "256"; 8056 8057 /* 8058 Query user for maximum number of colors. 8059 */ 8060 status=XDialogWidget(display,windows,"Quantize", 8061 "Maximum number of colors:",colors); 8062 if (*colors == '\0') 8063 break; 8064 /* 8065 Color reduce the image. 8066 */ 8067 XSetCursorState(display,windows,MagickTrue); 8068 XCheckRefreshWindows(display,windows); 8069 quantize_info.number_colors=StringToUnsignedLong(colors); 8070 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8071 (void) QuantizeImage(&quantize_info,*image,exception); 8072 XSetCursorState(display,windows,MagickFalse); 8073 if (windows->image.orphan != MagickFalse) 8074 break; 8075 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8076 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8077 break; 8078 } 8079 case DespeckleCommand: 8080 { 8081 Image 8082 *despeckle_image; 8083 8084 /* 8085 Despeckle image. 8086 */ 8087 XSetCursorState(display,windows,MagickTrue); 8088 XCheckRefreshWindows(display,windows); 8089 despeckle_image=DespeckleImage(*image,exception); 8090 if (despeckle_image != (Image *) NULL) 8091 { 8092 *image=DestroyImage(*image); 8093 *image=despeckle_image; 8094 } 8095 CatchException(exception); 8096 XSetCursorState(display,windows,MagickFalse); 8097 if (windows->image.orphan != MagickFalse) 8098 break; 8099 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8100 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8101 break; 8102 } 8103 case EmbossCommand: 8104 { 8105 Image 8106 *emboss_image; 8107 8108 static char 8109 radius[MaxTextExtent] = "0.0x1.0"; 8110 8111 /* 8112 Query user for emboss radius. 8113 */ 8114 (void) XDialogWidget(display,windows,"Emboss", 8115 "Enter the emboss radius and standard deviation:",radius); 8116 if (*radius == '\0') 8117 break; 8118 /* 8119 Reduce noise in the image. 8120 */ 8121 XSetCursorState(display,windows,MagickTrue); 8122 XCheckRefreshWindows(display,windows); 8123 flags=ParseGeometry(radius,&geometry_info); 8124 if ((flags & SigmaValue) == 0) 8125 geometry_info.sigma=1.0; 8126 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8127 exception); 8128 if (emboss_image != (Image *) NULL) 8129 { 8130 *image=DestroyImage(*image); 8131 *image=emboss_image; 8132 } 8133 CatchException(exception); 8134 XSetCursorState(display,windows,MagickFalse); 8135 if (windows->image.orphan != MagickFalse) 8136 break; 8137 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8138 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8139 break; 8140 } 8141 case ReduceNoiseCommand: 8142 { 8143 Image 8144 *noise_image; 8145 8146 static char 8147 radius[MaxTextExtent] = "0"; 8148 8149 /* 8150 Query user for noise radius. 8151 */ 8152 (void) XDialogWidget(display,windows,"Reduce Noise", 8153 "Enter the noise radius:",radius); 8154 if (*radius == '\0') 8155 break; 8156 /* 8157 Reduce noise in the image. 8158 */ 8159 XSetCursorState(display,windows,MagickTrue); 8160 XCheckRefreshWindows(display,windows); 8161 flags=ParseGeometry(radius,&geometry_info); 8162 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8163 geometry_info.rho,(size_t) geometry_info.rho,exception); 8164 if (noise_image != (Image *) NULL) 8165 { 8166 *image=DestroyImage(*image); 8167 *image=noise_image; 8168 } 8169 CatchException(exception); 8170 XSetCursorState(display,windows,MagickFalse); 8171 if (windows->image.orphan != MagickFalse) 8172 break; 8173 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8174 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8175 break; 8176 } 8177 case AddNoiseCommand: 8178 { 8179 char 8180 **noises; 8181 8182 Image 8183 *noise_image; 8184 8185 static char 8186 noise_type[MaxTextExtent] = "Gaussian"; 8187 8188 /* 8189 Add noise to the image. 8190 */ 8191 noises=GetCommandOptions(MagickNoiseOptions); 8192 if (noises == (char **) NULL) 8193 break; 8194 XListBrowserWidget(display,windows,&windows->widget, 8195 (const char **) noises,"Add Noise", 8196 "Select a type of noise to add to your image:",noise_type); 8197 noises=DestroyStringList(noises); 8198 if (*noise_type == '\0') 8199 break; 8200 XSetCursorState(display,windows,MagickTrue); 8201 XCheckRefreshWindows(display,windows); 8202 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8203 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8204 if (noise_image != (Image *) NULL) 8205 { 8206 *image=DestroyImage(*image); 8207 *image=noise_image; 8208 } 8209 CatchException(exception); 8210 XSetCursorState(display,windows,MagickFalse); 8211 if (windows->image.orphan != MagickFalse) 8212 break; 8213 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8214 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8215 break; 8216 } 8217 case SharpenCommand: 8218 { 8219 Image 8220 *sharp_image; 8221 8222 static char 8223 radius[MaxTextExtent] = "0.0x1.0"; 8224 8225 /* 8226 Query user for sharpen radius. 8227 */ 8228 (void) XDialogWidget(display,windows,"Sharpen", 8229 "Enter the sharpen radius and standard deviation:",radius); 8230 if (*radius == '\0') 8231 break; 8232 /* 8233 Sharpen image scanlines. 8234 */ 8235 XSetCursorState(display,windows,MagickTrue); 8236 XCheckRefreshWindows(display,windows); 8237 flags=ParseGeometry(radius,&geometry_info); 8238 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8239 geometry_info.xi,exception); 8240 if (sharp_image != (Image *) NULL) 8241 { 8242 *image=DestroyImage(*image); 8243 *image=sharp_image; 8244 } 8245 CatchException(exception); 8246 XSetCursorState(display,windows,MagickFalse); 8247 if (windows->image.orphan != MagickFalse) 8248 break; 8249 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8250 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8251 break; 8252 } 8253 case BlurCommand: 8254 { 8255 Image 8256 *blur_image; 8257 8258 static char 8259 radius[MaxTextExtent] = "0.0x1.0"; 8260 8261 /* 8262 Query user for blur radius. 8263 */ 8264 (void) XDialogWidget(display,windows,"Blur", 8265 "Enter the blur radius and standard deviation:",radius); 8266 if (*radius == '\0') 8267 break; 8268 /* 8269 Blur an image. 8270 */ 8271 XSetCursorState(display,windows,MagickTrue); 8272 XCheckRefreshWindows(display,windows); 8273 flags=ParseGeometry(radius,&geometry_info); 8274 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8275 geometry_info.xi,exception); 8276 if (blur_image != (Image *) NULL) 8277 { 8278 *image=DestroyImage(*image); 8279 *image=blur_image; 8280 } 8281 CatchException(exception); 8282 XSetCursorState(display,windows,MagickFalse); 8283 if (windows->image.orphan != MagickFalse) 8284 break; 8285 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8286 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8287 break; 8288 } 8289 case ThresholdCommand: 8290 { 8291 double 8292 threshold; 8293 8294 static char 8295 factor[MaxTextExtent] = "128"; 8296 8297 /* 8298 Query user for threshold value. 8299 */ 8300 (void) XDialogWidget(display,windows,"Threshold", 8301 "Enter threshold value:",factor); 8302 if (*factor == '\0') 8303 break; 8304 /* 8305 Gamma correct image. 8306 */ 8307 XSetCursorState(display,windows,MagickTrue); 8308 XCheckRefreshWindows(display,windows); 8309 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8310 (void) BilevelImage(*image,threshold,exception); 8311 XSetCursorState(display,windows,MagickFalse); 8312 if (windows->image.orphan != MagickFalse) 8313 break; 8314 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8315 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8316 break; 8317 } 8318 case EdgeDetectCommand: 8319 { 8320 Image 8321 *edge_image; 8322 8323 static char 8324 radius[MaxTextExtent] = "0"; 8325 8326 /* 8327 Query user for edge factor. 8328 */ 8329 (void) XDialogWidget(display,windows,"Detect Edges", 8330 "Enter the edge detect radius:",radius); 8331 if (*radius == '\0') 8332 break; 8333 /* 8334 Detect edge in image. 8335 */ 8336 XSetCursorState(display,windows,MagickTrue); 8337 XCheckRefreshWindows(display,windows); 8338 flags=ParseGeometry(radius,&geometry_info); 8339 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8340 exception); 8341 if (edge_image != (Image *) NULL) 8342 { 8343 *image=DestroyImage(*image); 8344 *image=edge_image; 8345 } 8346 CatchException(exception); 8347 XSetCursorState(display,windows,MagickFalse); 8348 if (windows->image.orphan != MagickFalse) 8349 break; 8350 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8351 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8352 break; 8353 } 8354 case SpreadCommand: 8355 { 8356 Image 8357 *spread_image; 8358 8359 static char 8360 amount[MaxTextExtent] = "2"; 8361 8362 /* 8363 Query user for spread amount. 8364 */ 8365 (void) XDialogWidget(display,windows,"Spread", 8366 "Enter the displacement amount:",amount); 8367 if (*amount == '\0') 8368 break; 8369 /* 8370 Displace image pixels by a random amount. 8371 */ 8372 XSetCursorState(display,windows,MagickTrue); 8373 XCheckRefreshWindows(display,windows); 8374 flags=ParseGeometry(amount,&geometry_info); 8375 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8376 exception); 8377 if (spread_image != (Image *) NULL) 8378 { 8379 *image=DestroyImage(*image); 8380 *image=spread_image; 8381 } 8382 CatchException(exception); 8383 XSetCursorState(display,windows,MagickFalse); 8384 if (windows->image.orphan != MagickFalse) 8385 break; 8386 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8387 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8388 break; 8389 } 8390 case ShadeCommand: 8391 { 8392 Image 8393 *shade_image; 8394 8395 int 8396 status; 8397 8398 static char 8399 geometry[MaxTextExtent] = "30x30"; 8400 8401 /* 8402 Query user for the shade geometry. 8403 */ 8404 status=XDialogWidget(display,windows,"Shade", 8405 "Enter the azimuth and elevation of the light source:",geometry); 8406 if (*geometry == '\0') 8407 break; 8408 /* 8409 Shade image pixels. 8410 */ 8411 XSetCursorState(display,windows,MagickTrue); 8412 XCheckRefreshWindows(display,windows); 8413 flags=ParseGeometry(geometry,&geometry_info); 8414 if ((flags & SigmaValue) == 0) 8415 geometry_info.sigma=1.0; 8416 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8417 geometry_info.rho,geometry_info.sigma,exception); 8418 if (shade_image != (Image *) NULL) 8419 { 8420 *image=DestroyImage(*image); 8421 *image=shade_image; 8422 } 8423 CatchException(exception); 8424 XSetCursorState(display,windows,MagickFalse); 8425 if (windows->image.orphan != MagickFalse) 8426 break; 8427 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8428 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8429 break; 8430 } 8431 case RaiseCommand: 8432 { 8433 static char 8434 bevel_width[MaxTextExtent] = "10"; 8435 8436 /* 8437 Query user for bevel width. 8438 */ 8439 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8440 if (*bevel_width == '\0') 8441 break; 8442 /* 8443 Raise an image. 8444 */ 8445 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8446 exception); 8447 XSetCursorState(display,windows,MagickTrue); 8448 XCheckRefreshWindows(display,windows); 8449 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8450 exception); 8451 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8452 XSetCursorState(display,windows,MagickFalse); 8453 if (windows->image.orphan != MagickFalse) 8454 break; 8455 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8456 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8457 break; 8458 } 8459 case SegmentCommand: 8460 { 8461 static char 8462 threshold[MaxTextExtent] = "1.0x1.5"; 8463 8464 /* 8465 Query user for smoothing threshold. 8466 */ 8467 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8468 threshold); 8469 if (*threshold == '\0') 8470 break; 8471 /* 8472 Segment an image. 8473 */ 8474 XSetCursorState(display,windows,MagickTrue); 8475 XCheckRefreshWindows(display,windows); 8476 flags=ParseGeometry(threshold,&geometry_info); 8477 if ((flags & SigmaValue) == 0) 8478 geometry_info.sigma=1.0; 8479 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8480 geometry_info.sigma,exception); 8481 XSetCursorState(display,windows,MagickFalse); 8482 if (windows->image.orphan != MagickFalse) 8483 break; 8484 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8485 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8486 break; 8487 } 8488 case SepiaToneCommand: 8489 { 8490 double 8491 threshold; 8492 8493 Image 8494 *sepia_image; 8495 8496 static char 8497 factor[MaxTextExtent] = "80%"; 8498 8499 /* 8500 Query user for sepia-tone factor. 8501 */ 8502 (void) XDialogWidget(display,windows,"Sepia Tone", 8503 "Enter the sepia tone factor (0 - 99.9%):",factor); 8504 if (*factor == '\0') 8505 break; 8506 /* 8507 Sepia tone image pixels. 8508 */ 8509 XSetCursorState(display,windows,MagickTrue); 8510 XCheckRefreshWindows(display,windows); 8511 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8512 sepia_image=SepiaToneImage(*image,threshold,exception); 8513 if (sepia_image != (Image *) NULL) 8514 { 8515 *image=DestroyImage(*image); 8516 *image=sepia_image; 8517 } 8518 CatchException(exception); 8519 XSetCursorState(display,windows,MagickFalse); 8520 if (windows->image.orphan != MagickFalse) 8521 break; 8522 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8523 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8524 break; 8525 } 8526 case SolarizeCommand: 8527 { 8528 double 8529 threshold; 8530 8531 static char 8532 factor[MaxTextExtent] = "60%"; 8533 8534 /* 8535 Query user for solarize factor. 8536 */ 8537 (void) XDialogWidget(display,windows,"Solarize", 8538 "Enter the solarize factor (0 - 99.9%):",factor); 8539 if (*factor == '\0') 8540 break; 8541 /* 8542 Solarize image pixels. 8543 */ 8544 XSetCursorState(display,windows,MagickTrue); 8545 XCheckRefreshWindows(display,windows); 8546 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8547 (void) SolarizeImage(*image,threshold,exception); 8548 XSetCursorState(display,windows,MagickFalse); 8549 if (windows->image.orphan != MagickFalse) 8550 break; 8551 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8552 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8553 break; 8554 } 8555 case SwirlCommand: 8556 { 8557 Image 8558 *swirl_image; 8559 8560 static char 8561 degrees[MaxTextExtent] = "60"; 8562 8563 /* 8564 Query user for swirl angle. 8565 */ 8566 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8567 degrees); 8568 if (*degrees == '\0') 8569 break; 8570 /* 8571 Swirl image pixels about the center. 8572 */ 8573 XSetCursorState(display,windows,MagickTrue); 8574 XCheckRefreshWindows(display,windows); 8575 flags=ParseGeometry(degrees,&geometry_info); 8576 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8577 exception); 8578 if (swirl_image != (Image *) NULL) 8579 { 8580 *image=DestroyImage(*image); 8581 *image=swirl_image; 8582 } 8583 CatchException(exception); 8584 XSetCursorState(display,windows,MagickFalse); 8585 if (windows->image.orphan != MagickFalse) 8586 break; 8587 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8588 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8589 break; 8590 } 8591 case ImplodeCommand: 8592 { 8593 Image 8594 *implode_image; 8595 8596 static char 8597 factor[MaxTextExtent] = "0.3"; 8598 8599 /* 8600 Query user for implode factor. 8601 */ 8602 (void) XDialogWidget(display,windows,"Implode", 8603 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8604 if (*factor == '\0') 8605 break; 8606 /* 8607 Implode image pixels about the center. 8608 */ 8609 XSetCursorState(display,windows,MagickTrue); 8610 XCheckRefreshWindows(display,windows); 8611 flags=ParseGeometry(factor,&geometry_info); 8612 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8613 exception); 8614 if (implode_image != (Image *) NULL) 8615 { 8616 *image=DestroyImage(*image); 8617 *image=implode_image; 8618 } 8619 CatchException(exception); 8620 XSetCursorState(display,windows,MagickFalse); 8621 if (windows->image.orphan != MagickFalse) 8622 break; 8623 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8624 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8625 break; 8626 } 8627 case VignetteCommand: 8628 { 8629 Image 8630 *vignette_image; 8631 8632 static char 8633 geometry[MaxTextExtent] = "0x20"; 8634 8635 /* 8636 Query user for the vignette geometry. 8637 */ 8638 (void) XDialogWidget(display,windows,"Vignette", 8639 "Enter the radius, sigma, and x and y offsets:",geometry); 8640 if (*geometry == '\0') 8641 break; 8642 /* 8643 Soften the edges of the image in vignette style 8644 */ 8645 XSetCursorState(display,windows,MagickTrue); 8646 XCheckRefreshWindows(display,windows); 8647 flags=ParseGeometry(geometry,&geometry_info); 8648 if ((flags & SigmaValue) == 0) 8649 geometry_info.sigma=1.0; 8650 if ((flags & XiValue) == 0) 8651 geometry_info.xi=0.1*(*image)->columns; 8652 if ((flags & PsiValue) == 0) 8653 geometry_info.psi=0.1*(*image)->rows; 8654 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8655 0.0,(ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 8656 ceil(geometry_info.psi-0.5),exception); 8657 if (vignette_image != (Image *) NULL) 8658 { 8659 *image=DestroyImage(*image); 8660 *image=vignette_image; 8661 } 8662 CatchException(exception); 8663 XSetCursorState(display,windows,MagickFalse); 8664 if (windows->image.orphan != MagickFalse) 8665 break; 8666 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8667 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8668 break; 8669 } 8670 case WaveCommand: 8671 { 8672 Image 8673 *wave_image; 8674 8675 static char 8676 geometry[MaxTextExtent] = "25x150"; 8677 8678 /* 8679 Query user for the wave geometry. 8680 */ 8681 (void) XDialogWidget(display,windows,"Wave", 8682 "Enter the amplitude and length of the wave:",geometry); 8683 if (*geometry == '\0') 8684 break; 8685 /* 8686 Alter an image along a sine wave. 8687 */ 8688 XSetCursorState(display,windows,MagickTrue); 8689 XCheckRefreshWindows(display,windows); 8690 flags=ParseGeometry(geometry,&geometry_info); 8691 if ((flags & SigmaValue) == 0) 8692 geometry_info.sigma=1.0; 8693 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8694 (*image)->interpolate,exception); 8695 if (wave_image != (Image *) NULL) 8696 { 8697 *image=DestroyImage(*image); 8698 *image=wave_image; 8699 } 8700 CatchException(exception); 8701 XSetCursorState(display,windows,MagickFalse); 8702 if (windows->image.orphan != MagickFalse) 8703 break; 8704 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8705 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8706 break; 8707 } 8708 case OilPaintCommand: 8709 { 8710 Image 8711 *paint_image; 8712 8713 static char 8714 radius[MaxTextExtent] = "0"; 8715 8716 /* 8717 Query user for circular neighborhood radius. 8718 */ 8719 (void) XDialogWidget(display,windows,"Oil Paint", 8720 "Enter the mask radius:",radius); 8721 if (*radius == '\0') 8722 break; 8723 /* 8724 OilPaint image scanlines. 8725 */ 8726 XSetCursorState(display,windows,MagickTrue); 8727 XCheckRefreshWindows(display,windows); 8728 flags=ParseGeometry(radius,&geometry_info); 8729 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8730 exception); 8731 if (paint_image != (Image *) NULL) 8732 { 8733 *image=DestroyImage(*image); 8734 *image=paint_image; 8735 } 8736 CatchException(exception); 8737 XSetCursorState(display,windows,MagickFalse); 8738 if (windows->image.orphan != MagickFalse) 8739 break; 8740 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8741 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8742 break; 8743 } 8744 case CharcoalDrawCommand: 8745 { 8746 Image 8747 *charcoal_image; 8748 8749 static char 8750 radius[MaxTextExtent] = "0x1"; 8751 8752 /* 8753 Query user for charcoal radius. 8754 */ 8755 (void) XDialogWidget(display,windows,"Charcoal Draw", 8756 "Enter the charcoal radius and sigma:",radius); 8757 if (*radius == '\0') 8758 break; 8759 /* 8760 Charcoal the image. 8761 */ 8762 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8763 exception); 8764 XSetCursorState(display,windows,MagickTrue); 8765 XCheckRefreshWindows(display,windows); 8766 flags=ParseGeometry(radius,&geometry_info); 8767 if ((flags & SigmaValue) == 0) 8768 geometry_info.sigma=geometry_info.rho; 8769 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8770 geometry_info.xi,exception); 8771 if (charcoal_image != (Image *) NULL) 8772 { 8773 *image=DestroyImage(*image); 8774 *image=charcoal_image; 8775 } 8776 CatchException(exception); 8777 XSetCursorState(display,windows,MagickFalse); 8778 if (windows->image.orphan != MagickFalse) 8779 break; 8780 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8781 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8782 break; 8783 } 8784 case AnnotateCommand: 8785 { 8786 /* 8787 Annotate the image with text. 8788 */ 8789 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8790 if (status == MagickFalse) 8791 { 8792 XNoticeWidget(display,windows,"Unable to annotate X image", 8793 (*image)->filename); 8794 break; 8795 } 8796 break; 8797 } 8798 case DrawCommand: 8799 { 8800 /* 8801 Draw image. 8802 */ 8803 status=XDrawEditImage(display,resource_info,windows,image,exception); 8804 if (status == MagickFalse) 8805 { 8806 XNoticeWidget(display,windows,"Unable to draw on the X image", 8807 (*image)->filename); 8808 break; 8809 } 8810 break; 8811 } 8812 case ColorCommand: 8813 { 8814 /* 8815 Color edit. 8816 */ 8817 status=XColorEditImage(display,resource_info,windows,image,exception); 8818 if (status == MagickFalse) 8819 { 8820 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8821 (*image)->filename); 8822 break; 8823 } 8824 break; 8825 } 8826 case MatteCommand: 8827 { 8828 /* 8829 Matte edit. 8830 */ 8831 status=XMatteEditImage(display,resource_info,windows,image,exception); 8832 if (status == MagickFalse) 8833 { 8834 XNoticeWidget(display,windows,"Unable to matte edit X image", 8835 (*image)->filename); 8836 break; 8837 } 8838 break; 8839 } 8840 case CompositeCommand: 8841 { 8842 /* 8843 Composite image. 8844 */ 8845 status=XCompositeImage(display,resource_info,windows,*image, 8846 exception); 8847 if (status == MagickFalse) 8848 { 8849 XNoticeWidget(display,windows,"Unable to composite X image", 8850 (*image)->filename); 8851 break; 8852 } 8853 break; 8854 } 8855 case AddBorderCommand: 8856 { 8857 Image 8858 *border_image; 8859 8860 static char 8861 geometry[MaxTextExtent] = "6x6"; 8862 8863 /* 8864 Query user for border color and geometry. 8865 */ 8866 XColorBrowserWidget(display,windows,"Select",color); 8867 if (*color == '\0') 8868 break; 8869 (void) XDialogWidget(display,windows,"Add Border", 8870 "Enter border geometry:",geometry); 8871 if (*geometry == '\0') 8872 break; 8873 /* 8874 Add a border to the image. 8875 */ 8876 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8877 exception); 8878 XSetCursorState(display,windows,MagickTrue); 8879 XCheckRefreshWindows(display,windows); 8880 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8881 exception); 8882 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8883 exception); 8884 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8885 exception); 8886 if (border_image != (Image *) NULL) 8887 { 8888 *image=DestroyImage(*image); 8889 *image=border_image; 8890 } 8891 CatchException(exception); 8892 XSetCursorState(display,windows,MagickFalse); 8893 if (windows->image.orphan != MagickFalse) 8894 break; 8895 windows->image.window_changes.width=(int) (*image)->columns; 8896 windows->image.window_changes.height=(int) (*image)->rows; 8897 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8898 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8899 break; 8900 } 8901 case AddFrameCommand: 8902 { 8903 FrameInfo 8904 frame_info; 8905 8906 Image 8907 *frame_image; 8908 8909 static char 8910 geometry[MaxTextExtent] = "6x6"; 8911 8912 /* 8913 Query user for frame color and geometry. 8914 */ 8915 XColorBrowserWidget(display,windows,"Select",color); 8916 if (*color == '\0') 8917 break; 8918 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8919 geometry); 8920 if (*geometry == '\0') 8921 break; 8922 /* 8923 Surround image with an ornamental border. 8924 */ 8925 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8926 exception); 8927 XSetCursorState(display,windows,MagickTrue); 8928 XCheckRefreshWindows(display,windows); 8929 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8930 exception); 8931 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8932 exception); 8933 frame_info.width=page_geometry.width; 8934 frame_info.height=page_geometry.height; 8935 frame_info.outer_bevel=page_geometry.x; 8936 frame_info.inner_bevel=page_geometry.y; 8937 frame_info.x=(ssize_t) frame_info.width; 8938 frame_info.y=(ssize_t) frame_info.height; 8939 frame_info.width=(*image)->columns+2*frame_info.width; 8940 frame_info.height=(*image)->rows+2*frame_info.height; 8941 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8942 if (frame_image != (Image *) NULL) 8943 { 8944 *image=DestroyImage(*image); 8945 *image=frame_image; 8946 } 8947 CatchException(exception); 8948 XSetCursorState(display,windows,MagickFalse); 8949 if (windows->image.orphan != MagickFalse) 8950 break; 8951 windows->image.window_changes.width=(int) (*image)->columns; 8952 windows->image.window_changes.height=(int) (*image)->rows; 8953 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8954 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8955 break; 8956 } 8957 case CommentCommand: 8958 { 8959 const char 8960 *value; 8961 8962 FILE 8963 *file; 8964 8965 int 8966 unique_file; 8967 8968 /* 8969 Edit image comment. 8970 */ 8971 unique_file=AcquireUniqueFileResource(image_info->filename); 8972 if (unique_file == -1) 8973 XNoticeWidget(display,windows,"Unable to edit image comment", 8974 image_info->filename); 8975 value=GetImageProperty(*image,"comment",exception); 8976 if (value == (char *) NULL) 8977 unique_file=close(unique_file)-1; 8978 else 8979 { 8980 register const char 8981 *p; 8982 8983 file=fdopen(unique_file,"w"); 8984 if (file == (FILE *) NULL) 8985 { 8986 XNoticeWidget(display,windows,"Unable to edit image comment", 8987 image_info->filename); 8988 break; 8989 } 8990 for (p=value; *p != '\0'; p++) 8991 (void) fputc((int) *p,file); 8992 (void) fputc('\n',file); 8993 (void) fclose(file); 8994 } 8995 XSetCursorState(display,windows,MagickTrue); 8996 XCheckRefreshWindows(display,windows); 8997 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8998 exception); 8999 if (status == MagickFalse) 9000 XNoticeWidget(display,windows,"Unable to edit image comment", 9001 (char *) NULL); 9002 else 9003 { 9004 char 9005 *comment; 9006 9007 comment=FileToString(image_info->filename,~0UL,exception); 9008 if (comment != (char *) NULL) 9009 { 9010 (void) SetImageProperty(*image,"comment",comment,exception); 9011 (*image)->taint=MagickTrue; 9012 } 9013 } 9014 (void) RelinquishUniqueFileResource(image_info->filename); 9015 XSetCursorState(display,windows,MagickFalse); 9016 break; 9017 } 9018 case LaunchCommand: 9019 { 9020 /* 9021 Launch program. 9022 */ 9023 XSetCursorState(display,windows,MagickTrue); 9024 XCheckRefreshWindows(display,windows); 9025 (void) AcquireUniqueFilename(filename); 9026 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9027 filename); 9028 status=WriteImage(image_info,*image,exception); 9029 if (status == MagickFalse) 9030 XNoticeWidget(display,windows,"Unable to launch image editor", 9031 (char *) NULL); 9032 else 9033 { 9034 nexus=ReadImage(resource_info->image_info,exception); 9035 CatchException(exception); 9036 XClientMessage(display,windows->image.id,windows->im_protocols, 9037 windows->im_next_image,CurrentTime); 9038 } 9039 (void) RelinquishUniqueFileResource(filename); 9040 XSetCursorState(display,windows,MagickFalse); 9041 break; 9042 } 9043 case RegionofInterestCommand: 9044 { 9045 /* 9046 Apply an image processing technique to a region of interest. 9047 */ 9048 (void) XROIImage(display,resource_info,windows,image,exception); 9049 break; 9050 } 9051 case InfoCommand: 9052 break; 9053 case ZoomCommand: 9054 { 9055 /* 9056 Zoom image. 9057 */ 9058 if (windows->magnify.mapped != MagickFalse) 9059 (void) XRaiseWindow(display,windows->magnify.id); 9060 else 9061 { 9062 /* 9063 Make magnify image. 9064 */ 9065 XSetCursorState(display,windows,MagickTrue); 9066 (void) XMapRaised(display,windows->magnify.id); 9067 XSetCursorState(display,windows,MagickFalse); 9068 } 9069 break; 9070 } 9071 case ShowPreviewCommand: 9072 { 9073 char 9074 **previews; 9075 9076 Image 9077 *preview_image; 9078 9079 static char 9080 preview_type[MaxTextExtent] = "Gamma"; 9081 9082 /* 9083 Select preview type from menu. 9084 */ 9085 previews=GetCommandOptions(MagickPreviewOptions); 9086 if (previews == (char **) NULL) 9087 break; 9088 XListBrowserWidget(display,windows,&windows->widget, 9089 (const char **) previews,"Preview", 9090 "Select an enhancement, effect, or F/X:",preview_type); 9091 previews=DestroyStringList(previews); 9092 if (*preview_type == '\0') 9093 break; 9094 /* 9095 Show image preview. 9096 */ 9097 XSetCursorState(display,windows,MagickTrue); 9098 XCheckRefreshWindows(display,windows); 9099 image_info->preview_type=(PreviewType) 9100 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9101 image_info->group=(ssize_t) windows->image.id; 9102 (void) DeleteImageProperty(*image,"label"); 9103 (void) SetImageProperty(*image,"label","Preview",exception); 9104 (void) AcquireUniqueFilename(filename); 9105 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9106 filename); 9107 status=WriteImage(image_info,*image,exception); 9108 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9109 preview_image=ReadImage(image_info,exception); 9110 (void) RelinquishUniqueFileResource(filename); 9111 if (preview_image == (Image *) NULL) 9112 break; 9113 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9114 filename); 9115 status=WriteImage(image_info,preview_image,exception); 9116 preview_image=DestroyImage(preview_image); 9117 if (status == MagickFalse) 9118 XNoticeWidget(display,windows,"Unable to show image preview", 9119 (*image)->filename); 9120 XDelay(display,1500); 9121 XSetCursorState(display,windows,MagickFalse); 9122 break; 9123 } 9124 case ShowHistogramCommand: 9125 { 9126 Image 9127 *histogram_image; 9128 9129 /* 9130 Show image histogram. 9131 */ 9132 XSetCursorState(display,windows,MagickTrue); 9133 XCheckRefreshWindows(display,windows); 9134 image_info->group=(ssize_t) windows->image.id; 9135 (void) DeleteImageProperty(*image,"label"); 9136 (void) SetImageProperty(*image,"label","Histogram",exception); 9137 (void) AcquireUniqueFilename(filename); 9138 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9139 filename); 9140 status=WriteImage(image_info,*image,exception); 9141 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9142 histogram_image=ReadImage(image_info,exception); 9143 (void) RelinquishUniqueFileResource(filename); 9144 if (histogram_image == (Image *) NULL) 9145 break; 9146 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9147 "show:%s",filename); 9148 status=WriteImage(image_info,histogram_image,exception); 9149 histogram_image=DestroyImage(histogram_image); 9150 if (status == MagickFalse) 9151 XNoticeWidget(display,windows,"Unable to show histogram", 9152 (*image)->filename); 9153 XDelay(display,1500); 9154 XSetCursorState(display,windows,MagickFalse); 9155 break; 9156 } 9157 case ShowMatteCommand: 9158 { 9159 Image 9160 *matte_image; 9161 9162 if ((*image)->matte == MagickFalse) 9163 { 9164 XNoticeWidget(display,windows, 9165 "Image does not have any matte information",(*image)->filename); 9166 break; 9167 } 9168 /* 9169 Show image matte. 9170 */ 9171 XSetCursorState(display,windows,MagickTrue); 9172 XCheckRefreshWindows(display,windows); 9173 image_info->group=(ssize_t) windows->image.id; 9174 (void) DeleteImageProperty(*image,"label"); 9175 (void) SetImageProperty(*image,"label","Matte",exception); 9176 (void) AcquireUniqueFilename(filename); 9177 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9178 filename); 9179 status=WriteImage(image_info,*image,exception); 9180 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9181 matte_image=ReadImage(image_info,exception); 9182 (void) RelinquishUniqueFileResource(filename); 9183 if (matte_image == (Image *) NULL) 9184 break; 9185 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9186 filename); 9187 status=WriteImage(image_info,matte_image,exception); 9188 matte_image=DestroyImage(matte_image); 9189 if (status == MagickFalse) 9190 XNoticeWidget(display,windows,"Unable to show matte", 9191 (*image)->filename); 9192 XDelay(display,1500); 9193 XSetCursorState(display,windows,MagickFalse); 9194 break; 9195 } 9196 case BackgroundCommand: 9197 { 9198 /* 9199 Background image. 9200 */ 9201 status=XBackgroundImage(display,resource_info,windows,image,exception); 9202 if (status == MagickFalse) 9203 break; 9204 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9205 if (nexus != (Image *) NULL) 9206 XClientMessage(display,windows->image.id,windows->im_protocols, 9207 windows->im_next_image,CurrentTime); 9208 break; 9209 } 9210 case SlideShowCommand: 9211 { 9212 static char 9213 delay[MaxTextExtent] = "5"; 9214 9215 /* 9216 Display next image after pausing. 9217 */ 9218 (void) XDialogWidget(display,windows,"Slide Show", 9219 "Pause how many 1/100ths of a second between images:",delay); 9220 if (*delay == '\0') 9221 break; 9222 resource_info->delay=StringToUnsignedLong(delay); 9223 XClientMessage(display,windows->image.id,windows->im_protocols, 9224 windows->im_next_image,CurrentTime); 9225 break; 9226 } 9227 case PreferencesCommand: 9228 { 9229 /* 9230 Set user preferences. 9231 */ 9232 status=XPreferencesWidget(display,resource_info,windows); 9233 if (status == MagickFalse) 9234 break; 9235 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9236 if (nexus != (Image *) NULL) 9237 XClientMessage(display,windows->image.id,windows->im_protocols, 9238 windows->im_next_image,CurrentTime); 9239 break; 9240 } 9241 case HelpCommand: 9242 { 9243 /* 9244 User requested help. 9245 */ 9246 XTextViewWidget(display,resource_info,windows,MagickFalse, 9247 "Help Viewer - Display",DisplayHelp); 9248 break; 9249 } 9250 case BrowseDocumentationCommand: 9251 { 9252 Atom 9253 mozilla_atom; 9254 9255 Window 9256 mozilla_window, 9257 root_window; 9258 9259 /* 9260 Browse the ImageMagick documentation. 9261 */ 9262 root_window=XRootWindow(display,XDefaultScreen(display)); 9263 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9264 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9265 if (mozilla_window != (Window) NULL) 9266 { 9267 char 9268 command[MaxTextExtent], 9269 *url; 9270 9271 /* 9272 Display documentation using Netscape remote control. 9273 */ 9274 url=GetMagickHomeURL(); 9275 (void) FormatLocaleString(command,MaxTextExtent, 9276 "openurl(%s,new-tab)",url); 9277 url=DestroyString(url); 9278 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9279 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9280 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9281 XSetCursorState(display,windows,MagickFalse); 9282 break; 9283 } 9284 XSetCursorState(display,windows,MagickTrue); 9285 XCheckRefreshWindows(display,windows); 9286 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9287 exception); 9288 if (status == MagickFalse) 9289 XNoticeWidget(display,windows,"Unable to browse documentation", 9290 (char *) NULL); 9291 XDelay(display,1500); 9292 XSetCursorState(display,windows,MagickFalse); 9293 break; 9294 } 9295 case VersionCommand: 9296 { 9297 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9298 GetMagickCopyright()); 9299 break; 9300 } 9301 case SaveToUndoBufferCommand: 9302 break; 9303 default: 9304 { 9305 (void) XBell(display,0); 9306 break; 9307 } 9308 } 9309 image_info=DestroyImageInfo(image_info); 9310 return(nexus); 9311} 9312 9313/* 9314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9315% % 9316% % 9317% % 9318+ X M a g n i f y I m a g e % 9319% % 9320% % 9321% % 9322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9323% 9324% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9325% The magnified portion is displayed in a separate window. 9326% 9327% The format of the XMagnifyImage method is: 9328% 9329% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9330% ExceptionInfo *exception) 9331% 9332% A description of each parameter follows: 9333% 9334% o display: Specifies a connection to an X server; returned from 9335% XOpenDisplay. 9336% 9337% o windows: Specifies a pointer to a XWindows structure. 9338% 9339% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9340% the entire image is refreshed. 9341% 9342% o exception: return any errors or warnings in this structure. 9343% 9344*/ 9345static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9346 ExceptionInfo *exception) 9347{ 9348 char 9349 text[MaxTextExtent]; 9350 9351 register int 9352 x, 9353 y; 9354 9355 size_t 9356 state; 9357 9358 /* 9359 Update magnified image until the mouse button is released. 9360 */ 9361 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9362 state=DefaultState; 9363 x=event->xbutton.x; 9364 y=event->xbutton.y; 9365 windows->magnify.x=(int) windows->image.x+x; 9366 windows->magnify.y=(int) windows->image.y+y; 9367 do 9368 { 9369 /* 9370 Map and unmap Info widget as text cursor crosses its boundaries. 9371 */ 9372 if (windows->info.mapped != MagickFalse) 9373 { 9374 if ((x < (int) (windows->info.x+windows->info.width)) && 9375 (y < (int) (windows->info.y+windows->info.height))) 9376 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9377 } 9378 else 9379 if ((x > (int) (windows->info.x+windows->info.width)) || 9380 (y > (int) (windows->info.y+windows->info.height))) 9381 (void) XMapWindow(display,windows->info.id); 9382 if (windows->info.mapped != MagickFalse) 9383 { 9384 /* 9385 Display pointer position. 9386 */ 9387 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9388 windows->magnify.x,windows->magnify.y); 9389 XInfoWidget(display,windows,text); 9390 } 9391 /* 9392 Wait for next event. 9393 */ 9394 XScreenEvent(display,windows,event,exception); 9395 switch (event->type) 9396 { 9397 case ButtonPress: 9398 break; 9399 case ButtonRelease: 9400 { 9401 /* 9402 User has finished magnifying image. 9403 */ 9404 x=event->xbutton.x; 9405 y=event->xbutton.y; 9406 state|=ExitState; 9407 break; 9408 } 9409 case Expose: 9410 break; 9411 case MotionNotify: 9412 { 9413 x=event->xmotion.x; 9414 y=event->xmotion.y; 9415 break; 9416 } 9417 default: 9418 break; 9419 } 9420 /* 9421 Check boundary conditions. 9422 */ 9423 if (x < 0) 9424 x=0; 9425 else 9426 if (x >= (int) windows->image.width) 9427 x=(int) windows->image.width-1; 9428 if (y < 0) 9429 y=0; 9430 else 9431 if (y >= (int) windows->image.height) 9432 y=(int) windows->image.height-1; 9433 } while ((state & ExitState) == 0); 9434 /* 9435 Display magnified image. 9436 */ 9437 XSetCursorState(display,windows,MagickFalse); 9438} 9439 9440/* 9441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9442% % 9443% % 9444% % 9445+ X M a g n i f y W i n d o w C o m m a n d % 9446% % 9447% % 9448% % 9449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9450% 9451% XMagnifyWindowCommand() moves the image within an Magnify window by one 9452% pixel as specified by the key symbol. 9453% 9454% The format of the XMagnifyWindowCommand method is: 9455% 9456% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9457% const MagickStatusType state,const KeySym key_symbol, 9458% ExceptionInfo *exception) 9459% 9460% A description of each parameter follows: 9461% 9462% o display: Specifies a connection to an X server; returned from 9463% XOpenDisplay. 9464% 9465% o windows: Specifies a pointer to a XWindows structure. 9466% 9467% o state: key mask. 9468% 9469% o key_symbol: Specifies a KeySym which indicates which side of the image 9470% to trim. 9471% 9472% o exception: return any errors or warnings in this structure. 9473% 9474*/ 9475static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9476 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9477{ 9478 unsigned int 9479 quantum; 9480 9481 /* 9482 User specified a magnify factor or position. 9483 */ 9484 quantum=1; 9485 if ((state & Mod1Mask) != 0) 9486 quantum=10; 9487 switch ((int) key_symbol) 9488 { 9489 case QuitCommand: 9490 { 9491 (void) XWithdrawWindow(display,windows->magnify.id, 9492 windows->magnify.screen); 9493 break; 9494 } 9495 case XK_Home: 9496 case XK_KP_Home: 9497 { 9498 windows->magnify.x=(int) windows->image.width/2; 9499 windows->magnify.y=(int) windows->image.height/2; 9500 break; 9501 } 9502 case XK_Left: 9503 case XK_KP_Left: 9504 { 9505 if (windows->magnify.x > 0) 9506 windows->magnify.x-=quantum; 9507 break; 9508 } 9509 case XK_Up: 9510 case XK_KP_Up: 9511 { 9512 if (windows->magnify.y > 0) 9513 windows->magnify.y-=quantum; 9514 break; 9515 } 9516 case XK_Right: 9517 case XK_KP_Right: 9518 { 9519 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9520 windows->magnify.x+=quantum; 9521 break; 9522 } 9523 case XK_Down: 9524 case XK_KP_Down: 9525 { 9526 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9527 windows->magnify.y+=quantum; 9528 break; 9529 } 9530 case XK_0: 9531 case XK_1: 9532 case XK_2: 9533 case XK_3: 9534 case XK_4: 9535 case XK_5: 9536 case XK_6: 9537 case XK_7: 9538 case XK_8: 9539 case XK_9: 9540 { 9541 windows->magnify.data=(key_symbol-XK_0); 9542 break; 9543 } 9544 case XK_KP_0: 9545 case XK_KP_1: 9546 case XK_KP_2: 9547 case XK_KP_3: 9548 case XK_KP_4: 9549 case XK_KP_5: 9550 case XK_KP_6: 9551 case XK_KP_7: 9552 case XK_KP_8: 9553 case XK_KP_9: 9554 { 9555 windows->magnify.data=(key_symbol-XK_KP_0); 9556 break; 9557 } 9558 default: 9559 break; 9560 } 9561 XMakeMagnifyImage(display,windows,exception); 9562} 9563 9564/* 9565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9566% % 9567% % 9568% % 9569+ X M a k e P a n I m a g e % 9570% % 9571% % 9572% % 9573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9574% 9575% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9576% icon window. 9577% 9578% The format of the XMakePanImage method is: 9579% 9580% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9581% XWindows *windows,Image *image,ExceptionInfo *exception) 9582% 9583% A description of each parameter follows: 9584% 9585% o display: Specifies a connection to an X server; returned from 9586% XOpenDisplay. 9587% 9588% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9589% 9590% o windows: Specifies a pointer to a XWindows structure. 9591% 9592% o image: the image. 9593% 9594% o exception: return any errors or warnings in this structure. 9595% 9596*/ 9597static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9598 XWindows *windows,Image *image,ExceptionInfo *exception) 9599{ 9600 MagickStatusType 9601 status; 9602 9603 /* 9604 Create and display image for panning icon. 9605 */ 9606 XSetCursorState(display,windows,MagickTrue); 9607 XCheckRefreshWindows(display,windows); 9608 windows->pan.x=(int) windows->image.x; 9609 windows->pan.y=(int) windows->image.y; 9610 status=XMakeImage(display,resource_info,&windows->pan,image, 9611 windows->pan.width,windows->pan.height,exception); 9612 if (status == MagickFalse) 9613 ThrowXWindowFatalException(ResourceLimitError, 9614 "MemoryAllocationFailed",image->filename); 9615 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9616 windows->pan.pixmap); 9617 (void) XClearWindow(display,windows->pan.id); 9618 XDrawPanRectangle(display,windows); 9619 XSetCursorState(display,windows,MagickFalse); 9620} 9621 9622/* 9623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9624% % 9625% % 9626% % 9627+ X M a t t a E d i t I m a g e % 9628% % 9629% % 9630% % 9631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9632% 9633% XMatteEditImage() allows the user to interactively change the Matte channel 9634% of an image. If the image is PseudoClass it is promoted to DirectClass 9635% before the matte information is stored. 9636% 9637% The format of the XMatteEditImage method is: 9638% 9639% MagickBooleanType XMatteEditImage(Display *display, 9640% XResourceInfo *resource_info,XWindows *windows,Image **image, 9641% ExceptionInfo *exception) 9642% 9643% A description of each parameter follows: 9644% 9645% o display: Specifies a connection to an X server; returned from 9646% XOpenDisplay. 9647% 9648% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9649% 9650% o windows: Specifies a pointer to a XWindows structure. 9651% 9652% o image: the image; returned from ReadImage. 9653% 9654% o exception: return any errors or warnings in this structure. 9655% 9656*/ 9657static MagickBooleanType XMatteEditImage(Display *display, 9658 XResourceInfo *resource_info,XWindows *windows,Image **image, 9659 ExceptionInfo *exception) 9660{ 9661 static char 9662 matte[MaxTextExtent] = "0"; 9663 9664 static const char 9665 *MatteEditMenu[] = 9666 { 9667 "Method", 9668 "Border Color", 9669 "Fuzz", 9670 "Matte Value", 9671 "Undo", 9672 "Help", 9673 "Dismiss", 9674 (char *) NULL 9675 }; 9676 9677 static const ModeType 9678 MatteEditCommands[] = 9679 { 9680 MatteEditMethod, 9681 MatteEditBorderCommand, 9682 MatteEditFuzzCommand, 9683 MatteEditValueCommand, 9684 MatteEditUndoCommand, 9685 MatteEditHelpCommand, 9686 MatteEditDismissCommand 9687 }; 9688 9689 static PaintMethod 9690 method = PointMethod; 9691 9692 static XColor 9693 border_color = { 0, 0, 0, 0, 0, 0 }; 9694 9695 char 9696 command[MaxTextExtent], 9697 text[MaxTextExtent]; 9698 9699 Cursor 9700 cursor; 9701 9702 int 9703 entry, 9704 id, 9705 x, 9706 x_offset, 9707 y, 9708 y_offset; 9709 9710 register int 9711 i; 9712 9713 register Quantum 9714 *q; 9715 9716 unsigned int 9717 height, 9718 width; 9719 9720 size_t 9721 state; 9722 9723 XEvent 9724 event; 9725 9726 /* 9727 Map Command widget. 9728 */ 9729 (void) CloneString(&windows->command.name,"Matte Edit"); 9730 windows->command.data=4; 9731 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9732 (void) XMapRaised(display,windows->command.id); 9733 XClientMessage(display,windows->image.id,windows->im_protocols, 9734 windows->im_update_widget,CurrentTime); 9735 /* 9736 Make cursor. 9737 */ 9738 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9739 resource_info->background_color,resource_info->foreground_color); 9740 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9741 /* 9742 Track pointer until button 1 is pressed. 9743 */ 9744 XQueryPosition(display,windows->image.id,&x,&y); 9745 (void) XSelectInput(display,windows->image.id, 9746 windows->image.attributes.event_mask | PointerMotionMask); 9747 state=DefaultState; 9748 do 9749 { 9750 if (windows->info.mapped != MagickFalse) 9751 { 9752 /* 9753 Display pointer position. 9754 */ 9755 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9756 x+windows->image.x,y+windows->image.y); 9757 XInfoWidget(display,windows,text); 9758 } 9759 /* 9760 Wait for next event. 9761 */ 9762 XScreenEvent(display,windows,&event,exception); 9763 if (event.xany.window == windows->command.id) 9764 { 9765 /* 9766 Select a command from the Command widget. 9767 */ 9768 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9769 if (id < 0) 9770 { 9771 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9772 continue; 9773 } 9774 switch (MatteEditCommands[id]) 9775 { 9776 case MatteEditMethod: 9777 { 9778 char 9779 **methods; 9780 9781 /* 9782 Select a method from the pop-up menu. 9783 */ 9784 methods=GetCommandOptions(MagickMethodOptions); 9785 if (methods == (char **) NULL) 9786 break; 9787 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9788 (const char **) methods,command); 9789 if (entry >= 0) 9790 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9791 MagickFalse,methods[entry]); 9792 methods=DestroyStringList(methods); 9793 break; 9794 } 9795 case MatteEditBorderCommand: 9796 { 9797 const char 9798 *ColorMenu[MaxNumberPens]; 9799 9800 int 9801 pen_number; 9802 9803 /* 9804 Initialize menu selections. 9805 */ 9806 for (i=0; i < (int) (MaxNumberPens-2); i++) 9807 ColorMenu[i]=resource_info->pen_colors[i]; 9808 ColorMenu[MaxNumberPens-2]="Browser..."; 9809 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9810 /* 9811 Select a pen color from the pop-up menu. 9812 */ 9813 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9814 (const char **) ColorMenu,command); 9815 if (pen_number < 0) 9816 break; 9817 if (pen_number == (MaxNumberPens-2)) 9818 { 9819 static char 9820 color_name[MaxTextExtent] = "gray"; 9821 9822 /* 9823 Select a pen color from a dialog. 9824 */ 9825 resource_info->pen_colors[pen_number]=color_name; 9826 XColorBrowserWidget(display,windows,"Select",color_name); 9827 if (*color_name == '\0') 9828 break; 9829 } 9830 /* 9831 Set border color. 9832 */ 9833 (void) XParseColor(display,windows->map_info->colormap, 9834 resource_info->pen_colors[pen_number],&border_color); 9835 break; 9836 } 9837 case MatteEditFuzzCommand: 9838 { 9839 static char 9840 fuzz[MaxTextExtent]; 9841 9842 static const char 9843 *FuzzMenu[] = 9844 { 9845 "0%", 9846 "2%", 9847 "5%", 9848 "10%", 9849 "15%", 9850 "Dialog...", 9851 (char *) NULL, 9852 }; 9853 9854 /* 9855 Select a command from the pop-up menu. 9856 */ 9857 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9858 command); 9859 if (entry < 0) 9860 break; 9861 if (entry != 5) 9862 { 9863 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9864 QuantumRange+1.0); 9865 break; 9866 } 9867 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9868 (void) XDialogWidget(display,windows,"Ok", 9869 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9870 if (*fuzz == '\0') 9871 break; 9872 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9873 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9874 1.0); 9875 break; 9876 } 9877 case MatteEditValueCommand: 9878 { 9879 static char 9880 message[MaxTextExtent]; 9881 9882 static const char 9883 *MatteMenu[] = 9884 { 9885 "Opaque", 9886 "Transparent", 9887 "Dialog...", 9888 (char *) NULL, 9889 }; 9890 9891 /* 9892 Select a command from the pop-up menu. 9893 */ 9894 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9895 command); 9896 if (entry < 0) 9897 break; 9898 if (entry != 2) 9899 { 9900 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9901 OpaqueAlpha); 9902 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9903 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9904 (Quantum) TransparentAlpha); 9905 break; 9906 } 9907 (void) FormatLocaleString(message,MaxTextExtent, 9908 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9909 QuantumRange); 9910 (void) XDialogWidget(display,windows,"Matte",message,matte); 9911 if (*matte == '\0') 9912 break; 9913 break; 9914 } 9915 case MatteEditUndoCommand: 9916 { 9917 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9918 image,exception); 9919 break; 9920 } 9921 case MatteEditHelpCommand: 9922 { 9923 XTextViewWidget(display,resource_info,windows,MagickFalse, 9924 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9925 break; 9926 } 9927 case MatteEditDismissCommand: 9928 { 9929 /* 9930 Prematurely exit. 9931 */ 9932 state|=EscapeState; 9933 state|=ExitState; 9934 break; 9935 } 9936 default: 9937 break; 9938 } 9939 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9940 continue; 9941 } 9942 switch (event.type) 9943 { 9944 case ButtonPress: 9945 { 9946 if (event.xbutton.button != Button1) 9947 break; 9948 if ((event.xbutton.window != windows->image.id) && 9949 (event.xbutton.window != windows->magnify.id)) 9950 break; 9951 /* 9952 Update matte data. 9953 */ 9954 x=event.xbutton.x; 9955 y=event.xbutton.y; 9956 (void) XMagickCommand(display,resource_info,windows, 9957 SaveToUndoBufferCommand,image,exception); 9958 state|=UpdateConfigurationState; 9959 break; 9960 } 9961 case ButtonRelease: 9962 { 9963 if (event.xbutton.button != Button1) 9964 break; 9965 if ((event.xbutton.window != windows->image.id) && 9966 (event.xbutton.window != windows->magnify.id)) 9967 break; 9968 /* 9969 Update colormap information. 9970 */ 9971 x=event.xbutton.x; 9972 y=event.xbutton.y; 9973 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9974 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9975 XInfoWidget(display,windows,text); 9976 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9977 state&=(~UpdateConfigurationState); 9978 break; 9979 } 9980 case Expose: 9981 break; 9982 case KeyPress: 9983 { 9984 char 9985 command[MaxTextExtent]; 9986 9987 KeySym 9988 key_symbol; 9989 9990 if (event.xkey.window == windows->magnify.id) 9991 { 9992 Window 9993 window; 9994 9995 window=windows->magnify.id; 9996 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9997 } 9998 if (event.xkey.window != windows->image.id) 9999 break; 10000 /* 10001 Respond to a user key press. 10002 */ 10003 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10004 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10005 switch ((int) key_symbol) 10006 { 10007 case XK_Escape: 10008 case XK_F20: 10009 { 10010 /* 10011 Prematurely exit. 10012 */ 10013 state|=ExitState; 10014 break; 10015 } 10016 case XK_F1: 10017 case XK_Help: 10018 { 10019 XTextViewWidget(display,resource_info,windows,MagickFalse, 10020 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10021 break; 10022 } 10023 default: 10024 { 10025 (void) XBell(display,0); 10026 break; 10027 } 10028 } 10029 break; 10030 } 10031 case MotionNotify: 10032 { 10033 /* 10034 Map and unmap Info widget as cursor crosses its boundaries. 10035 */ 10036 x=event.xmotion.x; 10037 y=event.xmotion.y; 10038 if (windows->info.mapped != MagickFalse) 10039 { 10040 if ((x < (int) (windows->info.x+windows->info.width)) && 10041 (y < (int) (windows->info.y+windows->info.height))) 10042 (void) XWithdrawWindow(display,windows->info.id, 10043 windows->info.screen); 10044 } 10045 else 10046 if ((x > (int) (windows->info.x+windows->info.width)) || 10047 (y > (int) (windows->info.y+windows->info.height))) 10048 (void) XMapWindow(display,windows->info.id); 10049 break; 10050 } 10051 default: 10052 break; 10053 } 10054 if (event.xany.window == windows->magnify.id) 10055 { 10056 x=windows->magnify.x-windows->image.x; 10057 y=windows->magnify.y-windows->image.y; 10058 } 10059 x_offset=x; 10060 y_offset=y; 10061 if ((state & UpdateConfigurationState) != 0) 10062 { 10063 CacheView 10064 *image_view; 10065 10066 int 10067 x, 10068 y; 10069 10070 /* 10071 Matte edit is relative to image configuration. 10072 */ 10073 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10074 MagickTrue); 10075 XPutPixel(windows->image.ximage,x_offset,y_offset, 10076 windows->pixel_info->background_color.pixel); 10077 width=(unsigned int) (*image)->columns; 10078 height=(unsigned int) (*image)->rows; 10079 x=0; 10080 y=0; 10081 if (windows->image.crop_geometry != (char *) NULL) 10082 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10083 &height); 10084 x_offset=(int) (width*(windows->image.x+x_offset)/ 10085 windows->image.ximage->width+x); 10086 y_offset=(int) (height*(windows->image.y+y_offset)/ 10087 windows->image.ximage->height+y); 10088 if ((x_offset < 0) || (y_offset < 0)) 10089 continue; 10090 if ((x_offset >= (int) (*image)->columns) || 10091 (y_offset >= (int) (*image)->rows)) 10092 continue; 10093 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10094 return(MagickFalse); 10095 if ((*image)->matte == MagickFalse) 10096 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10097 image_view=AcquireCacheView(*image); 10098 switch (method) 10099 { 10100 case PointMethod: 10101 default: 10102 { 10103 /* 10104 Update matte information using point algorithm. 10105 */ 10106 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10107 (ssize_t) y_offset,1,1,exception); 10108 if (q == (Quantum *) NULL) 10109 break; 10110 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10111 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10112 break; 10113 } 10114 case ReplaceMethod: 10115 { 10116 PixelInfo 10117 pixel, 10118 target; 10119 10120 /* 10121 Update matte information using replace algorithm. 10122 */ 10123 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10124 x_offset,(ssize_t) y_offset,&target,exception); 10125 for (y=0; y < (int) (*image)->rows; y++) 10126 { 10127 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10128 (*image)->columns,1,exception); 10129 if (q == (Quantum *) NULL) 10130 break; 10131 for (x=0; x < (int) (*image)->columns; x++) 10132 { 10133 GetPixelInfoPixel(*image,q,&pixel); 10134 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10135 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10136 q+=GetPixelChannels(*image); 10137 } 10138 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10139 break; 10140 } 10141 break; 10142 } 10143 case FloodfillMethod: 10144 case FillToBorderMethod: 10145 { 10146 ChannelType 10147 channel_mask; 10148 10149 DrawInfo 10150 *draw_info; 10151 10152 PixelInfo 10153 target; 10154 10155 /* 10156 Update matte information using floodfill algorithm. 10157 */ 10158 (void) GetOneVirtualPixelInfo(*image, 10159 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10160 y_offset,&target,exception); 10161 if (method == FillToBorderMethod) 10162 { 10163 target.red=(MagickRealType) ScaleShortToQuantum( 10164 border_color.red); 10165 target.green=(MagickRealType) ScaleShortToQuantum( 10166 border_color.green); 10167 target.blue=(MagickRealType) ScaleShortToQuantum( 10168 border_color.blue); 10169 } 10170 draw_info=CloneDrawInfo(resource_info->image_info, 10171 (DrawInfo *) NULL); 10172 draw_info->fill.alpha=(MagickRealType) ClampToQuantum( 10173 StringToDouble(matte,(char **) NULL)); 10174 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10175 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10176 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10177 MagickFalse : MagickTrue,exception); 10178 (void) SetPixelChannelMapMask(*image,channel_mask); 10179 draw_info=DestroyDrawInfo(draw_info); 10180 break; 10181 } 10182 case ResetMethod: 10183 { 10184 /* 10185 Update matte information using reset algorithm. 10186 */ 10187 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10188 return(MagickFalse); 10189 for (y=0; y < (int) (*image)->rows; y++) 10190 { 10191 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10192 (*image)->columns,1,exception); 10193 if (q == (Quantum *) NULL) 10194 break; 10195 for (x=0; x < (int) (*image)->columns; x++) 10196 { 10197 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10198 q+=GetPixelChannels(*image); 10199 } 10200 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10201 break; 10202 } 10203 if (StringToLong(matte) == (long) OpaqueAlpha) 10204 (*image)->matte=MagickFalse; 10205 break; 10206 } 10207 } 10208 image_view=DestroyCacheView(image_view); 10209 state&=(~UpdateConfigurationState); 10210 } 10211 } while ((state & ExitState) == 0); 10212 (void) XSelectInput(display,windows->image.id, 10213 windows->image.attributes.event_mask); 10214 XSetCursorState(display,windows,MagickFalse); 10215 (void) XFreeCursor(display,cursor); 10216 return(MagickTrue); 10217} 10218 10219/* 10220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10221% % 10222% % 10223% % 10224+ X O p e n I m a g e % 10225% % 10226% % 10227% % 10228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10229% 10230% XOpenImage() loads an image from a file. 10231% 10232% The format of the XOpenImage method is: 10233% 10234% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10235% XWindows *windows,const unsigned int command) 10236% 10237% A description of each parameter follows: 10238% 10239% o display: Specifies a connection to an X server; returned from 10240% XOpenDisplay. 10241% 10242% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10243% 10244% o windows: Specifies a pointer to a XWindows structure. 10245% 10246% o command: A value other than zero indicates that the file is selected 10247% from the command line argument list. 10248% 10249*/ 10250static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10251 XWindows *windows,const MagickBooleanType command) 10252{ 10253 const MagickInfo 10254 *magick_info; 10255 10256 ExceptionInfo 10257 *exception; 10258 10259 Image 10260 *nexus; 10261 10262 ImageInfo 10263 *image_info; 10264 10265 static char 10266 filename[MaxTextExtent] = "\0"; 10267 10268 /* 10269 Request file name from user. 10270 */ 10271 if (command == MagickFalse) 10272 XFileBrowserWidget(display,windows,"Open",filename); 10273 else 10274 { 10275 char 10276 **filelist, 10277 **files; 10278 10279 int 10280 count, 10281 status; 10282 10283 register int 10284 i, 10285 j; 10286 10287 /* 10288 Select next image from the command line. 10289 */ 10290 status=XGetCommand(display,windows->image.id,&files,&count); 10291 if (status == 0) 10292 { 10293 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10294 return((Image *) NULL); 10295 } 10296 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10297 if (filelist == (char **) NULL) 10298 { 10299 ThrowXWindowFatalException(ResourceLimitError, 10300 "MemoryAllocationFailed","..."); 10301 (void) XFreeStringList(files); 10302 return((Image *) NULL); 10303 } 10304 j=0; 10305 for (i=1; i < count; i++) 10306 if (*files[i] != '-') 10307 filelist[j++]=files[i]; 10308 filelist[j]=(char *) NULL; 10309 XListBrowserWidget(display,windows,&windows->widget, 10310 (const char **) filelist,"Load","Select Image to Load:",filename); 10311 filelist=(char **) RelinquishMagickMemory(filelist); 10312 (void) XFreeStringList(files); 10313 } 10314 if (*filename == '\0') 10315 return((Image *) NULL); 10316 image_info=CloneImageInfo(resource_info->image_info); 10317 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10318 (void *) NULL); 10319 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10320 exception=AcquireExceptionInfo(); 10321 (void) SetImageInfo(image_info,0,exception); 10322 if (LocaleCompare(image_info->magick,"X") == 0) 10323 { 10324 char 10325 seconds[MaxTextExtent]; 10326 10327 /* 10328 User may want to delay the X server screen grab. 10329 */ 10330 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10331 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10332 seconds); 10333 if (*seconds == '\0') 10334 return((Image *) NULL); 10335 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10336 } 10337 magick_info=GetMagickInfo(image_info->magick,exception); 10338 if ((magick_info != (const MagickInfo *) NULL) && 10339 (magick_info->raw != MagickFalse)) 10340 { 10341 char 10342 geometry[MaxTextExtent]; 10343 10344 /* 10345 Request image size from the user. 10346 */ 10347 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10348 if (image_info->size != (char *) NULL) 10349 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10350 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10351 geometry); 10352 (void) CloneString(&image_info->size,geometry); 10353 } 10354 /* 10355 Load the image. 10356 */ 10357 XSetCursorState(display,windows,MagickTrue); 10358 XCheckRefreshWindows(display,windows); 10359 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10360 nexus=ReadImage(image_info,exception); 10361 CatchException(exception); 10362 XSetCursorState(display,windows,MagickFalse); 10363 if (nexus != (Image *) NULL) 10364 XClientMessage(display,windows->image.id,windows->im_protocols, 10365 windows->im_next_image,CurrentTime); 10366 else 10367 { 10368 char 10369 *text, 10370 **textlist; 10371 10372 /* 10373 Unknown image format. 10374 */ 10375 text=FileToString(filename,~0,exception); 10376 if (text == (char *) NULL) 10377 return((Image *) NULL); 10378 textlist=StringToList(text); 10379 if (textlist != (char **) NULL) 10380 { 10381 char 10382 title[MaxTextExtent]; 10383 10384 register int 10385 i; 10386 10387 (void) FormatLocaleString(title,MaxTextExtent, 10388 "Unknown format: %s",filename); 10389 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10390 (const char **) textlist); 10391 for (i=0; textlist[i] != (char *) NULL; i++) 10392 textlist[i]=DestroyString(textlist[i]); 10393 textlist=(char **) RelinquishMagickMemory(textlist); 10394 } 10395 text=DestroyString(text); 10396 } 10397 exception=DestroyExceptionInfo(exception); 10398 image_info=DestroyImageInfo(image_info); 10399 return(nexus); 10400} 10401 10402/* 10403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10404% % 10405% % 10406% % 10407+ X P a n I m a g e % 10408% % 10409% % 10410% % 10411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10412% 10413% XPanImage() pans the image until the mouse button is released. 10414% 10415% The format of the XPanImage method is: 10416% 10417% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10418% ExceptionInfo *exception) 10419% 10420% A description of each parameter follows: 10421% 10422% o display: Specifies a connection to an X server; returned from 10423% XOpenDisplay. 10424% 10425% o windows: Specifies a pointer to a XWindows structure. 10426% 10427% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10428% the entire image is refreshed. 10429% 10430% o exception: return any errors or warnings in this structure. 10431% 10432*/ 10433static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10434 ExceptionInfo *exception) 10435{ 10436 char 10437 text[MaxTextExtent]; 10438 10439 Cursor 10440 cursor; 10441 10442 MagickRealType 10443 x_factor, 10444 y_factor; 10445 10446 RectangleInfo 10447 pan_info; 10448 10449 size_t 10450 state; 10451 10452 /* 10453 Define cursor. 10454 */ 10455 if ((windows->image.ximage->width > (int) windows->image.width) && 10456 (windows->image.ximage->height > (int) windows->image.height)) 10457 cursor=XCreateFontCursor(display,XC_fleur); 10458 else 10459 if (windows->image.ximage->width > (int) windows->image.width) 10460 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10461 else 10462 if (windows->image.ximage->height > (int) windows->image.height) 10463 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10464 else 10465 cursor=XCreateFontCursor(display,XC_arrow); 10466 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10467 /* 10468 Pan image as pointer moves until the mouse button is released. 10469 */ 10470 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10471 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10472 pan_info.width=windows->pan.width*windows->image.width/ 10473 windows->image.ximage->width; 10474 pan_info.height=windows->pan.height*windows->image.height/ 10475 windows->image.ximage->height; 10476 pan_info.x=0; 10477 pan_info.y=0; 10478 state=UpdateConfigurationState; 10479 do 10480 { 10481 switch (event->type) 10482 { 10483 case ButtonPress: 10484 { 10485 /* 10486 User choose an initial pan location. 10487 */ 10488 pan_info.x=(ssize_t) event->xbutton.x; 10489 pan_info.y=(ssize_t) event->xbutton.y; 10490 state|=UpdateConfigurationState; 10491 break; 10492 } 10493 case ButtonRelease: 10494 { 10495 /* 10496 User has finished panning the image. 10497 */ 10498 pan_info.x=(ssize_t) event->xbutton.x; 10499 pan_info.y=(ssize_t) event->xbutton.y; 10500 state|=UpdateConfigurationState | ExitState; 10501 break; 10502 } 10503 case MotionNotify: 10504 { 10505 pan_info.x=(ssize_t) event->xmotion.x; 10506 pan_info.y=(ssize_t) event->xmotion.y; 10507 state|=UpdateConfigurationState; 10508 } 10509 default: 10510 break; 10511 } 10512 if ((state & UpdateConfigurationState) != 0) 10513 { 10514 /* 10515 Check boundary conditions. 10516 */ 10517 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10518 pan_info.x=0; 10519 else 10520 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10521 if (pan_info.x < 0) 10522 pan_info.x=0; 10523 else 10524 if ((int) (pan_info.x+windows->image.width) > 10525 windows->image.ximage->width) 10526 pan_info.x=(ssize_t) 10527 (windows->image.ximage->width-windows->image.width); 10528 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10529 pan_info.y=0; 10530 else 10531 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10532 if (pan_info.y < 0) 10533 pan_info.y=0; 10534 else 10535 if ((int) (pan_info.y+windows->image.height) > 10536 windows->image.ximage->height) 10537 pan_info.y=(ssize_t) 10538 (windows->image.ximage->height-windows->image.height); 10539 if ((windows->image.x != (int) pan_info.x) || 10540 (windows->image.y != (int) pan_info.y)) 10541 { 10542 /* 10543 Display image pan offset. 10544 */ 10545 windows->image.x=(int) pan_info.x; 10546 windows->image.y=(int) pan_info.y; 10547 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10548 windows->image.width,windows->image.height,windows->image.x, 10549 windows->image.y); 10550 XInfoWidget(display,windows,text); 10551 /* 10552 Refresh Image window. 10553 */ 10554 XDrawPanRectangle(display,windows); 10555 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10556 } 10557 state&=(~UpdateConfigurationState); 10558 } 10559 /* 10560 Wait for next event. 10561 */ 10562 if ((state & ExitState) == 0) 10563 XScreenEvent(display,windows,event,exception); 10564 } while ((state & ExitState) == 0); 10565 /* 10566 Restore cursor. 10567 */ 10568 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10569 (void) XFreeCursor(display,cursor); 10570 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10571} 10572 10573/* 10574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10575% % 10576% % 10577% % 10578+ X P a s t e I m a g e % 10579% % 10580% % 10581% % 10582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10583% 10584% XPasteImage() pastes an image previously saved with XCropImage in the X 10585% window image at a location the user chooses with the pointer. 10586% 10587% The format of the XPasteImage method is: 10588% 10589% MagickBooleanType XPasteImage(Display *display, 10590% XResourceInfo *resource_info,XWindows *windows,Image *image, 10591% ExceptionInfo *exception) 10592% 10593% A description of each parameter follows: 10594% 10595% o display: Specifies a connection to an X server; returned from 10596% XOpenDisplay. 10597% 10598% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10599% 10600% o windows: Specifies a pointer to a XWindows structure. 10601% 10602% o image: the image; returned from ReadImage. 10603% 10604% o exception: return any errors or warnings in this structure. 10605% 10606*/ 10607static MagickBooleanType XPasteImage(Display *display, 10608 XResourceInfo *resource_info,XWindows *windows,Image *image, 10609 ExceptionInfo *exception) 10610{ 10611 static const char 10612 *PasteMenu[] = 10613 { 10614 "Operator", 10615 "Help", 10616 "Dismiss", 10617 (char *) NULL 10618 }; 10619 10620 static const ModeType 10621 PasteCommands[] = 10622 { 10623 PasteOperatorsCommand, 10624 PasteHelpCommand, 10625 PasteDismissCommand 10626 }; 10627 10628 static CompositeOperator 10629 compose = CopyCompositeOp; 10630 10631 char 10632 text[MaxTextExtent]; 10633 10634 Cursor 10635 cursor; 10636 10637 Image 10638 *paste_image; 10639 10640 int 10641 entry, 10642 id, 10643 x, 10644 y; 10645 10646 MagickRealType 10647 scale_factor; 10648 10649 RectangleInfo 10650 highlight_info, 10651 paste_info; 10652 10653 unsigned int 10654 height, 10655 width; 10656 10657 size_t 10658 state; 10659 10660 XEvent 10661 event; 10662 10663 /* 10664 Copy image. 10665 */ 10666 if (resource_info->copy_image == (Image *) NULL) 10667 return(MagickFalse); 10668 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10669 /* 10670 Map Command widget. 10671 */ 10672 (void) CloneString(&windows->command.name,"Paste"); 10673 windows->command.data=1; 10674 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10675 (void) XMapRaised(display,windows->command.id); 10676 XClientMessage(display,windows->image.id,windows->im_protocols, 10677 windows->im_update_widget,CurrentTime); 10678 /* 10679 Track pointer until button 1 is pressed. 10680 */ 10681 XSetCursorState(display,windows,MagickFalse); 10682 XQueryPosition(display,windows->image.id,&x,&y); 10683 (void) XSelectInput(display,windows->image.id, 10684 windows->image.attributes.event_mask | PointerMotionMask); 10685 paste_info.x=(ssize_t) windows->image.x+x; 10686 paste_info.y=(ssize_t) windows->image.y+y; 10687 paste_info.width=0; 10688 paste_info.height=0; 10689 cursor=XCreateFontCursor(display,XC_ul_angle); 10690 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10691 state=DefaultState; 10692 do 10693 { 10694 if (windows->info.mapped != MagickFalse) 10695 { 10696 /* 10697 Display pointer position. 10698 */ 10699 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10700 (long) paste_info.x,(long) paste_info.y); 10701 XInfoWidget(display,windows,text); 10702 } 10703 highlight_info=paste_info; 10704 highlight_info.x=paste_info.x-windows->image.x; 10705 highlight_info.y=paste_info.y-windows->image.y; 10706 XHighlightRectangle(display,windows->image.id, 10707 windows->image.highlight_context,&highlight_info); 10708 /* 10709 Wait for next event. 10710 */ 10711 XScreenEvent(display,windows,&event,exception); 10712 XHighlightRectangle(display,windows->image.id, 10713 windows->image.highlight_context,&highlight_info); 10714 if (event.xany.window == windows->command.id) 10715 { 10716 /* 10717 Select a command from the Command widget. 10718 */ 10719 id=XCommandWidget(display,windows,PasteMenu,&event); 10720 if (id < 0) 10721 continue; 10722 switch (PasteCommands[id]) 10723 { 10724 case PasteOperatorsCommand: 10725 { 10726 char 10727 command[MaxTextExtent], 10728 **operators; 10729 10730 /* 10731 Select a command from the pop-up menu. 10732 */ 10733 operators=GetCommandOptions(MagickComposeOptions); 10734 if (operators == (char **) NULL) 10735 break; 10736 entry=XMenuWidget(display,windows,PasteMenu[id], 10737 (const char **) operators,command); 10738 if (entry >= 0) 10739 compose=(CompositeOperator) ParseCommandOption( 10740 MagickComposeOptions,MagickFalse,operators[entry]); 10741 operators=DestroyStringList(operators); 10742 break; 10743 } 10744 case PasteHelpCommand: 10745 { 10746 XTextViewWidget(display,resource_info,windows,MagickFalse, 10747 "Help Viewer - Image Composite",ImagePasteHelp); 10748 break; 10749 } 10750 case PasteDismissCommand: 10751 { 10752 /* 10753 Prematurely exit. 10754 */ 10755 state|=EscapeState; 10756 state|=ExitState; 10757 break; 10758 } 10759 default: 10760 break; 10761 } 10762 continue; 10763 } 10764 switch (event.type) 10765 { 10766 case ButtonPress: 10767 { 10768 if (image->debug != MagickFalse) 10769 (void) LogMagickEvent(X11Event,GetMagickModule(), 10770 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10771 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10772 if (event.xbutton.button != Button1) 10773 break; 10774 if (event.xbutton.window != windows->image.id) 10775 break; 10776 /* 10777 Paste rectangle is relative to image configuration. 10778 */ 10779 width=(unsigned int) image->columns; 10780 height=(unsigned int) image->rows; 10781 x=0; 10782 y=0; 10783 if (windows->image.crop_geometry != (char *) NULL) 10784 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10785 &width,&height); 10786 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10787 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10788 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10789 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10790 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10791 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10792 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10793 break; 10794 } 10795 case ButtonRelease: 10796 { 10797 if (image->debug != MagickFalse) 10798 (void) LogMagickEvent(X11Event,GetMagickModule(), 10799 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10800 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10801 if (event.xbutton.button != Button1) 10802 break; 10803 if (event.xbutton.window != windows->image.id) 10804 break; 10805 if ((paste_info.width != 0) && (paste_info.height != 0)) 10806 { 10807 /* 10808 User has selected the location of the paste image. 10809 */ 10810 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10811 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10812 state|=ExitState; 10813 } 10814 break; 10815 } 10816 case Expose: 10817 break; 10818 case KeyPress: 10819 { 10820 char 10821 command[MaxTextExtent]; 10822 10823 KeySym 10824 key_symbol; 10825 10826 int 10827 length; 10828 10829 if (event.xkey.window != windows->image.id) 10830 break; 10831 /* 10832 Respond to a user key press. 10833 */ 10834 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10835 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10836 *(command+length)='\0'; 10837 if (image->debug != MagickFalse) 10838 (void) LogMagickEvent(X11Event,GetMagickModule(), 10839 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10840 switch ((int) key_symbol) 10841 { 10842 case XK_Escape: 10843 case XK_F20: 10844 { 10845 /* 10846 Prematurely exit. 10847 */ 10848 paste_image=DestroyImage(paste_image); 10849 state|=EscapeState; 10850 state|=ExitState; 10851 break; 10852 } 10853 case XK_F1: 10854 case XK_Help: 10855 { 10856 (void) XSetFunction(display,windows->image.highlight_context, 10857 GXcopy); 10858 XTextViewWidget(display,resource_info,windows,MagickFalse, 10859 "Help Viewer - Image Composite",ImagePasteHelp); 10860 (void) XSetFunction(display,windows->image.highlight_context, 10861 GXinvert); 10862 break; 10863 } 10864 default: 10865 { 10866 (void) XBell(display,0); 10867 break; 10868 } 10869 } 10870 break; 10871 } 10872 case MotionNotify: 10873 { 10874 /* 10875 Map and unmap Info widget as text cursor crosses its boundaries. 10876 */ 10877 x=event.xmotion.x; 10878 y=event.xmotion.y; 10879 if (windows->info.mapped != MagickFalse) 10880 { 10881 if ((x < (int) (windows->info.x+windows->info.width)) && 10882 (y < (int) (windows->info.y+windows->info.height))) 10883 (void) XWithdrawWindow(display,windows->info.id, 10884 windows->info.screen); 10885 } 10886 else 10887 if ((x > (int) (windows->info.x+windows->info.width)) || 10888 (y > (int) (windows->info.y+windows->info.height))) 10889 (void) XMapWindow(display,windows->info.id); 10890 paste_info.x=(ssize_t) windows->image.x+x; 10891 paste_info.y=(ssize_t) windows->image.y+y; 10892 break; 10893 } 10894 default: 10895 { 10896 if (image->debug != MagickFalse) 10897 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10898 event.type); 10899 break; 10900 } 10901 } 10902 } while ((state & ExitState) == 0); 10903 (void) XSelectInput(display,windows->image.id, 10904 windows->image.attributes.event_mask); 10905 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10906 XSetCursorState(display,windows,MagickFalse); 10907 (void) XFreeCursor(display,cursor); 10908 if ((state & EscapeState) != 0) 10909 return(MagickTrue); 10910 /* 10911 Image pasting is relative to image configuration. 10912 */ 10913 XSetCursorState(display,windows,MagickTrue); 10914 XCheckRefreshWindows(display,windows); 10915 width=(unsigned int) image->columns; 10916 height=(unsigned int) image->rows; 10917 x=0; 10918 y=0; 10919 if (windows->image.crop_geometry != (char *) NULL) 10920 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10921 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10922 paste_info.x+=x; 10923 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10924 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10925 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10926 paste_info.y+=y; 10927 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10928 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10929 /* 10930 Paste image with X Image window. 10931 */ 10932 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10933 exception); 10934 paste_image=DestroyImage(paste_image); 10935 XSetCursorState(display,windows,MagickFalse); 10936 /* 10937 Update image colormap. 10938 */ 10939 XConfigureImageColormap(display,resource_info,windows,image,exception); 10940 (void) XConfigureImage(display,resource_info,windows,image,exception); 10941 return(MagickTrue); 10942} 10943 10944/* 10945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10946% % 10947% % 10948% % 10949+ X P r i n t I m a g e % 10950% % 10951% % 10952% % 10953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10954% 10955% XPrintImage() prints an image to a Postscript printer. 10956% 10957% The format of the XPrintImage method is: 10958% 10959% MagickBooleanType XPrintImage(Display *display, 10960% XResourceInfo *resource_info,XWindows *windows,Image *image, 10961% ExceptionInfo *exception) 10962% 10963% A description of each parameter follows: 10964% 10965% o display: Specifies a connection to an X server; returned from 10966% XOpenDisplay. 10967% 10968% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10969% 10970% o windows: Specifies a pointer to a XWindows structure. 10971% 10972% o image: the image. 10973% 10974% o exception: return any errors or warnings in this structure. 10975% 10976*/ 10977static MagickBooleanType XPrintImage(Display *display, 10978 XResourceInfo *resource_info,XWindows *windows,Image *image, 10979 ExceptionInfo *exception) 10980{ 10981 char 10982 filename[MaxTextExtent], 10983 geometry[MaxTextExtent]; 10984 10985 Image 10986 *print_image; 10987 10988 ImageInfo 10989 *image_info; 10990 10991 MagickStatusType 10992 status; 10993 10994 /* 10995 Request Postscript page geometry from user. 10996 */ 10997 image_info=CloneImageInfo(resource_info->image_info); 10998 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10999 if (image_info->page != (char *) NULL) 11000 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11001 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11002 "Select Postscript Page Geometry:",geometry); 11003 if (*geometry == '\0') 11004 return(MagickTrue); 11005 image_info->page=GetPageGeometry(geometry); 11006 /* 11007 Apply image transforms. 11008 */ 11009 XSetCursorState(display,windows,MagickTrue); 11010 XCheckRefreshWindows(display,windows); 11011 print_image=CloneImage(image,0,0,MagickTrue,exception); 11012 if (print_image == (Image *) NULL) 11013 return(MagickFalse); 11014 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11015 windows->image.ximage->width,windows->image.ximage->height); 11016 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11017 exception); 11018 /* 11019 Print image. 11020 */ 11021 (void) AcquireUniqueFilename(filename); 11022 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11023 filename); 11024 status=WriteImage(image_info,print_image,exception); 11025 (void) RelinquishUniqueFileResource(filename); 11026 print_image=DestroyImage(print_image); 11027 image_info=DestroyImageInfo(image_info); 11028 XSetCursorState(display,windows,MagickFalse); 11029 return(status != 0 ? MagickTrue : MagickFalse); 11030} 11031 11032/* 11033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11034% % 11035% % 11036% % 11037+ X R O I I m a g e % 11038% % 11039% % 11040% % 11041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11042% 11043% XROIImage() applies an image processing technique to a region of interest. 11044% 11045% The format of the XROIImage method is: 11046% 11047% MagickBooleanType XROIImage(Display *display, 11048% XResourceInfo *resource_info,XWindows *windows,Image **image, 11049% ExceptionInfo *exception) 11050% 11051% A description of each parameter follows: 11052% 11053% o display: Specifies a connection to an X server; returned from 11054% XOpenDisplay. 11055% 11056% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11057% 11058% o windows: Specifies a pointer to a XWindows structure. 11059% 11060% o image: the image; returned from ReadImage. 11061% 11062% o exception: return any errors or warnings in this structure. 11063% 11064*/ 11065static MagickBooleanType XROIImage(Display *display, 11066 XResourceInfo *resource_info,XWindows *windows,Image **image, 11067 ExceptionInfo *exception) 11068{ 11069#define ApplyMenus 7 11070 11071 static const char 11072 *ROIMenu[] = 11073 { 11074 "Help", 11075 "Dismiss", 11076 (char *) NULL 11077 }, 11078 *ApplyMenu[] = 11079 { 11080 "File", 11081 "Edit", 11082 "Transform", 11083 "Enhance", 11084 "Effects", 11085 "F/X", 11086 "Miscellany", 11087 "Help", 11088 "Dismiss", 11089 (char *) NULL 11090 }, 11091 *FileMenu[] = 11092 { 11093 "Save...", 11094 "Print...", 11095 (char *) NULL 11096 }, 11097 *EditMenu[] = 11098 { 11099 "Undo", 11100 "Redo", 11101 (char *) NULL 11102 }, 11103 *TransformMenu[] = 11104 { 11105 "Flop", 11106 "Flip", 11107 "Rotate Right", 11108 "Rotate Left", 11109 (char *) NULL 11110 }, 11111 *EnhanceMenu[] = 11112 { 11113 "Hue...", 11114 "Saturation...", 11115 "Brightness...", 11116 "Gamma...", 11117 "Spiff", 11118 "Dull", 11119 "Contrast Stretch...", 11120 "Sigmoidal Contrast...", 11121 "Normalize", 11122 "Equalize", 11123 "Negate", 11124 "Grayscale", 11125 "Map...", 11126 "Quantize...", 11127 (char *) NULL 11128 }, 11129 *EffectsMenu[] = 11130 { 11131 "Despeckle", 11132 "Emboss", 11133 "Reduce Noise", 11134 "Add Noise", 11135 "Sharpen...", 11136 "Blur...", 11137 "Threshold...", 11138 "Edge Detect...", 11139 "Spread...", 11140 "Shade...", 11141 "Raise...", 11142 "Segment...", 11143 (char *) NULL 11144 }, 11145 *FXMenu[] = 11146 { 11147 "Solarize...", 11148 "Sepia Tone...", 11149 "Swirl...", 11150 "Implode...", 11151 "Vignette...", 11152 "Wave...", 11153 "Oil Paint...", 11154 "Charcoal Draw...", 11155 (char *) NULL 11156 }, 11157 *MiscellanyMenu[] = 11158 { 11159 "Image Info", 11160 "Zoom Image", 11161 "Show Preview...", 11162 "Show Histogram", 11163 "Show Matte", 11164 (char *) NULL 11165 }; 11166 11167 static const char 11168 **Menus[ApplyMenus] = 11169 { 11170 FileMenu, 11171 EditMenu, 11172 TransformMenu, 11173 EnhanceMenu, 11174 EffectsMenu, 11175 FXMenu, 11176 MiscellanyMenu 11177 }; 11178 11179 static const CommandType 11180 ApplyCommands[] = 11181 { 11182 NullCommand, 11183 NullCommand, 11184 NullCommand, 11185 NullCommand, 11186 NullCommand, 11187 NullCommand, 11188 NullCommand, 11189 HelpCommand, 11190 QuitCommand 11191 }, 11192 FileCommands[] = 11193 { 11194 SaveCommand, 11195 PrintCommand 11196 }, 11197 EditCommands[] = 11198 { 11199 UndoCommand, 11200 RedoCommand 11201 }, 11202 TransformCommands[] = 11203 { 11204 FlopCommand, 11205 FlipCommand, 11206 RotateRightCommand, 11207 RotateLeftCommand 11208 }, 11209 EnhanceCommands[] = 11210 { 11211 HueCommand, 11212 SaturationCommand, 11213 BrightnessCommand, 11214 GammaCommand, 11215 SpiffCommand, 11216 DullCommand, 11217 ContrastStretchCommand, 11218 SigmoidalContrastCommand, 11219 NormalizeCommand, 11220 EqualizeCommand, 11221 NegateCommand, 11222 GrayscaleCommand, 11223 MapCommand, 11224 QuantizeCommand 11225 }, 11226 EffectsCommands[] = 11227 { 11228 DespeckleCommand, 11229 EmbossCommand, 11230 ReduceNoiseCommand, 11231 AddNoiseCommand, 11232 SharpenCommand, 11233 BlurCommand, 11234 EdgeDetectCommand, 11235 SpreadCommand, 11236 ShadeCommand, 11237 RaiseCommand, 11238 SegmentCommand 11239 }, 11240 FXCommands[] = 11241 { 11242 SolarizeCommand, 11243 SepiaToneCommand, 11244 SwirlCommand, 11245 ImplodeCommand, 11246 VignetteCommand, 11247 WaveCommand, 11248 OilPaintCommand, 11249 CharcoalDrawCommand 11250 }, 11251 MiscellanyCommands[] = 11252 { 11253 InfoCommand, 11254 ZoomCommand, 11255 ShowPreviewCommand, 11256 ShowHistogramCommand, 11257 ShowMatteCommand 11258 }, 11259 ROICommands[] = 11260 { 11261 ROIHelpCommand, 11262 ROIDismissCommand 11263 }; 11264 11265 static const CommandType 11266 *Commands[ApplyMenus] = 11267 { 11268 FileCommands, 11269 EditCommands, 11270 TransformCommands, 11271 EnhanceCommands, 11272 EffectsCommands, 11273 FXCommands, 11274 MiscellanyCommands 11275 }; 11276 11277 char 11278 command[MaxTextExtent], 11279 text[MaxTextExtent]; 11280 11281 CommandType 11282 command_type; 11283 11284 Cursor 11285 cursor; 11286 11287 Image 11288 *roi_image; 11289 11290 int 11291 entry, 11292 id, 11293 x, 11294 y; 11295 11296 MagickRealType 11297 scale_factor; 11298 11299 MagickProgressMonitor 11300 progress_monitor; 11301 11302 RectangleInfo 11303 crop_info, 11304 highlight_info, 11305 roi_info; 11306 11307 unsigned int 11308 height, 11309 width; 11310 11311 size_t 11312 state; 11313 11314 XEvent 11315 event; 11316 11317 /* 11318 Map Command widget. 11319 */ 11320 (void) CloneString(&windows->command.name,"ROI"); 11321 windows->command.data=0; 11322 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11323 (void) XMapRaised(display,windows->command.id); 11324 XClientMessage(display,windows->image.id,windows->im_protocols, 11325 windows->im_update_widget,CurrentTime); 11326 /* 11327 Track pointer until button 1 is pressed. 11328 */ 11329 XQueryPosition(display,windows->image.id,&x,&y); 11330 (void) XSelectInput(display,windows->image.id, 11331 windows->image.attributes.event_mask | PointerMotionMask); 11332 roi_info.x=(ssize_t) windows->image.x+x; 11333 roi_info.y=(ssize_t) windows->image.y+y; 11334 roi_info.width=0; 11335 roi_info.height=0; 11336 cursor=XCreateFontCursor(display,XC_fleur); 11337 state=DefaultState; 11338 do 11339 { 11340 if (windows->info.mapped != MagickFalse) 11341 { 11342 /* 11343 Display pointer position. 11344 */ 11345 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11346 (long) roi_info.x,(long) roi_info.y); 11347 XInfoWidget(display,windows,text); 11348 } 11349 /* 11350 Wait for next event. 11351 */ 11352 XScreenEvent(display,windows,&event,exception); 11353 if (event.xany.window == windows->command.id) 11354 { 11355 /* 11356 Select a command from the Command widget. 11357 */ 11358 id=XCommandWidget(display,windows,ROIMenu,&event); 11359 if (id < 0) 11360 continue; 11361 switch (ROICommands[id]) 11362 { 11363 case ROIHelpCommand: 11364 { 11365 XTextViewWidget(display,resource_info,windows,MagickFalse, 11366 "Help Viewer - Region of Interest",ImageROIHelp); 11367 break; 11368 } 11369 case ROIDismissCommand: 11370 { 11371 /* 11372 Prematurely exit. 11373 */ 11374 state|=EscapeState; 11375 state|=ExitState; 11376 break; 11377 } 11378 default: 11379 break; 11380 } 11381 continue; 11382 } 11383 switch (event.type) 11384 { 11385 case ButtonPress: 11386 { 11387 if (event.xbutton.button != Button1) 11388 break; 11389 if (event.xbutton.window != windows->image.id) 11390 break; 11391 /* 11392 Note first corner of region of interest rectangle-- exit loop. 11393 */ 11394 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11395 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11396 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11397 state|=ExitState; 11398 break; 11399 } 11400 case ButtonRelease: 11401 break; 11402 case Expose: 11403 break; 11404 case KeyPress: 11405 { 11406 KeySym 11407 key_symbol; 11408 11409 if (event.xkey.window != windows->image.id) 11410 break; 11411 /* 11412 Respond to a user key press. 11413 */ 11414 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11415 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11416 switch ((int) key_symbol) 11417 { 11418 case XK_Escape: 11419 case XK_F20: 11420 { 11421 /* 11422 Prematurely exit. 11423 */ 11424 state|=EscapeState; 11425 state|=ExitState; 11426 break; 11427 } 11428 case XK_F1: 11429 case XK_Help: 11430 { 11431 XTextViewWidget(display,resource_info,windows,MagickFalse, 11432 "Help Viewer - Region of Interest",ImageROIHelp); 11433 break; 11434 } 11435 default: 11436 { 11437 (void) XBell(display,0); 11438 break; 11439 } 11440 } 11441 break; 11442 } 11443 case MotionNotify: 11444 { 11445 /* 11446 Map and unmap Info widget as text cursor crosses its boundaries. 11447 */ 11448 x=event.xmotion.x; 11449 y=event.xmotion.y; 11450 if (windows->info.mapped != MagickFalse) 11451 { 11452 if ((x < (int) (windows->info.x+windows->info.width)) && 11453 (y < (int) (windows->info.y+windows->info.height))) 11454 (void) XWithdrawWindow(display,windows->info.id, 11455 windows->info.screen); 11456 } 11457 else 11458 if ((x > (int) (windows->info.x+windows->info.width)) || 11459 (y > (int) (windows->info.y+windows->info.height))) 11460 (void) XMapWindow(display,windows->info.id); 11461 roi_info.x=(ssize_t) windows->image.x+x; 11462 roi_info.y=(ssize_t) windows->image.y+y; 11463 break; 11464 } 11465 default: 11466 break; 11467 } 11468 } while ((state & ExitState) == 0); 11469 (void) XSelectInput(display,windows->image.id, 11470 windows->image.attributes.event_mask); 11471 if ((state & EscapeState) != 0) 11472 { 11473 /* 11474 User want to exit without region of interest. 11475 */ 11476 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11477 (void) XFreeCursor(display,cursor); 11478 return(MagickTrue); 11479 } 11480 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11481 do 11482 { 11483 /* 11484 Size rectangle as pointer moves until the mouse button is released. 11485 */ 11486 x=(int) roi_info.x; 11487 y=(int) roi_info.y; 11488 roi_info.width=0; 11489 roi_info.height=0; 11490 state=DefaultState; 11491 do 11492 { 11493 highlight_info=roi_info; 11494 highlight_info.x=roi_info.x-windows->image.x; 11495 highlight_info.y=roi_info.y-windows->image.y; 11496 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11497 { 11498 /* 11499 Display info and draw region of interest rectangle. 11500 */ 11501 if (windows->info.mapped == MagickFalse) 11502 (void) XMapWindow(display,windows->info.id); 11503 (void) FormatLocaleString(text,MaxTextExtent, 11504 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11505 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11506 XInfoWidget(display,windows,text); 11507 XHighlightRectangle(display,windows->image.id, 11508 windows->image.highlight_context,&highlight_info); 11509 } 11510 else 11511 if (windows->info.mapped != MagickFalse) 11512 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11513 /* 11514 Wait for next event. 11515 */ 11516 XScreenEvent(display,windows,&event,exception); 11517 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11518 XHighlightRectangle(display,windows->image.id, 11519 windows->image.highlight_context,&highlight_info); 11520 switch (event.type) 11521 { 11522 case ButtonPress: 11523 { 11524 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11525 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11526 break; 11527 } 11528 case ButtonRelease: 11529 { 11530 /* 11531 User has committed to region of interest rectangle. 11532 */ 11533 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11534 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11535 XSetCursorState(display,windows,MagickFalse); 11536 state|=ExitState; 11537 if (LocaleCompare(windows->command.name,"Apply") == 0) 11538 break; 11539 (void) CloneString(&windows->command.name,"Apply"); 11540 windows->command.data=ApplyMenus; 11541 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11542 break; 11543 } 11544 case Expose: 11545 break; 11546 case MotionNotify: 11547 { 11548 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11549 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11550 } 11551 default: 11552 break; 11553 } 11554 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11555 ((state & ExitState) != 0)) 11556 { 11557 /* 11558 Check boundary conditions. 11559 */ 11560 if (roi_info.x < 0) 11561 roi_info.x=0; 11562 else 11563 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11564 roi_info.x=(ssize_t) windows->image.ximage->width; 11565 if ((int) roi_info.x < x) 11566 roi_info.width=(unsigned int) (x-roi_info.x); 11567 else 11568 { 11569 roi_info.width=(unsigned int) (roi_info.x-x); 11570 roi_info.x=(ssize_t) x; 11571 } 11572 if (roi_info.y < 0) 11573 roi_info.y=0; 11574 else 11575 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11576 roi_info.y=(ssize_t) windows->image.ximage->height; 11577 if ((int) roi_info.y < y) 11578 roi_info.height=(unsigned int) (y-roi_info.y); 11579 else 11580 { 11581 roi_info.height=(unsigned int) (roi_info.y-y); 11582 roi_info.y=(ssize_t) y; 11583 } 11584 } 11585 } while ((state & ExitState) == 0); 11586 /* 11587 Wait for user to grab a corner of the rectangle or press return. 11588 */ 11589 state=DefaultState; 11590 command_type=NullCommand; 11591 (void) XMapWindow(display,windows->info.id); 11592 do 11593 { 11594 if (windows->info.mapped != MagickFalse) 11595 { 11596 /* 11597 Display pointer position. 11598 */ 11599 (void) FormatLocaleString(text,MaxTextExtent, 11600 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11601 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11602 XInfoWidget(display,windows,text); 11603 } 11604 highlight_info=roi_info; 11605 highlight_info.x=roi_info.x-windows->image.x; 11606 highlight_info.y=roi_info.y-windows->image.y; 11607 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11608 { 11609 state|=EscapeState; 11610 state|=ExitState; 11611 break; 11612 } 11613 if ((state & UpdateRegionState) != 0) 11614 { 11615 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11616 switch (command_type) 11617 { 11618 case UndoCommand: 11619 case RedoCommand: 11620 { 11621 (void) XMagickCommand(display,resource_info,windows,command_type, 11622 image,exception); 11623 break; 11624 } 11625 default: 11626 { 11627 /* 11628 Region of interest is relative to image configuration. 11629 */ 11630 progress_monitor=SetImageProgressMonitor(*image, 11631 (MagickProgressMonitor) NULL,(*image)->client_data); 11632 crop_info=roi_info; 11633 width=(unsigned int) (*image)->columns; 11634 height=(unsigned int) (*image)->rows; 11635 x=0; 11636 y=0; 11637 if (windows->image.crop_geometry != (char *) NULL) 11638 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11639 &width,&height); 11640 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11641 crop_info.x+=x; 11642 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11643 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11644 scale_factor=(MagickRealType) 11645 height/windows->image.ximage->height; 11646 crop_info.y+=y; 11647 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11648 crop_info.height=(unsigned int) 11649 (scale_factor*crop_info.height+0.5); 11650 roi_image=CropImage(*image,&crop_info,exception); 11651 (void) SetImageProgressMonitor(*image,progress_monitor, 11652 (*image)->client_data); 11653 if (roi_image == (Image *) NULL) 11654 continue; 11655 /* 11656 Apply image processing technique to the region of interest. 11657 */ 11658 windows->image.orphan=MagickTrue; 11659 (void) XMagickCommand(display,resource_info,windows,command_type, 11660 &roi_image,exception); 11661 progress_monitor=SetImageProgressMonitor(*image, 11662 (MagickProgressMonitor) NULL,(*image)->client_data); 11663 (void) XMagickCommand(display,resource_info,windows, 11664 SaveToUndoBufferCommand,image,exception); 11665 windows->image.orphan=MagickFalse; 11666 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11667 crop_info.x,crop_info.y,exception); 11668 roi_image=DestroyImage(roi_image); 11669 (void) SetImageProgressMonitor(*image,progress_monitor, 11670 (*image)->client_data); 11671 break; 11672 } 11673 } 11674 if (command_type != InfoCommand) 11675 { 11676 XConfigureImageColormap(display,resource_info,windows,*image, 11677 exception); 11678 (void) XConfigureImage(display,resource_info,windows,*image, 11679 exception); 11680 } 11681 XCheckRefreshWindows(display,windows); 11682 XInfoWidget(display,windows,text); 11683 (void) XSetFunction(display,windows->image.highlight_context, 11684 GXinvert); 11685 state&=(~UpdateRegionState); 11686 } 11687 XHighlightRectangle(display,windows->image.id, 11688 windows->image.highlight_context,&highlight_info); 11689 XScreenEvent(display,windows,&event,exception); 11690 if (event.xany.window == windows->command.id) 11691 { 11692 /* 11693 Select a command from the Command widget. 11694 */ 11695 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11696 command_type=NullCommand; 11697 id=XCommandWidget(display,windows,ApplyMenu,&event); 11698 if (id >= 0) 11699 { 11700 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11701 command_type=ApplyCommands[id]; 11702 if (id < ApplyMenus) 11703 { 11704 /* 11705 Select a command from a pop-up menu. 11706 */ 11707 entry=XMenuWidget(display,windows,ApplyMenu[id], 11708 (const char **) Menus[id],command); 11709 if (entry >= 0) 11710 { 11711 (void) CopyMagickString(command,Menus[id][entry], 11712 MaxTextExtent); 11713 command_type=Commands[id][entry]; 11714 } 11715 } 11716 } 11717 (void) XSetFunction(display,windows->image.highlight_context, 11718 GXinvert); 11719 XHighlightRectangle(display,windows->image.id, 11720 windows->image.highlight_context,&highlight_info); 11721 if (command_type == HelpCommand) 11722 { 11723 (void) XSetFunction(display,windows->image.highlight_context, 11724 GXcopy); 11725 XTextViewWidget(display,resource_info,windows,MagickFalse, 11726 "Help Viewer - Region of Interest",ImageROIHelp); 11727 (void) XSetFunction(display,windows->image.highlight_context, 11728 GXinvert); 11729 continue; 11730 } 11731 if (command_type == QuitCommand) 11732 { 11733 /* 11734 exit. 11735 */ 11736 state|=EscapeState; 11737 state|=ExitState; 11738 continue; 11739 } 11740 if (command_type != NullCommand) 11741 state|=UpdateRegionState; 11742 continue; 11743 } 11744 XHighlightRectangle(display,windows->image.id, 11745 windows->image.highlight_context,&highlight_info); 11746 switch (event.type) 11747 { 11748 case ButtonPress: 11749 { 11750 x=windows->image.x; 11751 y=windows->image.y; 11752 if (event.xbutton.button != Button1) 11753 break; 11754 if (event.xbutton.window != windows->image.id) 11755 break; 11756 x=windows->image.x+event.xbutton.x; 11757 y=windows->image.y+event.xbutton.y; 11758 if ((x < (int) (roi_info.x+RoiDelta)) && 11759 (x > (int) (roi_info.x-RoiDelta)) && 11760 (y < (int) (roi_info.y+RoiDelta)) && 11761 (y > (int) (roi_info.y-RoiDelta))) 11762 { 11763 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11764 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11765 state|=UpdateConfigurationState; 11766 break; 11767 } 11768 if ((x < (int) (roi_info.x+RoiDelta)) && 11769 (x > (int) (roi_info.x-RoiDelta)) && 11770 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11771 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11772 { 11773 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11774 state|=UpdateConfigurationState; 11775 break; 11776 } 11777 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11778 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11779 (y < (int) (roi_info.y+RoiDelta)) && 11780 (y > (int) (roi_info.y-RoiDelta))) 11781 { 11782 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11783 state|=UpdateConfigurationState; 11784 break; 11785 } 11786 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11787 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11788 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11789 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11790 { 11791 state|=UpdateConfigurationState; 11792 break; 11793 } 11794 } 11795 case ButtonRelease: 11796 { 11797 if (event.xbutton.window == windows->pan.id) 11798 if ((highlight_info.x != crop_info.x-windows->image.x) || 11799 (highlight_info.y != crop_info.y-windows->image.y)) 11800 XHighlightRectangle(display,windows->image.id, 11801 windows->image.highlight_context,&highlight_info); 11802 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11803 event.xbutton.time); 11804 break; 11805 } 11806 case Expose: 11807 { 11808 if (event.xexpose.window == windows->image.id) 11809 if (event.xexpose.count == 0) 11810 { 11811 event.xexpose.x=(int) highlight_info.x; 11812 event.xexpose.y=(int) highlight_info.y; 11813 event.xexpose.width=(int) highlight_info.width; 11814 event.xexpose.height=(int) highlight_info.height; 11815 XRefreshWindow(display,&windows->image,&event); 11816 } 11817 if (event.xexpose.window == windows->info.id) 11818 if (event.xexpose.count == 0) 11819 XInfoWidget(display,windows,text); 11820 break; 11821 } 11822 case KeyPress: 11823 { 11824 KeySym 11825 key_symbol; 11826 11827 if (event.xkey.window != windows->image.id) 11828 break; 11829 /* 11830 Respond to a user key press. 11831 */ 11832 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11833 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11834 switch ((int) key_symbol) 11835 { 11836 case XK_Shift_L: 11837 case XK_Shift_R: 11838 break; 11839 case XK_Escape: 11840 case XK_F20: 11841 state|=EscapeState; 11842 case XK_Return: 11843 { 11844 state|=ExitState; 11845 break; 11846 } 11847 case XK_Home: 11848 case XK_KP_Home: 11849 { 11850 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11851 roi_info.y=(ssize_t) (windows->image.height/2L- 11852 roi_info.height/2L); 11853 break; 11854 } 11855 case XK_Left: 11856 case XK_KP_Left: 11857 { 11858 roi_info.x--; 11859 break; 11860 } 11861 case XK_Up: 11862 case XK_KP_Up: 11863 case XK_Next: 11864 { 11865 roi_info.y--; 11866 break; 11867 } 11868 case XK_Right: 11869 case XK_KP_Right: 11870 { 11871 roi_info.x++; 11872 break; 11873 } 11874 case XK_Prior: 11875 case XK_Down: 11876 case XK_KP_Down: 11877 { 11878 roi_info.y++; 11879 break; 11880 } 11881 case XK_F1: 11882 case XK_Help: 11883 { 11884 (void) XSetFunction(display,windows->image.highlight_context, 11885 GXcopy); 11886 XTextViewWidget(display,resource_info,windows,MagickFalse, 11887 "Help Viewer - Region of Interest",ImageROIHelp); 11888 (void) XSetFunction(display,windows->image.highlight_context, 11889 GXinvert); 11890 break; 11891 } 11892 default: 11893 { 11894 command_type=XImageWindowCommand(display,resource_info,windows, 11895 event.xkey.state,key_symbol,image,exception); 11896 if (command_type != NullCommand) 11897 state|=UpdateRegionState; 11898 break; 11899 } 11900 } 11901 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11902 event.xkey.time); 11903 break; 11904 } 11905 case KeyRelease: 11906 break; 11907 case MotionNotify: 11908 { 11909 if (event.xbutton.window != windows->image.id) 11910 break; 11911 /* 11912 Map and unmap Info widget as text cursor crosses its boundaries. 11913 */ 11914 x=event.xmotion.x; 11915 y=event.xmotion.y; 11916 if (windows->info.mapped != MagickFalse) 11917 { 11918 if ((x < (int) (windows->info.x+windows->info.width)) && 11919 (y < (int) (windows->info.y+windows->info.height))) 11920 (void) XWithdrawWindow(display,windows->info.id, 11921 windows->info.screen); 11922 } 11923 else 11924 if ((x > (int) (windows->info.x+windows->info.width)) || 11925 (y > (int) (windows->info.y+windows->info.height))) 11926 (void) XMapWindow(display,windows->info.id); 11927 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11928 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11929 break; 11930 } 11931 case SelectionRequest: 11932 { 11933 XSelectionEvent 11934 notify; 11935 11936 XSelectionRequestEvent 11937 *request; 11938 11939 /* 11940 Set primary selection. 11941 */ 11942 (void) FormatLocaleString(text,MaxTextExtent, 11943 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11944 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11945 request=(&(event.xselectionrequest)); 11946 (void) XChangeProperty(request->display,request->requestor, 11947 request->property,request->target,8,PropModeReplace, 11948 (unsigned char *) text,(int) strlen(text)); 11949 notify.type=SelectionNotify; 11950 notify.display=request->display; 11951 notify.requestor=request->requestor; 11952 notify.selection=request->selection; 11953 notify.target=request->target; 11954 notify.time=request->time; 11955 if (request->property == None) 11956 notify.property=request->target; 11957 else 11958 notify.property=request->property; 11959 (void) XSendEvent(request->display,request->requestor,False,0, 11960 (XEvent *) ¬ify); 11961 } 11962 default: 11963 break; 11964 } 11965 if ((state & UpdateConfigurationState) != 0) 11966 { 11967 (void) XPutBackEvent(display,&event); 11968 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11969 break; 11970 } 11971 } while ((state & ExitState) == 0); 11972 } while ((state & ExitState) == 0); 11973 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11974 XSetCursorState(display,windows,MagickFalse); 11975 if ((state & EscapeState) != 0) 11976 return(MagickTrue); 11977 return(MagickTrue); 11978} 11979 11980/* 11981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11982% % 11983% % 11984% % 11985+ X R o t a t e I m a g e % 11986% % 11987% % 11988% % 11989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11990% 11991% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11992% rotation angle is computed from the slope of a line drawn by the user. 11993% 11994% The format of the XRotateImage method is: 11995% 11996% MagickBooleanType XRotateImage(Display *display, 11997% XResourceInfo *resource_info,XWindows *windows,double degrees, 11998% Image **image,ExceptionInfo *exception) 11999% 12000% A description of each parameter follows: 12001% 12002% o display: Specifies a connection to an X server; returned from 12003% XOpenDisplay. 12004% 12005% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12006% 12007% o windows: Specifies a pointer to a XWindows structure. 12008% 12009% o degrees: Specifies the number of degrees to rotate the image. 12010% 12011% o image: the image. 12012% 12013% o exception: return any errors or warnings in this structure. 12014% 12015*/ 12016static MagickBooleanType XRotateImage(Display *display, 12017 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12018 ExceptionInfo *exception) 12019{ 12020 static const char 12021 *RotateMenu[] = 12022 { 12023 "Pixel Color", 12024 "Direction", 12025 "Help", 12026 "Dismiss", 12027 (char *) NULL 12028 }; 12029 12030 static ModeType 12031 direction = HorizontalRotateCommand; 12032 12033 static const ModeType 12034 DirectionCommands[] = 12035 { 12036 HorizontalRotateCommand, 12037 VerticalRotateCommand 12038 }, 12039 RotateCommands[] = 12040 { 12041 RotateColorCommand, 12042 RotateDirectionCommand, 12043 RotateHelpCommand, 12044 RotateDismissCommand 12045 }; 12046 12047 static unsigned int 12048 pen_id = 0; 12049 12050 char 12051 command[MaxTextExtent], 12052 text[MaxTextExtent]; 12053 12054 Image 12055 *rotate_image; 12056 12057 int 12058 id, 12059 x, 12060 y; 12061 12062 MagickRealType 12063 normalized_degrees; 12064 12065 register int 12066 i; 12067 12068 unsigned int 12069 height, 12070 rotations, 12071 width; 12072 12073 if (degrees == 0.0) 12074 { 12075 unsigned int 12076 distance; 12077 12078 size_t 12079 state; 12080 12081 XEvent 12082 event; 12083 12084 XSegment 12085 rotate_info; 12086 12087 /* 12088 Map Command widget. 12089 */ 12090 (void) CloneString(&windows->command.name,"Rotate"); 12091 windows->command.data=2; 12092 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12093 (void) XMapRaised(display,windows->command.id); 12094 XClientMessage(display,windows->image.id,windows->im_protocols, 12095 windows->im_update_widget,CurrentTime); 12096 /* 12097 Wait for first button press. 12098 */ 12099 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12100 XQueryPosition(display,windows->image.id,&x,&y); 12101 rotate_info.x1=x; 12102 rotate_info.y1=y; 12103 rotate_info.x2=x; 12104 rotate_info.y2=y; 12105 state=DefaultState; 12106 do 12107 { 12108 XHighlightLine(display,windows->image.id, 12109 windows->image.highlight_context,&rotate_info); 12110 /* 12111 Wait for next event. 12112 */ 12113 XScreenEvent(display,windows,&event,exception); 12114 XHighlightLine(display,windows->image.id, 12115 windows->image.highlight_context,&rotate_info); 12116 if (event.xany.window == windows->command.id) 12117 { 12118 /* 12119 Select a command from the Command widget. 12120 */ 12121 id=XCommandWidget(display,windows,RotateMenu,&event); 12122 if (id < 0) 12123 continue; 12124 (void) XSetFunction(display,windows->image.highlight_context, 12125 GXcopy); 12126 switch (RotateCommands[id]) 12127 { 12128 case RotateColorCommand: 12129 { 12130 const char 12131 *ColorMenu[MaxNumberPens]; 12132 12133 int 12134 pen_number; 12135 12136 XColor 12137 color; 12138 12139 /* 12140 Initialize menu selections. 12141 */ 12142 for (i=0; i < (int) (MaxNumberPens-2); i++) 12143 ColorMenu[i]=resource_info->pen_colors[i]; 12144 ColorMenu[MaxNumberPens-2]="Browser..."; 12145 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12146 /* 12147 Select a pen color from the pop-up menu. 12148 */ 12149 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12150 (const char **) ColorMenu,command); 12151 if (pen_number < 0) 12152 break; 12153 if (pen_number == (MaxNumberPens-2)) 12154 { 12155 static char 12156 color_name[MaxTextExtent] = "gray"; 12157 12158 /* 12159 Select a pen color from a dialog. 12160 */ 12161 resource_info->pen_colors[pen_number]=color_name; 12162 XColorBrowserWidget(display,windows,"Select",color_name); 12163 if (*color_name == '\0') 12164 break; 12165 } 12166 /* 12167 Set pen color. 12168 */ 12169 (void) XParseColor(display,windows->map_info->colormap, 12170 resource_info->pen_colors[pen_number],&color); 12171 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12172 (unsigned int) MaxColors,&color); 12173 windows->pixel_info->pen_colors[pen_number]=color; 12174 pen_id=(unsigned int) pen_number; 12175 break; 12176 } 12177 case RotateDirectionCommand: 12178 { 12179 static const char 12180 *Directions[] = 12181 { 12182 "horizontal", 12183 "vertical", 12184 (char *) NULL, 12185 }; 12186 12187 /* 12188 Select a command from the pop-up menu. 12189 */ 12190 id=XMenuWidget(display,windows,RotateMenu[id], 12191 Directions,command); 12192 if (id >= 0) 12193 direction=DirectionCommands[id]; 12194 break; 12195 } 12196 case RotateHelpCommand: 12197 { 12198 XTextViewWidget(display,resource_info,windows,MagickFalse, 12199 "Help Viewer - Image Rotation",ImageRotateHelp); 12200 break; 12201 } 12202 case RotateDismissCommand: 12203 { 12204 /* 12205 Prematurely exit. 12206 */ 12207 state|=EscapeState; 12208 state|=ExitState; 12209 break; 12210 } 12211 default: 12212 break; 12213 } 12214 (void) XSetFunction(display,windows->image.highlight_context, 12215 GXinvert); 12216 continue; 12217 } 12218 switch (event.type) 12219 { 12220 case ButtonPress: 12221 { 12222 if (event.xbutton.button != Button1) 12223 break; 12224 if (event.xbutton.window != windows->image.id) 12225 break; 12226 /* 12227 exit loop. 12228 */ 12229 (void) XSetFunction(display,windows->image.highlight_context, 12230 GXcopy); 12231 rotate_info.x1=event.xbutton.x; 12232 rotate_info.y1=event.xbutton.y; 12233 state|=ExitState; 12234 break; 12235 } 12236 case ButtonRelease: 12237 break; 12238 case Expose: 12239 break; 12240 case KeyPress: 12241 { 12242 char 12243 command[MaxTextExtent]; 12244 12245 KeySym 12246 key_symbol; 12247 12248 if (event.xkey.window != windows->image.id) 12249 break; 12250 /* 12251 Respond to a user key press. 12252 */ 12253 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12254 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12255 switch ((int) key_symbol) 12256 { 12257 case XK_Escape: 12258 case XK_F20: 12259 { 12260 /* 12261 Prematurely exit. 12262 */ 12263 state|=EscapeState; 12264 state|=ExitState; 12265 break; 12266 } 12267 case XK_F1: 12268 case XK_Help: 12269 { 12270 (void) XSetFunction(display,windows->image.highlight_context, 12271 GXcopy); 12272 XTextViewWidget(display,resource_info,windows,MagickFalse, 12273 "Help Viewer - Image Rotation",ImageRotateHelp); 12274 (void) XSetFunction(display,windows->image.highlight_context, 12275 GXinvert); 12276 break; 12277 } 12278 default: 12279 { 12280 (void) XBell(display,0); 12281 break; 12282 } 12283 } 12284 break; 12285 } 12286 case MotionNotify: 12287 { 12288 rotate_info.x1=event.xmotion.x; 12289 rotate_info.y1=event.xmotion.y; 12290 } 12291 } 12292 rotate_info.x2=rotate_info.x1; 12293 rotate_info.y2=rotate_info.y1; 12294 if (direction == HorizontalRotateCommand) 12295 rotate_info.x2+=32; 12296 else 12297 rotate_info.y2-=32; 12298 } while ((state & ExitState) == 0); 12299 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12300 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12301 if ((state & EscapeState) != 0) 12302 return(MagickTrue); 12303 /* 12304 Draw line as pointer moves until the mouse button is released. 12305 */ 12306 distance=0; 12307 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12308 state=DefaultState; 12309 do 12310 { 12311 if (distance > 9) 12312 { 12313 /* 12314 Display info and draw rotation line. 12315 */ 12316 if (windows->info.mapped == MagickFalse) 12317 (void) XMapWindow(display,windows->info.id); 12318 (void) FormatLocaleString(text,MaxTextExtent," %g", 12319 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12320 XInfoWidget(display,windows,text); 12321 XHighlightLine(display,windows->image.id, 12322 windows->image.highlight_context,&rotate_info); 12323 } 12324 else 12325 if (windows->info.mapped != MagickFalse) 12326 (void) XWithdrawWindow(display,windows->info.id, 12327 windows->info.screen); 12328 /* 12329 Wait for next event. 12330 */ 12331 XScreenEvent(display,windows,&event,exception); 12332 if (distance > 9) 12333 XHighlightLine(display,windows->image.id, 12334 windows->image.highlight_context,&rotate_info); 12335 switch (event.type) 12336 { 12337 case ButtonPress: 12338 break; 12339 case ButtonRelease: 12340 { 12341 /* 12342 User has committed to rotation line. 12343 */ 12344 rotate_info.x2=event.xbutton.x; 12345 rotate_info.y2=event.xbutton.y; 12346 state|=ExitState; 12347 break; 12348 } 12349 case Expose: 12350 break; 12351 case MotionNotify: 12352 { 12353 rotate_info.x2=event.xmotion.x; 12354 rotate_info.y2=event.xmotion.y; 12355 } 12356 default: 12357 break; 12358 } 12359 /* 12360 Check boundary conditions. 12361 */ 12362 if (rotate_info.x2 < 0) 12363 rotate_info.x2=0; 12364 else 12365 if (rotate_info.x2 > (int) windows->image.width) 12366 rotate_info.x2=(short) windows->image.width; 12367 if (rotate_info.y2 < 0) 12368 rotate_info.y2=0; 12369 else 12370 if (rotate_info.y2 > (int) windows->image.height) 12371 rotate_info.y2=(short) windows->image.height; 12372 /* 12373 Compute rotation angle from the slope of the line. 12374 */ 12375 degrees=0.0; 12376 distance=(unsigned int) 12377 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12378 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12379 if (distance > 9) 12380 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12381 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12382 } while ((state & ExitState) == 0); 12383 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12384 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12385 if (distance <= 9) 12386 return(MagickTrue); 12387 } 12388 if (direction == VerticalRotateCommand) 12389 degrees-=90.0; 12390 if (degrees == 0.0) 12391 return(MagickTrue); 12392 /* 12393 Rotate image. 12394 */ 12395 normalized_degrees=degrees; 12396 while (normalized_degrees < -45.0) 12397 normalized_degrees+=360.0; 12398 for (rotations=0; normalized_degrees > 45.0; rotations++) 12399 normalized_degrees-=90.0; 12400 if (normalized_degrees != 0.0) 12401 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12402 exception); 12403 XSetCursorState(display,windows,MagickTrue); 12404 XCheckRefreshWindows(display,windows); 12405 (*image)->background_color.red=(double) ScaleShortToQuantum( 12406 windows->pixel_info->pen_colors[pen_id].red); 12407 (*image)->background_color.green=(double) ScaleShortToQuantum( 12408 windows->pixel_info->pen_colors[pen_id].green); 12409 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12410 windows->pixel_info->pen_colors[pen_id].blue); 12411 rotate_image=RotateImage(*image,degrees,exception); 12412 XSetCursorState(display,windows,MagickFalse); 12413 if (rotate_image == (Image *) NULL) 12414 return(MagickFalse); 12415 *image=DestroyImage(*image); 12416 *image=rotate_image; 12417 if (windows->image.crop_geometry != (char *) NULL) 12418 { 12419 /* 12420 Rotate crop geometry. 12421 */ 12422 width=(unsigned int) (*image)->columns; 12423 height=(unsigned int) (*image)->rows; 12424 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12425 switch (rotations % 4) 12426 { 12427 default: 12428 case 0: 12429 break; 12430 case 1: 12431 { 12432 /* 12433 Rotate 90 degrees. 12434 */ 12435 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12436 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12437 (int) height-y,x); 12438 break; 12439 } 12440 case 2: 12441 { 12442 /* 12443 Rotate 180 degrees. 12444 */ 12445 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12446 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12447 break; 12448 } 12449 case 3: 12450 { 12451 /* 12452 Rotate 270 degrees. 12453 */ 12454 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12455 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12456 break; 12457 } 12458 } 12459 } 12460 if (windows->image.orphan != MagickFalse) 12461 return(MagickTrue); 12462 if (normalized_degrees != 0.0) 12463 { 12464 /* 12465 Update image colormap. 12466 */ 12467 windows->image.window_changes.width=(int) (*image)->columns; 12468 windows->image.window_changes.height=(int) (*image)->rows; 12469 if (windows->image.crop_geometry != (char *) NULL) 12470 { 12471 /* 12472 Obtain dimensions of image from crop geometry. 12473 */ 12474 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12475 &width,&height); 12476 windows->image.window_changes.width=(int) width; 12477 windows->image.window_changes.height=(int) height; 12478 } 12479 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12480 } 12481 else 12482 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12483 { 12484 windows->image.window_changes.width=windows->image.ximage->height; 12485 windows->image.window_changes.height=windows->image.ximage->width; 12486 } 12487 /* 12488 Update image configuration. 12489 */ 12490 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12491 return(MagickTrue); 12492} 12493 12494/* 12495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12496% % 12497% % 12498% % 12499+ X S a v e I m a g e % 12500% % 12501% % 12502% % 12503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12504% 12505% XSaveImage() saves an image to a file. 12506% 12507% The format of the XSaveImage method is: 12508% 12509% MagickBooleanType XSaveImage(Display *display, 12510% XResourceInfo *resource_info,XWindows *windows,Image *image, 12511% ExceptionInfo *exception) 12512% 12513% A description of each parameter follows: 12514% 12515% o display: Specifies a connection to an X server; returned from 12516% XOpenDisplay. 12517% 12518% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12519% 12520% o windows: Specifies a pointer to a XWindows structure. 12521% 12522% o image: the image. 12523% 12524% o exception: return any errors or warnings in this structure. 12525% 12526*/ 12527static MagickBooleanType XSaveImage(Display *display, 12528 XResourceInfo *resource_info,XWindows *windows,Image *image, 12529 ExceptionInfo *exception) 12530{ 12531 char 12532 filename[MaxTextExtent], 12533 geometry[MaxTextExtent]; 12534 12535 Image 12536 *save_image; 12537 12538 ImageInfo 12539 *image_info; 12540 12541 MagickStatusType 12542 status; 12543 12544 /* 12545 Request file name from user. 12546 */ 12547 if (resource_info->write_filename != (char *) NULL) 12548 (void) CopyMagickString(filename,resource_info->write_filename, 12549 MaxTextExtent); 12550 else 12551 { 12552 char 12553 path[MaxTextExtent]; 12554 12555 int 12556 status; 12557 12558 GetPathComponent(image->filename,HeadPath,path); 12559 GetPathComponent(image->filename,TailPath,filename); 12560 if (*path != '\0') 12561 { 12562 status=chdir(path); 12563 if (status == -1) 12564 (void) ThrowMagickException(exception,GetMagickModule(), 12565 FileOpenError,"UnableToOpenFile","%s",path); 12566 } 12567 } 12568 XFileBrowserWidget(display,windows,"Save",filename); 12569 if (*filename == '\0') 12570 return(MagickTrue); 12571 if (IsPathAccessible(filename) != MagickFalse) 12572 { 12573 int 12574 status; 12575 12576 /* 12577 File exists-- seek user's permission before overwriting. 12578 */ 12579 status=XConfirmWidget(display,windows,"Overwrite",filename); 12580 if (status <= 0) 12581 return(MagickTrue); 12582 } 12583 image_info=CloneImageInfo(resource_info->image_info); 12584 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12585 (void) SetImageInfo(image_info,1,exception); 12586 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12587 (LocaleCompare(image_info->magick,"JPG") == 0)) 12588 { 12589 char 12590 quality[MaxTextExtent]; 12591 12592 int 12593 status; 12594 12595 /* 12596 Request JPEG quality from user. 12597 */ 12598 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12599 image->quality); 12600 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12601 quality); 12602 if (*quality == '\0') 12603 return(MagickTrue); 12604 image->quality=StringToUnsignedLong(quality); 12605 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12606 } 12607 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12608 (LocaleCompare(image_info->magick,"PDF") == 0) || 12609 (LocaleCompare(image_info->magick,"PS") == 0) || 12610 (LocaleCompare(image_info->magick,"PS2") == 0)) 12611 { 12612 char 12613 geometry[MaxTextExtent]; 12614 12615 /* 12616 Request page geometry from user. 12617 */ 12618 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12619 if (LocaleCompare(image_info->magick,"PDF") == 0) 12620 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12621 if (image_info->page != (char *) NULL) 12622 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12623 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12624 "Select page geometry:",geometry); 12625 if (*geometry != '\0') 12626 image_info->page=GetPageGeometry(geometry); 12627 } 12628 /* 12629 Apply image transforms. 12630 */ 12631 XSetCursorState(display,windows,MagickTrue); 12632 XCheckRefreshWindows(display,windows); 12633 save_image=CloneImage(image,0,0,MagickTrue,exception); 12634 if (save_image == (Image *) NULL) 12635 return(MagickFalse); 12636 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12637 windows->image.ximage->width,windows->image.ximage->height); 12638 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12639 exception); 12640 /* 12641 Write image. 12642 */ 12643 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12644 status=WriteImage(image_info,save_image,exception); 12645 if (status != MagickFalse) 12646 image->taint=MagickFalse; 12647 save_image=DestroyImage(save_image); 12648 image_info=DestroyImageInfo(image_info); 12649 XSetCursorState(display,windows,MagickFalse); 12650 return(status != 0 ? MagickTrue : MagickFalse); 12651} 12652 12653/* 12654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12655% % 12656% % 12657% % 12658+ X S c r e e n E v e n t % 12659% % 12660% % 12661% % 12662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12663% 12664% XScreenEvent() handles global events associated with the Pan and Magnify 12665% windows. 12666% 12667% The format of the XScreenEvent function is: 12668% 12669% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12670% ExceptionInfo *exception) 12671% 12672% A description of each parameter follows: 12673% 12674% o display: Specifies a pointer to the Display structure; returned from 12675% XOpenDisplay. 12676% 12677% o windows: Specifies a pointer to a XWindows structure. 12678% 12679% o event: Specifies a pointer to a X11 XEvent structure. 12680% 12681% o exception: return any errors or warnings in this structure. 12682% 12683*/ 12684 12685#if defined(__cplusplus) || defined(c_plusplus) 12686extern "C" { 12687#endif 12688 12689static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12690{ 12691 register XWindows 12692 *windows; 12693 12694 windows=(XWindows *) data; 12695 if ((event->type == ClientMessage) && 12696 (event->xclient.window == windows->image.id)) 12697 return(MagickFalse); 12698 return(MagickTrue); 12699} 12700 12701#if defined(__cplusplus) || defined(c_plusplus) 12702} 12703#endif 12704 12705static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12706 ExceptionInfo *exception) 12707{ 12708 register int 12709 x, 12710 y; 12711 12712 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12713 if (event->xany.window == windows->command.id) 12714 return; 12715 switch (event->type) 12716 { 12717 case ButtonPress: 12718 case ButtonRelease: 12719 { 12720 if ((event->xbutton.button == Button3) && 12721 (event->xbutton.state & Mod1Mask)) 12722 { 12723 /* 12724 Convert Alt-Button3 to Button2. 12725 */ 12726 event->xbutton.button=Button2; 12727 event->xbutton.state&=(~Mod1Mask); 12728 } 12729 if (event->xbutton.window == windows->backdrop.id) 12730 { 12731 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12732 event->xbutton.time); 12733 break; 12734 } 12735 if (event->xbutton.window == windows->pan.id) 12736 { 12737 XPanImage(display,windows,event,exception); 12738 break; 12739 } 12740 if (event->xbutton.window == windows->image.id) 12741 if (event->xbutton.button == Button2) 12742 { 12743 /* 12744 Update magnified image. 12745 */ 12746 x=event->xbutton.x; 12747 y=event->xbutton.y; 12748 if (x < 0) 12749 x=0; 12750 else 12751 if (x >= (int) windows->image.width) 12752 x=(int) (windows->image.width-1); 12753 windows->magnify.x=(int) windows->image.x+x; 12754 if (y < 0) 12755 y=0; 12756 else 12757 if (y >= (int) windows->image.height) 12758 y=(int) (windows->image.height-1); 12759 windows->magnify.y=windows->image.y+y; 12760 if (windows->magnify.mapped == MagickFalse) 12761 (void) XMapRaised(display,windows->magnify.id); 12762 XMakeMagnifyImage(display,windows,exception); 12763 if (event->type == ButtonRelease) 12764 (void) XWithdrawWindow(display,windows->info.id, 12765 windows->info.screen); 12766 break; 12767 } 12768 break; 12769 } 12770 case ClientMessage: 12771 { 12772 /* 12773 If client window delete message, exit. 12774 */ 12775 if (event->xclient.message_type != windows->wm_protocols) 12776 break; 12777 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12778 break; 12779 if (event->xclient.window == windows->magnify.id) 12780 { 12781 (void) XWithdrawWindow(display,windows->magnify.id, 12782 windows->magnify.screen); 12783 break; 12784 } 12785 break; 12786 } 12787 case ConfigureNotify: 12788 { 12789 if (event->xconfigure.window == windows->magnify.id) 12790 { 12791 unsigned int 12792 magnify; 12793 12794 /* 12795 Magnify window has a new configuration. 12796 */ 12797 windows->magnify.width=(unsigned int) event->xconfigure.width; 12798 windows->magnify.height=(unsigned int) event->xconfigure.height; 12799 if (windows->magnify.mapped == MagickFalse) 12800 break; 12801 magnify=1; 12802 while ((int) magnify <= event->xconfigure.width) 12803 magnify<<=1; 12804 while ((int) magnify <= event->xconfigure.height) 12805 magnify<<=1; 12806 magnify>>=1; 12807 if (((int) magnify != event->xconfigure.width) || 12808 ((int) magnify != event->xconfigure.height)) 12809 { 12810 XWindowChanges 12811 window_changes; 12812 12813 window_changes.width=(int) magnify; 12814 window_changes.height=(int) magnify; 12815 (void) XReconfigureWMWindow(display,windows->magnify.id, 12816 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12817 &window_changes); 12818 break; 12819 } 12820 XMakeMagnifyImage(display,windows,exception); 12821 break; 12822 } 12823 break; 12824 } 12825 case Expose: 12826 { 12827 if (event->xexpose.window == windows->image.id) 12828 { 12829 XRefreshWindow(display,&windows->image,event); 12830 break; 12831 } 12832 if (event->xexpose.window == windows->pan.id) 12833 if (event->xexpose.count == 0) 12834 { 12835 XDrawPanRectangle(display,windows); 12836 break; 12837 } 12838 if (event->xexpose.window == windows->magnify.id) 12839 if (event->xexpose.count == 0) 12840 { 12841 XMakeMagnifyImage(display,windows,exception); 12842 break; 12843 } 12844 break; 12845 } 12846 case KeyPress: 12847 { 12848 char 12849 command[MaxTextExtent]; 12850 12851 KeySym 12852 key_symbol; 12853 12854 if (event->xkey.window != windows->magnify.id) 12855 break; 12856 /* 12857 Respond to a user key press. 12858 */ 12859 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12860 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12861 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12862 exception); 12863 break; 12864 } 12865 case MapNotify: 12866 { 12867 if (event->xmap.window == windows->magnify.id) 12868 { 12869 windows->magnify.mapped=MagickTrue; 12870 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12871 break; 12872 } 12873 if (event->xmap.window == windows->info.id) 12874 { 12875 windows->info.mapped=MagickTrue; 12876 break; 12877 } 12878 break; 12879 } 12880 case MotionNotify: 12881 { 12882 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12883 if (event->xmotion.window == windows->image.id) 12884 if (windows->magnify.mapped != MagickFalse) 12885 { 12886 /* 12887 Update magnified image. 12888 */ 12889 x=event->xmotion.x; 12890 y=event->xmotion.y; 12891 if (x < 0) 12892 x=0; 12893 else 12894 if (x >= (int) windows->image.width) 12895 x=(int) (windows->image.width-1); 12896 windows->magnify.x=(int) windows->image.x+x; 12897 if (y < 0) 12898 y=0; 12899 else 12900 if (y >= (int) windows->image.height) 12901 y=(int) (windows->image.height-1); 12902 windows->magnify.y=windows->image.y+y; 12903 XMakeMagnifyImage(display,windows,exception); 12904 } 12905 break; 12906 } 12907 case UnmapNotify: 12908 { 12909 if (event->xunmap.window == windows->magnify.id) 12910 { 12911 windows->magnify.mapped=MagickFalse; 12912 break; 12913 } 12914 if (event->xunmap.window == windows->info.id) 12915 { 12916 windows->info.mapped=MagickFalse; 12917 break; 12918 } 12919 break; 12920 } 12921 default: 12922 break; 12923 } 12924} 12925 12926/* 12927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12928% % 12929% % 12930% % 12931+ X S e t C r o p G e o m e t r y % 12932% % 12933% % 12934% % 12935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12936% 12937% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12938% and translates it to a cropping geometry relative to the image. 12939% 12940% The format of the XSetCropGeometry method is: 12941% 12942% void XSetCropGeometry(Display *display,XWindows *windows, 12943% RectangleInfo *crop_info,Image *image) 12944% 12945% A description of each parameter follows: 12946% 12947% o display: Specifies a connection to an X server; returned from 12948% XOpenDisplay. 12949% 12950% o windows: Specifies a pointer to a XWindows structure. 12951% 12952% o crop_info: A pointer to a RectangleInfo that defines a region of the 12953% Image window to crop. 12954% 12955% o image: the image. 12956% 12957*/ 12958static void XSetCropGeometry(Display *display,XWindows *windows, 12959 RectangleInfo *crop_info,Image *image) 12960{ 12961 char 12962 text[MaxTextExtent]; 12963 12964 int 12965 x, 12966 y; 12967 12968 MagickRealType 12969 scale_factor; 12970 12971 unsigned int 12972 height, 12973 width; 12974 12975 if (windows->info.mapped != MagickFalse) 12976 { 12977 /* 12978 Display info on cropping rectangle. 12979 */ 12980 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12981 (double) crop_info->width,(double) crop_info->height,(double) 12982 crop_info->x,(double) crop_info->y); 12983 XInfoWidget(display,windows,text); 12984 } 12985 /* 12986 Cropping geometry is relative to any previous crop geometry. 12987 */ 12988 x=0; 12989 y=0; 12990 width=(unsigned int) image->columns; 12991 height=(unsigned int) image->rows; 12992 if (windows->image.crop_geometry != (char *) NULL) 12993 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12994 else 12995 windows->image.crop_geometry=AcquireString((char *) NULL); 12996 /* 12997 Define the crop geometry string from the cropping rectangle. 12998 */ 12999 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13000 if (crop_info->x > 0) 13001 x+=(int) (scale_factor*crop_info->x+0.5); 13002 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13003 if (width == 0) 13004 width=1; 13005 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13006 if (crop_info->y > 0) 13007 y+=(int) (scale_factor*crop_info->y+0.5); 13008 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13009 if (height == 0) 13010 height=1; 13011 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13012 "%ux%u%+d%+d",width,height,x,y); 13013} 13014 13015/* 13016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13017% % 13018% % 13019% % 13020+ X T i l e I m a g e % 13021% % 13022% % 13023% % 13024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13025% 13026% XTileImage() loads or deletes a selected tile from a visual image directory. 13027% The load or delete command is chosen from a menu. 13028% 13029% The format of the XTileImage method is: 13030% 13031% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13032% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13033% 13034% A description of each parameter follows: 13035% 13036% o tile_image: XTileImage reads or deletes the tile image 13037% and returns it. A null image is returned if an error occurs. 13038% 13039% o display: Specifies a connection to an X server; returned from 13040% XOpenDisplay. 13041% 13042% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13043% 13044% o windows: Specifies a pointer to a XWindows structure. 13045% 13046% o image: the image; returned from ReadImage. 13047% 13048% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13049% the entire image is refreshed. 13050% 13051% o exception: return any errors or warnings in this structure. 13052% 13053*/ 13054static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13055 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13056{ 13057 static const char 13058 *VerbMenu[] = 13059 { 13060 "Load", 13061 "Next", 13062 "Former", 13063 "Delete", 13064 "Update", 13065 (char *) NULL, 13066 }; 13067 13068 static const ModeType 13069 TileCommands[] = 13070 { 13071 TileLoadCommand, 13072 TileNextCommand, 13073 TileFormerCommand, 13074 TileDeleteCommand, 13075 TileUpdateCommand 13076 }; 13077 13078 char 13079 command[MaxTextExtent], 13080 filename[MaxTextExtent]; 13081 13082 Image 13083 *tile_image; 13084 13085 int 13086 id, 13087 status, 13088 tile, 13089 x, 13090 y; 13091 13092 MagickRealType 13093 scale_factor; 13094 13095 register char 13096 *p, 13097 *q; 13098 13099 register int 13100 i; 13101 13102 unsigned int 13103 height, 13104 width; 13105 13106 /* 13107 Tile image is relative to montage image configuration. 13108 */ 13109 x=0; 13110 y=0; 13111 width=(unsigned int) image->columns; 13112 height=(unsigned int) image->rows; 13113 if (windows->image.crop_geometry != (char *) NULL) 13114 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13115 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13116 event->xbutton.x+=windows->image.x; 13117 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13118 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13119 event->xbutton.y+=windows->image.y; 13120 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13121 /* 13122 Determine size and location of each tile in the visual image directory. 13123 */ 13124 width=(unsigned int) image->columns; 13125 height=(unsigned int) image->rows; 13126 x=0; 13127 y=0; 13128 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13129 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13130 (event->xbutton.x-x)/width; 13131 if (tile < 0) 13132 { 13133 /* 13134 Button press is outside any tile. 13135 */ 13136 (void) XBell(display,0); 13137 return((Image *) NULL); 13138 } 13139 /* 13140 Determine file name from the tile directory. 13141 */ 13142 p=image->directory; 13143 for (i=tile; (i != 0) && (*p != '\0'); ) 13144 { 13145 if (*p == '\n') 13146 i--; 13147 p++; 13148 } 13149 if (*p == '\0') 13150 { 13151 /* 13152 Button press is outside any tile. 13153 */ 13154 (void) XBell(display,0); 13155 return((Image *) NULL); 13156 } 13157 /* 13158 Select a command from the pop-up menu. 13159 */ 13160 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13161 if (id < 0) 13162 return((Image *) NULL); 13163 q=p; 13164 while ((*q != '\n') && (*q != '\0')) 13165 q++; 13166 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13167 /* 13168 Perform command for the selected tile. 13169 */ 13170 XSetCursorState(display,windows,MagickTrue); 13171 XCheckRefreshWindows(display,windows); 13172 tile_image=NewImageList(); 13173 switch (TileCommands[id]) 13174 { 13175 case TileLoadCommand: 13176 { 13177 /* 13178 Load tile image. 13179 */ 13180 XCheckRefreshWindows(display,windows); 13181 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13182 MaxTextExtent); 13183 (void) CopyMagickString(resource_info->image_info->filename,filename, 13184 MaxTextExtent); 13185 tile_image=ReadImage(resource_info->image_info,exception); 13186 CatchException(exception); 13187 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13188 break; 13189 } 13190 case TileNextCommand: 13191 { 13192 /* 13193 Display next image. 13194 */ 13195 XClientMessage(display,windows->image.id,windows->im_protocols, 13196 windows->im_next_image,CurrentTime); 13197 break; 13198 } 13199 case TileFormerCommand: 13200 { 13201 /* 13202 Display former image. 13203 */ 13204 XClientMessage(display,windows->image.id,windows->im_protocols, 13205 windows->im_former_image,CurrentTime); 13206 break; 13207 } 13208 case TileDeleteCommand: 13209 { 13210 /* 13211 Delete tile image. 13212 */ 13213 if (IsPathAccessible(filename) == MagickFalse) 13214 { 13215 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13216 break; 13217 } 13218 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13219 if (status <= 0) 13220 break; 13221 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13222 if (status != MagickFalse) 13223 { 13224 XNoticeWidget(display,windows,"Unable to delete image file:", 13225 filename); 13226 break; 13227 } 13228 } 13229 case TileUpdateCommand: 13230 { 13231 int 13232 x_offset, 13233 y_offset; 13234 13235 PixelInfo 13236 pixel; 13237 13238 register int 13239 j; 13240 13241 register Quantum 13242 *s; 13243 13244 /* 13245 Ensure all the images exist. 13246 */ 13247 tile=0; 13248 GetPixelInfo(image,&pixel); 13249 for (p=image->directory; *p != '\0'; p++) 13250 { 13251 CacheView 13252 *image_view; 13253 13254 q=p; 13255 while ((*q != '\n') && (*q != '\0')) 13256 q++; 13257 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13258 p=q; 13259 if (IsPathAccessible(filename) != MagickFalse) 13260 { 13261 tile++; 13262 continue; 13263 } 13264 /* 13265 Overwrite tile with background color. 13266 */ 13267 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13268 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13269 image_view=AcquireCacheView(image); 13270 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13271 for (i=0; i < (int) height; i++) 13272 { 13273 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13274 y_offset+i,width,1,exception); 13275 if (s == (Quantum *) NULL) 13276 break; 13277 for (j=0; j < (int) width; j++) 13278 { 13279 SetPixelInfoPixel(image,&pixel,s); 13280 s+=GetPixelChannels(image); 13281 } 13282 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13283 break; 13284 } 13285 image_view=DestroyCacheView(image_view); 13286 tile++; 13287 } 13288 windows->image.window_changes.width=(int) image->columns; 13289 windows->image.window_changes.height=(int) image->rows; 13290 XConfigureImageColormap(display,resource_info,windows,image,exception); 13291 (void) XConfigureImage(display,resource_info,windows,image,exception); 13292 break; 13293 } 13294 default: 13295 break; 13296 } 13297 XSetCursorState(display,windows,MagickFalse); 13298 return(tile_image); 13299} 13300 13301/* 13302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13303% % 13304% % 13305% % 13306+ X T r a n s l a t e I m a g e % 13307% % 13308% % 13309% % 13310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13311% 13312% XTranslateImage() translates the image within an Image window by one pixel 13313% as specified by the key symbol. If the image has a `montage string the 13314% translation is respect to the width and height contained within the string. 13315% 13316% The format of the XTranslateImage method is: 13317% 13318% void XTranslateImage(Display *display,XWindows *windows, 13319% Image *image,const KeySym key_symbol) 13320% 13321% A description of each parameter follows: 13322% 13323% o display: Specifies a connection to an X server; returned from 13324% XOpenDisplay. 13325% 13326% o windows: Specifies a pointer to a XWindows structure. 13327% 13328% o image: the image. 13329% 13330% o key_symbol: Specifies a KeySym which indicates which side of the image 13331% to trim. 13332% 13333*/ 13334static void XTranslateImage(Display *display,XWindows *windows, 13335 Image *image,const KeySym key_symbol) 13336{ 13337 char 13338 text[MaxTextExtent]; 13339 13340 int 13341 x, 13342 y; 13343 13344 unsigned int 13345 x_offset, 13346 y_offset; 13347 13348 /* 13349 User specified a pan position offset. 13350 */ 13351 x_offset=windows->image.width; 13352 y_offset=windows->image.height; 13353 if (image->montage != (char *) NULL) 13354 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13355 switch ((int) key_symbol) 13356 { 13357 case XK_Home: 13358 case XK_KP_Home: 13359 { 13360 windows->image.x=(int) windows->image.width/2; 13361 windows->image.y=(int) windows->image.height/2; 13362 break; 13363 } 13364 case XK_Left: 13365 case XK_KP_Left: 13366 { 13367 windows->image.x-=x_offset; 13368 break; 13369 } 13370 case XK_Next: 13371 case XK_Up: 13372 case XK_KP_Up: 13373 { 13374 windows->image.y-=y_offset; 13375 break; 13376 } 13377 case XK_Right: 13378 case XK_KP_Right: 13379 { 13380 windows->image.x+=x_offset; 13381 break; 13382 } 13383 case XK_Prior: 13384 case XK_Down: 13385 case XK_KP_Down: 13386 { 13387 windows->image.y+=y_offset; 13388 break; 13389 } 13390 default: 13391 return; 13392 } 13393 /* 13394 Check boundary conditions. 13395 */ 13396 if (windows->image.x < 0) 13397 windows->image.x=0; 13398 else 13399 if ((int) (windows->image.x+windows->image.width) > 13400 windows->image.ximage->width) 13401 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13402 if (windows->image.y < 0) 13403 windows->image.y=0; 13404 else 13405 if ((int) (windows->image.y+windows->image.height) > 13406 windows->image.ximage->height) 13407 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13408 /* 13409 Refresh Image window. 13410 */ 13411 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13412 windows->image.width,windows->image.height,windows->image.x, 13413 windows->image.y); 13414 XInfoWidget(display,windows,text); 13415 XCheckRefreshWindows(display,windows); 13416 XDrawPanRectangle(display,windows); 13417 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13418 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13419} 13420 13421/* 13422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13423% % 13424% % 13425% % 13426+ X T r i m I m a g e % 13427% % 13428% % 13429% % 13430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13431% 13432% XTrimImage() trims the edges from the Image window. 13433% 13434% The format of the XTrimImage method is: 13435% 13436% MagickBooleanType XTrimImage(Display *display, 13437% XResourceInfo *resource_info,XWindows *windows,Image *image, 13438% ExceptionInfo *exception) 13439% 13440% A description of each parameter follows: 13441% 13442% o display: Specifies a connection to an X server; returned from 13443% XOpenDisplay. 13444% 13445% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13446% 13447% o windows: Specifies a pointer to a XWindows structure. 13448% 13449% o image: the image. 13450% 13451% o exception: return any errors or warnings in this structure. 13452% 13453*/ 13454static MagickBooleanType XTrimImage(Display *display, 13455 XResourceInfo *resource_info,XWindows *windows,Image *image, 13456 ExceptionInfo *exception) 13457{ 13458 RectangleInfo 13459 trim_info; 13460 13461 register int 13462 x, 13463 y; 13464 13465 size_t 13466 background, 13467 pixel; 13468 13469 /* 13470 Trim edges from image. 13471 */ 13472 XSetCursorState(display,windows,MagickTrue); 13473 XCheckRefreshWindows(display,windows); 13474 /* 13475 Crop the left edge. 13476 */ 13477 background=XGetPixel(windows->image.ximage,0,0); 13478 trim_info.width=(size_t) windows->image.ximage->width; 13479 for (x=0; x < windows->image.ximage->width; x++) 13480 { 13481 for (y=0; y < windows->image.ximage->height; y++) 13482 { 13483 pixel=XGetPixel(windows->image.ximage,x,y); 13484 if (pixel != background) 13485 break; 13486 } 13487 if (y < windows->image.ximage->height) 13488 break; 13489 } 13490 trim_info.x=(ssize_t) x; 13491 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13492 { 13493 XSetCursorState(display,windows,MagickFalse); 13494 return(MagickFalse); 13495 } 13496 /* 13497 Crop the right edge. 13498 */ 13499 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13500 for (x=windows->image.ximage->width-1; x != 0; x--) 13501 { 13502 for (y=0; y < windows->image.ximage->height; y++) 13503 { 13504 pixel=XGetPixel(windows->image.ximage,x,y); 13505 if (pixel != background) 13506 break; 13507 } 13508 if (y < windows->image.ximage->height) 13509 break; 13510 } 13511 trim_info.width=(size_t) (x-trim_info.x+1); 13512 /* 13513 Crop the top edge. 13514 */ 13515 background=XGetPixel(windows->image.ximage,0,0); 13516 trim_info.height=(size_t) windows->image.ximage->height; 13517 for (y=0; y < windows->image.ximage->height; y++) 13518 { 13519 for (x=0; x < windows->image.ximage->width; x++) 13520 { 13521 pixel=XGetPixel(windows->image.ximage,x,y); 13522 if (pixel != background) 13523 break; 13524 } 13525 if (x < windows->image.ximage->width) 13526 break; 13527 } 13528 trim_info.y=(ssize_t) y; 13529 /* 13530 Crop the bottom edge. 13531 */ 13532 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13533 for (y=windows->image.ximage->height-1; y != 0; y--) 13534 { 13535 for (x=0; x < windows->image.ximage->width; x++) 13536 { 13537 pixel=XGetPixel(windows->image.ximage,x,y); 13538 if (pixel != background) 13539 break; 13540 } 13541 if (x < windows->image.ximage->width) 13542 break; 13543 } 13544 trim_info.height=(size_t) y-trim_info.y+1; 13545 if (((unsigned int) trim_info.width != windows->image.width) || 13546 ((unsigned int) trim_info.height != windows->image.height)) 13547 { 13548 /* 13549 Reconfigure Image window as defined by the trimming rectangle. 13550 */ 13551 XSetCropGeometry(display,windows,&trim_info,image); 13552 windows->image.window_changes.width=(int) trim_info.width; 13553 windows->image.window_changes.height=(int) trim_info.height; 13554 (void) XConfigureImage(display,resource_info,windows,image,exception); 13555 } 13556 XSetCursorState(display,windows,MagickFalse); 13557 return(MagickTrue); 13558} 13559 13560/* 13561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13562% % 13563% % 13564% % 13565+ X V i s u a l D i r e c t o r y I m a g e % 13566% % 13567% % 13568% % 13569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13570% 13571% XVisualDirectoryImage() creates a Visual Image Directory. 13572% 13573% The format of the XVisualDirectoryImage method is: 13574% 13575% Image *XVisualDirectoryImage(Display *display, 13576% XResourceInfo *resource_info,XWindows *windows, 13577% ExceptionInfo *exception) 13578% 13579% A description of each parameter follows: 13580% 13581% o display: Specifies a connection to an X server; returned from 13582% XOpenDisplay. 13583% 13584% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13585% 13586% o windows: Specifies a pointer to a XWindows structure. 13587% 13588% o exception: return any errors or warnings in this structure. 13589% 13590*/ 13591static Image *XVisualDirectoryImage(Display *display, 13592 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13593{ 13594#define TileImageTag "Scale/Image" 13595#define XClientName "montage" 13596 13597 char 13598 **filelist; 13599 13600 Image 13601 *images, 13602 *montage_image, 13603 *next_image, 13604 *thumbnail_image; 13605 13606 ImageInfo 13607 *read_info; 13608 13609 int 13610 number_files; 13611 13612 MagickBooleanType 13613 backdrop; 13614 13615 MagickStatusType 13616 status; 13617 13618 MontageInfo 13619 *montage_info; 13620 13621 RectangleInfo 13622 geometry; 13623 13624 register int 13625 i; 13626 13627 static char 13628 filename[MaxTextExtent] = "\0", 13629 filenames[MaxTextExtent] = "*"; 13630 13631 XResourceInfo 13632 background_resources; 13633 13634 /* 13635 Request file name from user. 13636 */ 13637 XFileBrowserWidget(display,windows,"Directory",filenames); 13638 if (*filenames == '\0') 13639 return((Image *) NULL); 13640 /* 13641 Expand the filenames. 13642 */ 13643 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13644 if (filelist == (char **) NULL) 13645 { 13646 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13647 filenames); 13648 return((Image *) NULL); 13649 } 13650 number_files=1; 13651 filelist[0]=filenames; 13652 status=ExpandFilenames(&number_files,&filelist); 13653 if ((status == MagickFalse) || (number_files == 0)) 13654 { 13655 if (number_files == 0) 13656 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13657 else 13658 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13659 filenames); 13660 return((Image *) NULL); 13661 } 13662 /* 13663 Set image background resources. 13664 */ 13665 background_resources=(*resource_info); 13666 background_resources.window_id=AcquireString(""); 13667 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13668 "0x%lx",windows->image.id); 13669 background_resources.backdrop=MagickTrue; 13670 /* 13671 Read each image and convert them to a tile. 13672 */ 13673 backdrop=(windows->visual_info->klass == TrueColor) || 13674 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13675 read_info=CloneImageInfo(resource_info->image_info); 13676 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13677 (void) CloneString(&read_info->size,DefaultTileGeometry); 13678 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13679 (void *) NULL); 13680 images=NewImageList(); 13681 XSetCursorState(display,windows,MagickTrue); 13682 XCheckRefreshWindows(display,windows); 13683 for (i=0; i < (int) number_files; i++) 13684 { 13685 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13686 filelist[i]=DestroyString(filelist[i]); 13687 *read_info->magick='\0'; 13688 next_image=ReadImage(read_info,exception); 13689 CatchException(exception); 13690 if (next_image != (Image *) NULL) 13691 { 13692 (void) DeleteImageProperty(next_image,"label"); 13693 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13694 read_info,next_image,DefaultTileLabel,exception),exception); 13695 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13696 exception); 13697 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13698 geometry.height,exception); 13699 if (thumbnail_image != (Image *) NULL) 13700 { 13701 next_image=DestroyImage(next_image); 13702 next_image=thumbnail_image; 13703 } 13704 if (backdrop) 13705 { 13706 (void) XDisplayBackgroundImage(display,&background_resources, 13707 next_image,exception); 13708 XSetCursorState(display,windows,MagickTrue); 13709 } 13710 AppendImageToList(&images,next_image); 13711 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13712 { 13713 MagickBooleanType 13714 proceed; 13715 13716 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13717 (MagickSizeType) number_files); 13718 if (proceed == MagickFalse) 13719 break; 13720 } 13721 } 13722 } 13723 filelist=(char **) RelinquishMagickMemory(filelist); 13724 if (images == (Image *) NULL) 13725 { 13726 read_info=DestroyImageInfo(read_info); 13727 XSetCursorState(display,windows,MagickFalse); 13728 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13729 return((Image *) NULL); 13730 } 13731 /* 13732 Create the Visual Image Directory. 13733 */ 13734 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13735 montage_info->pointsize=10; 13736 if (resource_info->font != (char *) NULL) 13737 (void) CloneString(&montage_info->font,resource_info->font); 13738 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13739 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13740 images),exception); 13741 images=DestroyImageList(images); 13742 montage_info=DestroyMontageInfo(montage_info); 13743 read_info=DestroyImageInfo(read_info); 13744 XSetCursorState(display,windows,MagickFalse); 13745 if (montage_image == (Image *) NULL) 13746 return(montage_image); 13747 XClientMessage(display,windows->image.id,windows->im_protocols, 13748 windows->im_next_image,CurrentTime); 13749 return(montage_image); 13750} 13751 13752/* 13753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13754% % 13755% % 13756% % 13757% X D i s p l a y B a c k g r o u n d I m a g e % 13758% % 13759% % 13760% % 13761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13762% 13763% XDisplayBackgroundImage() displays an image in the background of a window. 13764% 13765% The format of the XDisplayBackgroundImage method is: 13766% 13767% MagickBooleanType XDisplayBackgroundImage(Display *display, 13768% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13769% 13770% A description of each parameter follows: 13771% 13772% o display: Specifies a connection to an X server; returned from 13773% XOpenDisplay. 13774% 13775% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13776% 13777% o image: the image. 13778% 13779% o exception: return any errors or warnings in this structure. 13780% 13781*/ 13782MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13783 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13784{ 13785 char 13786 geometry[MaxTextExtent], 13787 visual_type[MaxTextExtent]; 13788 13789 int 13790 height, 13791 status, 13792 width; 13793 13794 RectangleInfo 13795 geometry_info; 13796 13797 static XPixelInfo 13798 pixel; 13799 13800 static XStandardColormap 13801 *map_info; 13802 13803 static XVisualInfo 13804 *visual_info = (XVisualInfo *) NULL; 13805 13806 static XWindowInfo 13807 window_info; 13808 13809 size_t 13810 delay; 13811 13812 Window 13813 root_window; 13814 13815 XGCValues 13816 context_values; 13817 13818 XResourceInfo 13819 resources; 13820 13821 XWindowAttributes 13822 window_attributes; 13823 13824 /* 13825 Determine target window. 13826 */ 13827 assert(image != (Image *) NULL); 13828 assert(image->signature == MagickSignature); 13829 if (image->debug != MagickFalse) 13830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13831 resources=(*resource_info); 13832 window_info.id=(Window) NULL; 13833 root_window=XRootWindow(display,XDefaultScreen(display)); 13834 if (LocaleCompare(resources.window_id,"root") == 0) 13835 window_info.id=root_window; 13836 else 13837 { 13838 if (isdigit((unsigned char) *resources.window_id) != 0) 13839 window_info.id=XWindowByID(display,root_window, 13840 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13841 if (window_info.id == (Window) NULL) 13842 window_info.id=XWindowByName(display,root_window,resources.window_id); 13843 } 13844 if (window_info.id == (Window) NULL) 13845 { 13846 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13847 resources.window_id); 13848 return(MagickFalse); 13849 } 13850 /* 13851 Determine window visual id. 13852 */ 13853 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13854 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13855 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13856 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13857 if (status != 0) 13858 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13859 XVisualIDFromVisual(window_attributes.visual)); 13860 if (visual_info == (XVisualInfo *) NULL) 13861 { 13862 /* 13863 Allocate standard colormap. 13864 */ 13865 map_info=XAllocStandardColormap(); 13866 if (map_info == (XStandardColormap *) NULL) 13867 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13868 image->filename); 13869 map_info->colormap=(Colormap) NULL; 13870 pixel.pixels=(unsigned long *) NULL; 13871 /* 13872 Initialize visual info. 13873 */ 13874 resources.map_type=(char *) NULL; 13875 resources.visual_type=visual_type; 13876 visual_info=XBestVisualInfo(display,map_info,&resources); 13877 if (visual_info == (XVisualInfo *) NULL) 13878 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13879 resources.visual_type); 13880 /* 13881 Initialize window info. 13882 */ 13883 window_info.ximage=(XImage *) NULL; 13884 window_info.matte_image=(XImage *) NULL; 13885 window_info.pixmap=(Pixmap) NULL; 13886 window_info.matte_pixmap=(Pixmap) NULL; 13887 } 13888 /* 13889 Free previous root colors. 13890 */ 13891 if (window_info.id == root_window) 13892 (void) XDestroyWindowColors(display,root_window); 13893 /* 13894 Initialize Standard Colormap. 13895 */ 13896 resources.colormap=SharedColormap; 13897 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13898 exception); 13899 /* 13900 Graphic context superclass. 13901 */ 13902 context_values.background=pixel.background_color.pixel; 13903 context_values.foreground=pixel.foreground_color.pixel; 13904 pixel.annotate_context=XCreateGC(display,window_info.id, 13905 (size_t) (GCBackground | GCForeground),&context_values); 13906 if (pixel.annotate_context == (GC) NULL) 13907 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13908 image->filename); 13909 /* 13910 Initialize Image window attributes. 13911 */ 13912 window_info.name=AcquireString("\0"); 13913 window_info.icon_name=AcquireString("\0"); 13914 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13915 &resources,&window_info); 13916 /* 13917 Create the X image. 13918 */ 13919 window_info.width=(unsigned int) image->columns; 13920 window_info.height=(unsigned int) image->rows; 13921 if ((image->columns != window_info.width) || 13922 (image->rows != window_info.height)) 13923 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13924 image->filename); 13925 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13926 window_attributes.width,window_attributes.height); 13927 geometry_info.width=window_info.width; 13928 geometry_info.height=window_info.height; 13929 geometry_info.x=(ssize_t) window_info.x; 13930 geometry_info.y=(ssize_t) window_info.y; 13931 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13932 &geometry_info.width,&geometry_info.height); 13933 window_info.width=(unsigned int) geometry_info.width; 13934 window_info.height=(unsigned int) geometry_info.height; 13935 window_info.x=(int) geometry_info.x; 13936 window_info.y=(int) geometry_info.y; 13937 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13938 window_info.height,exception); 13939 if (status == MagickFalse) 13940 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13941 image->filename); 13942 window_info.x=0; 13943 window_info.y=0; 13944 if (image->debug != MagickFalse) 13945 { 13946 (void) LogMagickEvent(X11Event,GetMagickModule(), 13947 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13948 (double) image->columns,(double) image->rows); 13949 if (image->colors != 0) 13950 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13951 image->colors); 13952 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13953 } 13954 /* 13955 Adjust image dimensions as specified by backdrop or geometry options. 13956 */ 13957 width=(int) window_info.width; 13958 height=(int) window_info.height; 13959 if (resources.backdrop != MagickFalse) 13960 { 13961 /* 13962 Center image on window. 13963 */ 13964 window_info.x=(window_attributes.width/2)- 13965 (window_info.ximage->width/2); 13966 window_info.y=(window_attributes.height/2)- 13967 (window_info.ximage->height/2); 13968 width=window_attributes.width; 13969 height=window_attributes.height; 13970 } 13971 if ((resources.image_geometry != (char *) NULL) && 13972 (*resources.image_geometry != '\0')) 13973 { 13974 char 13975 default_geometry[MaxTextExtent]; 13976 13977 int 13978 flags, 13979 gravity; 13980 13981 XSizeHints 13982 *size_hints; 13983 13984 /* 13985 User specified geometry. 13986 */ 13987 size_hints=XAllocSizeHints(); 13988 if (size_hints == (XSizeHints *) NULL) 13989 ThrowXWindowFatalException(ResourceLimitFatalError, 13990 "MemoryAllocationFailed",image->filename); 13991 size_hints->flags=0L; 13992 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13993 width,height); 13994 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13995 default_geometry,window_info.border_width,size_hints,&window_info.x, 13996 &window_info.y,&width,&height,&gravity); 13997 if (flags & (XValue | YValue)) 13998 { 13999 width=window_attributes.width; 14000 height=window_attributes.height; 14001 } 14002 (void) XFree((void *) size_hints); 14003 } 14004 /* 14005 Create the X pixmap. 14006 */ 14007 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14008 (unsigned int) height,window_info.depth); 14009 if (window_info.pixmap == (Pixmap) NULL) 14010 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14011 image->filename); 14012 /* 14013 Display pixmap on the window. 14014 */ 14015 if (((unsigned int) width > window_info.width) || 14016 ((unsigned int) height > window_info.height)) 14017 (void) XFillRectangle(display,window_info.pixmap, 14018 window_info.annotate_context,0,0,(unsigned int) width, 14019 (unsigned int) height); 14020 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14021 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14022 window_info.width,(unsigned int) window_info.height); 14023 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14024 (void) XClearWindow(display,window_info.id); 14025 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14026 XDelay(display,delay == 0UL ? 10UL : delay); 14027 (void) XSync(display,MagickFalse); 14028 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14029} 14030 14031/* 14032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14033% % 14034% % 14035% % 14036+ X D i s p l a y I m a g e % 14037% % 14038% % 14039% % 14040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14041% 14042% XDisplayImage() displays an image via X11. A new image is created and 14043% returned if the user interactively transforms the displayed image. 14044% 14045% The format of the XDisplayImage method is: 14046% 14047% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14048% char **argv,int argc,Image **image,size_t *state, 14049% ExceptionInfo *exception) 14050% 14051% A description of each parameter follows: 14052% 14053% o nexus: Method XDisplayImage returns an image when the 14054% user chooses 'Open Image' from the command menu or picks a tile 14055% from the image directory. Otherwise a null image is returned. 14056% 14057% o display: Specifies a connection to an X server; returned from 14058% XOpenDisplay. 14059% 14060% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14061% 14062% o argv: Specifies the application's argument list. 14063% 14064% o argc: Specifies the number of arguments. 14065% 14066% o image: Specifies an address to an address of an Image structure; 14067% 14068% o exception: return any errors or warnings in this structure. 14069% 14070*/ 14071MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14072 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14073{ 14074#define MagnifySize 256 /* must be a power of 2 */ 14075#define MagickMenus 10 14076#define MagickTitle "Commands" 14077 14078 static const char 14079 *CommandMenu[] = 14080 { 14081 "File", 14082 "Edit", 14083 "View", 14084 "Transform", 14085 "Enhance", 14086 "Effects", 14087 "F/X", 14088 "Image Edit", 14089 "Miscellany", 14090 "Help", 14091 (char *) NULL 14092 }, 14093 *FileMenu[] = 14094 { 14095 "Open...", 14096 "Next", 14097 "Former", 14098 "Select...", 14099 "Save...", 14100 "Print...", 14101 "Delete...", 14102 "New...", 14103 "Visual Directory...", 14104 "Quit", 14105 (char *) NULL 14106 }, 14107 *EditMenu[] = 14108 { 14109 "Undo", 14110 "Redo", 14111 "Cut", 14112 "Copy", 14113 "Paste", 14114 (char *) NULL 14115 }, 14116 *ViewMenu[] = 14117 { 14118 "Half Size", 14119 "Original Size", 14120 "Double Size", 14121 "Resize...", 14122 "Apply", 14123 "Refresh", 14124 "Restore", 14125 (char *) NULL 14126 }, 14127 *TransformMenu[] = 14128 { 14129 "Crop", 14130 "Chop", 14131 "Flop", 14132 "Flip", 14133 "Rotate Right", 14134 "Rotate Left", 14135 "Rotate...", 14136 "Shear...", 14137 "Roll...", 14138 "Trim Edges", 14139 (char *) NULL 14140 }, 14141 *EnhanceMenu[] = 14142 { 14143 "Hue...", 14144 "Saturation...", 14145 "Brightness...", 14146 "Gamma...", 14147 "Spiff", 14148 "Dull", 14149 "Contrast Stretch...", 14150 "Sigmoidal Contrast...", 14151 "Normalize", 14152 "Equalize", 14153 "Negate", 14154 "Grayscale", 14155 "Map...", 14156 "Quantize...", 14157 (char *) NULL 14158 }, 14159 *EffectsMenu[] = 14160 { 14161 "Despeckle", 14162 "Emboss", 14163 "Reduce Noise", 14164 "Add Noise...", 14165 "Sharpen...", 14166 "Blur...", 14167 "Threshold...", 14168 "Edge Detect...", 14169 "Spread...", 14170 "Shade...", 14171 "Raise...", 14172 "Segment...", 14173 (char *) NULL 14174 }, 14175 *FXMenu[] = 14176 { 14177 "Solarize...", 14178 "Sepia Tone...", 14179 "Swirl...", 14180 "Implode...", 14181 "Vignette...", 14182 "Wave...", 14183 "Oil Paint...", 14184 "Charcoal Draw...", 14185 (char *) NULL 14186 }, 14187 *ImageEditMenu[] = 14188 { 14189 "Annotate...", 14190 "Draw...", 14191 "Color...", 14192 "Matte...", 14193 "Composite...", 14194 "Add Border...", 14195 "Add Frame...", 14196 "Comment...", 14197 "Launch...", 14198 "Region of Interest...", 14199 (char *) NULL 14200 }, 14201 *MiscellanyMenu[] = 14202 { 14203 "Image Info", 14204 "Zoom Image", 14205 "Show Preview...", 14206 "Show Histogram", 14207 "Show Matte", 14208 "Background...", 14209 "Slide Show...", 14210 "Preferences...", 14211 (char *) NULL 14212 }, 14213 *HelpMenu[] = 14214 { 14215 "Overview", 14216 "Browse Documentation", 14217 "About Display", 14218 (char *) NULL 14219 }, 14220 *ShortCutsMenu[] = 14221 { 14222 "Next", 14223 "Former", 14224 "Open...", 14225 "Save...", 14226 "Print...", 14227 "Undo", 14228 "Restore", 14229 "Image Info", 14230 "Quit", 14231 (char *) NULL 14232 }, 14233 *VirtualMenu[] = 14234 { 14235 "Image Info", 14236 "Print", 14237 "Next", 14238 "Quit", 14239 (char *) NULL 14240 }; 14241 14242 static const char 14243 **Menus[MagickMenus] = 14244 { 14245 FileMenu, 14246 EditMenu, 14247 ViewMenu, 14248 TransformMenu, 14249 EnhanceMenu, 14250 EffectsMenu, 14251 FXMenu, 14252 ImageEditMenu, 14253 MiscellanyMenu, 14254 HelpMenu 14255 }; 14256 14257 static CommandType 14258 CommandMenus[] = 14259 { 14260 NullCommand, 14261 NullCommand, 14262 NullCommand, 14263 NullCommand, 14264 NullCommand, 14265 NullCommand, 14266 NullCommand, 14267 NullCommand, 14268 NullCommand, 14269 NullCommand, 14270 }, 14271 FileCommands[] = 14272 { 14273 OpenCommand, 14274 NextCommand, 14275 FormerCommand, 14276 SelectCommand, 14277 SaveCommand, 14278 PrintCommand, 14279 DeleteCommand, 14280 NewCommand, 14281 VisualDirectoryCommand, 14282 QuitCommand 14283 }, 14284 EditCommands[] = 14285 { 14286 UndoCommand, 14287 RedoCommand, 14288 CutCommand, 14289 CopyCommand, 14290 PasteCommand 14291 }, 14292 ViewCommands[] = 14293 { 14294 HalfSizeCommand, 14295 OriginalSizeCommand, 14296 DoubleSizeCommand, 14297 ResizeCommand, 14298 ApplyCommand, 14299 RefreshCommand, 14300 RestoreCommand 14301 }, 14302 TransformCommands[] = 14303 { 14304 CropCommand, 14305 ChopCommand, 14306 FlopCommand, 14307 FlipCommand, 14308 RotateRightCommand, 14309 RotateLeftCommand, 14310 RotateCommand, 14311 ShearCommand, 14312 RollCommand, 14313 TrimCommand 14314 }, 14315 EnhanceCommands[] = 14316 { 14317 HueCommand, 14318 SaturationCommand, 14319 BrightnessCommand, 14320 GammaCommand, 14321 SpiffCommand, 14322 DullCommand, 14323 ContrastStretchCommand, 14324 SigmoidalContrastCommand, 14325 NormalizeCommand, 14326 EqualizeCommand, 14327 NegateCommand, 14328 GrayscaleCommand, 14329 MapCommand, 14330 QuantizeCommand 14331 }, 14332 EffectsCommands[] = 14333 { 14334 DespeckleCommand, 14335 EmbossCommand, 14336 ReduceNoiseCommand, 14337 AddNoiseCommand, 14338 SharpenCommand, 14339 BlurCommand, 14340 ThresholdCommand, 14341 EdgeDetectCommand, 14342 SpreadCommand, 14343 ShadeCommand, 14344 RaiseCommand, 14345 SegmentCommand 14346 }, 14347 FXCommands[] = 14348 { 14349 SolarizeCommand, 14350 SepiaToneCommand, 14351 SwirlCommand, 14352 ImplodeCommand, 14353 VignetteCommand, 14354 WaveCommand, 14355 OilPaintCommand, 14356 CharcoalDrawCommand 14357 }, 14358 ImageEditCommands[] = 14359 { 14360 AnnotateCommand, 14361 DrawCommand, 14362 ColorCommand, 14363 MatteCommand, 14364 CompositeCommand, 14365 AddBorderCommand, 14366 AddFrameCommand, 14367 CommentCommand, 14368 LaunchCommand, 14369 RegionofInterestCommand 14370 }, 14371 MiscellanyCommands[] = 14372 { 14373 InfoCommand, 14374 ZoomCommand, 14375 ShowPreviewCommand, 14376 ShowHistogramCommand, 14377 ShowMatteCommand, 14378 BackgroundCommand, 14379 SlideShowCommand, 14380 PreferencesCommand 14381 }, 14382 HelpCommands[] = 14383 { 14384 HelpCommand, 14385 BrowseDocumentationCommand, 14386 VersionCommand 14387 }, 14388 ShortCutsCommands[] = 14389 { 14390 NextCommand, 14391 FormerCommand, 14392 OpenCommand, 14393 SaveCommand, 14394 PrintCommand, 14395 UndoCommand, 14396 RestoreCommand, 14397 InfoCommand, 14398 QuitCommand 14399 }, 14400 VirtualCommands[] = 14401 { 14402 InfoCommand, 14403 PrintCommand, 14404 NextCommand, 14405 QuitCommand 14406 }; 14407 14408 static CommandType 14409 *Commands[MagickMenus] = 14410 { 14411 FileCommands, 14412 EditCommands, 14413 ViewCommands, 14414 TransformCommands, 14415 EnhanceCommands, 14416 EffectsCommands, 14417 FXCommands, 14418 ImageEditCommands, 14419 MiscellanyCommands, 14420 HelpCommands 14421 }; 14422 14423 char 14424 command[MaxTextExtent], 14425 *directory, 14426 geometry[MaxTextExtent], 14427 resource_name[MaxTextExtent]; 14428 14429 CommandType 14430 command_type; 14431 14432 Image 14433 *display_image, 14434 *nexus; 14435 14436 int 14437 entry, 14438 id; 14439 14440 KeySym 14441 key_symbol; 14442 14443 MagickStatusType 14444 context_mask, 14445 status; 14446 14447 RectangleInfo 14448 geometry_info; 14449 14450 register int 14451 i; 14452 14453 static char 14454 working_directory[MaxTextExtent]; 14455 14456 static XPoint 14457 vid_info; 14458 14459 static XWindowInfo 14460 *magick_windows[MaxXWindows]; 14461 14462 static unsigned int 14463 number_windows; 14464 14465 struct stat 14466 attributes; 14467 14468 time_t 14469 timer, 14470 timestamp, 14471 update_time; 14472 14473 unsigned int 14474 height, 14475 width; 14476 14477 size_t 14478 delay; 14479 14480 WarningHandler 14481 warning_handler; 14482 14483 Window 14484 root_window; 14485 14486 XClassHint 14487 *class_hints; 14488 14489 XEvent 14490 event; 14491 14492 XFontStruct 14493 *font_info; 14494 14495 XGCValues 14496 context_values; 14497 14498 XPixelInfo 14499 *icon_pixel, 14500 *pixel; 14501 14502 XResourceInfo 14503 *icon_resources; 14504 14505 XStandardColormap 14506 *icon_map, 14507 *map_info; 14508 14509 XVisualInfo 14510 *icon_visual, 14511 *visual_info; 14512 14513 XWindowChanges 14514 window_changes; 14515 14516 XWindows 14517 *windows; 14518 14519 XWMHints 14520 *manager_hints; 14521 14522 assert(image != (Image **) NULL); 14523 assert((*image)->signature == MagickSignature); 14524 if ((*image)->debug != MagickFalse) 14525 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14526 display_image=(*image); 14527 warning_handler=(WarningHandler) NULL; 14528 windows=XSetWindows((XWindows *) ~0); 14529 if (windows != (XWindows *) NULL) 14530 { 14531 int 14532 status; 14533 14534 status=chdir(working_directory); 14535 if (status == -1) 14536 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14537 "UnableToOpenFile","%s",working_directory); 14538 warning_handler=resource_info->display_warnings ? 14539 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14540 warning_handler=resource_info->display_warnings ? 14541 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14542 } 14543 else 14544 { 14545 /* 14546 Allocate windows structure. 14547 */ 14548 resource_info->colors=display_image->colors; 14549 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14550 if (windows == (XWindows *) NULL) 14551 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14552 (*image)->filename); 14553 /* 14554 Initialize window id's. 14555 */ 14556 number_windows=0; 14557 magick_windows[number_windows++]=(&windows->icon); 14558 magick_windows[number_windows++]=(&windows->backdrop); 14559 magick_windows[number_windows++]=(&windows->image); 14560 magick_windows[number_windows++]=(&windows->info); 14561 magick_windows[number_windows++]=(&windows->command); 14562 magick_windows[number_windows++]=(&windows->widget); 14563 magick_windows[number_windows++]=(&windows->popup); 14564 magick_windows[number_windows++]=(&windows->magnify); 14565 magick_windows[number_windows++]=(&windows->pan); 14566 for (i=0; i < (int) number_windows; i++) 14567 magick_windows[i]->id=(Window) NULL; 14568 vid_info.x=0; 14569 vid_info.y=0; 14570 } 14571 /* 14572 Initialize font info. 14573 */ 14574 if (windows->font_info != (XFontStruct *) NULL) 14575 (void) XFreeFont(display,windows->font_info); 14576 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14577 if (windows->font_info == (XFontStruct *) NULL) 14578 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14579 resource_info->font); 14580 /* 14581 Initialize Standard Colormap. 14582 */ 14583 map_info=windows->map_info; 14584 icon_map=windows->icon_map; 14585 visual_info=windows->visual_info; 14586 icon_visual=windows->icon_visual; 14587 pixel=windows->pixel_info; 14588 icon_pixel=windows->icon_pixel; 14589 font_info=windows->font_info; 14590 icon_resources=windows->icon_resources; 14591 class_hints=windows->class_hints; 14592 manager_hints=windows->manager_hints; 14593 root_window=XRootWindow(display,visual_info->screen); 14594 nexus=NewImageList(); 14595 if (display_image->debug != MagickFalse) 14596 { 14597 (void) LogMagickEvent(X11Event,GetMagickModule(), 14598 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14599 (double) display_image->scene,(double) display_image->columns, 14600 (double) display_image->rows); 14601 if (display_image->colors != 0) 14602 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14603 display_image->colors); 14604 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14605 display_image->magick); 14606 } 14607 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14608 map_info,pixel,exception); 14609 display_image->taint=MagickFalse; 14610 /* 14611 Initialize graphic context. 14612 */ 14613 windows->context.id=(Window) NULL; 14614 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14615 resource_info,&windows->context); 14616 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14617 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14618 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14619 manager_hints->flags=InputHint | StateHint; 14620 manager_hints->input=MagickFalse; 14621 manager_hints->initial_state=WithdrawnState; 14622 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14623 &windows->context); 14624 if (display_image->debug != MagickFalse) 14625 (void) LogMagickEvent(X11Event,GetMagickModule(), 14626 "Window id: 0x%lx (context)",windows->context.id); 14627 context_values.background=pixel->background_color.pixel; 14628 context_values.font=font_info->fid; 14629 context_values.foreground=pixel->foreground_color.pixel; 14630 context_values.graphics_exposures=MagickFalse; 14631 context_mask=(MagickStatusType) 14632 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14633 if (pixel->annotate_context != (GC) NULL) 14634 (void) XFreeGC(display,pixel->annotate_context); 14635 pixel->annotate_context=XCreateGC(display,windows->context.id, 14636 context_mask,&context_values); 14637 if (pixel->annotate_context == (GC) NULL) 14638 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14639 display_image->filename); 14640 context_values.background=pixel->depth_color.pixel; 14641 if (pixel->widget_context != (GC) NULL) 14642 (void) XFreeGC(display,pixel->widget_context); 14643 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14644 &context_values); 14645 if (pixel->widget_context == (GC) NULL) 14646 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14647 display_image->filename); 14648 context_values.background=pixel->foreground_color.pixel; 14649 context_values.foreground=pixel->background_color.pixel; 14650 context_values.plane_mask=context_values.background ^ 14651 context_values.foreground; 14652 if (pixel->highlight_context != (GC) NULL) 14653 (void) XFreeGC(display,pixel->highlight_context); 14654 pixel->highlight_context=XCreateGC(display,windows->context.id, 14655 (size_t) (context_mask | GCPlaneMask),&context_values); 14656 if (pixel->highlight_context == (GC) NULL) 14657 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14658 display_image->filename); 14659 (void) XDestroyWindow(display,windows->context.id); 14660 /* 14661 Initialize icon window. 14662 */ 14663 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14664 icon_resources,&windows->icon); 14665 windows->icon.geometry=resource_info->icon_geometry; 14666 XBestIconSize(display,&windows->icon,display_image); 14667 windows->icon.attributes.colormap=XDefaultColormap(display, 14668 icon_visual->screen); 14669 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14670 manager_hints->flags=InputHint | StateHint; 14671 manager_hints->input=MagickFalse; 14672 manager_hints->initial_state=IconicState; 14673 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14674 &windows->icon); 14675 if (display_image->debug != MagickFalse) 14676 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14677 windows->icon.id); 14678 /* 14679 Initialize graphic context for icon window. 14680 */ 14681 if (icon_pixel->annotate_context != (GC) NULL) 14682 (void) XFreeGC(display,icon_pixel->annotate_context); 14683 context_values.background=icon_pixel->background_color.pixel; 14684 context_values.foreground=icon_pixel->foreground_color.pixel; 14685 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14686 (size_t) (GCBackground | GCForeground),&context_values); 14687 if (icon_pixel->annotate_context == (GC) NULL) 14688 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14689 display_image->filename); 14690 windows->icon.annotate_context=icon_pixel->annotate_context; 14691 /* 14692 Initialize Image window. 14693 */ 14694 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14695 &windows->image); 14696 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14697 if (resource_info->use_shared_memory == MagickFalse) 14698 windows->image.shared_memory=MagickFalse; 14699 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14700 { 14701 char 14702 *title; 14703 14704 title=InterpretImageProperties(resource_info->image_info,display_image, 14705 resource_info->title,exception); 14706 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14707 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14708 title=DestroyString(title); 14709 } 14710 else 14711 { 14712 char 14713 filename[MaxTextExtent]; 14714 14715 /* 14716 Window name is the base of the filename. 14717 */ 14718 GetPathComponent(display_image->magick_filename,TailPath,filename); 14719 if (display_image->scene == 0) 14720 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14721 "%s: %s",MagickPackageName,filename); 14722 else 14723 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14724 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14725 (double) display_image->scene,(double) GetImageListLength( 14726 display_image)); 14727 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14728 } 14729 if (resource_info->immutable) 14730 windows->image.immutable=MagickTrue; 14731 windows->image.use_pixmap=resource_info->use_pixmap; 14732 windows->image.geometry=resource_info->image_geometry; 14733 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14734 XDisplayWidth(display,visual_info->screen), 14735 XDisplayHeight(display,visual_info->screen)); 14736 geometry_info.width=display_image->columns; 14737 geometry_info.height=display_image->rows; 14738 geometry_info.x=0; 14739 geometry_info.y=0; 14740 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14741 &geometry_info.width,&geometry_info.height); 14742 windows->image.width=(unsigned int) geometry_info.width; 14743 windows->image.height=(unsigned int) geometry_info.height; 14744 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14745 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14746 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14747 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14748 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14749 resource_info,&windows->backdrop); 14750 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14751 { 14752 /* 14753 Initialize backdrop window. 14754 */ 14755 windows->backdrop.x=0; 14756 windows->backdrop.y=0; 14757 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14758 windows->backdrop.flags=(size_t) (USSize | USPosition); 14759 windows->backdrop.width=(unsigned int) 14760 XDisplayWidth(display,visual_info->screen); 14761 windows->backdrop.height=(unsigned int) 14762 XDisplayHeight(display,visual_info->screen); 14763 windows->backdrop.border_width=0; 14764 windows->backdrop.immutable=MagickTrue; 14765 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14766 ButtonReleaseMask; 14767 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14768 StructureNotifyMask; 14769 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14770 manager_hints->icon_window=windows->icon.id; 14771 manager_hints->input=MagickTrue; 14772 manager_hints->initial_state=resource_info->iconic ? IconicState : 14773 NormalState; 14774 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14775 &windows->backdrop); 14776 if (display_image->debug != MagickFalse) 14777 (void) LogMagickEvent(X11Event,GetMagickModule(), 14778 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14779 (void) XMapWindow(display,windows->backdrop.id); 14780 (void) XClearWindow(display,windows->backdrop.id); 14781 if (windows->image.id != (Window) NULL) 14782 { 14783 (void) XDestroyWindow(display,windows->image.id); 14784 windows->image.id=(Window) NULL; 14785 } 14786 /* 14787 Position image in the center the backdrop. 14788 */ 14789 windows->image.flags|=USPosition; 14790 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14791 (windows->image.width/2); 14792 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14793 (windows->image.height/2); 14794 } 14795 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14796 manager_hints->icon_window=windows->icon.id; 14797 manager_hints->input=MagickTrue; 14798 manager_hints->initial_state=resource_info->iconic ? IconicState : 14799 NormalState; 14800 if (windows->group_leader.id != (Window) NULL) 14801 { 14802 /* 14803 Follow the leader. 14804 */ 14805 manager_hints->flags|=WindowGroupHint; 14806 manager_hints->window_group=windows->group_leader.id; 14807 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14808 if (display_image->debug != MagickFalse) 14809 (void) LogMagickEvent(X11Event,GetMagickModule(), 14810 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14811 } 14812 XMakeWindow(display, 14813 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14814 argv,argc,class_hints,manager_hints,&windows->image); 14815 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14816 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14817 if (windows->group_leader.id != (Window) NULL) 14818 (void) XSetTransientForHint(display,windows->image.id, 14819 windows->group_leader.id); 14820 if (display_image->debug != MagickFalse) 14821 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14822 windows->image.id); 14823 /* 14824 Initialize Info widget. 14825 */ 14826 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14827 &windows->info); 14828 (void) CloneString(&windows->info.name,"Info"); 14829 (void) CloneString(&windows->info.icon_name,"Info"); 14830 windows->info.border_width=1; 14831 windows->info.x=2; 14832 windows->info.y=2; 14833 windows->info.flags|=PPosition; 14834 windows->info.attributes.win_gravity=UnmapGravity; 14835 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14836 StructureNotifyMask; 14837 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14838 manager_hints->input=MagickFalse; 14839 manager_hints->initial_state=NormalState; 14840 manager_hints->window_group=windows->image.id; 14841 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14842 &windows->info); 14843 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14844 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14845 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14846 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14847 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14848 if (windows->image.mapped != MagickFalse) 14849 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14850 if (display_image->debug != MagickFalse) 14851 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14852 windows->info.id); 14853 /* 14854 Initialize Command widget. 14855 */ 14856 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14857 resource_info,&windows->command); 14858 windows->command.data=MagickMenus; 14859 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14860 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14861 resource_info->client_name); 14862 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14863 resource_name,"geometry",(char *) NULL); 14864 (void) CloneString(&windows->command.name,MagickTitle); 14865 windows->command.border_width=0; 14866 windows->command.flags|=PPosition; 14867 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14868 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14869 OwnerGrabButtonMask | StructureNotifyMask; 14870 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14871 manager_hints->input=MagickTrue; 14872 manager_hints->initial_state=NormalState; 14873 manager_hints->window_group=windows->image.id; 14874 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14875 &windows->command); 14876 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14877 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14878 HighlightHeight); 14879 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14880 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14881 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14882 if (windows->command.mapped != MagickFalse) 14883 (void) XMapRaised(display,windows->command.id); 14884 if (display_image->debug != MagickFalse) 14885 (void) LogMagickEvent(X11Event,GetMagickModule(), 14886 "Window id: 0x%lx (command)",windows->command.id); 14887 /* 14888 Initialize Widget window. 14889 */ 14890 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14891 resource_info,&windows->widget); 14892 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14893 resource_info->client_name); 14894 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14895 resource_name,"geometry",(char *) NULL); 14896 windows->widget.border_width=0; 14897 windows->widget.flags|=PPosition; 14898 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14899 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14900 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14901 StructureNotifyMask; 14902 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14903 manager_hints->input=MagickTrue; 14904 manager_hints->initial_state=NormalState; 14905 manager_hints->window_group=windows->image.id; 14906 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14907 &windows->widget); 14908 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14909 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14910 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14911 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14912 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14913 if (display_image->debug != MagickFalse) 14914 (void) LogMagickEvent(X11Event,GetMagickModule(), 14915 "Window id: 0x%lx (widget)",windows->widget.id); 14916 /* 14917 Initialize popup window. 14918 */ 14919 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14920 resource_info,&windows->popup); 14921 windows->popup.border_width=0; 14922 windows->popup.flags|=PPosition; 14923 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14924 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14925 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14926 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14927 manager_hints->input=MagickTrue; 14928 manager_hints->initial_state=NormalState; 14929 manager_hints->window_group=windows->image.id; 14930 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14931 &windows->popup); 14932 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14933 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14934 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14935 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14936 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14937 if (display_image->debug != MagickFalse) 14938 (void) LogMagickEvent(X11Event,GetMagickModule(), 14939 "Window id: 0x%lx (pop up)",windows->popup.id); 14940 /* 14941 Initialize Magnify window and cursor. 14942 */ 14943 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14944 resource_info,&windows->magnify); 14945 if (resource_info->use_shared_memory == MagickFalse) 14946 windows->magnify.shared_memory=MagickFalse; 14947 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14948 resource_info->client_name); 14949 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14950 resource_name,"geometry",(char *) NULL); 14951 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14952 resource_info->magnify); 14953 if (windows->magnify.cursor != (Cursor) NULL) 14954 (void) XFreeCursor(display,windows->magnify.cursor); 14955 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14956 map_info->colormap,resource_info->background_color, 14957 resource_info->foreground_color); 14958 if (windows->magnify.cursor == (Cursor) NULL) 14959 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14960 display_image->filename); 14961 windows->magnify.width=MagnifySize; 14962 windows->magnify.height=MagnifySize; 14963 windows->magnify.flags|=PPosition; 14964 windows->magnify.min_width=MagnifySize; 14965 windows->magnify.min_height=MagnifySize; 14966 windows->magnify.width_inc=MagnifySize; 14967 windows->magnify.height_inc=MagnifySize; 14968 windows->magnify.data=resource_info->magnify; 14969 windows->magnify.attributes.cursor=windows->magnify.cursor; 14970 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14971 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14972 StructureNotifyMask; 14973 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14974 manager_hints->input=MagickTrue; 14975 manager_hints->initial_state=NormalState; 14976 manager_hints->window_group=windows->image.id; 14977 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14978 &windows->magnify); 14979 if (display_image->debug != MagickFalse) 14980 (void) LogMagickEvent(X11Event,GetMagickModule(), 14981 "Window id: 0x%lx (magnify)",windows->magnify.id); 14982 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14983 /* 14984 Initialize panning window. 14985 */ 14986 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14987 resource_info,&windows->pan); 14988 (void) CloneString(&windows->pan.name,"Pan Icon"); 14989 windows->pan.width=windows->icon.width; 14990 windows->pan.height=windows->icon.height; 14991 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14992 resource_info->client_name); 14993 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14994 resource_name,"geometry",(char *) NULL); 14995 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14996 &windows->pan.width,&windows->pan.height); 14997 windows->pan.flags|=PPosition; 14998 windows->pan.immutable=MagickTrue; 14999 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15000 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15001 StructureNotifyMask; 15002 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15003 manager_hints->input=MagickFalse; 15004 manager_hints->initial_state=NormalState; 15005 manager_hints->window_group=windows->image.id; 15006 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15007 &windows->pan); 15008 if (display_image->debug != MagickFalse) 15009 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15010 windows->pan.id); 15011 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15012 if (windows->info.mapped != MagickFalse) 15013 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15014 if ((windows->image.mapped == MagickFalse) || 15015 (windows->backdrop.id != (Window) NULL)) 15016 (void) XMapWindow(display,windows->image.id); 15017 /* 15018 Set our progress monitor and warning handlers. 15019 */ 15020 if (warning_handler == (WarningHandler) NULL) 15021 { 15022 warning_handler=resource_info->display_warnings ? 15023 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15024 warning_handler=resource_info->display_warnings ? 15025 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15026 } 15027 /* 15028 Initialize Image and Magnify X images. 15029 */ 15030 windows->image.x=0; 15031 windows->image.y=0; 15032 windows->magnify.shape=MagickFalse; 15033 width=(unsigned int) display_image->columns; 15034 height=(unsigned int) display_image->rows; 15035 if ((display_image->columns != width) || (display_image->rows != height)) 15036 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15037 display_image->filename); 15038 status=XMakeImage(display,resource_info,&windows->image,display_image, 15039 width,height,exception); 15040 if (status == MagickFalse) 15041 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15042 display_image->filename); 15043 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15044 windows->magnify.width,windows->magnify.height,exception); 15045 if (status == MagickFalse) 15046 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15047 display_image->filename); 15048 if (windows->magnify.mapped != MagickFalse) 15049 (void) XMapRaised(display,windows->magnify.id); 15050 if (windows->pan.mapped != MagickFalse) 15051 (void) XMapRaised(display,windows->pan.id); 15052 windows->image.window_changes.width=(int) display_image->columns; 15053 windows->image.window_changes.height=(int) display_image->rows; 15054 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15055 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15056 (void) XSync(display,MagickFalse); 15057 /* 15058 Respond to events. 15059 */ 15060 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15061 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15062 update_time=0; 15063 if (resource_info->update != MagickFalse) 15064 { 15065 MagickBooleanType 15066 status; 15067 15068 /* 15069 Determine when file data was last modified. 15070 */ 15071 status=GetPathAttributes(display_image->filename,&attributes); 15072 if (status != MagickFalse) 15073 update_time=attributes.st_mtime; 15074 } 15075 *state&=(~FormerImageState); 15076 *state&=(~MontageImageState); 15077 *state&=(~NextImageState); 15078 do 15079 { 15080 /* 15081 Handle a window event. 15082 */ 15083 if (windows->image.mapped != MagickFalse) 15084 if ((display_image->delay != 0) || (resource_info->update != 0)) 15085 { 15086 if (timer < time((time_t *) NULL)) 15087 { 15088 if (resource_info->update == MagickFalse) 15089 *state|=NextImageState | ExitState; 15090 else 15091 { 15092 MagickBooleanType 15093 status; 15094 15095 /* 15096 Determine if image file was modified. 15097 */ 15098 status=GetPathAttributes(display_image->filename,&attributes); 15099 if (status != MagickFalse) 15100 if (update_time != attributes.st_mtime) 15101 { 15102 /* 15103 Redisplay image. 15104 */ 15105 (void) FormatLocaleString( 15106 resource_info->image_info->filename,MaxTextExtent, 15107 "%s:%s",display_image->magick, 15108 display_image->filename); 15109 nexus=ReadImage(resource_info->image_info,exception); 15110 if (nexus != (Image *) NULL) 15111 { 15112 nexus=DestroyImage(nexus); 15113 *state|=NextImageState | ExitState; 15114 } 15115 } 15116 delay=display_image->delay/MagickMax( 15117 display_image->ticks_per_second,1L); 15118 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15119 } 15120 } 15121 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15122 { 15123 /* 15124 Do not block if delay > 0. 15125 */ 15126 XDelay(display,SuspendTime << 2); 15127 continue; 15128 } 15129 } 15130 timestamp=time((time_t *) NULL); 15131 (void) XNextEvent(display,&event); 15132 if (windows->image.stasis == MagickFalse) 15133 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15134 MagickTrue : MagickFalse; 15135 if (windows->magnify.stasis == MagickFalse) 15136 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15137 MagickTrue : MagickFalse; 15138 if (event.xany.window == windows->command.id) 15139 { 15140 /* 15141 Select a command from the Command widget. 15142 */ 15143 id=XCommandWidget(display,windows,CommandMenu,&event); 15144 if (id < 0) 15145 continue; 15146 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15147 command_type=CommandMenus[id]; 15148 if (id < MagickMenus) 15149 { 15150 /* 15151 Select a command from a pop-up menu. 15152 */ 15153 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15154 command); 15155 if (entry < 0) 15156 continue; 15157 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15158 command_type=Commands[id][entry]; 15159 } 15160 if (command_type != NullCommand) 15161 nexus=XMagickCommand(display,resource_info,windows,command_type, 15162 &display_image,exception); 15163 continue; 15164 } 15165 switch (event.type) 15166 { 15167 case ButtonPress: 15168 { 15169 if (display_image->debug != MagickFalse) 15170 (void) LogMagickEvent(X11Event,GetMagickModule(), 15171 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15172 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15173 if ((event.xbutton.button == Button3) && 15174 (event.xbutton.state & Mod1Mask)) 15175 { 15176 /* 15177 Convert Alt-Button3 to Button2. 15178 */ 15179 event.xbutton.button=Button2; 15180 event.xbutton.state&=(~Mod1Mask); 15181 } 15182 if (event.xbutton.window == windows->backdrop.id) 15183 { 15184 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15185 event.xbutton.time); 15186 break; 15187 } 15188 if (event.xbutton.window == windows->image.id) 15189 { 15190 switch (event.xbutton.button) 15191 { 15192 case Button1: 15193 { 15194 if (resource_info->immutable) 15195 { 15196 /* 15197 Select a command from the Virtual menu. 15198 */ 15199 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15200 command); 15201 if (entry >= 0) 15202 nexus=XMagickCommand(display,resource_info,windows, 15203 VirtualCommands[entry],&display_image,exception); 15204 break; 15205 } 15206 /* 15207 Map/unmap Command widget. 15208 */ 15209 if (windows->command.mapped != MagickFalse) 15210 (void) XWithdrawWindow(display,windows->command.id, 15211 windows->command.screen); 15212 else 15213 { 15214 (void) XCommandWidget(display,windows,CommandMenu, 15215 (XEvent *) NULL); 15216 (void) XMapRaised(display,windows->command.id); 15217 } 15218 break; 15219 } 15220 case Button2: 15221 { 15222 /* 15223 User pressed the image magnify button. 15224 */ 15225 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15226 &display_image,exception); 15227 XMagnifyImage(display,windows,&event,exception); 15228 break; 15229 } 15230 case Button3: 15231 { 15232 if (resource_info->immutable) 15233 { 15234 /* 15235 Select a command from the Virtual menu. 15236 */ 15237 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15238 command); 15239 if (entry >= 0) 15240 nexus=XMagickCommand(display,resource_info,windows, 15241 VirtualCommands[entry],&display_image,exception); 15242 break; 15243 } 15244 if (display_image->montage != (char *) NULL) 15245 { 15246 /* 15247 Open or delete a tile from a visual image directory. 15248 */ 15249 nexus=XTileImage(display,resource_info,windows, 15250 display_image,&event,exception); 15251 if (nexus != (Image *) NULL) 15252 *state|=MontageImageState | NextImageState | ExitState; 15253 vid_info.x=(short int) windows->image.x; 15254 vid_info.y=(short int) windows->image.y; 15255 break; 15256 } 15257 /* 15258 Select a command from the Short Cuts menu. 15259 */ 15260 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15261 command); 15262 if (entry >= 0) 15263 nexus=XMagickCommand(display,resource_info,windows, 15264 ShortCutsCommands[entry],&display_image,exception); 15265 break; 15266 } 15267 case Button4: 15268 { 15269 /* 15270 Wheel up. 15271 */ 15272 XTranslateImage(display,windows,*image,XK_Up); 15273 break; 15274 } 15275 case Button5: 15276 { 15277 /* 15278 Wheel down. 15279 */ 15280 XTranslateImage(display,windows,*image,XK_Down); 15281 break; 15282 } 15283 default: 15284 break; 15285 } 15286 break; 15287 } 15288 if (event.xbutton.window == windows->magnify.id) 15289 { 15290 int 15291 factor; 15292 15293 static const char 15294 *MagnifyMenu[] = 15295 { 15296 "2", 15297 "4", 15298 "5", 15299 "6", 15300 "7", 15301 "8", 15302 "9", 15303 "3", 15304 (char *) NULL, 15305 }; 15306 15307 static KeySym 15308 MagnifyCommands[] = 15309 { 15310 XK_2, 15311 XK_4, 15312 XK_5, 15313 XK_6, 15314 XK_7, 15315 XK_8, 15316 XK_9, 15317 XK_3 15318 }; 15319 15320 /* 15321 Select a magnify factor from the pop-up menu. 15322 */ 15323 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15324 if (factor >= 0) 15325 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15326 exception); 15327 break; 15328 } 15329 if (event.xbutton.window == windows->pan.id) 15330 { 15331 switch (event.xbutton.button) 15332 { 15333 case Button4: 15334 { 15335 /* 15336 Wheel up. 15337 */ 15338 XTranslateImage(display,windows,*image,XK_Up); 15339 break; 15340 } 15341 case Button5: 15342 { 15343 /* 15344 Wheel down. 15345 */ 15346 XTranslateImage(display,windows,*image,XK_Down); 15347 break; 15348 } 15349 default: 15350 { 15351 XPanImage(display,windows,&event,exception); 15352 break; 15353 } 15354 } 15355 break; 15356 } 15357 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15358 1L); 15359 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15360 break; 15361 } 15362 case ButtonRelease: 15363 { 15364 if (display_image->debug != MagickFalse) 15365 (void) LogMagickEvent(X11Event,GetMagickModule(), 15366 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15367 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15368 break; 15369 } 15370 case ClientMessage: 15371 { 15372 if (display_image->debug != MagickFalse) 15373 (void) LogMagickEvent(X11Event,GetMagickModule(), 15374 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15375 event.xclient.message_type,event.xclient.format,(unsigned long) 15376 event.xclient.data.l[0]); 15377 if (event.xclient.message_type == windows->im_protocols) 15378 { 15379 if (*event.xclient.data.l == (long) windows->im_update_widget) 15380 { 15381 (void) CloneString(&windows->command.name,MagickTitle); 15382 windows->command.data=MagickMenus; 15383 (void) XCommandWidget(display,windows,CommandMenu, 15384 (XEvent *) NULL); 15385 break; 15386 } 15387 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15388 { 15389 /* 15390 Update graphic context and window colormap. 15391 */ 15392 for (i=0; i < (int) number_windows; i++) 15393 { 15394 if (magick_windows[i]->id == windows->icon.id) 15395 continue; 15396 context_values.background=pixel->background_color.pixel; 15397 context_values.foreground=pixel->foreground_color.pixel; 15398 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15399 context_mask,&context_values); 15400 (void) XChangeGC(display,magick_windows[i]->widget_context, 15401 context_mask,&context_values); 15402 context_values.background=pixel->foreground_color.pixel; 15403 context_values.foreground=pixel->background_color.pixel; 15404 context_values.plane_mask=context_values.background ^ 15405 context_values.foreground; 15406 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15407 (size_t) (context_mask | GCPlaneMask), 15408 &context_values); 15409 magick_windows[i]->attributes.background_pixel= 15410 pixel->background_color.pixel; 15411 magick_windows[i]->attributes.border_pixel= 15412 pixel->border_color.pixel; 15413 magick_windows[i]->attributes.colormap=map_info->colormap; 15414 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15415 (unsigned long) magick_windows[i]->mask, 15416 &magick_windows[i]->attributes); 15417 } 15418 if (windows->pan.mapped != MagickFalse) 15419 { 15420 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15421 windows->pan.pixmap); 15422 (void) XClearWindow(display,windows->pan.id); 15423 XDrawPanRectangle(display,windows); 15424 } 15425 if (windows->backdrop.id != (Window) NULL) 15426 (void) XInstallColormap(display,map_info->colormap); 15427 break; 15428 } 15429 if (*event.xclient.data.l == (long) windows->im_former_image) 15430 { 15431 *state|=FormerImageState | ExitState; 15432 break; 15433 } 15434 if (*event.xclient.data.l == (long) windows->im_next_image) 15435 { 15436 *state|=NextImageState | ExitState; 15437 break; 15438 } 15439 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15440 { 15441 *state|=RetainColorsState; 15442 break; 15443 } 15444 if (*event.xclient.data.l == (long) windows->im_exit) 15445 { 15446 *state|=ExitState; 15447 break; 15448 } 15449 break; 15450 } 15451 if (event.xclient.message_type == windows->dnd_protocols) 15452 { 15453 Atom 15454 selection, 15455 type; 15456 15457 int 15458 format, 15459 status; 15460 15461 unsigned char 15462 *data; 15463 15464 unsigned long 15465 after, 15466 length; 15467 15468 /* 15469 Display image named by the Drag-and-Drop selection. 15470 */ 15471 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15472 break; 15473 selection=XInternAtom(display,"DndSelection",MagickFalse); 15474 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15475 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15476 &length,&after,&data); 15477 if ((status != Success) || (length == 0)) 15478 break; 15479 if (*event.xclient.data.l == 2) 15480 { 15481 /* 15482 Offix DND. 15483 */ 15484 (void) CopyMagickString(resource_info->image_info->filename, 15485 (char *) data,MaxTextExtent); 15486 } 15487 else 15488 { 15489 /* 15490 XDND. 15491 */ 15492 if (strncmp((char *) data, "file:", 5) != 0) 15493 { 15494 (void) XFree((void *) data); 15495 break; 15496 } 15497 (void) CopyMagickString(resource_info->image_info->filename, 15498 ((char *) data)+5,MaxTextExtent); 15499 } 15500 nexus=ReadImage(resource_info->image_info,exception); 15501 CatchException(exception); 15502 if (nexus != (Image *) NULL) 15503 *state|=NextImageState | ExitState; 15504 (void) XFree((void *) data); 15505 break; 15506 } 15507 /* 15508 If client window delete message, exit. 15509 */ 15510 if (event.xclient.message_type != windows->wm_protocols) 15511 break; 15512 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15513 break; 15514 (void) XWithdrawWindow(display,event.xclient.window, 15515 visual_info->screen); 15516 if (event.xclient.window == windows->image.id) 15517 { 15518 *state|=ExitState; 15519 break; 15520 } 15521 if (event.xclient.window == windows->pan.id) 15522 { 15523 /* 15524 Restore original image size when pan window is deleted. 15525 */ 15526 windows->image.window_changes.width=windows->image.ximage->width; 15527 windows->image.window_changes.height=windows->image.ximage->height; 15528 (void) XConfigureImage(display,resource_info,windows, 15529 display_image,exception); 15530 } 15531 break; 15532 } 15533 case ConfigureNotify: 15534 { 15535 if (display_image->debug != MagickFalse) 15536 (void) LogMagickEvent(X11Event,GetMagickModule(), 15537 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15538 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15539 event.xconfigure.y,event.xconfigure.send_event); 15540 if (event.xconfigure.window == windows->image.id) 15541 { 15542 /* 15543 Image window has a new configuration. 15544 */ 15545 if (event.xconfigure.send_event != 0) 15546 { 15547 XWindowChanges 15548 window_changes; 15549 15550 /* 15551 Position the transient windows relative of the Image window. 15552 */ 15553 if (windows->command.geometry == (char *) NULL) 15554 if (windows->command.mapped == MagickFalse) 15555 { 15556 windows->command.x=event.xconfigure.x- 15557 windows->command.width-25; 15558 windows->command.y=event.xconfigure.y; 15559 XConstrainWindowPosition(display,&windows->command); 15560 window_changes.x=windows->command.x; 15561 window_changes.y=windows->command.y; 15562 (void) XReconfigureWMWindow(display,windows->command.id, 15563 windows->command.screen,(unsigned int) (CWX | CWY), 15564 &window_changes); 15565 } 15566 if (windows->widget.geometry == (char *) NULL) 15567 if (windows->widget.mapped == MagickFalse) 15568 { 15569 windows->widget.x=event.xconfigure.x+ 15570 event.xconfigure.width/10; 15571 windows->widget.y=event.xconfigure.y+ 15572 event.xconfigure.height/10; 15573 XConstrainWindowPosition(display,&windows->widget); 15574 window_changes.x=windows->widget.x; 15575 window_changes.y=windows->widget.y; 15576 (void) XReconfigureWMWindow(display,windows->widget.id, 15577 windows->widget.screen,(unsigned int) (CWX | CWY), 15578 &window_changes); 15579 } 15580 if (windows->magnify.geometry == (char *) NULL) 15581 if (windows->magnify.mapped == MagickFalse) 15582 { 15583 windows->magnify.x=event.xconfigure.x+ 15584 event.xconfigure.width+25; 15585 windows->magnify.y=event.xconfigure.y; 15586 XConstrainWindowPosition(display,&windows->magnify); 15587 window_changes.x=windows->magnify.x; 15588 window_changes.y=windows->magnify.y; 15589 (void) XReconfigureWMWindow(display,windows->magnify.id, 15590 windows->magnify.screen,(unsigned int) (CWX | CWY), 15591 &window_changes); 15592 } 15593 if (windows->pan.geometry == (char *) NULL) 15594 if (windows->pan.mapped == MagickFalse) 15595 { 15596 windows->pan.x=event.xconfigure.x+ 15597 event.xconfigure.width+25; 15598 windows->pan.y=event.xconfigure.y+ 15599 windows->magnify.height+50; 15600 XConstrainWindowPosition(display,&windows->pan); 15601 window_changes.x=windows->pan.x; 15602 window_changes.y=windows->pan.y; 15603 (void) XReconfigureWMWindow(display,windows->pan.id, 15604 windows->pan.screen,(unsigned int) (CWX | CWY), 15605 &window_changes); 15606 } 15607 } 15608 if ((event.xconfigure.width == (int) windows->image.width) && 15609 (event.xconfigure.height == (int) windows->image.height)) 15610 break; 15611 windows->image.width=(unsigned int) event.xconfigure.width; 15612 windows->image.height=(unsigned int) event.xconfigure.height; 15613 windows->image.x=0; 15614 windows->image.y=0; 15615 if (display_image->montage != (char *) NULL) 15616 { 15617 windows->image.x=vid_info.x; 15618 windows->image.y=vid_info.y; 15619 } 15620 if ((windows->image.mapped != MagickFalse) && 15621 (windows->image.stasis != MagickFalse)) 15622 { 15623 /* 15624 Update image window configuration. 15625 */ 15626 windows->image.window_changes.width=event.xconfigure.width; 15627 windows->image.window_changes.height=event.xconfigure.height; 15628 (void) XConfigureImage(display,resource_info,windows, 15629 display_image,exception); 15630 } 15631 /* 15632 Update pan window configuration. 15633 */ 15634 if ((event.xconfigure.width < windows->image.ximage->width) || 15635 (event.xconfigure.height < windows->image.ximage->height)) 15636 { 15637 (void) XMapRaised(display,windows->pan.id); 15638 XDrawPanRectangle(display,windows); 15639 } 15640 else 15641 if (windows->pan.mapped != MagickFalse) 15642 (void) XWithdrawWindow(display,windows->pan.id, 15643 windows->pan.screen); 15644 break; 15645 } 15646 if (event.xconfigure.window == windows->magnify.id) 15647 { 15648 unsigned int 15649 magnify; 15650 15651 /* 15652 Magnify window has a new configuration. 15653 */ 15654 windows->magnify.width=(unsigned int) event.xconfigure.width; 15655 windows->magnify.height=(unsigned int) event.xconfigure.height; 15656 if (windows->magnify.mapped == MagickFalse) 15657 break; 15658 magnify=1; 15659 while ((int) magnify <= event.xconfigure.width) 15660 magnify<<=1; 15661 while ((int) magnify <= event.xconfigure.height) 15662 magnify<<=1; 15663 magnify>>=1; 15664 if (((int) magnify != event.xconfigure.width) || 15665 ((int) magnify != event.xconfigure.height)) 15666 { 15667 window_changes.width=(int) magnify; 15668 window_changes.height=(int) magnify; 15669 (void) XReconfigureWMWindow(display,windows->magnify.id, 15670 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15671 &window_changes); 15672 break; 15673 } 15674 if ((windows->magnify.mapped != MagickFalse) && 15675 (windows->magnify.stasis != MagickFalse)) 15676 { 15677 status=XMakeImage(display,resource_info,&windows->magnify, 15678 display_image,windows->magnify.width,windows->magnify.height, 15679 exception); 15680 XMakeMagnifyImage(display,windows,exception); 15681 } 15682 break; 15683 } 15684 if ((windows->magnify.mapped != MagickFalse) && 15685 (event.xconfigure.window == windows->pan.id)) 15686 { 15687 /* 15688 Pan icon window has a new configuration. 15689 */ 15690 if (event.xconfigure.send_event != 0) 15691 { 15692 windows->pan.x=event.xconfigure.x; 15693 windows->pan.y=event.xconfigure.y; 15694 } 15695 windows->pan.width=(unsigned int) event.xconfigure.width; 15696 windows->pan.height=(unsigned int) event.xconfigure.height; 15697 break; 15698 } 15699 if (event.xconfigure.window == windows->icon.id) 15700 { 15701 /* 15702 Icon window has a new configuration. 15703 */ 15704 windows->icon.width=(unsigned int) event.xconfigure.width; 15705 windows->icon.height=(unsigned int) event.xconfigure.height; 15706 break; 15707 } 15708 break; 15709 } 15710 case DestroyNotify: 15711 { 15712 /* 15713 Group leader has exited. 15714 */ 15715 if (display_image->debug != MagickFalse) 15716 (void) LogMagickEvent(X11Event,GetMagickModule(), 15717 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15718 if (event.xdestroywindow.window == windows->group_leader.id) 15719 { 15720 *state|=ExitState; 15721 break; 15722 } 15723 break; 15724 } 15725 case EnterNotify: 15726 { 15727 /* 15728 Selectively install colormap. 15729 */ 15730 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15731 if (event.xcrossing.mode != NotifyUngrab) 15732 XInstallColormap(display,map_info->colormap); 15733 break; 15734 } 15735 case Expose: 15736 { 15737 if (display_image->debug != MagickFalse) 15738 (void) LogMagickEvent(X11Event,GetMagickModule(), 15739 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15740 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15741 event.xexpose.y); 15742 /* 15743 Refresh windows that are now exposed. 15744 */ 15745 if ((event.xexpose.window == windows->image.id) && 15746 (windows->image.mapped != MagickFalse)) 15747 { 15748 XRefreshWindow(display,&windows->image,&event); 15749 delay=display_image->delay/MagickMax( 15750 display_image->ticks_per_second,1L); 15751 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15752 break; 15753 } 15754 if ((event.xexpose.window == windows->magnify.id) && 15755 (windows->magnify.mapped != MagickFalse)) 15756 { 15757 XMakeMagnifyImage(display,windows,exception); 15758 break; 15759 } 15760 if (event.xexpose.window == windows->pan.id) 15761 { 15762 XDrawPanRectangle(display,windows); 15763 break; 15764 } 15765 if (event.xexpose.window == windows->icon.id) 15766 { 15767 XRefreshWindow(display,&windows->icon,&event); 15768 break; 15769 } 15770 break; 15771 } 15772 case KeyPress: 15773 { 15774 int 15775 length; 15776 15777 /* 15778 Respond to a user key press. 15779 */ 15780 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15781 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15782 *(command+length)='\0'; 15783 if (display_image->debug != MagickFalse) 15784 (void) LogMagickEvent(X11Event,GetMagickModule(), 15785 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15786 key_symbol,command); 15787 if (event.xkey.window == windows->image.id) 15788 { 15789 command_type=XImageWindowCommand(display,resource_info,windows, 15790 event.xkey.state,key_symbol,&display_image,exception); 15791 if (command_type != NullCommand) 15792 nexus=XMagickCommand(display,resource_info,windows,command_type, 15793 &display_image,exception); 15794 } 15795 if (event.xkey.window == windows->magnify.id) 15796 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15797 exception); 15798 if (event.xkey.window == windows->pan.id) 15799 { 15800 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15801 (void) XWithdrawWindow(display,windows->pan.id, 15802 windows->pan.screen); 15803 else 15804 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15805 XTextViewWidget(display,resource_info,windows,MagickFalse, 15806 "Help Viewer - Image Pan",ImagePanHelp); 15807 else 15808 XTranslateImage(display,windows,*image,key_symbol); 15809 } 15810 delay=display_image->delay/MagickMax( 15811 display_image->ticks_per_second,1L); 15812 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15813 break; 15814 } 15815 case KeyRelease: 15816 { 15817 /* 15818 Respond to a user key release. 15819 */ 15820 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15821 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15822 if (display_image->debug != MagickFalse) 15823 (void) LogMagickEvent(X11Event,GetMagickModule(), 15824 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15825 break; 15826 } 15827 case LeaveNotify: 15828 { 15829 /* 15830 Selectively uninstall colormap. 15831 */ 15832 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15833 if (event.xcrossing.mode != NotifyUngrab) 15834 XUninstallColormap(display,map_info->colormap); 15835 break; 15836 } 15837 case MapNotify: 15838 { 15839 if (display_image->debug != MagickFalse) 15840 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15841 event.xmap.window); 15842 if (event.xmap.window == windows->backdrop.id) 15843 { 15844 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15845 CurrentTime); 15846 windows->backdrop.mapped=MagickTrue; 15847 break; 15848 } 15849 if (event.xmap.window == windows->image.id) 15850 { 15851 if (windows->backdrop.id != (Window) NULL) 15852 (void) XInstallColormap(display,map_info->colormap); 15853 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15854 { 15855 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15856 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15857 } 15858 if (((int) windows->image.width < windows->image.ximage->width) || 15859 ((int) windows->image.height < windows->image.ximage->height)) 15860 (void) XMapRaised(display,windows->pan.id); 15861 windows->image.mapped=MagickTrue; 15862 break; 15863 } 15864 if (event.xmap.window == windows->magnify.id) 15865 { 15866 XMakeMagnifyImage(display,windows,exception); 15867 windows->magnify.mapped=MagickTrue; 15868 (void) XWithdrawWindow(display,windows->info.id, 15869 windows->info.screen); 15870 break; 15871 } 15872 if (event.xmap.window == windows->pan.id) 15873 { 15874 XMakePanImage(display,resource_info,windows,display_image, 15875 exception); 15876 windows->pan.mapped=MagickTrue; 15877 break; 15878 } 15879 if (event.xmap.window == windows->info.id) 15880 { 15881 windows->info.mapped=MagickTrue; 15882 break; 15883 } 15884 if (event.xmap.window == windows->icon.id) 15885 { 15886 MagickBooleanType 15887 taint; 15888 15889 /* 15890 Create an icon image. 15891 */ 15892 taint=display_image->taint; 15893 XMakeStandardColormap(display,icon_visual,icon_resources, 15894 display_image,icon_map,icon_pixel,exception); 15895 (void) XMakeImage(display,icon_resources,&windows->icon, 15896 display_image,windows->icon.width,windows->icon.height, 15897 exception); 15898 display_image->taint=taint; 15899 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15900 windows->icon.pixmap); 15901 (void) XClearWindow(display,windows->icon.id); 15902 (void) XWithdrawWindow(display,windows->info.id, 15903 windows->info.screen); 15904 windows->icon.mapped=MagickTrue; 15905 break; 15906 } 15907 if (event.xmap.window == windows->command.id) 15908 { 15909 windows->command.mapped=MagickTrue; 15910 break; 15911 } 15912 if (event.xmap.window == windows->popup.id) 15913 { 15914 windows->popup.mapped=MagickTrue; 15915 break; 15916 } 15917 if (event.xmap.window == windows->widget.id) 15918 { 15919 windows->widget.mapped=MagickTrue; 15920 break; 15921 } 15922 break; 15923 } 15924 case MappingNotify: 15925 { 15926 (void) XRefreshKeyboardMapping(&event.xmapping); 15927 break; 15928 } 15929 case NoExpose: 15930 break; 15931 case PropertyNotify: 15932 { 15933 Atom 15934 type; 15935 15936 int 15937 format, 15938 status; 15939 15940 unsigned char 15941 *data; 15942 15943 unsigned long 15944 after, 15945 length; 15946 15947 if (display_image->debug != MagickFalse) 15948 (void) LogMagickEvent(X11Event,GetMagickModule(), 15949 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15950 event.xproperty.atom,event.xproperty.state); 15951 if (event.xproperty.atom != windows->im_remote_command) 15952 break; 15953 /* 15954 Display image named by the remote command protocol. 15955 */ 15956 status=XGetWindowProperty(display,event.xproperty.window, 15957 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15958 AnyPropertyType,&type,&format,&length,&after,&data); 15959 if ((status != Success) || (length == 0)) 15960 break; 15961 if (LocaleCompare((char *) data,"-quit") == 0) 15962 { 15963 XClientMessage(display,windows->image.id,windows->im_protocols, 15964 windows->im_exit,CurrentTime); 15965 (void) XFree((void *) data); 15966 break; 15967 } 15968 (void) CopyMagickString(resource_info->image_info->filename, 15969 (char *) data,MaxTextExtent); 15970 (void) XFree((void *) data); 15971 nexus=ReadImage(resource_info->image_info,exception); 15972 CatchException(exception); 15973 if (nexus != (Image *) NULL) 15974 *state|=NextImageState | ExitState; 15975 break; 15976 } 15977 case ReparentNotify: 15978 { 15979 if (display_image->debug != MagickFalse) 15980 (void) LogMagickEvent(X11Event,GetMagickModule(), 15981 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15982 event.xreparent.window); 15983 break; 15984 } 15985 case UnmapNotify: 15986 { 15987 if (display_image->debug != MagickFalse) 15988 (void) LogMagickEvent(X11Event,GetMagickModule(), 15989 "Unmap Notify: 0x%lx",event.xunmap.window); 15990 if (event.xunmap.window == windows->backdrop.id) 15991 { 15992 windows->backdrop.mapped=MagickFalse; 15993 break; 15994 } 15995 if (event.xunmap.window == windows->image.id) 15996 { 15997 windows->image.mapped=MagickFalse; 15998 break; 15999 } 16000 if (event.xunmap.window == windows->magnify.id) 16001 { 16002 windows->magnify.mapped=MagickFalse; 16003 break; 16004 } 16005 if (event.xunmap.window == windows->pan.id) 16006 { 16007 windows->pan.mapped=MagickFalse; 16008 break; 16009 } 16010 if (event.xunmap.window == windows->info.id) 16011 { 16012 windows->info.mapped=MagickFalse; 16013 break; 16014 } 16015 if (event.xunmap.window == windows->icon.id) 16016 { 16017 if (map_info->colormap == icon_map->colormap) 16018 XConfigureImageColormap(display,resource_info,windows, 16019 display_image,exception); 16020 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16021 icon_pixel); 16022 windows->icon.mapped=MagickFalse; 16023 break; 16024 } 16025 if (event.xunmap.window == windows->command.id) 16026 { 16027 windows->command.mapped=MagickFalse; 16028 break; 16029 } 16030 if (event.xunmap.window == windows->popup.id) 16031 { 16032 if (windows->backdrop.id != (Window) NULL) 16033 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16034 CurrentTime); 16035 windows->popup.mapped=MagickFalse; 16036 break; 16037 } 16038 if (event.xunmap.window == windows->widget.id) 16039 { 16040 if (windows->backdrop.id != (Window) NULL) 16041 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16042 CurrentTime); 16043 windows->widget.mapped=MagickFalse; 16044 break; 16045 } 16046 break; 16047 } 16048 default: 16049 { 16050 if (display_image->debug != MagickFalse) 16051 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16052 event.type); 16053 break; 16054 } 16055 } 16056 } while (!(*state & ExitState)); 16057 if ((*state & ExitState) == 0) 16058 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16059 &display_image,exception); 16060 else 16061 if (resource_info->confirm_edit != MagickFalse) 16062 { 16063 /* 16064 Query user if image has changed. 16065 */ 16066 if ((resource_info->immutable == MagickFalse) && 16067 (display_image->taint != MagickFalse)) 16068 { 16069 int 16070 status; 16071 16072 status=XConfirmWidget(display,windows,"Your image changed.", 16073 "Do you want to save it"); 16074 if (status == 0) 16075 *state&=(~ExitState); 16076 else 16077 if (status > 0) 16078 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16079 &display_image,exception); 16080 } 16081 } 16082 if ((windows->visual_info->klass == GrayScale) || 16083 (windows->visual_info->klass == PseudoColor) || 16084 (windows->visual_info->klass == DirectColor)) 16085 { 16086 /* 16087 Withdraw pan and Magnify window. 16088 */ 16089 if (windows->info.mapped != MagickFalse) 16090 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16091 if (windows->magnify.mapped != MagickFalse) 16092 (void) XWithdrawWindow(display,windows->magnify.id, 16093 windows->magnify.screen); 16094 if (windows->command.mapped != MagickFalse) 16095 (void) XWithdrawWindow(display,windows->command.id, 16096 windows->command.screen); 16097 } 16098 if (windows->pan.mapped != MagickFalse) 16099 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16100 if (resource_info->backdrop == MagickFalse) 16101 if (windows->backdrop.mapped) 16102 { 16103 (void) XWithdrawWindow(display,windows->backdrop.id, 16104 windows->backdrop.screen); 16105 (void) XDestroyWindow(display,windows->backdrop.id); 16106 windows->backdrop.id=(Window) NULL; 16107 (void) XWithdrawWindow(display,windows->image.id, 16108 windows->image.screen); 16109 (void) XDestroyWindow(display,windows->image.id); 16110 windows->image.id=(Window) NULL; 16111 } 16112 XSetCursorState(display,windows,MagickTrue); 16113 XCheckRefreshWindows(display,windows); 16114 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16115 *state&=(~ExitState); 16116 if (*state & ExitState) 16117 { 16118 /* 16119 Free Standard Colormap. 16120 */ 16121 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16122 if (resource_info->map_type == (char *) NULL) 16123 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16124 /* 16125 Free X resources. 16126 */ 16127 if (resource_info->copy_image != (Image *) NULL) 16128 { 16129 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16130 resource_info->copy_image=NewImageList(); 16131 } 16132 DestroyXResources(); 16133 } 16134 (void) XSync(display,MagickFalse); 16135 /* 16136 Restore our progress monitor and warning handlers. 16137 */ 16138 (void) SetErrorHandler(warning_handler); 16139 (void) SetWarningHandler(warning_handler); 16140 /* 16141 Change to home directory. 16142 */ 16143 directory=getcwd(working_directory,MaxTextExtent); 16144 (void) directory; 16145 { 16146 int 16147 status; 16148 16149 status=chdir(resource_info->home_directory); 16150 if (status == -1) 16151 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16152 "UnableToOpenFile","%s",resource_info->home_directory); 16153 } 16154 *image=display_image; 16155 return(nexus); 16156} 16157#else 16158 16159/* 16160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16161% % 16162% % 16163% % 16164+ D i s p l a y I m a g e s % 16165% % 16166% % 16167% % 16168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16169% 16170% DisplayImages() displays an image sequence to any X window screen. It 16171% returns a value other than 0 if successful. Check the exception member 16172% of image to determine the reason for any failure. 16173% 16174% The format of the DisplayImages method is: 16175% 16176% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16177% Image *images,ExceptionInfo *exception) 16178% 16179% A description of each parameter follows: 16180% 16181% o image_info: the image info. 16182% 16183% o image: the image. 16184% 16185% o exception: return any errors or warnings in this structure. 16186% 16187*/ 16188MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16189 Image *image,ExceptionInfo *exception) 16190{ 16191 assert(image_info != (const ImageInfo *) NULL); 16192 assert(image_info->signature == MagickSignature); 16193 assert(image != (Image *) NULL); 16194 assert(image->signature == MagickSignature); 16195 if (image->debug != MagickFalse) 16196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16197 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16198 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16199 return(MagickFalse); 16200} 16201 16202/* 16203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16204% % 16205% % 16206% % 16207+ R e m o t e D i s p l a y C o m m a n d % 16208% % 16209% % 16210% % 16211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16212% 16213% RemoteDisplayCommand() encourages a remote display program to display the 16214% specified image filename. 16215% 16216% The format of the RemoteDisplayCommand method is: 16217% 16218% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16219% const char *window,const char *filename,ExceptionInfo *exception) 16220% 16221% A description of each parameter follows: 16222% 16223% o image_info: the image info. 16224% 16225% o window: Specifies the name or id of an X window. 16226% 16227% o filename: the name of the image filename to display. 16228% 16229% o exception: return any errors or warnings in this structure. 16230% 16231*/ 16232MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16233 const char *window,const char *filename,ExceptionInfo *exception) 16234{ 16235 assert(image_info != (const ImageInfo *) NULL); 16236 assert(image_info->signature == MagickSignature); 16237 assert(filename != (char *) NULL); 16238 (void) window; 16239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16240 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16241 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16242 return(MagickFalse); 16243} 16244#endif 16245