display.c revision e2a912b6c9086c98ec838baa0824cd8deca55538
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/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/string_.h" 86#include "MagickCore/string-private.h" 87#include "MagickCore/transform.h" 88#include "MagickCore/threshold.h" 89#include "MagickCore/utility.h" 90#include "MagickCore/utility-private.h" 91#include "MagickCore/version.h" 92#include "MagickCore/widget.h" 93#include "MagickCore/widget-private.h" 94#include "MagickCore/xwindow.h" 95#include "MagickCore/xwindow-private.h" 96 97#if defined(MAGICKCORE_X11_DELEGATE) 98/* 99 Define declarations. 100*/ 101#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 102 103/* 104 Constant declarations. 105*/ 106static const unsigned char 107 HighlightBitmap[8] = 108 { 109 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 110 }, 111 OpaqueBitmap[8] = 112 { 113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 114 }, 115 ShadowBitmap[8] = 116 { 117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 118 }; 119 120static const char 121 *PageSizes[] = 122 { 123 "Letter", 124 "Tabloid", 125 "Ledger", 126 "Legal", 127 "Statement", 128 "Executive", 129 "A3", 130 "A4", 131 "A5", 132 "B4", 133 "B5", 134 "Folio", 135 "Quarto", 136 "10x14", 137 (char *) NULL 138 }; 139 140/* 141 Help widget declarations. 142*/ 143static const char 144 *ImageAnnotateHelp[] = 145 { 146 "In annotate mode, the Command widget has these options:", 147 "", 148 " Font Name", 149 " fixed", 150 " variable", 151 " 5x8", 152 " 6x10", 153 " 7x13bold", 154 " 8x13bold", 155 " 9x15bold", 156 " 10x20", 157 " 12x24", 158 " Browser...", 159 " Font Color", 160 " black", 161 " blue", 162 " cyan", 163 " green", 164 " gray", 165 " red", 166 " magenta", 167 " yellow", 168 " white", 169 " transparent", 170 " Browser...", 171 " Font Color", 172 " black", 173 " blue", 174 " cyan", 175 " green", 176 " gray", 177 " red", 178 " magenta", 179 " yellow", 180 " white", 181 " transparent", 182 " Browser...", 183 " Rotate Text", 184 " -90", 185 " -45", 186 " -30", 187 " 0", 188 " 30", 189 " 45", 190 " 90", 191 " 180", 192 " Dialog...", 193 " Help", 194 " Dismiss", 195 "", 196 "Choose a font name from the Font Name sub-menu. Additional", 197 "font names can be specified with the font browser. You can", 198 "change the menu names by setting the X resources font1", 199 "through font9.", 200 "", 201 "Choose a font color from the Font Color sub-menu.", 202 "Additional font colors can be specified with the color", 203 "browser. You can change the menu colors by setting the X", 204 "resources pen1 through pen9.", 205 "", 206 "If you select the color browser and press Grab, you can", 207 "choose the font color by moving the pointer to the desired", 208 "color on the screen and press any button.", 209 "", 210 "If you choose to rotate the text, choose Rotate Text from the", 211 "menu and select an angle. Typically you will only want to", 212 "rotate one line of text at a time. Depending on the angle you", 213 "choose, subsequent lines may end up overwriting each other.", 214 "", 215 "Choosing a font and its color is optional. The default font", 216 "is fixed and the default color is black. However, you must", 217 "choose a location to begin entering text and press button 1.", 218 "An underscore character will appear at the location of the", 219 "pointer. The cursor changes to a pencil to indicate you are", 220 "in text mode. To exit immediately, press Dismiss.", 221 "", 222 "In text mode, any key presses will display the character at", 223 "the location of the underscore and advance the underscore", 224 "cursor. Enter your text and once completed press Apply to", 225 "finish your image annotation. To correct errors press BACK", 226 "SPACE. To delete an entire line of text, press DELETE. Any", 227 "text that exceeds the boundaries of the image window is", 228 "automagically continued onto the next line.", 229 "", 230 "The actual color you request for the font is saved in the", 231 "image. However, the color that appears in your image window", 232 "may be different. For example, on a monochrome screen the", 233 "text will appear black or white even if you choose the color", 234 "red as the font color. However, the image saved to a file", 235 "with -write is written with red lettering. To assure the", 236 "correct color text in the final image, any PseudoClass image", 237 "is promoted to DirectClass (see miff(5)). To force a", 238 "PseudoClass image to remain PseudoClass, use -colors.", 239 (char *) NULL, 240 }, 241 *ImageChopHelp[] = 242 { 243 "In chop mode, the Command widget has these options:", 244 "", 245 " Direction", 246 " horizontal", 247 " vertical", 248 " Help", 249 " Dismiss", 250 "", 251 "If the you choose the horizontal direction (this the", 252 "default), the area of the image between the two horizontal", 253 "endpoints of the chop line is removed. Otherwise, the area", 254 "of the image between the two vertical endpoints of the chop", 255 "line is removed.", 256 "", 257 "Select a location within the image window to begin your chop,", 258 "press and hold any button. Next, move the pointer to", 259 "another location in the image. As you move a line will", 260 "connect the initial location and the pointer. When you", 261 "release the button, the area within the image to chop is", 262 "determined by which direction you choose from the Command", 263 "widget.", 264 "", 265 "To cancel the image chopping, move the pointer back to the", 266 "starting point of the line and release the button.", 267 (char *) NULL, 268 }, 269 *ImageColorEditHelp[] = 270 { 271 "In color edit mode, the Command widget has these options:", 272 "", 273 " Method", 274 " point", 275 " replace", 276 " floodfill", 277 " filltoborder", 278 " reset", 279 " Pixel Color", 280 " black", 281 " blue", 282 " cyan", 283 " green", 284 " gray", 285 " red", 286 " magenta", 287 " yellow", 288 " white", 289 " Browser...", 290 " Border Color", 291 " black", 292 " blue", 293 " cyan", 294 " green", 295 " gray", 296 " red", 297 " magenta", 298 " yellow", 299 " white", 300 " Browser...", 301 " Fuzz", 302 " 0%", 303 " 2%", 304 " 5%", 305 " 10%", 306 " 15%", 307 " Dialog...", 308 " Undo", 309 " Help", 310 " Dismiss", 311 "", 312 "Choose a color editing method from the Method sub-menu", 313 "of the Command widget. The point method recolors any pixel", 314 "selected with the pointer until the button is released. The", 315 "replace method recolors any pixel that matches the color of", 316 "the pixel you select with a button press. Floodfill recolors", 317 "any pixel that matches the color of the pixel you select with", 318 "a button press and is a neighbor. Whereas filltoborder recolors", 319 "any neighbor pixel that is not the border color. Finally reset", 320 "changes the entire image to the designated color.", 321 "", 322 "Next, choose a pixel color from the Pixel Color sub-menu.", 323 "Additional pixel colors can be specified with the color", 324 "browser. You can change the menu colors by setting the X", 325 "resources pen1 through pen9.", 326 "", 327 "Now press button 1 to select a pixel within the image window", 328 "to change its color. Additional pixels may be recolored as", 329 "prescribed by the method you choose.", 330 "", 331 "If the Magnify widget is mapped, it can be helpful in positioning", 332 "your pointer within the image (refer to button 2).", 333 "", 334 "The actual color you request for the pixels is saved in the", 335 "image. However, the color that appears in your image window", 336 "may be different. For example, on a monochrome screen the", 337 "pixel will appear black or white even if you choose the", 338 "color red as the pixel color. However, the image saved to a", 339 "file with -write is written with red pixels. To assure the", 340 "correct color text in the final image, any PseudoClass image", 341 "is promoted to DirectClass (see miff(5)). To force a", 342 "PseudoClass image to remain PseudoClass, use -colors.", 343 (char *) NULL, 344 }, 345 *ImageCompositeHelp[] = 346 { 347 "First a widget window is displayed requesting you to enter an", 348 "image name. Press Composite, Grab or type a file name.", 349 "Press Cancel if you choose not to create a composite image.", 350 "When you choose Grab, move the pointer to the desired window", 351 "and press any button.", 352 "", 353 "If the Composite image does not have any matte information,", 354 "you are informed and the file browser is displayed again.", 355 "Enter the name of a mask image. The image is typically", 356 "grayscale and the same size as the composite image. If the", 357 "image is not grayscale, it is converted to grayscale and the", 358 "resulting intensities are used as matte information.", 359 "", 360 "A small window appears showing the location of the cursor in", 361 "the image window. You are now in composite mode. To exit", 362 "immediately, press Dismiss. In composite mode, the Command", 363 "widget has these options:", 364 "", 365 " Operators", 366 " Over", 367 " In", 368 " Out", 369 " Atop", 370 " Xor", 371 " Plus", 372 " Minus", 373 " Add", 374 " Subtract", 375 " Difference", 376 " Multiply", 377 " Bumpmap", 378 " Copy", 379 " CopyRed", 380 " CopyGreen", 381 " CopyBlue", 382 " CopyOpacity", 383 " Clear", 384 " Dissolve", 385 " Displace", 386 " Help", 387 " Dismiss", 388 "", 389 "Choose a composite operation from the Operators sub-menu of", 390 "the Command widget. How each operator behaves is described", 391 "below. Image window is the image currently displayed on", 392 "your X server and image is the image obtained with the File", 393 "Browser widget.", 394 "", 395 "Over The result is the union of the two image shapes,", 396 " with image obscuring image window in the region of", 397 " overlap.", 398 "", 399 "In The result is simply image cut by the shape of", 400 " image window. None of the image data of image", 401 " window is in the result.", 402 "", 403 "Out The resulting image is image with the shape of", 404 " image window cut out.", 405 "", 406 "Atop The result is the same shape as image image window,", 407 " with image obscuring image window where the image", 408 " shapes overlap. Note this differs from over", 409 " because the portion of image outside image window's", 410 " shape does not appear in the result.", 411 "", 412 "Xor The result is the image data from both image and", 413 " image window that is outside the overlap region.", 414 " The overlap region is blank.", 415 "", 416 "Plus The result is just the sum of the image data.", 417 " Output values are cropped to QuantumRange (no overflow).", 418 "", 419 "Minus The result of image - image window, with underflow", 420 " cropped to zero.", 421 "", 422 "Add The result of image + image window, with overflow", 423 " wrapping around (mod 256).", 424 "", 425 "Subtract The result of image - image window, with underflow", 426 " wrapping around (mod 256). The add and subtract", 427 " operators can be used to perform reversible", 428 " transformations.", 429 "", 430 "Difference", 431 " The result of abs(image - image window). This", 432 " useful for comparing two very similar images.", 433 "", 434 "Multiply", 435 " The result of image * image window. This", 436 " useful for the creation of drop-shadows.", 437 "", 438 "Bumpmap The result of surface normals from image * image", 439 " window.", 440 "", 441 "Copy The resulting image is image window replaced with", 442 " image. Here the matte information is ignored.", 443 "", 444 "CopyRed The red layer of the image window is replace with", 445 " the red layer of the image. The other layers are", 446 " untouched.", 447 "", 448 "CopyGreen", 449 " The green layer of the image window is replace with", 450 " the green layer of the image. The other layers are", 451 " untouched.", 452 "", 453 "CopyBlue The blue layer of the image window is replace with", 454 " the blue layer of the image. The other layers are", 455 " untouched.", 456 "", 457 "CopyOpacity", 458 " The matte layer of the image window is replace with", 459 " the matte layer of the image. The other layers are", 460 " untouched.", 461 "", 462 "The image compositor requires a matte, or alpha channel in", 463 "the image for some operations. This extra channel usually", 464 "defines a mask which represents a sort of a cookie-cutter", 465 "for the image. This the case when matte is opaque (full", 466 "coverage) for pixels inside the shape, zero outside, and", 467 "between 0 and QuantumRange on the boundary. If image does not", 468 "have a matte channel, it is initialized with 0 for any pixel", 469 "matching in color to pixel location (0,0), otherwise QuantumRange.", 470 "", 471 "If you choose Dissolve, the composite operator becomes Over. The", 472 "image matte channel percent transparency is initialized to factor.", 473 "The image window is initialized to (100-factor). Where factor is the", 474 "value you specify in the Dialog widget.", 475 "", 476 "Displace shifts the image pixels as defined by a displacement", 477 "map. With this option, image is used as a displacement map.", 478 "Black, within the displacement map, is a maximum positive", 479 "displacement. White is a maximum negative displacement and", 480 "middle gray is neutral. The displacement is scaled to determine", 481 "the pixel shift. By default, the displacement applies in both the", 482 "horizontal and vertical directions. However, if you specify a mask,", 483 "image is the horizontal X displacement and mask the vertical Y", 484 "displacement.", 485 "", 486 "Note that matte information for image window is not retained", 487 "for colormapped X server visuals (e.g. StaticColor,", 488 "StaticColor, GrayScale, PseudoColor). Correct compositing", 489 "behavior may require a TrueColor or DirectColor visual or a", 490 "Standard Colormap.", 491 "", 492 "Choosing a composite operator is optional. The default", 493 "operator is replace. However, you must choose a location to", 494 "composite your image and press button 1. Press and hold the", 495 "button before releasing and an outline of the image will", 496 "appear to help you identify your location.", 497 "", 498 "The actual colors of the composite image is saved. However,", 499 "the color that appears in image window may be different.", 500 "For example, on a monochrome screen image window will appear", 501 "black or white even though your composited image may have", 502 "many colors. If the image is saved to a file it is written", 503 "with the correct colors. To assure the correct colors are", 504 "saved in the final image, any PseudoClass image is promoted", 505 "to DirectClass (see miff(5)). To force a PseudoClass image", 506 "to remain PseudoClass, use -colors.", 507 (char *) NULL, 508 }, 509 *ImageCutHelp[] = 510 { 511 "In cut mode, the Command widget has these options:", 512 "", 513 " Help", 514 " Dismiss", 515 "", 516 "To define a cut region, press button 1 and drag. The", 517 "cut region is defined by a highlighted rectangle that", 518 "expands or contracts as it follows the pointer. Once you", 519 "are satisfied with the cut region, release the button.", 520 "You are now in rectify mode. In rectify mode, the Command", 521 "widget has these options:", 522 "", 523 " Cut", 524 " Help", 525 " Dismiss", 526 "", 527 "You can make adjustments by moving the pointer to one of the", 528 "cut rectangle corners, pressing a button, and dragging.", 529 "Finally, press Cut to commit your copy region. To", 530 "exit without cutting the image, press Dismiss.", 531 (char *) NULL, 532 }, 533 *ImageCopyHelp[] = 534 { 535 "In copy mode, the Command widget has these options:", 536 "", 537 " Help", 538 " Dismiss", 539 "", 540 "To define a copy region, press button 1 and drag. The", 541 "copy region is defined by a highlighted rectangle that", 542 "expands or contracts as it follows the pointer. Once you", 543 "are satisfied with the copy region, release the button.", 544 "You are now in rectify mode. In rectify mode, the Command", 545 "widget has these options:", 546 "", 547 " Copy", 548 " Help", 549 " Dismiss", 550 "", 551 "You can make adjustments by moving the pointer to one of the", 552 "copy rectangle corners, pressing a button, and dragging.", 553 "Finally, press Copy to commit your copy region. To", 554 "exit without copying the image, press Dismiss.", 555 (char *) NULL, 556 }, 557 *ImageCropHelp[] = 558 { 559 "In crop mode, the Command widget has these options:", 560 "", 561 " Help", 562 " Dismiss", 563 "", 564 "To define a cropping region, press button 1 and drag. The", 565 "cropping region is defined by a highlighted rectangle that", 566 "expands or contracts as it follows the pointer. Once you", 567 "are satisfied with the cropping region, release the button.", 568 "You are now in rectify mode. In rectify mode, the Command", 569 "widget has these options:", 570 "", 571 " Crop", 572 " Help", 573 " Dismiss", 574 "", 575 "You can make adjustments by moving the pointer to one of the", 576 "cropping rectangle corners, pressing a button, and dragging.", 577 "Finally, press Crop to commit your cropping region. To", 578 "exit without cropping the image, press Dismiss.", 579 (char *) NULL, 580 }, 581 *ImageDrawHelp[] = 582 { 583 "The cursor changes to a crosshair to indicate you are in", 584 "draw mode. To exit immediately, press Dismiss. In draw mode,", 585 "the Command widget has these options:", 586 "", 587 " Element", 588 " point", 589 " line", 590 " rectangle", 591 " fill rectangle", 592 " circle", 593 " fill circle", 594 " ellipse", 595 " fill ellipse", 596 " polygon", 597 " fill polygon", 598 " Color", 599 " black", 600 " blue", 601 " cyan", 602 " green", 603 " gray", 604 " red", 605 " magenta", 606 " yellow", 607 " white", 608 " transparent", 609 " Browser...", 610 " Stipple", 611 " Brick", 612 " Diagonal", 613 " Scales", 614 " Vertical", 615 " Wavy", 616 " Translucent", 617 " Opaque", 618 " Open...", 619 " Width", 620 " 1", 621 " 2", 622 " 4", 623 " 8", 624 " 16", 625 " Dialog...", 626 " Undo", 627 " Help", 628 " Dismiss", 629 "", 630 "Choose a drawing primitive from the Element sub-menu.", 631 "", 632 "Choose a color from the Color sub-menu. Additional", 633 "colors can be specified with the color browser.", 634 "", 635 "If you choose the color browser and press Grab, you can", 636 "select the color by moving the pointer to the desired", 637 "color on the screen and press any button. The transparent", 638 "color updates the image matte channel and is useful for", 639 "image compositing.", 640 "", 641 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 642 "Additional stipples can be specified with the file browser.", 643 "Stipples obtained from the file browser must be on disk in the", 644 "X11 bitmap format.", 645 "", 646 "Choose a width, if appropriate, from the Width sub-menu. To", 647 "choose a specific width select the Dialog widget.", 648 "", 649 "Choose a point in the Image window and press button 1 and", 650 "hold. Next, move the pointer to another location in the", 651 "image. As you move, a line connects the initial location and", 652 "the pointer. When you release the button, the image is", 653 "updated with the primitive you just drew. For polygons, the", 654 "image is updated when you press and release the button without", 655 "moving the pointer.", 656 "", 657 "To cancel image drawing, move the pointer back to the", 658 "starting point of the line and release the button.", 659 (char *) NULL, 660 }, 661 *DisplayHelp[] = 662 { 663 "BUTTONS", 664 " The effects of each button press is described below. Three", 665 " buttons are required. If you have a two button mouse,", 666 " button 1 and 3 are returned. Press ALT and button 3 to", 667 " simulate button 2.", 668 "", 669 " 1 Press this button to map or unmap the Command widget.", 670 "", 671 " 2 Press and drag to define a region of the image to", 672 " magnify.", 673 "", 674 " 3 Press and drag to choose from a select set of commands.", 675 " This button behaves differently if the image being", 676 " displayed is a visual image directory. Here, choose a", 677 " particular tile of the directory and press this button and", 678 " drag to select a command from a pop-up menu. Choose from", 679 " these menu items:", 680 "", 681 " Open", 682 " Next", 683 " Former", 684 " Delete", 685 " Update", 686 "", 687 " If you choose Open, the image represented by the tile is", 688 " displayed. To return to the visual image directory, choose", 689 " Next from the Command widget. Next and Former moves to the", 690 " next or former image respectively. Choose Delete to delete", 691 " a particular image tile. Finally, choose Update to", 692 " synchronize all the image tiles with their respective", 693 " images.", 694 "", 695 "COMMAND WIDGET", 696 " The Command widget lists a number of sub-menus and commands.", 697 " They are", 698 "", 699 " File", 700 " Open...", 701 " Next", 702 " Former", 703 " Select...", 704 " Save...", 705 " Print...", 706 " Delete...", 707 " New...", 708 " Visual Directory...", 709 " Quit", 710 " Edit", 711 " Undo", 712 " Redo", 713 " Cut", 714 " Copy", 715 " Paste", 716 " View", 717 " Half Size", 718 " Original Size", 719 " Double Size", 720 " Resize...", 721 " Apply", 722 " Refresh", 723 " Restore", 724 " Transform", 725 " Crop", 726 " Chop", 727 " Flop", 728 " Flip", 729 " Rotate Right", 730 " Rotate Left", 731 " Rotate...", 732 " Shear...", 733 " Roll...", 734 " Trim Edges", 735 " Enhance", 736 " Brightness...", 737 " Saturation...", 738 " Hue...", 739 " Gamma...", 740 " Sharpen...", 741 " Dull", 742 " Contrast Stretch...", 743 " Sigmoidal Contrast...", 744 " Normalize", 745 " Equalize", 746 " Negate", 747 " Grayscale", 748 " Map...", 749 " Quantize...", 750 " Effects", 751 " Despeckle", 752 " Emboss", 753 " Reduce Noise", 754 " Add Noise", 755 " Sharpen...", 756 " Blur...", 757 " Threshold...", 758 " Edge Detect...", 759 " Spread...", 760 " Shade...", 761 " Painting...", 762 " Segment...", 763 " F/X", 764 " Solarize...", 765 " Sepia Tone...", 766 " Swirl...", 767 " Implode...", 768 " Vignette...", 769 " Wave...", 770 " Oil Painting...", 771 " Charcoal Drawing...", 772 " Image Edit", 773 " Annotate...", 774 " Draw...", 775 " Color...", 776 " Matte...", 777 " Composite...", 778 " Add Border...", 779 " Add Frame...", 780 " Comment...", 781 " Launch...", 782 " Region of Interest...", 783 " Miscellany", 784 " Image Info", 785 " Zoom Image", 786 " Show Preview...", 787 " Show Histogram", 788 " Show Matte", 789 " Background...", 790 " Slide Show", 791 " Preferences...", 792 " Help", 793 " Overview", 794 " Browse Documentation", 795 " About Display", 796 "", 797 " Menu items with a indented triangle have a sub-menu. They", 798 " are represented above as the indented items. To access a", 799 " sub-menu item, move the pointer to the appropriate menu and", 800 " press a button and drag. When you find the desired sub-menu", 801 " item, release the button and the command is executed. Move", 802 " the pointer away from the sub-menu if you decide not to", 803 " execute a particular command.", 804 "", 805 "KEYBOARD ACCELERATORS", 806 " Accelerators are one or two key presses that effect a", 807 " particular command. The keyboard accelerators that", 808 " display(1) understands is:", 809 "", 810 " Ctl+O Press to open an image from a file.", 811 "", 812 " space Press to display the next image.", 813 "", 814 " If the image is a multi-paged document such as a Postscript", 815 " document, you can skip ahead several pages by preceding", 816 " this command with a number. For example to display the", 817 " third page beyond the current page, press 3<space>.", 818 "", 819 " backspace Press to display the former image.", 820 "", 821 " If the image is a multi-paged document such as a Postscript", 822 " document, you can skip behind several pages by preceding", 823 " this command with a number. For example to display the", 824 " third page preceding the current page, press 3<backspace>.", 825 "", 826 " Ctl+S Press to write the image to a file.", 827 "", 828 " Ctl+P Press to print the image to a Postscript printer.", 829 "", 830 " Ctl+D Press to delete an image file.", 831 "", 832 " Ctl+N Press to create a blank canvas.", 833 "", 834 " Ctl+Q Press to discard all images and exit program.", 835 "", 836 " Ctl+Z Press to undo last image transformation.", 837 "", 838 " Ctl+R Press to redo last image transformation.", 839 "", 840 " Ctl+X Press to cut a region of the image.", 841 "", 842 " Ctl+C Press to copy a region of the image.", 843 "", 844 " Ctl+V Press to paste a region to the image.", 845 "", 846 " < Press to half the image size.", 847 "", 848 " - Press to return to the original image size.", 849 "", 850 " > Press to double the image size.", 851 "", 852 " % Press to resize the image to a width and height you", 853 " specify.", 854 "", 855 "Cmd-A Press to make any image transformations permanent." 856 "", 857 " By default, any image size transformations are applied", 858 " to the original image to create the image displayed on", 859 " the X server. However, the transformations are not", 860 " permanent (i.e. the original image does not change", 861 " size only the X image does). For example, if you", 862 " press > the X image will appear to double in size,", 863 " but the original image will in fact remain the same size.", 864 " To force the original image to double in size, press >", 865 " followed by Cmd-A.", 866 "", 867 " @ Press to refresh the image window.", 868 "", 869 " C Press to cut out a rectangular region of the image.", 870 "", 871 " [ Press to chop the image.", 872 "", 873 " H Press to flop image in the horizontal direction.", 874 "", 875 " V Press to flip image in the vertical direction.", 876 "", 877 " / Press to rotate the image 90 degrees clockwise.", 878 "", 879 " \\ Press to rotate the image 90 degrees counter-clockwise.", 880 "", 881 " * Press to rotate the image the number of degrees you", 882 " specify.", 883 "", 884 " S Press to shear the image the number of degrees you", 885 " specify.", 886 "", 887 " R Press to roll the image.", 888 "", 889 " T Press to trim the image edges.", 890 "", 891 " Shft-H Press to vary the image hue.", 892 "", 893 " Shft-S Press to vary the color saturation.", 894 "", 895 " Shft-L Press to vary the color brightness.", 896 "", 897 " Shft-G Press to gamma correct the image.", 898 "", 899 " Shft-C Press to sharpen the image contrast.", 900 "", 901 " Shft-Z Press to dull the image contrast.", 902 "", 903 " = Press to perform histogram equalization on the image.", 904 "", 905 " Shft-N Press to perform histogram normalization on the image.", 906 "", 907 " Shft-~ Press to negate the colors of the image.", 908 "", 909 " . Press to convert the image colors to gray.", 910 "", 911 " Shft-# Press to set the maximum number of unique colors in the", 912 " image.", 913 "", 914 " F2 Press to reduce the speckles in an image.", 915 "", 916 " F3 Press to eliminate peak noise from an image.", 917 "", 918 " F4 Press to add noise to an image.", 919 "", 920 " F5 Press to sharpen an image.", 921 "", 922 " F6 Press to delete an image file.", 923 "", 924 " F7 Press to threshold the image.", 925 "", 926 " F8 Press to detect edges within an image.", 927 "", 928 " F9 Press to emboss an image.", 929 "", 930 " F10 Press to displace pixels by a random amount.", 931 "", 932 " F11 Press to negate all pixels above the threshold level.", 933 "", 934 " F12 Press to shade the image using a distant light source.", 935 "", 936 " F13 Press to lighten or darken image edges to create a 3-D effect.", 937 "", 938 " F14 Press to segment the image by color.", 939 "", 940 " Meta-S Press to swirl image pixels about the center.", 941 "", 942 " Meta-I Press to implode image pixels about the center.", 943 "", 944 " Meta-W Press to alter an image along a sine wave.", 945 "", 946 " Meta-P Press to simulate an oil painting.", 947 "", 948 " Meta-C Press to simulate a charcoal drawing.", 949 "", 950 " Alt-A Press to annotate the image with text.", 951 "", 952 " Alt-D Press to draw on an image.", 953 "", 954 " Alt-P Press to edit an image pixel color.", 955 "", 956 " Alt-M Press to edit the image matte information.", 957 "", 958 " Alt-V Press to composite the image with another.", 959 "", 960 " Alt-B Press to add a border to the image.", 961 "", 962 " Alt-F Press to add an ornamental border to the image.", 963 "", 964 " Alt-Shft-!", 965 " Press to add an image comment.", 966 "", 967 " Ctl-A Press to apply image processing techniques to a region", 968 " of interest.", 969 "", 970 " Shft-? Press to display information about the image.", 971 "", 972 " Shft-+ Press to map the zoom image window.", 973 "", 974 " Shft-P Press to preview an image enhancement, effect, or f/x.", 975 "", 976 " F1 Press to display helpful information about display(1).", 977 "", 978 " Find Press to browse documentation about ImageMagick.", 979 "", 980 " 1-9 Press to change the level of magnification.", 981 "", 982 " Use the arrow keys to move the image one pixel up, down,", 983 " left, or right within the magnify window. Be sure to first", 984 " map the magnify window by pressing button 2.", 985 "", 986 " Press ALT and one of the arrow keys to trim off one pixel", 987 " from any side of the image.", 988 (char *) NULL, 989 }, 990 *ImageMatteEditHelp[] = 991 { 992 "Matte information within an image is useful for some", 993 "operations such as image compositing (See IMAGE", 994 "COMPOSITING). This extra channel usually defines a mask", 995 "which represents a sort of a cookie-cutter for the image.", 996 "This the case when matte is opaque (full coverage) for", 997 "pixels inside the shape, zero outside, and between 0 and", 998 "QuantumRange on the boundary.", 999 "", 1000 "A small window appears showing the location of the cursor in", 1001 "the image window. You are now in matte edit mode. To exit", 1002 "immediately, press Dismiss. In matte edit mode, the Command", 1003 "widget has these options:", 1004 "", 1005 " Method", 1006 " point", 1007 " replace", 1008 " floodfill", 1009 " filltoborder", 1010 " reset", 1011 " Border Color", 1012 " black", 1013 " blue", 1014 " cyan", 1015 " green", 1016 " gray", 1017 " red", 1018 " magenta", 1019 " yellow", 1020 " white", 1021 " Browser...", 1022 " Fuzz", 1023 " 0%", 1024 " 2%", 1025 " 5%", 1026 " 10%", 1027 " 15%", 1028 " Dialog...", 1029 " Matte", 1030 " Opaque", 1031 " Transparent", 1032 " Dialog...", 1033 " Undo", 1034 " Help", 1035 " Dismiss", 1036 "", 1037 "Choose a matte editing method from the Method sub-menu of", 1038 "the Command widget. The point method changes the matte value", 1039 "of any pixel selected with the pointer until the button is", 1040 "is released. The replace method changes the matte value of", 1041 "any pixel that matches the color of the pixel you select with", 1042 "a button press. Floodfill changes the matte value of any pixel", 1043 "that matches the color of the pixel you select with a button", 1044 "press and is a neighbor. Whereas filltoborder changes the matte", 1045 "value any neighbor pixel that is not the border color. Finally", 1046 "reset changes the entire image to the designated matte value.", 1047 "", 1048 "Choose Matte Value and pick Opaque or Transarent. For other values", 1049 "select the Dialog entry. Here a dialog appears requesting a matte", 1050 "value. The value you select is assigned as the opacity value of the", 1051 "selected pixel or pixels.", 1052 "", 1053 "Now, press any button to select a pixel within the image", 1054 "window to change its matte value.", 1055 "", 1056 "If the Magnify widget is mapped, it can be helpful in positioning", 1057 "your pointer within the image (refer to button 2).", 1058 "", 1059 "Matte information is only valid in a DirectClass image.", 1060 "Therefore, any PseudoClass image is promoted to DirectClass", 1061 "(see miff(5)). Note that matte information for PseudoClass", 1062 "is not retained for colormapped X server visuals (e.g.", 1063 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1064 "immediately save your image to a file (refer to Write).", 1065 "Correct matte editing behavior may require a TrueColor or", 1066 "DirectColor visual or a Standard Colormap.", 1067 (char *) NULL, 1068 }, 1069 *ImagePanHelp[] = 1070 { 1071 "When an image exceeds the width or height of the X server", 1072 "screen, display maps a small panning icon. The rectangle", 1073 "within the panning icon shows the area that is currently", 1074 "displayed in the image window. To pan about the image,", 1075 "press any button and drag the pointer within the panning", 1076 "icon. The pan rectangle moves with the pointer and the", 1077 "image window is updated to reflect the location of the", 1078 "rectangle within the panning icon. When you have selected", 1079 "the area of the image you wish to view, release the button.", 1080 "", 1081 "Use the arrow keys to pan the image one pixel up, down,", 1082 "left, or right within the image window.", 1083 "", 1084 "The panning icon is withdrawn if the image becomes smaller", 1085 "than the dimensions of the X server screen.", 1086 (char *) NULL, 1087 }, 1088 *ImagePasteHelp[] = 1089 { 1090 "A small window appears showing the location of the cursor in", 1091 "the image window. You are now in paste mode. To exit", 1092 "immediately, press Dismiss. In paste mode, the Command", 1093 "widget has these options:", 1094 "", 1095 " Operators", 1096 " over", 1097 " in", 1098 " out", 1099 " atop", 1100 " xor", 1101 " plus", 1102 " minus", 1103 " add", 1104 " subtract", 1105 " difference", 1106 " replace", 1107 " Help", 1108 " Dismiss", 1109 "", 1110 "Choose a composite operation from the Operators sub-menu of", 1111 "the Command widget. How each operator behaves is described", 1112 "below. Image window is the image currently displayed on", 1113 "your X server and image is the image obtained with the File", 1114 "Browser widget.", 1115 "", 1116 "Over The result is the union of the two image shapes,", 1117 " with image obscuring image window in the region of", 1118 " overlap.", 1119 "", 1120 "In The result is simply image cut by the shape of", 1121 " image window. None of the image data of image", 1122 " window is in the result.", 1123 "", 1124 "Out The resulting image is image with the shape of", 1125 " image window cut out.", 1126 "", 1127 "Atop The result is the same shape as image image window,", 1128 " with image obscuring image window where the image", 1129 " shapes overlap. Note this differs from over", 1130 " because the portion of image outside image window's", 1131 " shape does not appear in the result.", 1132 "", 1133 "Xor The result is the image data from both image and", 1134 " image window that is outside the overlap region.", 1135 " The overlap region is blank.", 1136 "", 1137 "Plus The result is just the sum of the image data.", 1138 " Output values are cropped to QuantumRange (no overflow).", 1139 " This operation is independent of the matte", 1140 " channels.", 1141 "", 1142 "Minus The result of image - image window, with underflow", 1143 " cropped to zero.", 1144 "", 1145 "Add The result of image + image window, with overflow", 1146 " wrapping around (mod 256).", 1147 "", 1148 "Subtract The result of image - image window, with underflow", 1149 " wrapping around (mod 256). The add and subtract", 1150 " operators can be used to perform reversible", 1151 " transformations.", 1152 "", 1153 "Difference", 1154 " The result of abs(image - image window). This", 1155 " useful for comparing two very similar images.", 1156 "", 1157 "Copy The resulting image is image window replaced with", 1158 " image. Here the matte information is ignored.", 1159 "", 1160 "CopyRed The red layer of the image window is replace with", 1161 " the red layer of the image. The other layers are", 1162 " untouched.", 1163 "", 1164 "CopyGreen", 1165 " The green layer of the image window is replace with", 1166 " the green layer of the image. The other layers are", 1167 " untouched.", 1168 "", 1169 "CopyBlue The blue layer of the image window is replace with", 1170 " the blue layer of the image. The other layers are", 1171 " untouched.", 1172 "", 1173 "CopyOpacity", 1174 " The matte layer of the image window is replace with", 1175 " the matte layer of the image. The other layers are", 1176 " untouched.", 1177 "", 1178 "The image compositor requires a matte, or alpha channel in", 1179 "the image for some operations. This extra channel usually", 1180 "defines a mask which represents a sort of a cookie-cutter", 1181 "for the image. This the case when matte is opaque (full", 1182 "coverage) for pixels inside the shape, zero outside, and", 1183 "between 0 and QuantumRange on the boundary. If image does not", 1184 "have a matte channel, it is initialized with 0 for any pixel", 1185 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1186 "", 1187 "Note that matte information for image window is not retained", 1188 "for colormapped X server visuals (e.g. StaticColor,", 1189 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1190 "behavior may require a TrueColor or DirectColor visual or a", 1191 "Standard Colormap.", 1192 "", 1193 "Choosing a composite operator is optional. The default", 1194 "operator is replace. However, you must choose a location to", 1195 "paste your image and press button 1. Press and hold the", 1196 "button before releasing and an outline of the image will", 1197 "appear to help you identify your location.", 1198 "", 1199 "The actual colors of the pasted image is saved. However,", 1200 "the color that appears in image window may be different.", 1201 "For example, on a monochrome screen image window will appear", 1202 "black or white even though your pasted image may have", 1203 "many colors. If the image is saved to a file it is written", 1204 "with the correct colors. To assure the correct colors are", 1205 "saved in the final image, any PseudoClass image is promoted", 1206 "to DirectClass (see miff(5)). To force a PseudoClass image", 1207 "to remain PseudoClass, use -colors.", 1208 (char *) NULL, 1209 }, 1210 *ImageROIHelp[] = 1211 { 1212 "In region of interest mode, the Command widget has these", 1213 "options:", 1214 "", 1215 " Help", 1216 " Dismiss", 1217 "", 1218 "To define a region of interest, press button 1 and drag.", 1219 "The region of interest is defined by a highlighted rectangle", 1220 "that expands or contracts as it follows the pointer. Once", 1221 "you are satisfied with the region of interest, release the", 1222 "button. You are now in apply mode. In apply mode the", 1223 "Command widget has these options:", 1224 "", 1225 " File", 1226 " Save...", 1227 " Print...", 1228 " Edit", 1229 " Undo", 1230 " Redo", 1231 " Transform", 1232 " Flop", 1233 " Flip", 1234 " Rotate Right", 1235 " Rotate Left", 1236 " Enhance", 1237 " Hue...", 1238 " Saturation...", 1239 " Brightness...", 1240 " Gamma...", 1241 " Spiff", 1242 " Dull", 1243 " Contrast Stretch", 1244 " Sigmoidal Contrast...", 1245 " Normalize", 1246 " Equalize", 1247 " Negate", 1248 " Grayscale", 1249 " Map...", 1250 " Quantize...", 1251 " Effects", 1252 " Despeckle", 1253 " Emboss", 1254 " Reduce Noise", 1255 " Sharpen...", 1256 " Blur...", 1257 " Threshold...", 1258 " Edge Detect...", 1259 " Spread...", 1260 " Shade...", 1261 " Raise...", 1262 " Segment...", 1263 " F/X", 1264 " Solarize...", 1265 " Sepia Tone...", 1266 " Swirl...", 1267 " Implode...", 1268 " Vignette...", 1269 " Wave...", 1270 " Oil Painting...", 1271 " Charcoal Drawing...", 1272 " Miscellany", 1273 " Image Info", 1274 " Zoom Image", 1275 " Show Preview...", 1276 " Show Histogram", 1277 " Show Matte", 1278 " Help", 1279 " Dismiss", 1280 "", 1281 "You can make adjustments to the region of interest by moving", 1282 "the pointer to one of the rectangle corners, pressing a", 1283 "button, and dragging. Finally, choose an image processing", 1284 "technique from the Command widget. You can choose more than", 1285 "one image processing technique to apply to an area.", 1286 "Alternatively, you can move the region of interest before", 1287 "applying another image processing technique. To exit, press", 1288 "Dismiss.", 1289 (char *) NULL, 1290 }, 1291 *ImageRotateHelp[] = 1292 { 1293 "In rotate mode, the Command widget has these options:", 1294 "", 1295 " Pixel Color", 1296 " black", 1297 " blue", 1298 " cyan", 1299 " green", 1300 " gray", 1301 " red", 1302 " magenta", 1303 " yellow", 1304 " white", 1305 " Browser...", 1306 " Direction", 1307 " horizontal", 1308 " vertical", 1309 " Help", 1310 " Dismiss", 1311 "", 1312 "Choose a background color from the Pixel Color sub-menu.", 1313 "Additional background colors can be specified with the color", 1314 "browser. You can change the menu colors by setting the X", 1315 "resources pen1 through pen9.", 1316 "", 1317 "If you choose the color browser and press Grab, you can", 1318 "select the background color by moving the pointer to the", 1319 "desired color on the screen and press any button.", 1320 "", 1321 "Choose a point in the image window and press this button and", 1322 "hold. Next, move the pointer to another location in the", 1323 "image. As you move a line connects the initial location and", 1324 "the pointer. When you release the button, the degree of", 1325 "image rotation is determined by the slope of the line you", 1326 "just drew. The slope is relative to the direction you", 1327 "choose from the Direction sub-menu of the Command widget.", 1328 "", 1329 "To cancel the image rotation, move the pointer back to the", 1330 "starting point of the line and release the button.", 1331 (char *) NULL, 1332 }; 1333 1334/* 1335 Enumeration declarations. 1336*/ 1337typedef enum 1338{ 1339 CopyMode, 1340 CropMode, 1341 CutMode 1342} ClipboardMode; 1343 1344typedef enum 1345{ 1346 OpenCommand, 1347 NextCommand, 1348 FormerCommand, 1349 SelectCommand, 1350 SaveCommand, 1351 PrintCommand, 1352 DeleteCommand, 1353 NewCommand, 1354 VisualDirectoryCommand, 1355 QuitCommand, 1356 UndoCommand, 1357 RedoCommand, 1358 CutCommand, 1359 CopyCommand, 1360 PasteCommand, 1361 HalfSizeCommand, 1362 OriginalSizeCommand, 1363 DoubleSizeCommand, 1364 ResizeCommand, 1365 ApplyCommand, 1366 RefreshCommand, 1367 RestoreCommand, 1368 CropCommand, 1369 ChopCommand, 1370 FlopCommand, 1371 FlipCommand, 1372 RotateRightCommand, 1373 RotateLeftCommand, 1374 RotateCommand, 1375 ShearCommand, 1376 RollCommand, 1377 TrimCommand, 1378 HueCommand, 1379 SaturationCommand, 1380 BrightnessCommand, 1381 GammaCommand, 1382 SpiffCommand, 1383 DullCommand, 1384 ContrastStretchCommand, 1385 SigmoidalContrastCommand, 1386 NormalizeCommand, 1387 EqualizeCommand, 1388 NegateCommand, 1389 GrayscaleCommand, 1390 MapCommand, 1391 QuantizeCommand, 1392 DespeckleCommand, 1393 EmbossCommand, 1394 ReduceNoiseCommand, 1395 AddNoiseCommand, 1396 SharpenCommand, 1397 BlurCommand, 1398 ThresholdCommand, 1399 EdgeDetectCommand, 1400 SpreadCommand, 1401 ShadeCommand, 1402 RaiseCommand, 1403 SegmentCommand, 1404 SolarizeCommand, 1405 SepiaToneCommand, 1406 SwirlCommand, 1407 ImplodeCommand, 1408 VignetteCommand, 1409 WaveCommand, 1410 OilPaintCommand, 1411 CharcoalDrawCommand, 1412 AnnotateCommand, 1413 DrawCommand, 1414 ColorCommand, 1415 MatteCommand, 1416 CompositeCommand, 1417 AddBorderCommand, 1418 AddFrameCommand, 1419 CommentCommand, 1420 LaunchCommand, 1421 RegionofInterestCommand, 1422 ROIHelpCommand, 1423 ROIDismissCommand, 1424 InfoCommand, 1425 ZoomCommand, 1426 ShowPreviewCommand, 1427 ShowHistogramCommand, 1428 ShowMatteCommand, 1429 BackgroundCommand, 1430 SlideShowCommand, 1431 PreferencesCommand, 1432 HelpCommand, 1433 BrowseDocumentationCommand, 1434 VersionCommand, 1435 SaveToUndoBufferCommand, 1436 FreeBuffersCommand, 1437 NullCommand 1438} CommandType; 1439 1440typedef enum 1441{ 1442 AnnotateNameCommand, 1443 AnnotateFontColorCommand, 1444 AnnotateBackgroundColorCommand, 1445 AnnotateRotateCommand, 1446 AnnotateHelpCommand, 1447 AnnotateDismissCommand, 1448 TextHelpCommand, 1449 TextApplyCommand, 1450 ChopDirectionCommand, 1451 ChopHelpCommand, 1452 ChopDismissCommand, 1453 HorizontalChopCommand, 1454 VerticalChopCommand, 1455 ColorEditMethodCommand, 1456 ColorEditColorCommand, 1457 ColorEditBorderCommand, 1458 ColorEditFuzzCommand, 1459 ColorEditUndoCommand, 1460 ColorEditHelpCommand, 1461 ColorEditDismissCommand, 1462 CompositeOperatorsCommand, 1463 CompositeDissolveCommand, 1464 CompositeDisplaceCommand, 1465 CompositeHelpCommand, 1466 CompositeDismissCommand, 1467 CropHelpCommand, 1468 CropDismissCommand, 1469 RectifyCopyCommand, 1470 RectifyHelpCommand, 1471 RectifyDismissCommand, 1472 DrawElementCommand, 1473 DrawColorCommand, 1474 DrawStippleCommand, 1475 DrawWidthCommand, 1476 DrawUndoCommand, 1477 DrawHelpCommand, 1478 DrawDismissCommand, 1479 MatteEditMethod, 1480 MatteEditBorderCommand, 1481 MatteEditFuzzCommand, 1482 MatteEditValueCommand, 1483 MatteEditUndoCommand, 1484 MatteEditHelpCommand, 1485 MatteEditDismissCommand, 1486 PasteOperatorsCommand, 1487 PasteHelpCommand, 1488 PasteDismissCommand, 1489 RotateColorCommand, 1490 RotateDirectionCommand, 1491 RotateCropCommand, 1492 RotateSharpenCommand, 1493 RotateHelpCommand, 1494 RotateDismissCommand, 1495 HorizontalRotateCommand, 1496 VerticalRotateCommand, 1497 TileLoadCommand, 1498 TileNextCommand, 1499 TileFormerCommand, 1500 TileDeleteCommand, 1501 TileUpdateCommand 1502} ModeType; 1503 1504/* 1505 Stipples. 1506*/ 1507#define BricksWidth 20 1508#define BricksHeight 20 1509#define DiagonalWidth 16 1510#define DiagonalHeight 16 1511#define HighlightWidth 8 1512#define HighlightHeight 8 1513#define OpaqueWidth 8 1514#define OpaqueHeight 8 1515#define ScalesWidth 16 1516#define ScalesHeight 16 1517#define ShadowWidth 8 1518#define ShadowHeight 8 1519#define VerticalWidth 16 1520#define VerticalHeight 16 1521#define WavyWidth 16 1522#define WavyHeight 16 1523 1524/* 1525 Constant declaration. 1526*/ 1527static const int 1528 RoiDelta = 8; 1529 1530static const unsigned char 1531 BricksBitmap[] = 1532 { 1533 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1534 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1535 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1536 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1537 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1538 }, 1539 DiagonalBitmap[] = 1540 { 1541 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1542 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1543 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1544 }, 1545 ScalesBitmap[] = 1546 { 1547 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1548 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1549 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1550 }, 1551 VerticalBitmap[] = 1552 { 1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1556 }, 1557 WavyBitmap[] = 1558 { 1559 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1560 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1561 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1562 }; 1563 1564/* 1565 Function prototypes. 1566*/ 1567static CommandType 1568 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1569 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1570 1571static Image 1572 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1573 Image **,ExceptionInfo *), 1574 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1575 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1576 ExceptionInfo *), 1577 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1578 ExceptionInfo *); 1579 1580static MagickBooleanType 1581 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1582 ExceptionInfo *), 1583 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1584 ExceptionInfo *), 1585 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1586 ExceptionInfo *), 1587 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1588 ExceptionInfo *), 1589 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1590 ExceptionInfo *), 1591 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1592 ExceptionInfo *), 1593 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1594 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1595 ExceptionInfo *), 1596 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1597 ExceptionInfo *), 1598 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1599 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1600 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1601 ExceptionInfo *), 1602 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1603 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1604 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1605 1606static void 1607 XDrawPanRectangle(Display *,XWindows *), 1608 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1609 ExceptionInfo *), 1610 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1611 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1612 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1613 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1614 const KeySym,ExceptionInfo *), 1615 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1616 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1617 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1618 1619/* 1620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1621% % 1622% % 1623% % 1624% D i s p l a y I m a g e s % 1625% % 1626% % 1627% % 1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1629% 1630% DisplayImages() displays an image sequence to any X window screen. It 1631% returns a value other than 0 if successful. Check the exception member 1632% of image to determine the reason for any failure. 1633% 1634% The format of the DisplayImages method is: 1635% 1636% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1637% Image *images,ExceptionInfo *exception) 1638% 1639% A description of each parameter follows: 1640% 1641% o image_info: the image info. 1642% 1643% o image: the image. 1644% 1645% o exception: return any errors or warnings in this structure. 1646% 1647*/ 1648MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1649 Image *images,ExceptionInfo *exception) 1650{ 1651 char 1652 *argv[1]; 1653 1654 Display 1655 *display; 1656 1657 Image 1658 *image; 1659 1660 register ssize_t 1661 i; 1662 1663 size_t 1664 state; 1665 1666 XrmDatabase 1667 resource_database; 1668 1669 XResourceInfo 1670 resource_info; 1671 1672 assert(image_info != (const ImageInfo *) NULL); 1673 assert(image_info->signature == MagickSignature); 1674 assert(images != (Image *) NULL); 1675 assert(images->signature == MagickSignature); 1676 if (images->debug != MagickFalse) 1677 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1678 display=XOpenDisplay(image_info->server_name); 1679 if (display == (Display *) NULL) 1680 { 1681 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1682 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1683 return(MagickFalse); 1684 } 1685 if (exception->severity != UndefinedException) 1686 CatchException(exception); 1687 (void) XSetErrorHandler(XError); 1688 resource_database=XGetResourceDatabase(display,GetClientName()); 1689 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1690 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1691 if (image_info->page != (char *) NULL) 1692 resource_info.image_geometry=AcquireString(image_info->page); 1693 resource_info.immutable=MagickTrue; 1694 argv[0]=AcquireString(GetClientName()); 1695 state=DefaultState; 1696 for (i=0; (state & ExitState) == 0; i++) 1697 { 1698 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1699 break; 1700 image=GetImageFromList(images,i % GetImageListLength(images)); 1701 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1702 } 1703 SetErrorHandler((ErrorHandler) NULL); 1704 SetWarningHandler((WarningHandler) NULL); 1705 argv[0]=DestroyString(argv[0]); 1706 (void) XCloseDisplay(display); 1707 XDestroyResourceInfo(&resource_info); 1708 if (exception->severity != UndefinedException) 1709 return(MagickFalse); 1710 return(MagickTrue); 1711} 1712 1713/* 1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1715% % 1716% % 1717% % 1718% R e m o t e D i s p l a y C o m m a n d % 1719% % 1720% % 1721% % 1722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1723% 1724% RemoteDisplayCommand() encourages a remote display program to display the 1725% specified image filename. 1726% 1727% The format of the RemoteDisplayCommand method is: 1728% 1729% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1730% const char *window,const char *filename,ExceptionInfo *exception) 1731% 1732% A description of each parameter follows: 1733% 1734% o image_info: the image info. 1735% 1736% o window: Specifies the name or id of an X window. 1737% 1738% o filename: the name of the image filename to display. 1739% 1740% o exception: return any errors or warnings in this structure. 1741% 1742*/ 1743MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1744 const char *window,const char *filename,ExceptionInfo *exception) 1745{ 1746 Display 1747 *display; 1748 1749 MagickStatusType 1750 status; 1751 1752 assert(image_info != (const ImageInfo *) NULL); 1753 assert(image_info->signature == MagickSignature); 1754 assert(filename != (char *) NULL); 1755 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1756 display=XOpenDisplay(image_info->server_name); 1757 if (display == (Display *) NULL) 1758 { 1759 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1760 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1761 return(MagickFalse); 1762 } 1763 (void) XSetErrorHandler(XError); 1764 status=XRemoteCommand(display,window,filename); 1765 (void) XCloseDisplay(display); 1766 return(status != 0 ? MagickTrue : MagickFalse); 1767} 1768 1769/* 1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1771% % 1772% % 1773% % 1774+ X A n n o t a t e E d i t I m a g e % 1775% % 1776% % 1777% % 1778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1779% 1780% XAnnotateEditImage() annotates the image with text. 1781% 1782% The format of the XAnnotateEditImage method is: 1783% 1784% MagickBooleanType XAnnotateEditImage(Display *display, 1785% XResourceInfo *resource_info,XWindows *windows,Image *image, 1786% ExceptionInfo *exception) 1787% 1788% A description of each parameter follows: 1789% 1790% o display: Specifies a connection to an X server; returned from 1791% XOpenDisplay. 1792% 1793% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1794% 1795% o windows: Specifies a pointer to a XWindows structure. 1796% 1797% o image: the image; returned from ReadImage. 1798% 1799*/ 1800 1801static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1802{ 1803 if (x > y) 1804 return(x); 1805 return(y); 1806} 1807 1808static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1809{ 1810 if (x < y) 1811 return(x); 1812 return(y); 1813} 1814 1815static MagickBooleanType XAnnotateEditImage(Display *display, 1816 XResourceInfo *resource_info,XWindows *windows,Image *image, 1817 ExceptionInfo *exception) 1818{ 1819 static const char 1820 *AnnotateMenu[] = 1821 { 1822 "Font Name", 1823 "Font Color", 1824 "Box Color", 1825 "Rotate Text", 1826 "Help", 1827 "Dismiss", 1828 (char *) NULL 1829 }, 1830 *TextMenu[] = 1831 { 1832 "Help", 1833 "Apply", 1834 (char *) NULL 1835 }; 1836 1837 static const ModeType 1838 AnnotateCommands[] = 1839 { 1840 AnnotateNameCommand, 1841 AnnotateFontColorCommand, 1842 AnnotateBackgroundColorCommand, 1843 AnnotateRotateCommand, 1844 AnnotateHelpCommand, 1845 AnnotateDismissCommand 1846 }, 1847 TextCommands[] = 1848 { 1849 TextHelpCommand, 1850 TextApplyCommand 1851 }; 1852 1853 static MagickBooleanType 1854 transparent_box = MagickTrue, 1855 transparent_pen = MagickFalse; 1856 1857 static MagickRealType 1858 degrees = 0.0; 1859 1860 static unsigned int 1861 box_id = MaxNumberPens-2, 1862 font_id = 0, 1863 pen_id = 0; 1864 1865 char 1866 command[MaxTextExtent], 1867 text[MaxTextExtent]; 1868 1869 const char 1870 *ColorMenu[MaxNumberPens+1]; 1871 1872 Cursor 1873 cursor; 1874 1875 GC 1876 annotate_context; 1877 1878 int 1879 id, 1880 pen_number, 1881 status, 1882 x, 1883 y; 1884 1885 KeySym 1886 key_symbol; 1887 1888 register char 1889 *p; 1890 1891 register ssize_t 1892 i; 1893 1894 unsigned int 1895 height, 1896 width; 1897 1898 size_t 1899 state; 1900 1901 XAnnotateInfo 1902 *annotate_info, 1903 *previous_info; 1904 1905 XColor 1906 color; 1907 1908 XFontStruct 1909 *font_info; 1910 1911 XEvent 1912 event, 1913 text_event; 1914 1915 /* 1916 Map Command widget. 1917 */ 1918 (void) CloneString(&windows->command.name,"Annotate"); 1919 windows->command.data=4; 1920 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1921 (void) XMapRaised(display,windows->command.id); 1922 XClientMessage(display,windows->image.id,windows->im_protocols, 1923 windows->im_update_widget,CurrentTime); 1924 /* 1925 Track pointer until button 1 is pressed. 1926 */ 1927 XQueryPosition(display,windows->image.id,&x,&y); 1928 (void) XSelectInput(display,windows->image.id, 1929 windows->image.attributes.event_mask | PointerMotionMask); 1930 cursor=XCreateFontCursor(display,XC_left_side); 1931 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1932 state=DefaultState; 1933 do 1934 { 1935 if (windows->info.mapped != MagickFalse) 1936 { 1937 /* 1938 Display pointer position. 1939 */ 1940 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1941 x+windows->image.x,y+windows->image.y); 1942 XInfoWidget(display,windows,text); 1943 } 1944 /* 1945 Wait for next event. 1946 */ 1947 XScreenEvent(display,windows,&event,exception); 1948 if (event.xany.window == windows->command.id) 1949 { 1950 /* 1951 Select a command from the Command widget. 1952 */ 1953 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1954 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1955 if (id < 0) 1956 continue; 1957 switch (AnnotateCommands[id]) 1958 { 1959 case AnnotateNameCommand: 1960 { 1961 const char 1962 *FontMenu[MaxNumberFonts]; 1963 1964 int 1965 font_number; 1966 1967 /* 1968 Initialize menu selections. 1969 */ 1970 for (i=0; i < MaxNumberFonts; i++) 1971 FontMenu[i]=resource_info->font_name[i]; 1972 FontMenu[MaxNumberFonts-2]="Browser..."; 1973 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1974 /* 1975 Select a font name from the pop-up menu. 1976 */ 1977 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1978 (const char **) FontMenu,command); 1979 if (font_number < 0) 1980 break; 1981 if (font_number == (MaxNumberFonts-2)) 1982 { 1983 static char 1984 font_name[MaxTextExtent] = "fixed"; 1985 1986 /* 1987 Select a font name from a browser. 1988 */ 1989 resource_info->font_name[font_number]=font_name; 1990 XFontBrowserWidget(display,windows,"Select",font_name); 1991 if (*font_name == '\0') 1992 break; 1993 } 1994 /* 1995 Initialize font info. 1996 */ 1997 font_info=XLoadQueryFont(display,resource_info->font_name[ 1998 font_number]); 1999 if (font_info == (XFontStruct *) NULL) 2000 { 2001 XNoticeWidget(display,windows,"Unable to load font:", 2002 resource_info->font_name[font_number]); 2003 break; 2004 } 2005 font_id=(unsigned int) font_number; 2006 (void) XFreeFont(display,font_info); 2007 break; 2008 } 2009 case AnnotateFontColorCommand: 2010 { 2011 /* 2012 Initialize menu selections. 2013 */ 2014 for (i=0; i < (int) (MaxNumberPens-2); i++) 2015 ColorMenu[i]=resource_info->pen_colors[i]; 2016 ColorMenu[MaxNumberPens-2]="transparent"; 2017 ColorMenu[MaxNumberPens-1]="Browser..."; 2018 ColorMenu[MaxNumberPens]=(const char *) NULL; 2019 /* 2020 Select a pen color from the pop-up menu. 2021 */ 2022 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2023 (const char **) ColorMenu,command); 2024 if (pen_number < 0) 2025 break; 2026 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2027 MagickFalse; 2028 if (transparent_pen != MagickFalse) 2029 break; 2030 if (pen_number == (MaxNumberPens-1)) 2031 { 2032 static char 2033 color_name[MaxTextExtent] = "gray"; 2034 2035 /* 2036 Select a pen color from a dialog. 2037 */ 2038 resource_info->pen_colors[pen_number]=color_name; 2039 XColorBrowserWidget(display,windows,"Select",color_name); 2040 if (*color_name == '\0') 2041 break; 2042 } 2043 /* 2044 Set pen color. 2045 */ 2046 (void) XParseColor(display,windows->map_info->colormap, 2047 resource_info->pen_colors[pen_number],&color); 2048 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2049 (unsigned int) MaxColors,&color); 2050 windows->pixel_info->pen_colors[pen_number]=color; 2051 pen_id=(unsigned int) pen_number; 2052 break; 2053 } 2054 case AnnotateBackgroundColorCommand: 2055 { 2056 /* 2057 Initialize menu selections. 2058 */ 2059 for (i=0; i < (int) (MaxNumberPens-2); i++) 2060 ColorMenu[i]=resource_info->pen_colors[i]; 2061 ColorMenu[MaxNumberPens-2]="transparent"; 2062 ColorMenu[MaxNumberPens-1]="Browser..."; 2063 ColorMenu[MaxNumberPens]=(const char *) NULL; 2064 /* 2065 Select a pen color from the pop-up menu. 2066 */ 2067 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2068 (const char **) ColorMenu,command); 2069 if (pen_number < 0) 2070 break; 2071 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2072 MagickFalse; 2073 if (transparent_box != MagickFalse) 2074 break; 2075 if (pen_number == (MaxNumberPens-1)) 2076 { 2077 static char 2078 color_name[MaxTextExtent] = "gray"; 2079 2080 /* 2081 Select a pen color from a dialog. 2082 */ 2083 resource_info->pen_colors[pen_number]=color_name; 2084 XColorBrowserWidget(display,windows,"Select",color_name); 2085 if (*color_name == '\0') 2086 break; 2087 } 2088 /* 2089 Set pen color. 2090 */ 2091 (void) XParseColor(display,windows->map_info->colormap, 2092 resource_info->pen_colors[pen_number],&color); 2093 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2094 (unsigned int) MaxColors,&color); 2095 windows->pixel_info->pen_colors[pen_number]=color; 2096 box_id=(unsigned int) pen_number; 2097 break; 2098 } 2099 case AnnotateRotateCommand: 2100 { 2101 int 2102 entry; 2103 2104 static char 2105 angle[MaxTextExtent] = "30.0"; 2106 2107 static const char 2108 *RotateMenu[] = 2109 { 2110 "-90", 2111 "-45", 2112 "-30", 2113 "0", 2114 "30", 2115 "45", 2116 "90", 2117 "180", 2118 "Dialog...", 2119 (char *) NULL, 2120 }; 2121 2122 /* 2123 Select a command from the pop-up menu. 2124 */ 2125 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2126 command); 2127 if (entry < 0) 2128 break; 2129 if (entry != 8) 2130 { 2131 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2132 break; 2133 } 2134 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2135 angle); 2136 if (*angle == '\0') 2137 break; 2138 degrees=StringToDouble(angle,(char **) NULL); 2139 break; 2140 } 2141 case AnnotateHelpCommand: 2142 { 2143 XTextViewWidget(display,resource_info,windows,MagickFalse, 2144 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2145 break; 2146 } 2147 case AnnotateDismissCommand: 2148 { 2149 /* 2150 Prematurely exit. 2151 */ 2152 state|=EscapeState; 2153 state|=ExitState; 2154 break; 2155 } 2156 default: 2157 break; 2158 } 2159 continue; 2160 } 2161 switch (event.type) 2162 { 2163 case ButtonPress: 2164 { 2165 if (event.xbutton.button != Button1) 2166 break; 2167 if (event.xbutton.window != windows->image.id) 2168 break; 2169 /* 2170 Change to text entering mode. 2171 */ 2172 x=event.xbutton.x; 2173 y=event.xbutton.y; 2174 state|=ExitState; 2175 break; 2176 } 2177 case ButtonRelease: 2178 break; 2179 case Expose: 2180 break; 2181 case KeyPress: 2182 { 2183 if (event.xkey.window != windows->image.id) 2184 break; 2185 /* 2186 Respond to a user key press. 2187 */ 2188 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2189 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2190 switch ((int) key_symbol) 2191 { 2192 case XK_Escape: 2193 case XK_F20: 2194 { 2195 /* 2196 Prematurely exit. 2197 */ 2198 state|=EscapeState; 2199 state|=ExitState; 2200 break; 2201 } 2202 case XK_F1: 2203 case XK_Help: 2204 { 2205 XTextViewWidget(display,resource_info,windows,MagickFalse, 2206 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2207 break; 2208 } 2209 default: 2210 { 2211 (void) XBell(display,0); 2212 break; 2213 } 2214 } 2215 break; 2216 } 2217 case MotionNotify: 2218 { 2219 /* 2220 Map and unmap Info widget as cursor crosses its boundaries. 2221 */ 2222 x=event.xmotion.x; 2223 y=event.xmotion.y; 2224 if (windows->info.mapped != MagickFalse) 2225 { 2226 if ((x < (int) (windows->info.x+windows->info.width)) && 2227 (y < (int) (windows->info.y+windows->info.height))) 2228 (void) XWithdrawWindow(display,windows->info.id, 2229 windows->info.screen); 2230 } 2231 else 2232 if ((x > (int) (windows->info.x+windows->info.width)) || 2233 (y > (int) (windows->info.y+windows->info.height))) 2234 (void) XMapWindow(display,windows->info.id); 2235 break; 2236 } 2237 default: 2238 break; 2239 } 2240 } while ((state & ExitState) == 0); 2241 (void) XSelectInput(display,windows->image.id, 2242 windows->image.attributes.event_mask); 2243 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2244 if ((state & EscapeState) != 0) 2245 return(MagickTrue); 2246 /* 2247 Set font info and check boundary conditions. 2248 */ 2249 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2250 if (font_info == (XFontStruct *) NULL) 2251 { 2252 XNoticeWidget(display,windows,"Unable to load font:", 2253 resource_info->font_name[font_id]); 2254 font_info=windows->font_info; 2255 } 2256 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2257 x=(int) windows->image.width-font_info->max_bounds.width; 2258 if (y < (int) (font_info->ascent+font_info->descent)) 2259 y=(int) font_info->ascent+font_info->descent; 2260 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2261 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2262 return(MagickFalse); 2263 /* 2264 Initialize annotate structure. 2265 */ 2266 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2267 if (annotate_info == (XAnnotateInfo *) NULL) 2268 return(MagickFalse); 2269 XGetAnnotateInfo(annotate_info); 2270 annotate_info->x=x; 2271 annotate_info->y=y; 2272 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2273 annotate_info->stencil=OpaqueStencil; 2274 else 2275 if (transparent_box == MagickFalse) 2276 annotate_info->stencil=BackgroundStencil; 2277 else 2278 annotate_info->stencil=ForegroundStencil; 2279 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2280 annotate_info->degrees=degrees; 2281 annotate_info->font_info=font_info; 2282 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2283 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2284 sizeof(*annotate_info->text)); 2285 if (annotate_info->text == (char *) NULL) 2286 return(MagickFalse); 2287 /* 2288 Create cursor and set graphic context. 2289 */ 2290 cursor=XCreateFontCursor(display,XC_pencil); 2291 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2292 annotate_context=windows->image.annotate_context; 2293 (void) XSetFont(display,annotate_context,font_info->fid); 2294 (void) XSetBackground(display,annotate_context, 2295 windows->pixel_info->pen_colors[box_id].pixel); 2296 (void) XSetForeground(display,annotate_context, 2297 windows->pixel_info->pen_colors[pen_id].pixel); 2298 /* 2299 Begin annotating the image with text. 2300 */ 2301 (void) CloneString(&windows->command.name,"Text"); 2302 windows->command.data=0; 2303 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2304 state=DefaultState; 2305 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2306 text_event.xexpose.width=(int) font_info->max_bounds.width; 2307 text_event.xexpose.height=font_info->max_bounds.ascent+ 2308 font_info->max_bounds.descent; 2309 p=annotate_info->text; 2310 do 2311 { 2312 /* 2313 Display text cursor. 2314 */ 2315 *p='\0'; 2316 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2317 /* 2318 Wait for next event. 2319 */ 2320 XScreenEvent(display,windows,&event,exception); 2321 if (event.xany.window == windows->command.id) 2322 { 2323 /* 2324 Select a command from the Command widget. 2325 */ 2326 (void) XSetBackground(display,annotate_context, 2327 windows->pixel_info->background_color.pixel); 2328 (void) XSetForeground(display,annotate_context, 2329 windows->pixel_info->foreground_color.pixel); 2330 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2331 (void) XSetBackground(display,annotate_context, 2332 windows->pixel_info->pen_colors[box_id].pixel); 2333 (void) XSetForeground(display,annotate_context, 2334 windows->pixel_info->pen_colors[pen_id].pixel); 2335 if (id < 0) 2336 continue; 2337 switch (TextCommands[id]) 2338 { 2339 case TextHelpCommand: 2340 { 2341 XTextViewWidget(display,resource_info,windows,MagickFalse, 2342 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2343 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2344 break; 2345 } 2346 case TextApplyCommand: 2347 { 2348 /* 2349 Finished annotating. 2350 */ 2351 annotate_info->width=(unsigned int) XTextWidth(font_info, 2352 annotate_info->text,(int) strlen(annotate_info->text)); 2353 XRefreshWindow(display,&windows->image,&text_event); 2354 state|=ExitState; 2355 break; 2356 } 2357 default: 2358 break; 2359 } 2360 continue; 2361 } 2362 /* 2363 Erase text cursor. 2364 */ 2365 text_event.xexpose.x=x; 2366 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2367 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2368 (unsigned int) text_event.xexpose.width,(unsigned int) 2369 text_event.xexpose.height,MagickFalse); 2370 XRefreshWindow(display,&windows->image,&text_event); 2371 switch (event.type) 2372 { 2373 case ButtonPress: 2374 { 2375 if (event.xbutton.window != windows->image.id) 2376 break; 2377 if (event.xbutton.button == Button2) 2378 { 2379 /* 2380 Request primary selection. 2381 */ 2382 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2383 windows->image.id,CurrentTime); 2384 break; 2385 } 2386 break; 2387 } 2388 case Expose: 2389 { 2390 if (event.xexpose.count == 0) 2391 { 2392 XAnnotateInfo 2393 *text_info; 2394 2395 /* 2396 Refresh Image window. 2397 */ 2398 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2399 text_info=annotate_info; 2400 while (text_info != (XAnnotateInfo *) NULL) 2401 { 2402 if (annotate_info->stencil == ForegroundStencil) 2403 (void) XDrawString(display,windows->image.id,annotate_context, 2404 text_info->x,text_info->y,text_info->text, 2405 (int) strlen(text_info->text)); 2406 else 2407 (void) XDrawImageString(display,windows->image.id, 2408 annotate_context,text_info->x,text_info->y,text_info->text, 2409 (int) strlen(text_info->text)); 2410 text_info=text_info->previous; 2411 } 2412 (void) XDrawString(display,windows->image.id,annotate_context, 2413 x,y,"_",1); 2414 } 2415 break; 2416 } 2417 case KeyPress: 2418 { 2419 int 2420 length; 2421 2422 if (event.xkey.window != windows->image.id) 2423 break; 2424 /* 2425 Respond to a user key press. 2426 */ 2427 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2428 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2429 *(command+length)='\0'; 2430 if (((event.xkey.state & ControlMask) != 0) || 2431 ((event.xkey.state & Mod1Mask) != 0)) 2432 state|=ModifierState; 2433 if ((state & ModifierState) != 0) 2434 switch ((int) key_symbol) 2435 { 2436 case XK_u: 2437 case XK_U: 2438 { 2439 key_symbol=DeleteCommand; 2440 break; 2441 } 2442 default: 2443 break; 2444 } 2445 switch ((int) key_symbol) 2446 { 2447 case XK_BackSpace: 2448 { 2449 /* 2450 Erase one character. 2451 */ 2452 if (p == annotate_info->text) 2453 { 2454 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2455 break; 2456 else 2457 { 2458 /* 2459 Go to end of the previous line of text. 2460 */ 2461 annotate_info=annotate_info->previous; 2462 p=annotate_info->text; 2463 x=annotate_info->x+annotate_info->width; 2464 y=annotate_info->y; 2465 if (annotate_info->width != 0) 2466 p+=strlen(annotate_info->text); 2467 break; 2468 } 2469 } 2470 p--; 2471 x-=XTextWidth(font_info,p,1); 2472 text_event.xexpose.x=x; 2473 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2474 XRefreshWindow(display,&windows->image,&text_event); 2475 break; 2476 } 2477 case XK_bracketleft: 2478 { 2479 key_symbol=XK_Escape; 2480 break; 2481 } 2482 case DeleteCommand: 2483 { 2484 /* 2485 Erase the entire line of text. 2486 */ 2487 while (p != annotate_info->text) 2488 { 2489 p--; 2490 x-=XTextWidth(font_info,p,1); 2491 text_event.xexpose.x=x; 2492 XRefreshWindow(display,&windows->image,&text_event); 2493 } 2494 break; 2495 } 2496 case XK_Escape: 2497 case XK_F20: 2498 { 2499 /* 2500 Finished annotating. 2501 */ 2502 annotate_info->width=(unsigned int) XTextWidth(font_info, 2503 annotate_info->text,(int) strlen(annotate_info->text)); 2504 XRefreshWindow(display,&windows->image,&text_event); 2505 state|=ExitState; 2506 break; 2507 } 2508 default: 2509 { 2510 /* 2511 Draw a single character on the Image window. 2512 */ 2513 if ((state & ModifierState) != 0) 2514 break; 2515 if (*command == '\0') 2516 break; 2517 *p=(*command); 2518 if (annotate_info->stencil == ForegroundStencil) 2519 (void) XDrawString(display,windows->image.id,annotate_context, 2520 x,y,p,1); 2521 else 2522 (void) XDrawImageString(display,windows->image.id, 2523 annotate_context,x,y,p,1); 2524 x+=XTextWidth(font_info,p,1); 2525 p++; 2526 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2527 break; 2528 } 2529 case XK_Return: 2530 case XK_KP_Enter: 2531 { 2532 /* 2533 Advance to the next line of text. 2534 */ 2535 *p='\0'; 2536 annotate_info->width=(unsigned int) XTextWidth(font_info, 2537 annotate_info->text,(int) strlen(annotate_info->text)); 2538 if (annotate_info->next != (XAnnotateInfo *) NULL) 2539 { 2540 /* 2541 Line of text already exists. 2542 */ 2543 annotate_info=annotate_info->next; 2544 x=annotate_info->x; 2545 y=annotate_info->y; 2546 p=annotate_info->text; 2547 break; 2548 } 2549 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2550 sizeof(*annotate_info->next)); 2551 if (annotate_info->next == (XAnnotateInfo *) NULL) 2552 return(MagickFalse); 2553 *annotate_info->next=(*annotate_info); 2554 annotate_info->next->previous=annotate_info; 2555 annotate_info=annotate_info->next; 2556 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2557 windows->image.width/MagickMax((ssize_t) 2558 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2559 if (annotate_info->text == (char *) NULL) 2560 return(MagickFalse); 2561 annotate_info->y+=annotate_info->height; 2562 if (annotate_info->y > (int) windows->image.height) 2563 annotate_info->y=(int) annotate_info->height; 2564 annotate_info->next=(XAnnotateInfo *) NULL; 2565 x=annotate_info->x; 2566 y=annotate_info->y; 2567 p=annotate_info->text; 2568 break; 2569 } 2570 } 2571 break; 2572 } 2573 case KeyRelease: 2574 { 2575 /* 2576 Respond to a user key release. 2577 */ 2578 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2579 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2580 state&=(~ModifierState); 2581 break; 2582 } 2583 case SelectionNotify: 2584 { 2585 Atom 2586 type; 2587 2588 int 2589 format; 2590 2591 unsigned char 2592 *data; 2593 2594 unsigned long 2595 after, 2596 length; 2597 2598 /* 2599 Obtain response from primary selection. 2600 */ 2601 if (event.xselection.property == (Atom) None) 2602 break; 2603 status=XGetWindowProperty(display,event.xselection.requestor, 2604 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2605 &type,&format,&length,&after,&data); 2606 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2607 (length == 0)) 2608 break; 2609 /* 2610 Annotate Image window with primary selection. 2611 */ 2612 for (i=0; i < (ssize_t) length; i++) 2613 { 2614 if ((char) data[i] != '\n') 2615 { 2616 /* 2617 Draw a single character on the Image window. 2618 */ 2619 *p=(char) data[i]; 2620 (void) XDrawString(display,windows->image.id,annotate_context, 2621 x,y,p,1); 2622 x+=XTextWidth(font_info,p,1); 2623 p++; 2624 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2625 continue; 2626 } 2627 /* 2628 Advance to the next line of text. 2629 */ 2630 *p='\0'; 2631 annotate_info->width=(unsigned int) XTextWidth(font_info, 2632 annotate_info->text,(int) strlen(annotate_info->text)); 2633 if (annotate_info->next != (XAnnotateInfo *) NULL) 2634 { 2635 /* 2636 Line of text already exists. 2637 */ 2638 annotate_info=annotate_info->next; 2639 x=annotate_info->x; 2640 y=annotate_info->y; 2641 p=annotate_info->text; 2642 continue; 2643 } 2644 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2645 sizeof(*annotate_info->next)); 2646 if (annotate_info->next == (XAnnotateInfo *) NULL) 2647 return(MagickFalse); 2648 *annotate_info->next=(*annotate_info); 2649 annotate_info->next->previous=annotate_info; 2650 annotate_info=annotate_info->next; 2651 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2652 windows->image.width/MagickMax((ssize_t) 2653 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2654 if (annotate_info->text == (char *) NULL) 2655 return(MagickFalse); 2656 annotate_info->y+=annotate_info->height; 2657 if (annotate_info->y > (int) windows->image.height) 2658 annotate_info->y=(int) annotate_info->height; 2659 annotate_info->next=(XAnnotateInfo *) NULL; 2660 x=annotate_info->x; 2661 y=annotate_info->y; 2662 p=annotate_info->text; 2663 } 2664 (void) XFree((void *) data); 2665 break; 2666 } 2667 default: 2668 break; 2669 } 2670 } while ((state & ExitState) == 0); 2671 (void) XFreeCursor(display,cursor); 2672 /* 2673 Annotation is relative to image configuration. 2674 */ 2675 width=(unsigned int) image->columns; 2676 height=(unsigned int) image->rows; 2677 x=0; 2678 y=0; 2679 if (windows->image.crop_geometry != (char *) NULL) 2680 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2681 /* 2682 Initialize annotated image. 2683 */ 2684 XSetCursorState(display,windows,MagickTrue); 2685 XCheckRefreshWindows(display,windows); 2686 while (annotate_info != (XAnnotateInfo *) NULL) 2687 { 2688 if (annotate_info->width == 0) 2689 { 2690 /* 2691 No text on this line-- go to the next line of text. 2692 */ 2693 previous_info=annotate_info->previous; 2694 annotate_info->text=(char *) 2695 RelinquishMagickMemory(annotate_info->text); 2696 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2697 annotate_info=previous_info; 2698 continue; 2699 } 2700 /* 2701 Determine pixel index for box and pen color. 2702 */ 2703 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2704 if (windows->pixel_info->colors != 0) 2705 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2706 if (windows->pixel_info->pixels[i] == 2707 windows->pixel_info->pen_colors[box_id].pixel) 2708 { 2709 windows->pixel_info->box_index=(unsigned short) i; 2710 break; 2711 } 2712 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2713 if (windows->pixel_info->colors != 0) 2714 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2715 if (windows->pixel_info->pixels[i] == 2716 windows->pixel_info->pen_colors[pen_id].pixel) 2717 { 2718 windows->pixel_info->pen_index=(unsigned short) i; 2719 break; 2720 } 2721 /* 2722 Define the annotate geometry string. 2723 */ 2724 annotate_info->x=(int) 2725 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2726 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2727 windows->image.y)/windows->image.ximage->height; 2728 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2729 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2730 height*annotate_info->height/windows->image.ximage->height, 2731 annotate_info->x+x,annotate_info->y+y); 2732 /* 2733 Annotate image with text. 2734 */ 2735 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2736 exception); 2737 if (status == 0) 2738 return(MagickFalse); 2739 /* 2740 Free up memory. 2741 */ 2742 previous_info=annotate_info->previous; 2743 annotate_info->text=DestroyString(annotate_info->text); 2744 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2745 annotate_info=previous_info; 2746 } 2747 (void) XSetForeground(display,annotate_context, 2748 windows->pixel_info->foreground_color.pixel); 2749 (void) XSetBackground(display,annotate_context, 2750 windows->pixel_info->background_color.pixel); 2751 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2752 XSetCursorState(display,windows,MagickFalse); 2753 (void) XFreeFont(display,font_info); 2754 /* 2755 Update image configuration. 2756 */ 2757 XConfigureImageColormap(display,resource_info,windows,image,exception); 2758 (void) XConfigureImage(display,resource_info,windows,image,exception); 2759 return(MagickTrue); 2760} 2761 2762/* 2763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2764% % 2765% % 2766% % 2767+ X B a c k g r o u n d I m a g e % 2768% % 2769% % 2770% % 2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2772% 2773% XBackgroundImage() displays the image in the background of a window. 2774% 2775% The format of the XBackgroundImage method is: 2776% 2777% MagickBooleanType XBackgroundImage(Display *display, 2778% XResourceInfo *resource_info,XWindows *windows,Image **image, 2779% ExceptionInfo *exception) 2780% 2781% A description of each parameter follows: 2782% 2783% o display: Specifies a connection to an X server; returned from 2784% XOpenDisplay. 2785% 2786% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2787% 2788% o windows: Specifies a pointer to a XWindows structure. 2789% 2790% o image: the image. 2791% 2792% o exception: return any errors or warnings in this structure. 2793% 2794*/ 2795static MagickBooleanType XBackgroundImage(Display *display, 2796 XResourceInfo *resource_info,XWindows *windows,Image **image, 2797 ExceptionInfo *exception) 2798{ 2799#define BackgroundImageTag "Background/Image" 2800 2801 int 2802 status; 2803 2804 static char 2805 window_id[MaxTextExtent] = "root"; 2806 2807 XResourceInfo 2808 background_resources; 2809 2810 /* 2811 Put image in background. 2812 */ 2813 status=XDialogWidget(display,windows,"Background", 2814 "Enter window id (id 0x00 selects window with pointer):",window_id); 2815 if (*window_id == '\0') 2816 return(MagickFalse); 2817 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2818 exception); 2819 XInfoWidget(display,windows,BackgroundImageTag); 2820 XSetCursorState(display,windows,MagickTrue); 2821 XCheckRefreshWindows(display,windows); 2822 background_resources=(*resource_info); 2823 background_resources.window_id=window_id; 2824 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2825 status=XDisplayBackgroundImage(display,&background_resources,*image, 2826 exception); 2827 if (status != MagickFalse) 2828 XClientMessage(display,windows->image.id,windows->im_protocols, 2829 windows->im_retain_colors,CurrentTime); 2830 XSetCursorState(display,windows,MagickFalse); 2831 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2832 exception); 2833 return(MagickTrue); 2834} 2835 2836/* 2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2838% % 2839% % 2840% % 2841+ X C h o p I m a g e % 2842% % 2843% % 2844% % 2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2846% 2847% XChopImage() chops the X image. 2848% 2849% The format of the XChopImage method is: 2850% 2851% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2852% XWindows *windows,Image **image,ExceptionInfo *exception) 2853% 2854% A description of each parameter follows: 2855% 2856% o display: Specifies a connection to an X server; returned from 2857% XOpenDisplay. 2858% 2859% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2860% 2861% o windows: Specifies a pointer to a XWindows structure. 2862% 2863% o image: the image. 2864% 2865% o exception: return any errors or warnings in this structure. 2866% 2867*/ 2868static MagickBooleanType XChopImage(Display *display, 2869 XResourceInfo *resource_info,XWindows *windows,Image **image, 2870 ExceptionInfo *exception) 2871{ 2872 static const char 2873 *ChopMenu[] = 2874 { 2875 "Direction", 2876 "Help", 2877 "Dismiss", 2878 (char *) NULL 2879 }; 2880 2881 static ModeType 2882 direction = HorizontalChopCommand; 2883 2884 static const ModeType 2885 ChopCommands[] = 2886 { 2887 ChopDirectionCommand, 2888 ChopHelpCommand, 2889 ChopDismissCommand 2890 }, 2891 DirectionCommands[] = 2892 { 2893 HorizontalChopCommand, 2894 VerticalChopCommand 2895 }; 2896 2897 char 2898 text[MaxTextExtent]; 2899 2900 Image 2901 *chop_image; 2902 2903 int 2904 id, 2905 x, 2906 y; 2907 2908 MagickRealType 2909 scale_factor; 2910 2911 RectangleInfo 2912 chop_info; 2913 2914 unsigned int 2915 distance, 2916 height, 2917 width; 2918 2919 size_t 2920 state; 2921 2922 XEvent 2923 event; 2924 2925 XSegment 2926 segment_info; 2927 2928 /* 2929 Map Command widget. 2930 */ 2931 (void) CloneString(&windows->command.name,"Chop"); 2932 windows->command.data=1; 2933 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2934 (void) XMapRaised(display,windows->command.id); 2935 XClientMessage(display,windows->image.id,windows->im_protocols, 2936 windows->im_update_widget,CurrentTime); 2937 /* 2938 Track pointer until button 1 is pressed. 2939 */ 2940 XQueryPosition(display,windows->image.id,&x,&y); 2941 (void) XSelectInput(display,windows->image.id, 2942 windows->image.attributes.event_mask | PointerMotionMask); 2943 state=DefaultState; 2944 do 2945 { 2946 if (windows->info.mapped != MagickFalse) 2947 { 2948 /* 2949 Display pointer position. 2950 */ 2951 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2952 x+windows->image.x,y+windows->image.y); 2953 XInfoWidget(display,windows,text); 2954 } 2955 /* 2956 Wait for next event. 2957 */ 2958 XScreenEvent(display,windows,&event,exception); 2959 if (event.xany.window == windows->command.id) 2960 { 2961 /* 2962 Select a command from the Command widget. 2963 */ 2964 id=XCommandWidget(display,windows,ChopMenu,&event); 2965 if (id < 0) 2966 continue; 2967 switch (ChopCommands[id]) 2968 { 2969 case ChopDirectionCommand: 2970 { 2971 char 2972 command[MaxTextExtent]; 2973 2974 static const char 2975 *Directions[] = 2976 { 2977 "horizontal", 2978 "vertical", 2979 (char *) NULL, 2980 }; 2981 2982 /* 2983 Select a command from the pop-up menu. 2984 */ 2985 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2986 if (id >= 0) 2987 direction=DirectionCommands[id]; 2988 break; 2989 } 2990 case ChopHelpCommand: 2991 { 2992 XTextViewWidget(display,resource_info,windows,MagickFalse, 2993 "Help Viewer - Image Chop",ImageChopHelp); 2994 break; 2995 } 2996 case ChopDismissCommand: 2997 { 2998 /* 2999 Prematurely exit. 3000 */ 3001 state|=EscapeState; 3002 state|=ExitState; 3003 break; 3004 } 3005 default: 3006 break; 3007 } 3008 continue; 3009 } 3010 switch (event.type) 3011 { 3012 case ButtonPress: 3013 { 3014 if (event.xbutton.button != Button1) 3015 break; 3016 if (event.xbutton.window != windows->image.id) 3017 break; 3018 /* 3019 User has committed to start point of chopping line. 3020 */ 3021 segment_info.x1=(short int) event.xbutton.x; 3022 segment_info.x2=(short int) event.xbutton.x; 3023 segment_info.y1=(short int) event.xbutton.y; 3024 segment_info.y2=(short int) event.xbutton.y; 3025 state|=ExitState; 3026 break; 3027 } 3028 case ButtonRelease: 3029 break; 3030 case Expose: 3031 break; 3032 case KeyPress: 3033 { 3034 char 3035 command[MaxTextExtent]; 3036 3037 KeySym 3038 key_symbol; 3039 3040 if (event.xkey.window != windows->image.id) 3041 break; 3042 /* 3043 Respond to a user key press. 3044 */ 3045 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3046 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3047 switch ((int) key_symbol) 3048 { 3049 case XK_Escape: 3050 case XK_F20: 3051 { 3052 /* 3053 Prematurely exit. 3054 */ 3055 state|=EscapeState; 3056 state|=ExitState; 3057 break; 3058 } 3059 case XK_F1: 3060 case XK_Help: 3061 { 3062 (void) XSetFunction(display,windows->image.highlight_context, 3063 GXcopy); 3064 XTextViewWidget(display,resource_info,windows,MagickFalse, 3065 "Help Viewer - Image Chop",ImageChopHelp); 3066 (void) XSetFunction(display,windows->image.highlight_context, 3067 GXinvert); 3068 break; 3069 } 3070 default: 3071 { 3072 (void) XBell(display,0); 3073 break; 3074 } 3075 } 3076 break; 3077 } 3078 case MotionNotify: 3079 { 3080 /* 3081 Map and unmap Info widget as text cursor crosses its boundaries. 3082 */ 3083 x=event.xmotion.x; 3084 y=event.xmotion.y; 3085 if (windows->info.mapped != MagickFalse) 3086 { 3087 if ((x < (int) (windows->info.x+windows->info.width)) && 3088 (y < (int) (windows->info.y+windows->info.height))) 3089 (void) XWithdrawWindow(display,windows->info.id, 3090 windows->info.screen); 3091 } 3092 else 3093 if ((x > (int) (windows->info.x+windows->info.width)) || 3094 (y > (int) (windows->info.y+windows->info.height))) 3095 (void) XMapWindow(display,windows->info.id); 3096 } 3097 } 3098 } while ((state & ExitState) == 0); 3099 (void) XSelectInput(display,windows->image.id, 3100 windows->image.attributes.event_mask); 3101 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3102 if ((state & EscapeState) != 0) 3103 return(MagickTrue); 3104 /* 3105 Draw line as pointer moves until the mouse button is released. 3106 */ 3107 chop_info.width=0; 3108 chop_info.height=0; 3109 chop_info.x=0; 3110 chop_info.y=0; 3111 distance=0; 3112 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3113 state=DefaultState; 3114 do 3115 { 3116 if (distance > 9) 3117 { 3118 /* 3119 Display info and draw chopping line. 3120 */ 3121 if (windows->info.mapped == MagickFalse) 3122 (void) XMapWindow(display,windows->info.id); 3123 (void) FormatLocaleString(text,MaxTextExtent, 3124 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3125 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3126 XInfoWidget(display,windows,text); 3127 XHighlightLine(display,windows->image.id, 3128 windows->image.highlight_context,&segment_info); 3129 } 3130 else 3131 if (windows->info.mapped != MagickFalse) 3132 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3133 /* 3134 Wait for next event. 3135 */ 3136 XScreenEvent(display,windows,&event,exception); 3137 if (distance > 9) 3138 XHighlightLine(display,windows->image.id, 3139 windows->image.highlight_context,&segment_info); 3140 switch (event.type) 3141 { 3142 case ButtonPress: 3143 { 3144 segment_info.x2=(short int) event.xmotion.x; 3145 segment_info.y2=(short int) event.xmotion.y; 3146 break; 3147 } 3148 case ButtonRelease: 3149 { 3150 /* 3151 User has committed to chopping line. 3152 */ 3153 segment_info.x2=(short int) event.xbutton.x; 3154 segment_info.y2=(short int) event.xbutton.y; 3155 state|=ExitState; 3156 break; 3157 } 3158 case Expose: 3159 break; 3160 case MotionNotify: 3161 { 3162 segment_info.x2=(short int) event.xmotion.x; 3163 segment_info.y2=(short int) event.xmotion.y; 3164 } 3165 default: 3166 break; 3167 } 3168 /* 3169 Check boundary conditions. 3170 */ 3171 if (segment_info.x2 < 0) 3172 segment_info.x2=0; 3173 else 3174 if (segment_info.x2 > windows->image.ximage->width) 3175 segment_info.x2=windows->image.ximage->width; 3176 if (segment_info.y2 < 0) 3177 segment_info.y2=0; 3178 else 3179 if (segment_info.y2 > windows->image.ximage->height) 3180 segment_info.y2=windows->image.ximage->height; 3181 distance=(unsigned int) 3182 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3183 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3184 /* 3185 Compute chopping geometry. 3186 */ 3187 if (direction == HorizontalChopCommand) 3188 { 3189 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3190 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3191 chop_info.height=0; 3192 chop_info.y=0; 3193 if (segment_info.x1 > (int) segment_info.x2) 3194 { 3195 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3196 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3197 } 3198 } 3199 else 3200 { 3201 chop_info.width=0; 3202 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3203 chop_info.x=0; 3204 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3205 if (segment_info.y1 > segment_info.y2) 3206 { 3207 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3208 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3209 } 3210 } 3211 } while ((state & ExitState) == 0); 3212 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3213 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3214 if (distance <= 9) 3215 return(MagickTrue); 3216 /* 3217 Image chopping is relative to image configuration. 3218 */ 3219 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3220 exception); 3221 XSetCursorState(display,windows,MagickTrue); 3222 XCheckRefreshWindows(display,windows); 3223 windows->image.window_changes.width=windows->image.ximage->width- 3224 (unsigned int) chop_info.width; 3225 windows->image.window_changes.height=windows->image.ximage->height- 3226 (unsigned int) chop_info.height; 3227 width=(unsigned int) (*image)->columns; 3228 height=(unsigned int) (*image)->rows; 3229 x=0; 3230 y=0; 3231 if (windows->image.crop_geometry != (char *) NULL) 3232 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3233 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3234 chop_info.x+=x; 3235 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3236 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3237 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3238 chop_info.y+=y; 3239 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3240 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3241 /* 3242 Chop image. 3243 */ 3244 chop_image=ChopImage(*image,&chop_info,exception); 3245 XSetCursorState(display,windows,MagickFalse); 3246 if (chop_image == (Image *) NULL) 3247 return(MagickFalse); 3248 *image=DestroyImage(*image); 3249 *image=chop_image; 3250 /* 3251 Update image configuration. 3252 */ 3253 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3254 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3255 return(MagickTrue); 3256} 3257 3258/* 3259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3260% % 3261% % 3262% % 3263+ X C o l o r E d i t I m a g e % 3264% % 3265% % 3266% % 3267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3268% 3269% XColorEditImage() allows the user to interactively change the color of one 3270% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3271% 3272% The format of the XColorEditImage method is: 3273% 3274% MagickBooleanType XColorEditImage(Display *display, 3275% XResourceInfo *resource_info,XWindows *windows,Image **image, 3276% ExceptionInfo *exception) 3277% 3278% A description of each parameter follows: 3279% 3280% o display: Specifies a connection to an X server; returned from 3281% XOpenDisplay. 3282% 3283% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3284% 3285% o windows: Specifies a pointer to a XWindows structure. 3286% 3287% o image: the image; returned from ReadImage. 3288% 3289% o exception: return any errors or warnings in this structure. 3290% 3291*/ 3292static MagickBooleanType XColorEditImage(Display *display, 3293 XResourceInfo *resource_info,XWindows *windows,Image **image, 3294 ExceptionInfo *exception) 3295{ 3296 static const char 3297 *ColorEditMenu[] = 3298 { 3299 "Method", 3300 "Pixel Color", 3301 "Border Color", 3302 "Fuzz", 3303 "Undo", 3304 "Help", 3305 "Dismiss", 3306 (char *) NULL 3307 }; 3308 3309 static const ModeType 3310 ColorEditCommands[] = 3311 { 3312 ColorEditMethodCommand, 3313 ColorEditColorCommand, 3314 ColorEditBorderCommand, 3315 ColorEditFuzzCommand, 3316 ColorEditUndoCommand, 3317 ColorEditHelpCommand, 3318 ColorEditDismissCommand 3319 }; 3320 3321 static PaintMethod 3322 method = PointMethod; 3323 3324 static unsigned int 3325 pen_id = 0; 3326 3327 static XColor 3328 border_color = { 0, 0, 0, 0, 0, 0 }; 3329 3330 char 3331 command[MaxTextExtent], 3332 text[MaxTextExtent]; 3333 3334 Cursor 3335 cursor; 3336 3337 int 3338 entry, 3339 id, 3340 x, 3341 x_offset, 3342 y, 3343 y_offset; 3344 3345 register Quantum 3346 *q; 3347 3348 register ssize_t 3349 i; 3350 3351 unsigned int 3352 height, 3353 width; 3354 3355 size_t 3356 state; 3357 3358 XColor 3359 color; 3360 3361 XEvent 3362 event; 3363 3364 /* 3365 Map Command widget. 3366 */ 3367 (void) CloneString(&windows->command.name,"Color Edit"); 3368 windows->command.data=4; 3369 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3370 (void) XMapRaised(display,windows->command.id); 3371 XClientMessage(display,windows->image.id,windows->im_protocols, 3372 windows->im_update_widget,CurrentTime); 3373 /* 3374 Make cursor. 3375 */ 3376 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3377 resource_info->background_color,resource_info->foreground_color); 3378 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3379 /* 3380 Track pointer until button 1 is pressed. 3381 */ 3382 XQueryPosition(display,windows->image.id,&x,&y); 3383 (void) XSelectInput(display,windows->image.id, 3384 windows->image.attributes.event_mask | PointerMotionMask); 3385 state=DefaultState; 3386 do 3387 { 3388 if (windows->info.mapped != MagickFalse) 3389 { 3390 /* 3391 Display pointer position. 3392 */ 3393 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3394 x+windows->image.x,y+windows->image.y); 3395 XInfoWidget(display,windows,text); 3396 } 3397 /* 3398 Wait for next event. 3399 */ 3400 XScreenEvent(display,windows,&event,exception); 3401 if (event.xany.window == windows->command.id) 3402 { 3403 /* 3404 Select a command from the Command widget. 3405 */ 3406 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3407 if (id < 0) 3408 { 3409 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3410 continue; 3411 } 3412 switch (ColorEditCommands[id]) 3413 { 3414 case ColorEditMethodCommand: 3415 { 3416 char 3417 **methods; 3418 3419 /* 3420 Select a method from the pop-up menu. 3421 */ 3422 methods=(char **) GetCommandOptions(MagickMethodOptions); 3423 if (methods == (char **) NULL) 3424 break; 3425 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3426 (const char **) methods,command); 3427 if (entry >= 0) 3428 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3429 MagickFalse,methods[entry]); 3430 methods=DestroyStringList(methods); 3431 break; 3432 } 3433 case ColorEditColorCommand: 3434 { 3435 const char 3436 *ColorMenu[MaxNumberPens]; 3437 3438 int 3439 pen_number; 3440 3441 /* 3442 Initialize menu selections. 3443 */ 3444 for (i=0; i < (int) (MaxNumberPens-2); i++) 3445 ColorMenu[i]=resource_info->pen_colors[i]; 3446 ColorMenu[MaxNumberPens-2]="Browser..."; 3447 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3448 /* 3449 Select a pen color from the pop-up menu. 3450 */ 3451 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3452 (const char **) ColorMenu,command); 3453 if (pen_number < 0) 3454 break; 3455 if (pen_number == (MaxNumberPens-2)) 3456 { 3457 static char 3458 color_name[MaxTextExtent] = "gray"; 3459 3460 /* 3461 Select a pen color from a dialog. 3462 */ 3463 resource_info->pen_colors[pen_number]=color_name; 3464 XColorBrowserWidget(display,windows,"Select",color_name); 3465 if (*color_name == '\0') 3466 break; 3467 } 3468 /* 3469 Set pen color. 3470 */ 3471 (void) XParseColor(display,windows->map_info->colormap, 3472 resource_info->pen_colors[pen_number],&color); 3473 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3474 (unsigned int) MaxColors,&color); 3475 windows->pixel_info->pen_colors[pen_number]=color; 3476 pen_id=(unsigned int) pen_number; 3477 break; 3478 } 3479 case ColorEditBorderCommand: 3480 { 3481 const char 3482 *ColorMenu[MaxNumberPens]; 3483 3484 int 3485 pen_number; 3486 3487 /* 3488 Initialize menu selections. 3489 */ 3490 for (i=0; i < (int) (MaxNumberPens-2); i++) 3491 ColorMenu[i]=resource_info->pen_colors[i]; 3492 ColorMenu[MaxNumberPens-2]="Browser..."; 3493 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3494 /* 3495 Select a pen color from the pop-up menu. 3496 */ 3497 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3498 (const char **) ColorMenu,command); 3499 if (pen_number < 0) 3500 break; 3501 if (pen_number == (MaxNumberPens-2)) 3502 { 3503 static char 3504 color_name[MaxTextExtent] = "gray"; 3505 3506 /* 3507 Select a pen color from a dialog. 3508 */ 3509 resource_info->pen_colors[pen_number]=color_name; 3510 XColorBrowserWidget(display,windows,"Select",color_name); 3511 if (*color_name == '\0') 3512 break; 3513 } 3514 /* 3515 Set border color. 3516 */ 3517 (void) XParseColor(display,windows->map_info->colormap, 3518 resource_info->pen_colors[pen_number],&border_color); 3519 break; 3520 } 3521 case ColorEditFuzzCommand: 3522 { 3523 static char 3524 fuzz[MaxTextExtent]; 3525 3526 static const char 3527 *FuzzMenu[] = 3528 { 3529 "0%", 3530 "2%", 3531 "5%", 3532 "10%", 3533 "15%", 3534 "Dialog...", 3535 (char *) NULL, 3536 }; 3537 3538 /* 3539 Select a command from the pop-up menu. 3540 */ 3541 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3542 command); 3543 if (entry < 0) 3544 break; 3545 if (entry != 5) 3546 { 3547 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3548 QuantumRange+1.0); 3549 break; 3550 } 3551 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3552 (void) XDialogWidget(display,windows,"Ok", 3553 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3554 if (*fuzz == '\0') 3555 break; 3556 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3557 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3558 1.0); 3559 break; 3560 } 3561 case ColorEditUndoCommand: 3562 { 3563 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3564 image,exception); 3565 break; 3566 } 3567 case ColorEditHelpCommand: 3568 default: 3569 { 3570 XTextViewWidget(display,resource_info,windows,MagickFalse, 3571 "Help Viewer - Image Annotation",ImageColorEditHelp); 3572 break; 3573 } 3574 case ColorEditDismissCommand: 3575 { 3576 /* 3577 Prematurely exit. 3578 */ 3579 state|=EscapeState; 3580 state|=ExitState; 3581 break; 3582 } 3583 } 3584 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3585 continue; 3586 } 3587 switch (event.type) 3588 { 3589 case ButtonPress: 3590 { 3591 if (event.xbutton.button != Button1) 3592 break; 3593 if ((event.xbutton.window != windows->image.id) && 3594 (event.xbutton.window != windows->magnify.id)) 3595 break; 3596 /* 3597 exit loop. 3598 */ 3599 x=event.xbutton.x; 3600 y=event.xbutton.y; 3601 (void) XMagickCommand(display,resource_info,windows, 3602 SaveToUndoBufferCommand,image,exception); 3603 state|=UpdateConfigurationState; 3604 break; 3605 } 3606 case ButtonRelease: 3607 { 3608 if (event.xbutton.button != Button1) 3609 break; 3610 if ((event.xbutton.window != windows->image.id) && 3611 (event.xbutton.window != windows->magnify.id)) 3612 break; 3613 /* 3614 Update colormap information. 3615 */ 3616 x=event.xbutton.x; 3617 y=event.xbutton.y; 3618 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3619 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3620 XInfoWidget(display,windows,text); 3621 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3622 state&=(~UpdateConfigurationState); 3623 break; 3624 } 3625 case Expose: 3626 break; 3627 case KeyPress: 3628 { 3629 KeySym 3630 key_symbol; 3631 3632 if (event.xkey.window == windows->magnify.id) 3633 { 3634 Window 3635 window; 3636 3637 window=windows->magnify.id; 3638 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3639 } 3640 if (event.xkey.window != windows->image.id) 3641 break; 3642 /* 3643 Respond to a user key press. 3644 */ 3645 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3646 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3647 switch ((int) key_symbol) 3648 { 3649 case XK_Escape: 3650 case XK_F20: 3651 { 3652 /* 3653 Prematurely exit. 3654 */ 3655 state|=ExitState; 3656 break; 3657 } 3658 case XK_F1: 3659 case XK_Help: 3660 { 3661 XTextViewWidget(display,resource_info,windows,MagickFalse, 3662 "Help Viewer - Image Annotation",ImageColorEditHelp); 3663 break; 3664 } 3665 default: 3666 { 3667 (void) XBell(display,0); 3668 break; 3669 } 3670 } 3671 break; 3672 } 3673 case MotionNotify: 3674 { 3675 /* 3676 Map and unmap Info widget as cursor crosses its boundaries. 3677 */ 3678 x=event.xmotion.x; 3679 y=event.xmotion.y; 3680 if (windows->info.mapped != MagickFalse) 3681 { 3682 if ((x < (int) (windows->info.x+windows->info.width)) && 3683 (y < (int) (windows->info.y+windows->info.height))) 3684 (void) XWithdrawWindow(display,windows->info.id, 3685 windows->info.screen); 3686 } 3687 else 3688 if ((x > (int) (windows->info.x+windows->info.width)) || 3689 (y > (int) (windows->info.y+windows->info.height))) 3690 (void) XMapWindow(display,windows->info.id); 3691 break; 3692 } 3693 default: 3694 break; 3695 } 3696 if (event.xany.window == windows->magnify.id) 3697 { 3698 x=windows->magnify.x-windows->image.x; 3699 y=windows->magnify.y-windows->image.y; 3700 } 3701 x_offset=x; 3702 y_offset=y; 3703 if ((state & UpdateConfigurationState) != 0) 3704 { 3705 CacheView 3706 *image_view; 3707 3708 int 3709 x, 3710 y; 3711 3712 /* 3713 Pixel edit is relative to image configuration. 3714 */ 3715 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3716 MagickTrue); 3717 color=windows->pixel_info->pen_colors[pen_id]; 3718 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3719 width=(unsigned int) (*image)->columns; 3720 height=(unsigned int) (*image)->rows; 3721 x=0; 3722 y=0; 3723 if (windows->image.crop_geometry != (char *) NULL) 3724 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3725 &width,&height); 3726 x_offset=(int) 3727 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3728 y_offset=(int) 3729 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3730 if ((x_offset < 0) || (y_offset < 0)) 3731 continue; 3732 if ((x_offset >= (int) (*image)->columns) || 3733 (y_offset >= (int) (*image)->rows)) 3734 continue; 3735 image_view=AcquireCacheView(*image); 3736 switch (method) 3737 { 3738 case PointMethod: 3739 default: 3740 { 3741 /* 3742 Update color information using point algorithm. 3743 */ 3744 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3745 return(MagickFalse); 3746 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3747 (ssize_t) y_offset,1,1,exception); 3748 if (q == (Quantum *) NULL) 3749 break; 3750 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3751 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3752 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3753 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3754 break; 3755 } 3756 case ReplaceMethod: 3757 { 3758 PixelInfo 3759 pixel, 3760 target; 3761 3762 Quantum 3763 virtual_pixel[CompositePixelChannel]; 3764 3765 /* 3766 Update color information using replace algorithm. 3767 */ 3768 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3769 (ssize_t) y_offset,virtual_pixel,exception); 3770 target.red=virtual_pixel[RedPixelChannel]; 3771 target.green=virtual_pixel[GreenPixelChannel]; 3772 target.blue=virtual_pixel[BluePixelChannel]; 3773 target.alpha=virtual_pixel[AlphaPixelChannel]; 3774 if ((*image)->storage_class == DirectClass) 3775 { 3776 for (y=0; y < (int) (*image)->rows; y++) 3777 { 3778 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3779 (*image)->columns,1,exception); 3780 if (q == (Quantum *) NULL) 3781 break; 3782 for (x=0; x < (int) (*image)->columns; x++) 3783 { 3784 GetPixelInfoPixel(*image,q,&pixel); 3785 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3786 { 3787 SetPixelRed(*image,ScaleShortToQuantum( 3788 color.red),q); 3789 SetPixelGreen(*image,ScaleShortToQuantum( 3790 color.green),q); 3791 SetPixelBlue(*image,ScaleShortToQuantum( 3792 color.blue),q); 3793 } 3794 q+=GetPixelChannels(*image); 3795 } 3796 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3797 break; 3798 } 3799 } 3800 else 3801 { 3802 for (i=0; i < (ssize_t) (*image)->colors; i++) 3803 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3804 { 3805 (*image)->colormap[i].red=ScaleShortToQuantum( 3806 color.red); 3807 (*image)->colormap[i].green=ScaleShortToQuantum( 3808 color.green); 3809 (*image)->colormap[i].blue=ScaleShortToQuantum( 3810 color.blue); 3811 } 3812 (void) SyncImage(*image,exception); 3813 } 3814 break; 3815 } 3816 case FloodfillMethod: 3817 case FillToBorderMethod: 3818 { 3819 DrawInfo 3820 *draw_info; 3821 3822 PixelInfo 3823 target; 3824 3825 /* 3826 Update color information using floodfill algorithm. 3827 */ 3828 (void) GetOneVirtualMagickPixel(*image, 3829 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3830 y_offset,&target,exception); 3831 if (method == FillToBorderMethod) 3832 { 3833 target.red=(MagickRealType) 3834 ScaleShortToQuantum(border_color.red); 3835 target.green=(MagickRealType) 3836 ScaleShortToQuantum(border_color.green); 3837 target.blue=(MagickRealType) 3838 ScaleShortToQuantum(border_color.blue); 3839 } 3840 draw_info=CloneDrawInfo(resource_info->image_info, 3841 (DrawInfo *) NULL); 3842 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3843 AllCompliance,&draw_info->fill,exception); 3844 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3845 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3846 MagickFalse : MagickTrue,exception); 3847 draw_info=DestroyDrawInfo(draw_info); 3848 break; 3849 } 3850 case ResetMethod: 3851 { 3852 /* 3853 Update color information using reset algorithm. 3854 */ 3855 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3856 return(MagickFalse); 3857 for (y=0; y < (int) (*image)->rows; y++) 3858 { 3859 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3860 (*image)->columns,1,exception); 3861 if (q == (Quantum *) NULL) 3862 break; 3863 for (x=0; x < (int) (*image)->columns; x++) 3864 { 3865 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3866 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3867 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3868 q+=GetPixelChannels(*image); 3869 } 3870 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3871 break; 3872 } 3873 break; 3874 } 3875 } 3876 image_view=DestroyCacheView(image_view); 3877 state&=(~UpdateConfigurationState); 3878 } 3879 } while ((state & ExitState) == 0); 3880 (void) XSelectInput(display,windows->image.id, 3881 windows->image.attributes.event_mask); 3882 XSetCursorState(display,windows,MagickFalse); 3883 (void) XFreeCursor(display,cursor); 3884 return(MagickTrue); 3885} 3886 3887/* 3888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3889% % 3890% % 3891% % 3892+ X C o m p o s i t e I m a g e % 3893% % 3894% % 3895% % 3896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3897% 3898% XCompositeImage() requests an image name from the user, reads the image and 3899% composites it with the X window image at a location the user chooses with 3900% the pointer. 3901% 3902% The format of the XCompositeImage method is: 3903% 3904% MagickBooleanType XCompositeImage(Display *display, 3905% XResourceInfo *resource_info,XWindows *windows,Image *image, 3906% ExceptionInfo *exception) 3907% 3908% A description of each parameter follows: 3909% 3910% o display: Specifies a connection to an X server; returned from 3911% XOpenDisplay. 3912% 3913% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3914% 3915% o windows: Specifies a pointer to a XWindows structure. 3916% 3917% o image: the image; returned from ReadImage. 3918% 3919% o exception: return any errors or warnings in this structure. 3920% 3921*/ 3922static MagickBooleanType XCompositeImage(Display *display, 3923 XResourceInfo *resource_info,XWindows *windows,Image *image, 3924 ExceptionInfo *exception) 3925{ 3926 static char 3927 displacement_geometry[MaxTextExtent] = "30x30", 3928 filename[MaxTextExtent] = "\0"; 3929 3930 static const char 3931 *CompositeMenu[] = 3932 { 3933 "Operators", 3934 "Dissolve", 3935 "Displace", 3936 "Help", 3937 "Dismiss", 3938 (char *) NULL 3939 }; 3940 3941 static CompositeOperator 3942 compose = CopyCompositeOp; 3943 3944 static const ModeType 3945 CompositeCommands[] = 3946 { 3947 CompositeOperatorsCommand, 3948 CompositeDissolveCommand, 3949 CompositeDisplaceCommand, 3950 CompositeHelpCommand, 3951 CompositeDismissCommand 3952 }; 3953 3954 char 3955 text[MaxTextExtent]; 3956 3957 Cursor 3958 cursor; 3959 3960 Image 3961 *composite_image; 3962 3963 int 3964 entry, 3965 id, 3966 x, 3967 y; 3968 3969 MagickRealType 3970 blend, 3971 scale_factor; 3972 3973 RectangleInfo 3974 highlight_info, 3975 composite_info; 3976 3977 unsigned int 3978 height, 3979 width; 3980 3981 size_t 3982 state; 3983 3984 XEvent 3985 event; 3986 3987 /* 3988 Request image file name from user. 3989 */ 3990 XFileBrowserWidget(display,windows,"Composite",filename); 3991 if (*filename == '\0') 3992 return(MagickTrue); 3993 /* 3994 Read image. 3995 */ 3996 XSetCursorState(display,windows,MagickTrue); 3997 XCheckRefreshWindows(display,windows); 3998 (void) CopyMagickString(resource_info->image_info->filename,filename, 3999 MaxTextExtent); 4000 composite_image=ReadImage(resource_info->image_info,exception); 4001 CatchException(exception); 4002 XSetCursorState(display,windows,MagickFalse); 4003 if (composite_image == (Image *) NULL) 4004 return(MagickFalse); 4005 /* 4006 Map Command widget. 4007 */ 4008 (void) CloneString(&windows->command.name,"Composite"); 4009 windows->command.data=1; 4010 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4011 (void) XMapRaised(display,windows->command.id); 4012 XClientMessage(display,windows->image.id,windows->im_protocols, 4013 windows->im_update_widget,CurrentTime); 4014 /* 4015 Track pointer until button 1 is pressed. 4016 */ 4017 XQueryPosition(display,windows->image.id,&x,&y); 4018 (void) XSelectInput(display,windows->image.id, 4019 windows->image.attributes.event_mask | PointerMotionMask); 4020 composite_info.x=(ssize_t) windows->image.x+x; 4021 composite_info.y=(ssize_t) windows->image.y+y; 4022 composite_info.width=0; 4023 composite_info.height=0; 4024 cursor=XCreateFontCursor(display,XC_ul_angle); 4025 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4026 blend=0.0; 4027 state=DefaultState; 4028 do 4029 { 4030 if (windows->info.mapped != MagickFalse) 4031 { 4032 /* 4033 Display pointer position. 4034 */ 4035 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4036 (long) composite_info.x,(long) composite_info.y); 4037 XInfoWidget(display,windows,text); 4038 } 4039 highlight_info=composite_info; 4040 highlight_info.x=composite_info.x-windows->image.x; 4041 highlight_info.y=composite_info.y-windows->image.y; 4042 XHighlightRectangle(display,windows->image.id, 4043 windows->image.highlight_context,&highlight_info); 4044 /* 4045 Wait for next event. 4046 */ 4047 XScreenEvent(display,windows,&event,exception); 4048 XHighlightRectangle(display,windows->image.id, 4049 windows->image.highlight_context,&highlight_info); 4050 if (event.xany.window == windows->command.id) 4051 { 4052 /* 4053 Select a command from the Command widget. 4054 */ 4055 id=XCommandWidget(display,windows,CompositeMenu,&event); 4056 if (id < 0) 4057 continue; 4058 switch (CompositeCommands[id]) 4059 { 4060 case CompositeOperatorsCommand: 4061 { 4062 char 4063 command[MaxTextExtent], 4064 **operators; 4065 4066 /* 4067 Select a command from the pop-up menu. 4068 */ 4069 operators=GetCommandOptions(MagickComposeOptions); 4070 if (operators == (char **) NULL) 4071 break; 4072 entry=XMenuWidget(display,windows,CompositeMenu[id], 4073 (const char **) operators,command); 4074 if (entry >= 0) 4075 compose=(CompositeOperator) ParseCommandOption( 4076 MagickComposeOptions,MagickFalse,operators[entry]); 4077 operators=DestroyStringList(operators); 4078 break; 4079 } 4080 case CompositeDissolveCommand: 4081 { 4082 static char 4083 factor[MaxTextExtent] = "20.0"; 4084 4085 /* 4086 Dissolve the two images a given percent. 4087 */ 4088 (void) XSetFunction(display,windows->image.highlight_context, 4089 GXcopy); 4090 (void) XDialogWidget(display,windows,"Dissolve", 4091 "Enter the blend factor (0.0 - 99.9%):",factor); 4092 (void) XSetFunction(display,windows->image.highlight_context, 4093 GXinvert); 4094 if (*factor == '\0') 4095 break; 4096 blend=StringToDouble(factor,(char **) NULL); 4097 compose=DissolveCompositeOp; 4098 break; 4099 } 4100 case CompositeDisplaceCommand: 4101 { 4102 /* 4103 Get horizontal and vertical scale displacement geometry. 4104 */ 4105 (void) XSetFunction(display,windows->image.highlight_context, 4106 GXcopy); 4107 (void) XDialogWidget(display,windows,"Displace", 4108 "Enter the horizontal and vertical scale:",displacement_geometry); 4109 (void) XSetFunction(display,windows->image.highlight_context, 4110 GXinvert); 4111 if (*displacement_geometry == '\0') 4112 break; 4113 compose=DisplaceCompositeOp; 4114 break; 4115 } 4116 case CompositeHelpCommand: 4117 { 4118 (void) XSetFunction(display,windows->image.highlight_context, 4119 GXcopy); 4120 XTextViewWidget(display,resource_info,windows,MagickFalse, 4121 "Help Viewer - Image Composite",ImageCompositeHelp); 4122 (void) XSetFunction(display,windows->image.highlight_context, 4123 GXinvert); 4124 break; 4125 } 4126 case CompositeDismissCommand: 4127 { 4128 /* 4129 Prematurely exit. 4130 */ 4131 state|=EscapeState; 4132 state|=ExitState; 4133 break; 4134 } 4135 default: 4136 break; 4137 } 4138 continue; 4139 } 4140 switch (event.type) 4141 { 4142 case ButtonPress: 4143 { 4144 if (image->debug != MagickFalse) 4145 (void) LogMagickEvent(X11Event,GetMagickModule(), 4146 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4147 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4148 if (event.xbutton.button != Button1) 4149 break; 4150 if (event.xbutton.window != windows->image.id) 4151 break; 4152 /* 4153 Change cursor. 4154 */ 4155 composite_info.width=composite_image->columns; 4156 composite_info.height=composite_image->rows; 4157 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4158 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4159 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4160 break; 4161 } 4162 case ButtonRelease: 4163 { 4164 if (image->debug != MagickFalse) 4165 (void) LogMagickEvent(X11Event,GetMagickModule(), 4166 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4167 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4168 if (event.xbutton.button != Button1) 4169 break; 4170 if (event.xbutton.window != windows->image.id) 4171 break; 4172 if ((composite_info.width != 0) && (composite_info.height != 0)) 4173 { 4174 /* 4175 User has selected the location of the composite image. 4176 */ 4177 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4178 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4179 state|=ExitState; 4180 } 4181 break; 4182 } 4183 case Expose: 4184 break; 4185 case KeyPress: 4186 { 4187 char 4188 command[MaxTextExtent]; 4189 4190 KeySym 4191 key_symbol; 4192 4193 int 4194 length; 4195 4196 if (event.xkey.window != windows->image.id) 4197 break; 4198 /* 4199 Respond to a user key press. 4200 */ 4201 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4202 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4203 *(command+length)='\0'; 4204 if (image->debug != MagickFalse) 4205 (void) LogMagickEvent(X11Event,GetMagickModule(), 4206 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4207 switch ((int) key_symbol) 4208 { 4209 case XK_Escape: 4210 case XK_F20: 4211 { 4212 /* 4213 Prematurely exit. 4214 */ 4215 composite_image=DestroyImage(composite_image); 4216 state|=EscapeState; 4217 state|=ExitState; 4218 break; 4219 } 4220 case XK_F1: 4221 case XK_Help: 4222 { 4223 (void) XSetFunction(display,windows->image.highlight_context, 4224 GXcopy); 4225 XTextViewWidget(display,resource_info,windows,MagickFalse, 4226 "Help Viewer - Image Composite",ImageCompositeHelp); 4227 (void) XSetFunction(display,windows->image.highlight_context, 4228 GXinvert); 4229 break; 4230 } 4231 default: 4232 { 4233 (void) XBell(display,0); 4234 break; 4235 } 4236 } 4237 break; 4238 } 4239 case MotionNotify: 4240 { 4241 /* 4242 Map and unmap Info widget as text cursor crosses its boundaries. 4243 */ 4244 x=event.xmotion.x; 4245 y=event.xmotion.y; 4246 if (windows->info.mapped != MagickFalse) 4247 { 4248 if ((x < (int) (windows->info.x+windows->info.width)) && 4249 (y < (int) (windows->info.y+windows->info.height))) 4250 (void) XWithdrawWindow(display,windows->info.id, 4251 windows->info.screen); 4252 } 4253 else 4254 if ((x > (int) (windows->info.x+windows->info.width)) || 4255 (y > (int) (windows->info.y+windows->info.height))) 4256 (void) XMapWindow(display,windows->info.id); 4257 composite_info.x=(ssize_t) windows->image.x+x; 4258 composite_info.y=(ssize_t) windows->image.y+y; 4259 break; 4260 } 4261 default: 4262 { 4263 if (image->debug != MagickFalse) 4264 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4265 event.type); 4266 break; 4267 } 4268 } 4269 } while ((state & ExitState) == 0); 4270 (void) XSelectInput(display,windows->image.id, 4271 windows->image.attributes.event_mask); 4272 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4273 XSetCursorState(display,windows,MagickFalse); 4274 (void) XFreeCursor(display,cursor); 4275 if ((state & EscapeState) != 0) 4276 return(MagickTrue); 4277 /* 4278 Image compositing is relative to image configuration. 4279 */ 4280 XSetCursorState(display,windows,MagickTrue); 4281 XCheckRefreshWindows(display,windows); 4282 width=(unsigned int) image->columns; 4283 height=(unsigned int) image->rows; 4284 x=0; 4285 y=0; 4286 if (windows->image.crop_geometry != (char *) NULL) 4287 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4288 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4289 composite_info.x+=x; 4290 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4291 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4292 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4293 composite_info.y+=y; 4294 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4295 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4296 if ((composite_info.width != composite_image->columns) || 4297 (composite_info.height != composite_image->rows)) 4298 { 4299 Image 4300 *resize_image; 4301 4302 /* 4303 Scale composite image. 4304 */ 4305 resize_image=ResizeImage(composite_image,composite_info.width, 4306 composite_info.height,composite_image->filter,composite_image->blur, 4307 exception); 4308 composite_image=DestroyImage(composite_image); 4309 if (resize_image == (Image *) NULL) 4310 { 4311 XSetCursorState(display,windows,MagickFalse); 4312 return(MagickFalse); 4313 } 4314 composite_image=resize_image; 4315 } 4316 if (compose == DisplaceCompositeOp) 4317 (void) SetImageArtifact(composite_image,"compose:args", 4318 displacement_geometry); 4319 if (blend != 0.0) 4320 { 4321 CacheView 4322 *image_view; 4323 4324 int 4325 y; 4326 4327 Quantum 4328 opacity; 4329 4330 register int 4331 x; 4332 4333 register Quantum 4334 *q; 4335 4336 /* 4337 Create mattes for blending. 4338 */ 4339 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4340 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4341 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4342 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4343 return(MagickFalse); 4344 image->matte=MagickTrue; 4345 image_view=AcquireCacheView(image); 4346 for (y=0; y < (int) image->rows; y++) 4347 { 4348 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4349 exception); 4350 if (q == (Quantum *) NULL) 4351 break; 4352 for (x=0; x < (int) image->columns; x++) 4353 { 4354 SetPixelAlpha(image,opacity,q); 4355 q+=GetPixelChannels(image); 4356 } 4357 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4358 break; 4359 } 4360 image_view=DestroyCacheView(image_view); 4361 } 4362 /* 4363 Composite image with X Image window. 4364 */ 4365 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4366 composite_info.y,exception); 4367 composite_image=DestroyImage(composite_image); 4368 XSetCursorState(display,windows,MagickFalse); 4369 /* 4370 Update image configuration. 4371 */ 4372 XConfigureImageColormap(display,resource_info,windows,image,exception); 4373 (void) XConfigureImage(display,resource_info,windows,image,exception); 4374 return(MagickTrue); 4375} 4376 4377/* 4378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4379% % 4380% % 4381% % 4382+ X C o n f i g u r e I m a g e % 4383% % 4384% % 4385% % 4386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4387% 4388% XConfigureImage() creates a new X image. It also notifies the window 4389% manager of the new image size and configures the transient widows. 4390% 4391% The format of the XConfigureImage method is: 4392% 4393% MagickBooleanType XConfigureImage(Display *display, 4394% XResourceInfo *resource_info,XWindows *windows,Image *image, 4395% ExceptionInfo *exception) 4396% 4397% A description of each parameter follows: 4398% 4399% o display: Specifies a connection to an X server; returned from 4400% XOpenDisplay. 4401% 4402% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4403% 4404% o windows: Specifies a pointer to a XWindows structure. 4405% 4406% o image: the image. 4407% 4408% o exception: return any errors or warnings in this structure. 4409% 4410% o exception: return any errors or warnings in this structure. 4411% 4412*/ 4413static MagickBooleanType XConfigureImage(Display *display, 4414 XResourceInfo *resource_info,XWindows *windows,Image *image, 4415 ExceptionInfo *exception) 4416{ 4417 char 4418 geometry[MaxTextExtent]; 4419 4420 MagickStatusType 4421 status; 4422 4423 size_t 4424 mask, 4425 height, 4426 width; 4427 4428 ssize_t 4429 x, 4430 y; 4431 4432 XSizeHints 4433 *size_hints; 4434 4435 XWindowChanges 4436 window_changes; 4437 4438 /* 4439 Dismiss if window dimensions are zero. 4440 */ 4441 width=(unsigned int) windows->image.window_changes.width; 4442 height=(unsigned int) windows->image.window_changes.height; 4443 if (image->debug != MagickFalse) 4444 (void) LogMagickEvent(X11Event,GetMagickModule(), 4445 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4446 windows->image.ximage->height,(double) width,(double) height); 4447 if ((width*height) == 0) 4448 return(MagickTrue); 4449 x=0; 4450 y=0; 4451 /* 4452 Resize image to fit Image window dimensions. 4453 */ 4454 XSetCursorState(display,windows,MagickTrue); 4455 (void) XFlush(display); 4456 if (((int) width != windows->image.ximage->width) || 4457 ((int) height != windows->image.ximage->height)) 4458 image->taint=MagickTrue; 4459 windows->magnify.x=(int) 4460 width*windows->magnify.x/windows->image.ximage->width; 4461 windows->magnify.y=(int) 4462 height*windows->magnify.y/windows->image.ximage->height; 4463 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4464 windows->image.y=(int) 4465 (height*windows->image.y/windows->image.ximage->height); 4466 status=XMakeImage(display,resource_info,&windows->image,image, 4467 (unsigned int) width,(unsigned int) height,exception); 4468 if (status == MagickFalse) 4469 XNoticeWidget(display,windows,"Unable to configure X image:", 4470 windows->image.name); 4471 /* 4472 Notify window manager of the new configuration. 4473 */ 4474 if (resource_info->image_geometry != (char *) NULL) 4475 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4476 resource_info->image_geometry); 4477 else 4478 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4479 XDisplayWidth(display,windows->image.screen), 4480 XDisplayHeight(display,windows->image.screen)); 4481 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4482 window_changes.width=(int) width; 4483 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4484 window_changes.width=XDisplayWidth(display,windows->image.screen); 4485 window_changes.height=(int) height; 4486 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4487 window_changes.height=XDisplayHeight(display,windows->image.screen); 4488 mask=(size_t) (CWWidth | CWHeight); 4489 if (resource_info->backdrop) 4490 { 4491 mask|=CWX | CWY; 4492 window_changes.x=(int) 4493 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4494 window_changes.y=(int) 4495 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4496 } 4497 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4498 (unsigned int) mask,&window_changes); 4499 (void) XClearWindow(display,windows->image.id); 4500 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4501 /* 4502 Update Magnify window configuration. 4503 */ 4504 if (windows->magnify.mapped != MagickFalse) 4505 XMakeMagnifyImage(display,windows,exception); 4506 windows->pan.crop_geometry=windows->image.crop_geometry; 4507 XBestIconSize(display,&windows->pan,image); 4508 while (((windows->pan.width << 1) < MaxIconSize) && 4509 ((windows->pan.height << 1) < MaxIconSize)) 4510 { 4511 windows->pan.width<<=1; 4512 windows->pan.height<<=1; 4513 } 4514 if (windows->pan.geometry != (char *) NULL) 4515 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4516 &windows->pan.width,&windows->pan.height); 4517 window_changes.width=(int) windows->pan.width; 4518 window_changes.height=(int) windows->pan.height; 4519 size_hints=XAllocSizeHints(); 4520 if (size_hints != (XSizeHints *) NULL) 4521 { 4522 /* 4523 Set new size hints. 4524 */ 4525 size_hints->flags=PSize | PMinSize | PMaxSize; 4526 size_hints->width=window_changes.width; 4527 size_hints->height=window_changes.height; 4528 size_hints->min_width=size_hints->width; 4529 size_hints->min_height=size_hints->height; 4530 size_hints->max_width=size_hints->width; 4531 size_hints->max_height=size_hints->height; 4532 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4533 (void) XFree((void *) size_hints); 4534 } 4535 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4536 (unsigned int) (CWWidth | CWHeight),&window_changes); 4537 /* 4538 Update icon window configuration. 4539 */ 4540 windows->icon.crop_geometry=windows->image.crop_geometry; 4541 XBestIconSize(display,&windows->icon,image); 4542 window_changes.width=(int) windows->icon.width; 4543 window_changes.height=(int) windows->icon.height; 4544 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4545 (unsigned int) (CWWidth | CWHeight),&window_changes); 4546 XSetCursorState(display,windows,MagickFalse); 4547 return(status != 0 ? MagickTrue : MagickFalse); 4548} 4549 4550/* 4551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4552% % 4553% % 4554% % 4555+ X C r o p I m a g e % 4556% % 4557% % 4558% % 4559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4560% 4561% XCropImage() allows the user to select a region of the image and crop, copy, 4562% or cut it. For copy or cut, the image can subsequently be composited onto 4563% the image with XPasteImage. 4564% 4565% The format of the XCropImage method is: 4566% 4567% MagickBooleanType XCropImage(Display *display, 4568% XResourceInfo *resource_info,XWindows *windows,Image *image, 4569% const ClipboardMode mode,ExceptionInfo *exception) 4570% 4571% A description of each parameter follows: 4572% 4573% o display: Specifies a connection to an X server; returned from 4574% XOpenDisplay. 4575% 4576% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4577% 4578% o windows: Specifies a pointer to a XWindows structure. 4579% 4580% o image: the image; returned from ReadImage. 4581% 4582% o mode: This unsigned value specified whether the image should be 4583% cropped, copied, or cut. 4584% 4585% o exception: return any errors or warnings in this structure. 4586% 4587*/ 4588static MagickBooleanType XCropImage(Display *display, 4589 XResourceInfo *resource_info,XWindows *windows,Image *image, 4590 const ClipboardMode mode,ExceptionInfo *exception) 4591{ 4592 static const char 4593 *CropModeMenu[] = 4594 { 4595 "Help", 4596 "Dismiss", 4597 (char *) NULL 4598 }, 4599 *RectifyModeMenu[] = 4600 { 4601 "Crop", 4602 "Help", 4603 "Dismiss", 4604 (char *) NULL 4605 }; 4606 4607 static const ModeType 4608 CropCommands[] = 4609 { 4610 CropHelpCommand, 4611 CropDismissCommand 4612 }, 4613 RectifyCommands[] = 4614 { 4615 RectifyCopyCommand, 4616 RectifyHelpCommand, 4617 RectifyDismissCommand 4618 }; 4619 4620 CacheView 4621 *image_view; 4622 4623 char 4624 command[MaxTextExtent], 4625 text[MaxTextExtent]; 4626 4627 Cursor 4628 cursor; 4629 4630 int 4631 id, 4632 x, 4633 y; 4634 4635 KeySym 4636 key_symbol; 4637 4638 Image 4639 *crop_image; 4640 4641 MagickRealType 4642 scale_factor; 4643 4644 RectangleInfo 4645 crop_info, 4646 highlight_info; 4647 4648 register Quantum 4649 *q; 4650 4651 unsigned int 4652 height, 4653 width; 4654 4655 size_t 4656 state; 4657 4658 XEvent 4659 event; 4660 4661 /* 4662 Map Command widget. 4663 */ 4664 switch (mode) 4665 { 4666 case CopyMode: 4667 { 4668 (void) CloneString(&windows->command.name,"Copy"); 4669 break; 4670 } 4671 case CropMode: 4672 { 4673 (void) CloneString(&windows->command.name,"Crop"); 4674 break; 4675 } 4676 case CutMode: 4677 { 4678 (void) CloneString(&windows->command.name,"Cut"); 4679 break; 4680 } 4681 } 4682 RectifyModeMenu[0]=windows->command.name; 4683 windows->command.data=0; 4684 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4685 (void) XMapRaised(display,windows->command.id); 4686 XClientMessage(display,windows->image.id,windows->im_protocols, 4687 windows->im_update_widget,CurrentTime); 4688 /* 4689 Track pointer until button 1 is pressed. 4690 */ 4691 XQueryPosition(display,windows->image.id,&x,&y); 4692 (void) XSelectInput(display,windows->image.id, 4693 windows->image.attributes.event_mask | PointerMotionMask); 4694 crop_info.x=(ssize_t) windows->image.x+x; 4695 crop_info.y=(ssize_t) windows->image.y+y; 4696 crop_info.width=0; 4697 crop_info.height=0; 4698 cursor=XCreateFontCursor(display,XC_fleur); 4699 state=DefaultState; 4700 do 4701 { 4702 if (windows->info.mapped != MagickFalse) 4703 { 4704 /* 4705 Display pointer position. 4706 */ 4707 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4708 (long) crop_info.x,(long) crop_info.y); 4709 XInfoWidget(display,windows,text); 4710 } 4711 /* 4712 Wait for next event. 4713 */ 4714 XScreenEvent(display,windows,&event,exception); 4715 if (event.xany.window == windows->command.id) 4716 { 4717 /* 4718 Select a command from the Command widget. 4719 */ 4720 id=XCommandWidget(display,windows,CropModeMenu,&event); 4721 if (id < 0) 4722 continue; 4723 switch (CropCommands[id]) 4724 { 4725 case CropHelpCommand: 4726 { 4727 switch (mode) 4728 { 4729 case CopyMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Copy",ImageCopyHelp); 4733 break; 4734 } 4735 case CropMode: 4736 { 4737 XTextViewWidget(display,resource_info,windows,MagickFalse, 4738 "Help Viewer - Image Crop",ImageCropHelp); 4739 break; 4740 } 4741 case CutMode: 4742 { 4743 XTextViewWidget(display,resource_info,windows,MagickFalse, 4744 "Help Viewer - Image Cut",ImageCutHelp); 4745 break; 4746 } 4747 } 4748 break; 4749 } 4750 case CropDismissCommand: 4751 { 4752 /* 4753 Prematurely exit. 4754 */ 4755 state|=EscapeState; 4756 state|=ExitState; 4757 break; 4758 } 4759 default: 4760 break; 4761 } 4762 continue; 4763 } 4764 switch (event.type) 4765 { 4766 case ButtonPress: 4767 { 4768 if (event.xbutton.button != Button1) 4769 break; 4770 if (event.xbutton.window != windows->image.id) 4771 break; 4772 /* 4773 Note first corner of cropping rectangle-- exit loop. 4774 */ 4775 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4776 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4777 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4778 state|=ExitState; 4779 break; 4780 } 4781 case ButtonRelease: 4782 break; 4783 case Expose: 4784 break; 4785 case KeyPress: 4786 { 4787 if (event.xkey.window != windows->image.id) 4788 break; 4789 /* 4790 Respond to a user key press. 4791 */ 4792 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4793 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4794 switch ((int) key_symbol) 4795 { 4796 case XK_Escape: 4797 case XK_F20: 4798 { 4799 /* 4800 Prematurely exit. 4801 */ 4802 state|=EscapeState; 4803 state|=ExitState; 4804 break; 4805 } 4806 case XK_F1: 4807 case XK_Help: 4808 { 4809 switch (mode) 4810 { 4811 case CopyMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Copy",ImageCopyHelp); 4815 break; 4816 } 4817 case CropMode: 4818 { 4819 XTextViewWidget(display,resource_info,windows,MagickFalse, 4820 "Help Viewer - Image Crop",ImageCropHelp); 4821 break; 4822 } 4823 case CutMode: 4824 { 4825 XTextViewWidget(display,resource_info,windows,MagickFalse, 4826 "Help Viewer - Image Cut",ImageCutHelp); 4827 break; 4828 } 4829 } 4830 break; 4831 } 4832 default: 4833 { 4834 (void) XBell(display,0); 4835 break; 4836 } 4837 } 4838 break; 4839 } 4840 case MotionNotify: 4841 { 4842 if (event.xmotion.window != windows->image.id) 4843 break; 4844 /* 4845 Map and unmap Info widget as text cursor crosses its boundaries. 4846 */ 4847 x=event.xmotion.x; 4848 y=event.xmotion.y; 4849 if (windows->info.mapped != MagickFalse) 4850 { 4851 if ((x < (int) (windows->info.x+windows->info.width)) && 4852 (y < (int) (windows->info.y+windows->info.height))) 4853 (void) XWithdrawWindow(display,windows->info.id, 4854 windows->info.screen); 4855 } 4856 else 4857 if ((x > (int) (windows->info.x+windows->info.width)) || 4858 (y > (int) (windows->info.y+windows->info.height))) 4859 (void) XMapWindow(display,windows->info.id); 4860 crop_info.x=(ssize_t) windows->image.x+x; 4861 crop_info.y=(ssize_t) windows->image.y+y; 4862 break; 4863 } 4864 default: 4865 break; 4866 } 4867 } while ((state & ExitState) == 0); 4868 (void) XSelectInput(display,windows->image.id, 4869 windows->image.attributes.event_mask); 4870 if ((state & EscapeState) != 0) 4871 { 4872 /* 4873 User want to exit without cropping. 4874 */ 4875 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4876 (void) XFreeCursor(display,cursor); 4877 return(MagickTrue); 4878 } 4879 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4880 do 4881 { 4882 /* 4883 Size rectangle as pointer moves until the mouse button is released. 4884 */ 4885 x=(int) crop_info.x; 4886 y=(int) crop_info.y; 4887 crop_info.width=0; 4888 crop_info.height=0; 4889 state=DefaultState; 4890 do 4891 { 4892 highlight_info=crop_info; 4893 highlight_info.x=crop_info.x-windows->image.x; 4894 highlight_info.y=crop_info.y-windows->image.y; 4895 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4896 { 4897 /* 4898 Display info and draw cropping rectangle. 4899 */ 4900 if (windows->info.mapped == MagickFalse) 4901 (void) XMapWindow(display,windows->info.id); 4902 (void) FormatLocaleString(text,MaxTextExtent, 4903 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4904 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4905 XInfoWidget(display,windows,text); 4906 XHighlightRectangle(display,windows->image.id, 4907 windows->image.highlight_context,&highlight_info); 4908 } 4909 else 4910 if (windows->info.mapped != MagickFalse) 4911 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4912 /* 4913 Wait for next event. 4914 */ 4915 XScreenEvent(display,windows,&event,exception); 4916 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4917 XHighlightRectangle(display,windows->image.id, 4918 windows->image.highlight_context,&highlight_info); 4919 switch (event.type) 4920 { 4921 case ButtonPress: 4922 { 4923 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4924 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4925 break; 4926 } 4927 case ButtonRelease: 4928 { 4929 /* 4930 User has committed to cropping rectangle. 4931 */ 4932 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4933 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4934 XSetCursorState(display,windows,MagickFalse); 4935 state|=ExitState; 4936 windows->command.data=0; 4937 (void) XCommandWidget(display,windows,RectifyModeMenu, 4938 (XEvent *) NULL); 4939 break; 4940 } 4941 case Expose: 4942 break; 4943 case MotionNotify: 4944 { 4945 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4946 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4947 } 4948 default: 4949 break; 4950 } 4951 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4952 ((state & ExitState) != 0)) 4953 { 4954 /* 4955 Check boundary conditions. 4956 */ 4957 if (crop_info.x < 0) 4958 crop_info.x=0; 4959 else 4960 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4961 crop_info.x=(ssize_t) windows->image.ximage->width; 4962 if ((int) crop_info.x < x) 4963 crop_info.width=(unsigned int) (x-crop_info.x); 4964 else 4965 { 4966 crop_info.width=(unsigned int) (crop_info.x-x); 4967 crop_info.x=(ssize_t) x; 4968 } 4969 if (crop_info.y < 0) 4970 crop_info.y=0; 4971 else 4972 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4973 crop_info.y=(ssize_t) windows->image.ximage->height; 4974 if ((int) crop_info.y < y) 4975 crop_info.height=(unsigned int) (y-crop_info.y); 4976 else 4977 { 4978 crop_info.height=(unsigned int) (crop_info.y-y); 4979 crop_info.y=(ssize_t) y; 4980 } 4981 } 4982 } while ((state & ExitState) == 0); 4983 /* 4984 Wait for user to grab a corner of the rectangle or press return. 4985 */ 4986 state=DefaultState; 4987 (void) XMapWindow(display,windows->info.id); 4988 do 4989 { 4990 if (windows->info.mapped != MagickFalse) 4991 { 4992 /* 4993 Display pointer position. 4994 */ 4995 (void) FormatLocaleString(text,MaxTextExtent, 4996 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4997 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4998 XInfoWidget(display,windows,text); 4999 } 5000 highlight_info=crop_info; 5001 highlight_info.x=crop_info.x-windows->image.x; 5002 highlight_info.y=crop_info.y-windows->image.y; 5003 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5004 { 5005 state|=EscapeState; 5006 state|=ExitState; 5007 break; 5008 } 5009 XHighlightRectangle(display,windows->image.id, 5010 windows->image.highlight_context,&highlight_info); 5011 XScreenEvent(display,windows,&event,exception); 5012 if (event.xany.window == windows->command.id) 5013 { 5014 /* 5015 Select a command from the Command widget. 5016 */ 5017 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5018 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5019 (void) XSetFunction(display,windows->image.highlight_context, 5020 GXinvert); 5021 XHighlightRectangle(display,windows->image.id, 5022 windows->image.highlight_context,&highlight_info); 5023 if (id >= 0) 5024 switch (RectifyCommands[id]) 5025 { 5026 case RectifyCopyCommand: 5027 { 5028 state|=ExitState; 5029 break; 5030 } 5031 case RectifyHelpCommand: 5032 { 5033 (void) XSetFunction(display,windows->image.highlight_context, 5034 GXcopy); 5035 switch (mode) 5036 { 5037 case CopyMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Copy",ImageCopyHelp); 5041 break; 5042 } 5043 case CropMode: 5044 { 5045 XTextViewWidget(display,resource_info,windows,MagickFalse, 5046 "Help Viewer - Image Crop",ImageCropHelp); 5047 break; 5048 } 5049 case CutMode: 5050 { 5051 XTextViewWidget(display,resource_info,windows,MagickFalse, 5052 "Help Viewer - Image Cut",ImageCutHelp); 5053 break; 5054 } 5055 } 5056 (void) XSetFunction(display,windows->image.highlight_context, 5057 GXinvert); 5058 break; 5059 } 5060 case RectifyDismissCommand: 5061 { 5062 /* 5063 Prematurely exit. 5064 */ 5065 state|=EscapeState; 5066 state|=ExitState; 5067 break; 5068 } 5069 default: 5070 break; 5071 } 5072 continue; 5073 } 5074 XHighlightRectangle(display,windows->image.id, 5075 windows->image.highlight_context,&highlight_info); 5076 switch (event.type) 5077 { 5078 case ButtonPress: 5079 { 5080 if (event.xbutton.button != Button1) 5081 break; 5082 if (event.xbutton.window != windows->image.id) 5083 break; 5084 x=windows->image.x+event.xbutton.x; 5085 y=windows->image.y+event.xbutton.y; 5086 if ((x < (int) (crop_info.x+RoiDelta)) && 5087 (x > (int) (crop_info.x-RoiDelta)) && 5088 (y < (int) (crop_info.y+RoiDelta)) && 5089 (y > (int) (crop_info.y-RoiDelta))) 5090 { 5091 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5092 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5093 state|=UpdateConfigurationState; 5094 break; 5095 } 5096 if ((x < (int) (crop_info.x+RoiDelta)) && 5097 (x > (int) (crop_info.x-RoiDelta)) && 5098 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5099 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5100 { 5101 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5102 state|=UpdateConfigurationState; 5103 break; 5104 } 5105 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5106 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5107 (y < (int) (crop_info.y+RoiDelta)) && 5108 (y > (int) (crop_info.y-RoiDelta))) 5109 { 5110 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5111 state|=UpdateConfigurationState; 5112 break; 5113 } 5114 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5115 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5116 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5117 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5118 { 5119 state|=UpdateConfigurationState; 5120 break; 5121 } 5122 } 5123 case ButtonRelease: 5124 { 5125 if (event.xbutton.window == windows->pan.id) 5126 if ((highlight_info.x != crop_info.x-windows->image.x) || 5127 (highlight_info.y != crop_info.y-windows->image.y)) 5128 XHighlightRectangle(display,windows->image.id, 5129 windows->image.highlight_context,&highlight_info); 5130 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5131 event.xbutton.time); 5132 break; 5133 } 5134 case Expose: 5135 { 5136 if (event.xexpose.window == windows->image.id) 5137 if (event.xexpose.count == 0) 5138 { 5139 event.xexpose.x=(int) highlight_info.x; 5140 event.xexpose.y=(int) highlight_info.y; 5141 event.xexpose.width=(int) highlight_info.width; 5142 event.xexpose.height=(int) highlight_info.height; 5143 XRefreshWindow(display,&windows->image,&event); 5144 } 5145 if (event.xexpose.window == windows->info.id) 5146 if (event.xexpose.count == 0) 5147 XInfoWidget(display,windows,text); 5148 break; 5149 } 5150 case KeyPress: 5151 { 5152 if (event.xkey.window != windows->image.id) 5153 break; 5154 /* 5155 Respond to a user key press. 5156 */ 5157 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5158 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5159 switch ((int) key_symbol) 5160 { 5161 case XK_Escape: 5162 case XK_F20: 5163 state|=EscapeState; 5164 case XK_Return: 5165 { 5166 state|=ExitState; 5167 break; 5168 } 5169 case XK_Home: 5170 case XK_KP_Home: 5171 { 5172 crop_info.x=(ssize_t) (windows->image.width/2L- 5173 crop_info.width/2L); 5174 crop_info.y=(ssize_t) (windows->image.height/2L- 5175 crop_info.height/2L); 5176 break; 5177 } 5178 case XK_Left: 5179 case XK_KP_Left: 5180 { 5181 crop_info.x--; 5182 break; 5183 } 5184 case XK_Up: 5185 case XK_KP_Up: 5186 case XK_Next: 5187 { 5188 crop_info.y--; 5189 break; 5190 } 5191 case XK_Right: 5192 case XK_KP_Right: 5193 { 5194 crop_info.x++; 5195 break; 5196 } 5197 case XK_Prior: 5198 case XK_Down: 5199 case XK_KP_Down: 5200 { 5201 crop_info.y++; 5202 break; 5203 } 5204 case XK_F1: 5205 case XK_Help: 5206 { 5207 (void) XSetFunction(display,windows->image.highlight_context, 5208 GXcopy); 5209 switch (mode) 5210 { 5211 case CopyMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Copy",ImageCopyHelp); 5215 break; 5216 } 5217 case CropMode: 5218 { 5219 XTextViewWidget(display,resource_info,windows,MagickFalse, 5220 "Help Viewer - Image Cropg",ImageCropHelp); 5221 break; 5222 } 5223 case CutMode: 5224 { 5225 XTextViewWidget(display,resource_info,windows,MagickFalse, 5226 "Help Viewer - Image Cutg",ImageCutHelp); 5227 break; 5228 } 5229 } 5230 (void) XSetFunction(display,windows->image.highlight_context, 5231 GXinvert); 5232 break; 5233 } 5234 default: 5235 { 5236 (void) XBell(display,0); 5237 break; 5238 } 5239 } 5240 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5241 event.xkey.time); 5242 break; 5243 } 5244 case KeyRelease: 5245 break; 5246 case MotionNotify: 5247 { 5248 if (event.xmotion.window != windows->image.id) 5249 break; 5250 /* 5251 Map and unmap Info widget as text cursor crosses its boundaries. 5252 */ 5253 x=event.xmotion.x; 5254 y=event.xmotion.y; 5255 if (windows->info.mapped != MagickFalse) 5256 { 5257 if ((x < (int) (windows->info.x+windows->info.width)) && 5258 (y < (int) (windows->info.y+windows->info.height))) 5259 (void) XWithdrawWindow(display,windows->info.id, 5260 windows->info.screen); 5261 } 5262 else 5263 if ((x > (int) (windows->info.x+windows->info.width)) || 5264 (y > (int) (windows->info.y+windows->info.height))) 5265 (void) XMapWindow(display,windows->info.id); 5266 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5267 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5268 break; 5269 } 5270 case SelectionRequest: 5271 { 5272 XSelectionEvent 5273 notify; 5274 5275 XSelectionRequestEvent 5276 *request; 5277 5278 /* 5279 Set primary selection. 5280 */ 5281 (void) FormatLocaleString(text,MaxTextExtent, 5282 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5283 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5284 request=(&(event.xselectionrequest)); 5285 (void) XChangeProperty(request->display,request->requestor, 5286 request->property,request->target,8,PropModeReplace, 5287 (unsigned char *) text,(int) strlen(text)); 5288 notify.type=SelectionNotify; 5289 notify.display=request->display; 5290 notify.requestor=request->requestor; 5291 notify.selection=request->selection; 5292 notify.target=request->target; 5293 notify.time=request->time; 5294 if (request->property == None) 5295 notify.property=request->target; 5296 else 5297 notify.property=request->property; 5298 (void) XSendEvent(request->display,request->requestor,False,0, 5299 (XEvent *) ¬ify); 5300 } 5301 default: 5302 break; 5303 } 5304 if ((state & UpdateConfigurationState) != 0) 5305 { 5306 (void) XPutBackEvent(display,&event); 5307 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5308 break; 5309 } 5310 } while ((state & ExitState) == 0); 5311 } while ((state & ExitState) == 0); 5312 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5313 XSetCursorState(display,windows,MagickFalse); 5314 if ((state & EscapeState) != 0) 5315 return(MagickTrue); 5316 if (mode == CropMode) 5317 if (((int) crop_info.width != windows->image.ximage->width) || 5318 ((int) crop_info.height != windows->image.ximage->height)) 5319 { 5320 /* 5321 Reconfigure Image window as defined by cropping rectangle. 5322 */ 5323 XSetCropGeometry(display,windows,&crop_info,image); 5324 windows->image.window_changes.width=(int) crop_info.width; 5325 windows->image.window_changes.height=(int) crop_info.height; 5326 (void) XConfigureImage(display,resource_info,windows,image,exception); 5327 return(MagickTrue); 5328 } 5329 /* 5330 Copy image before applying image transforms. 5331 */ 5332 XSetCursorState(display,windows,MagickTrue); 5333 XCheckRefreshWindows(display,windows); 5334 width=(unsigned int) image->columns; 5335 height=(unsigned int) image->rows; 5336 x=0; 5337 y=0; 5338 if (windows->image.crop_geometry != (char *) NULL) 5339 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5340 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5341 crop_info.x+=x; 5342 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5343 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5344 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5345 crop_info.y+=y; 5346 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5347 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5348 crop_image=CropImage(image,&crop_info,exception); 5349 XSetCursorState(display,windows,MagickFalse); 5350 if (crop_image == (Image *) NULL) 5351 return(MagickFalse); 5352 if (resource_info->copy_image != (Image *) NULL) 5353 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5354 resource_info->copy_image=crop_image; 5355 if (mode == CopyMode) 5356 { 5357 (void) XConfigureImage(display,resource_info,windows,image,exception); 5358 return(MagickTrue); 5359 } 5360 /* 5361 Cut image. 5362 */ 5363 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5364 return(MagickFalse); 5365 image->matte=MagickTrue; 5366 image_view=AcquireCacheView(image); 5367 for (y=0; y < (int) crop_info.height; y++) 5368 { 5369 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5370 crop_info.width,1,exception); 5371 if (q == (Quantum *) NULL) 5372 break; 5373 for (x=0; x < (int) crop_info.width; x++) 5374 { 5375 SetPixelAlpha(image,TransparentAlpha,q); 5376 q+=GetPixelChannels(image); 5377 } 5378 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5379 break; 5380 } 5381 image_view=DestroyCacheView(image_view); 5382 /* 5383 Update image configuration. 5384 */ 5385 XConfigureImageColormap(display,resource_info,windows,image,exception); 5386 (void) XConfigureImage(display,resource_info,windows,image,exception); 5387 return(MagickTrue); 5388} 5389 5390/* 5391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5392% % 5393% % 5394% % 5395+ X D r a w I m a g e % 5396% % 5397% % 5398% % 5399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5400% 5401% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5402% the image. 5403% 5404% The format of the XDrawEditImage method is: 5405% 5406% MagickBooleanType XDrawEditImage(Display *display, 5407% XResourceInfo *resource_info,XWindows *windows,Image **image, 5408% ExceptionInfo *exception) 5409% 5410% A description of each parameter follows: 5411% 5412% o display: Specifies a connection to an X server; returned from 5413% XOpenDisplay. 5414% 5415% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5416% 5417% o windows: Specifies a pointer to a XWindows structure. 5418% 5419% o image: the image. 5420% 5421% o exception: return any errors or warnings in this structure. 5422% 5423*/ 5424static MagickBooleanType XDrawEditImage(Display *display, 5425 XResourceInfo *resource_info,XWindows *windows,Image **image, 5426 ExceptionInfo *exception) 5427{ 5428 static const char 5429 *DrawMenu[] = 5430 { 5431 "Element", 5432 "Color", 5433 "Stipple", 5434 "Width", 5435 "Undo", 5436 "Help", 5437 "Dismiss", 5438 (char *) NULL 5439 }; 5440 5441 static ElementType 5442 element = PointElement; 5443 5444 static const ModeType 5445 DrawCommands[] = 5446 { 5447 DrawElementCommand, 5448 DrawColorCommand, 5449 DrawStippleCommand, 5450 DrawWidthCommand, 5451 DrawUndoCommand, 5452 DrawHelpCommand, 5453 DrawDismissCommand 5454 }; 5455 5456 static Pixmap 5457 stipple = (Pixmap) NULL; 5458 5459 static unsigned int 5460 pen_id = 0, 5461 line_width = 1; 5462 5463 char 5464 command[MaxTextExtent], 5465 text[MaxTextExtent]; 5466 5467 Cursor 5468 cursor; 5469 5470 int 5471 entry, 5472 id, 5473 number_coordinates, 5474 x, 5475 y; 5476 5477 MagickRealType 5478 degrees; 5479 5480 MagickStatusType 5481 status; 5482 5483 RectangleInfo 5484 rectangle_info; 5485 5486 register int 5487 i; 5488 5489 unsigned int 5490 distance, 5491 height, 5492 max_coordinates, 5493 width; 5494 5495 size_t 5496 state; 5497 5498 Window 5499 root_window; 5500 5501 XDrawInfo 5502 draw_info; 5503 5504 XEvent 5505 event; 5506 5507 XPoint 5508 *coordinate_info; 5509 5510 XSegment 5511 line_info; 5512 5513 /* 5514 Allocate polygon info. 5515 */ 5516 max_coordinates=2048; 5517 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5518 sizeof(*coordinate_info)); 5519 if (coordinate_info == (XPoint *) NULL) 5520 { 5521 (void) ThrowMagickException(exception,GetMagickModule(), 5522 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5523 return(MagickFalse); 5524 } 5525 /* 5526 Map Command widget. 5527 */ 5528 (void) CloneString(&windows->command.name,"Draw"); 5529 windows->command.data=4; 5530 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5531 (void) XMapRaised(display,windows->command.id); 5532 XClientMessage(display,windows->image.id,windows->im_protocols, 5533 windows->im_update_widget,CurrentTime); 5534 /* 5535 Wait for first button press. 5536 */ 5537 root_window=XRootWindow(display,XDefaultScreen(display)); 5538 draw_info.stencil=OpaqueStencil; 5539 status=MagickTrue; 5540 cursor=XCreateFontCursor(display,XC_tcross); 5541 for ( ; ; ) 5542 { 5543 XQueryPosition(display,windows->image.id,&x,&y); 5544 (void) XSelectInput(display,windows->image.id, 5545 windows->image.attributes.event_mask | PointerMotionMask); 5546 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5547 state=DefaultState; 5548 do 5549 { 5550 if (windows->info.mapped != MagickFalse) 5551 { 5552 /* 5553 Display pointer position. 5554 */ 5555 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5556 x+windows->image.x,y+windows->image.y); 5557 XInfoWidget(display,windows,text); 5558 } 5559 /* 5560 Wait for next event. 5561 */ 5562 XScreenEvent(display,windows,&event,exception); 5563 if (event.xany.window == windows->command.id) 5564 { 5565 /* 5566 Select a command from the Command widget. 5567 */ 5568 id=XCommandWidget(display,windows,DrawMenu,&event); 5569 if (id < 0) 5570 continue; 5571 switch (DrawCommands[id]) 5572 { 5573 case DrawElementCommand: 5574 { 5575 static const char 5576 *Elements[] = 5577 { 5578 "point", 5579 "line", 5580 "rectangle", 5581 "fill rectangle", 5582 "circle", 5583 "fill circle", 5584 "ellipse", 5585 "fill ellipse", 5586 "polygon", 5587 "fill polygon", 5588 (char *) NULL, 5589 }; 5590 5591 /* 5592 Select a command from the pop-up menu. 5593 */ 5594 element=(ElementType) (XMenuWidget(display,windows, 5595 DrawMenu[id],Elements,command)+1); 5596 break; 5597 } 5598 case DrawColorCommand: 5599 { 5600 const char 5601 *ColorMenu[MaxNumberPens+1]; 5602 5603 int 5604 pen_number; 5605 5606 MagickBooleanType 5607 transparent; 5608 5609 XColor 5610 color; 5611 5612 /* 5613 Initialize menu selections. 5614 */ 5615 for (i=0; i < (int) (MaxNumberPens-2); i++) 5616 ColorMenu[i]=resource_info->pen_colors[i]; 5617 ColorMenu[MaxNumberPens-2]="transparent"; 5618 ColorMenu[MaxNumberPens-1]="Browser..."; 5619 ColorMenu[MaxNumberPens]=(char *) NULL; 5620 /* 5621 Select a pen color from the pop-up menu. 5622 */ 5623 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5624 (const char **) ColorMenu,command); 5625 if (pen_number < 0) 5626 break; 5627 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5628 MagickFalse; 5629 if (transparent != MagickFalse) 5630 { 5631 draw_info.stencil=TransparentStencil; 5632 break; 5633 } 5634 if (pen_number == (MaxNumberPens-1)) 5635 { 5636 static char 5637 color_name[MaxTextExtent] = "gray"; 5638 5639 /* 5640 Select a pen color from a dialog. 5641 */ 5642 resource_info->pen_colors[pen_number]=color_name; 5643 XColorBrowserWidget(display,windows,"Select",color_name); 5644 if (*color_name == '\0') 5645 break; 5646 } 5647 /* 5648 Set pen color. 5649 */ 5650 (void) XParseColor(display,windows->map_info->colormap, 5651 resource_info->pen_colors[pen_number],&color); 5652 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5653 (unsigned int) MaxColors,&color); 5654 windows->pixel_info->pen_colors[pen_number]=color; 5655 pen_id=(unsigned int) pen_number; 5656 draw_info.stencil=OpaqueStencil; 5657 break; 5658 } 5659 case DrawStippleCommand: 5660 { 5661 Image 5662 *stipple_image; 5663 5664 ImageInfo 5665 *image_info; 5666 5667 int 5668 status; 5669 5670 static char 5671 filename[MaxTextExtent] = "\0"; 5672 5673 static const char 5674 *StipplesMenu[] = 5675 { 5676 "Brick", 5677 "Diagonal", 5678 "Scales", 5679 "Vertical", 5680 "Wavy", 5681 "Translucent", 5682 "Opaque", 5683 (char *) NULL, 5684 (char *) NULL, 5685 }; 5686 5687 /* 5688 Select a command from the pop-up menu. 5689 */ 5690 StipplesMenu[7]="Open..."; 5691 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5692 command); 5693 if (entry < 0) 5694 break; 5695 if (stipple != (Pixmap) NULL) 5696 (void) XFreePixmap(display,stipple); 5697 stipple=(Pixmap) NULL; 5698 if (entry != 7) 5699 { 5700 switch (entry) 5701 { 5702 case 0: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) BricksBitmap,BricksWidth,BricksHeight); 5706 break; 5707 } 5708 case 1: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5712 break; 5713 } 5714 case 2: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5718 break; 5719 } 5720 case 3: 5721 { 5722 stipple=XCreateBitmapFromData(display,root_window, 5723 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5724 break; 5725 } 5726 case 4: 5727 { 5728 stipple=XCreateBitmapFromData(display,root_window, 5729 (char *) WavyBitmap,WavyWidth,WavyHeight); 5730 break; 5731 } 5732 case 5: 5733 { 5734 stipple=XCreateBitmapFromData(display,root_window, 5735 (char *) HighlightBitmap,HighlightWidth, 5736 HighlightHeight); 5737 break; 5738 } 5739 case 6: 5740 default: 5741 { 5742 stipple=XCreateBitmapFromData(display,root_window, 5743 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5744 break; 5745 } 5746 } 5747 break; 5748 } 5749 XFileBrowserWidget(display,windows,"Stipple",filename); 5750 if (*filename == '\0') 5751 break; 5752 /* 5753 Read image. 5754 */ 5755 XSetCursorState(display,windows,MagickTrue); 5756 XCheckRefreshWindows(display,windows); 5757 image_info=AcquireImageInfo(); 5758 (void) CopyMagickString(image_info->filename,filename, 5759 MaxTextExtent); 5760 stipple_image=ReadImage(image_info,exception); 5761 CatchException(exception); 5762 XSetCursorState(display,windows,MagickFalse); 5763 if (stipple_image == (Image *) NULL) 5764 break; 5765 (void) AcquireUniqueFileResource(filename); 5766 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5767 "xbm:%s",filename); 5768 (void) WriteImage(image_info,stipple_image,exception); 5769 stipple_image=DestroyImage(stipple_image); 5770 image_info=DestroyImageInfo(image_info); 5771 status=XReadBitmapFile(display,root_window,filename,&width, 5772 &height,&stipple,&x,&y); 5773 (void) RelinquishUniqueFileResource(filename); 5774 if ((status != BitmapSuccess) != 0) 5775 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5776 filename); 5777 break; 5778 } 5779 case DrawWidthCommand: 5780 { 5781 static char 5782 width[MaxTextExtent] = "0"; 5783 5784 static const char 5785 *WidthsMenu[] = 5786 { 5787 "1", 5788 "2", 5789 "4", 5790 "8", 5791 "16", 5792 "Dialog...", 5793 (char *) NULL, 5794 }; 5795 5796 /* 5797 Select a command from the pop-up menu. 5798 */ 5799 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5800 command); 5801 if (entry < 0) 5802 break; 5803 if (entry != 5) 5804 { 5805 line_width=(unsigned int) StringToUnsignedLong( 5806 WidthsMenu[entry]); 5807 break; 5808 } 5809 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5810 width); 5811 if (*width == '\0') 5812 break; 5813 line_width=(unsigned int) StringToUnsignedLong(width); 5814 break; 5815 } 5816 case DrawUndoCommand: 5817 { 5818 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5819 image,exception); 5820 break; 5821 } 5822 case DrawHelpCommand: 5823 { 5824 XTextViewWidget(display,resource_info,windows,MagickFalse, 5825 "Help Viewer - Image Rotation",ImageDrawHelp); 5826 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5827 break; 5828 } 5829 case DrawDismissCommand: 5830 { 5831 /* 5832 Prematurely exit. 5833 */ 5834 state|=EscapeState; 5835 state|=ExitState; 5836 break; 5837 } 5838 default: 5839 break; 5840 } 5841 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5842 continue; 5843 } 5844 switch (event.type) 5845 { 5846 case ButtonPress: 5847 { 5848 if (event.xbutton.button != Button1) 5849 break; 5850 if (event.xbutton.window != windows->image.id) 5851 break; 5852 /* 5853 exit loop. 5854 */ 5855 x=event.xbutton.x; 5856 y=event.xbutton.y; 5857 state|=ExitState; 5858 break; 5859 } 5860 case ButtonRelease: 5861 break; 5862 case Expose: 5863 break; 5864 case KeyPress: 5865 { 5866 KeySym 5867 key_symbol; 5868 5869 if (event.xkey.window != windows->image.id) 5870 break; 5871 /* 5872 Respond to a user key press. 5873 */ 5874 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5875 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5876 switch ((int) key_symbol) 5877 { 5878 case XK_Escape: 5879 case XK_F20: 5880 { 5881 /* 5882 Prematurely exit. 5883 */ 5884 state|=EscapeState; 5885 state|=ExitState; 5886 break; 5887 } 5888 case XK_F1: 5889 case XK_Help: 5890 { 5891 XTextViewWidget(display,resource_info,windows,MagickFalse, 5892 "Help Viewer - Image Rotation",ImageDrawHelp); 5893 break; 5894 } 5895 default: 5896 { 5897 (void) XBell(display,0); 5898 break; 5899 } 5900 } 5901 break; 5902 } 5903 case MotionNotify: 5904 { 5905 /* 5906 Map and unmap Info widget as text cursor crosses its boundaries. 5907 */ 5908 x=event.xmotion.x; 5909 y=event.xmotion.y; 5910 if (windows->info.mapped != MagickFalse) 5911 { 5912 if ((x < (int) (windows->info.x+windows->info.width)) && 5913 (y < (int) (windows->info.y+windows->info.height))) 5914 (void) XWithdrawWindow(display,windows->info.id, 5915 windows->info.screen); 5916 } 5917 else 5918 if ((x > (int) (windows->info.x+windows->info.width)) || 5919 (y > (int) (windows->info.y+windows->info.height))) 5920 (void) XMapWindow(display,windows->info.id); 5921 break; 5922 } 5923 } 5924 } while ((state & ExitState) == 0); 5925 (void) XSelectInput(display,windows->image.id, 5926 windows->image.attributes.event_mask); 5927 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5928 if ((state & EscapeState) != 0) 5929 break; 5930 /* 5931 Draw element as pointer moves until the button is released. 5932 */ 5933 distance=0; 5934 degrees=0.0; 5935 line_info.x1=x; 5936 line_info.y1=y; 5937 line_info.x2=x; 5938 line_info.y2=y; 5939 rectangle_info.x=(ssize_t) x; 5940 rectangle_info.y=(ssize_t) y; 5941 rectangle_info.width=0; 5942 rectangle_info.height=0; 5943 number_coordinates=1; 5944 coordinate_info->x=x; 5945 coordinate_info->y=y; 5946 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5947 state=DefaultState; 5948 do 5949 { 5950 switch (element) 5951 { 5952 case PointElement: 5953 default: 5954 { 5955 if (number_coordinates > 1) 5956 { 5957 (void) XDrawLines(display,windows->image.id, 5958 windows->image.highlight_context,coordinate_info, 5959 number_coordinates,CoordModeOrigin); 5960 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5961 coordinate_info[number_coordinates-1].x, 5962 coordinate_info[number_coordinates-1].y); 5963 XInfoWidget(display,windows,text); 5964 } 5965 break; 5966 } 5967 case LineElement: 5968 { 5969 if (distance > 9) 5970 { 5971 /* 5972 Display angle of the line. 5973 */ 5974 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5975 line_info.y1),(double) (line_info.x2-line_info.x1))); 5976 (void) FormatLocaleString(text,MaxTextExtent," %g", 5977 (double) degrees); 5978 XInfoWidget(display,windows,text); 5979 XHighlightLine(display,windows->image.id, 5980 windows->image.highlight_context,&line_info); 5981 } 5982 else 5983 if (windows->info.mapped != MagickFalse) 5984 (void) XWithdrawWindow(display,windows->info.id, 5985 windows->info.screen); 5986 break; 5987 } 5988 case RectangleElement: 5989 case FillRectangleElement: 5990 { 5991 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5992 { 5993 /* 5994 Display info and draw drawing rectangle. 5995 */ 5996 (void) FormatLocaleString(text,MaxTextExtent, 5997 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5998 (double) rectangle_info.height,(double) rectangle_info.x, 5999 (double) rectangle_info.y); 6000 XInfoWidget(display,windows,text); 6001 XHighlightRectangle(display,windows->image.id, 6002 windows->image.highlight_context,&rectangle_info); 6003 } 6004 else 6005 if (windows->info.mapped != MagickFalse) 6006 (void) XWithdrawWindow(display,windows->info.id, 6007 windows->info.screen); 6008 break; 6009 } 6010 case CircleElement: 6011 case FillCircleElement: 6012 case EllipseElement: 6013 case FillEllipseElement: 6014 { 6015 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6016 { 6017 /* 6018 Display info and draw drawing rectangle. 6019 */ 6020 (void) FormatLocaleString(text,MaxTextExtent, 6021 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6022 (double) rectangle_info.height,(double) rectangle_info.x, 6023 (double) rectangle_info.y); 6024 XInfoWidget(display,windows,text); 6025 XHighlightEllipse(display,windows->image.id, 6026 windows->image.highlight_context,&rectangle_info); 6027 } 6028 else 6029 if (windows->info.mapped != MagickFalse) 6030 (void) XWithdrawWindow(display,windows->info.id, 6031 windows->info.screen); 6032 break; 6033 } 6034 case PolygonElement: 6035 case FillPolygonElement: 6036 { 6037 if (number_coordinates > 1) 6038 (void) XDrawLines(display,windows->image.id, 6039 windows->image.highlight_context,coordinate_info, 6040 number_coordinates,CoordModeOrigin); 6041 if (distance > 9) 6042 { 6043 /* 6044 Display angle of the line. 6045 */ 6046 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6047 line_info.y1),(double) (line_info.x2-line_info.x1))); 6048 (void) FormatLocaleString(text,MaxTextExtent," %g", 6049 (double) degrees); 6050 XInfoWidget(display,windows,text); 6051 XHighlightLine(display,windows->image.id, 6052 windows->image.highlight_context,&line_info); 6053 } 6054 else 6055 if (windows->info.mapped != MagickFalse) 6056 (void) XWithdrawWindow(display,windows->info.id, 6057 windows->info.screen); 6058 break; 6059 } 6060 } 6061 /* 6062 Wait for next event. 6063 */ 6064 XScreenEvent(display,windows,&event,exception); 6065 switch (element) 6066 { 6067 case PointElement: 6068 default: 6069 { 6070 if (number_coordinates > 1) 6071 (void) XDrawLines(display,windows->image.id, 6072 windows->image.highlight_context,coordinate_info, 6073 number_coordinates,CoordModeOrigin); 6074 break; 6075 } 6076 case LineElement: 6077 { 6078 if (distance > 9) 6079 XHighlightLine(display,windows->image.id, 6080 windows->image.highlight_context,&line_info); 6081 break; 6082 } 6083 case RectangleElement: 6084 case FillRectangleElement: 6085 { 6086 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6087 XHighlightRectangle(display,windows->image.id, 6088 windows->image.highlight_context,&rectangle_info); 6089 break; 6090 } 6091 case CircleElement: 6092 case FillCircleElement: 6093 case EllipseElement: 6094 case FillEllipseElement: 6095 { 6096 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6097 XHighlightEllipse(display,windows->image.id, 6098 windows->image.highlight_context,&rectangle_info); 6099 break; 6100 } 6101 case PolygonElement: 6102 case FillPolygonElement: 6103 { 6104 if (number_coordinates > 1) 6105 (void) XDrawLines(display,windows->image.id, 6106 windows->image.highlight_context,coordinate_info, 6107 number_coordinates,CoordModeOrigin); 6108 if (distance > 9) 6109 XHighlightLine(display,windows->image.id, 6110 windows->image.highlight_context,&line_info); 6111 break; 6112 } 6113 } 6114 switch (event.type) 6115 { 6116 case ButtonPress: 6117 break; 6118 case ButtonRelease: 6119 { 6120 /* 6121 User has committed to element. 6122 */ 6123 line_info.x2=event.xbutton.x; 6124 line_info.y2=event.xbutton.y; 6125 rectangle_info.x=(ssize_t) event.xbutton.x; 6126 rectangle_info.y=(ssize_t) event.xbutton.y; 6127 coordinate_info[number_coordinates].x=event.xbutton.x; 6128 coordinate_info[number_coordinates].y=event.xbutton.y; 6129 if (((element != PolygonElement) && 6130 (element != FillPolygonElement)) || (distance <= 9)) 6131 { 6132 state|=ExitState; 6133 break; 6134 } 6135 number_coordinates++; 6136 if (number_coordinates < (int) max_coordinates) 6137 { 6138 line_info.x1=event.xbutton.x; 6139 line_info.y1=event.xbutton.y; 6140 break; 6141 } 6142 max_coordinates<<=1; 6143 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6144 max_coordinates,sizeof(*coordinate_info)); 6145 if (coordinate_info == (XPoint *) NULL) 6146 (void) ThrowMagickException(exception,GetMagickModule(), 6147 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6148 break; 6149 } 6150 case Expose: 6151 break; 6152 case MotionNotify: 6153 { 6154 if (event.xmotion.window != windows->image.id) 6155 break; 6156 if (element != PointElement) 6157 { 6158 line_info.x2=event.xmotion.x; 6159 line_info.y2=event.xmotion.y; 6160 rectangle_info.x=(ssize_t) event.xmotion.x; 6161 rectangle_info.y=(ssize_t) event.xmotion.y; 6162 break; 6163 } 6164 coordinate_info[number_coordinates].x=event.xbutton.x; 6165 coordinate_info[number_coordinates].y=event.xbutton.y; 6166 number_coordinates++; 6167 if (number_coordinates < (int) max_coordinates) 6168 break; 6169 max_coordinates<<=1; 6170 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6171 max_coordinates,sizeof(*coordinate_info)); 6172 if (coordinate_info == (XPoint *) NULL) 6173 (void) ThrowMagickException(exception,GetMagickModule(), 6174 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6175 break; 6176 } 6177 default: 6178 break; 6179 } 6180 /* 6181 Check boundary conditions. 6182 */ 6183 if (line_info.x2 < 0) 6184 line_info.x2=0; 6185 else 6186 if (line_info.x2 > (int) windows->image.width) 6187 line_info.x2=(short) windows->image.width; 6188 if (line_info.y2 < 0) 6189 line_info.y2=0; 6190 else 6191 if (line_info.y2 > (int) windows->image.height) 6192 line_info.y2=(short) windows->image.height; 6193 distance=(unsigned int) 6194 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6195 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6196 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6197 ((state & ExitState) != 0)) 6198 { 6199 if (rectangle_info.x < 0) 6200 rectangle_info.x=0; 6201 else 6202 if (rectangle_info.x > (ssize_t) windows->image.width) 6203 rectangle_info.x=(ssize_t) windows->image.width; 6204 if ((int) rectangle_info.x < x) 6205 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6206 else 6207 { 6208 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6209 rectangle_info.x=(ssize_t) x; 6210 } 6211 if (rectangle_info.y < 0) 6212 rectangle_info.y=0; 6213 else 6214 if (rectangle_info.y > (ssize_t) windows->image.height) 6215 rectangle_info.y=(ssize_t) windows->image.height; 6216 if ((int) rectangle_info.y < y) 6217 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6218 else 6219 { 6220 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6221 rectangle_info.y=(ssize_t) y; 6222 } 6223 } 6224 } while ((state & ExitState) == 0); 6225 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6226 if ((element == PointElement) || (element == PolygonElement) || 6227 (element == FillPolygonElement)) 6228 { 6229 /* 6230 Determine polygon bounding box. 6231 */ 6232 rectangle_info.x=(ssize_t) coordinate_info->x; 6233 rectangle_info.y=(ssize_t) coordinate_info->y; 6234 x=coordinate_info->x; 6235 y=coordinate_info->y; 6236 for (i=1; i < number_coordinates; i++) 6237 { 6238 if (coordinate_info[i].x > x) 6239 x=coordinate_info[i].x; 6240 if (coordinate_info[i].y > y) 6241 y=coordinate_info[i].y; 6242 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6243 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6244 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6245 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6246 } 6247 rectangle_info.width=(size_t) (x-rectangle_info.x); 6248 rectangle_info.height=(size_t) (y-rectangle_info.y); 6249 for (i=0; i < number_coordinates; i++) 6250 { 6251 coordinate_info[i].x-=rectangle_info.x; 6252 coordinate_info[i].y-=rectangle_info.y; 6253 } 6254 } 6255 else 6256 if (distance <= 9) 6257 continue; 6258 else 6259 if ((element == RectangleElement) || 6260 (element == CircleElement) || (element == EllipseElement)) 6261 { 6262 rectangle_info.width--; 6263 rectangle_info.height--; 6264 } 6265 /* 6266 Drawing is relative to image configuration. 6267 */ 6268 draw_info.x=(int) rectangle_info.x; 6269 draw_info.y=(int) rectangle_info.y; 6270 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6271 image,exception); 6272 width=(unsigned int) (*image)->columns; 6273 height=(unsigned int) (*image)->rows; 6274 x=0; 6275 y=0; 6276 if (windows->image.crop_geometry != (char *) NULL) 6277 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6278 draw_info.x+=windows->image.x-(line_width/2); 6279 if (draw_info.x < 0) 6280 draw_info.x=0; 6281 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6282 draw_info.y+=windows->image.y-(line_width/2); 6283 if (draw_info.y < 0) 6284 draw_info.y=0; 6285 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6286 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6287 if (draw_info.width > (unsigned int) (*image)->columns) 6288 draw_info.width=(unsigned int) (*image)->columns; 6289 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6290 if (draw_info.height > (unsigned int) (*image)->rows) 6291 draw_info.height=(unsigned int) (*image)->rows; 6292 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6293 width*draw_info.width/windows->image.ximage->width, 6294 height*draw_info.height/windows->image.ximage->height, 6295 draw_info.x+x,draw_info.y+y); 6296 /* 6297 Initialize drawing attributes. 6298 */ 6299 draw_info.degrees=0.0; 6300 draw_info.element=element; 6301 draw_info.stipple=stipple; 6302 draw_info.line_width=line_width; 6303 draw_info.line_info=line_info; 6304 if (line_info.x1 > (int) (line_width/2)) 6305 draw_info.line_info.x1=(short) line_width/2; 6306 if (line_info.y1 > (int) (line_width/2)) 6307 draw_info.line_info.y1=(short) line_width/2; 6308 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6309 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6310 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6311 { 6312 draw_info.line_info.x2=(-draw_info.line_info.x2); 6313 draw_info.line_info.y2=(-draw_info.line_info.y2); 6314 } 6315 if (draw_info.line_info.x2 < 0) 6316 { 6317 draw_info.line_info.x2=(-draw_info.line_info.x2); 6318 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6319 } 6320 if (draw_info.line_info.y2 < 0) 6321 { 6322 draw_info.line_info.y2=(-draw_info.line_info.y2); 6323 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6324 } 6325 draw_info.rectangle_info=rectangle_info; 6326 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6327 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6328 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6329 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6330 draw_info.number_coordinates=(unsigned int) number_coordinates; 6331 draw_info.coordinate_info=coordinate_info; 6332 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6333 /* 6334 Draw element on image. 6335 */ 6336 XSetCursorState(display,windows,MagickTrue); 6337 XCheckRefreshWindows(display,windows); 6338 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6339 XSetCursorState(display,windows,MagickFalse); 6340 /* 6341 Update image colormap and return to image drawing. 6342 */ 6343 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6344 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6345 } 6346 XSetCursorState(display,windows,MagickFalse); 6347 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6348 return(status != 0 ? MagickTrue : MagickFalse); 6349} 6350 6351/* 6352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6353% % 6354% % 6355% % 6356+ X D r a w P a n R e c t a n g l e % 6357% % 6358% % 6359% % 6360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6361% 6362% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6363% displays a zoom image and the rectangle shows which portion of the image is 6364% displayed in the Image window. 6365% 6366% The format of the XDrawPanRectangle method is: 6367% 6368% XDrawPanRectangle(Display *display,XWindows *windows) 6369% 6370% A description of each parameter follows: 6371% 6372% o display: Specifies a connection to an X server; returned from 6373% XOpenDisplay. 6374% 6375% o windows: Specifies a pointer to a XWindows structure. 6376% 6377*/ 6378static void XDrawPanRectangle(Display *display,XWindows *windows) 6379{ 6380 MagickRealType 6381 scale_factor; 6382 6383 RectangleInfo 6384 highlight_info; 6385 6386 /* 6387 Determine dimensions of the panning rectangle. 6388 */ 6389 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6390 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6391 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6392 scale_factor=(MagickRealType) 6393 windows->pan.height/windows->image.ximage->height; 6394 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6395 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6396 /* 6397 Display the panning rectangle. 6398 */ 6399 (void) XClearWindow(display,windows->pan.id); 6400 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6401 &highlight_info); 6402} 6403 6404/* 6405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6406% % 6407% % 6408% % 6409+ X I m a g e C a c h e % 6410% % 6411% % 6412% % 6413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6414% 6415% XImageCache() handles the creation, manipulation, and destruction of the 6416% image cache (undo and redo buffers). 6417% 6418% The format of the XImageCache method is: 6419% 6420% void XImageCache(Display *display,XResourceInfo *resource_info, 6421% XWindows *windows,const CommandType command,Image **image, 6422% ExceptionInfo *exception) 6423% 6424% A description of each parameter follows: 6425% 6426% o display: Specifies a connection to an X server; returned from 6427% XOpenDisplay. 6428% 6429% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6430% 6431% o windows: Specifies a pointer to a XWindows structure. 6432% 6433% o command: Specifies a command to perform. 6434% 6435% o image: the image; XImageCache may transform the image and return a new 6436% image pointer. 6437% 6438% o exception: return any errors or warnings in this structure. 6439% 6440*/ 6441static void XImageCache(Display *display,XResourceInfo *resource_info, 6442 XWindows *windows,const CommandType command,Image **image, 6443 ExceptionInfo *exception) 6444{ 6445 Image 6446 *cache_image; 6447 6448 static Image 6449 *redo_image = (Image *) NULL, 6450 *undo_image = (Image *) NULL; 6451 6452 switch (command) 6453 { 6454 case FreeBuffersCommand: 6455 { 6456 /* 6457 Free memory from the undo and redo cache. 6458 */ 6459 while (undo_image != (Image *) NULL) 6460 { 6461 cache_image=undo_image; 6462 undo_image=GetPreviousImageInList(undo_image); 6463 cache_image->list=DestroyImage(cache_image->list); 6464 cache_image=DestroyImage(cache_image); 6465 } 6466 undo_image=NewImageList(); 6467 if (redo_image != (Image *) NULL) 6468 redo_image=DestroyImage(redo_image); 6469 redo_image=NewImageList(); 6470 return; 6471 } 6472 case UndoCommand: 6473 { 6474 char 6475 image_geometry[MaxTextExtent]; 6476 6477 /* 6478 Undo the last image transformation. 6479 */ 6480 if (undo_image == (Image *) NULL) 6481 { 6482 (void) XBell(display,0); 6483 return; 6484 } 6485 cache_image=undo_image; 6486 undo_image=GetPreviousImageInList(undo_image); 6487 windows->image.window_changes.width=(int) cache_image->columns; 6488 windows->image.window_changes.height=(int) cache_image->rows; 6489 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6490 windows->image.ximage->width,windows->image.ximage->height); 6491 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6492 exception); 6493 if (windows->image.crop_geometry != (char *) NULL) 6494 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6495 windows->image.crop_geometry); 6496 windows->image.crop_geometry=cache_image->geometry; 6497 if (redo_image != (Image *) NULL) 6498 redo_image=DestroyImage(redo_image); 6499 redo_image=(*image); 6500 *image=cache_image->list; 6501 cache_image=DestroyImage(cache_image); 6502 if (windows->image.orphan != MagickFalse) 6503 return; 6504 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6505 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6506 return; 6507 } 6508 case CutCommand: 6509 case PasteCommand: 6510 case ApplyCommand: 6511 case HalfSizeCommand: 6512 case OriginalSizeCommand: 6513 case DoubleSizeCommand: 6514 case ResizeCommand: 6515 case TrimCommand: 6516 case CropCommand: 6517 case ChopCommand: 6518 case FlipCommand: 6519 case FlopCommand: 6520 case RotateRightCommand: 6521 case RotateLeftCommand: 6522 case RotateCommand: 6523 case ShearCommand: 6524 case RollCommand: 6525 case NegateCommand: 6526 case ContrastStretchCommand: 6527 case SigmoidalContrastCommand: 6528 case NormalizeCommand: 6529 case EqualizeCommand: 6530 case HueCommand: 6531 case SaturationCommand: 6532 case BrightnessCommand: 6533 case GammaCommand: 6534 case SpiffCommand: 6535 case DullCommand: 6536 case GrayscaleCommand: 6537 case MapCommand: 6538 case QuantizeCommand: 6539 case DespeckleCommand: 6540 case EmbossCommand: 6541 case ReduceNoiseCommand: 6542 case AddNoiseCommand: 6543 case SharpenCommand: 6544 case BlurCommand: 6545 case ThresholdCommand: 6546 case EdgeDetectCommand: 6547 case SpreadCommand: 6548 case ShadeCommand: 6549 case RaiseCommand: 6550 case SegmentCommand: 6551 case SolarizeCommand: 6552 case SepiaToneCommand: 6553 case SwirlCommand: 6554 case ImplodeCommand: 6555 case VignetteCommand: 6556 case WaveCommand: 6557 case OilPaintCommand: 6558 case CharcoalDrawCommand: 6559 case AnnotateCommand: 6560 case AddBorderCommand: 6561 case AddFrameCommand: 6562 case CompositeCommand: 6563 case CommentCommand: 6564 case LaunchCommand: 6565 case RegionofInterestCommand: 6566 case SaveToUndoBufferCommand: 6567 case RedoCommand: 6568 { 6569 Image 6570 *previous_image; 6571 6572 ssize_t 6573 bytes; 6574 6575 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6576 if (undo_image != (Image *) NULL) 6577 { 6578 /* 6579 Ensure the undo cache has enough memory available. 6580 */ 6581 previous_image=undo_image; 6582 while (previous_image != (Image *) NULL) 6583 { 6584 bytes+=previous_image->list->columns*previous_image->list->rows* 6585 sizeof(PixelInfo); 6586 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6587 { 6588 previous_image=GetPreviousImageInList(previous_image); 6589 continue; 6590 } 6591 bytes-=previous_image->list->columns*previous_image->list->rows* 6592 sizeof(PixelInfo); 6593 if (previous_image == undo_image) 6594 undo_image=NewImageList(); 6595 else 6596 previous_image->next->previous=NewImageList(); 6597 break; 6598 } 6599 while (previous_image != (Image *) NULL) 6600 { 6601 /* 6602 Delete any excess memory from undo cache. 6603 */ 6604 cache_image=previous_image; 6605 previous_image=GetPreviousImageInList(previous_image); 6606 cache_image->list=DestroyImage(cache_image->list); 6607 cache_image=DestroyImage(cache_image); 6608 } 6609 } 6610 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6611 break; 6612 /* 6613 Save image before transformations are applied. 6614 */ 6615 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6616 if (cache_image == (Image *) NULL) 6617 break; 6618 XSetCursorState(display,windows,MagickTrue); 6619 XCheckRefreshWindows(display,windows); 6620 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6621 XSetCursorState(display,windows,MagickFalse); 6622 if (cache_image->list == (Image *) NULL) 6623 { 6624 cache_image=DestroyImage(cache_image); 6625 break; 6626 } 6627 cache_image->columns=(size_t) windows->image.ximage->width; 6628 cache_image->rows=(size_t) windows->image.ximage->height; 6629 cache_image->geometry=windows->image.crop_geometry; 6630 if (windows->image.crop_geometry != (char *) NULL) 6631 { 6632 cache_image->geometry=AcquireString((char *) NULL); 6633 (void) CopyMagickString(cache_image->geometry, 6634 windows->image.crop_geometry,MaxTextExtent); 6635 } 6636 if (undo_image == (Image *) NULL) 6637 { 6638 undo_image=cache_image; 6639 break; 6640 } 6641 undo_image->next=cache_image; 6642 undo_image->next->previous=undo_image; 6643 undo_image=undo_image->next; 6644 break; 6645 } 6646 default: 6647 break; 6648 } 6649 if (command == RedoCommand) 6650 { 6651 /* 6652 Redo the last image transformation. 6653 */ 6654 if (redo_image == (Image *) NULL) 6655 { 6656 (void) XBell(display,0); 6657 return; 6658 } 6659 windows->image.window_changes.width=(int) redo_image->columns; 6660 windows->image.window_changes.height=(int) redo_image->rows; 6661 if (windows->image.crop_geometry != (char *) NULL) 6662 windows->image.crop_geometry=(char *) 6663 RelinquishMagickMemory(windows->image.crop_geometry); 6664 windows->image.crop_geometry=redo_image->geometry; 6665 *image=DestroyImage(*image); 6666 *image=redo_image; 6667 redo_image=NewImageList(); 6668 if (windows->image.orphan != MagickFalse) 6669 return; 6670 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6671 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6672 return; 6673 } 6674 if (command != InfoCommand) 6675 return; 6676 /* 6677 Display image info. 6678 */ 6679 XSetCursorState(display,windows,MagickTrue); 6680 XCheckRefreshWindows(display,windows); 6681 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6682 XSetCursorState(display,windows,MagickFalse); 6683} 6684 6685/* 6686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6687% % 6688% % 6689% % 6690+ X I m a g e W i n d o w C o m m a n d % 6691% % 6692% % 6693% % 6694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6695% 6696% XImageWindowCommand() makes a transform to the image or Image window as 6697% specified by a user menu button or keyboard command. 6698% 6699% The format of the XImageWindowCommand method is: 6700% 6701% CommandType XImageWindowCommand(Display *display, 6702% XResourceInfo *resource_info,XWindows *windows, 6703% const MagickStatusType state,KeySym key_symbol,Image **image, 6704% ExceptionInfo *exception) 6705% 6706% A description of each parameter follows: 6707% 6708% o nexus: Method XImageWindowCommand returns an image when the 6709% user chooses 'Open Image' from the command menu. Otherwise a null 6710% image is returned. 6711% 6712% o display: Specifies a connection to an X server; returned from 6713% XOpenDisplay. 6714% 6715% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6716% 6717% o windows: Specifies a pointer to a XWindows structure. 6718% 6719% o state: key mask. 6720% 6721% o key_symbol: Specifies a command to perform. 6722% 6723% o image: the image; XImageWIndowCommand may transform the image and 6724% return a new image pointer. 6725% 6726% o exception: return any errors or warnings in this structure. 6727% 6728*/ 6729static CommandType XImageWindowCommand(Display *display, 6730 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6731 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6732{ 6733 static char 6734 delta[MaxTextExtent] = ""; 6735 6736 static const char 6737 Digits[] = "01234567890"; 6738 6739 static KeySym 6740 last_symbol = XK_0; 6741 6742 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6743 { 6744 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6745 { 6746 *delta='\0'; 6747 resource_info->quantum=1; 6748 } 6749 last_symbol=key_symbol; 6750 delta[strlen(delta)+1]='\0'; 6751 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6752 resource_info->quantum=StringToLong(delta); 6753 return(NullCommand); 6754 } 6755 last_symbol=key_symbol; 6756 if (resource_info->immutable) 6757 { 6758 /* 6759 Virtual image window has a restricted command set. 6760 */ 6761 switch (key_symbol) 6762 { 6763 case XK_question: 6764 return(InfoCommand); 6765 case XK_p: 6766 case XK_Print: 6767 return(PrintCommand); 6768 case XK_space: 6769 return(NextCommand); 6770 case XK_q: 6771 case XK_Escape: 6772 return(QuitCommand); 6773 default: 6774 break; 6775 } 6776 return(NullCommand); 6777 } 6778 switch ((int) key_symbol) 6779 { 6780 case XK_o: 6781 { 6782 if ((state & ControlMask) == 0) 6783 break; 6784 return(OpenCommand); 6785 } 6786 case XK_space: 6787 return(NextCommand); 6788 case XK_BackSpace: 6789 return(FormerCommand); 6790 case XK_s: 6791 { 6792 if ((state & Mod1Mask) != 0) 6793 return(SwirlCommand); 6794 if ((state & ControlMask) == 0) 6795 return(ShearCommand); 6796 return(SaveCommand); 6797 } 6798 case XK_p: 6799 case XK_Print: 6800 { 6801 if ((state & Mod1Mask) != 0) 6802 return(OilPaintCommand); 6803 if ((state & Mod4Mask) != 0) 6804 return(ColorCommand); 6805 if ((state & ControlMask) == 0) 6806 return(NullCommand); 6807 return(PrintCommand); 6808 } 6809 case XK_d: 6810 { 6811 if ((state & Mod4Mask) != 0) 6812 return(DrawCommand); 6813 if ((state & ControlMask) == 0) 6814 return(NullCommand); 6815 return(DeleteCommand); 6816 } 6817 case XK_Select: 6818 { 6819 if ((state & ControlMask) == 0) 6820 return(NullCommand); 6821 return(SelectCommand); 6822 } 6823 case XK_n: 6824 { 6825 if ((state & ControlMask) == 0) 6826 return(NullCommand); 6827 return(NewCommand); 6828 } 6829 case XK_q: 6830 case XK_Escape: 6831 return(QuitCommand); 6832 case XK_z: 6833 case XK_Undo: 6834 { 6835 if ((state & ControlMask) == 0) 6836 return(NullCommand); 6837 return(UndoCommand); 6838 } 6839 case XK_r: 6840 case XK_Redo: 6841 { 6842 if ((state & ControlMask) == 0) 6843 return(RollCommand); 6844 return(RedoCommand); 6845 } 6846 case XK_x: 6847 { 6848 if ((state & ControlMask) == 0) 6849 return(NullCommand); 6850 return(CutCommand); 6851 } 6852 case XK_c: 6853 { 6854 if ((state & Mod1Mask) != 0) 6855 return(CharcoalDrawCommand); 6856 if ((state & ControlMask) == 0) 6857 return(CropCommand); 6858 return(CopyCommand); 6859 } 6860 case XK_v: 6861 case XK_Insert: 6862 { 6863 if ((state & Mod4Mask) != 0) 6864 return(CompositeCommand); 6865 if ((state & ControlMask) == 0) 6866 return(FlipCommand); 6867 return(PasteCommand); 6868 } 6869 case XK_less: 6870 return(HalfSizeCommand); 6871 case XK_minus: 6872 return(OriginalSizeCommand); 6873 case XK_greater: 6874 return(DoubleSizeCommand); 6875 case XK_percent: 6876 return(ResizeCommand); 6877 case XK_at: 6878 return(RefreshCommand); 6879 case XK_bracketleft: 6880 return(ChopCommand); 6881 case XK_h: 6882 return(FlopCommand); 6883 case XK_slash: 6884 return(RotateRightCommand); 6885 case XK_backslash: 6886 return(RotateLeftCommand); 6887 case XK_asterisk: 6888 return(RotateCommand); 6889 case XK_t: 6890 return(TrimCommand); 6891 case XK_H: 6892 return(HueCommand); 6893 case XK_S: 6894 return(SaturationCommand); 6895 case XK_L: 6896 return(BrightnessCommand); 6897 case XK_G: 6898 return(GammaCommand); 6899 case XK_C: 6900 return(SpiffCommand); 6901 case XK_Z: 6902 return(DullCommand); 6903 case XK_N: 6904 return(NormalizeCommand); 6905 case XK_equal: 6906 return(EqualizeCommand); 6907 case XK_asciitilde: 6908 return(NegateCommand); 6909 case XK_period: 6910 return(GrayscaleCommand); 6911 case XK_numbersign: 6912 return(QuantizeCommand); 6913 case XK_F2: 6914 return(DespeckleCommand); 6915 case XK_F3: 6916 return(EmbossCommand); 6917 case XK_F4: 6918 return(ReduceNoiseCommand); 6919 case XK_F5: 6920 return(AddNoiseCommand); 6921 case XK_F6: 6922 return(SharpenCommand); 6923 case XK_F7: 6924 return(BlurCommand); 6925 case XK_F8: 6926 return(ThresholdCommand); 6927 case XK_F9: 6928 return(EdgeDetectCommand); 6929 case XK_F10: 6930 return(SpreadCommand); 6931 case XK_F11: 6932 return(ShadeCommand); 6933 case XK_F12: 6934 return(RaiseCommand); 6935 case XK_F13: 6936 return(SegmentCommand); 6937 case XK_i: 6938 { 6939 if ((state & Mod1Mask) == 0) 6940 return(NullCommand); 6941 return(ImplodeCommand); 6942 } 6943 case XK_w: 6944 { 6945 if ((state & Mod1Mask) == 0) 6946 return(NullCommand); 6947 return(WaveCommand); 6948 } 6949 case XK_m: 6950 { 6951 if ((state & Mod4Mask) == 0) 6952 return(NullCommand); 6953 return(MatteCommand); 6954 } 6955 case XK_b: 6956 { 6957 if ((state & Mod4Mask) == 0) 6958 return(NullCommand); 6959 return(AddBorderCommand); 6960 } 6961 case XK_f: 6962 { 6963 if ((state & Mod4Mask) == 0) 6964 return(NullCommand); 6965 return(AddFrameCommand); 6966 } 6967 case XK_exclam: 6968 { 6969 if ((state & Mod4Mask) == 0) 6970 return(NullCommand); 6971 return(CommentCommand); 6972 } 6973 case XK_a: 6974 { 6975 if ((state & Mod1Mask) != 0) 6976 return(ApplyCommand); 6977 if ((state & Mod4Mask) != 0) 6978 return(AnnotateCommand); 6979 if ((state & ControlMask) == 0) 6980 return(NullCommand); 6981 return(RegionofInterestCommand); 6982 } 6983 case XK_question: 6984 return(InfoCommand); 6985 case XK_plus: 6986 return(ZoomCommand); 6987 case XK_P: 6988 { 6989 if ((state & ShiftMask) == 0) 6990 return(NullCommand); 6991 return(ShowPreviewCommand); 6992 } 6993 case XK_Execute: 6994 return(LaunchCommand); 6995 case XK_F1: 6996 return(HelpCommand); 6997 case XK_Find: 6998 return(BrowseDocumentationCommand); 6999 case XK_Menu: 7000 { 7001 (void) XMapRaised(display,windows->command.id); 7002 return(NullCommand); 7003 } 7004 case XK_Next: 7005 case XK_Prior: 7006 case XK_Home: 7007 case XK_KP_Home: 7008 { 7009 XTranslateImage(display,windows,*image,key_symbol); 7010 return(NullCommand); 7011 } 7012 case XK_Up: 7013 case XK_KP_Up: 7014 case XK_Down: 7015 case XK_KP_Down: 7016 case XK_Left: 7017 case XK_KP_Left: 7018 case XK_Right: 7019 case XK_KP_Right: 7020 { 7021 if ((state & Mod1Mask) != 0) 7022 { 7023 RectangleInfo 7024 crop_info; 7025 7026 /* 7027 Trim one pixel from edge of image. 7028 */ 7029 crop_info.x=0; 7030 crop_info.y=0; 7031 crop_info.width=(size_t) windows->image.ximage->width; 7032 crop_info.height=(size_t) windows->image.ximage->height; 7033 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7034 { 7035 if (resource_info->quantum >= (int) crop_info.height) 7036 resource_info->quantum=(int) crop_info.height-1; 7037 crop_info.height-=resource_info->quantum; 7038 } 7039 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7040 { 7041 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7042 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7043 crop_info.y+=resource_info->quantum; 7044 crop_info.height-=resource_info->quantum; 7045 } 7046 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7047 { 7048 if (resource_info->quantum >= (int) crop_info.width) 7049 resource_info->quantum=(int) crop_info.width-1; 7050 crop_info.width-=resource_info->quantum; 7051 } 7052 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7053 { 7054 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7055 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7056 crop_info.x+=resource_info->quantum; 7057 crop_info.width-=resource_info->quantum; 7058 } 7059 if ((int) (windows->image.x+windows->image.width) > 7060 (int) crop_info.width) 7061 windows->image.x=(int) (crop_info.width-windows->image.width); 7062 if ((int) (windows->image.y+windows->image.height) > 7063 (int) crop_info.height) 7064 windows->image.y=(int) (crop_info.height-windows->image.height); 7065 XSetCropGeometry(display,windows,&crop_info,*image); 7066 windows->image.window_changes.width=(int) crop_info.width; 7067 windows->image.window_changes.height=(int) crop_info.height; 7068 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7069 (void) XConfigureImage(display,resource_info,windows,*image, 7070 exception); 7071 return(NullCommand); 7072 } 7073 XTranslateImage(display,windows,*image,key_symbol); 7074 return(NullCommand); 7075 } 7076 default: 7077 return(NullCommand); 7078 } 7079 return(NullCommand); 7080} 7081 7082/* 7083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7084% % 7085% % 7086% % 7087+ X M a g i c k C o m m a n d % 7088% % 7089% % 7090% % 7091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7092% 7093% XMagickCommand() makes a transform to the image or Image window as 7094% specified by a user menu button or keyboard command. 7095% 7096% The format of the XMagickCommand method is: 7097% 7098% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7099% XWindows *windows,const CommandType command,Image **image, 7100% ExceptionInfo *exception) 7101% 7102% A description of each parameter follows: 7103% 7104% o display: Specifies a connection to an X server; returned from 7105% XOpenDisplay. 7106% 7107% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7108% 7109% o windows: Specifies a pointer to a XWindows structure. 7110% 7111% o command: Specifies a command to perform. 7112% 7113% o image: the image; XMagickCommand may transform the image and return a 7114% new image pointer. 7115% 7116% o exception: return any errors or warnings in this structure. 7117% 7118*/ 7119static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7120 XWindows *windows,const CommandType command,Image **image, 7121 ExceptionInfo *exception) 7122{ 7123 char 7124 filename[MaxTextExtent], 7125 geometry[MaxTextExtent], 7126 modulate_factors[MaxTextExtent]; 7127 7128 GeometryInfo 7129 geometry_info; 7130 7131 Image 7132 *nexus; 7133 7134 ImageInfo 7135 *image_info; 7136 7137 int 7138 x, 7139 y; 7140 7141 MagickStatusType 7142 flags, 7143 status; 7144 7145 QuantizeInfo 7146 quantize_info; 7147 7148 RectangleInfo 7149 page_geometry; 7150 7151 register int 7152 i; 7153 7154 static char 7155 color[MaxTextExtent] = "gray"; 7156 7157 unsigned int 7158 height, 7159 width; 7160 7161 /* 7162 Process user command. 7163 */ 7164 XCheckRefreshWindows(display,windows); 7165 XImageCache(display,resource_info,windows,command,image,exception); 7166 nexus=NewImageList(); 7167 windows->image.window_changes.width=windows->image.ximage->width; 7168 windows->image.window_changes.height=windows->image.ximage->height; 7169 image_info=CloneImageInfo(resource_info->image_info); 7170 SetGeometryInfo(&geometry_info); 7171 GetQuantizeInfo(&quantize_info); 7172 switch (command) 7173 { 7174 case OpenCommand: 7175 { 7176 /* 7177 Load image. 7178 */ 7179 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7180 break; 7181 } 7182 case NextCommand: 7183 { 7184 /* 7185 Display next image. 7186 */ 7187 for (i=0; i < resource_info->quantum; i++) 7188 XClientMessage(display,windows->image.id,windows->im_protocols, 7189 windows->im_next_image,CurrentTime); 7190 break; 7191 } 7192 case FormerCommand: 7193 { 7194 /* 7195 Display former image. 7196 */ 7197 for (i=0; i < resource_info->quantum; i++) 7198 XClientMessage(display,windows->image.id,windows->im_protocols, 7199 windows->im_former_image,CurrentTime); 7200 break; 7201 } 7202 case SelectCommand: 7203 { 7204 int 7205 status; 7206 7207 /* 7208 Select image. 7209 */ 7210 status=chdir(resource_info->home_directory); 7211 if (status == -1) 7212 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7213 "UnableToOpenFile","%s",resource_info->home_directory); 7214 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7215 break; 7216 } 7217 case SaveCommand: 7218 { 7219 /* 7220 Save image. 7221 */ 7222 status=XSaveImage(display,resource_info,windows,*image,exception); 7223 if (status == MagickFalse) 7224 { 7225 char 7226 message[MaxTextExtent]; 7227 7228 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7229 exception->reason != (char *) NULL ? exception->reason : "", 7230 exception->description != (char *) NULL ? exception->description : 7231 ""); 7232 XNoticeWidget(display,windows,"Unable to save file:",message); 7233 break; 7234 } 7235 break; 7236 } 7237 case PrintCommand: 7238 { 7239 /* 7240 Print image. 7241 */ 7242 status=XPrintImage(display,resource_info,windows,*image,exception); 7243 if (status == MagickFalse) 7244 { 7245 char 7246 message[MaxTextExtent]; 7247 7248 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7249 exception->reason != (char *) NULL ? exception->reason : "", 7250 exception->description != (char *) NULL ? exception->description : 7251 ""); 7252 XNoticeWidget(display,windows,"Unable to print file:",message); 7253 break; 7254 } 7255 break; 7256 } 7257 case DeleteCommand: 7258 { 7259 static char 7260 filename[MaxTextExtent] = "\0"; 7261 7262 /* 7263 Delete image file. 7264 */ 7265 XFileBrowserWidget(display,windows,"Delete",filename); 7266 if (*filename == '\0') 7267 break; 7268 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7269 if (status != MagickFalse) 7270 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7271 break; 7272 } 7273 case NewCommand: 7274 { 7275 int 7276 status; 7277 7278 static char 7279 color[MaxTextExtent] = "gray", 7280 geometry[MaxTextExtent] = "640x480"; 7281 7282 static const char 7283 *format = "gradient"; 7284 7285 /* 7286 Query user for canvas geometry. 7287 */ 7288 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7289 geometry); 7290 if (*geometry == '\0') 7291 break; 7292 if (status == 0) 7293 format="xc"; 7294 XColorBrowserWidget(display,windows,"Select",color); 7295 if (*color == '\0') 7296 break; 7297 /* 7298 Create canvas. 7299 */ 7300 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7301 "%s:%s",format,color); 7302 (void) CloneString(&image_info->size,geometry); 7303 nexus=ReadImage(image_info,exception); 7304 CatchException(exception); 7305 XClientMessage(display,windows->image.id,windows->im_protocols, 7306 windows->im_next_image,CurrentTime); 7307 break; 7308 } 7309 case VisualDirectoryCommand: 7310 { 7311 /* 7312 Visual Image directory. 7313 */ 7314 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7315 break; 7316 } 7317 case QuitCommand: 7318 { 7319 /* 7320 exit program. 7321 */ 7322 if (resource_info->confirm_exit == MagickFalse) 7323 XClientMessage(display,windows->image.id,windows->im_protocols, 7324 windows->im_exit,CurrentTime); 7325 else 7326 { 7327 int 7328 status; 7329 7330 /* 7331 Confirm program exit. 7332 */ 7333 status=XConfirmWidget(display,windows,"Do you really want to exit", 7334 resource_info->client_name); 7335 if (status > 0) 7336 XClientMessage(display,windows->image.id,windows->im_protocols, 7337 windows->im_exit,CurrentTime); 7338 } 7339 break; 7340 } 7341 case CutCommand: 7342 { 7343 /* 7344 Cut image. 7345 */ 7346 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7347 break; 7348 } 7349 case CopyCommand: 7350 { 7351 /* 7352 Copy image. 7353 */ 7354 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7355 exception); 7356 break; 7357 } 7358 case PasteCommand: 7359 { 7360 /* 7361 Paste image. 7362 */ 7363 status=XPasteImage(display,resource_info,windows,*image,exception); 7364 if (status == MagickFalse) 7365 { 7366 XNoticeWidget(display,windows,"Unable to paste X image", 7367 (*image)->filename); 7368 break; 7369 } 7370 break; 7371 } 7372 case HalfSizeCommand: 7373 { 7374 /* 7375 Half image size. 7376 */ 7377 windows->image.window_changes.width=windows->image.ximage->width/2; 7378 windows->image.window_changes.height=windows->image.ximage->height/2; 7379 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7380 break; 7381 } 7382 case OriginalSizeCommand: 7383 { 7384 /* 7385 Original image size. 7386 */ 7387 windows->image.window_changes.width=(int) (*image)->columns; 7388 windows->image.window_changes.height=(int) (*image)->rows; 7389 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7390 break; 7391 } 7392 case DoubleSizeCommand: 7393 { 7394 /* 7395 Double the image size. 7396 */ 7397 windows->image.window_changes.width=windows->image.ximage->width << 1; 7398 windows->image.window_changes.height=windows->image.ximage->height << 1; 7399 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7400 break; 7401 } 7402 case ResizeCommand: 7403 { 7404 int 7405 status; 7406 7407 size_t 7408 height, 7409 width; 7410 7411 ssize_t 7412 x, 7413 y; 7414 7415 /* 7416 Resize image. 7417 */ 7418 width=(size_t) windows->image.ximage->width; 7419 height=(size_t) windows->image.ximage->height; 7420 x=0; 7421 y=0; 7422 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7423 (double) width,(double) height); 7424 status=XDialogWidget(display,windows,"Resize", 7425 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7426 if (*geometry == '\0') 7427 break; 7428 if (status == 0) 7429 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7430 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7431 windows->image.window_changes.width=(int) width; 7432 windows->image.window_changes.height=(int) height; 7433 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7434 break; 7435 } 7436 case ApplyCommand: 7437 { 7438 char 7439 image_geometry[MaxTextExtent]; 7440 7441 if ((windows->image.crop_geometry == (char *) NULL) && 7442 ((int) (*image)->columns == windows->image.ximage->width) && 7443 ((int) (*image)->rows == windows->image.ximage->height)) 7444 break; 7445 /* 7446 Apply size transforms to image. 7447 */ 7448 XSetCursorState(display,windows,MagickTrue); 7449 XCheckRefreshWindows(display,windows); 7450 /* 7451 Crop and/or scale displayed image. 7452 */ 7453 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7454 windows->image.ximage->width,windows->image.ximage->height); 7455 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7456 exception); 7457 if (windows->image.crop_geometry != (char *) NULL) 7458 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7459 windows->image.crop_geometry); 7460 windows->image.x=0; 7461 windows->image.y=0; 7462 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7463 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7464 break; 7465 } 7466 case RefreshCommand: 7467 { 7468 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7469 break; 7470 } 7471 case RestoreCommand: 7472 { 7473 /* 7474 Restore Image window to its original size. 7475 */ 7476 if ((windows->image.width == (unsigned int) (*image)->columns) && 7477 (windows->image.height == (unsigned int) (*image)->rows) && 7478 (windows->image.crop_geometry == (char *) NULL)) 7479 { 7480 (void) XBell(display,0); 7481 break; 7482 } 7483 windows->image.window_changes.width=(int) (*image)->columns; 7484 windows->image.window_changes.height=(int) (*image)->rows; 7485 if (windows->image.crop_geometry != (char *) NULL) 7486 { 7487 windows->image.crop_geometry=(char *) 7488 RelinquishMagickMemory(windows->image.crop_geometry); 7489 windows->image.crop_geometry=(char *) NULL; 7490 windows->image.x=0; 7491 windows->image.y=0; 7492 } 7493 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7494 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7495 break; 7496 } 7497 case CropCommand: 7498 { 7499 /* 7500 Crop image. 7501 */ 7502 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7503 exception); 7504 break; 7505 } 7506 case ChopCommand: 7507 { 7508 /* 7509 Chop image. 7510 */ 7511 status=XChopImage(display,resource_info,windows,image,exception); 7512 if (status == MagickFalse) 7513 { 7514 XNoticeWidget(display,windows,"Unable to cut X image", 7515 (*image)->filename); 7516 break; 7517 } 7518 break; 7519 } 7520 case FlopCommand: 7521 { 7522 Image 7523 *flop_image; 7524 7525 /* 7526 Flop image scanlines. 7527 */ 7528 XSetCursorState(display,windows,MagickTrue); 7529 XCheckRefreshWindows(display,windows); 7530 flop_image=FlopImage(*image,exception); 7531 if (flop_image != (Image *) NULL) 7532 { 7533 *image=DestroyImage(*image); 7534 *image=flop_image; 7535 } 7536 CatchException(exception); 7537 XSetCursorState(display,windows,MagickFalse); 7538 if (windows->image.crop_geometry != (char *) NULL) 7539 { 7540 /* 7541 Flop crop geometry. 7542 */ 7543 width=(unsigned int) (*image)->columns; 7544 height=(unsigned int) (*image)->rows; 7545 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7546 &width,&height); 7547 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7548 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7549 } 7550 if (windows->image.orphan != MagickFalse) 7551 break; 7552 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7553 break; 7554 } 7555 case FlipCommand: 7556 { 7557 Image 7558 *flip_image; 7559 7560 /* 7561 Flip image scanlines. 7562 */ 7563 XSetCursorState(display,windows,MagickTrue); 7564 XCheckRefreshWindows(display,windows); 7565 flip_image=FlipImage(*image,exception); 7566 if (flip_image != (Image *) NULL) 7567 { 7568 *image=DestroyImage(*image); 7569 *image=flip_image; 7570 } 7571 CatchException(exception); 7572 XSetCursorState(display,windows,MagickFalse); 7573 if (windows->image.crop_geometry != (char *) NULL) 7574 { 7575 /* 7576 Flip crop geometry. 7577 */ 7578 width=(unsigned int) (*image)->columns; 7579 height=(unsigned int) (*image)->rows; 7580 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7581 &width,&height); 7582 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7583 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7584 } 7585 if (windows->image.orphan != MagickFalse) 7586 break; 7587 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7588 break; 7589 } 7590 case RotateRightCommand: 7591 { 7592 /* 7593 Rotate image 90 degrees clockwise. 7594 */ 7595 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7596 if (status == MagickFalse) 7597 { 7598 XNoticeWidget(display,windows,"Unable to rotate X image", 7599 (*image)->filename); 7600 break; 7601 } 7602 break; 7603 } 7604 case RotateLeftCommand: 7605 { 7606 /* 7607 Rotate image 90 degrees counter-clockwise. 7608 */ 7609 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7610 if (status == MagickFalse) 7611 { 7612 XNoticeWidget(display,windows,"Unable to rotate X image", 7613 (*image)->filename); 7614 break; 7615 } 7616 break; 7617 } 7618 case RotateCommand: 7619 { 7620 /* 7621 Rotate image. 7622 */ 7623 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7624 if (status == MagickFalse) 7625 { 7626 XNoticeWidget(display,windows,"Unable to rotate X image", 7627 (*image)->filename); 7628 break; 7629 } 7630 break; 7631 } 7632 case ShearCommand: 7633 { 7634 Image 7635 *shear_image; 7636 7637 static char 7638 geometry[MaxTextExtent] = "45.0x45.0"; 7639 7640 /* 7641 Query user for shear color and geometry. 7642 */ 7643 XColorBrowserWidget(display,windows,"Select",color); 7644 if (*color == '\0') 7645 break; 7646 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7647 geometry); 7648 if (*geometry == '\0') 7649 break; 7650 /* 7651 Shear image. 7652 */ 7653 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7654 exception); 7655 XSetCursorState(display,windows,MagickTrue); 7656 XCheckRefreshWindows(display,windows); 7657 (void) QueryColorCompliance(color,AllCompliance, 7658 &(*image)->background_color,exception); 7659 flags=ParseGeometry(geometry,&geometry_info); 7660 if ((flags & SigmaValue) == 0) 7661 geometry_info.sigma=geometry_info.rho; 7662 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7663 exception); 7664 if (shear_image != (Image *) NULL) 7665 { 7666 *image=DestroyImage(*image); 7667 *image=shear_image; 7668 } 7669 CatchException(exception); 7670 XSetCursorState(display,windows,MagickFalse); 7671 if (windows->image.orphan != MagickFalse) 7672 break; 7673 windows->image.window_changes.width=(int) (*image)->columns; 7674 windows->image.window_changes.height=(int) (*image)->rows; 7675 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7676 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7677 break; 7678 } 7679 case RollCommand: 7680 { 7681 Image 7682 *roll_image; 7683 7684 static char 7685 geometry[MaxTextExtent] = "+2+2"; 7686 7687 /* 7688 Query user for the roll geometry. 7689 */ 7690 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7691 geometry); 7692 if (*geometry == '\0') 7693 break; 7694 /* 7695 Roll image. 7696 */ 7697 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7698 exception); 7699 XSetCursorState(display,windows,MagickTrue); 7700 XCheckRefreshWindows(display,windows); 7701 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7702 exception); 7703 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7704 exception); 7705 if (roll_image != (Image *) NULL) 7706 { 7707 *image=DestroyImage(*image); 7708 *image=roll_image; 7709 } 7710 CatchException(exception); 7711 XSetCursorState(display,windows,MagickFalse); 7712 if (windows->image.orphan != MagickFalse) 7713 break; 7714 windows->image.window_changes.width=(int) (*image)->columns; 7715 windows->image.window_changes.height=(int) (*image)->rows; 7716 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7717 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7718 break; 7719 } 7720 case TrimCommand: 7721 { 7722 static char 7723 fuzz[MaxTextExtent]; 7724 7725 /* 7726 Query user for the fuzz factor. 7727 */ 7728 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7729 (*image)->fuzz/(QuantumRange+1.0)); 7730 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7731 if (*fuzz == '\0') 7732 break; 7733 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7734 /* 7735 Trim image. 7736 */ 7737 status=XTrimImage(display,resource_info,windows,*image,exception); 7738 if (status == MagickFalse) 7739 { 7740 XNoticeWidget(display,windows,"Unable to trim X image", 7741 (*image)->filename); 7742 break; 7743 } 7744 break; 7745 } 7746 case HueCommand: 7747 { 7748 static char 7749 hue_percent[MaxTextExtent] = "110"; 7750 7751 /* 7752 Query user for percent hue change. 7753 */ 7754 (void) XDialogWidget(display,windows,"Apply", 7755 "Enter percent change in image hue (0-200):",hue_percent); 7756 if (*hue_percent == '\0') 7757 break; 7758 /* 7759 Vary the image hue. 7760 */ 7761 XSetCursorState(display,windows,MagickTrue); 7762 XCheckRefreshWindows(display,windows); 7763 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7764 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7765 MaxTextExtent); 7766 (void) ModulateImage(*image,modulate_factors,exception); 7767 XSetCursorState(display,windows,MagickFalse); 7768 if (windows->image.orphan != MagickFalse) 7769 break; 7770 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7771 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7772 break; 7773 } 7774 case SaturationCommand: 7775 { 7776 static char 7777 saturation_percent[MaxTextExtent] = "110"; 7778 7779 /* 7780 Query user for percent saturation change. 7781 */ 7782 (void) XDialogWidget(display,windows,"Apply", 7783 "Enter percent change in color saturation (0-200):",saturation_percent); 7784 if (*saturation_percent == '\0') 7785 break; 7786 /* 7787 Vary color saturation. 7788 */ 7789 XSetCursorState(display,windows,MagickTrue); 7790 XCheckRefreshWindows(display,windows); 7791 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7792 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7793 MaxTextExtent); 7794 (void) ModulateImage(*image,modulate_factors,exception); 7795 XSetCursorState(display,windows,MagickFalse); 7796 if (windows->image.orphan != MagickFalse) 7797 break; 7798 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7799 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7800 break; 7801 } 7802 case BrightnessCommand: 7803 { 7804 static char 7805 brightness_percent[MaxTextExtent] = "110"; 7806 7807 /* 7808 Query user for percent brightness change. 7809 */ 7810 (void) XDialogWidget(display,windows,"Apply", 7811 "Enter percent change in color brightness (0-200):",brightness_percent); 7812 if (*brightness_percent == '\0') 7813 break; 7814 /* 7815 Vary the color brightness. 7816 */ 7817 XSetCursorState(display,windows,MagickTrue); 7818 XCheckRefreshWindows(display,windows); 7819 (void) CopyMagickString(modulate_factors,brightness_percent, 7820 MaxTextExtent); 7821 (void) ModulateImage(*image,modulate_factors,exception); 7822 XSetCursorState(display,windows,MagickFalse); 7823 if (windows->image.orphan != MagickFalse) 7824 break; 7825 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7826 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7827 break; 7828 } 7829 case GammaCommand: 7830 { 7831 static char 7832 factor[MaxTextExtent] = "1.6"; 7833 7834 /* 7835 Query user for gamma value. 7836 */ 7837 (void) XDialogWidget(display,windows,"Gamma", 7838 "Enter gamma value (e.g. 1.2):",factor); 7839 if (*factor == '\0') 7840 break; 7841 /* 7842 Gamma correct image. 7843 */ 7844 XSetCursorState(display,windows,MagickTrue); 7845 XCheckRefreshWindows(display,windows); 7846 (void) GammaImage(*image,atof(factor),exception); 7847 XSetCursorState(display,windows,MagickFalse); 7848 if (windows->image.orphan != MagickFalse) 7849 break; 7850 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7851 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7852 break; 7853 } 7854 case SpiffCommand: 7855 { 7856 /* 7857 Sharpen the image contrast. 7858 */ 7859 XSetCursorState(display,windows,MagickTrue); 7860 XCheckRefreshWindows(display,windows); 7861 (void) ContrastImage(*image,MagickTrue,exception); 7862 XSetCursorState(display,windows,MagickFalse); 7863 if (windows->image.orphan != MagickFalse) 7864 break; 7865 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7866 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7867 break; 7868 } 7869 case DullCommand: 7870 { 7871 /* 7872 Dull the image contrast. 7873 */ 7874 XSetCursorState(display,windows,MagickTrue); 7875 XCheckRefreshWindows(display,windows); 7876 (void) ContrastImage(*image,MagickFalse,exception); 7877 XSetCursorState(display,windows,MagickFalse); 7878 if (windows->image.orphan != MagickFalse) 7879 break; 7880 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7881 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7882 break; 7883 } 7884 case ContrastStretchCommand: 7885 { 7886 double 7887 black_point, 7888 white_point; 7889 7890 static char 7891 levels[MaxTextExtent] = "1%"; 7892 7893 /* 7894 Query user for gamma value. 7895 */ 7896 (void) XDialogWidget(display,windows,"Contrast Stretch", 7897 "Enter black and white points:",levels); 7898 if (*levels == '\0') 7899 break; 7900 /* 7901 Contrast stretch image. 7902 */ 7903 XSetCursorState(display,windows,MagickTrue); 7904 XCheckRefreshWindows(display,windows); 7905 flags=ParseGeometry(levels,&geometry_info); 7906 black_point=geometry_info.rho; 7907 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7908 if ((flags & PercentValue) != 0) 7909 { 7910 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7911 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7912 } 7913 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7914 (void) ContrastStretchImage(*image,black_point,white_point, 7915 exception); 7916 XSetCursorState(display,windows,MagickFalse); 7917 if (windows->image.orphan != MagickFalse) 7918 break; 7919 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7920 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7921 break; 7922 } 7923 case SigmoidalContrastCommand: 7924 { 7925 GeometryInfo 7926 geometry_info; 7927 7928 MagickStatusType 7929 flags; 7930 7931 static char 7932 levels[MaxTextExtent] = "3x50%"; 7933 7934 /* 7935 Query user for gamma value. 7936 */ 7937 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7938 "Enter contrast and midpoint:",levels); 7939 if (*levels == '\0') 7940 break; 7941 /* 7942 Contrast stretch image. 7943 */ 7944 XSetCursorState(display,windows,MagickTrue); 7945 XCheckRefreshWindows(display,windows); 7946 flags=ParseGeometry(levels,&geometry_info); 7947 if ((flags & SigmaValue) == 0) 7948 geometry_info.sigma=1.0*QuantumRange/2.0; 7949 if ((flags & PercentValue) != 0) 7950 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7951 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7952 geometry_info.sigma,exception); 7953 XSetCursorState(display,windows,MagickFalse); 7954 if (windows->image.orphan != MagickFalse) 7955 break; 7956 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7957 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7958 break; 7959 } 7960 case NormalizeCommand: 7961 { 7962 /* 7963 Perform histogram normalization on the image. 7964 */ 7965 XSetCursorState(display,windows,MagickTrue); 7966 XCheckRefreshWindows(display,windows); 7967 (void) NormalizeImage(*image,exception); 7968 XSetCursorState(display,windows,MagickFalse); 7969 if (windows->image.orphan != MagickFalse) 7970 break; 7971 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7972 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7973 break; 7974 } 7975 case EqualizeCommand: 7976 { 7977 /* 7978 Perform histogram equalization on the image. 7979 */ 7980 XSetCursorState(display,windows,MagickTrue); 7981 XCheckRefreshWindows(display,windows); 7982 (void) EqualizeImage(*image,exception); 7983 XSetCursorState(display,windows,MagickFalse); 7984 if (windows->image.orphan != MagickFalse) 7985 break; 7986 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7987 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7988 break; 7989 } 7990 case NegateCommand: 7991 { 7992 /* 7993 Negate colors in image. 7994 */ 7995 XSetCursorState(display,windows,MagickTrue); 7996 XCheckRefreshWindows(display,windows); 7997 (void) NegateImage(*image,MagickFalse,exception); 7998 XSetCursorState(display,windows,MagickFalse); 7999 if (windows->image.orphan != MagickFalse) 8000 break; 8001 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8002 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8003 break; 8004 } 8005 case GrayscaleCommand: 8006 { 8007 /* 8008 Convert image to grayscale. 8009 */ 8010 XSetCursorState(display,windows,MagickTrue); 8011 XCheckRefreshWindows(display,windows); 8012 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8013 GrayscaleType : GrayscaleMatteType,exception); 8014 XSetCursorState(display,windows,MagickFalse); 8015 if (windows->image.orphan != MagickFalse) 8016 break; 8017 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8018 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8019 break; 8020 } 8021 case MapCommand: 8022 { 8023 Image 8024 *affinity_image; 8025 8026 static char 8027 filename[MaxTextExtent] = "\0"; 8028 8029 /* 8030 Request image file name from user. 8031 */ 8032 XFileBrowserWidget(display,windows,"Map",filename); 8033 if (*filename == '\0') 8034 break; 8035 /* 8036 Map image. 8037 */ 8038 XSetCursorState(display,windows,MagickTrue); 8039 XCheckRefreshWindows(display,windows); 8040 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8041 affinity_image=ReadImage(image_info,exception); 8042 if (affinity_image != (Image *) NULL) 8043 { 8044 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8045 affinity_image=DestroyImage(affinity_image); 8046 } 8047 CatchException(exception); 8048 XSetCursorState(display,windows,MagickFalse); 8049 if (windows->image.orphan != MagickFalse) 8050 break; 8051 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8052 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8053 break; 8054 } 8055 case QuantizeCommand: 8056 { 8057 int 8058 status; 8059 8060 static char 8061 colors[MaxTextExtent] = "256"; 8062 8063 /* 8064 Query user for maximum number of colors. 8065 */ 8066 status=XDialogWidget(display,windows,"Quantize", 8067 "Maximum number of colors:",colors); 8068 if (*colors == '\0') 8069 break; 8070 /* 8071 Color reduce the image. 8072 */ 8073 XSetCursorState(display,windows,MagickTrue); 8074 XCheckRefreshWindows(display,windows); 8075 quantize_info.number_colors=StringToUnsignedLong(colors); 8076 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8077 (void) QuantizeImage(&quantize_info,*image,exception); 8078 XSetCursorState(display,windows,MagickFalse); 8079 if (windows->image.orphan != MagickFalse) 8080 break; 8081 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8082 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8083 break; 8084 } 8085 case DespeckleCommand: 8086 { 8087 Image 8088 *despeckle_image; 8089 8090 /* 8091 Despeckle image. 8092 */ 8093 XSetCursorState(display,windows,MagickTrue); 8094 XCheckRefreshWindows(display,windows); 8095 despeckle_image=DespeckleImage(*image,exception); 8096 if (despeckle_image != (Image *) NULL) 8097 { 8098 *image=DestroyImage(*image); 8099 *image=despeckle_image; 8100 } 8101 CatchException(exception); 8102 XSetCursorState(display,windows,MagickFalse); 8103 if (windows->image.orphan != MagickFalse) 8104 break; 8105 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8106 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8107 break; 8108 } 8109 case EmbossCommand: 8110 { 8111 Image 8112 *emboss_image; 8113 8114 static char 8115 radius[MaxTextExtent] = "0.0x1.0"; 8116 8117 /* 8118 Query user for emboss radius. 8119 */ 8120 (void) XDialogWidget(display,windows,"Emboss", 8121 "Enter the emboss radius and standard deviation:",radius); 8122 if (*radius == '\0') 8123 break; 8124 /* 8125 Reduce noise in the image. 8126 */ 8127 XSetCursorState(display,windows,MagickTrue); 8128 XCheckRefreshWindows(display,windows); 8129 flags=ParseGeometry(radius,&geometry_info); 8130 if ((flags & SigmaValue) == 0) 8131 geometry_info.sigma=1.0; 8132 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8133 exception); 8134 if (emboss_image != (Image *) NULL) 8135 { 8136 *image=DestroyImage(*image); 8137 *image=emboss_image; 8138 } 8139 CatchException(exception); 8140 XSetCursorState(display,windows,MagickFalse); 8141 if (windows->image.orphan != MagickFalse) 8142 break; 8143 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8144 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8145 break; 8146 } 8147 case ReduceNoiseCommand: 8148 { 8149 Image 8150 *noise_image; 8151 8152 static char 8153 radius[MaxTextExtent] = "0"; 8154 8155 /* 8156 Query user for noise radius. 8157 */ 8158 (void) XDialogWidget(display,windows,"Reduce Noise", 8159 "Enter the noise radius:",radius); 8160 if (*radius == '\0') 8161 break; 8162 /* 8163 Reduce noise in the image. 8164 */ 8165 XSetCursorState(display,windows,MagickTrue); 8166 XCheckRefreshWindows(display,windows); 8167 flags=ParseGeometry(radius,&geometry_info); 8168 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8169 geometry_info.rho,(size_t) geometry_info.rho,exception); 8170 if (noise_image != (Image *) NULL) 8171 { 8172 *image=DestroyImage(*image); 8173 *image=noise_image; 8174 } 8175 CatchException(exception); 8176 XSetCursorState(display,windows,MagickFalse); 8177 if (windows->image.orphan != MagickFalse) 8178 break; 8179 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8180 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8181 break; 8182 } 8183 case AddNoiseCommand: 8184 { 8185 char 8186 **noises; 8187 8188 Image 8189 *noise_image; 8190 8191 static char 8192 noise_type[MaxTextExtent] = "Gaussian"; 8193 8194 /* 8195 Add noise to the image. 8196 */ 8197 noises=GetCommandOptions(MagickNoiseOptions); 8198 if (noises == (char **) NULL) 8199 break; 8200 XListBrowserWidget(display,windows,&windows->widget, 8201 (const char **) noises,"Add Noise", 8202 "Select a type of noise to add to your image:",noise_type); 8203 noises=DestroyStringList(noises); 8204 if (*noise_type == '\0') 8205 break; 8206 XSetCursorState(display,windows,MagickTrue); 8207 XCheckRefreshWindows(display,windows); 8208 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8209 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8210 if (noise_image != (Image *) NULL) 8211 { 8212 *image=DestroyImage(*image); 8213 *image=noise_image; 8214 } 8215 CatchException(exception); 8216 XSetCursorState(display,windows,MagickFalse); 8217 if (windows->image.orphan != MagickFalse) 8218 break; 8219 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8220 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8221 break; 8222 } 8223 case SharpenCommand: 8224 { 8225 Image 8226 *sharp_image; 8227 8228 static char 8229 radius[MaxTextExtent] = "0.0x1.0"; 8230 8231 /* 8232 Query user for sharpen radius. 8233 */ 8234 (void) XDialogWidget(display,windows,"Sharpen", 8235 "Enter the sharpen radius and standard deviation:",radius); 8236 if (*radius == '\0') 8237 break; 8238 /* 8239 Sharpen image scanlines. 8240 */ 8241 XSetCursorState(display,windows,MagickTrue); 8242 XCheckRefreshWindows(display,windows); 8243 flags=ParseGeometry(radius,&geometry_info); 8244 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8245 geometry_info.xi,exception); 8246 if (sharp_image != (Image *) NULL) 8247 { 8248 *image=DestroyImage(*image); 8249 *image=sharp_image; 8250 } 8251 CatchException(exception); 8252 XSetCursorState(display,windows,MagickFalse); 8253 if (windows->image.orphan != MagickFalse) 8254 break; 8255 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8256 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8257 break; 8258 } 8259 case BlurCommand: 8260 { 8261 Image 8262 *blur_image; 8263 8264 static char 8265 radius[MaxTextExtent] = "0.0x1.0"; 8266 8267 /* 8268 Query user for blur radius. 8269 */ 8270 (void) XDialogWidget(display,windows,"Blur", 8271 "Enter the blur radius and standard deviation:",radius); 8272 if (*radius == '\0') 8273 break; 8274 /* 8275 Blur an image. 8276 */ 8277 XSetCursorState(display,windows,MagickTrue); 8278 XCheckRefreshWindows(display,windows); 8279 flags=ParseGeometry(radius,&geometry_info); 8280 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8281 geometry_info.xi,exception); 8282 if (blur_image != (Image *) NULL) 8283 { 8284 *image=DestroyImage(*image); 8285 *image=blur_image; 8286 } 8287 CatchException(exception); 8288 XSetCursorState(display,windows,MagickFalse); 8289 if (windows->image.orphan != MagickFalse) 8290 break; 8291 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8292 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8293 break; 8294 } 8295 case ThresholdCommand: 8296 { 8297 double 8298 threshold; 8299 8300 static char 8301 factor[MaxTextExtent] = "128"; 8302 8303 /* 8304 Query user for threshold value. 8305 */ 8306 (void) XDialogWidget(display,windows,"Threshold", 8307 "Enter threshold value:",factor); 8308 if (*factor == '\0') 8309 break; 8310 /* 8311 Gamma correct image. 8312 */ 8313 XSetCursorState(display,windows,MagickTrue); 8314 XCheckRefreshWindows(display,windows); 8315 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8316 (void) BilevelImage(*image,threshold,exception); 8317 XSetCursorState(display,windows,MagickFalse); 8318 if (windows->image.orphan != MagickFalse) 8319 break; 8320 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8321 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8322 break; 8323 } 8324 case EdgeDetectCommand: 8325 { 8326 Image 8327 *edge_image; 8328 8329 static char 8330 radius[MaxTextExtent] = "0"; 8331 8332 /* 8333 Query user for edge factor. 8334 */ 8335 (void) XDialogWidget(display,windows,"Detect Edges", 8336 "Enter the edge detect radius:",radius); 8337 if (*radius == '\0') 8338 break; 8339 /* 8340 Detect edge in image. 8341 */ 8342 XSetCursorState(display,windows,MagickTrue); 8343 XCheckRefreshWindows(display,windows); 8344 flags=ParseGeometry(radius,&geometry_info); 8345 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8346 exception); 8347 if (edge_image != (Image *) NULL) 8348 { 8349 *image=DestroyImage(*image); 8350 *image=edge_image; 8351 } 8352 CatchException(exception); 8353 XSetCursorState(display,windows,MagickFalse); 8354 if (windows->image.orphan != MagickFalse) 8355 break; 8356 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8357 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8358 break; 8359 } 8360 case SpreadCommand: 8361 { 8362 Image 8363 *spread_image; 8364 8365 static char 8366 amount[MaxTextExtent] = "2"; 8367 8368 /* 8369 Query user for spread amount. 8370 */ 8371 (void) XDialogWidget(display,windows,"Spread", 8372 "Enter the displacement amount:",amount); 8373 if (*amount == '\0') 8374 break; 8375 /* 8376 Displace image pixels by a random amount. 8377 */ 8378 XSetCursorState(display,windows,MagickTrue); 8379 XCheckRefreshWindows(display,windows); 8380 flags=ParseGeometry(amount,&geometry_info); 8381 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8382 exception); 8383 if (spread_image != (Image *) NULL) 8384 { 8385 *image=DestroyImage(*image); 8386 *image=spread_image; 8387 } 8388 CatchException(exception); 8389 XSetCursorState(display,windows,MagickFalse); 8390 if (windows->image.orphan != MagickFalse) 8391 break; 8392 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8393 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8394 break; 8395 } 8396 case ShadeCommand: 8397 { 8398 Image 8399 *shade_image; 8400 8401 int 8402 status; 8403 8404 static char 8405 geometry[MaxTextExtent] = "30x30"; 8406 8407 /* 8408 Query user for the shade geometry. 8409 */ 8410 status=XDialogWidget(display,windows,"Shade", 8411 "Enter the azimuth and elevation of the light source:",geometry); 8412 if (*geometry == '\0') 8413 break; 8414 /* 8415 Shade image pixels. 8416 */ 8417 XSetCursorState(display,windows,MagickTrue); 8418 XCheckRefreshWindows(display,windows); 8419 flags=ParseGeometry(geometry,&geometry_info); 8420 if ((flags & SigmaValue) == 0) 8421 geometry_info.sigma=1.0; 8422 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8423 geometry_info.rho,geometry_info.sigma,exception); 8424 if (shade_image != (Image *) NULL) 8425 { 8426 *image=DestroyImage(*image); 8427 *image=shade_image; 8428 } 8429 CatchException(exception); 8430 XSetCursorState(display,windows,MagickFalse); 8431 if (windows->image.orphan != MagickFalse) 8432 break; 8433 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8434 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8435 break; 8436 } 8437 case RaiseCommand: 8438 { 8439 static char 8440 bevel_width[MaxTextExtent] = "10"; 8441 8442 /* 8443 Query user for bevel width. 8444 */ 8445 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8446 if (*bevel_width == '\0') 8447 break; 8448 /* 8449 Raise an image. 8450 */ 8451 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8452 exception); 8453 XSetCursorState(display,windows,MagickTrue); 8454 XCheckRefreshWindows(display,windows); 8455 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8456 exception); 8457 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8458 XSetCursorState(display,windows,MagickFalse); 8459 if (windows->image.orphan != MagickFalse) 8460 break; 8461 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8462 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8463 break; 8464 } 8465 case SegmentCommand: 8466 { 8467 static char 8468 threshold[MaxTextExtent] = "1.0x1.5"; 8469 8470 /* 8471 Query user for smoothing threshold. 8472 */ 8473 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8474 threshold); 8475 if (*threshold == '\0') 8476 break; 8477 /* 8478 Segment an image. 8479 */ 8480 XSetCursorState(display,windows,MagickTrue); 8481 XCheckRefreshWindows(display,windows); 8482 flags=ParseGeometry(threshold,&geometry_info); 8483 if ((flags & SigmaValue) == 0) 8484 geometry_info.sigma=1.0; 8485 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8486 geometry_info.sigma,exception); 8487 XSetCursorState(display,windows,MagickFalse); 8488 if (windows->image.orphan != MagickFalse) 8489 break; 8490 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8491 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8492 break; 8493 } 8494 case SepiaToneCommand: 8495 { 8496 double 8497 threshold; 8498 8499 Image 8500 *sepia_image; 8501 8502 static char 8503 factor[MaxTextExtent] = "80%"; 8504 8505 /* 8506 Query user for sepia-tone factor. 8507 */ 8508 (void) XDialogWidget(display,windows,"Sepia Tone", 8509 "Enter the sepia tone factor (0 - 99.9%):",factor); 8510 if (*factor == '\0') 8511 break; 8512 /* 8513 Sepia tone image pixels. 8514 */ 8515 XSetCursorState(display,windows,MagickTrue); 8516 XCheckRefreshWindows(display,windows); 8517 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8518 sepia_image=SepiaToneImage(*image,threshold,exception); 8519 if (sepia_image != (Image *) NULL) 8520 { 8521 *image=DestroyImage(*image); 8522 *image=sepia_image; 8523 } 8524 CatchException(exception); 8525 XSetCursorState(display,windows,MagickFalse); 8526 if (windows->image.orphan != MagickFalse) 8527 break; 8528 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8529 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8530 break; 8531 } 8532 case SolarizeCommand: 8533 { 8534 double 8535 threshold; 8536 8537 static char 8538 factor[MaxTextExtent] = "60%"; 8539 8540 /* 8541 Query user for solarize factor. 8542 */ 8543 (void) XDialogWidget(display,windows,"Solarize", 8544 "Enter the solarize factor (0 - 99.9%):",factor); 8545 if (*factor == '\0') 8546 break; 8547 /* 8548 Solarize image pixels. 8549 */ 8550 XSetCursorState(display,windows,MagickTrue); 8551 XCheckRefreshWindows(display,windows); 8552 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8553 (void) SolarizeImage(*image,threshold,exception); 8554 XSetCursorState(display,windows,MagickFalse); 8555 if (windows->image.orphan != MagickFalse) 8556 break; 8557 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8558 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8559 break; 8560 } 8561 case SwirlCommand: 8562 { 8563 Image 8564 *swirl_image; 8565 8566 static char 8567 degrees[MaxTextExtent] = "60"; 8568 8569 /* 8570 Query user for swirl angle. 8571 */ 8572 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8573 degrees); 8574 if (*degrees == '\0') 8575 break; 8576 /* 8577 Swirl image pixels about the center. 8578 */ 8579 XSetCursorState(display,windows,MagickTrue); 8580 XCheckRefreshWindows(display,windows); 8581 flags=ParseGeometry(degrees,&geometry_info); 8582 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8583 exception); 8584 if (swirl_image != (Image *) NULL) 8585 { 8586 *image=DestroyImage(*image); 8587 *image=swirl_image; 8588 } 8589 CatchException(exception); 8590 XSetCursorState(display,windows,MagickFalse); 8591 if (windows->image.orphan != MagickFalse) 8592 break; 8593 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8594 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8595 break; 8596 } 8597 case ImplodeCommand: 8598 { 8599 Image 8600 *implode_image; 8601 8602 static char 8603 factor[MaxTextExtent] = "0.3"; 8604 8605 /* 8606 Query user for implode factor. 8607 */ 8608 (void) XDialogWidget(display,windows,"Implode", 8609 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8610 if (*factor == '\0') 8611 break; 8612 /* 8613 Implode image pixels about the center. 8614 */ 8615 XSetCursorState(display,windows,MagickTrue); 8616 XCheckRefreshWindows(display,windows); 8617 flags=ParseGeometry(factor,&geometry_info); 8618 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8619 exception); 8620 if (implode_image != (Image *) NULL) 8621 { 8622 *image=DestroyImage(*image); 8623 *image=implode_image; 8624 } 8625 CatchException(exception); 8626 XSetCursorState(display,windows,MagickFalse); 8627 if (windows->image.orphan != MagickFalse) 8628 break; 8629 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8630 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8631 break; 8632 } 8633 case VignetteCommand: 8634 { 8635 Image 8636 *vignette_image; 8637 8638 static char 8639 geometry[MaxTextExtent] = "0x20"; 8640 8641 /* 8642 Query user for the vignette geometry. 8643 */ 8644 (void) XDialogWidget(display,windows,"Vignette", 8645 "Enter the radius, sigma, and x and y offsets:",geometry); 8646 if (*geometry == '\0') 8647 break; 8648 /* 8649 Soften the edges of the image in vignette style 8650 */ 8651 XSetCursorState(display,windows,MagickTrue); 8652 XCheckRefreshWindows(display,windows); 8653 flags=ParseGeometry(geometry,&geometry_info); 8654 if ((flags & SigmaValue) == 0) 8655 geometry_info.sigma=1.0; 8656 if ((flags & XiValue) == 0) 8657 geometry_info.xi=0.1*(*image)->columns; 8658 if ((flags & PsiValue) == 0) 8659 geometry_info.psi=0.1*(*image)->rows; 8660 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8661 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8662 0.5),exception); 8663 if (vignette_image != (Image *) NULL) 8664 { 8665 *image=DestroyImage(*image); 8666 *image=vignette_image; 8667 } 8668 CatchException(exception); 8669 XSetCursorState(display,windows,MagickFalse); 8670 if (windows->image.orphan != MagickFalse) 8671 break; 8672 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8673 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8674 break; 8675 } 8676 case WaveCommand: 8677 { 8678 Image 8679 *wave_image; 8680 8681 static char 8682 geometry[MaxTextExtent] = "25x150"; 8683 8684 /* 8685 Query user for the wave geometry. 8686 */ 8687 (void) XDialogWidget(display,windows,"Wave", 8688 "Enter the amplitude and length of the wave:",geometry); 8689 if (*geometry == '\0') 8690 break; 8691 /* 8692 Alter an image along a sine wave. 8693 */ 8694 XSetCursorState(display,windows,MagickTrue); 8695 XCheckRefreshWindows(display,windows); 8696 flags=ParseGeometry(geometry,&geometry_info); 8697 if ((flags & SigmaValue) == 0) 8698 geometry_info.sigma=1.0; 8699 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8700 (*image)->interpolate,exception); 8701 if (wave_image != (Image *) NULL) 8702 { 8703 *image=DestroyImage(*image); 8704 *image=wave_image; 8705 } 8706 CatchException(exception); 8707 XSetCursorState(display,windows,MagickFalse); 8708 if (windows->image.orphan != MagickFalse) 8709 break; 8710 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8711 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8712 break; 8713 } 8714 case OilPaintCommand: 8715 { 8716 Image 8717 *paint_image; 8718 8719 static char 8720 radius[MaxTextExtent] = "0"; 8721 8722 /* 8723 Query user for circular neighborhood radius. 8724 */ 8725 (void) XDialogWidget(display,windows,"Oil Paint", 8726 "Enter the mask radius:",radius); 8727 if (*radius == '\0') 8728 break; 8729 /* 8730 OilPaint image scanlines. 8731 */ 8732 XSetCursorState(display,windows,MagickTrue); 8733 XCheckRefreshWindows(display,windows); 8734 flags=ParseGeometry(radius,&geometry_info); 8735 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8736 exception); 8737 if (paint_image != (Image *) NULL) 8738 { 8739 *image=DestroyImage(*image); 8740 *image=paint_image; 8741 } 8742 CatchException(exception); 8743 XSetCursorState(display,windows,MagickFalse); 8744 if (windows->image.orphan != MagickFalse) 8745 break; 8746 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8747 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8748 break; 8749 } 8750 case CharcoalDrawCommand: 8751 { 8752 Image 8753 *charcoal_image; 8754 8755 static char 8756 radius[MaxTextExtent] = "0x1"; 8757 8758 /* 8759 Query user for charcoal radius. 8760 */ 8761 (void) XDialogWidget(display,windows,"Charcoal Draw", 8762 "Enter the charcoal radius and sigma:",radius); 8763 if (*radius == '\0') 8764 break; 8765 /* 8766 Charcoal the image. 8767 */ 8768 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8769 exception); 8770 XSetCursorState(display,windows,MagickTrue); 8771 XCheckRefreshWindows(display,windows); 8772 flags=ParseGeometry(radius,&geometry_info); 8773 if ((flags & SigmaValue) == 0) 8774 geometry_info.sigma=geometry_info.rho; 8775 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8776 geometry_info.xi,exception); 8777 if (charcoal_image != (Image *) NULL) 8778 { 8779 *image=DestroyImage(*image); 8780 *image=charcoal_image; 8781 } 8782 CatchException(exception); 8783 XSetCursorState(display,windows,MagickFalse); 8784 if (windows->image.orphan != MagickFalse) 8785 break; 8786 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8787 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8788 break; 8789 } 8790 case AnnotateCommand: 8791 { 8792 /* 8793 Annotate the image with text. 8794 */ 8795 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8796 if (status == MagickFalse) 8797 { 8798 XNoticeWidget(display,windows,"Unable to annotate X image", 8799 (*image)->filename); 8800 break; 8801 } 8802 break; 8803 } 8804 case DrawCommand: 8805 { 8806 /* 8807 Draw image. 8808 */ 8809 status=XDrawEditImage(display,resource_info,windows,image,exception); 8810 if (status == MagickFalse) 8811 { 8812 XNoticeWidget(display,windows,"Unable to draw on the X image", 8813 (*image)->filename); 8814 break; 8815 } 8816 break; 8817 } 8818 case ColorCommand: 8819 { 8820 /* 8821 Color edit. 8822 */ 8823 status=XColorEditImage(display,resource_info,windows,image,exception); 8824 if (status == MagickFalse) 8825 { 8826 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8827 (*image)->filename); 8828 break; 8829 } 8830 break; 8831 } 8832 case MatteCommand: 8833 { 8834 /* 8835 Matte edit. 8836 */ 8837 status=XMatteEditImage(display,resource_info,windows,image,exception); 8838 if (status == MagickFalse) 8839 { 8840 XNoticeWidget(display,windows,"Unable to matte edit X image", 8841 (*image)->filename); 8842 break; 8843 } 8844 break; 8845 } 8846 case CompositeCommand: 8847 { 8848 /* 8849 Composite image. 8850 */ 8851 status=XCompositeImage(display,resource_info,windows,*image, 8852 exception); 8853 if (status == MagickFalse) 8854 { 8855 XNoticeWidget(display,windows,"Unable to composite X image", 8856 (*image)->filename); 8857 break; 8858 } 8859 break; 8860 } 8861 case AddBorderCommand: 8862 { 8863 Image 8864 *border_image; 8865 8866 static char 8867 geometry[MaxTextExtent] = "6x6"; 8868 8869 /* 8870 Query user for border color and geometry. 8871 */ 8872 XColorBrowserWidget(display,windows,"Select",color); 8873 if (*color == '\0') 8874 break; 8875 (void) XDialogWidget(display,windows,"Add Border", 8876 "Enter border geometry:",geometry); 8877 if (*geometry == '\0') 8878 break; 8879 /* 8880 Add a border to the image. 8881 */ 8882 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8883 exception); 8884 XSetCursorState(display,windows,MagickTrue); 8885 XCheckRefreshWindows(display,windows); 8886 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8887 exception); 8888 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8889 exception); 8890 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8891 exception); 8892 if (border_image != (Image *) NULL) 8893 { 8894 *image=DestroyImage(*image); 8895 *image=border_image; 8896 } 8897 CatchException(exception); 8898 XSetCursorState(display,windows,MagickFalse); 8899 if (windows->image.orphan != MagickFalse) 8900 break; 8901 windows->image.window_changes.width=(int) (*image)->columns; 8902 windows->image.window_changes.height=(int) (*image)->rows; 8903 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8904 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8905 break; 8906 } 8907 case AddFrameCommand: 8908 { 8909 FrameInfo 8910 frame_info; 8911 8912 Image 8913 *frame_image; 8914 8915 static char 8916 geometry[MaxTextExtent] = "6x6"; 8917 8918 /* 8919 Query user for frame color and geometry. 8920 */ 8921 XColorBrowserWidget(display,windows,"Select",color); 8922 if (*color == '\0') 8923 break; 8924 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8925 geometry); 8926 if (*geometry == '\0') 8927 break; 8928 /* 8929 Surround image with an ornamental border. 8930 */ 8931 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8932 exception); 8933 XSetCursorState(display,windows,MagickTrue); 8934 XCheckRefreshWindows(display,windows); 8935 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8936 exception); 8937 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8938 exception); 8939 frame_info.width=page_geometry.width; 8940 frame_info.height=page_geometry.height; 8941 frame_info.outer_bevel=page_geometry.x; 8942 frame_info.inner_bevel=page_geometry.y; 8943 frame_info.x=(ssize_t) frame_info.width; 8944 frame_info.y=(ssize_t) frame_info.height; 8945 frame_info.width=(*image)->columns+2*frame_info.width; 8946 frame_info.height=(*image)->rows+2*frame_info.height; 8947 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8948 if (frame_image != (Image *) NULL) 8949 { 8950 *image=DestroyImage(*image); 8951 *image=frame_image; 8952 } 8953 CatchException(exception); 8954 XSetCursorState(display,windows,MagickFalse); 8955 if (windows->image.orphan != MagickFalse) 8956 break; 8957 windows->image.window_changes.width=(int) (*image)->columns; 8958 windows->image.window_changes.height=(int) (*image)->rows; 8959 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8960 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8961 break; 8962 } 8963 case CommentCommand: 8964 { 8965 const char 8966 *value; 8967 8968 FILE 8969 *file; 8970 8971 int 8972 unique_file; 8973 8974 /* 8975 Edit image comment. 8976 */ 8977 unique_file=AcquireUniqueFileResource(image_info->filename); 8978 if (unique_file == -1) 8979 XNoticeWidget(display,windows,"Unable to edit image comment", 8980 image_info->filename); 8981 value=GetImageProperty(*image,"comment",exception); 8982 if (value == (char *) NULL) 8983 unique_file=close(unique_file)-1; 8984 else 8985 { 8986 register const char 8987 *p; 8988 8989 file=fdopen(unique_file,"w"); 8990 if (file == (FILE *) NULL) 8991 { 8992 XNoticeWidget(display,windows,"Unable to edit image comment", 8993 image_info->filename); 8994 break; 8995 } 8996 for (p=value; *p != '\0'; p++) 8997 (void) fputc((int) *p,file); 8998 (void) fputc('\n',file); 8999 (void) fclose(file); 9000 } 9001 XSetCursorState(display,windows,MagickTrue); 9002 XCheckRefreshWindows(display,windows); 9003 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9004 exception); 9005 if (status == MagickFalse) 9006 XNoticeWidget(display,windows,"Unable to edit image comment", 9007 (char *) NULL); 9008 else 9009 { 9010 char 9011 *comment; 9012 9013 comment=FileToString(image_info->filename,~0UL,exception); 9014 if (comment != (char *) NULL) 9015 { 9016 (void) SetImageProperty(*image,"comment",comment,exception); 9017 (*image)->taint=MagickTrue; 9018 } 9019 } 9020 (void) RelinquishUniqueFileResource(image_info->filename); 9021 XSetCursorState(display,windows,MagickFalse); 9022 break; 9023 } 9024 case LaunchCommand: 9025 { 9026 /* 9027 Launch program. 9028 */ 9029 XSetCursorState(display,windows,MagickTrue); 9030 XCheckRefreshWindows(display,windows); 9031 (void) AcquireUniqueFilename(filename); 9032 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9033 filename); 9034 status=WriteImage(image_info,*image,exception); 9035 if (status == MagickFalse) 9036 XNoticeWidget(display,windows,"Unable to launch image editor", 9037 (char *) NULL); 9038 else 9039 { 9040 nexus=ReadImage(resource_info->image_info,exception); 9041 CatchException(exception); 9042 XClientMessage(display,windows->image.id,windows->im_protocols, 9043 windows->im_next_image,CurrentTime); 9044 } 9045 (void) RelinquishUniqueFileResource(filename); 9046 XSetCursorState(display,windows,MagickFalse); 9047 break; 9048 } 9049 case RegionofInterestCommand: 9050 { 9051 /* 9052 Apply an image processing technique to a region of interest. 9053 */ 9054 (void) XROIImage(display,resource_info,windows,image,exception); 9055 break; 9056 } 9057 case InfoCommand: 9058 break; 9059 case ZoomCommand: 9060 { 9061 /* 9062 Zoom image. 9063 */ 9064 if (windows->magnify.mapped != MagickFalse) 9065 (void) XRaiseWindow(display,windows->magnify.id); 9066 else 9067 { 9068 /* 9069 Make magnify image. 9070 */ 9071 XSetCursorState(display,windows,MagickTrue); 9072 (void) XMapRaised(display,windows->magnify.id); 9073 XSetCursorState(display,windows,MagickFalse); 9074 } 9075 break; 9076 } 9077 case ShowPreviewCommand: 9078 { 9079 char 9080 **previews; 9081 9082 Image 9083 *preview_image; 9084 9085 static char 9086 preview_type[MaxTextExtent] = "Gamma"; 9087 9088 /* 9089 Select preview type from menu. 9090 */ 9091 previews=GetCommandOptions(MagickPreviewOptions); 9092 if (previews == (char **) NULL) 9093 break; 9094 XListBrowserWidget(display,windows,&windows->widget, 9095 (const char **) previews,"Preview", 9096 "Select an enhancement, effect, or F/X:",preview_type); 9097 previews=DestroyStringList(previews); 9098 if (*preview_type == '\0') 9099 break; 9100 /* 9101 Show image preview. 9102 */ 9103 XSetCursorState(display,windows,MagickTrue); 9104 XCheckRefreshWindows(display,windows); 9105 image_info->preview_type=(PreviewType) 9106 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9107 image_info->group=(ssize_t) windows->image.id; 9108 (void) DeleteImageProperty(*image,"label"); 9109 (void) SetImageProperty(*image,"label","Preview",exception); 9110 (void) AcquireUniqueFilename(filename); 9111 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9112 filename); 9113 status=WriteImage(image_info,*image,exception); 9114 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9115 preview_image=ReadImage(image_info,exception); 9116 (void) RelinquishUniqueFileResource(filename); 9117 if (preview_image == (Image *) NULL) 9118 break; 9119 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9120 filename); 9121 status=WriteImage(image_info,preview_image,exception); 9122 preview_image=DestroyImage(preview_image); 9123 if (status == MagickFalse) 9124 XNoticeWidget(display,windows,"Unable to show image preview", 9125 (*image)->filename); 9126 XDelay(display,1500); 9127 XSetCursorState(display,windows,MagickFalse); 9128 break; 9129 } 9130 case ShowHistogramCommand: 9131 { 9132 Image 9133 *histogram_image; 9134 9135 /* 9136 Show image histogram. 9137 */ 9138 XSetCursorState(display,windows,MagickTrue); 9139 XCheckRefreshWindows(display,windows); 9140 image_info->group=(ssize_t) windows->image.id; 9141 (void) DeleteImageProperty(*image,"label"); 9142 (void) SetImageProperty(*image,"label","Histogram",exception); 9143 (void) AcquireUniqueFilename(filename); 9144 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9145 filename); 9146 status=WriteImage(image_info,*image,exception); 9147 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9148 histogram_image=ReadImage(image_info,exception); 9149 (void) RelinquishUniqueFileResource(filename); 9150 if (histogram_image == (Image *) NULL) 9151 break; 9152 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9153 "show:%s",filename); 9154 status=WriteImage(image_info,histogram_image,exception); 9155 histogram_image=DestroyImage(histogram_image); 9156 if (status == MagickFalse) 9157 XNoticeWidget(display,windows,"Unable to show histogram", 9158 (*image)->filename); 9159 XDelay(display,1500); 9160 XSetCursorState(display,windows,MagickFalse); 9161 break; 9162 } 9163 case ShowMatteCommand: 9164 { 9165 Image 9166 *matte_image; 9167 9168 if ((*image)->matte == MagickFalse) 9169 { 9170 XNoticeWidget(display,windows, 9171 "Image does not have any matte information",(*image)->filename); 9172 break; 9173 } 9174 /* 9175 Show image matte. 9176 */ 9177 XSetCursorState(display,windows,MagickTrue); 9178 XCheckRefreshWindows(display,windows); 9179 image_info->group=(ssize_t) windows->image.id; 9180 (void) DeleteImageProperty(*image,"label"); 9181 (void) SetImageProperty(*image,"label","Matte",exception); 9182 (void) AcquireUniqueFilename(filename); 9183 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9184 filename); 9185 status=WriteImage(image_info,*image,exception); 9186 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9187 matte_image=ReadImage(image_info,exception); 9188 (void) RelinquishUniqueFileResource(filename); 9189 if (matte_image == (Image *) NULL) 9190 break; 9191 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9192 filename); 9193 status=WriteImage(image_info,matte_image,exception); 9194 matte_image=DestroyImage(matte_image); 9195 if (status == MagickFalse) 9196 XNoticeWidget(display,windows,"Unable to show matte", 9197 (*image)->filename); 9198 XDelay(display,1500); 9199 XSetCursorState(display,windows,MagickFalse); 9200 break; 9201 } 9202 case BackgroundCommand: 9203 { 9204 /* 9205 Background image. 9206 */ 9207 status=XBackgroundImage(display,resource_info,windows,image,exception); 9208 if (status == MagickFalse) 9209 break; 9210 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9211 if (nexus != (Image *) NULL) 9212 XClientMessage(display,windows->image.id,windows->im_protocols, 9213 windows->im_next_image,CurrentTime); 9214 break; 9215 } 9216 case SlideShowCommand: 9217 { 9218 static char 9219 delay[MaxTextExtent] = "5"; 9220 9221 /* 9222 Display next image after pausing. 9223 */ 9224 (void) XDialogWidget(display,windows,"Slide Show", 9225 "Pause how many 1/100ths of a second between images:",delay); 9226 if (*delay == '\0') 9227 break; 9228 resource_info->delay=StringToUnsignedLong(delay); 9229 XClientMessage(display,windows->image.id,windows->im_protocols, 9230 windows->im_next_image,CurrentTime); 9231 break; 9232 } 9233 case PreferencesCommand: 9234 { 9235 /* 9236 Set user preferences. 9237 */ 9238 status=XPreferencesWidget(display,resource_info,windows); 9239 if (status == MagickFalse) 9240 break; 9241 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9242 if (nexus != (Image *) NULL) 9243 XClientMessage(display,windows->image.id,windows->im_protocols, 9244 windows->im_next_image,CurrentTime); 9245 break; 9246 } 9247 case HelpCommand: 9248 { 9249 /* 9250 User requested help. 9251 */ 9252 XTextViewWidget(display,resource_info,windows,MagickFalse, 9253 "Help Viewer - Display",DisplayHelp); 9254 break; 9255 } 9256 case BrowseDocumentationCommand: 9257 { 9258 Atom 9259 mozilla_atom; 9260 9261 Window 9262 mozilla_window, 9263 root_window; 9264 9265 /* 9266 Browse the ImageMagick documentation. 9267 */ 9268 root_window=XRootWindow(display,XDefaultScreen(display)); 9269 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9270 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9271 if (mozilla_window != (Window) NULL) 9272 { 9273 char 9274 command[MaxTextExtent], 9275 *url; 9276 9277 /* 9278 Display documentation using Netscape remote control. 9279 */ 9280 url=GetMagickHomeURL(); 9281 (void) FormatLocaleString(command,MaxTextExtent, 9282 "openurl(%s,new-tab)",url); 9283 url=DestroyString(url); 9284 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9285 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9286 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9287 XSetCursorState(display,windows,MagickFalse); 9288 break; 9289 } 9290 XSetCursorState(display,windows,MagickTrue); 9291 XCheckRefreshWindows(display,windows); 9292 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9293 exception); 9294 if (status == MagickFalse) 9295 XNoticeWidget(display,windows,"Unable to browse documentation", 9296 (char *) NULL); 9297 XDelay(display,1500); 9298 XSetCursorState(display,windows,MagickFalse); 9299 break; 9300 } 9301 case VersionCommand: 9302 { 9303 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9304 GetMagickCopyright()); 9305 break; 9306 } 9307 case SaveToUndoBufferCommand: 9308 break; 9309 default: 9310 { 9311 (void) XBell(display,0); 9312 break; 9313 } 9314 } 9315 image_info=DestroyImageInfo(image_info); 9316 return(nexus); 9317} 9318 9319/* 9320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9321% % 9322% % 9323% % 9324+ X M a g n i f y I m a g e % 9325% % 9326% % 9327% % 9328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9329% 9330% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9331% The magnified portion is displayed in a separate window. 9332% 9333% The format of the XMagnifyImage method is: 9334% 9335% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9336% ExceptionInfo *exception) 9337% 9338% A description of each parameter follows: 9339% 9340% o display: Specifies a connection to an X server; returned from 9341% XOpenDisplay. 9342% 9343% o windows: Specifies a pointer to a XWindows structure. 9344% 9345% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9346% the entire image is refreshed. 9347% 9348% o exception: return any errors or warnings in this structure. 9349% 9350*/ 9351static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9352 ExceptionInfo *exception) 9353{ 9354 char 9355 text[MaxTextExtent]; 9356 9357 register int 9358 x, 9359 y; 9360 9361 size_t 9362 state; 9363 9364 /* 9365 Update magnified image until the mouse button is released. 9366 */ 9367 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9368 state=DefaultState; 9369 x=event->xbutton.x; 9370 y=event->xbutton.y; 9371 windows->magnify.x=(int) windows->image.x+x; 9372 windows->magnify.y=(int) windows->image.y+y; 9373 do 9374 { 9375 /* 9376 Map and unmap Info widget as text cursor crosses its boundaries. 9377 */ 9378 if (windows->info.mapped != MagickFalse) 9379 { 9380 if ((x < (int) (windows->info.x+windows->info.width)) && 9381 (y < (int) (windows->info.y+windows->info.height))) 9382 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9383 } 9384 else 9385 if ((x > (int) (windows->info.x+windows->info.width)) || 9386 (y > (int) (windows->info.y+windows->info.height))) 9387 (void) XMapWindow(display,windows->info.id); 9388 if (windows->info.mapped != MagickFalse) 9389 { 9390 /* 9391 Display pointer position. 9392 */ 9393 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9394 windows->magnify.x,windows->magnify.y); 9395 XInfoWidget(display,windows,text); 9396 } 9397 /* 9398 Wait for next event. 9399 */ 9400 XScreenEvent(display,windows,event,exception); 9401 switch (event->type) 9402 { 9403 case ButtonPress: 9404 break; 9405 case ButtonRelease: 9406 { 9407 /* 9408 User has finished magnifying image. 9409 */ 9410 x=event->xbutton.x; 9411 y=event->xbutton.y; 9412 state|=ExitState; 9413 break; 9414 } 9415 case Expose: 9416 break; 9417 case MotionNotify: 9418 { 9419 x=event->xmotion.x; 9420 y=event->xmotion.y; 9421 break; 9422 } 9423 default: 9424 break; 9425 } 9426 /* 9427 Check boundary conditions. 9428 */ 9429 if (x < 0) 9430 x=0; 9431 else 9432 if (x >= (int) windows->image.width) 9433 x=(int) windows->image.width-1; 9434 if (y < 0) 9435 y=0; 9436 else 9437 if (y >= (int) windows->image.height) 9438 y=(int) windows->image.height-1; 9439 } while ((state & ExitState) == 0); 9440 /* 9441 Display magnified image. 9442 */ 9443 XSetCursorState(display,windows,MagickFalse); 9444} 9445 9446/* 9447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9448% % 9449% % 9450% % 9451+ X M a g n i f y W i n d o w C o m m a n d % 9452% % 9453% % 9454% % 9455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9456% 9457% XMagnifyWindowCommand() moves the image within an Magnify window by one 9458% pixel as specified by the key symbol. 9459% 9460% The format of the XMagnifyWindowCommand method is: 9461% 9462% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9463% const MagickStatusType state,const KeySym key_symbol, 9464% ExceptionInfo *exception) 9465% 9466% A description of each parameter follows: 9467% 9468% o display: Specifies a connection to an X server; returned from 9469% XOpenDisplay. 9470% 9471% o windows: Specifies a pointer to a XWindows structure. 9472% 9473% o state: key mask. 9474% 9475% o key_symbol: Specifies a KeySym which indicates which side of the image 9476% to trim. 9477% 9478% o exception: return any errors or warnings in this structure. 9479% 9480*/ 9481static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9482 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9483{ 9484 unsigned int 9485 quantum; 9486 9487 /* 9488 User specified a magnify factor or position. 9489 */ 9490 quantum=1; 9491 if ((state & Mod1Mask) != 0) 9492 quantum=10; 9493 switch ((int) key_symbol) 9494 { 9495 case QuitCommand: 9496 { 9497 (void) XWithdrawWindow(display,windows->magnify.id, 9498 windows->magnify.screen); 9499 break; 9500 } 9501 case XK_Home: 9502 case XK_KP_Home: 9503 { 9504 windows->magnify.x=(int) windows->image.width/2; 9505 windows->magnify.y=(int) windows->image.height/2; 9506 break; 9507 } 9508 case XK_Left: 9509 case XK_KP_Left: 9510 { 9511 if (windows->magnify.x > 0) 9512 windows->magnify.x-=quantum; 9513 break; 9514 } 9515 case XK_Up: 9516 case XK_KP_Up: 9517 { 9518 if (windows->magnify.y > 0) 9519 windows->magnify.y-=quantum; 9520 break; 9521 } 9522 case XK_Right: 9523 case XK_KP_Right: 9524 { 9525 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9526 windows->magnify.x+=quantum; 9527 break; 9528 } 9529 case XK_Down: 9530 case XK_KP_Down: 9531 { 9532 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9533 windows->magnify.y+=quantum; 9534 break; 9535 } 9536 case XK_0: 9537 case XK_1: 9538 case XK_2: 9539 case XK_3: 9540 case XK_4: 9541 case XK_5: 9542 case XK_6: 9543 case XK_7: 9544 case XK_8: 9545 case XK_9: 9546 { 9547 windows->magnify.data=(key_symbol-XK_0); 9548 break; 9549 } 9550 case XK_KP_0: 9551 case XK_KP_1: 9552 case XK_KP_2: 9553 case XK_KP_3: 9554 case XK_KP_4: 9555 case XK_KP_5: 9556 case XK_KP_6: 9557 case XK_KP_7: 9558 case XK_KP_8: 9559 case XK_KP_9: 9560 { 9561 windows->magnify.data=(key_symbol-XK_KP_0); 9562 break; 9563 } 9564 default: 9565 break; 9566 } 9567 XMakeMagnifyImage(display,windows,exception); 9568} 9569 9570/* 9571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9572% % 9573% % 9574% % 9575+ X M a k e P a n I m a g e % 9576% % 9577% % 9578% % 9579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9580% 9581% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9582% icon window. 9583% 9584% The format of the XMakePanImage method is: 9585% 9586% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9587% XWindows *windows,Image *image,ExceptionInfo *exception) 9588% 9589% A description of each parameter follows: 9590% 9591% o display: Specifies a connection to an X server; returned from 9592% XOpenDisplay. 9593% 9594% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9595% 9596% o windows: Specifies a pointer to a XWindows structure. 9597% 9598% o image: the image. 9599% 9600% o exception: return any errors or warnings in this structure. 9601% 9602*/ 9603static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9604 XWindows *windows,Image *image,ExceptionInfo *exception) 9605{ 9606 MagickStatusType 9607 status; 9608 9609 /* 9610 Create and display image for panning icon. 9611 */ 9612 XSetCursorState(display,windows,MagickTrue); 9613 XCheckRefreshWindows(display,windows); 9614 windows->pan.x=(int) windows->image.x; 9615 windows->pan.y=(int) windows->image.y; 9616 status=XMakeImage(display,resource_info,&windows->pan,image, 9617 windows->pan.width,windows->pan.height,exception); 9618 if (status == MagickFalse) 9619 ThrowXWindowFatalException(ResourceLimitError, 9620 "MemoryAllocationFailed",image->filename); 9621 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9622 windows->pan.pixmap); 9623 (void) XClearWindow(display,windows->pan.id); 9624 XDrawPanRectangle(display,windows); 9625 XSetCursorState(display,windows,MagickFalse); 9626} 9627 9628/* 9629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9630% % 9631% % 9632% % 9633+ X M a t t a E d i t I m a g e % 9634% % 9635% % 9636% % 9637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9638% 9639% XMatteEditImage() allows the user to interactively change the Matte channel 9640% of an image. If the image is PseudoClass it is promoted to DirectClass 9641% before the matte information is stored. 9642% 9643% The format of the XMatteEditImage method is: 9644% 9645% MagickBooleanType XMatteEditImage(Display *display, 9646% XResourceInfo *resource_info,XWindows *windows,Image **image, 9647% ExceptionInfo *exception) 9648% 9649% A description of each parameter follows: 9650% 9651% o display: Specifies a connection to an X server; returned from 9652% XOpenDisplay. 9653% 9654% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9655% 9656% o windows: Specifies a pointer to a XWindows structure. 9657% 9658% o image: the image; returned from ReadImage. 9659% 9660% o exception: return any errors or warnings in this structure. 9661% 9662*/ 9663static MagickBooleanType XMatteEditImage(Display *display, 9664 XResourceInfo *resource_info,XWindows *windows,Image **image, 9665 ExceptionInfo *exception) 9666{ 9667 static char 9668 matte[MaxTextExtent] = "0"; 9669 9670 static const char 9671 *MatteEditMenu[] = 9672 { 9673 "Method", 9674 "Border Color", 9675 "Fuzz", 9676 "Matte Value", 9677 "Undo", 9678 "Help", 9679 "Dismiss", 9680 (char *) NULL 9681 }; 9682 9683 static const ModeType 9684 MatteEditCommands[] = 9685 { 9686 MatteEditMethod, 9687 MatteEditBorderCommand, 9688 MatteEditFuzzCommand, 9689 MatteEditValueCommand, 9690 MatteEditUndoCommand, 9691 MatteEditHelpCommand, 9692 MatteEditDismissCommand 9693 }; 9694 9695 static PaintMethod 9696 method = PointMethod; 9697 9698 static XColor 9699 border_color = { 0, 0, 0, 0, 0, 0 }; 9700 9701 char 9702 command[MaxTextExtent], 9703 text[MaxTextExtent]; 9704 9705 Cursor 9706 cursor; 9707 9708 int 9709 entry, 9710 id, 9711 x, 9712 x_offset, 9713 y, 9714 y_offset; 9715 9716 register int 9717 i; 9718 9719 register Quantum 9720 *q; 9721 9722 unsigned int 9723 height, 9724 width; 9725 9726 size_t 9727 state; 9728 9729 XEvent 9730 event; 9731 9732 /* 9733 Map Command widget. 9734 */ 9735 (void) CloneString(&windows->command.name,"Matte Edit"); 9736 windows->command.data=4; 9737 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9738 (void) XMapRaised(display,windows->command.id); 9739 XClientMessage(display,windows->image.id,windows->im_protocols, 9740 windows->im_update_widget,CurrentTime); 9741 /* 9742 Make cursor. 9743 */ 9744 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9745 resource_info->background_color,resource_info->foreground_color); 9746 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9747 /* 9748 Track pointer until button 1 is pressed. 9749 */ 9750 XQueryPosition(display,windows->image.id,&x,&y); 9751 (void) XSelectInput(display,windows->image.id, 9752 windows->image.attributes.event_mask | PointerMotionMask); 9753 state=DefaultState; 9754 do 9755 { 9756 if (windows->info.mapped != MagickFalse) 9757 { 9758 /* 9759 Display pointer position. 9760 */ 9761 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9762 x+windows->image.x,y+windows->image.y); 9763 XInfoWidget(display,windows,text); 9764 } 9765 /* 9766 Wait for next event. 9767 */ 9768 XScreenEvent(display,windows,&event,exception); 9769 if (event.xany.window == windows->command.id) 9770 { 9771 /* 9772 Select a command from the Command widget. 9773 */ 9774 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9775 if (id < 0) 9776 { 9777 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9778 continue; 9779 } 9780 switch (MatteEditCommands[id]) 9781 { 9782 case MatteEditMethod: 9783 { 9784 char 9785 **methods; 9786 9787 /* 9788 Select a method from the pop-up menu. 9789 */ 9790 methods=GetCommandOptions(MagickMethodOptions); 9791 if (methods == (char **) NULL) 9792 break; 9793 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9794 (const char **) methods,command); 9795 if (entry >= 0) 9796 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9797 MagickFalse,methods[entry]); 9798 methods=DestroyStringList(methods); 9799 break; 9800 } 9801 case MatteEditBorderCommand: 9802 { 9803 const char 9804 *ColorMenu[MaxNumberPens]; 9805 9806 int 9807 pen_number; 9808 9809 /* 9810 Initialize menu selections. 9811 */ 9812 for (i=0; i < (int) (MaxNumberPens-2); i++) 9813 ColorMenu[i]=resource_info->pen_colors[i]; 9814 ColorMenu[MaxNumberPens-2]="Browser..."; 9815 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9816 /* 9817 Select a pen color from the pop-up menu. 9818 */ 9819 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9820 (const char **) ColorMenu,command); 9821 if (pen_number < 0) 9822 break; 9823 if (pen_number == (MaxNumberPens-2)) 9824 { 9825 static char 9826 color_name[MaxTextExtent] = "gray"; 9827 9828 /* 9829 Select a pen color from a dialog. 9830 */ 9831 resource_info->pen_colors[pen_number]=color_name; 9832 XColorBrowserWidget(display,windows,"Select",color_name); 9833 if (*color_name == '\0') 9834 break; 9835 } 9836 /* 9837 Set border color. 9838 */ 9839 (void) XParseColor(display,windows->map_info->colormap, 9840 resource_info->pen_colors[pen_number],&border_color); 9841 break; 9842 } 9843 case MatteEditFuzzCommand: 9844 { 9845 static char 9846 fuzz[MaxTextExtent]; 9847 9848 static const char 9849 *FuzzMenu[] = 9850 { 9851 "0%", 9852 "2%", 9853 "5%", 9854 "10%", 9855 "15%", 9856 "Dialog...", 9857 (char *) NULL, 9858 }; 9859 9860 /* 9861 Select a command from the pop-up menu. 9862 */ 9863 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9864 command); 9865 if (entry < 0) 9866 break; 9867 if (entry != 5) 9868 { 9869 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9870 QuantumRange+1.0); 9871 break; 9872 } 9873 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9874 (void) XDialogWidget(display,windows,"Ok", 9875 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9876 if (*fuzz == '\0') 9877 break; 9878 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9879 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9880 1.0); 9881 break; 9882 } 9883 case MatteEditValueCommand: 9884 { 9885 static char 9886 message[MaxTextExtent]; 9887 9888 static const char 9889 *MatteMenu[] = 9890 { 9891 "Opaque", 9892 "Transparent", 9893 "Dialog...", 9894 (char *) NULL, 9895 }; 9896 9897 /* 9898 Select a command from the pop-up menu. 9899 */ 9900 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9901 command); 9902 if (entry < 0) 9903 break; 9904 if (entry != 2) 9905 { 9906 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9907 OpaqueAlpha); 9908 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9909 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9910 (Quantum) TransparentAlpha); 9911 break; 9912 } 9913 (void) FormatLocaleString(message,MaxTextExtent, 9914 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9915 QuantumRange); 9916 (void) XDialogWidget(display,windows,"Matte",message,matte); 9917 if (*matte == '\0') 9918 break; 9919 break; 9920 } 9921 case MatteEditUndoCommand: 9922 { 9923 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9924 image,exception); 9925 break; 9926 } 9927 case MatteEditHelpCommand: 9928 { 9929 XTextViewWidget(display,resource_info,windows,MagickFalse, 9930 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9931 break; 9932 } 9933 case MatteEditDismissCommand: 9934 { 9935 /* 9936 Prematurely exit. 9937 */ 9938 state|=EscapeState; 9939 state|=ExitState; 9940 break; 9941 } 9942 default: 9943 break; 9944 } 9945 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9946 continue; 9947 } 9948 switch (event.type) 9949 { 9950 case ButtonPress: 9951 { 9952 if (event.xbutton.button != Button1) 9953 break; 9954 if ((event.xbutton.window != windows->image.id) && 9955 (event.xbutton.window != windows->magnify.id)) 9956 break; 9957 /* 9958 Update matte data. 9959 */ 9960 x=event.xbutton.x; 9961 y=event.xbutton.y; 9962 (void) XMagickCommand(display,resource_info,windows, 9963 SaveToUndoBufferCommand,image,exception); 9964 state|=UpdateConfigurationState; 9965 break; 9966 } 9967 case ButtonRelease: 9968 { 9969 if (event.xbutton.button != Button1) 9970 break; 9971 if ((event.xbutton.window != windows->image.id) && 9972 (event.xbutton.window != windows->magnify.id)) 9973 break; 9974 /* 9975 Update colormap information. 9976 */ 9977 x=event.xbutton.x; 9978 y=event.xbutton.y; 9979 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9980 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9981 XInfoWidget(display,windows,text); 9982 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9983 state&=(~UpdateConfigurationState); 9984 break; 9985 } 9986 case Expose: 9987 break; 9988 case KeyPress: 9989 { 9990 char 9991 command[MaxTextExtent]; 9992 9993 KeySym 9994 key_symbol; 9995 9996 if (event.xkey.window == windows->magnify.id) 9997 { 9998 Window 9999 window; 10000 10001 window=windows->magnify.id; 10002 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10003 } 10004 if (event.xkey.window != windows->image.id) 10005 break; 10006 /* 10007 Respond to a user key press. 10008 */ 10009 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10010 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10011 switch ((int) key_symbol) 10012 { 10013 case XK_Escape: 10014 case XK_F20: 10015 { 10016 /* 10017 Prematurely exit. 10018 */ 10019 state|=ExitState; 10020 break; 10021 } 10022 case XK_F1: 10023 case XK_Help: 10024 { 10025 XTextViewWidget(display,resource_info,windows,MagickFalse, 10026 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10027 break; 10028 } 10029 default: 10030 { 10031 (void) XBell(display,0); 10032 break; 10033 } 10034 } 10035 break; 10036 } 10037 case MotionNotify: 10038 { 10039 /* 10040 Map and unmap Info widget as cursor crosses its boundaries. 10041 */ 10042 x=event.xmotion.x; 10043 y=event.xmotion.y; 10044 if (windows->info.mapped != MagickFalse) 10045 { 10046 if ((x < (int) (windows->info.x+windows->info.width)) && 10047 (y < (int) (windows->info.y+windows->info.height))) 10048 (void) XWithdrawWindow(display,windows->info.id, 10049 windows->info.screen); 10050 } 10051 else 10052 if ((x > (int) (windows->info.x+windows->info.width)) || 10053 (y > (int) (windows->info.y+windows->info.height))) 10054 (void) XMapWindow(display,windows->info.id); 10055 break; 10056 } 10057 default: 10058 break; 10059 } 10060 if (event.xany.window == windows->magnify.id) 10061 { 10062 x=windows->magnify.x-windows->image.x; 10063 y=windows->magnify.y-windows->image.y; 10064 } 10065 x_offset=x; 10066 y_offset=y; 10067 if ((state & UpdateConfigurationState) != 0) 10068 { 10069 CacheView 10070 *image_view; 10071 10072 int 10073 x, 10074 y; 10075 10076 /* 10077 Matte edit is relative to image configuration. 10078 */ 10079 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10080 MagickTrue); 10081 XPutPixel(windows->image.ximage,x_offset,y_offset, 10082 windows->pixel_info->background_color.pixel); 10083 width=(unsigned int) (*image)->columns; 10084 height=(unsigned int) (*image)->rows; 10085 x=0; 10086 y=0; 10087 if (windows->image.crop_geometry != (char *) NULL) 10088 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10089 &height); 10090 x_offset=(int) (width*(windows->image.x+x_offset)/ 10091 windows->image.ximage->width+x); 10092 y_offset=(int) (height*(windows->image.y+y_offset)/ 10093 windows->image.ximage->height+y); 10094 if ((x_offset < 0) || (y_offset < 0)) 10095 continue; 10096 if ((x_offset >= (int) (*image)->columns) || 10097 (y_offset >= (int) (*image)->rows)) 10098 continue; 10099 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10100 return(MagickFalse); 10101 (*image)->matte=MagickTrue; 10102 image_view=AcquireCacheView(*image); 10103 switch (method) 10104 { 10105 case PointMethod: 10106 default: 10107 { 10108 /* 10109 Update matte information using point algorithm. 10110 */ 10111 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10112 (ssize_t) y_offset,1,1,exception); 10113 if (q == (Quantum *) NULL) 10114 break; 10115 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10116 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10117 break; 10118 } 10119 case ReplaceMethod: 10120 { 10121 PixelInfo 10122 pixel, 10123 target; 10124 10125 Quantum 10126 virtual_pixel[CompositePixelChannel]; 10127 10128 /* 10129 Update matte information using replace algorithm. 10130 */ 10131 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10132 (ssize_t) y_offset,virtual_pixel,exception); 10133 target.red=virtual_pixel[RedPixelChannel]; 10134 target.green=virtual_pixel[GreenPixelChannel]; 10135 target.blue=virtual_pixel[BluePixelChannel]; 10136 target.alpha=virtual_pixel[AlphaPixelChannel]; 10137 for (y=0; y < (int) (*image)->rows; y++) 10138 { 10139 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10140 (*image)->columns,1,exception); 10141 if (q == (Quantum *) NULL) 10142 break; 10143 for (x=0; x < (int) (*image)->columns; x++) 10144 { 10145 GetPixelInfoPixel(*image,q,&pixel); 10146 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10147 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10148 q+=GetPixelChannels(*image); 10149 } 10150 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10151 break; 10152 } 10153 break; 10154 } 10155 case FloodfillMethod: 10156 case FillToBorderMethod: 10157 { 10158 ChannelType 10159 channel_mask; 10160 10161 DrawInfo 10162 *draw_info; 10163 10164 PixelInfo 10165 target; 10166 10167 /* 10168 Update matte information using floodfill algorithm. 10169 */ 10170 (void) GetOneVirtualMagickPixel(*image, 10171 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10172 y_offset,&target,exception); 10173 if (method == FillToBorderMethod) 10174 { 10175 target.red=(MagickRealType) ScaleShortToQuantum( 10176 border_color.red); 10177 target.green=(MagickRealType) ScaleShortToQuantum( 10178 border_color.green); 10179 target.blue=(MagickRealType) ScaleShortToQuantum( 10180 border_color.blue); 10181 } 10182 draw_info=CloneDrawInfo(resource_info->image_info, 10183 (DrawInfo *) NULL); 10184 draw_info->fill.alpha=ClampToQuantum(StringToDouble(matte, 10185 (char **) NULL)); 10186 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10187 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10188 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10189 MagickFalse : MagickTrue,exception); 10190 (void) SetPixelChannelMapMask(*image,channel_mask); 10191 draw_info=DestroyDrawInfo(draw_info); 10192 break; 10193 } 10194 case ResetMethod: 10195 { 10196 /* 10197 Update matte information using reset algorithm. 10198 */ 10199 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10200 return(MagickFalse); 10201 for (y=0; y < (int) (*image)->rows; y++) 10202 { 10203 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10204 (*image)->columns,1,exception); 10205 if (q == (Quantum *) NULL) 10206 break; 10207 for (x=0; x < (int) (*image)->columns; x++) 10208 { 10209 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10210 q+=GetPixelChannels(*image); 10211 } 10212 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10213 break; 10214 } 10215 if (StringToLong(matte) == (long) OpaqueAlpha) 10216 (*image)->matte=MagickFalse; 10217 break; 10218 } 10219 } 10220 image_view=DestroyCacheView(image_view); 10221 state&=(~UpdateConfigurationState); 10222 } 10223 } while ((state & ExitState) == 0); 10224 (void) XSelectInput(display,windows->image.id, 10225 windows->image.attributes.event_mask); 10226 XSetCursorState(display,windows,MagickFalse); 10227 (void) XFreeCursor(display,cursor); 10228 return(MagickTrue); 10229} 10230 10231/* 10232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10233% % 10234% % 10235% % 10236+ X O p e n I m a g e % 10237% % 10238% % 10239% % 10240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10241% 10242% XOpenImage() loads an image from a file. 10243% 10244% The format of the XOpenImage method is: 10245% 10246% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10247% XWindows *windows,const unsigned int command) 10248% 10249% A description of each parameter follows: 10250% 10251% o display: Specifies a connection to an X server; returned from 10252% XOpenDisplay. 10253% 10254% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10255% 10256% o windows: Specifies a pointer to a XWindows structure. 10257% 10258% o command: A value other than zero indicates that the file is selected 10259% from the command line argument list. 10260% 10261*/ 10262static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10263 XWindows *windows,const MagickBooleanType command) 10264{ 10265 const MagickInfo 10266 *magick_info; 10267 10268 ExceptionInfo 10269 *exception; 10270 10271 Image 10272 *nexus; 10273 10274 ImageInfo 10275 *image_info; 10276 10277 static char 10278 filename[MaxTextExtent] = "\0"; 10279 10280 /* 10281 Request file name from user. 10282 */ 10283 if (command == MagickFalse) 10284 XFileBrowserWidget(display,windows,"Open",filename); 10285 else 10286 { 10287 char 10288 **filelist, 10289 **files; 10290 10291 int 10292 count, 10293 status; 10294 10295 register int 10296 i, 10297 j; 10298 10299 /* 10300 Select next image from the command line. 10301 */ 10302 status=XGetCommand(display,windows->image.id,&files,&count); 10303 if (status == 0) 10304 { 10305 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10306 return((Image *) NULL); 10307 } 10308 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10309 if (filelist == (char **) NULL) 10310 { 10311 ThrowXWindowFatalException(ResourceLimitError, 10312 "MemoryAllocationFailed","..."); 10313 (void) XFreeStringList(files); 10314 return((Image *) NULL); 10315 } 10316 j=0; 10317 for (i=1; i < count; i++) 10318 if (*files[i] != '-') 10319 filelist[j++]=files[i]; 10320 filelist[j]=(char *) NULL; 10321 XListBrowserWidget(display,windows,&windows->widget, 10322 (const char **) filelist,"Load","Select Image to Load:",filename); 10323 filelist=(char **) RelinquishMagickMemory(filelist); 10324 (void) XFreeStringList(files); 10325 } 10326 if (*filename == '\0') 10327 return((Image *) NULL); 10328 image_info=CloneImageInfo(resource_info->image_info); 10329 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10330 (void *) NULL); 10331 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10332 exception=AcquireExceptionInfo(); 10333 (void) SetImageInfo(image_info,0,exception); 10334 if (LocaleCompare(image_info->magick,"X") == 0) 10335 { 10336 char 10337 seconds[MaxTextExtent]; 10338 10339 /* 10340 User may want to delay the X server screen grab. 10341 */ 10342 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10343 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10344 seconds); 10345 if (*seconds == '\0') 10346 return((Image *) NULL); 10347 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10348 } 10349 magick_info=GetMagickInfo(image_info->magick,exception); 10350 if ((magick_info != (const MagickInfo *) NULL) && 10351 (magick_info->raw != MagickFalse)) 10352 { 10353 char 10354 geometry[MaxTextExtent]; 10355 10356 /* 10357 Request image size from the user. 10358 */ 10359 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10360 if (image_info->size != (char *) NULL) 10361 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10362 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10363 geometry); 10364 (void) CloneString(&image_info->size,geometry); 10365 } 10366 /* 10367 Load the image. 10368 */ 10369 XSetCursorState(display,windows,MagickTrue); 10370 XCheckRefreshWindows(display,windows); 10371 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10372 nexus=ReadImage(image_info,exception); 10373 CatchException(exception); 10374 XSetCursorState(display,windows,MagickFalse); 10375 if (nexus != (Image *) NULL) 10376 XClientMessage(display,windows->image.id,windows->im_protocols, 10377 windows->im_next_image,CurrentTime); 10378 else 10379 { 10380 char 10381 *text, 10382 **textlist; 10383 10384 /* 10385 Unknown image format. 10386 */ 10387 text=FileToString(filename,~0,exception); 10388 if (text == (char *) NULL) 10389 return((Image *) NULL); 10390 textlist=StringToList(text); 10391 if (textlist != (char **) NULL) 10392 { 10393 char 10394 title[MaxTextExtent]; 10395 10396 register int 10397 i; 10398 10399 (void) FormatLocaleString(title,MaxTextExtent, 10400 "Unknown format: %s",filename); 10401 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10402 (const char **) textlist); 10403 for (i=0; textlist[i] != (char *) NULL; i++) 10404 textlist[i]=DestroyString(textlist[i]); 10405 textlist=(char **) RelinquishMagickMemory(textlist); 10406 } 10407 text=DestroyString(text); 10408 } 10409 exception=DestroyExceptionInfo(exception); 10410 image_info=DestroyImageInfo(image_info); 10411 return(nexus); 10412} 10413 10414/* 10415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10416% % 10417% % 10418% % 10419+ X P a n I m a g e % 10420% % 10421% % 10422% % 10423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10424% 10425% XPanImage() pans the image until the mouse button is released. 10426% 10427% The format of the XPanImage method is: 10428% 10429% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10430% ExceptionInfo *exception) 10431% 10432% A description of each parameter follows: 10433% 10434% o display: Specifies a connection to an X server; returned from 10435% XOpenDisplay. 10436% 10437% o windows: Specifies a pointer to a XWindows structure. 10438% 10439% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10440% the entire image is refreshed. 10441% 10442% o exception: return any errors or warnings in this structure. 10443% 10444*/ 10445static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10446 ExceptionInfo *exception) 10447{ 10448 char 10449 text[MaxTextExtent]; 10450 10451 Cursor 10452 cursor; 10453 10454 MagickRealType 10455 x_factor, 10456 y_factor; 10457 10458 RectangleInfo 10459 pan_info; 10460 10461 size_t 10462 state; 10463 10464 /* 10465 Define cursor. 10466 */ 10467 if ((windows->image.ximage->width > (int) windows->image.width) && 10468 (windows->image.ximage->height > (int) windows->image.height)) 10469 cursor=XCreateFontCursor(display,XC_fleur); 10470 else 10471 if (windows->image.ximage->width > (int) windows->image.width) 10472 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10473 else 10474 if (windows->image.ximage->height > (int) windows->image.height) 10475 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10476 else 10477 cursor=XCreateFontCursor(display,XC_arrow); 10478 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10479 /* 10480 Pan image as pointer moves until the mouse button is released. 10481 */ 10482 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10483 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10484 pan_info.width=windows->pan.width*windows->image.width/ 10485 windows->image.ximage->width; 10486 pan_info.height=windows->pan.height*windows->image.height/ 10487 windows->image.ximage->height; 10488 pan_info.x=0; 10489 pan_info.y=0; 10490 state=UpdateConfigurationState; 10491 do 10492 { 10493 switch (event->type) 10494 { 10495 case ButtonPress: 10496 { 10497 /* 10498 User choose an initial pan location. 10499 */ 10500 pan_info.x=(ssize_t) event->xbutton.x; 10501 pan_info.y=(ssize_t) event->xbutton.y; 10502 state|=UpdateConfigurationState; 10503 break; 10504 } 10505 case ButtonRelease: 10506 { 10507 /* 10508 User has finished panning the image. 10509 */ 10510 pan_info.x=(ssize_t) event->xbutton.x; 10511 pan_info.y=(ssize_t) event->xbutton.y; 10512 state|=UpdateConfigurationState | ExitState; 10513 break; 10514 } 10515 case MotionNotify: 10516 { 10517 pan_info.x=(ssize_t) event->xmotion.x; 10518 pan_info.y=(ssize_t) event->xmotion.y; 10519 state|=UpdateConfigurationState; 10520 } 10521 default: 10522 break; 10523 } 10524 if ((state & UpdateConfigurationState) != 0) 10525 { 10526 /* 10527 Check boundary conditions. 10528 */ 10529 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10530 pan_info.x=0; 10531 else 10532 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10533 if (pan_info.x < 0) 10534 pan_info.x=0; 10535 else 10536 if ((int) (pan_info.x+windows->image.width) > 10537 windows->image.ximage->width) 10538 pan_info.x=(ssize_t) 10539 (windows->image.ximage->width-windows->image.width); 10540 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10541 pan_info.y=0; 10542 else 10543 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10544 if (pan_info.y < 0) 10545 pan_info.y=0; 10546 else 10547 if ((int) (pan_info.y+windows->image.height) > 10548 windows->image.ximage->height) 10549 pan_info.y=(ssize_t) 10550 (windows->image.ximage->height-windows->image.height); 10551 if ((windows->image.x != (int) pan_info.x) || 10552 (windows->image.y != (int) pan_info.y)) 10553 { 10554 /* 10555 Display image pan offset. 10556 */ 10557 windows->image.x=(int) pan_info.x; 10558 windows->image.y=(int) pan_info.y; 10559 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10560 windows->image.width,windows->image.height,windows->image.x, 10561 windows->image.y); 10562 XInfoWidget(display,windows,text); 10563 /* 10564 Refresh Image window. 10565 */ 10566 XDrawPanRectangle(display,windows); 10567 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10568 } 10569 state&=(~UpdateConfigurationState); 10570 } 10571 /* 10572 Wait for next event. 10573 */ 10574 if ((state & ExitState) == 0) 10575 XScreenEvent(display,windows,event,exception); 10576 } while ((state & ExitState) == 0); 10577 /* 10578 Restore cursor. 10579 */ 10580 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10581 (void) XFreeCursor(display,cursor); 10582 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10583} 10584 10585/* 10586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10587% % 10588% % 10589% % 10590+ X P a s t e I m a g e % 10591% % 10592% % 10593% % 10594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10595% 10596% XPasteImage() pastes an image previously saved with XCropImage in the X 10597% window image at a location the user chooses with the pointer. 10598% 10599% The format of the XPasteImage method is: 10600% 10601% MagickBooleanType XPasteImage(Display *display, 10602% XResourceInfo *resource_info,XWindows *windows,Image *image, 10603% ExceptionInfo *exception) 10604% 10605% A description of each parameter follows: 10606% 10607% o display: Specifies a connection to an X server; returned from 10608% XOpenDisplay. 10609% 10610% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10611% 10612% o windows: Specifies a pointer to a XWindows structure. 10613% 10614% o image: the image; returned from ReadImage. 10615% 10616% o exception: return any errors or warnings in this structure. 10617% 10618*/ 10619static MagickBooleanType XPasteImage(Display *display, 10620 XResourceInfo *resource_info,XWindows *windows,Image *image, 10621 ExceptionInfo *exception) 10622{ 10623 static const char 10624 *PasteMenu[] = 10625 { 10626 "Operator", 10627 "Help", 10628 "Dismiss", 10629 (char *) NULL 10630 }; 10631 10632 static const ModeType 10633 PasteCommands[] = 10634 { 10635 PasteOperatorsCommand, 10636 PasteHelpCommand, 10637 PasteDismissCommand 10638 }; 10639 10640 static CompositeOperator 10641 compose = CopyCompositeOp; 10642 10643 char 10644 text[MaxTextExtent]; 10645 10646 Cursor 10647 cursor; 10648 10649 Image 10650 *paste_image; 10651 10652 int 10653 entry, 10654 id, 10655 x, 10656 y; 10657 10658 MagickRealType 10659 scale_factor; 10660 10661 RectangleInfo 10662 highlight_info, 10663 paste_info; 10664 10665 unsigned int 10666 height, 10667 width; 10668 10669 size_t 10670 state; 10671 10672 XEvent 10673 event; 10674 10675 /* 10676 Copy image. 10677 */ 10678 if (resource_info->copy_image == (Image *) NULL) 10679 return(MagickFalse); 10680 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10681 /* 10682 Map Command widget. 10683 */ 10684 (void) CloneString(&windows->command.name,"Paste"); 10685 windows->command.data=1; 10686 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10687 (void) XMapRaised(display,windows->command.id); 10688 XClientMessage(display,windows->image.id,windows->im_protocols, 10689 windows->im_update_widget,CurrentTime); 10690 /* 10691 Track pointer until button 1 is pressed. 10692 */ 10693 XSetCursorState(display,windows,MagickFalse); 10694 XQueryPosition(display,windows->image.id,&x,&y); 10695 (void) XSelectInput(display,windows->image.id, 10696 windows->image.attributes.event_mask | PointerMotionMask); 10697 paste_info.x=(ssize_t) windows->image.x+x; 10698 paste_info.y=(ssize_t) windows->image.y+y; 10699 paste_info.width=0; 10700 paste_info.height=0; 10701 cursor=XCreateFontCursor(display,XC_ul_angle); 10702 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10703 state=DefaultState; 10704 do 10705 { 10706 if (windows->info.mapped != MagickFalse) 10707 { 10708 /* 10709 Display pointer position. 10710 */ 10711 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10712 (long) paste_info.x,(long) paste_info.y); 10713 XInfoWidget(display,windows,text); 10714 } 10715 highlight_info=paste_info; 10716 highlight_info.x=paste_info.x-windows->image.x; 10717 highlight_info.y=paste_info.y-windows->image.y; 10718 XHighlightRectangle(display,windows->image.id, 10719 windows->image.highlight_context,&highlight_info); 10720 /* 10721 Wait for next event. 10722 */ 10723 XScreenEvent(display,windows,&event,exception); 10724 XHighlightRectangle(display,windows->image.id, 10725 windows->image.highlight_context,&highlight_info); 10726 if (event.xany.window == windows->command.id) 10727 { 10728 /* 10729 Select a command from the Command widget. 10730 */ 10731 id=XCommandWidget(display,windows,PasteMenu,&event); 10732 if (id < 0) 10733 continue; 10734 switch (PasteCommands[id]) 10735 { 10736 case PasteOperatorsCommand: 10737 { 10738 char 10739 command[MaxTextExtent], 10740 **operators; 10741 10742 /* 10743 Select a command from the pop-up menu. 10744 */ 10745 operators=GetCommandOptions(MagickComposeOptions); 10746 if (operators == (char **) NULL) 10747 break; 10748 entry=XMenuWidget(display,windows,PasteMenu[id], 10749 (const char **) operators,command); 10750 if (entry >= 0) 10751 compose=(CompositeOperator) ParseCommandOption( 10752 MagickComposeOptions,MagickFalse,operators[entry]); 10753 operators=DestroyStringList(operators); 10754 break; 10755 } 10756 case PasteHelpCommand: 10757 { 10758 XTextViewWidget(display,resource_info,windows,MagickFalse, 10759 "Help Viewer - Image Composite",ImagePasteHelp); 10760 break; 10761 } 10762 case PasteDismissCommand: 10763 { 10764 /* 10765 Prematurely exit. 10766 */ 10767 state|=EscapeState; 10768 state|=ExitState; 10769 break; 10770 } 10771 default: 10772 break; 10773 } 10774 continue; 10775 } 10776 switch (event.type) 10777 { 10778 case ButtonPress: 10779 { 10780 if (image->debug != MagickFalse) 10781 (void) LogMagickEvent(X11Event,GetMagickModule(), 10782 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10783 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10784 if (event.xbutton.button != Button1) 10785 break; 10786 if (event.xbutton.window != windows->image.id) 10787 break; 10788 /* 10789 Paste rectangle is relative to image configuration. 10790 */ 10791 width=(unsigned int) image->columns; 10792 height=(unsigned int) image->rows; 10793 x=0; 10794 y=0; 10795 if (windows->image.crop_geometry != (char *) NULL) 10796 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10797 &width,&height); 10798 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10799 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10800 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10801 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10802 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10803 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10804 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10805 break; 10806 } 10807 case ButtonRelease: 10808 { 10809 if (image->debug != MagickFalse) 10810 (void) LogMagickEvent(X11Event,GetMagickModule(), 10811 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10812 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10813 if (event.xbutton.button != Button1) 10814 break; 10815 if (event.xbutton.window != windows->image.id) 10816 break; 10817 if ((paste_info.width != 0) && (paste_info.height != 0)) 10818 { 10819 /* 10820 User has selected the location of the paste image. 10821 */ 10822 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10823 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10824 state|=ExitState; 10825 } 10826 break; 10827 } 10828 case Expose: 10829 break; 10830 case KeyPress: 10831 { 10832 char 10833 command[MaxTextExtent]; 10834 10835 KeySym 10836 key_symbol; 10837 10838 int 10839 length; 10840 10841 if (event.xkey.window != windows->image.id) 10842 break; 10843 /* 10844 Respond to a user key press. 10845 */ 10846 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10847 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10848 *(command+length)='\0'; 10849 if (image->debug != MagickFalse) 10850 (void) LogMagickEvent(X11Event,GetMagickModule(), 10851 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10852 switch ((int) key_symbol) 10853 { 10854 case XK_Escape: 10855 case XK_F20: 10856 { 10857 /* 10858 Prematurely exit. 10859 */ 10860 paste_image=DestroyImage(paste_image); 10861 state|=EscapeState; 10862 state|=ExitState; 10863 break; 10864 } 10865 case XK_F1: 10866 case XK_Help: 10867 { 10868 (void) XSetFunction(display,windows->image.highlight_context, 10869 GXcopy); 10870 XTextViewWidget(display,resource_info,windows,MagickFalse, 10871 "Help Viewer - Image Composite",ImagePasteHelp); 10872 (void) XSetFunction(display,windows->image.highlight_context, 10873 GXinvert); 10874 break; 10875 } 10876 default: 10877 { 10878 (void) XBell(display,0); 10879 break; 10880 } 10881 } 10882 break; 10883 } 10884 case MotionNotify: 10885 { 10886 /* 10887 Map and unmap Info widget as text cursor crosses its boundaries. 10888 */ 10889 x=event.xmotion.x; 10890 y=event.xmotion.y; 10891 if (windows->info.mapped != MagickFalse) 10892 { 10893 if ((x < (int) (windows->info.x+windows->info.width)) && 10894 (y < (int) (windows->info.y+windows->info.height))) 10895 (void) XWithdrawWindow(display,windows->info.id, 10896 windows->info.screen); 10897 } 10898 else 10899 if ((x > (int) (windows->info.x+windows->info.width)) || 10900 (y > (int) (windows->info.y+windows->info.height))) 10901 (void) XMapWindow(display,windows->info.id); 10902 paste_info.x=(ssize_t) windows->image.x+x; 10903 paste_info.y=(ssize_t) windows->image.y+y; 10904 break; 10905 } 10906 default: 10907 { 10908 if (image->debug != MagickFalse) 10909 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10910 event.type); 10911 break; 10912 } 10913 } 10914 } while ((state & ExitState) == 0); 10915 (void) XSelectInput(display,windows->image.id, 10916 windows->image.attributes.event_mask); 10917 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10918 XSetCursorState(display,windows,MagickFalse); 10919 (void) XFreeCursor(display,cursor); 10920 if ((state & EscapeState) != 0) 10921 return(MagickTrue); 10922 /* 10923 Image pasting is relative to image configuration. 10924 */ 10925 XSetCursorState(display,windows,MagickTrue); 10926 XCheckRefreshWindows(display,windows); 10927 width=(unsigned int) image->columns; 10928 height=(unsigned int) image->rows; 10929 x=0; 10930 y=0; 10931 if (windows->image.crop_geometry != (char *) NULL) 10932 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10933 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10934 paste_info.x+=x; 10935 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10936 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10937 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10938 paste_info.y+=y; 10939 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10940 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10941 /* 10942 Paste image with X Image window. 10943 */ 10944 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10945 exception); 10946 paste_image=DestroyImage(paste_image); 10947 XSetCursorState(display,windows,MagickFalse); 10948 /* 10949 Update image colormap. 10950 */ 10951 XConfigureImageColormap(display,resource_info,windows,image,exception); 10952 (void) XConfigureImage(display,resource_info,windows,image,exception); 10953 return(MagickTrue); 10954} 10955 10956/* 10957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10958% % 10959% % 10960% % 10961+ X P r i n t I m a g e % 10962% % 10963% % 10964% % 10965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10966% 10967% XPrintImage() prints an image to a Postscript printer. 10968% 10969% The format of the XPrintImage method is: 10970% 10971% MagickBooleanType XPrintImage(Display *display, 10972% XResourceInfo *resource_info,XWindows *windows,Image *image, 10973% ExceptionInfo *exception) 10974% 10975% A description of each parameter follows: 10976% 10977% o display: Specifies a connection to an X server; returned from 10978% XOpenDisplay. 10979% 10980% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10981% 10982% o windows: Specifies a pointer to a XWindows structure. 10983% 10984% o image: the image. 10985% 10986% o exception: return any errors or warnings in this structure. 10987% 10988*/ 10989static MagickBooleanType XPrintImage(Display *display, 10990 XResourceInfo *resource_info,XWindows *windows,Image *image, 10991 ExceptionInfo *exception) 10992{ 10993 char 10994 filename[MaxTextExtent], 10995 geometry[MaxTextExtent]; 10996 10997 Image 10998 *print_image; 10999 11000 ImageInfo 11001 *image_info; 11002 11003 MagickStatusType 11004 status; 11005 11006 /* 11007 Request Postscript page geometry from user. 11008 */ 11009 image_info=CloneImageInfo(resource_info->image_info); 11010 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11011 if (image_info->page != (char *) NULL) 11012 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11013 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11014 "Select Postscript Page Geometry:",geometry); 11015 if (*geometry == '\0') 11016 return(MagickTrue); 11017 image_info->page=GetPageGeometry(geometry); 11018 /* 11019 Apply image transforms. 11020 */ 11021 XSetCursorState(display,windows,MagickTrue); 11022 XCheckRefreshWindows(display,windows); 11023 print_image=CloneImage(image,0,0,MagickTrue,exception); 11024 if (print_image == (Image *) NULL) 11025 return(MagickFalse); 11026 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11027 windows->image.ximage->width,windows->image.ximage->height); 11028 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11029 exception); 11030 /* 11031 Print image. 11032 */ 11033 (void) AcquireUniqueFilename(filename); 11034 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11035 filename); 11036 status=WriteImage(image_info,print_image,exception); 11037 (void) RelinquishUniqueFileResource(filename); 11038 print_image=DestroyImage(print_image); 11039 image_info=DestroyImageInfo(image_info); 11040 XSetCursorState(display,windows,MagickFalse); 11041 return(status != 0 ? MagickTrue : MagickFalse); 11042} 11043 11044/* 11045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11046% % 11047% % 11048% % 11049+ X R O I I m a g e % 11050% % 11051% % 11052% % 11053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11054% 11055% XROIImage() applies an image processing technique to a region of interest. 11056% 11057% The format of the XROIImage method is: 11058% 11059% MagickBooleanType XROIImage(Display *display, 11060% XResourceInfo *resource_info,XWindows *windows,Image **image, 11061% ExceptionInfo *exception) 11062% 11063% A description of each parameter follows: 11064% 11065% o display: Specifies a connection to an X server; returned from 11066% XOpenDisplay. 11067% 11068% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11069% 11070% o windows: Specifies a pointer to a XWindows structure. 11071% 11072% o image: the image; returned from ReadImage. 11073% 11074% o exception: return any errors or warnings in this structure. 11075% 11076*/ 11077static MagickBooleanType XROIImage(Display *display, 11078 XResourceInfo *resource_info,XWindows *windows,Image **image, 11079 ExceptionInfo *exception) 11080{ 11081#define ApplyMenus 7 11082 11083 static const char 11084 *ROIMenu[] = 11085 { 11086 "Help", 11087 "Dismiss", 11088 (char *) NULL 11089 }, 11090 *ApplyMenu[] = 11091 { 11092 "File", 11093 "Edit", 11094 "Transform", 11095 "Enhance", 11096 "Effects", 11097 "F/X", 11098 "Miscellany", 11099 "Help", 11100 "Dismiss", 11101 (char *) NULL 11102 }, 11103 *FileMenu[] = 11104 { 11105 "Save...", 11106 "Print...", 11107 (char *) NULL 11108 }, 11109 *EditMenu[] = 11110 { 11111 "Undo", 11112 "Redo", 11113 (char *) NULL 11114 }, 11115 *TransformMenu[] = 11116 { 11117 "Flop", 11118 "Flip", 11119 "Rotate Right", 11120 "Rotate Left", 11121 (char *) NULL 11122 }, 11123 *EnhanceMenu[] = 11124 { 11125 "Hue...", 11126 "Saturation...", 11127 "Brightness...", 11128 "Gamma...", 11129 "Spiff", 11130 "Dull", 11131 "Contrast Stretch...", 11132 "Sigmoidal Contrast...", 11133 "Normalize", 11134 "Equalize", 11135 "Negate", 11136 "Grayscale", 11137 "Map...", 11138 "Quantize...", 11139 (char *) NULL 11140 }, 11141 *EffectsMenu[] = 11142 { 11143 "Despeckle", 11144 "Emboss", 11145 "Reduce Noise", 11146 "Add Noise", 11147 "Sharpen...", 11148 "Blur...", 11149 "Threshold...", 11150 "Edge Detect...", 11151 "Spread...", 11152 "Shade...", 11153 "Raise...", 11154 "Segment...", 11155 (char *) NULL 11156 }, 11157 *FXMenu[] = 11158 { 11159 "Solarize...", 11160 "Sepia Tone...", 11161 "Swirl...", 11162 "Implode...", 11163 "Vignette...", 11164 "Wave...", 11165 "Oil Paint...", 11166 "Charcoal Draw...", 11167 (char *) NULL 11168 }, 11169 *MiscellanyMenu[] = 11170 { 11171 "Image Info", 11172 "Zoom Image", 11173 "Show Preview...", 11174 "Show Histogram", 11175 "Show Matte", 11176 (char *) NULL 11177 }; 11178 11179 static const char 11180 **Menus[ApplyMenus] = 11181 { 11182 FileMenu, 11183 EditMenu, 11184 TransformMenu, 11185 EnhanceMenu, 11186 EffectsMenu, 11187 FXMenu, 11188 MiscellanyMenu 11189 }; 11190 11191 static const CommandType 11192 ApplyCommands[] = 11193 { 11194 NullCommand, 11195 NullCommand, 11196 NullCommand, 11197 NullCommand, 11198 NullCommand, 11199 NullCommand, 11200 NullCommand, 11201 HelpCommand, 11202 QuitCommand 11203 }, 11204 FileCommands[] = 11205 { 11206 SaveCommand, 11207 PrintCommand 11208 }, 11209 EditCommands[] = 11210 { 11211 UndoCommand, 11212 RedoCommand 11213 }, 11214 TransformCommands[] = 11215 { 11216 FlopCommand, 11217 FlipCommand, 11218 RotateRightCommand, 11219 RotateLeftCommand 11220 }, 11221 EnhanceCommands[] = 11222 { 11223 HueCommand, 11224 SaturationCommand, 11225 BrightnessCommand, 11226 GammaCommand, 11227 SpiffCommand, 11228 DullCommand, 11229 ContrastStretchCommand, 11230 SigmoidalContrastCommand, 11231 NormalizeCommand, 11232 EqualizeCommand, 11233 NegateCommand, 11234 GrayscaleCommand, 11235 MapCommand, 11236 QuantizeCommand 11237 }, 11238 EffectsCommands[] = 11239 { 11240 DespeckleCommand, 11241 EmbossCommand, 11242 ReduceNoiseCommand, 11243 AddNoiseCommand, 11244 SharpenCommand, 11245 BlurCommand, 11246 EdgeDetectCommand, 11247 SpreadCommand, 11248 ShadeCommand, 11249 RaiseCommand, 11250 SegmentCommand 11251 }, 11252 FXCommands[] = 11253 { 11254 SolarizeCommand, 11255 SepiaToneCommand, 11256 SwirlCommand, 11257 ImplodeCommand, 11258 VignetteCommand, 11259 WaveCommand, 11260 OilPaintCommand, 11261 CharcoalDrawCommand 11262 }, 11263 MiscellanyCommands[] = 11264 { 11265 InfoCommand, 11266 ZoomCommand, 11267 ShowPreviewCommand, 11268 ShowHistogramCommand, 11269 ShowMatteCommand 11270 }, 11271 ROICommands[] = 11272 { 11273 ROIHelpCommand, 11274 ROIDismissCommand 11275 }; 11276 11277 static const CommandType 11278 *Commands[ApplyMenus] = 11279 { 11280 FileCommands, 11281 EditCommands, 11282 TransformCommands, 11283 EnhanceCommands, 11284 EffectsCommands, 11285 FXCommands, 11286 MiscellanyCommands 11287 }; 11288 11289 char 11290 command[MaxTextExtent], 11291 text[MaxTextExtent]; 11292 11293 CommandType 11294 command_type; 11295 11296 Cursor 11297 cursor; 11298 11299 Image 11300 *roi_image; 11301 11302 int 11303 entry, 11304 id, 11305 x, 11306 y; 11307 11308 MagickRealType 11309 scale_factor; 11310 11311 MagickProgressMonitor 11312 progress_monitor; 11313 11314 RectangleInfo 11315 crop_info, 11316 highlight_info, 11317 roi_info; 11318 11319 unsigned int 11320 height, 11321 width; 11322 11323 size_t 11324 state; 11325 11326 XEvent 11327 event; 11328 11329 /* 11330 Map Command widget. 11331 */ 11332 (void) CloneString(&windows->command.name,"ROI"); 11333 windows->command.data=0; 11334 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11335 (void) XMapRaised(display,windows->command.id); 11336 XClientMessage(display,windows->image.id,windows->im_protocols, 11337 windows->im_update_widget,CurrentTime); 11338 /* 11339 Track pointer until button 1 is pressed. 11340 */ 11341 XQueryPosition(display,windows->image.id,&x,&y); 11342 (void) XSelectInput(display,windows->image.id, 11343 windows->image.attributes.event_mask | PointerMotionMask); 11344 roi_info.x=(ssize_t) windows->image.x+x; 11345 roi_info.y=(ssize_t) windows->image.y+y; 11346 roi_info.width=0; 11347 roi_info.height=0; 11348 cursor=XCreateFontCursor(display,XC_fleur); 11349 state=DefaultState; 11350 do 11351 { 11352 if (windows->info.mapped != MagickFalse) 11353 { 11354 /* 11355 Display pointer position. 11356 */ 11357 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11358 (long) roi_info.x,(long) roi_info.y); 11359 XInfoWidget(display,windows,text); 11360 } 11361 /* 11362 Wait for next event. 11363 */ 11364 XScreenEvent(display,windows,&event,exception); 11365 if (event.xany.window == windows->command.id) 11366 { 11367 /* 11368 Select a command from the Command widget. 11369 */ 11370 id=XCommandWidget(display,windows,ROIMenu,&event); 11371 if (id < 0) 11372 continue; 11373 switch (ROICommands[id]) 11374 { 11375 case ROIHelpCommand: 11376 { 11377 XTextViewWidget(display,resource_info,windows,MagickFalse, 11378 "Help Viewer - Region of Interest",ImageROIHelp); 11379 break; 11380 } 11381 case ROIDismissCommand: 11382 { 11383 /* 11384 Prematurely exit. 11385 */ 11386 state|=EscapeState; 11387 state|=ExitState; 11388 break; 11389 } 11390 default: 11391 break; 11392 } 11393 continue; 11394 } 11395 switch (event.type) 11396 { 11397 case ButtonPress: 11398 { 11399 if (event.xbutton.button != Button1) 11400 break; 11401 if (event.xbutton.window != windows->image.id) 11402 break; 11403 /* 11404 Note first corner of region of interest rectangle-- exit loop. 11405 */ 11406 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11407 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11408 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11409 state|=ExitState; 11410 break; 11411 } 11412 case ButtonRelease: 11413 break; 11414 case Expose: 11415 break; 11416 case KeyPress: 11417 { 11418 KeySym 11419 key_symbol; 11420 11421 if (event.xkey.window != windows->image.id) 11422 break; 11423 /* 11424 Respond to a user key press. 11425 */ 11426 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11427 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11428 switch ((int) key_symbol) 11429 { 11430 case XK_Escape: 11431 case XK_F20: 11432 { 11433 /* 11434 Prematurely exit. 11435 */ 11436 state|=EscapeState; 11437 state|=ExitState; 11438 break; 11439 } 11440 case XK_F1: 11441 case XK_Help: 11442 { 11443 XTextViewWidget(display,resource_info,windows,MagickFalse, 11444 "Help Viewer - Region of Interest",ImageROIHelp); 11445 break; 11446 } 11447 default: 11448 { 11449 (void) XBell(display,0); 11450 break; 11451 } 11452 } 11453 break; 11454 } 11455 case MotionNotify: 11456 { 11457 /* 11458 Map and unmap Info widget as text cursor crosses its boundaries. 11459 */ 11460 x=event.xmotion.x; 11461 y=event.xmotion.y; 11462 if (windows->info.mapped != MagickFalse) 11463 { 11464 if ((x < (int) (windows->info.x+windows->info.width)) && 11465 (y < (int) (windows->info.y+windows->info.height))) 11466 (void) XWithdrawWindow(display,windows->info.id, 11467 windows->info.screen); 11468 } 11469 else 11470 if ((x > (int) (windows->info.x+windows->info.width)) || 11471 (y > (int) (windows->info.y+windows->info.height))) 11472 (void) XMapWindow(display,windows->info.id); 11473 roi_info.x=(ssize_t) windows->image.x+x; 11474 roi_info.y=(ssize_t) windows->image.y+y; 11475 break; 11476 } 11477 default: 11478 break; 11479 } 11480 } while ((state & ExitState) == 0); 11481 (void) XSelectInput(display,windows->image.id, 11482 windows->image.attributes.event_mask); 11483 if ((state & EscapeState) != 0) 11484 { 11485 /* 11486 User want to exit without region of interest. 11487 */ 11488 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11489 (void) XFreeCursor(display,cursor); 11490 return(MagickTrue); 11491 } 11492 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11493 do 11494 { 11495 /* 11496 Size rectangle as pointer moves until the mouse button is released. 11497 */ 11498 x=(int) roi_info.x; 11499 y=(int) roi_info.y; 11500 roi_info.width=0; 11501 roi_info.height=0; 11502 state=DefaultState; 11503 do 11504 { 11505 highlight_info=roi_info; 11506 highlight_info.x=roi_info.x-windows->image.x; 11507 highlight_info.y=roi_info.y-windows->image.y; 11508 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11509 { 11510 /* 11511 Display info and draw region of interest rectangle. 11512 */ 11513 if (windows->info.mapped == MagickFalse) 11514 (void) XMapWindow(display,windows->info.id); 11515 (void) FormatLocaleString(text,MaxTextExtent, 11516 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11517 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11518 XInfoWidget(display,windows,text); 11519 XHighlightRectangle(display,windows->image.id, 11520 windows->image.highlight_context,&highlight_info); 11521 } 11522 else 11523 if (windows->info.mapped != MagickFalse) 11524 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11525 /* 11526 Wait for next event. 11527 */ 11528 XScreenEvent(display,windows,&event,exception); 11529 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11530 XHighlightRectangle(display,windows->image.id, 11531 windows->image.highlight_context,&highlight_info); 11532 switch (event.type) 11533 { 11534 case ButtonPress: 11535 { 11536 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11537 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11538 break; 11539 } 11540 case ButtonRelease: 11541 { 11542 /* 11543 User has committed to region of interest rectangle. 11544 */ 11545 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11546 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11547 XSetCursorState(display,windows,MagickFalse); 11548 state|=ExitState; 11549 if (LocaleCompare(windows->command.name,"Apply") == 0) 11550 break; 11551 (void) CloneString(&windows->command.name,"Apply"); 11552 windows->command.data=ApplyMenus; 11553 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11554 break; 11555 } 11556 case Expose: 11557 break; 11558 case MotionNotify: 11559 { 11560 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11561 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11562 } 11563 default: 11564 break; 11565 } 11566 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11567 ((state & ExitState) != 0)) 11568 { 11569 /* 11570 Check boundary conditions. 11571 */ 11572 if (roi_info.x < 0) 11573 roi_info.x=0; 11574 else 11575 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11576 roi_info.x=(ssize_t) windows->image.ximage->width; 11577 if ((int) roi_info.x < x) 11578 roi_info.width=(unsigned int) (x-roi_info.x); 11579 else 11580 { 11581 roi_info.width=(unsigned int) (roi_info.x-x); 11582 roi_info.x=(ssize_t) x; 11583 } 11584 if (roi_info.y < 0) 11585 roi_info.y=0; 11586 else 11587 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11588 roi_info.y=(ssize_t) windows->image.ximage->height; 11589 if ((int) roi_info.y < y) 11590 roi_info.height=(unsigned int) (y-roi_info.y); 11591 else 11592 { 11593 roi_info.height=(unsigned int) (roi_info.y-y); 11594 roi_info.y=(ssize_t) y; 11595 } 11596 } 11597 } while ((state & ExitState) == 0); 11598 /* 11599 Wait for user to grab a corner of the rectangle or press return. 11600 */ 11601 state=DefaultState; 11602 command_type=NullCommand; 11603 (void) XMapWindow(display,windows->info.id); 11604 do 11605 { 11606 if (windows->info.mapped != MagickFalse) 11607 { 11608 /* 11609 Display pointer position. 11610 */ 11611 (void) FormatLocaleString(text,MaxTextExtent, 11612 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11613 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11614 XInfoWidget(display,windows,text); 11615 } 11616 highlight_info=roi_info; 11617 highlight_info.x=roi_info.x-windows->image.x; 11618 highlight_info.y=roi_info.y-windows->image.y; 11619 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11620 { 11621 state|=EscapeState; 11622 state|=ExitState; 11623 break; 11624 } 11625 if ((state & UpdateRegionState) != 0) 11626 { 11627 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11628 switch (command_type) 11629 { 11630 case UndoCommand: 11631 case RedoCommand: 11632 { 11633 (void) XMagickCommand(display,resource_info,windows,command_type, 11634 image,exception); 11635 break; 11636 } 11637 default: 11638 { 11639 /* 11640 Region of interest is relative to image configuration. 11641 */ 11642 progress_monitor=SetImageProgressMonitor(*image, 11643 (MagickProgressMonitor) NULL,(*image)->client_data); 11644 crop_info=roi_info; 11645 width=(unsigned int) (*image)->columns; 11646 height=(unsigned int) (*image)->rows; 11647 x=0; 11648 y=0; 11649 if (windows->image.crop_geometry != (char *) NULL) 11650 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11651 &width,&height); 11652 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11653 crop_info.x+=x; 11654 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11655 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11656 scale_factor=(MagickRealType) 11657 height/windows->image.ximage->height; 11658 crop_info.y+=y; 11659 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11660 crop_info.height=(unsigned int) 11661 (scale_factor*crop_info.height+0.5); 11662 roi_image=CropImage(*image,&crop_info,exception); 11663 (void) SetImageProgressMonitor(*image,progress_monitor, 11664 (*image)->client_data); 11665 if (roi_image == (Image *) NULL) 11666 continue; 11667 /* 11668 Apply image processing technique to the region of interest. 11669 */ 11670 windows->image.orphan=MagickTrue; 11671 (void) XMagickCommand(display,resource_info,windows,command_type, 11672 &roi_image,exception); 11673 progress_monitor=SetImageProgressMonitor(*image, 11674 (MagickProgressMonitor) NULL,(*image)->client_data); 11675 (void) XMagickCommand(display,resource_info,windows, 11676 SaveToUndoBufferCommand,image,exception); 11677 windows->image.orphan=MagickFalse; 11678 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11679 crop_info.x,crop_info.y,exception); 11680 roi_image=DestroyImage(roi_image); 11681 (void) SetImageProgressMonitor(*image,progress_monitor, 11682 (*image)->client_data); 11683 break; 11684 } 11685 } 11686 if (command_type != InfoCommand) 11687 { 11688 XConfigureImageColormap(display,resource_info,windows,*image, 11689 exception); 11690 (void) XConfigureImage(display,resource_info,windows,*image, 11691 exception); 11692 } 11693 XCheckRefreshWindows(display,windows); 11694 XInfoWidget(display,windows,text); 11695 (void) XSetFunction(display,windows->image.highlight_context, 11696 GXinvert); 11697 state&=(~UpdateRegionState); 11698 } 11699 XHighlightRectangle(display,windows->image.id, 11700 windows->image.highlight_context,&highlight_info); 11701 XScreenEvent(display,windows,&event,exception); 11702 if (event.xany.window == windows->command.id) 11703 { 11704 /* 11705 Select a command from the Command widget. 11706 */ 11707 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11708 command_type=NullCommand; 11709 id=XCommandWidget(display,windows,ApplyMenu,&event); 11710 if (id >= 0) 11711 { 11712 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11713 command_type=ApplyCommands[id]; 11714 if (id < ApplyMenus) 11715 { 11716 /* 11717 Select a command from a pop-up menu. 11718 */ 11719 entry=XMenuWidget(display,windows,ApplyMenu[id], 11720 (const char **) Menus[id],command); 11721 if (entry >= 0) 11722 { 11723 (void) CopyMagickString(command,Menus[id][entry], 11724 MaxTextExtent); 11725 command_type=Commands[id][entry]; 11726 } 11727 } 11728 } 11729 (void) XSetFunction(display,windows->image.highlight_context, 11730 GXinvert); 11731 XHighlightRectangle(display,windows->image.id, 11732 windows->image.highlight_context,&highlight_info); 11733 if (command_type == HelpCommand) 11734 { 11735 (void) XSetFunction(display,windows->image.highlight_context, 11736 GXcopy); 11737 XTextViewWidget(display,resource_info,windows,MagickFalse, 11738 "Help Viewer - Region of Interest",ImageROIHelp); 11739 (void) XSetFunction(display,windows->image.highlight_context, 11740 GXinvert); 11741 continue; 11742 } 11743 if (command_type == QuitCommand) 11744 { 11745 /* 11746 exit. 11747 */ 11748 state|=EscapeState; 11749 state|=ExitState; 11750 continue; 11751 } 11752 if (command_type != NullCommand) 11753 state|=UpdateRegionState; 11754 continue; 11755 } 11756 XHighlightRectangle(display,windows->image.id, 11757 windows->image.highlight_context,&highlight_info); 11758 switch (event.type) 11759 { 11760 case ButtonPress: 11761 { 11762 x=windows->image.x; 11763 y=windows->image.y; 11764 if (event.xbutton.button != Button1) 11765 break; 11766 if (event.xbutton.window != windows->image.id) 11767 break; 11768 x=windows->image.x+event.xbutton.x; 11769 y=windows->image.y+event.xbutton.y; 11770 if ((x < (int) (roi_info.x+RoiDelta)) && 11771 (x > (int) (roi_info.x-RoiDelta)) && 11772 (y < (int) (roi_info.y+RoiDelta)) && 11773 (y > (int) (roi_info.y-RoiDelta))) 11774 { 11775 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11776 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11777 state|=UpdateConfigurationState; 11778 break; 11779 } 11780 if ((x < (int) (roi_info.x+RoiDelta)) && 11781 (x > (int) (roi_info.x-RoiDelta)) && 11782 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11783 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11784 { 11785 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11786 state|=UpdateConfigurationState; 11787 break; 11788 } 11789 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11790 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11791 (y < (int) (roi_info.y+RoiDelta)) && 11792 (y > (int) (roi_info.y-RoiDelta))) 11793 { 11794 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11795 state|=UpdateConfigurationState; 11796 break; 11797 } 11798 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11799 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11800 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11801 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11802 { 11803 state|=UpdateConfigurationState; 11804 break; 11805 } 11806 } 11807 case ButtonRelease: 11808 { 11809 if (event.xbutton.window == windows->pan.id) 11810 if ((highlight_info.x != crop_info.x-windows->image.x) || 11811 (highlight_info.y != crop_info.y-windows->image.y)) 11812 XHighlightRectangle(display,windows->image.id, 11813 windows->image.highlight_context,&highlight_info); 11814 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11815 event.xbutton.time); 11816 break; 11817 } 11818 case Expose: 11819 { 11820 if (event.xexpose.window == windows->image.id) 11821 if (event.xexpose.count == 0) 11822 { 11823 event.xexpose.x=(int) highlight_info.x; 11824 event.xexpose.y=(int) highlight_info.y; 11825 event.xexpose.width=(int) highlight_info.width; 11826 event.xexpose.height=(int) highlight_info.height; 11827 XRefreshWindow(display,&windows->image,&event); 11828 } 11829 if (event.xexpose.window == windows->info.id) 11830 if (event.xexpose.count == 0) 11831 XInfoWidget(display,windows,text); 11832 break; 11833 } 11834 case KeyPress: 11835 { 11836 KeySym 11837 key_symbol; 11838 11839 if (event.xkey.window != windows->image.id) 11840 break; 11841 /* 11842 Respond to a user key press. 11843 */ 11844 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11845 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11846 switch ((int) key_symbol) 11847 { 11848 case XK_Shift_L: 11849 case XK_Shift_R: 11850 break; 11851 case XK_Escape: 11852 case XK_F20: 11853 state|=EscapeState; 11854 case XK_Return: 11855 { 11856 state|=ExitState; 11857 break; 11858 } 11859 case XK_Home: 11860 case XK_KP_Home: 11861 { 11862 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11863 roi_info.y=(ssize_t) (windows->image.height/2L- 11864 roi_info.height/2L); 11865 break; 11866 } 11867 case XK_Left: 11868 case XK_KP_Left: 11869 { 11870 roi_info.x--; 11871 break; 11872 } 11873 case XK_Up: 11874 case XK_KP_Up: 11875 case XK_Next: 11876 { 11877 roi_info.y--; 11878 break; 11879 } 11880 case XK_Right: 11881 case XK_KP_Right: 11882 { 11883 roi_info.x++; 11884 break; 11885 } 11886 case XK_Prior: 11887 case XK_Down: 11888 case XK_KP_Down: 11889 { 11890 roi_info.y++; 11891 break; 11892 } 11893 case XK_F1: 11894 case XK_Help: 11895 { 11896 (void) XSetFunction(display,windows->image.highlight_context, 11897 GXcopy); 11898 XTextViewWidget(display,resource_info,windows,MagickFalse, 11899 "Help Viewer - Region of Interest",ImageROIHelp); 11900 (void) XSetFunction(display,windows->image.highlight_context, 11901 GXinvert); 11902 break; 11903 } 11904 default: 11905 { 11906 command_type=XImageWindowCommand(display,resource_info,windows, 11907 event.xkey.state,key_symbol,image,exception); 11908 if (command_type != NullCommand) 11909 state|=UpdateRegionState; 11910 break; 11911 } 11912 } 11913 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11914 event.xkey.time); 11915 break; 11916 } 11917 case KeyRelease: 11918 break; 11919 case MotionNotify: 11920 { 11921 if (event.xbutton.window != windows->image.id) 11922 break; 11923 /* 11924 Map and unmap Info widget as text cursor crosses its boundaries. 11925 */ 11926 x=event.xmotion.x; 11927 y=event.xmotion.y; 11928 if (windows->info.mapped != MagickFalse) 11929 { 11930 if ((x < (int) (windows->info.x+windows->info.width)) && 11931 (y < (int) (windows->info.y+windows->info.height))) 11932 (void) XWithdrawWindow(display,windows->info.id, 11933 windows->info.screen); 11934 } 11935 else 11936 if ((x > (int) (windows->info.x+windows->info.width)) || 11937 (y > (int) (windows->info.y+windows->info.height))) 11938 (void) XMapWindow(display,windows->info.id); 11939 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11940 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11941 break; 11942 } 11943 case SelectionRequest: 11944 { 11945 XSelectionEvent 11946 notify; 11947 11948 XSelectionRequestEvent 11949 *request; 11950 11951 /* 11952 Set primary selection. 11953 */ 11954 (void) FormatLocaleString(text,MaxTextExtent, 11955 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11956 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11957 request=(&(event.xselectionrequest)); 11958 (void) XChangeProperty(request->display,request->requestor, 11959 request->property,request->target,8,PropModeReplace, 11960 (unsigned char *) text,(int) strlen(text)); 11961 notify.type=SelectionNotify; 11962 notify.display=request->display; 11963 notify.requestor=request->requestor; 11964 notify.selection=request->selection; 11965 notify.target=request->target; 11966 notify.time=request->time; 11967 if (request->property == None) 11968 notify.property=request->target; 11969 else 11970 notify.property=request->property; 11971 (void) XSendEvent(request->display,request->requestor,False,0, 11972 (XEvent *) ¬ify); 11973 } 11974 default: 11975 break; 11976 } 11977 if ((state & UpdateConfigurationState) != 0) 11978 { 11979 (void) XPutBackEvent(display,&event); 11980 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11981 break; 11982 } 11983 } while ((state & ExitState) == 0); 11984 } while ((state & ExitState) == 0); 11985 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11986 XSetCursorState(display,windows,MagickFalse); 11987 if ((state & EscapeState) != 0) 11988 return(MagickTrue); 11989 return(MagickTrue); 11990} 11991 11992/* 11993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11994% % 11995% % 11996% % 11997+ X R o t a t e I m a g e % 11998% % 11999% % 12000% % 12001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12002% 12003% XRotateImage() rotates the X image. If the degrees parameter if zero, the 12004% rotation angle is computed from the slope of a line drawn by the user. 12005% 12006% The format of the XRotateImage method is: 12007% 12008% MagickBooleanType XRotateImage(Display *display, 12009% XResourceInfo *resource_info,XWindows *windows,double degrees, 12010% Image **image,ExceptionInfo *exception) 12011% 12012% A description of each parameter follows: 12013% 12014% o display: Specifies a connection to an X server; returned from 12015% XOpenDisplay. 12016% 12017% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12018% 12019% o windows: Specifies a pointer to a XWindows structure. 12020% 12021% o degrees: Specifies the number of degrees to rotate the image. 12022% 12023% o image: the image. 12024% 12025% o exception: return any errors or warnings in this structure. 12026% 12027*/ 12028static MagickBooleanType XRotateImage(Display *display, 12029 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12030 ExceptionInfo *exception) 12031{ 12032 static const char 12033 *RotateMenu[] = 12034 { 12035 "Pixel Color", 12036 "Direction", 12037 "Help", 12038 "Dismiss", 12039 (char *) NULL 12040 }; 12041 12042 static ModeType 12043 direction = HorizontalRotateCommand; 12044 12045 static const ModeType 12046 DirectionCommands[] = 12047 { 12048 HorizontalRotateCommand, 12049 VerticalRotateCommand 12050 }, 12051 RotateCommands[] = 12052 { 12053 RotateColorCommand, 12054 RotateDirectionCommand, 12055 RotateHelpCommand, 12056 RotateDismissCommand 12057 }; 12058 12059 static unsigned int 12060 pen_id = 0; 12061 12062 char 12063 command[MaxTextExtent], 12064 text[MaxTextExtent]; 12065 12066 Image 12067 *rotate_image; 12068 12069 int 12070 id, 12071 x, 12072 y; 12073 12074 MagickRealType 12075 normalized_degrees; 12076 12077 register int 12078 i; 12079 12080 unsigned int 12081 height, 12082 rotations, 12083 width; 12084 12085 if (degrees == 0.0) 12086 { 12087 unsigned int 12088 distance; 12089 12090 size_t 12091 state; 12092 12093 XEvent 12094 event; 12095 12096 XSegment 12097 rotate_info; 12098 12099 /* 12100 Map Command widget. 12101 */ 12102 (void) CloneString(&windows->command.name,"Rotate"); 12103 windows->command.data=2; 12104 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12105 (void) XMapRaised(display,windows->command.id); 12106 XClientMessage(display,windows->image.id,windows->im_protocols, 12107 windows->im_update_widget,CurrentTime); 12108 /* 12109 Wait for first button press. 12110 */ 12111 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12112 XQueryPosition(display,windows->image.id,&x,&y); 12113 rotate_info.x1=x; 12114 rotate_info.y1=y; 12115 rotate_info.x2=x; 12116 rotate_info.y2=y; 12117 state=DefaultState; 12118 do 12119 { 12120 XHighlightLine(display,windows->image.id, 12121 windows->image.highlight_context,&rotate_info); 12122 /* 12123 Wait for next event. 12124 */ 12125 XScreenEvent(display,windows,&event,exception); 12126 XHighlightLine(display,windows->image.id, 12127 windows->image.highlight_context,&rotate_info); 12128 if (event.xany.window == windows->command.id) 12129 { 12130 /* 12131 Select a command from the Command widget. 12132 */ 12133 id=XCommandWidget(display,windows,RotateMenu,&event); 12134 if (id < 0) 12135 continue; 12136 (void) XSetFunction(display,windows->image.highlight_context, 12137 GXcopy); 12138 switch (RotateCommands[id]) 12139 { 12140 case RotateColorCommand: 12141 { 12142 const char 12143 *ColorMenu[MaxNumberPens]; 12144 12145 int 12146 pen_number; 12147 12148 XColor 12149 color; 12150 12151 /* 12152 Initialize menu selections. 12153 */ 12154 for (i=0; i < (int) (MaxNumberPens-2); i++) 12155 ColorMenu[i]=resource_info->pen_colors[i]; 12156 ColorMenu[MaxNumberPens-2]="Browser..."; 12157 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12158 /* 12159 Select a pen color from the pop-up menu. 12160 */ 12161 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12162 (const char **) ColorMenu,command); 12163 if (pen_number < 0) 12164 break; 12165 if (pen_number == (MaxNumberPens-2)) 12166 { 12167 static char 12168 color_name[MaxTextExtent] = "gray"; 12169 12170 /* 12171 Select a pen color from a dialog. 12172 */ 12173 resource_info->pen_colors[pen_number]=color_name; 12174 XColorBrowserWidget(display,windows,"Select",color_name); 12175 if (*color_name == '\0') 12176 break; 12177 } 12178 /* 12179 Set pen color. 12180 */ 12181 (void) XParseColor(display,windows->map_info->colormap, 12182 resource_info->pen_colors[pen_number],&color); 12183 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12184 (unsigned int) MaxColors,&color); 12185 windows->pixel_info->pen_colors[pen_number]=color; 12186 pen_id=(unsigned int) pen_number; 12187 break; 12188 } 12189 case RotateDirectionCommand: 12190 { 12191 static const char 12192 *Directions[] = 12193 { 12194 "horizontal", 12195 "vertical", 12196 (char *) NULL, 12197 }; 12198 12199 /* 12200 Select a command from the pop-up menu. 12201 */ 12202 id=XMenuWidget(display,windows,RotateMenu[id], 12203 Directions,command); 12204 if (id >= 0) 12205 direction=DirectionCommands[id]; 12206 break; 12207 } 12208 case RotateHelpCommand: 12209 { 12210 XTextViewWidget(display,resource_info,windows,MagickFalse, 12211 "Help Viewer - Image Rotation",ImageRotateHelp); 12212 break; 12213 } 12214 case RotateDismissCommand: 12215 { 12216 /* 12217 Prematurely exit. 12218 */ 12219 state|=EscapeState; 12220 state|=ExitState; 12221 break; 12222 } 12223 default: 12224 break; 12225 } 12226 (void) XSetFunction(display,windows->image.highlight_context, 12227 GXinvert); 12228 continue; 12229 } 12230 switch (event.type) 12231 { 12232 case ButtonPress: 12233 { 12234 if (event.xbutton.button != Button1) 12235 break; 12236 if (event.xbutton.window != windows->image.id) 12237 break; 12238 /* 12239 exit loop. 12240 */ 12241 (void) XSetFunction(display,windows->image.highlight_context, 12242 GXcopy); 12243 rotate_info.x1=event.xbutton.x; 12244 rotate_info.y1=event.xbutton.y; 12245 state|=ExitState; 12246 break; 12247 } 12248 case ButtonRelease: 12249 break; 12250 case Expose: 12251 break; 12252 case KeyPress: 12253 { 12254 char 12255 command[MaxTextExtent]; 12256 12257 KeySym 12258 key_symbol; 12259 12260 if (event.xkey.window != windows->image.id) 12261 break; 12262 /* 12263 Respond to a user key press. 12264 */ 12265 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12266 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12267 switch ((int) key_symbol) 12268 { 12269 case XK_Escape: 12270 case XK_F20: 12271 { 12272 /* 12273 Prematurely exit. 12274 */ 12275 state|=EscapeState; 12276 state|=ExitState; 12277 break; 12278 } 12279 case XK_F1: 12280 case XK_Help: 12281 { 12282 (void) XSetFunction(display,windows->image.highlight_context, 12283 GXcopy); 12284 XTextViewWidget(display,resource_info,windows,MagickFalse, 12285 "Help Viewer - Image Rotation",ImageRotateHelp); 12286 (void) XSetFunction(display,windows->image.highlight_context, 12287 GXinvert); 12288 break; 12289 } 12290 default: 12291 { 12292 (void) XBell(display,0); 12293 break; 12294 } 12295 } 12296 break; 12297 } 12298 case MotionNotify: 12299 { 12300 rotate_info.x1=event.xmotion.x; 12301 rotate_info.y1=event.xmotion.y; 12302 } 12303 } 12304 rotate_info.x2=rotate_info.x1; 12305 rotate_info.y2=rotate_info.y1; 12306 if (direction == HorizontalRotateCommand) 12307 rotate_info.x2+=32; 12308 else 12309 rotate_info.y2-=32; 12310 } while ((state & ExitState) == 0); 12311 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12312 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12313 if ((state & EscapeState) != 0) 12314 return(MagickTrue); 12315 /* 12316 Draw line as pointer moves until the mouse button is released. 12317 */ 12318 distance=0; 12319 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12320 state=DefaultState; 12321 do 12322 { 12323 if (distance > 9) 12324 { 12325 /* 12326 Display info and draw rotation line. 12327 */ 12328 if (windows->info.mapped == MagickFalse) 12329 (void) XMapWindow(display,windows->info.id); 12330 (void) FormatLocaleString(text,MaxTextExtent," %g", 12331 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12332 XInfoWidget(display,windows,text); 12333 XHighlightLine(display,windows->image.id, 12334 windows->image.highlight_context,&rotate_info); 12335 } 12336 else 12337 if (windows->info.mapped != MagickFalse) 12338 (void) XWithdrawWindow(display,windows->info.id, 12339 windows->info.screen); 12340 /* 12341 Wait for next event. 12342 */ 12343 XScreenEvent(display,windows,&event,exception); 12344 if (distance > 9) 12345 XHighlightLine(display,windows->image.id, 12346 windows->image.highlight_context,&rotate_info); 12347 switch (event.type) 12348 { 12349 case ButtonPress: 12350 break; 12351 case ButtonRelease: 12352 { 12353 /* 12354 User has committed to rotation line. 12355 */ 12356 rotate_info.x2=event.xbutton.x; 12357 rotate_info.y2=event.xbutton.y; 12358 state|=ExitState; 12359 break; 12360 } 12361 case Expose: 12362 break; 12363 case MotionNotify: 12364 { 12365 rotate_info.x2=event.xmotion.x; 12366 rotate_info.y2=event.xmotion.y; 12367 } 12368 default: 12369 break; 12370 } 12371 /* 12372 Check boundary conditions. 12373 */ 12374 if (rotate_info.x2 < 0) 12375 rotate_info.x2=0; 12376 else 12377 if (rotate_info.x2 > (int) windows->image.width) 12378 rotate_info.x2=(short) windows->image.width; 12379 if (rotate_info.y2 < 0) 12380 rotate_info.y2=0; 12381 else 12382 if (rotate_info.y2 > (int) windows->image.height) 12383 rotate_info.y2=(short) windows->image.height; 12384 /* 12385 Compute rotation angle from the slope of the line. 12386 */ 12387 degrees=0.0; 12388 distance=(unsigned int) 12389 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12390 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12391 if (distance > 9) 12392 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12393 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12394 } while ((state & ExitState) == 0); 12395 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12396 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12397 if (distance <= 9) 12398 return(MagickTrue); 12399 } 12400 if (direction == VerticalRotateCommand) 12401 degrees-=90.0; 12402 if (degrees == 0.0) 12403 return(MagickTrue); 12404 /* 12405 Rotate image. 12406 */ 12407 normalized_degrees=degrees; 12408 while (normalized_degrees < -45.0) 12409 normalized_degrees+=360.0; 12410 for (rotations=0; normalized_degrees > 45.0; rotations++) 12411 normalized_degrees-=90.0; 12412 if (normalized_degrees != 0.0) 12413 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12414 exception); 12415 XSetCursorState(display,windows,MagickTrue); 12416 XCheckRefreshWindows(display,windows); 12417 (*image)->background_color.red=ScaleShortToQuantum( 12418 windows->pixel_info->pen_colors[pen_id].red); 12419 (*image)->background_color.green=ScaleShortToQuantum( 12420 windows->pixel_info->pen_colors[pen_id].green); 12421 (*image)->background_color.blue=ScaleShortToQuantum( 12422 windows->pixel_info->pen_colors[pen_id].blue); 12423 rotate_image=RotateImage(*image,degrees,exception); 12424 XSetCursorState(display,windows,MagickFalse); 12425 if (rotate_image == (Image *) NULL) 12426 return(MagickFalse); 12427 *image=DestroyImage(*image); 12428 *image=rotate_image; 12429 if (windows->image.crop_geometry != (char *) NULL) 12430 { 12431 /* 12432 Rotate crop geometry. 12433 */ 12434 width=(unsigned int) (*image)->columns; 12435 height=(unsigned int) (*image)->rows; 12436 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12437 switch (rotations % 4) 12438 { 12439 default: 12440 case 0: 12441 break; 12442 case 1: 12443 { 12444 /* 12445 Rotate 90 degrees. 12446 */ 12447 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12448 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12449 (int) height-y,x); 12450 break; 12451 } 12452 case 2: 12453 { 12454 /* 12455 Rotate 180 degrees. 12456 */ 12457 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12458 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12459 break; 12460 } 12461 case 3: 12462 { 12463 /* 12464 Rotate 270 degrees. 12465 */ 12466 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12467 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12468 break; 12469 } 12470 } 12471 } 12472 if (windows->image.orphan != MagickFalse) 12473 return(MagickTrue); 12474 if (normalized_degrees != 0.0) 12475 { 12476 /* 12477 Update image colormap. 12478 */ 12479 windows->image.window_changes.width=(int) (*image)->columns; 12480 windows->image.window_changes.height=(int) (*image)->rows; 12481 if (windows->image.crop_geometry != (char *) NULL) 12482 { 12483 /* 12484 Obtain dimensions of image from crop geometry. 12485 */ 12486 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12487 &width,&height); 12488 windows->image.window_changes.width=(int) width; 12489 windows->image.window_changes.height=(int) height; 12490 } 12491 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12492 } 12493 else 12494 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12495 { 12496 windows->image.window_changes.width=windows->image.ximage->height; 12497 windows->image.window_changes.height=windows->image.ximage->width; 12498 } 12499 /* 12500 Update image configuration. 12501 */ 12502 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12503 return(MagickTrue); 12504} 12505 12506/* 12507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12508% % 12509% % 12510% % 12511+ X S a v e I m a g e % 12512% % 12513% % 12514% % 12515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12516% 12517% XSaveImage() saves an image to a file. 12518% 12519% The format of the XSaveImage method is: 12520% 12521% MagickBooleanType XSaveImage(Display *display, 12522% XResourceInfo *resource_info,XWindows *windows,Image *image, 12523% ExceptionInfo *exception) 12524% 12525% A description of each parameter follows: 12526% 12527% o display: Specifies a connection to an X server; returned from 12528% XOpenDisplay. 12529% 12530% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12531% 12532% o windows: Specifies a pointer to a XWindows structure. 12533% 12534% o image: the image. 12535% 12536% o exception: return any errors or warnings in this structure. 12537% 12538*/ 12539static MagickBooleanType XSaveImage(Display *display, 12540 XResourceInfo *resource_info,XWindows *windows,Image *image, 12541 ExceptionInfo *exception) 12542{ 12543 char 12544 filename[MaxTextExtent], 12545 geometry[MaxTextExtent]; 12546 12547 Image 12548 *save_image; 12549 12550 ImageInfo 12551 *image_info; 12552 12553 MagickStatusType 12554 status; 12555 12556 /* 12557 Request file name from user. 12558 */ 12559 if (resource_info->write_filename != (char *) NULL) 12560 (void) CopyMagickString(filename,resource_info->write_filename, 12561 MaxTextExtent); 12562 else 12563 { 12564 char 12565 path[MaxTextExtent]; 12566 12567 int 12568 status; 12569 12570 GetPathComponent(image->filename,HeadPath,path); 12571 GetPathComponent(image->filename,TailPath,filename); 12572 if (*path != '\0') 12573 { 12574 status=chdir(path); 12575 if (status == -1) 12576 (void) ThrowMagickException(exception,GetMagickModule(), 12577 FileOpenError,"UnableToOpenFile","%s",path); 12578 } 12579 } 12580 XFileBrowserWidget(display,windows,"Save",filename); 12581 if (*filename == '\0') 12582 return(MagickTrue); 12583 if (IsPathAccessible(filename) != MagickFalse) 12584 { 12585 int 12586 status; 12587 12588 /* 12589 File exists-- seek user's permission before overwriting. 12590 */ 12591 status=XConfirmWidget(display,windows,"Overwrite",filename); 12592 if (status <= 0) 12593 return(MagickTrue); 12594 } 12595 image_info=CloneImageInfo(resource_info->image_info); 12596 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12597 (void) SetImageInfo(image_info,1,exception); 12598 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12599 (LocaleCompare(image_info->magick,"JPG") == 0)) 12600 { 12601 char 12602 quality[MaxTextExtent]; 12603 12604 int 12605 status; 12606 12607 /* 12608 Request JPEG quality from user. 12609 */ 12610 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12611 image->quality); 12612 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12613 quality); 12614 if (*quality == '\0') 12615 return(MagickTrue); 12616 image->quality=StringToUnsignedLong(quality); 12617 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12618 } 12619 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12620 (LocaleCompare(image_info->magick,"PDF") == 0) || 12621 (LocaleCompare(image_info->magick,"PS") == 0) || 12622 (LocaleCompare(image_info->magick,"PS2") == 0)) 12623 { 12624 char 12625 geometry[MaxTextExtent]; 12626 12627 /* 12628 Request page geometry from user. 12629 */ 12630 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12631 if (LocaleCompare(image_info->magick,"PDF") == 0) 12632 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12633 if (image_info->page != (char *) NULL) 12634 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12635 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12636 "Select page geometry:",geometry); 12637 if (*geometry != '\0') 12638 image_info->page=GetPageGeometry(geometry); 12639 } 12640 /* 12641 Apply image transforms. 12642 */ 12643 XSetCursorState(display,windows,MagickTrue); 12644 XCheckRefreshWindows(display,windows); 12645 save_image=CloneImage(image,0,0,MagickTrue,exception); 12646 if (save_image == (Image *) NULL) 12647 return(MagickFalse); 12648 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12649 windows->image.ximage->width,windows->image.ximage->height); 12650 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12651 exception); 12652 /* 12653 Write image. 12654 */ 12655 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12656 status=WriteImage(image_info,save_image,exception); 12657 if (status != MagickFalse) 12658 image->taint=MagickFalse; 12659 save_image=DestroyImage(save_image); 12660 image_info=DestroyImageInfo(image_info); 12661 XSetCursorState(display,windows,MagickFalse); 12662 return(status != 0 ? MagickTrue : MagickFalse); 12663} 12664 12665/* 12666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12667% % 12668% % 12669% % 12670+ X S c r e e n E v e n t % 12671% % 12672% % 12673% % 12674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12675% 12676% XScreenEvent() handles global events associated with the Pan and Magnify 12677% windows. 12678% 12679% The format of the XScreenEvent function is: 12680% 12681% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12682% ExceptionInfo *exception) 12683% 12684% A description of each parameter follows: 12685% 12686% o display: Specifies a pointer to the Display structure; returned from 12687% XOpenDisplay. 12688% 12689% o windows: Specifies a pointer to a XWindows structure. 12690% 12691% o event: Specifies a pointer to a X11 XEvent structure. 12692% 12693% o exception: return any errors or warnings in this structure. 12694% 12695*/ 12696 12697#if defined(__cplusplus) || defined(c_plusplus) 12698extern "C" { 12699#endif 12700 12701static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12702{ 12703 register XWindows 12704 *windows; 12705 12706 windows=(XWindows *) data; 12707 if ((event->type == ClientMessage) && 12708 (event->xclient.window == windows->image.id)) 12709 return(MagickFalse); 12710 return(MagickTrue); 12711} 12712 12713#if defined(__cplusplus) || defined(c_plusplus) 12714} 12715#endif 12716 12717static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12718 ExceptionInfo *exception) 12719{ 12720 register int 12721 x, 12722 y; 12723 12724 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12725 if (event->xany.window == windows->command.id) 12726 return; 12727 switch (event->type) 12728 { 12729 case ButtonPress: 12730 case ButtonRelease: 12731 { 12732 if ((event->xbutton.button == Button3) && 12733 (event->xbutton.state & Mod1Mask)) 12734 { 12735 /* 12736 Convert Alt-Button3 to Button2. 12737 */ 12738 event->xbutton.button=Button2; 12739 event->xbutton.state&=(~Mod1Mask); 12740 } 12741 if (event->xbutton.window == windows->backdrop.id) 12742 { 12743 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12744 event->xbutton.time); 12745 break; 12746 } 12747 if (event->xbutton.window == windows->pan.id) 12748 { 12749 XPanImage(display,windows,event,exception); 12750 break; 12751 } 12752 if (event->xbutton.window == windows->image.id) 12753 if (event->xbutton.button == Button2) 12754 { 12755 /* 12756 Update magnified image. 12757 */ 12758 x=event->xbutton.x; 12759 y=event->xbutton.y; 12760 if (x < 0) 12761 x=0; 12762 else 12763 if (x >= (int) windows->image.width) 12764 x=(int) (windows->image.width-1); 12765 windows->magnify.x=(int) windows->image.x+x; 12766 if (y < 0) 12767 y=0; 12768 else 12769 if (y >= (int) windows->image.height) 12770 y=(int) (windows->image.height-1); 12771 windows->magnify.y=windows->image.y+y; 12772 if (windows->magnify.mapped == MagickFalse) 12773 (void) XMapRaised(display,windows->magnify.id); 12774 XMakeMagnifyImage(display,windows,exception); 12775 if (event->type == ButtonRelease) 12776 (void) XWithdrawWindow(display,windows->info.id, 12777 windows->info.screen); 12778 break; 12779 } 12780 break; 12781 } 12782 case ClientMessage: 12783 { 12784 /* 12785 If client window delete message, exit. 12786 */ 12787 if (event->xclient.message_type != windows->wm_protocols) 12788 break; 12789 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12790 break; 12791 if (event->xclient.window == windows->magnify.id) 12792 { 12793 (void) XWithdrawWindow(display,windows->magnify.id, 12794 windows->magnify.screen); 12795 break; 12796 } 12797 break; 12798 } 12799 case ConfigureNotify: 12800 { 12801 if (event->xconfigure.window == windows->magnify.id) 12802 { 12803 unsigned int 12804 magnify; 12805 12806 /* 12807 Magnify window has a new configuration. 12808 */ 12809 windows->magnify.width=(unsigned int) event->xconfigure.width; 12810 windows->magnify.height=(unsigned int) event->xconfigure.height; 12811 if (windows->magnify.mapped == MagickFalse) 12812 break; 12813 magnify=1; 12814 while ((int) magnify <= event->xconfigure.width) 12815 magnify<<=1; 12816 while ((int) magnify <= event->xconfigure.height) 12817 magnify<<=1; 12818 magnify>>=1; 12819 if (((int) magnify != event->xconfigure.width) || 12820 ((int) magnify != event->xconfigure.height)) 12821 { 12822 XWindowChanges 12823 window_changes; 12824 12825 window_changes.width=(int) magnify; 12826 window_changes.height=(int) magnify; 12827 (void) XReconfigureWMWindow(display,windows->magnify.id, 12828 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12829 &window_changes); 12830 break; 12831 } 12832 XMakeMagnifyImage(display,windows,exception); 12833 break; 12834 } 12835 break; 12836 } 12837 case Expose: 12838 { 12839 if (event->xexpose.window == windows->image.id) 12840 { 12841 XRefreshWindow(display,&windows->image,event); 12842 break; 12843 } 12844 if (event->xexpose.window == windows->pan.id) 12845 if (event->xexpose.count == 0) 12846 { 12847 XDrawPanRectangle(display,windows); 12848 break; 12849 } 12850 if (event->xexpose.window == windows->magnify.id) 12851 if (event->xexpose.count == 0) 12852 { 12853 XMakeMagnifyImage(display,windows,exception); 12854 break; 12855 } 12856 break; 12857 } 12858 case KeyPress: 12859 { 12860 char 12861 command[MaxTextExtent]; 12862 12863 KeySym 12864 key_symbol; 12865 12866 if (event->xkey.window != windows->magnify.id) 12867 break; 12868 /* 12869 Respond to a user key press. 12870 */ 12871 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12872 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12873 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12874 exception); 12875 break; 12876 } 12877 case MapNotify: 12878 { 12879 if (event->xmap.window == windows->magnify.id) 12880 { 12881 windows->magnify.mapped=MagickTrue; 12882 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12883 break; 12884 } 12885 if (event->xmap.window == windows->info.id) 12886 { 12887 windows->info.mapped=MagickTrue; 12888 break; 12889 } 12890 break; 12891 } 12892 case MotionNotify: 12893 { 12894 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12895 if (event->xmotion.window == windows->image.id) 12896 if (windows->magnify.mapped != MagickFalse) 12897 { 12898 /* 12899 Update magnified image. 12900 */ 12901 x=event->xmotion.x; 12902 y=event->xmotion.y; 12903 if (x < 0) 12904 x=0; 12905 else 12906 if (x >= (int) windows->image.width) 12907 x=(int) (windows->image.width-1); 12908 windows->magnify.x=(int) windows->image.x+x; 12909 if (y < 0) 12910 y=0; 12911 else 12912 if (y >= (int) windows->image.height) 12913 y=(int) (windows->image.height-1); 12914 windows->magnify.y=windows->image.y+y; 12915 XMakeMagnifyImage(display,windows,exception); 12916 } 12917 break; 12918 } 12919 case UnmapNotify: 12920 { 12921 if (event->xunmap.window == windows->magnify.id) 12922 { 12923 windows->magnify.mapped=MagickFalse; 12924 break; 12925 } 12926 if (event->xunmap.window == windows->info.id) 12927 { 12928 windows->info.mapped=MagickFalse; 12929 break; 12930 } 12931 break; 12932 } 12933 default: 12934 break; 12935 } 12936} 12937 12938/* 12939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12940% % 12941% % 12942% % 12943+ X S e t C r o p G e o m e t r y % 12944% % 12945% % 12946% % 12947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12948% 12949% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12950% and translates it to a cropping geometry relative to the image. 12951% 12952% The format of the XSetCropGeometry method is: 12953% 12954% void XSetCropGeometry(Display *display,XWindows *windows, 12955% RectangleInfo *crop_info,Image *image) 12956% 12957% A description of each parameter follows: 12958% 12959% o display: Specifies a connection to an X server; returned from 12960% XOpenDisplay. 12961% 12962% o windows: Specifies a pointer to a XWindows structure. 12963% 12964% o crop_info: A pointer to a RectangleInfo that defines a region of the 12965% Image window to crop. 12966% 12967% o image: the image. 12968% 12969*/ 12970static void XSetCropGeometry(Display *display,XWindows *windows, 12971 RectangleInfo *crop_info,Image *image) 12972{ 12973 char 12974 text[MaxTextExtent]; 12975 12976 int 12977 x, 12978 y; 12979 12980 MagickRealType 12981 scale_factor; 12982 12983 unsigned int 12984 height, 12985 width; 12986 12987 if (windows->info.mapped != MagickFalse) 12988 { 12989 /* 12990 Display info on cropping rectangle. 12991 */ 12992 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12993 (double) crop_info->width,(double) crop_info->height,(double) 12994 crop_info->x,(double) crop_info->y); 12995 XInfoWidget(display,windows,text); 12996 } 12997 /* 12998 Cropping geometry is relative to any previous crop geometry. 12999 */ 13000 x=0; 13001 y=0; 13002 width=(unsigned int) image->columns; 13003 height=(unsigned int) image->rows; 13004 if (windows->image.crop_geometry != (char *) NULL) 13005 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13006 else 13007 windows->image.crop_geometry=AcquireString((char *) NULL); 13008 /* 13009 Define the crop geometry string from the cropping rectangle. 13010 */ 13011 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13012 if (crop_info->x > 0) 13013 x+=(int) (scale_factor*crop_info->x+0.5); 13014 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13015 if (width == 0) 13016 width=1; 13017 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13018 if (crop_info->y > 0) 13019 y+=(int) (scale_factor*crop_info->y+0.5); 13020 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13021 if (height == 0) 13022 height=1; 13023 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13024 "%ux%u%+d%+d",width,height,x,y); 13025} 13026 13027/* 13028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13029% % 13030% % 13031% % 13032+ X T i l e I m a g e % 13033% % 13034% % 13035% % 13036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13037% 13038% XTileImage() loads or deletes a selected tile from a visual image directory. 13039% The load or delete command is chosen from a menu. 13040% 13041% The format of the XTileImage method is: 13042% 13043% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13044% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13045% 13046% A description of each parameter follows: 13047% 13048% o tile_image: XTileImage reads or deletes the tile image 13049% and returns it. A null image is returned if an error occurs. 13050% 13051% o display: Specifies a connection to an X server; returned from 13052% XOpenDisplay. 13053% 13054% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13055% 13056% o windows: Specifies a pointer to a XWindows structure. 13057% 13058% o image: the image; returned from ReadImage. 13059% 13060% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13061% the entire image is refreshed. 13062% 13063% o exception: return any errors or warnings in this structure. 13064% 13065*/ 13066static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13067 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13068{ 13069 static const char 13070 *VerbMenu[] = 13071 { 13072 "Load", 13073 "Next", 13074 "Former", 13075 "Delete", 13076 "Update", 13077 (char *) NULL, 13078 }; 13079 13080 static const ModeType 13081 TileCommands[] = 13082 { 13083 TileLoadCommand, 13084 TileNextCommand, 13085 TileFormerCommand, 13086 TileDeleteCommand, 13087 TileUpdateCommand 13088 }; 13089 13090 char 13091 command[MaxTextExtent], 13092 filename[MaxTextExtent]; 13093 13094 Image 13095 *tile_image; 13096 13097 int 13098 id, 13099 status, 13100 tile, 13101 x, 13102 y; 13103 13104 MagickRealType 13105 scale_factor; 13106 13107 register char 13108 *p, 13109 *q; 13110 13111 register int 13112 i; 13113 13114 unsigned int 13115 height, 13116 width; 13117 13118 /* 13119 Tile image is relative to montage image configuration. 13120 */ 13121 x=0; 13122 y=0; 13123 width=(unsigned int) image->columns; 13124 height=(unsigned int) image->rows; 13125 if (windows->image.crop_geometry != (char *) NULL) 13126 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13127 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13128 event->xbutton.x+=windows->image.x; 13129 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13130 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13131 event->xbutton.y+=windows->image.y; 13132 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13133 /* 13134 Determine size and location of each tile in the visual image directory. 13135 */ 13136 width=(unsigned int) image->columns; 13137 height=(unsigned int) image->rows; 13138 x=0; 13139 y=0; 13140 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13141 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13142 (event->xbutton.x-x)/width; 13143 if (tile < 0) 13144 { 13145 /* 13146 Button press is outside any tile. 13147 */ 13148 (void) XBell(display,0); 13149 return((Image *) NULL); 13150 } 13151 /* 13152 Determine file name from the tile directory. 13153 */ 13154 p=image->directory; 13155 for (i=tile; (i != 0) && (*p != '\0'); ) 13156 { 13157 if (*p == '\n') 13158 i--; 13159 p++; 13160 } 13161 if (*p == '\0') 13162 { 13163 /* 13164 Button press is outside any tile. 13165 */ 13166 (void) XBell(display,0); 13167 return((Image *) NULL); 13168 } 13169 /* 13170 Select a command from the pop-up menu. 13171 */ 13172 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13173 if (id < 0) 13174 return((Image *) NULL); 13175 q=p; 13176 while ((*q != '\n') && (*q != '\0')) 13177 q++; 13178 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13179 /* 13180 Perform command for the selected tile. 13181 */ 13182 XSetCursorState(display,windows,MagickTrue); 13183 XCheckRefreshWindows(display,windows); 13184 tile_image=NewImageList(); 13185 switch (TileCommands[id]) 13186 { 13187 case TileLoadCommand: 13188 { 13189 /* 13190 Load tile image. 13191 */ 13192 XCheckRefreshWindows(display,windows); 13193 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13194 MaxTextExtent); 13195 (void) CopyMagickString(resource_info->image_info->filename,filename, 13196 MaxTextExtent); 13197 tile_image=ReadImage(resource_info->image_info,exception); 13198 CatchException(exception); 13199 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13200 break; 13201 } 13202 case TileNextCommand: 13203 { 13204 /* 13205 Display next image. 13206 */ 13207 XClientMessage(display,windows->image.id,windows->im_protocols, 13208 windows->im_next_image,CurrentTime); 13209 break; 13210 } 13211 case TileFormerCommand: 13212 { 13213 /* 13214 Display former image. 13215 */ 13216 XClientMessage(display,windows->image.id,windows->im_protocols, 13217 windows->im_former_image,CurrentTime); 13218 break; 13219 } 13220 case TileDeleteCommand: 13221 { 13222 /* 13223 Delete tile image. 13224 */ 13225 if (IsPathAccessible(filename) == MagickFalse) 13226 { 13227 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13228 break; 13229 } 13230 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13231 if (status <= 0) 13232 break; 13233 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13234 if (status != MagickFalse) 13235 { 13236 XNoticeWidget(display,windows,"Unable to delete image file:", 13237 filename); 13238 break; 13239 } 13240 } 13241 case TileUpdateCommand: 13242 { 13243 int 13244 x_offset, 13245 y_offset; 13246 13247 PixelInfo 13248 pixel; 13249 13250 Quantum 13251 virtual_pixel[CompositePixelChannel]; 13252 13253 register int 13254 j; 13255 13256 register Quantum 13257 *s; 13258 13259 /* 13260 Ensure all the images exist. 13261 */ 13262 tile=0; 13263 GetPixelInfo(image,&pixel); 13264 for (p=image->directory; *p != '\0'; p++) 13265 { 13266 CacheView 13267 *image_view; 13268 13269 q=p; 13270 while ((*q != '\n') && (*q != '\0')) 13271 q++; 13272 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13273 p=q; 13274 if (IsPathAccessible(filename) != MagickFalse) 13275 { 13276 tile++; 13277 continue; 13278 } 13279 /* 13280 Overwrite tile with background color. 13281 */ 13282 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13283 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13284 image_view=AcquireCacheView(image); 13285 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13286 exception); 13287 pixel.red=virtual_pixel[RedPixelChannel]; 13288 pixel.green=virtual_pixel[GreenPixelChannel]; 13289 pixel.blue=virtual_pixel[BluePixelChannel]; 13290 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13291 for (i=0; i < (int) height; i++) 13292 { 13293 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13294 y_offset+i,width,1,exception); 13295 if (s == (Quantum *) NULL) 13296 break; 13297 for (j=0; j < (int) width; j++) 13298 { 13299 SetPixelInfoPixel(image,&pixel,s); 13300 s+=GetPixelChannels(image); 13301 } 13302 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13303 break; 13304 } 13305 image_view=DestroyCacheView(image_view); 13306 tile++; 13307 } 13308 windows->image.window_changes.width=(int) image->columns; 13309 windows->image.window_changes.height=(int) image->rows; 13310 XConfigureImageColormap(display,resource_info,windows,image,exception); 13311 (void) XConfigureImage(display,resource_info,windows,image,exception); 13312 break; 13313 } 13314 default: 13315 break; 13316 } 13317 XSetCursorState(display,windows,MagickFalse); 13318 return(tile_image); 13319} 13320 13321/* 13322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13323% % 13324% % 13325% % 13326+ X T r a n s l a t e I m a g e % 13327% % 13328% % 13329% % 13330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13331% 13332% XTranslateImage() translates the image within an Image window by one pixel 13333% as specified by the key symbol. If the image has a `montage string the 13334% translation is respect to the width and height contained within the string. 13335% 13336% The format of the XTranslateImage method is: 13337% 13338% void XTranslateImage(Display *display,XWindows *windows, 13339% Image *image,const KeySym key_symbol) 13340% 13341% A description of each parameter follows: 13342% 13343% o display: Specifies a connection to an X server; returned from 13344% XOpenDisplay. 13345% 13346% o windows: Specifies a pointer to a XWindows structure. 13347% 13348% o image: the image. 13349% 13350% o key_symbol: Specifies a KeySym which indicates which side of the image 13351% to trim. 13352% 13353*/ 13354static void XTranslateImage(Display *display,XWindows *windows, 13355 Image *image,const KeySym key_symbol) 13356{ 13357 char 13358 text[MaxTextExtent]; 13359 13360 int 13361 x, 13362 y; 13363 13364 unsigned int 13365 x_offset, 13366 y_offset; 13367 13368 /* 13369 User specified a pan position offset. 13370 */ 13371 x_offset=windows->image.width; 13372 y_offset=windows->image.height; 13373 if (image->montage != (char *) NULL) 13374 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13375 switch ((int) key_symbol) 13376 { 13377 case XK_Home: 13378 case XK_KP_Home: 13379 { 13380 windows->image.x=(int) windows->image.width/2; 13381 windows->image.y=(int) windows->image.height/2; 13382 break; 13383 } 13384 case XK_Left: 13385 case XK_KP_Left: 13386 { 13387 windows->image.x-=x_offset; 13388 break; 13389 } 13390 case XK_Next: 13391 case XK_Up: 13392 case XK_KP_Up: 13393 { 13394 windows->image.y-=y_offset; 13395 break; 13396 } 13397 case XK_Right: 13398 case XK_KP_Right: 13399 { 13400 windows->image.x+=x_offset; 13401 break; 13402 } 13403 case XK_Prior: 13404 case XK_Down: 13405 case XK_KP_Down: 13406 { 13407 windows->image.y+=y_offset; 13408 break; 13409 } 13410 default: 13411 return; 13412 } 13413 /* 13414 Check boundary conditions. 13415 */ 13416 if (windows->image.x < 0) 13417 windows->image.x=0; 13418 else 13419 if ((int) (windows->image.x+windows->image.width) > 13420 windows->image.ximage->width) 13421 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13422 if (windows->image.y < 0) 13423 windows->image.y=0; 13424 else 13425 if ((int) (windows->image.y+windows->image.height) > 13426 windows->image.ximage->height) 13427 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13428 /* 13429 Refresh Image window. 13430 */ 13431 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13432 windows->image.width,windows->image.height,windows->image.x, 13433 windows->image.y); 13434 XInfoWidget(display,windows,text); 13435 XCheckRefreshWindows(display,windows); 13436 XDrawPanRectangle(display,windows); 13437 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13438 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13439} 13440 13441/* 13442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13443% % 13444% % 13445% % 13446+ X T r i m I m a g e % 13447% % 13448% % 13449% % 13450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13451% 13452% XTrimImage() trims the edges from the Image window. 13453% 13454% The format of the XTrimImage method is: 13455% 13456% MagickBooleanType XTrimImage(Display *display, 13457% XResourceInfo *resource_info,XWindows *windows,Image *image, 13458% ExceptionInfo *exception) 13459% 13460% A description of each parameter follows: 13461% 13462% o display: Specifies a connection to an X server; returned from 13463% XOpenDisplay. 13464% 13465% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13466% 13467% o windows: Specifies a pointer to a XWindows structure. 13468% 13469% o image: the image. 13470% 13471% o exception: return any errors or warnings in this structure. 13472% 13473*/ 13474static MagickBooleanType XTrimImage(Display *display, 13475 XResourceInfo *resource_info,XWindows *windows,Image *image, 13476 ExceptionInfo *exception) 13477{ 13478 RectangleInfo 13479 trim_info; 13480 13481 register int 13482 x, 13483 y; 13484 13485 size_t 13486 background, 13487 pixel; 13488 13489 /* 13490 Trim edges from image. 13491 */ 13492 XSetCursorState(display,windows,MagickTrue); 13493 XCheckRefreshWindows(display,windows); 13494 /* 13495 Crop the left edge. 13496 */ 13497 background=XGetPixel(windows->image.ximage,0,0); 13498 trim_info.width=(size_t) windows->image.ximage->width; 13499 for (x=0; x < windows->image.ximage->width; x++) 13500 { 13501 for (y=0; y < windows->image.ximage->height; y++) 13502 { 13503 pixel=XGetPixel(windows->image.ximage,x,y); 13504 if (pixel != background) 13505 break; 13506 } 13507 if (y < windows->image.ximage->height) 13508 break; 13509 } 13510 trim_info.x=(ssize_t) x; 13511 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13512 { 13513 XSetCursorState(display,windows,MagickFalse); 13514 return(MagickFalse); 13515 } 13516 /* 13517 Crop the right edge. 13518 */ 13519 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13520 for (x=windows->image.ximage->width-1; x != 0; x--) 13521 { 13522 for (y=0; y < windows->image.ximage->height; y++) 13523 { 13524 pixel=XGetPixel(windows->image.ximage,x,y); 13525 if (pixel != background) 13526 break; 13527 } 13528 if (y < windows->image.ximage->height) 13529 break; 13530 } 13531 trim_info.width=(size_t) (x-trim_info.x+1); 13532 /* 13533 Crop the top edge. 13534 */ 13535 background=XGetPixel(windows->image.ximage,0,0); 13536 trim_info.height=(size_t) windows->image.ximage->height; 13537 for (y=0; y < windows->image.ximage->height; y++) 13538 { 13539 for (x=0; x < windows->image.ximage->width; x++) 13540 { 13541 pixel=XGetPixel(windows->image.ximage,x,y); 13542 if (pixel != background) 13543 break; 13544 } 13545 if (x < windows->image.ximage->width) 13546 break; 13547 } 13548 trim_info.y=(ssize_t) y; 13549 /* 13550 Crop the bottom edge. 13551 */ 13552 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13553 for (y=windows->image.ximage->height-1; y != 0; y--) 13554 { 13555 for (x=0; x < windows->image.ximage->width; x++) 13556 { 13557 pixel=XGetPixel(windows->image.ximage,x,y); 13558 if (pixel != background) 13559 break; 13560 } 13561 if (x < windows->image.ximage->width) 13562 break; 13563 } 13564 trim_info.height=(size_t) y-trim_info.y+1; 13565 if (((unsigned int) trim_info.width != windows->image.width) || 13566 ((unsigned int) trim_info.height != windows->image.height)) 13567 { 13568 /* 13569 Reconfigure Image window as defined by the trimming rectangle. 13570 */ 13571 XSetCropGeometry(display,windows,&trim_info,image); 13572 windows->image.window_changes.width=(int) trim_info.width; 13573 windows->image.window_changes.height=(int) trim_info.height; 13574 (void) XConfigureImage(display,resource_info,windows,image,exception); 13575 } 13576 XSetCursorState(display,windows,MagickFalse); 13577 return(MagickTrue); 13578} 13579 13580/* 13581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13582% % 13583% % 13584% % 13585+ X V i s u a l D i r e c t o r y I m a g e % 13586% % 13587% % 13588% % 13589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13590% 13591% XVisualDirectoryImage() creates a Visual Image Directory. 13592% 13593% The format of the XVisualDirectoryImage method is: 13594% 13595% Image *XVisualDirectoryImage(Display *display, 13596% XResourceInfo *resource_info,XWindows *windows, 13597% ExceptionInfo *exception) 13598% 13599% A description of each parameter follows: 13600% 13601% o display: Specifies a connection to an X server; returned from 13602% XOpenDisplay. 13603% 13604% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13605% 13606% o windows: Specifies a pointer to a XWindows structure. 13607% 13608% o exception: return any errors or warnings in this structure. 13609% 13610*/ 13611static Image *XVisualDirectoryImage(Display *display, 13612 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13613{ 13614#define TileImageTag "Scale/Image" 13615#define XClientName "montage" 13616 13617 char 13618 **filelist; 13619 13620 Image 13621 *images, 13622 *montage_image, 13623 *next_image, 13624 *thumbnail_image; 13625 13626 ImageInfo 13627 *read_info; 13628 13629 int 13630 number_files; 13631 13632 MagickBooleanType 13633 backdrop; 13634 13635 MagickStatusType 13636 status; 13637 13638 MontageInfo 13639 *montage_info; 13640 13641 RectangleInfo 13642 geometry; 13643 13644 register int 13645 i; 13646 13647 static char 13648 filename[MaxTextExtent] = "\0", 13649 filenames[MaxTextExtent] = "*"; 13650 13651 XResourceInfo 13652 background_resources; 13653 13654 /* 13655 Request file name from user. 13656 */ 13657 XFileBrowserWidget(display,windows,"Directory",filenames); 13658 if (*filenames == '\0') 13659 return((Image *) NULL); 13660 /* 13661 Expand the filenames. 13662 */ 13663 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13664 if (filelist == (char **) NULL) 13665 { 13666 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13667 filenames); 13668 return((Image *) NULL); 13669 } 13670 number_files=1; 13671 filelist[0]=filenames; 13672 status=ExpandFilenames(&number_files,&filelist); 13673 if ((status == MagickFalse) || (number_files == 0)) 13674 { 13675 if (number_files == 0) 13676 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13677 else 13678 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13679 filenames); 13680 return((Image *) NULL); 13681 } 13682 /* 13683 Set image background resources. 13684 */ 13685 background_resources=(*resource_info); 13686 background_resources.window_id=AcquireString(""); 13687 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13688 "0x%lx",windows->image.id); 13689 background_resources.backdrop=MagickTrue; 13690 /* 13691 Read each image and convert them to a tile. 13692 */ 13693 backdrop=(windows->visual_info->klass == TrueColor) || 13694 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13695 read_info=CloneImageInfo(resource_info->image_info); 13696 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13697 (void) CloneString(&read_info->size,DefaultTileGeometry); 13698 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13699 (void *) NULL); 13700 images=NewImageList(); 13701 XSetCursorState(display,windows,MagickTrue); 13702 XCheckRefreshWindows(display,windows); 13703 for (i=0; i < (int) number_files; i++) 13704 { 13705 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13706 filelist[i]=DestroyString(filelist[i]); 13707 *read_info->magick='\0'; 13708 next_image=ReadImage(read_info,exception); 13709 CatchException(exception); 13710 if (next_image != (Image *) NULL) 13711 { 13712 (void) DeleteImageProperty(next_image,"label"); 13713 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13714 read_info,next_image,DefaultTileLabel,exception),exception); 13715 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13716 exception); 13717 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13718 geometry.height,exception); 13719 if (thumbnail_image != (Image *) NULL) 13720 { 13721 next_image=DestroyImage(next_image); 13722 next_image=thumbnail_image; 13723 } 13724 if (backdrop) 13725 { 13726 (void) XDisplayBackgroundImage(display,&background_resources, 13727 next_image,exception); 13728 XSetCursorState(display,windows,MagickTrue); 13729 } 13730 AppendImageToList(&images,next_image); 13731 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13732 { 13733 MagickBooleanType 13734 proceed; 13735 13736 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13737 (MagickSizeType) number_files); 13738 if (proceed == MagickFalse) 13739 break; 13740 } 13741 } 13742 } 13743 filelist=(char **) RelinquishMagickMemory(filelist); 13744 if (images == (Image *) NULL) 13745 { 13746 read_info=DestroyImageInfo(read_info); 13747 XSetCursorState(display,windows,MagickFalse); 13748 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13749 return((Image *) NULL); 13750 } 13751 /* 13752 Create the Visual Image Directory. 13753 */ 13754 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13755 montage_info->pointsize=10; 13756 if (resource_info->font != (char *) NULL) 13757 (void) CloneString(&montage_info->font,resource_info->font); 13758 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13759 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13760 images),exception); 13761 images=DestroyImageList(images); 13762 montage_info=DestroyMontageInfo(montage_info); 13763 read_info=DestroyImageInfo(read_info); 13764 XSetCursorState(display,windows,MagickFalse); 13765 if (montage_image == (Image *) NULL) 13766 return(montage_image); 13767 XClientMessage(display,windows->image.id,windows->im_protocols, 13768 windows->im_next_image,CurrentTime); 13769 return(montage_image); 13770} 13771 13772/* 13773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13774% % 13775% % 13776% % 13777% X D i s p l a y B a c k g r o u n d I m a g e % 13778% % 13779% % 13780% % 13781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13782% 13783% XDisplayBackgroundImage() displays an image in the background of a window. 13784% 13785% The format of the XDisplayBackgroundImage method is: 13786% 13787% MagickBooleanType XDisplayBackgroundImage(Display *display, 13788% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13789% 13790% A description of each parameter follows: 13791% 13792% o display: Specifies a connection to an X server; returned from 13793% XOpenDisplay. 13794% 13795% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13796% 13797% o image: the image. 13798% 13799% o exception: return any errors or warnings in this structure. 13800% 13801*/ 13802MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13803 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13804{ 13805 char 13806 geometry[MaxTextExtent], 13807 visual_type[MaxTextExtent]; 13808 13809 int 13810 height, 13811 status, 13812 width; 13813 13814 RectangleInfo 13815 geometry_info; 13816 13817 static XPixelInfo 13818 pixel; 13819 13820 static XStandardColormap 13821 *map_info; 13822 13823 static XVisualInfo 13824 *visual_info = (XVisualInfo *) NULL; 13825 13826 static XWindowInfo 13827 window_info; 13828 13829 size_t 13830 delay; 13831 13832 Window 13833 root_window; 13834 13835 XGCValues 13836 context_values; 13837 13838 XResourceInfo 13839 resources; 13840 13841 XWindowAttributes 13842 window_attributes; 13843 13844 /* 13845 Determine target window. 13846 */ 13847 assert(image != (Image *) NULL); 13848 assert(image->signature == MagickSignature); 13849 if (image->debug != MagickFalse) 13850 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13851 resources=(*resource_info); 13852 window_info.id=(Window) NULL; 13853 root_window=XRootWindow(display,XDefaultScreen(display)); 13854 if (LocaleCompare(resources.window_id,"root") == 0) 13855 window_info.id=root_window; 13856 else 13857 { 13858 if (isdigit((unsigned char) *resources.window_id) != 0) 13859 window_info.id=XWindowByID(display,root_window, 13860 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13861 if (window_info.id == (Window) NULL) 13862 window_info.id=XWindowByName(display,root_window,resources.window_id); 13863 } 13864 if (window_info.id == (Window) NULL) 13865 { 13866 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13867 resources.window_id); 13868 return(MagickFalse); 13869 } 13870 /* 13871 Determine window visual id. 13872 */ 13873 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13874 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13875 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13876 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13877 if (status != 0) 13878 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13879 XVisualIDFromVisual(window_attributes.visual)); 13880 if (visual_info == (XVisualInfo *) NULL) 13881 { 13882 /* 13883 Allocate standard colormap. 13884 */ 13885 map_info=XAllocStandardColormap(); 13886 if (map_info == (XStandardColormap *) NULL) 13887 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13888 image->filename); 13889 map_info->colormap=(Colormap) NULL; 13890 pixel.pixels=(unsigned long *) NULL; 13891 /* 13892 Initialize visual info. 13893 */ 13894 resources.map_type=(char *) NULL; 13895 resources.visual_type=visual_type; 13896 visual_info=XBestVisualInfo(display,map_info,&resources); 13897 if (visual_info == (XVisualInfo *) NULL) 13898 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13899 resources.visual_type); 13900 /* 13901 Initialize window info. 13902 */ 13903 window_info.ximage=(XImage *) NULL; 13904 window_info.matte_image=(XImage *) NULL; 13905 window_info.pixmap=(Pixmap) NULL; 13906 window_info.matte_pixmap=(Pixmap) NULL; 13907 } 13908 /* 13909 Free previous root colors. 13910 */ 13911 if (window_info.id == root_window) 13912 (void) XDestroyWindowColors(display,root_window); 13913 /* 13914 Initialize Standard Colormap. 13915 */ 13916 resources.colormap=SharedColormap; 13917 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13918 exception); 13919 /* 13920 Graphic context superclass. 13921 */ 13922 context_values.background=pixel.background_color.pixel; 13923 context_values.foreground=pixel.foreground_color.pixel; 13924 pixel.annotate_context=XCreateGC(display,window_info.id, 13925 (size_t) (GCBackground | GCForeground),&context_values); 13926 if (pixel.annotate_context == (GC) NULL) 13927 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13928 image->filename); 13929 /* 13930 Initialize Image window attributes. 13931 */ 13932 window_info.name=AcquireString("\0"); 13933 window_info.icon_name=AcquireString("\0"); 13934 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13935 &resources,&window_info); 13936 /* 13937 Create the X image. 13938 */ 13939 window_info.width=(unsigned int) image->columns; 13940 window_info.height=(unsigned int) image->rows; 13941 if ((image->columns != window_info.width) || 13942 (image->rows != window_info.height)) 13943 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13944 image->filename); 13945 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13946 window_attributes.width,window_attributes.height); 13947 geometry_info.width=window_info.width; 13948 geometry_info.height=window_info.height; 13949 geometry_info.x=(ssize_t) window_info.x; 13950 geometry_info.y=(ssize_t) window_info.y; 13951 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13952 &geometry_info.width,&geometry_info.height); 13953 window_info.width=(unsigned int) geometry_info.width; 13954 window_info.height=(unsigned int) geometry_info.height; 13955 window_info.x=(int) geometry_info.x; 13956 window_info.y=(int) geometry_info.y; 13957 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13958 window_info.height,exception); 13959 if (status == MagickFalse) 13960 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13961 image->filename); 13962 window_info.x=0; 13963 window_info.y=0; 13964 if (image->debug != MagickFalse) 13965 { 13966 (void) LogMagickEvent(X11Event,GetMagickModule(), 13967 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13968 (double) image->columns,(double) image->rows); 13969 if (image->colors != 0) 13970 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13971 image->colors); 13972 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13973 } 13974 /* 13975 Adjust image dimensions as specified by backdrop or geometry options. 13976 */ 13977 width=(int) window_info.width; 13978 height=(int) window_info.height; 13979 if (resources.backdrop != MagickFalse) 13980 { 13981 /* 13982 Center image on window. 13983 */ 13984 window_info.x=(window_attributes.width/2)- 13985 (window_info.ximage->width/2); 13986 window_info.y=(window_attributes.height/2)- 13987 (window_info.ximage->height/2); 13988 width=window_attributes.width; 13989 height=window_attributes.height; 13990 } 13991 if ((resources.image_geometry != (char *) NULL) && 13992 (*resources.image_geometry != '\0')) 13993 { 13994 char 13995 default_geometry[MaxTextExtent]; 13996 13997 int 13998 flags, 13999 gravity; 14000 14001 XSizeHints 14002 *size_hints; 14003 14004 /* 14005 User specified geometry. 14006 */ 14007 size_hints=XAllocSizeHints(); 14008 if (size_hints == (XSizeHints *) NULL) 14009 ThrowXWindowFatalException(ResourceLimitFatalError, 14010 "MemoryAllocationFailed",image->filename); 14011 size_hints->flags=0L; 14012 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 14013 width,height); 14014 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14015 default_geometry,window_info.border_width,size_hints,&window_info.x, 14016 &window_info.y,&width,&height,&gravity); 14017 if (flags & (XValue | YValue)) 14018 { 14019 width=window_attributes.width; 14020 height=window_attributes.height; 14021 } 14022 (void) XFree((void *) size_hints); 14023 } 14024 /* 14025 Create the X pixmap. 14026 */ 14027 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14028 (unsigned int) height,window_info.depth); 14029 if (window_info.pixmap == (Pixmap) NULL) 14030 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14031 image->filename); 14032 /* 14033 Display pixmap on the window. 14034 */ 14035 if (((unsigned int) width > window_info.width) || 14036 ((unsigned int) height > window_info.height)) 14037 (void) XFillRectangle(display,window_info.pixmap, 14038 window_info.annotate_context,0,0,(unsigned int) width, 14039 (unsigned int) height); 14040 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14041 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14042 window_info.width,(unsigned int) window_info.height); 14043 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14044 (void) XClearWindow(display,window_info.id); 14045 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14046 XDelay(display,delay == 0UL ? 10UL : delay); 14047 (void) XSync(display,MagickFalse); 14048 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14049} 14050 14051/* 14052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14053% % 14054% % 14055% % 14056+ X D i s p l a y I m a g e % 14057% % 14058% % 14059% % 14060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14061% 14062% XDisplayImage() displays an image via X11. A new image is created and 14063% returned if the user interactively transforms the displayed image. 14064% 14065% The format of the XDisplayImage method is: 14066% 14067% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14068% char **argv,int argc,Image **image,size_t *state, 14069% ExceptionInfo *exception) 14070% 14071% A description of each parameter follows: 14072% 14073% o nexus: Method XDisplayImage returns an image when the 14074% user chooses 'Open Image' from the command menu or picks a tile 14075% from the image directory. Otherwise a null image is returned. 14076% 14077% o display: Specifies a connection to an X server; returned from 14078% XOpenDisplay. 14079% 14080% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14081% 14082% o argv: Specifies the application's argument list. 14083% 14084% o argc: Specifies the number of arguments. 14085% 14086% o image: Specifies an address to an address of an Image structure; 14087% 14088% o exception: return any errors or warnings in this structure. 14089% 14090*/ 14091MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14092 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14093{ 14094#define MagnifySize 256 /* must be a power of 2 */ 14095#define MagickMenus 10 14096#define MagickTitle "Commands" 14097 14098 static const char 14099 *CommandMenu[] = 14100 { 14101 "File", 14102 "Edit", 14103 "View", 14104 "Transform", 14105 "Enhance", 14106 "Effects", 14107 "F/X", 14108 "Image Edit", 14109 "Miscellany", 14110 "Help", 14111 (char *) NULL 14112 }, 14113 *FileMenu[] = 14114 { 14115 "Open...", 14116 "Next", 14117 "Former", 14118 "Select...", 14119 "Save...", 14120 "Print...", 14121 "Delete...", 14122 "New...", 14123 "Visual Directory...", 14124 "Quit", 14125 (char *) NULL 14126 }, 14127 *EditMenu[] = 14128 { 14129 "Undo", 14130 "Redo", 14131 "Cut", 14132 "Copy", 14133 "Paste", 14134 (char *) NULL 14135 }, 14136 *ViewMenu[] = 14137 { 14138 "Half Size", 14139 "Original Size", 14140 "Double Size", 14141 "Resize...", 14142 "Apply", 14143 "Refresh", 14144 "Restore", 14145 (char *) NULL 14146 }, 14147 *TransformMenu[] = 14148 { 14149 "Crop", 14150 "Chop", 14151 "Flop", 14152 "Flip", 14153 "Rotate Right", 14154 "Rotate Left", 14155 "Rotate...", 14156 "Shear...", 14157 "Roll...", 14158 "Trim Edges", 14159 (char *) NULL 14160 }, 14161 *EnhanceMenu[] = 14162 { 14163 "Hue...", 14164 "Saturation...", 14165 "Brightness...", 14166 "Gamma...", 14167 "Spiff", 14168 "Dull", 14169 "Contrast Stretch...", 14170 "Sigmoidal Contrast...", 14171 "Normalize", 14172 "Equalize", 14173 "Negate", 14174 "Grayscale", 14175 "Map...", 14176 "Quantize...", 14177 (char *) NULL 14178 }, 14179 *EffectsMenu[] = 14180 { 14181 "Despeckle", 14182 "Emboss", 14183 "Reduce Noise", 14184 "Add Noise...", 14185 "Sharpen...", 14186 "Blur...", 14187 "Threshold...", 14188 "Edge Detect...", 14189 "Spread...", 14190 "Shade...", 14191 "Raise...", 14192 "Segment...", 14193 (char *) NULL 14194 }, 14195 *FXMenu[] = 14196 { 14197 "Solarize...", 14198 "Sepia Tone...", 14199 "Swirl...", 14200 "Implode...", 14201 "Vignette...", 14202 "Wave...", 14203 "Oil Paint...", 14204 "Charcoal Draw...", 14205 (char *) NULL 14206 }, 14207 *ImageEditMenu[] = 14208 { 14209 "Annotate...", 14210 "Draw...", 14211 "Color...", 14212 "Matte...", 14213 "Composite...", 14214 "Add Border...", 14215 "Add Frame...", 14216 "Comment...", 14217 "Launch...", 14218 "Region of Interest...", 14219 (char *) NULL 14220 }, 14221 *MiscellanyMenu[] = 14222 { 14223 "Image Info", 14224 "Zoom Image", 14225 "Show Preview...", 14226 "Show Histogram", 14227 "Show Matte", 14228 "Background...", 14229 "Slide Show...", 14230 "Preferences...", 14231 (char *) NULL 14232 }, 14233 *HelpMenu[] = 14234 { 14235 "Overview", 14236 "Browse Documentation", 14237 "About Display", 14238 (char *) NULL 14239 }, 14240 *ShortCutsMenu[] = 14241 { 14242 "Next", 14243 "Former", 14244 "Open...", 14245 "Save...", 14246 "Print...", 14247 "Undo", 14248 "Restore", 14249 "Image Info", 14250 "Quit", 14251 (char *) NULL 14252 }, 14253 *VirtualMenu[] = 14254 { 14255 "Image Info", 14256 "Print", 14257 "Next", 14258 "Quit", 14259 (char *) NULL 14260 }; 14261 14262 static const char 14263 **Menus[MagickMenus] = 14264 { 14265 FileMenu, 14266 EditMenu, 14267 ViewMenu, 14268 TransformMenu, 14269 EnhanceMenu, 14270 EffectsMenu, 14271 FXMenu, 14272 ImageEditMenu, 14273 MiscellanyMenu, 14274 HelpMenu 14275 }; 14276 14277 static CommandType 14278 CommandMenus[] = 14279 { 14280 NullCommand, 14281 NullCommand, 14282 NullCommand, 14283 NullCommand, 14284 NullCommand, 14285 NullCommand, 14286 NullCommand, 14287 NullCommand, 14288 NullCommand, 14289 NullCommand, 14290 }, 14291 FileCommands[] = 14292 { 14293 OpenCommand, 14294 NextCommand, 14295 FormerCommand, 14296 SelectCommand, 14297 SaveCommand, 14298 PrintCommand, 14299 DeleteCommand, 14300 NewCommand, 14301 VisualDirectoryCommand, 14302 QuitCommand 14303 }, 14304 EditCommands[] = 14305 { 14306 UndoCommand, 14307 RedoCommand, 14308 CutCommand, 14309 CopyCommand, 14310 PasteCommand 14311 }, 14312 ViewCommands[] = 14313 { 14314 HalfSizeCommand, 14315 OriginalSizeCommand, 14316 DoubleSizeCommand, 14317 ResizeCommand, 14318 ApplyCommand, 14319 RefreshCommand, 14320 RestoreCommand 14321 }, 14322 TransformCommands[] = 14323 { 14324 CropCommand, 14325 ChopCommand, 14326 FlopCommand, 14327 FlipCommand, 14328 RotateRightCommand, 14329 RotateLeftCommand, 14330 RotateCommand, 14331 ShearCommand, 14332 RollCommand, 14333 TrimCommand 14334 }, 14335 EnhanceCommands[] = 14336 { 14337 HueCommand, 14338 SaturationCommand, 14339 BrightnessCommand, 14340 GammaCommand, 14341 SpiffCommand, 14342 DullCommand, 14343 ContrastStretchCommand, 14344 SigmoidalContrastCommand, 14345 NormalizeCommand, 14346 EqualizeCommand, 14347 NegateCommand, 14348 GrayscaleCommand, 14349 MapCommand, 14350 QuantizeCommand 14351 }, 14352 EffectsCommands[] = 14353 { 14354 DespeckleCommand, 14355 EmbossCommand, 14356 ReduceNoiseCommand, 14357 AddNoiseCommand, 14358 SharpenCommand, 14359 BlurCommand, 14360 ThresholdCommand, 14361 EdgeDetectCommand, 14362 SpreadCommand, 14363 ShadeCommand, 14364 RaiseCommand, 14365 SegmentCommand 14366 }, 14367 FXCommands[] = 14368 { 14369 SolarizeCommand, 14370 SepiaToneCommand, 14371 SwirlCommand, 14372 ImplodeCommand, 14373 VignetteCommand, 14374 WaveCommand, 14375 OilPaintCommand, 14376 CharcoalDrawCommand 14377 }, 14378 ImageEditCommands[] = 14379 { 14380 AnnotateCommand, 14381 DrawCommand, 14382 ColorCommand, 14383 MatteCommand, 14384 CompositeCommand, 14385 AddBorderCommand, 14386 AddFrameCommand, 14387 CommentCommand, 14388 LaunchCommand, 14389 RegionofInterestCommand 14390 }, 14391 MiscellanyCommands[] = 14392 { 14393 InfoCommand, 14394 ZoomCommand, 14395 ShowPreviewCommand, 14396 ShowHistogramCommand, 14397 ShowMatteCommand, 14398 BackgroundCommand, 14399 SlideShowCommand, 14400 PreferencesCommand 14401 }, 14402 HelpCommands[] = 14403 { 14404 HelpCommand, 14405 BrowseDocumentationCommand, 14406 VersionCommand 14407 }, 14408 ShortCutsCommands[] = 14409 { 14410 NextCommand, 14411 FormerCommand, 14412 OpenCommand, 14413 SaveCommand, 14414 PrintCommand, 14415 UndoCommand, 14416 RestoreCommand, 14417 InfoCommand, 14418 QuitCommand 14419 }, 14420 VirtualCommands[] = 14421 { 14422 InfoCommand, 14423 PrintCommand, 14424 NextCommand, 14425 QuitCommand 14426 }; 14427 14428 static CommandType 14429 *Commands[MagickMenus] = 14430 { 14431 FileCommands, 14432 EditCommands, 14433 ViewCommands, 14434 TransformCommands, 14435 EnhanceCommands, 14436 EffectsCommands, 14437 FXCommands, 14438 ImageEditCommands, 14439 MiscellanyCommands, 14440 HelpCommands 14441 }; 14442 14443 char 14444 command[MaxTextExtent], 14445 *directory, 14446 geometry[MaxTextExtent], 14447 resource_name[MaxTextExtent]; 14448 14449 CommandType 14450 command_type; 14451 14452 Image 14453 *display_image, 14454 *nexus; 14455 14456 int 14457 entry, 14458 id; 14459 14460 KeySym 14461 key_symbol; 14462 14463 MagickStatusType 14464 context_mask, 14465 status; 14466 14467 RectangleInfo 14468 geometry_info; 14469 14470 register int 14471 i; 14472 14473 static char 14474 working_directory[MaxTextExtent]; 14475 14476 static XPoint 14477 vid_info; 14478 14479 static XWindowInfo 14480 *magick_windows[MaxXWindows]; 14481 14482 static unsigned int 14483 number_windows; 14484 14485 struct stat 14486 attributes; 14487 14488 time_t 14489 timer, 14490 timestamp, 14491 update_time; 14492 14493 unsigned int 14494 height, 14495 width; 14496 14497 size_t 14498 delay; 14499 14500 WarningHandler 14501 warning_handler; 14502 14503 Window 14504 root_window; 14505 14506 XClassHint 14507 *class_hints; 14508 14509 XEvent 14510 event; 14511 14512 XFontStruct 14513 *font_info; 14514 14515 XGCValues 14516 context_values; 14517 14518 XPixelInfo 14519 *icon_pixel, 14520 *pixel; 14521 14522 XResourceInfo 14523 *icon_resources; 14524 14525 XStandardColormap 14526 *icon_map, 14527 *map_info; 14528 14529 XVisualInfo 14530 *icon_visual, 14531 *visual_info; 14532 14533 XWindowChanges 14534 window_changes; 14535 14536 XWindows 14537 *windows; 14538 14539 XWMHints 14540 *manager_hints; 14541 14542 assert(image != (Image **) NULL); 14543 assert((*image)->signature == MagickSignature); 14544 if ((*image)->debug != MagickFalse) 14545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14546 display_image=(*image); 14547 warning_handler=(WarningHandler) NULL; 14548 windows=XSetWindows((XWindows *) ~0); 14549 if (windows != (XWindows *) NULL) 14550 { 14551 int 14552 status; 14553 14554 status=chdir(working_directory); 14555 if (status == -1) 14556 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14557 "UnableToOpenFile","%s",working_directory); 14558 warning_handler=resource_info->display_warnings ? 14559 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14560 warning_handler=resource_info->display_warnings ? 14561 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14562 } 14563 else 14564 { 14565 /* 14566 Allocate windows structure. 14567 */ 14568 resource_info->colors=display_image->colors; 14569 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14570 if (windows == (XWindows *) NULL) 14571 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14572 (*image)->filename); 14573 /* 14574 Initialize window id's. 14575 */ 14576 number_windows=0; 14577 magick_windows[number_windows++]=(&windows->icon); 14578 magick_windows[number_windows++]=(&windows->backdrop); 14579 magick_windows[number_windows++]=(&windows->image); 14580 magick_windows[number_windows++]=(&windows->info); 14581 magick_windows[number_windows++]=(&windows->command); 14582 magick_windows[number_windows++]=(&windows->widget); 14583 magick_windows[number_windows++]=(&windows->popup); 14584 magick_windows[number_windows++]=(&windows->magnify); 14585 magick_windows[number_windows++]=(&windows->pan); 14586 for (i=0; i < (int) number_windows; i++) 14587 magick_windows[i]->id=(Window) NULL; 14588 vid_info.x=0; 14589 vid_info.y=0; 14590 } 14591 /* 14592 Initialize font info. 14593 */ 14594 if (windows->font_info != (XFontStruct *) NULL) 14595 (void) XFreeFont(display,windows->font_info); 14596 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14597 if (windows->font_info == (XFontStruct *) NULL) 14598 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14599 resource_info->font); 14600 /* 14601 Initialize Standard Colormap. 14602 */ 14603 map_info=windows->map_info; 14604 icon_map=windows->icon_map; 14605 visual_info=windows->visual_info; 14606 icon_visual=windows->icon_visual; 14607 pixel=windows->pixel_info; 14608 icon_pixel=windows->icon_pixel; 14609 font_info=windows->font_info; 14610 icon_resources=windows->icon_resources; 14611 class_hints=windows->class_hints; 14612 manager_hints=windows->manager_hints; 14613 root_window=XRootWindow(display,visual_info->screen); 14614 nexus=NewImageList(); 14615 if (display_image->debug != MagickFalse) 14616 { 14617 (void) LogMagickEvent(X11Event,GetMagickModule(), 14618 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14619 (double) display_image->scene,(double) display_image->columns, 14620 (double) display_image->rows); 14621 if (display_image->colors != 0) 14622 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14623 display_image->colors); 14624 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14625 display_image->magick); 14626 } 14627 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14628 map_info,pixel,exception); 14629 display_image->taint=MagickFalse; 14630 /* 14631 Initialize graphic context. 14632 */ 14633 windows->context.id=(Window) NULL; 14634 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14635 resource_info,&windows->context); 14636 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14637 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14638 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14639 manager_hints->flags=InputHint | StateHint; 14640 manager_hints->input=MagickFalse; 14641 manager_hints->initial_state=WithdrawnState; 14642 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14643 &windows->context); 14644 if (display_image->debug != MagickFalse) 14645 (void) LogMagickEvent(X11Event,GetMagickModule(), 14646 "Window id: 0x%lx (context)",windows->context.id); 14647 context_values.background=pixel->background_color.pixel; 14648 context_values.font=font_info->fid; 14649 context_values.foreground=pixel->foreground_color.pixel; 14650 context_values.graphics_exposures=MagickFalse; 14651 context_mask=(MagickStatusType) 14652 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14653 if (pixel->annotate_context != (GC) NULL) 14654 (void) XFreeGC(display,pixel->annotate_context); 14655 pixel->annotate_context=XCreateGC(display,windows->context.id, 14656 context_mask,&context_values); 14657 if (pixel->annotate_context == (GC) NULL) 14658 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14659 display_image->filename); 14660 context_values.background=pixel->depth_color.pixel; 14661 if (pixel->widget_context != (GC) NULL) 14662 (void) XFreeGC(display,pixel->widget_context); 14663 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14664 &context_values); 14665 if (pixel->widget_context == (GC) NULL) 14666 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14667 display_image->filename); 14668 context_values.background=pixel->foreground_color.pixel; 14669 context_values.foreground=pixel->background_color.pixel; 14670 context_values.plane_mask=context_values.background ^ 14671 context_values.foreground; 14672 if (pixel->highlight_context != (GC) NULL) 14673 (void) XFreeGC(display,pixel->highlight_context); 14674 pixel->highlight_context=XCreateGC(display,windows->context.id, 14675 (size_t) (context_mask | GCPlaneMask),&context_values); 14676 if (pixel->highlight_context == (GC) NULL) 14677 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14678 display_image->filename); 14679 (void) XDestroyWindow(display,windows->context.id); 14680 /* 14681 Initialize icon window. 14682 */ 14683 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14684 icon_resources,&windows->icon); 14685 windows->icon.geometry=resource_info->icon_geometry; 14686 XBestIconSize(display,&windows->icon,display_image); 14687 windows->icon.attributes.colormap=XDefaultColormap(display, 14688 icon_visual->screen); 14689 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14690 manager_hints->flags=InputHint | StateHint; 14691 manager_hints->input=MagickFalse; 14692 manager_hints->initial_state=IconicState; 14693 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14694 &windows->icon); 14695 if (display_image->debug != MagickFalse) 14696 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14697 windows->icon.id); 14698 /* 14699 Initialize graphic context for icon window. 14700 */ 14701 if (icon_pixel->annotate_context != (GC) NULL) 14702 (void) XFreeGC(display,icon_pixel->annotate_context); 14703 context_values.background=icon_pixel->background_color.pixel; 14704 context_values.foreground=icon_pixel->foreground_color.pixel; 14705 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14706 (size_t) (GCBackground | GCForeground),&context_values); 14707 if (icon_pixel->annotate_context == (GC) NULL) 14708 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14709 display_image->filename); 14710 windows->icon.annotate_context=icon_pixel->annotate_context; 14711 /* 14712 Initialize Image window. 14713 */ 14714 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14715 &windows->image); 14716 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14717 if (resource_info->use_shared_memory == MagickFalse) 14718 windows->image.shared_memory=MagickFalse; 14719 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14720 { 14721 char 14722 *title; 14723 14724 title=InterpretImageProperties(resource_info->image_info,display_image, 14725 resource_info->title,exception); 14726 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14727 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14728 title=DestroyString(title); 14729 } 14730 else 14731 { 14732 char 14733 filename[MaxTextExtent]; 14734 14735 /* 14736 Window name is the base of the filename. 14737 */ 14738 GetPathComponent(display_image->magick_filename,TailPath,filename); 14739 if (display_image->scene == 0) 14740 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14741 "%s: %s",MagickPackageName,filename); 14742 else 14743 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14744 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14745 (double) display_image->scene,(double) GetImageListLength( 14746 display_image)); 14747 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14748 } 14749 if (resource_info->immutable) 14750 windows->image.immutable=MagickTrue; 14751 windows->image.use_pixmap=resource_info->use_pixmap; 14752 windows->image.geometry=resource_info->image_geometry; 14753 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14754 XDisplayWidth(display,visual_info->screen), 14755 XDisplayHeight(display,visual_info->screen)); 14756 geometry_info.width=display_image->columns; 14757 geometry_info.height=display_image->rows; 14758 geometry_info.x=0; 14759 geometry_info.y=0; 14760 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14761 &geometry_info.width,&geometry_info.height); 14762 windows->image.width=(unsigned int) geometry_info.width; 14763 windows->image.height=(unsigned int) geometry_info.height; 14764 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14765 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14766 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14767 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14768 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14769 resource_info,&windows->backdrop); 14770 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14771 { 14772 /* 14773 Initialize backdrop window. 14774 */ 14775 windows->backdrop.x=0; 14776 windows->backdrop.y=0; 14777 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14778 windows->backdrop.flags=(size_t) (USSize | USPosition); 14779 windows->backdrop.width=(unsigned int) 14780 XDisplayWidth(display,visual_info->screen); 14781 windows->backdrop.height=(unsigned int) 14782 XDisplayHeight(display,visual_info->screen); 14783 windows->backdrop.border_width=0; 14784 windows->backdrop.immutable=MagickTrue; 14785 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14786 ButtonReleaseMask; 14787 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14788 StructureNotifyMask; 14789 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14790 manager_hints->icon_window=windows->icon.id; 14791 manager_hints->input=MagickTrue; 14792 manager_hints->initial_state=resource_info->iconic ? IconicState : 14793 NormalState; 14794 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14795 &windows->backdrop); 14796 if (display_image->debug != MagickFalse) 14797 (void) LogMagickEvent(X11Event,GetMagickModule(), 14798 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14799 (void) XMapWindow(display,windows->backdrop.id); 14800 (void) XClearWindow(display,windows->backdrop.id); 14801 if (windows->image.id != (Window) NULL) 14802 { 14803 (void) XDestroyWindow(display,windows->image.id); 14804 windows->image.id=(Window) NULL; 14805 } 14806 /* 14807 Position image in the center the backdrop. 14808 */ 14809 windows->image.flags|=USPosition; 14810 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14811 (windows->image.width/2); 14812 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14813 (windows->image.height/2); 14814 } 14815 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14816 manager_hints->icon_window=windows->icon.id; 14817 manager_hints->input=MagickTrue; 14818 manager_hints->initial_state=resource_info->iconic ? IconicState : 14819 NormalState; 14820 if (windows->group_leader.id != (Window) NULL) 14821 { 14822 /* 14823 Follow the leader. 14824 */ 14825 manager_hints->flags|=WindowGroupHint; 14826 manager_hints->window_group=windows->group_leader.id; 14827 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14828 if (display_image->debug != MagickFalse) 14829 (void) LogMagickEvent(X11Event,GetMagickModule(), 14830 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14831 } 14832 XMakeWindow(display, 14833 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14834 argv,argc,class_hints,manager_hints,&windows->image); 14835 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14836 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14837 if (windows->group_leader.id != (Window) NULL) 14838 (void) XSetTransientForHint(display,windows->image.id, 14839 windows->group_leader.id); 14840 if (display_image->debug != MagickFalse) 14841 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14842 windows->image.id); 14843 /* 14844 Initialize Info widget. 14845 */ 14846 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14847 &windows->info); 14848 (void) CloneString(&windows->info.name,"Info"); 14849 (void) CloneString(&windows->info.icon_name,"Info"); 14850 windows->info.border_width=1; 14851 windows->info.x=2; 14852 windows->info.y=2; 14853 windows->info.flags|=PPosition; 14854 windows->info.attributes.win_gravity=UnmapGravity; 14855 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14856 StructureNotifyMask; 14857 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14858 manager_hints->input=MagickFalse; 14859 manager_hints->initial_state=NormalState; 14860 manager_hints->window_group=windows->image.id; 14861 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14862 &windows->info); 14863 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14864 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14865 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14866 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14867 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14868 if (windows->image.mapped != MagickFalse) 14869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14870 if (display_image->debug != MagickFalse) 14871 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14872 windows->info.id); 14873 /* 14874 Initialize Command widget. 14875 */ 14876 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14877 resource_info,&windows->command); 14878 windows->command.data=MagickMenus; 14879 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14880 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14881 resource_info->client_name); 14882 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14883 resource_name,"geometry",(char *) NULL); 14884 (void) CloneString(&windows->command.name,MagickTitle); 14885 windows->command.border_width=0; 14886 windows->command.flags|=PPosition; 14887 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14888 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14889 OwnerGrabButtonMask | StructureNotifyMask; 14890 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14891 manager_hints->input=MagickTrue; 14892 manager_hints->initial_state=NormalState; 14893 manager_hints->window_group=windows->image.id; 14894 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14895 &windows->command); 14896 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14897 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14898 HighlightHeight); 14899 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14900 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14901 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14902 if (windows->command.mapped != MagickFalse) 14903 (void) XMapRaised(display,windows->command.id); 14904 if (display_image->debug != MagickFalse) 14905 (void) LogMagickEvent(X11Event,GetMagickModule(), 14906 "Window id: 0x%lx (command)",windows->command.id); 14907 /* 14908 Initialize Widget window. 14909 */ 14910 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14911 resource_info,&windows->widget); 14912 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14913 resource_info->client_name); 14914 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14915 resource_name,"geometry",(char *) NULL); 14916 windows->widget.border_width=0; 14917 windows->widget.flags|=PPosition; 14918 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14919 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14920 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14921 StructureNotifyMask; 14922 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14923 manager_hints->input=MagickTrue; 14924 manager_hints->initial_state=NormalState; 14925 manager_hints->window_group=windows->image.id; 14926 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14927 &windows->widget); 14928 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14929 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14930 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14931 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14932 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14933 if (display_image->debug != MagickFalse) 14934 (void) LogMagickEvent(X11Event,GetMagickModule(), 14935 "Window id: 0x%lx (widget)",windows->widget.id); 14936 /* 14937 Initialize popup window. 14938 */ 14939 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14940 resource_info,&windows->popup); 14941 windows->popup.border_width=0; 14942 windows->popup.flags|=PPosition; 14943 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14944 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14945 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14946 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14947 manager_hints->input=MagickTrue; 14948 manager_hints->initial_state=NormalState; 14949 manager_hints->window_group=windows->image.id; 14950 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14951 &windows->popup); 14952 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14953 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14954 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14955 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14956 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14957 if (display_image->debug != MagickFalse) 14958 (void) LogMagickEvent(X11Event,GetMagickModule(), 14959 "Window id: 0x%lx (pop up)",windows->popup.id); 14960 /* 14961 Initialize Magnify window and cursor. 14962 */ 14963 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14964 resource_info,&windows->magnify); 14965 if (resource_info->use_shared_memory == MagickFalse) 14966 windows->magnify.shared_memory=MagickFalse; 14967 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14968 resource_info->client_name); 14969 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14970 resource_name,"geometry",(char *) NULL); 14971 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14972 resource_info->magnify); 14973 if (windows->magnify.cursor != (Cursor) NULL) 14974 (void) XFreeCursor(display,windows->magnify.cursor); 14975 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14976 map_info->colormap,resource_info->background_color, 14977 resource_info->foreground_color); 14978 if (windows->magnify.cursor == (Cursor) NULL) 14979 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14980 display_image->filename); 14981 windows->magnify.width=MagnifySize; 14982 windows->magnify.height=MagnifySize; 14983 windows->magnify.flags|=PPosition; 14984 windows->magnify.min_width=MagnifySize; 14985 windows->magnify.min_height=MagnifySize; 14986 windows->magnify.width_inc=MagnifySize; 14987 windows->magnify.height_inc=MagnifySize; 14988 windows->magnify.data=resource_info->magnify; 14989 windows->magnify.attributes.cursor=windows->magnify.cursor; 14990 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14991 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14992 StructureNotifyMask; 14993 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14994 manager_hints->input=MagickTrue; 14995 manager_hints->initial_state=NormalState; 14996 manager_hints->window_group=windows->image.id; 14997 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14998 &windows->magnify); 14999 if (display_image->debug != MagickFalse) 15000 (void) LogMagickEvent(X11Event,GetMagickModule(), 15001 "Window id: 0x%lx (magnify)",windows->magnify.id); 15002 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 15003 /* 15004 Initialize panning window. 15005 */ 15006 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 15007 resource_info,&windows->pan); 15008 (void) CloneString(&windows->pan.name,"Pan Icon"); 15009 windows->pan.width=windows->icon.width; 15010 windows->pan.height=windows->icon.height; 15011 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 15012 resource_info->client_name); 15013 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15014 resource_name,"geometry",(char *) NULL); 15015 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15016 &windows->pan.width,&windows->pan.height); 15017 windows->pan.flags|=PPosition; 15018 windows->pan.immutable=MagickTrue; 15019 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15020 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15021 StructureNotifyMask; 15022 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15023 manager_hints->input=MagickFalse; 15024 manager_hints->initial_state=NormalState; 15025 manager_hints->window_group=windows->image.id; 15026 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15027 &windows->pan); 15028 if (display_image->debug != MagickFalse) 15029 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15030 windows->pan.id); 15031 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15032 if (windows->info.mapped != MagickFalse) 15033 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15034 if ((windows->image.mapped == MagickFalse) || 15035 (windows->backdrop.id != (Window) NULL)) 15036 (void) XMapWindow(display,windows->image.id); 15037 /* 15038 Set our progress monitor and warning handlers. 15039 */ 15040 if (warning_handler == (WarningHandler) NULL) 15041 { 15042 warning_handler=resource_info->display_warnings ? 15043 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15044 warning_handler=resource_info->display_warnings ? 15045 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15046 } 15047 /* 15048 Initialize Image and Magnify X images. 15049 */ 15050 windows->image.x=0; 15051 windows->image.y=0; 15052 windows->magnify.shape=MagickFalse; 15053 width=(unsigned int) display_image->columns; 15054 height=(unsigned int) display_image->rows; 15055 if ((display_image->columns != width) || (display_image->rows != height)) 15056 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15057 display_image->filename); 15058 status=XMakeImage(display,resource_info,&windows->image,display_image, 15059 width,height,exception); 15060 if (status == MagickFalse) 15061 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15062 display_image->filename); 15063 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15064 windows->magnify.width,windows->magnify.height,exception); 15065 if (status == MagickFalse) 15066 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15067 display_image->filename); 15068 if (windows->magnify.mapped != MagickFalse) 15069 (void) XMapRaised(display,windows->magnify.id); 15070 if (windows->pan.mapped != MagickFalse) 15071 (void) XMapRaised(display,windows->pan.id); 15072 windows->image.window_changes.width=(int) display_image->columns; 15073 windows->image.window_changes.height=(int) display_image->rows; 15074 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15075 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15076 (void) XSync(display,MagickFalse); 15077 /* 15078 Respond to events. 15079 */ 15080 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15081 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15082 update_time=0; 15083 if (resource_info->update != MagickFalse) 15084 { 15085 MagickBooleanType 15086 status; 15087 15088 /* 15089 Determine when file data was last modified. 15090 */ 15091 status=GetPathAttributes(display_image->filename,&attributes); 15092 if (status != MagickFalse) 15093 update_time=attributes.st_mtime; 15094 } 15095 *state&=(~FormerImageState); 15096 *state&=(~MontageImageState); 15097 *state&=(~NextImageState); 15098 do 15099 { 15100 /* 15101 Handle a window event. 15102 */ 15103 if (windows->image.mapped != MagickFalse) 15104 if ((display_image->delay != 0) || (resource_info->update != 0)) 15105 { 15106 if (timer < time((time_t *) NULL)) 15107 { 15108 if (resource_info->update == MagickFalse) 15109 *state|=NextImageState | ExitState; 15110 else 15111 { 15112 MagickBooleanType 15113 status; 15114 15115 /* 15116 Determine if image file was modified. 15117 */ 15118 status=GetPathAttributes(display_image->filename,&attributes); 15119 if (status != MagickFalse) 15120 if (update_time != attributes.st_mtime) 15121 { 15122 /* 15123 Redisplay image. 15124 */ 15125 (void) FormatLocaleString( 15126 resource_info->image_info->filename,MaxTextExtent, 15127 "%s:%s",display_image->magick, 15128 display_image->filename); 15129 nexus=ReadImage(resource_info->image_info,exception); 15130 if (nexus != (Image *) NULL) 15131 { 15132 nexus=DestroyImage(nexus); 15133 *state|=NextImageState | ExitState; 15134 } 15135 } 15136 delay=display_image->delay/MagickMax( 15137 display_image->ticks_per_second,1L); 15138 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15139 } 15140 } 15141 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15142 { 15143 /* 15144 Do not block if delay > 0. 15145 */ 15146 XDelay(display,SuspendTime << 2); 15147 continue; 15148 } 15149 } 15150 timestamp=time((time_t *) NULL); 15151 (void) XNextEvent(display,&event); 15152 if (windows->image.stasis == MagickFalse) 15153 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15154 MagickTrue : MagickFalse; 15155 if (windows->magnify.stasis == MagickFalse) 15156 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15157 MagickTrue : MagickFalse; 15158 if (event.xany.window == windows->command.id) 15159 { 15160 /* 15161 Select a command from the Command widget. 15162 */ 15163 id=XCommandWidget(display,windows,CommandMenu,&event); 15164 if (id < 0) 15165 continue; 15166 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15167 command_type=CommandMenus[id]; 15168 if (id < MagickMenus) 15169 { 15170 /* 15171 Select a command from a pop-up menu. 15172 */ 15173 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15174 command); 15175 if (entry < 0) 15176 continue; 15177 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15178 command_type=Commands[id][entry]; 15179 } 15180 if (command_type != NullCommand) 15181 nexus=XMagickCommand(display,resource_info,windows,command_type, 15182 &display_image,exception); 15183 continue; 15184 } 15185 switch (event.type) 15186 { 15187 case ButtonPress: 15188 { 15189 if (display_image->debug != MagickFalse) 15190 (void) LogMagickEvent(X11Event,GetMagickModule(), 15191 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15192 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15193 if ((event.xbutton.button == Button3) && 15194 (event.xbutton.state & Mod1Mask)) 15195 { 15196 /* 15197 Convert Alt-Button3 to Button2. 15198 */ 15199 event.xbutton.button=Button2; 15200 event.xbutton.state&=(~Mod1Mask); 15201 } 15202 if (event.xbutton.window == windows->backdrop.id) 15203 { 15204 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15205 event.xbutton.time); 15206 break; 15207 } 15208 if (event.xbutton.window == windows->image.id) 15209 { 15210 switch (event.xbutton.button) 15211 { 15212 case Button1: 15213 { 15214 if (resource_info->immutable) 15215 { 15216 /* 15217 Select a command from the Virtual menu. 15218 */ 15219 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15220 command); 15221 if (entry >= 0) 15222 nexus=XMagickCommand(display,resource_info,windows, 15223 VirtualCommands[entry],&display_image,exception); 15224 break; 15225 } 15226 /* 15227 Map/unmap Command widget. 15228 */ 15229 if (windows->command.mapped != MagickFalse) 15230 (void) XWithdrawWindow(display,windows->command.id, 15231 windows->command.screen); 15232 else 15233 { 15234 (void) XCommandWidget(display,windows,CommandMenu, 15235 (XEvent *) NULL); 15236 (void) XMapRaised(display,windows->command.id); 15237 } 15238 break; 15239 } 15240 case Button2: 15241 { 15242 /* 15243 User pressed the image magnify button. 15244 */ 15245 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15246 &display_image,exception); 15247 XMagnifyImage(display,windows,&event,exception); 15248 break; 15249 } 15250 case Button3: 15251 { 15252 if (resource_info->immutable) 15253 { 15254 /* 15255 Select a command from the Virtual menu. 15256 */ 15257 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15258 command); 15259 if (entry >= 0) 15260 nexus=XMagickCommand(display,resource_info,windows, 15261 VirtualCommands[entry],&display_image,exception); 15262 break; 15263 } 15264 if (display_image->montage != (char *) NULL) 15265 { 15266 /* 15267 Open or delete a tile from a visual image directory. 15268 */ 15269 nexus=XTileImage(display,resource_info,windows, 15270 display_image,&event,exception); 15271 if (nexus != (Image *) NULL) 15272 *state|=MontageImageState | NextImageState | ExitState; 15273 vid_info.x=(short int) windows->image.x; 15274 vid_info.y=(short int) windows->image.y; 15275 break; 15276 } 15277 /* 15278 Select a command from the Short Cuts menu. 15279 */ 15280 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15281 command); 15282 if (entry >= 0) 15283 nexus=XMagickCommand(display,resource_info,windows, 15284 ShortCutsCommands[entry],&display_image,exception); 15285 break; 15286 } 15287 case Button4: 15288 { 15289 /* 15290 Wheel up. 15291 */ 15292 XTranslateImage(display,windows,*image,XK_Up); 15293 break; 15294 } 15295 case Button5: 15296 { 15297 /* 15298 Wheel down. 15299 */ 15300 XTranslateImage(display,windows,*image,XK_Down); 15301 break; 15302 } 15303 default: 15304 break; 15305 } 15306 break; 15307 } 15308 if (event.xbutton.window == windows->magnify.id) 15309 { 15310 int 15311 factor; 15312 15313 static const char 15314 *MagnifyMenu[] = 15315 { 15316 "2", 15317 "4", 15318 "5", 15319 "6", 15320 "7", 15321 "8", 15322 "9", 15323 "3", 15324 (char *) NULL, 15325 }; 15326 15327 static KeySym 15328 MagnifyCommands[] = 15329 { 15330 XK_2, 15331 XK_4, 15332 XK_5, 15333 XK_6, 15334 XK_7, 15335 XK_8, 15336 XK_9, 15337 XK_3 15338 }; 15339 15340 /* 15341 Select a magnify factor from the pop-up menu. 15342 */ 15343 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15344 if (factor >= 0) 15345 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15346 exception); 15347 break; 15348 } 15349 if (event.xbutton.window == windows->pan.id) 15350 { 15351 switch (event.xbutton.button) 15352 { 15353 case Button4: 15354 { 15355 /* 15356 Wheel up. 15357 */ 15358 XTranslateImage(display,windows,*image,XK_Up); 15359 break; 15360 } 15361 case Button5: 15362 { 15363 /* 15364 Wheel down. 15365 */ 15366 XTranslateImage(display,windows,*image,XK_Down); 15367 break; 15368 } 15369 default: 15370 { 15371 XPanImage(display,windows,&event,exception); 15372 break; 15373 } 15374 } 15375 break; 15376 } 15377 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15378 1L); 15379 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15380 break; 15381 } 15382 case ButtonRelease: 15383 { 15384 if (display_image->debug != MagickFalse) 15385 (void) LogMagickEvent(X11Event,GetMagickModule(), 15386 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15387 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15388 break; 15389 } 15390 case ClientMessage: 15391 { 15392 if (display_image->debug != MagickFalse) 15393 (void) LogMagickEvent(X11Event,GetMagickModule(), 15394 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15395 event.xclient.message_type,event.xclient.format,(unsigned long) 15396 event.xclient.data.l[0]); 15397 if (event.xclient.message_type == windows->im_protocols) 15398 { 15399 if (*event.xclient.data.l == (long) windows->im_update_widget) 15400 { 15401 (void) CloneString(&windows->command.name,MagickTitle); 15402 windows->command.data=MagickMenus; 15403 (void) XCommandWidget(display,windows,CommandMenu, 15404 (XEvent *) NULL); 15405 break; 15406 } 15407 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15408 { 15409 /* 15410 Update graphic context and window colormap. 15411 */ 15412 for (i=0; i < (int) number_windows; i++) 15413 { 15414 if (magick_windows[i]->id == windows->icon.id) 15415 continue; 15416 context_values.background=pixel->background_color.pixel; 15417 context_values.foreground=pixel->foreground_color.pixel; 15418 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15419 context_mask,&context_values); 15420 (void) XChangeGC(display,magick_windows[i]->widget_context, 15421 context_mask,&context_values); 15422 context_values.background=pixel->foreground_color.pixel; 15423 context_values.foreground=pixel->background_color.pixel; 15424 context_values.plane_mask=context_values.background ^ 15425 context_values.foreground; 15426 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15427 (size_t) (context_mask | GCPlaneMask), 15428 &context_values); 15429 magick_windows[i]->attributes.background_pixel= 15430 pixel->background_color.pixel; 15431 magick_windows[i]->attributes.border_pixel= 15432 pixel->border_color.pixel; 15433 magick_windows[i]->attributes.colormap=map_info->colormap; 15434 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15435 (unsigned long) magick_windows[i]->mask, 15436 &magick_windows[i]->attributes); 15437 } 15438 if (windows->pan.mapped != MagickFalse) 15439 { 15440 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15441 windows->pan.pixmap); 15442 (void) XClearWindow(display,windows->pan.id); 15443 XDrawPanRectangle(display,windows); 15444 } 15445 if (windows->backdrop.id != (Window) NULL) 15446 (void) XInstallColormap(display,map_info->colormap); 15447 break; 15448 } 15449 if (*event.xclient.data.l == (long) windows->im_former_image) 15450 { 15451 *state|=FormerImageState | ExitState; 15452 break; 15453 } 15454 if (*event.xclient.data.l == (long) windows->im_next_image) 15455 { 15456 *state|=NextImageState | ExitState; 15457 break; 15458 } 15459 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15460 { 15461 *state|=RetainColorsState; 15462 break; 15463 } 15464 if (*event.xclient.data.l == (long) windows->im_exit) 15465 { 15466 *state|=ExitState; 15467 break; 15468 } 15469 break; 15470 } 15471 if (event.xclient.message_type == windows->dnd_protocols) 15472 { 15473 Atom 15474 selection, 15475 type; 15476 15477 int 15478 format, 15479 status; 15480 15481 unsigned char 15482 *data; 15483 15484 unsigned long 15485 after, 15486 length; 15487 15488 /* 15489 Display image named by the Drag-and-Drop selection. 15490 */ 15491 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15492 break; 15493 selection=XInternAtom(display,"DndSelection",MagickFalse); 15494 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15495 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15496 &length,&after,&data); 15497 if ((status != Success) || (length == 0)) 15498 break; 15499 if (*event.xclient.data.l == 2) 15500 { 15501 /* 15502 Offix DND. 15503 */ 15504 (void) CopyMagickString(resource_info->image_info->filename, 15505 (char *) data,MaxTextExtent); 15506 } 15507 else 15508 { 15509 /* 15510 XDND. 15511 */ 15512 if (strncmp((char *) data, "file:", 5) != 0) 15513 { 15514 (void) XFree((void *) data); 15515 break; 15516 } 15517 (void) CopyMagickString(resource_info->image_info->filename, 15518 ((char *) data)+5,MaxTextExtent); 15519 } 15520 nexus=ReadImage(resource_info->image_info,exception); 15521 CatchException(exception); 15522 if (nexus != (Image *) NULL) 15523 *state|=NextImageState | ExitState; 15524 (void) XFree((void *) data); 15525 break; 15526 } 15527 /* 15528 If client window delete message, exit. 15529 */ 15530 if (event.xclient.message_type != windows->wm_protocols) 15531 break; 15532 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15533 break; 15534 (void) XWithdrawWindow(display,event.xclient.window, 15535 visual_info->screen); 15536 if (event.xclient.window == windows->image.id) 15537 { 15538 *state|=ExitState; 15539 break; 15540 } 15541 if (event.xclient.window == windows->pan.id) 15542 { 15543 /* 15544 Restore original image size when pan window is deleted. 15545 */ 15546 windows->image.window_changes.width=windows->image.ximage->width; 15547 windows->image.window_changes.height=windows->image.ximage->height; 15548 (void) XConfigureImage(display,resource_info,windows, 15549 display_image,exception); 15550 } 15551 break; 15552 } 15553 case ConfigureNotify: 15554 { 15555 if (display_image->debug != MagickFalse) 15556 (void) LogMagickEvent(X11Event,GetMagickModule(), 15557 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15558 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15559 event.xconfigure.y,event.xconfigure.send_event); 15560 if (event.xconfigure.window == windows->image.id) 15561 { 15562 /* 15563 Image window has a new configuration. 15564 */ 15565 if (event.xconfigure.send_event != 0) 15566 { 15567 XWindowChanges 15568 window_changes; 15569 15570 /* 15571 Position the transient windows relative of the Image window. 15572 */ 15573 if (windows->command.geometry == (char *) NULL) 15574 if (windows->command.mapped == MagickFalse) 15575 { 15576 windows->command.x=event.xconfigure.x- 15577 windows->command.width-25; 15578 windows->command.y=event.xconfigure.y; 15579 XConstrainWindowPosition(display,&windows->command); 15580 window_changes.x=windows->command.x; 15581 window_changes.y=windows->command.y; 15582 (void) XReconfigureWMWindow(display,windows->command.id, 15583 windows->command.screen,(unsigned int) (CWX | CWY), 15584 &window_changes); 15585 } 15586 if (windows->widget.geometry == (char *) NULL) 15587 if (windows->widget.mapped == MagickFalse) 15588 { 15589 windows->widget.x=event.xconfigure.x+ 15590 event.xconfigure.width/10; 15591 windows->widget.y=event.xconfigure.y+ 15592 event.xconfigure.height/10; 15593 XConstrainWindowPosition(display,&windows->widget); 15594 window_changes.x=windows->widget.x; 15595 window_changes.y=windows->widget.y; 15596 (void) XReconfigureWMWindow(display,windows->widget.id, 15597 windows->widget.screen,(unsigned int) (CWX | CWY), 15598 &window_changes); 15599 } 15600 if (windows->magnify.geometry == (char *) NULL) 15601 if (windows->magnify.mapped == MagickFalse) 15602 { 15603 windows->magnify.x=event.xconfigure.x+ 15604 event.xconfigure.width+25; 15605 windows->magnify.y=event.xconfigure.y; 15606 XConstrainWindowPosition(display,&windows->magnify); 15607 window_changes.x=windows->magnify.x; 15608 window_changes.y=windows->magnify.y; 15609 (void) XReconfigureWMWindow(display,windows->magnify.id, 15610 windows->magnify.screen,(unsigned int) (CWX | CWY), 15611 &window_changes); 15612 } 15613 if (windows->pan.geometry == (char *) NULL) 15614 if (windows->pan.mapped == MagickFalse) 15615 { 15616 windows->pan.x=event.xconfigure.x+ 15617 event.xconfigure.width+25; 15618 windows->pan.y=event.xconfigure.y+ 15619 windows->magnify.height+50; 15620 XConstrainWindowPosition(display,&windows->pan); 15621 window_changes.x=windows->pan.x; 15622 window_changes.y=windows->pan.y; 15623 (void) XReconfigureWMWindow(display,windows->pan.id, 15624 windows->pan.screen,(unsigned int) (CWX | CWY), 15625 &window_changes); 15626 } 15627 } 15628 if ((event.xconfigure.width == (int) windows->image.width) && 15629 (event.xconfigure.height == (int) windows->image.height)) 15630 break; 15631 windows->image.width=(unsigned int) event.xconfigure.width; 15632 windows->image.height=(unsigned int) event.xconfigure.height; 15633 windows->image.x=0; 15634 windows->image.y=0; 15635 if (display_image->montage != (char *) NULL) 15636 { 15637 windows->image.x=vid_info.x; 15638 windows->image.y=vid_info.y; 15639 } 15640 if ((windows->image.mapped != MagickFalse) && 15641 (windows->image.stasis != MagickFalse)) 15642 { 15643 /* 15644 Update image window configuration. 15645 */ 15646 windows->image.window_changes.width=event.xconfigure.width; 15647 windows->image.window_changes.height=event.xconfigure.height; 15648 (void) XConfigureImage(display,resource_info,windows, 15649 display_image,exception); 15650 } 15651 /* 15652 Update pan window configuration. 15653 */ 15654 if ((event.xconfigure.width < windows->image.ximage->width) || 15655 (event.xconfigure.height < windows->image.ximage->height)) 15656 { 15657 (void) XMapRaised(display,windows->pan.id); 15658 XDrawPanRectangle(display,windows); 15659 } 15660 else 15661 if (windows->pan.mapped != MagickFalse) 15662 (void) XWithdrawWindow(display,windows->pan.id, 15663 windows->pan.screen); 15664 break; 15665 } 15666 if (event.xconfigure.window == windows->magnify.id) 15667 { 15668 unsigned int 15669 magnify; 15670 15671 /* 15672 Magnify window has a new configuration. 15673 */ 15674 windows->magnify.width=(unsigned int) event.xconfigure.width; 15675 windows->magnify.height=(unsigned int) event.xconfigure.height; 15676 if (windows->magnify.mapped == MagickFalse) 15677 break; 15678 magnify=1; 15679 while ((int) magnify <= event.xconfigure.width) 15680 magnify<<=1; 15681 while ((int) magnify <= event.xconfigure.height) 15682 magnify<<=1; 15683 magnify>>=1; 15684 if (((int) magnify != event.xconfigure.width) || 15685 ((int) magnify != event.xconfigure.height)) 15686 { 15687 window_changes.width=(int) magnify; 15688 window_changes.height=(int) magnify; 15689 (void) XReconfigureWMWindow(display,windows->magnify.id, 15690 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15691 &window_changes); 15692 break; 15693 } 15694 if ((windows->magnify.mapped != MagickFalse) && 15695 (windows->magnify.stasis != MagickFalse)) 15696 { 15697 status=XMakeImage(display,resource_info,&windows->magnify, 15698 display_image,windows->magnify.width,windows->magnify.height, 15699 exception); 15700 XMakeMagnifyImage(display,windows,exception); 15701 } 15702 break; 15703 } 15704 if ((windows->magnify.mapped != MagickFalse) && 15705 (event.xconfigure.window == windows->pan.id)) 15706 { 15707 /* 15708 Pan icon window has a new configuration. 15709 */ 15710 if (event.xconfigure.send_event != 0) 15711 { 15712 windows->pan.x=event.xconfigure.x; 15713 windows->pan.y=event.xconfigure.y; 15714 } 15715 windows->pan.width=(unsigned int) event.xconfigure.width; 15716 windows->pan.height=(unsigned int) event.xconfigure.height; 15717 break; 15718 } 15719 if (event.xconfigure.window == windows->icon.id) 15720 { 15721 /* 15722 Icon window has a new configuration. 15723 */ 15724 windows->icon.width=(unsigned int) event.xconfigure.width; 15725 windows->icon.height=(unsigned int) event.xconfigure.height; 15726 break; 15727 } 15728 break; 15729 } 15730 case DestroyNotify: 15731 { 15732 /* 15733 Group leader has exited. 15734 */ 15735 if (display_image->debug != MagickFalse) 15736 (void) LogMagickEvent(X11Event,GetMagickModule(), 15737 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15738 if (event.xdestroywindow.window == windows->group_leader.id) 15739 { 15740 *state|=ExitState; 15741 break; 15742 } 15743 break; 15744 } 15745 case EnterNotify: 15746 { 15747 /* 15748 Selectively install colormap. 15749 */ 15750 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15751 if (event.xcrossing.mode != NotifyUngrab) 15752 XInstallColormap(display,map_info->colormap); 15753 break; 15754 } 15755 case Expose: 15756 { 15757 if (display_image->debug != MagickFalse) 15758 (void) LogMagickEvent(X11Event,GetMagickModule(), 15759 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15760 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15761 event.xexpose.y); 15762 /* 15763 Refresh windows that are now exposed. 15764 */ 15765 if ((event.xexpose.window == windows->image.id) && 15766 (windows->image.mapped != MagickFalse)) 15767 { 15768 XRefreshWindow(display,&windows->image,&event); 15769 delay=display_image->delay/MagickMax( 15770 display_image->ticks_per_second,1L); 15771 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15772 break; 15773 } 15774 if ((event.xexpose.window == windows->magnify.id) && 15775 (windows->magnify.mapped != MagickFalse)) 15776 { 15777 XMakeMagnifyImage(display,windows,exception); 15778 break; 15779 } 15780 if (event.xexpose.window == windows->pan.id) 15781 { 15782 XDrawPanRectangle(display,windows); 15783 break; 15784 } 15785 if (event.xexpose.window == windows->icon.id) 15786 { 15787 XRefreshWindow(display,&windows->icon,&event); 15788 break; 15789 } 15790 break; 15791 } 15792 case KeyPress: 15793 { 15794 int 15795 length; 15796 15797 /* 15798 Respond to a user key press. 15799 */ 15800 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15801 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15802 *(command+length)='\0'; 15803 if (display_image->debug != MagickFalse) 15804 (void) LogMagickEvent(X11Event,GetMagickModule(), 15805 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15806 key_symbol,command); 15807 if (event.xkey.window == windows->image.id) 15808 { 15809 command_type=XImageWindowCommand(display,resource_info,windows, 15810 event.xkey.state,key_symbol,&display_image,exception); 15811 if (command_type != NullCommand) 15812 nexus=XMagickCommand(display,resource_info,windows,command_type, 15813 &display_image,exception); 15814 } 15815 if (event.xkey.window == windows->magnify.id) 15816 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15817 exception); 15818 if (event.xkey.window == windows->pan.id) 15819 { 15820 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15821 (void) XWithdrawWindow(display,windows->pan.id, 15822 windows->pan.screen); 15823 else 15824 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15825 XTextViewWidget(display,resource_info,windows,MagickFalse, 15826 "Help Viewer - Image Pan",ImagePanHelp); 15827 else 15828 XTranslateImage(display,windows,*image,key_symbol); 15829 } 15830 delay=display_image->delay/MagickMax( 15831 display_image->ticks_per_second,1L); 15832 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15833 break; 15834 } 15835 case KeyRelease: 15836 { 15837 /* 15838 Respond to a user key release. 15839 */ 15840 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15841 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15842 if (display_image->debug != MagickFalse) 15843 (void) LogMagickEvent(X11Event,GetMagickModule(), 15844 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15845 break; 15846 } 15847 case LeaveNotify: 15848 { 15849 /* 15850 Selectively uninstall colormap. 15851 */ 15852 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15853 if (event.xcrossing.mode != NotifyUngrab) 15854 XUninstallColormap(display,map_info->colormap); 15855 break; 15856 } 15857 case MapNotify: 15858 { 15859 if (display_image->debug != MagickFalse) 15860 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15861 event.xmap.window); 15862 if (event.xmap.window == windows->backdrop.id) 15863 { 15864 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15865 CurrentTime); 15866 windows->backdrop.mapped=MagickTrue; 15867 break; 15868 } 15869 if (event.xmap.window == windows->image.id) 15870 { 15871 if (windows->backdrop.id != (Window) NULL) 15872 (void) XInstallColormap(display,map_info->colormap); 15873 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15874 { 15875 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15876 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15877 } 15878 if (((int) windows->image.width < windows->image.ximage->width) || 15879 ((int) windows->image.height < windows->image.ximage->height)) 15880 (void) XMapRaised(display,windows->pan.id); 15881 windows->image.mapped=MagickTrue; 15882 break; 15883 } 15884 if (event.xmap.window == windows->magnify.id) 15885 { 15886 XMakeMagnifyImage(display,windows,exception); 15887 windows->magnify.mapped=MagickTrue; 15888 (void) XWithdrawWindow(display,windows->info.id, 15889 windows->info.screen); 15890 break; 15891 } 15892 if (event.xmap.window == windows->pan.id) 15893 { 15894 XMakePanImage(display,resource_info,windows,display_image, 15895 exception); 15896 windows->pan.mapped=MagickTrue; 15897 break; 15898 } 15899 if (event.xmap.window == windows->info.id) 15900 { 15901 windows->info.mapped=MagickTrue; 15902 break; 15903 } 15904 if (event.xmap.window == windows->icon.id) 15905 { 15906 MagickBooleanType 15907 taint; 15908 15909 /* 15910 Create an icon image. 15911 */ 15912 taint=display_image->taint; 15913 XMakeStandardColormap(display,icon_visual,icon_resources, 15914 display_image,icon_map,icon_pixel,exception); 15915 (void) XMakeImage(display,icon_resources,&windows->icon, 15916 display_image,windows->icon.width,windows->icon.height, 15917 exception); 15918 display_image->taint=taint; 15919 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15920 windows->icon.pixmap); 15921 (void) XClearWindow(display,windows->icon.id); 15922 (void) XWithdrawWindow(display,windows->info.id, 15923 windows->info.screen); 15924 windows->icon.mapped=MagickTrue; 15925 break; 15926 } 15927 if (event.xmap.window == windows->command.id) 15928 { 15929 windows->command.mapped=MagickTrue; 15930 break; 15931 } 15932 if (event.xmap.window == windows->popup.id) 15933 { 15934 windows->popup.mapped=MagickTrue; 15935 break; 15936 } 15937 if (event.xmap.window == windows->widget.id) 15938 { 15939 windows->widget.mapped=MagickTrue; 15940 break; 15941 } 15942 break; 15943 } 15944 case MappingNotify: 15945 { 15946 (void) XRefreshKeyboardMapping(&event.xmapping); 15947 break; 15948 } 15949 case NoExpose: 15950 break; 15951 case PropertyNotify: 15952 { 15953 Atom 15954 type; 15955 15956 int 15957 format, 15958 status; 15959 15960 unsigned char 15961 *data; 15962 15963 unsigned long 15964 after, 15965 length; 15966 15967 if (display_image->debug != MagickFalse) 15968 (void) LogMagickEvent(X11Event,GetMagickModule(), 15969 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15970 event.xproperty.atom,event.xproperty.state); 15971 if (event.xproperty.atom != windows->im_remote_command) 15972 break; 15973 /* 15974 Display image named by the remote command protocol. 15975 */ 15976 status=XGetWindowProperty(display,event.xproperty.window, 15977 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15978 AnyPropertyType,&type,&format,&length,&after,&data); 15979 if ((status != Success) || (length == 0)) 15980 break; 15981 if (LocaleCompare((char *) data,"-quit") == 0) 15982 { 15983 XClientMessage(display,windows->image.id,windows->im_protocols, 15984 windows->im_exit,CurrentTime); 15985 (void) XFree((void *) data); 15986 break; 15987 } 15988 (void) CopyMagickString(resource_info->image_info->filename, 15989 (char *) data,MaxTextExtent); 15990 (void) XFree((void *) data); 15991 nexus=ReadImage(resource_info->image_info,exception); 15992 CatchException(exception); 15993 if (nexus != (Image *) NULL) 15994 *state|=NextImageState | ExitState; 15995 break; 15996 } 15997 case ReparentNotify: 15998 { 15999 if (display_image->debug != MagickFalse) 16000 (void) LogMagickEvent(X11Event,GetMagickModule(), 16001 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 16002 event.xreparent.window); 16003 break; 16004 } 16005 case UnmapNotify: 16006 { 16007 if (display_image->debug != MagickFalse) 16008 (void) LogMagickEvent(X11Event,GetMagickModule(), 16009 "Unmap Notify: 0x%lx",event.xunmap.window); 16010 if (event.xunmap.window == windows->backdrop.id) 16011 { 16012 windows->backdrop.mapped=MagickFalse; 16013 break; 16014 } 16015 if (event.xunmap.window == windows->image.id) 16016 { 16017 windows->image.mapped=MagickFalse; 16018 break; 16019 } 16020 if (event.xunmap.window == windows->magnify.id) 16021 { 16022 windows->magnify.mapped=MagickFalse; 16023 break; 16024 } 16025 if (event.xunmap.window == windows->pan.id) 16026 { 16027 windows->pan.mapped=MagickFalse; 16028 break; 16029 } 16030 if (event.xunmap.window == windows->info.id) 16031 { 16032 windows->info.mapped=MagickFalse; 16033 break; 16034 } 16035 if (event.xunmap.window == windows->icon.id) 16036 { 16037 if (map_info->colormap == icon_map->colormap) 16038 XConfigureImageColormap(display,resource_info,windows, 16039 display_image,exception); 16040 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16041 icon_pixel); 16042 windows->icon.mapped=MagickFalse; 16043 break; 16044 } 16045 if (event.xunmap.window == windows->command.id) 16046 { 16047 windows->command.mapped=MagickFalse; 16048 break; 16049 } 16050 if (event.xunmap.window == windows->popup.id) 16051 { 16052 if (windows->backdrop.id != (Window) NULL) 16053 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16054 CurrentTime); 16055 windows->popup.mapped=MagickFalse; 16056 break; 16057 } 16058 if (event.xunmap.window == windows->widget.id) 16059 { 16060 if (windows->backdrop.id != (Window) NULL) 16061 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16062 CurrentTime); 16063 windows->widget.mapped=MagickFalse; 16064 break; 16065 } 16066 break; 16067 } 16068 default: 16069 { 16070 if (display_image->debug != MagickFalse) 16071 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16072 event.type); 16073 break; 16074 } 16075 } 16076 } while (!(*state & ExitState)); 16077 if ((*state & ExitState) == 0) 16078 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16079 &display_image,exception); 16080 else 16081 if (resource_info->confirm_edit != MagickFalse) 16082 { 16083 /* 16084 Query user if image has changed. 16085 */ 16086 if ((resource_info->immutable == MagickFalse) && 16087 (display_image->taint != MagickFalse)) 16088 { 16089 int 16090 status; 16091 16092 status=XConfirmWidget(display,windows,"Your image changed.", 16093 "Do you want to save it"); 16094 if (status == 0) 16095 *state&=(~ExitState); 16096 else 16097 if (status > 0) 16098 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16099 &display_image,exception); 16100 } 16101 } 16102 if ((windows->visual_info->klass == GrayScale) || 16103 (windows->visual_info->klass == PseudoColor) || 16104 (windows->visual_info->klass == DirectColor)) 16105 { 16106 /* 16107 Withdraw pan and Magnify window. 16108 */ 16109 if (windows->info.mapped != MagickFalse) 16110 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16111 if (windows->magnify.mapped != MagickFalse) 16112 (void) XWithdrawWindow(display,windows->magnify.id, 16113 windows->magnify.screen); 16114 if (windows->command.mapped != MagickFalse) 16115 (void) XWithdrawWindow(display,windows->command.id, 16116 windows->command.screen); 16117 } 16118 if (windows->pan.mapped != MagickFalse) 16119 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16120 if (resource_info->backdrop == MagickFalse) 16121 if (windows->backdrop.mapped) 16122 { 16123 (void) XWithdrawWindow(display,windows->backdrop.id, 16124 windows->backdrop.screen); 16125 (void) XDestroyWindow(display,windows->backdrop.id); 16126 windows->backdrop.id=(Window) NULL; 16127 (void) XWithdrawWindow(display,windows->image.id, 16128 windows->image.screen); 16129 (void) XDestroyWindow(display,windows->image.id); 16130 windows->image.id=(Window) NULL; 16131 } 16132 XSetCursorState(display,windows,MagickTrue); 16133 XCheckRefreshWindows(display,windows); 16134 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16135 *state&=(~ExitState); 16136 if (*state & ExitState) 16137 { 16138 /* 16139 Free Standard Colormap. 16140 */ 16141 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16142 if (resource_info->map_type == (char *) NULL) 16143 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16144 /* 16145 Free X resources. 16146 */ 16147 if (resource_info->copy_image != (Image *) NULL) 16148 { 16149 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16150 resource_info->copy_image=NewImageList(); 16151 } 16152 DestroyXResources(); 16153 } 16154 (void) XSync(display,MagickFalse); 16155 /* 16156 Restore our progress monitor and warning handlers. 16157 */ 16158 (void) SetErrorHandler(warning_handler); 16159 (void) SetWarningHandler(warning_handler); 16160 /* 16161 Change to home directory. 16162 */ 16163 directory=getcwd(working_directory,MaxTextExtent); 16164 (void) directory; 16165 { 16166 int 16167 status; 16168 16169 status=chdir(resource_info->home_directory); 16170 if (status == -1) 16171 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16172 "UnableToOpenFile","%s",resource_info->home_directory); 16173 } 16174 *image=display_image; 16175 return(nexus); 16176} 16177#else 16178 16179/* 16180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16181% % 16182% % 16183% % 16184+ D i s p l a y I m a g e s % 16185% % 16186% % 16187% % 16188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16189% 16190% DisplayImages() displays an image sequence to any X window screen. It 16191% returns a value other than 0 if successful. Check the exception member 16192% of image to determine the reason for any failure. 16193% 16194% The format of the DisplayImages method is: 16195% 16196% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16197% Image *images,ExceptionInfo *exception) 16198% 16199% A description of each parameter follows: 16200% 16201% o image_info: the image info. 16202% 16203% o image: the image. 16204% 16205% o exception: return any errors or warnings in this structure. 16206% 16207*/ 16208MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16209 Image *image,ExceptionInfo *exception) 16210{ 16211 assert(image_info != (const ImageInfo *) NULL); 16212 assert(image_info->signature == MagickSignature); 16213 assert(image != (Image *) NULL); 16214 assert(image->signature == MagickSignature); 16215 if (image->debug != MagickFalse) 16216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16217 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16218 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16219 return(MagickFalse); 16220} 16221 16222/* 16223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16224% % 16225% % 16226% % 16227+ R e m o t e D i s p l a y C o m m a n d % 16228% % 16229% % 16230% % 16231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16232% 16233% RemoteDisplayCommand() encourages a remote display program to display the 16234% specified image filename. 16235% 16236% The format of the RemoteDisplayCommand method is: 16237% 16238% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16239% const char *window,const char *filename,ExceptionInfo *exception) 16240% 16241% A description of each parameter follows: 16242% 16243% o image_info: the image info. 16244% 16245% o window: Specifies the name or id of an X window. 16246% 16247% o filename: the name of the image filename to display. 16248% 16249% o exception: return any errors or warnings in this structure. 16250% 16251*/ 16252MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16253 const char *window,const char *filename,ExceptionInfo *exception) 16254{ 16255 assert(image_info != (const ImageInfo *) NULL); 16256 assert(image_info->signature == MagickSignature); 16257 assert(filename != (char *) NULL); 16258 (void) window; 16259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16260 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16261 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16262 return(MagickFalse); 16263} 16264#endif 16265