display.c revision 947cb4c68bebf79b15b6f3e824bc973491a77709
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/client.h" 47#include "MagickCore/color.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/composite.h" 50#include "MagickCore/constitute.h" 51#include "MagickCore/decorate.h" 52#include "MagickCore/delegate.h" 53#include "MagickCore/display.h" 54#include "MagickCore/display-private.h" 55#include "MagickCore/draw.h" 56#include "MagickCore/effect.h" 57#include "MagickCore/enhance.h" 58#include "MagickCore/exception.h" 59#include "MagickCore/exception-private.h" 60#include "MagickCore/fx.h" 61#include "MagickCore/geometry.h" 62#include "MagickCore/image.h" 63#include "MagickCore/image-private.h" 64#include "MagickCore/list.h" 65#include "MagickCore/log.h" 66#include "MagickCore/magick.h" 67#include "MagickCore/memory_.h" 68#include "MagickCore/monitor.h" 69#include "MagickCore/monitor-private.h" 70#include "MagickCore/montage.h" 71#include "MagickCore/option.h" 72#include "MagickCore/paint.h" 73#include "MagickCore/pixel.h" 74#include "MagickCore/pixel-accessor.h" 75#include "MagickCore/PreRvIcccm.h" 76#include "MagickCore/property.h" 77#include "MagickCore/quantum.h" 78#include "MagickCore/quantum-private.h" 79#include "MagickCore/resize.h" 80#include "MagickCore/resource_.h" 81#include "MagickCore/shear.h" 82#include "MagickCore/segment.h" 83#include "MagickCore/string_.h" 84#include "MagickCore/string-private.h" 85#include "MagickCore/transform.h" 86#include "MagickCore/threshold.h" 87#include "MagickCore/utility.h" 88#include "MagickCore/utility-private.h" 89#include "MagickCore/version.h" 90#include "MagickCore/widget.h" 91#include "MagickCore/widget-private.h" 92#include "MagickCore/xwindow.h" 93#include "MagickCore/xwindow-private.h" 94 95#if defined(MAGICKCORE_X11_DELEGATE) 96/* 97 Define declarations. 98*/ 99#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 100 101/* 102 Constant declarations. 103*/ 104static const unsigned char 105 HighlightBitmap[8] = 106 { 107 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 108 }, 109 OpaqueBitmap[8] = 110 { 111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 112 }, 113 ShadowBitmap[8] = 114 { 115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 116 }; 117 118static const char 119 *PageSizes[] = 120 { 121 "Letter", 122 "Tabloid", 123 "Ledger", 124 "Legal", 125 "Statement", 126 "Executive", 127 "A3", 128 "A4", 129 "A5", 130 "B4", 131 "B5", 132 "Folio", 133 "Quarto", 134 "10x14", 135 (char *) NULL 136 }; 137 138/* 139 Help widget declarations. 140*/ 141static const char 142 *ImageAnnotateHelp[] = 143 { 144 "In annotate mode, the Command widget has these options:", 145 "", 146 " Font Name", 147 " fixed", 148 " variable", 149 " 5x8", 150 " 6x10", 151 " 7x13bold", 152 " 8x13bold", 153 " 9x15bold", 154 " 10x20", 155 " 12x24", 156 " Browser...", 157 " Font Color", 158 " black", 159 " blue", 160 " cyan", 161 " green", 162 " gray", 163 " red", 164 " magenta", 165 " yellow", 166 " white", 167 " transparent", 168 " Browser...", 169 " Font Color", 170 " black", 171 " blue", 172 " cyan", 173 " green", 174 " gray", 175 " red", 176 " magenta", 177 " yellow", 178 " white", 179 " transparent", 180 " Browser...", 181 " Rotate Text", 182 " -90", 183 " -45", 184 " -30", 185 " 0", 186 " 30", 187 " 45", 188 " 90", 189 " 180", 190 " Dialog...", 191 " Help", 192 " Dismiss", 193 "", 194 "Choose a font name from the Font Name sub-menu. Additional", 195 "font names can be specified with the font browser. You can", 196 "change the menu names by setting the X resources font1", 197 "through font9.", 198 "", 199 "Choose a font color from the Font Color sub-menu.", 200 "Additional font colors can be specified with the color", 201 "browser. You can change the menu colors by setting the X", 202 "resources pen1 through pen9.", 203 "", 204 "If you select the color browser and press Grab, you can", 205 "choose the font color by moving the pointer to the desired", 206 "color on the screen and press any button.", 207 "", 208 "If you choose to rotate the text, choose Rotate Text from the", 209 "menu and select an angle. Typically you will only want to", 210 "rotate one line of text at a time. Depending on the angle you", 211 "choose, subsequent lines may end up overwriting each other.", 212 "", 213 "Choosing a font and its color is optional. The default font", 214 "is fixed and the default color is black. However, you must", 215 "choose a location to begin entering text and press button 1.", 216 "An underscore character will appear at the location of the", 217 "pointer. The cursor changes to a pencil to indicate you are", 218 "in text mode. To exit immediately, press Dismiss.", 219 "", 220 "In text mode, any key presses will display the character at", 221 "the location of the underscore and advance the underscore", 222 "cursor. Enter your text and once completed press Apply to", 223 "finish your image annotation. To correct errors press BACK", 224 "SPACE. To delete an entire line of text, press DELETE. Any", 225 "text that exceeds the boundaries of the image window is", 226 "automagically continued onto the next line.", 227 "", 228 "The actual color you request for the font is saved in the", 229 "image. However, the color that appears in your image window", 230 "may be different. For example, on a monochrome screen the", 231 "text will appear black or white even if you choose the color", 232 "red as the font color. However, the image saved to a file", 233 "with -write is written with red lettering. To assure the", 234 "correct color text in the final image, any PseudoClass image", 235 "is promoted to DirectClass (see miff(5)). To force a", 236 "PseudoClass image to remain PseudoClass, use -colors.", 237 (char *) NULL, 238 }, 239 *ImageChopHelp[] = 240 { 241 "In chop mode, the Command widget has these options:", 242 "", 243 " Direction", 244 " horizontal", 245 " vertical", 246 " Help", 247 " Dismiss", 248 "", 249 "If the you choose the horizontal direction (this the", 250 "default), the area of the image between the two horizontal", 251 "endpoints of the chop line is removed. Otherwise, the area", 252 "of the image between the two vertical endpoints of the chop", 253 "line is removed.", 254 "", 255 "Select a location within the image window to begin your chop,", 256 "press and hold any button. Next, move the pointer to", 257 "another location in the image. As you move a line will", 258 "connect the initial location and the pointer. When you", 259 "release the button, the area within the image to chop is", 260 "determined by which direction you choose from the Command", 261 "widget.", 262 "", 263 "To cancel the image chopping, move the pointer back to the", 264 "starting point of the line and release the button.", 265 (char *) NULL, 266 }, 267 *ImageColorEditHelp[] = 268 { 269 "In color edit mode, the Command widget has these options:", 270 "", 271 " Method", 272 " point", 273 " replace", 274 " floodfill", 275 " filltoborder", 276 " reset", 277 " Pixel Color", 278 " black", 279 " blue", 280 " cyan", 281 " green", 282 " gray", 283 " red", 284 " magenta", 285 " yellow", 286 " white", 287 " Browser...", 288 " Border Color", 289 " black", 290 " blue", 291 " cyan", 292 " green", 293 " gray", 294 " red", 295 " magenta", 296 " yellow", 297 " white", 298 " Browser...", 299 " Fuzz", 300 " 0%", 301 " 2%", 302 " 5%", 303 " 10%", 304 " 15%", 305 " Dialog...", 306 " Undo", 307 " Help", 308 " Dismiss", 309 "", 310 "Choose a color editing method from the Method sub-menu", 311 "of the Command widget. The point method recolors any pixel", 312 "selected with the pointer until the button is released. The", 313 "replace method recolors any pixel that matches the color of", 314 "the pixel you select with a button press. Floodfill recolors", 315 "any pixel that matches the color of the pixel you select with", 316 "a button press and is a neighbor. Whereas filltoborder recolors", 317 "any neighbor pixel that is not the border color. Finally reset", 318 "changes the entire image to the designated color.", 319 "", 320 "Next, choose a pixel color from the Pixel Color sub-menu.", 321 "Additional pixel colors can be specified with the color", 322 "browser. You can change the menu colors by setting the X", 323 "resources pen1 through pen9.", 324 "", 325 "Now press button 1 to select a pixel within the image window", 326 "to change its color. Additional pixels may be recolored as", 327 "prescribed by the method you choose.", 328 "", 329 "If the Magnify widget is mapped, it can be helpful in positioning", 330 "your pointer within the image (refer to button 2).", 331 "", 332 "The actual color you request for the pixels is saved in the", 333 "image. However, the color that appears in your image window", 334 "may be different. For example, on a monochrome screen the", 335 "pixel will appear black or white even if you choose the", 336 "color red as the pixel color. However, the image saved to a", 337 "file with -write is written with red pixels. To assure the", 338 "correct color text in the final image, any PseudoClass image", 339 "is promoted to DirectClass (see miff(5)). To force a", 340 "PseudoClass image to remain PseudoClass, use -colors.", 341 (char *) NULL, 342 }, 343 *ImageCompositeHelp[] = 344 { 345 "First a widget window is displayed requesting you to enter an", 346 "image name. Press Composite, Grab or type a file name.", 347 "Press Cancel if you choose not to create a composite image.", 348 "When you choose Grab, move the pointer to the desired window", 349 "and press any button.", 350 "", 351 "If the Composite image does not have any matte information,", 352 "you are informed and the file browser is displayed again.", 353 "Enter the name of a mask image. The image is typically", 354 "grayscale and the same size as the composite image. If the", 355 "image is not grayscale, it is converted to grayscale and the", 356 "resulting intensities are used as matte information.", 357 "", 358 "A small window appears showing the location of the cursor in", 359 "the image window. You are now in composite mode. To exit", 360 "immediately, press Dismiss. In composite mode, the Command", 361 "widget has these options:", 362 "", 363 " Operators", 364 " Over", 365 " In", 366 " Out", 367 " Atop", 368 " Xor", 369 " Plus", 370 " Minus", 371 " Add", 372 " Subtract", 373 " Difference", 374 " Multiply", 375 " Bumpmap", 376 " Copy", 377 " CopyRed", 378 " CopyGreen", 379 " CopyBlue", 380 " CopyOpacity", 381 " Clear", 382 " Dissolve", 383 " Displace", 384 " Help", 385 " Dismiss", 386 "", 387 "Choose a composite operation from the Operators sub-menu of", 388 "the Command widget. How each operator behaves is described", 389 "below. Image window is the image currently displayed on", 390 "your X server and image is the image obtained with the File", 391 "Browser widget.", 392 "", 393 "Over The result is the union of the two image shapes,", 394 " with image obscuring image window in the region of", 395 " overlap.", 396 "", 397 "In The result is simply image cut by the shape of", 398 " image window. None of the image data of image", 399 " window is in the result.", 400 "", 401 "Out The resulting image is image with the shape of", 402 " image window cut out.", 403 "", 404 "Atop The result is the same shape as image image window,", 405 " with image obscuring image window where the image", 406 " shapes overlap. Note this differs from over", 407 " because the portion of image outside image window's", 408 " shape does not appear in the result.", 409 "", 410 "Xor The result is the image data from both image and", 411 " image window that is outside the overlap region.", 412 " The overlap region is blank.", 413 "", 414 "Plus The result is just the sum of the image data.", 415 " Output values are cropped to QuantumRange (no overflow).", 416 "", 417 "Minus The result of image - image window, with underflow", 418 " cropped to zero.", 419 "", 420 "Add The result of image + image window, with overflow", 421 " wrapping around (mod 256).", 422 "", 423 "Subtract The result of image - image window, with underflow", 424 " wrapping around (mod 256). The add and subtract", 425 " operators can be used to perform reversible", 426 " transformations.", 427 "", 428 "Difference", 429 " The result of abs(image - image window). This", 430 " useful for comparing two very similar images.", 431 "", 432 "Multiply", 433 " The result of image * image window. This", 434 " useful for the creation of drop-shadows.", 435 "", 436 "Bumpmap The result of surface normals from image * image", 437 " window.", 438 "", 439 "Copy The resulting image is image window replaced with", 440 " image. Here the matte information is ignored.", 441 "", 442 "CopyRed The red layer of the image window is replace with", 443 " the red layer of the image. The other layers are", 444 " untouched.", 445 "", 446 "CopyGreen", 447 " The green layer of the image window is replace with", 448 " the green layer of the image. The other layers are", 449 " untouched.", 450 "", 451 "CopyBlue The blue layer of the image window is replace with", 452 " the blue layer of the image. The other layers are", 453 " untouched.", 454 "", 455 "CopyOpacity", 456 " The matte layer of the image window is replace with", 457 " the matte layer of the image. The other layers are", 458 " untouched.", 459 "", 460 "The image compositor requires a matte, or alpha channel in", 461 "the image for some operations. This extra channel usually", 462 "defines a mask which represents a sort of a cookie-cutter", 463 "for the image. This the case when matte is opaque (full", 464 "coverage) for pixels inside the shape, zero outside, and", 465 "between 0 and QuantumRange on the boundary. If image does not", 466 "have a matte channel, it is initialized with 0 for any pixel", 467 "matching in color to pixel location (0,0), otherwise QuantumRange.", 468 "", 469 "If you choose Dissolve, the composite operator becomes Over. The", 470 "image matte channel percent transparency is initialized to factor.", 471 "The image window is initialized to (100-factor). Where factor is the", 472 "value you specify in the Dialog widget.", 473 "", 474 "Displace shifts the image pixels as defined by a displacement", 475 "map. With this option, image is used as a displacement map.", 476 "Black, within the displacement map, is a maximum positive", 477 "displacement. White is a maximum negative displacement and", 478 "middle gray is neutral. The displacement is scaled to determine", 479 "the pixel shift. By default, the displacement applies in both the", 480 "horizontal and vertical directions. However, if you specify a mask,", 481 "image is the horizontal X displacement and mask the vertical Y", 482 "displacement.", 483 "", 484 "Note that matte information for image window is not retained", 485 "for colormapped X server visuals (e.g. StaticColor,", 486 "StaticColor, GrayScale, PseudoColor). Correct compositing", 487 "behavior may require a TrueColor or DirectColor visual or a", 488 "Standard Colormap.", 489 "", 490 "Choosing a composite operator is optional. The default", 491 "operator is replace. However, you must choose a location to", 492 "composite your image and press button 1. Press and hold the", 493 "button before releasing and an outline of the image will", 494 "appear to help you identify your location.", 495 "", 496 "The actual colors of the composite image is saved. However,", 497 "the color that appears in image window may be different.", 498 "For example, on a monochrome screen image window will appear", 499 "black or white even though your composited image may have", 500 "many colors. If the image is saved to a file it is written", 501 "with the correct colors. To assure the correct colors are", 502 "saved in the final image, any PseudoClass image is promoted", 503 "to DirectClass (see miff(5)). To force a PseudoClass image", 504 "to remain PseudoClass, use -colors.", 505 (char *) NULL, 506 }, 507 *ImageCutHelp[] = 508 { 509 "In cut mode, the Command widget has these options:", 510 "", 511 " Help", 512 " Dismiss", 513 "", 514 "To define a cut region, press button 1 and drag. The", 515 "cut region is defined by a highlighted rectangle that", 516 "expands or contracts as it follows the pointer. Once you", 517 "are satisfied with the cut region, release the button.", 518 "You are now in rectify mode. In rectify mode, the Command", 519 "widget has these options:", 520 "", 521 " Cut", 522 " Help", 523 " Dismiss", 524 "", 525 "You can make adjustments by moving the pointer to one of the", 526 "cut rectangle corners, pressing a button, and dragging.", 527 "Finally, press Cut to commit your copy region. To", 528 "exit without cutting the image, press Dismiss.", 529 (char *) NULL, 530 }, 531 *ImageCopyHelp[] = 532 { 533 "In copy mode, the Command widget has these options:", 534 "", 535 " Help", 536 " Dismiss", 537 "", 538 "To define a copy region, press button 1 and drag. The", 539 "copy region is defined by a highlighted rectangle that", 540 "expands or contracts as it follows the pointer. Once you", 541 "are satisfied with the copy region, release the button.", 542 "You are now in rectify mode. In rectify mode, the Command", 543 "widget has these options:", 544 "", 545 " Copy", 546 " Help", 547 " Dismiss", 548 "", 549 "You can make adjustments by moving the pointer to one of the", 550 "copy rectangle corners, pressing a button, and dragging.", 551 "Finally, press Copy to commit your copy region. To", 552 "exit without copying the image, press Dismiss.", 553 (char *) NULL, 554 }, 555 *ImageCropHelp[] = 556 { 557 "In crop mode, the Command widget has these options:", 558 "", 559 " Help", 560 " Dismiss", 561 "", 562 "To define a cropping region, press button 1 and drag. The", 563 "cropping region is defined by a highlighted rectangle that", 564 "expands or contracts as it follows the pointer. Once you", 565 "are satisfied with the cropping region, release the button.", 566 "You are now in rectify mode. In rectify mode, the Command", 567 "widget has these options:", 568 "", 569 " Crop", 570 " Help", 571 " Dismiss", 572 "", 573 "You can make adjustments by moving the pointer to one of the", 574 "cropping rectangle corners, pressing a button, and dragging.", 575 "Finally, press Crop to commit your cropping region. To", 576 "exit without cropping the image, press Dismiss.", 577 (char *) NULL, 578 }, 579 *ImageDrawHelp[] = 580 { 581 "The cursor changes to a crosshair to indicate you are in", 582 "draw mode. To exit immediately, press Dismiss. In draw mode,", 583 "the Command widget has these options:", 584 "", 585 " Element", 586 " point", 587 " line", 588 " rectangle", 589 " fill rectangle", 590 " circle", 591 " fill circle", 592 " ellipse", 593 " fill ellipse", 594 " polygon", 595 " fill polygon", 596 " Color", 597 " black", 598 " blue", 599 " cyan", 600 " green", 601 " gray", 602 " red", 603 " magenta", 604 " yellow", 605 " white", 606 " transparent", 607 " Browser...", 608 " Stipple", 609 " Brick", 610 " Diagonal", 611 " Scales", 612 " Vertical", 613 " Wavy", 614 " Translucent", 615 " Opaque", 616 " Open...", 617 " Width", 618 " 1", 619 " 2", 620 " 4", 621 " 8", 622 " 16", 623 " Dialog...", 624 " Undo", 625 " Help", 626 " Dismiss", 627 "", 628 "Choose a drawing primitive from the Element sub-menu.", 629 "", 630 "Choose a color from the Color sub-menu. Additional", 631 "colors can be specified with the color browser.", 632 "", 633 "If you choose the color browser and press Grab, you can", 634 "select the color by moving the pointer to the desired", 635 "color on the screen and press any button. The transparent", 636 "color updates the image matte channel and is useful for", 637 "image compositing.", 638 "", 639 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 640 "Additional stipples can be specified with the file browser.", 641 "Stipples obtained from the file browser must be on disk in the", 642 "X11 bitmap format.", 643 "", 644 "Choose a width, if appropriate, from the Width sub-menu. To", 645 "choose a specific width select the Dialog widget.", 646 "", 647 "Choose a point in the Image window and press button 1 and", 648 "hold. Next, move the pointer to another location in the", 649 "image. As you move, a line connects the initial location and", 650 "the pointer. When you release the button, the image is", 651 "updated with the primitive you just drew. For polygons, the", 652 "image is updated when you press and release the button without", 653 "moving the pointer.", 654 "", 655 "To cancel image drawing, move the pointer back to the", 656 "starting point of the line and release the button.", 657 (char *) NULL, 658 }, 659 *DisplayHelp[] = 660 { 661 "BUTTONS", 662 " The effects of each button press is described below. Three", 663 " buttons are required. If you have a two button mouse,", 664 " button 1 and 3 are returned. Press ALT and button 3 to", 665 " simulate button 2.", 666 "", 667 " 1 Press this button to map or unmap the Command widget.", 668 "", 669 " 2 Press and drag to define a region of the image to", 670 " magnify.", 671 "", 672 " 3 Press and drag to choose from a select set of commands.", 673 " This button behaves differently if the image being", 674 " displayed is a visual image directory. Here, choose a", 675 " particular tile of the directory and press this button and", 676 " drag to select a command from a pop-up menu. Choose from", 677 " these menu items:", 678 "", 679 " Open", 680 " Next", 681 " Former", 682 " Delete", 683 " Update", 684 "", 685 " If you choose Open, the image represented by the tile is", 686 " displayed. To return to the visual image directory, choose", 687 " Next from the Command widget. Next and Former moves to the", 688 " next or former image respectively. Choose Delete to delete", 689 " a particular image tile. Finally, choose Update to", 690 " synchronize all the image tiles with their respective", 691 " images.", 692 "", 693 "COMMAND WIDGET", 694 " The Command widget lists a number of sub-menus and commands.", 695 " They are", 696 "", 697 " File", 698 " Open...", 699 " Next", 700 " Former", 701 " Select...", 702 " Save...", 703 " Print...", 704 " Delete...", 705 " New...", 706 " Visual Directory...", 707 " Quit", 708 " Edit", 709 " Undo", 710 " Redo", 711 " Cut", 712 " Copy", 713 " Paste", 714 " View", 715 " Half Size", 716 " Original Size", 717 " Double Size", 718 " Resize...", 719 " Apply", 720 " Refresh", 721 " Restore", 722 " Transform", 723 " Crop", 724 " Chop", 725 " Flop", 726 " Flip", 727 " Rotate Right", 728 " Rotate Left", 729 " Rotate...", 730 " Shear...", 731 " Roll...", 732 " Trim Edges", 733 " Enhance", 734 " Brightness...", 735 " Saturation...", 736 " Hue...", 737 " Gamma...", 738 " Sharpen...", 739 " Dull", 740 " Contrast Stretch...", 741 " Sigmoidal Contrast...", 742 " Normalize", 743 " Equalize", 744 " Negate", 745 " Grayscale", 746 " Map...", 747 " Quantize...", 748 " Effects", 749 " Despeckle", 750 " Emboss", 751 " Reduce Noise", 752 " Add Noise", 753 " Sharpen...", 754 " Blur...", 755 " Threshold...", 756 " Edge Detect...", 757 " Spread...", 758 " Shade...", 759 " Painting...", 760 " Segment...", 761 " F/X", 762 " Solarize...", 763 " Sepia Tone...", 764 " Swirl...", 765 " Implode...", 766 " Vignette...", 767 " Wave...", 768 " Oil Painting...", 769 " Charcoal Drawing...", 770 " Image Edit", 771 " Annotate...", 772 " Draw...", 773 " Color...", 774 " Matte...", 775 " Composite...", 776 " Add Border...", 777 " Add Frame...", 778 " Comment...", 779 " Launch...", 780 " Region of Interest...", 781 " Miscellany", 782 " Image Info", 783 " Zoom Image", 784 " Show Preview...", 785 " Show Histogram", 786 " Show Matte", 787 " Background...", 788 " Slide Show", 789 " Preferences...", 790 " Help", 791 " Overview", 792 " Browse Documentation", 793 " About Display", 794 "", 795 " Menu items with a indented triangle have a sub-menu. They", 796 " are represented above as the indented items. To access a", 797 " sub-menu item, move the pointer to the appropriate menu and", 798 " press a button and drag. When you find the desired sub-menu", 799 " item, release the button and the command is executed. Move", 800 " the pointer away from the sub-menu if you decide not to", 801 " execute a particular command.", 802 "", 803 "KEYBOARD ACCELERATORS", 804 " Accelerators are one or two key presses that effect a", 805 " particular command. The keyboard accelerators that", 806 " display(1) understands is:", 807 "", 808 " Ctl+O Press to open an image from a file.", 809 "", 810 " space Press to display the next image.", 811 "", 812 " If the image is a multi-paged document such as a Postscript", 813 " document, you can skip ahead several pages by preceding", 814 " this command with a number. For example to display the", 815 " third page beyond the current page, press 3<space>.", 816 "", 817 " backspace Press to display the former image.", 818 "", 819 " If the image is a multi-paged document such as a Postscript", 820 " document, you can skip behind several pages by preceding", 821 " this command with a number. For example to display the", 822 " third page preceding the current page, press 3<backspace>.", 823 "", 824 " Ctl+S Press to write the image to a file.", 825 "", 826 " Ctl+P Press to print the image to a Postscript printer.", 827 "", 828 " Ctl+D Press to delete an image file.", 829 "", 830 " Ctl+N Press to create a blank canvas.", 831 "", 832 " Ctl+Q Press to discard all images and exit program.", 833 "", 834 " Ctl+Z Press to undo last image transformation.", 835 "", 836 " Ctl+R Press to redo last image transformation.", 837 "", 838 " Ctl+X Press to cut a region of the image.", 839 "", 840 " Ctl+C Press to copy a region of the image.", 841 "", 842 " Ctl+V Press to paste a region to the image.", 843 "", 844 " < Press to half the image size.", 845 "", 846 " - Press to return to the original image size.", 847 "", 848 " > Press to double the image size.", 849 "", 850 " % Press to resize the image to a width and height you", 851 " specify.", 852 "", 853 "Cmd-A Press to make any image transformations permanent." 854 "", 855 " By default, any image size transformations are applied", 856 " to the original image to create the image displayed on", 857 " the X server. However, the transformations are not", 858 " permanent (i.e. the original image does not change", 859 " size only the X image does). For example, if you", 860 " press > the X image will appear to double in size,", 861 " but the original image will in fact remain the same size.", 862 " To force the original image to double in size, press >", 863 " followed by Cmd-A.", 864 "", 865 " @ Press to refresh the image window.", 866 "", 867 " C Press to cut out a rectangular region of the image.", 868 "", 869 " [ Press to chop the image.", 870 "", 871 " H Press to flop image in the horizontal direction.", 872 "", 873 " V Press to flip image in the vertical direction.", 874 "", 875 " / Press to rotate the image 90 degrees clockwise.", 876 "", 877 " \\ Press to rotate the image 90 degrees counter-clockwise.", 878 "", 879 " * Press to rotate the image the number of degrees you", 880 " specify.", 881 "", 882 " S Press to shear the image the number of degrees you", 883 " specify.", 884 "", 885 " R Press to roll the image.", 886 "", 887 " T Press to trim the image edges.", 888 "", 889 " Shft-H Press to vary the image hue.", 890 "", 891 " Shft-S Press to vary the color saturation.", 892 "", 893 " Shft-L Press to vary the color brightness.", 894 "", 895 " Shft-G Press to gamma correct the image.", 896 "", 897 " Shft-C Press to sharpen the image contrast.", 898 "", 899 " Shft-Z Press to dull the image contrast.", 900 "", 901 " = Press to perform histogram equalization on the image.", 902 "", 903 " Shft-N Press to perform histogram normalization on the image.", 904 "", 905 " Shft-~ Press to negate the colors of the image.", 906 "", 907 " . Press to convert the image colors to gray.", 908 "", 909 " Shft-# Press to set the maximum number of unique colors in the", 910 " image.", 911 "", 912 " F2 Press to reduce the speckles in an image.", 913 "", 914 " F3 Press to eliminate peak noise from an image.", 915 "", 916 " F4 Press to add noise to an image.", 917 "", 918 " F5 Press to sharpen an image.", 919 "", 920 " F6 Press to delete an image file.", 921 "", 922 " F7 Press to threshold the image.", 923 "", 924 " F8 Press to detect edges within an image.", 925 "", 926 " F9 Press to emboss an image.", 927 "", 928 " F10 Press to displace pixels by a random amount.", 929 "", 930 " F11 Press to negate all pixels above the threshold level.", 931 "", 932 " F12 Press to shade the image using a distant light source.", 933 "", 934 " F13 Press to lighten or darken image edges to create a 3-D effect.", 935 "", 936 " F14 Press to segment the image by color.", 937 "", 938 " Meta-S Press to swirl image pixels about the center.", 939 "", 940 " Meta-I Press to implode image pixels about the center.", 941 "", 942 " Meta-W Press to alter an image along a sine wave.", 943 "", 944 " Meta-P Press to simulate an oil painting.", 945 "", 946 " Meta-C Press to simulate a charcoal drawing.", 947 "", 948 " Alt-A Press to annotate the image with text.", 949 "", 950 " Alt-D Press to draw on an image.", 951 "", 952 " Alt-P Press to edit an image pixel color.", 953 "", 954 " Alt-M Press to edit the image matte information.", 955 "", 956 " Alt-V Press to composite the image with another.", 957 "", 958 " Alt-B Press to add a border to the image.", 959 "", 960 " Alt-F Press to add an ornamental border to the image.", 961 "", 962 " Alt-Shft-!", 963 " Press to add an image comment.", 964 "", 965 " Ctl-A Press to apply image processing techniques to a region", 966 " of interest.", 967 "", 968 " Shft-? Press to display information about the image.", 969 "", 970 " Shft-+ Press to map the zoom image window.", 971 "", 972 " Shft-P Press to preview an image enhancement, effect, or f/x.", 973 "", 974 " F1 Press to display helpful information about display(1).", 975 "", 976 " Find Press to browse documentation about ImageMagick.", 977 "", 978 " 1-9 Press to change the level of magnification.", 979 "", 980 " Use the arrow keys to move the image one pixel up, down,", 981 " left, or right within the magnify window. Be sure to first", 982 " map the magnify window by pressing button 2.", 983 "", 984 " Press ALT and one of the arrow keys to trim off one pixel", 985 " from any side of the image.", 986 (char *) NULL, 987 }, 988 *ImageMatteEditHelp[] = 989 { 990 "Matte information within an image is useful for some", 991 "operations such as image compositing (See IMAGE", 992 "COMPOSITING). This extra channel usually defines a mask", 993 "which represents a sort of a cookie-cutter for the image.", 994 "This the case when matte is opaque (full coverage) for", 995 "pixels inside the shape, zero outside, and between 0 and", 996 "QuantumRange on the boundary.", 997 "", 998 "A small window appears showing the location of the cursor in", 999 "the image window. You are now in matte edit mode. To exit", 1000 "immediately, press Dismiss. In matte edit mode, the Command", 1001 "widget has these options:", 1002 "", 1003 " Method", 1004 " point", 1005 " replace", 1006 " floodfill", 1007 " filltoborder", 1008 " reset", 1009 " Border Color", 1010 " black", 1011 " blue", 1012 " cyan", 1013 " green", 1014 " gray", 1015 " red", 1016 " magenta", 1017 " yellow", 1018 " white", 1019 " Browser...", 1020 " Fuzz", 1021 " 0%", 1022 " 2%", 1023 " 5%", 1024 " 10%", 1025 " 15%", 1026 " Dialog...", 1027 " Matte", 1028 " Opaque", 1029 " Transparent", 1030 " Dialog...", 1031 " Undo", 1032 " Help", 1033 " Dismiss", 1034 "", 1035 "Choose a matte editing method from the Method sub-menu of", 1036 "the Command widget. The point method changes the matte value", 1037 "of any pixel selected with the pointer until the button is", 1038 "is released. The replace method changes the matte value of", 1039 "any pixel that matches the color of the pixel you select with", 1040 "a button press. Floodfill changes the matte value of any pixel", 1041 "that matches the color of the pixel you select with a button", 1042 "press and is a neighbor. Whereas filltoborder changes the matte", 1043 "value any neighbor pixel that is not the border color. Finally", 1044 "reset changes the entire image to the designated matte value.", 1045 "", 1046 "Choose Matte Value and pick Opaque or Transarent. For other values", 1047 "select the Dialog entry. Here a dialog appears requesting a matte", 1048 "value. The value you select is assigned as the opacity value of the", 1049 "selected pixel or pixels.", 1050 "", 1051 "Now, press any button to select a pixel within the image", 1052 "window to change its matte value.", 1053 "", 1054 "If the Magnify widget is mapped, it can be helpful in positioning", 1055 "your pointer within the image (refer to button 2).", 1056 "", 1057 "Matte information is only valid in a DirectClass image.", 1058 "Therefore, any PseudoClass image is promoted to DirectClass", 1059 "(see miff(5)). Note that matte information for PseudoClass", 1060 "is not retained for colormapped X server visuals (e.g.", 1061 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1062 "immediately save your image to a file (refer to Write).", 1063 "Correct matte editing behavior may require a TrueColor or", 1064 "DirectColor visual or a Standard Colormap.", 1065 (char *) NULL, 1066 }, 1067 *ImagePanHelp[] = 1068 { 1069 "When an image exceeds the width or height of the X server", 1070 "screen, display maps a small panning icon. The rectangle", 1071 "within the panning icon shows the area that is currently", 1072 "displayed in the image window. To pan about the image,", 1073 "press any button and drag the pointer within the panning", 1074 "icon. The pan rectangle moves with the pointer and the", 1075 "image window is updated to reflect the location of the", 1076 "rectangle within the panning icon. When you have selected", 1077 "the area of the image you wish to view, release the button.", 1078 "", 1079 "Use the arrow keys to pan the image one pixel up, down,", 1080 "left, or right within the image window.", 1081 "", 1082 "The panning icon is withdrawn if the image becomes smaller", 1083 "than the dimensions of the X server screen.", 1084 (char *) NULL, 1085 }, 1086 *ImagePasteHelp[] = 1087 { 1088 "A small window appears showing the location of the cursor in", 1089 "the image window. You are now in paste mode. To exit", 1090 "immediately, press Dismiss. In paste mode, the Command", 1091 "widget has these options:", 1092 "", 1093 " Operators", 1094 " over", 1095 " in", 1096 " out", 1097 " atop", 1098 " xor", 1099 " plus", 1100 " minus", 1101 " add", 1102 " subtract", 1103 " difference", 1104 " replace", 1105 " Help", 1106 " Dismiss", 1107 "", 1108 "Choose a composite operation from the Operators sub-menu of", 1109 "the Command widget. How each operator behaves is described", 1110 "below. Image window is the image currently displayed on", 1111 "your X server and image is the image obtained with the File", 1112 "Browser widget.", 1113 "", 1114 "Over The result is the union of the two image shapes,", 1115 " with image obscuring image window in the region of", 1116 " overlap.", 1117 "", 1118 "In The result is simply image cut by the shape of", 1119 " image window. None of the image data of image", 1120 " window is in the result.", 1121 "", 1122 "Out The resulting image is image with the shape of", 1123 " image window cut out.", 1124 "", 1125 "Atop The result is the same shape as image image window,", 1126 " with image obscuring image window where the image", 1127 " shapes overlap. Note this differs from over", 1128 " because the portion of image outside image window's", 1129 " shape does not appear in the result.", 1130 "", 1131 "Xor The result is the image data from both image and", 1132 " image window that is outside the overlap region.", 1133 " The overlap region is blank.", 1134 "", 1135 "Plus The result is just the sum of the image data.", 1136 " Output values are cropped to QuantumRange (no overflow).", 1137 " This operation is independent of the matte", 1138 " channels.", 1139 "", 1140 "Minus The result of image - image window, with underflow", 1141 " cropped to zero.", 1142 "", 1143 "Add The result of image + image window, with overflow", 1144 " wrapping around (mod 256).", 1145 "", 1146 "Subtract The result of image - image window, with underflow", 1147 " wrapping around (mod 256). The add and subtract", 1148 " operators can be used to perform reversible", 1149 " transformations.", 1150 "", 1151 "Difference", 1152 " The result of abs(image - image window). This", 1153 " useful for comparing two very similar images.", 1154 "", 1155 "Copy The resulting image is image window replaced with", 1156 " image. Here the matte information is ignored.", 1157 "", 1158 "CopyRed The red layer of the image window is replace with", 1159 " the red layer of the image. The other layers are", 1160 " untouched.", 1161 "", 1162 "CopyGreen", 1163 " The green layer of the image window is replace with", 1164 " the green layer of the image. The other layers are", 1165 " untouched.", 1166 "", 1167 "CopyBlue The blue layer of the image window is replace with", 1168 " the blue layer of the image. The other layers are", 1169 " untouched.", 1170 "", 1171 "CopyOpacity", 1172 " The matte layer of the image window is replace with", 1173 " the matte layer of the image. The other layers are", 1174 " untouched.", 1175 "", 1176 "The image compositor requires a matte, or alpha channel in", 1177 "the image for some operations. This extra channel usually", 1178 "defines a mask which represents a sort of a cookie-cutter", 1179 "for the image. This the case when matte is opaque (full", 1180 "coverage) for pixels inside the shape, zero outside, and", 1181 "between 0 and QuantumRange on the boundary. If image does not", 1182 "have a matte channel, it is initialized with 0 for any pixel", 1183 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1184 "", 1185 "Note that matte information for image window is not retained", 1186 "for colormapped X server visuals (e.g. StaticColor,", 1187 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1188 "behavior may require a TrueColor or DirectColor visual or a", 1189 "Standard Colormap.", 1190 "", 1191 "Choosing a composite operator is optional. The default", 1192 "operator is replace. However, you must choose a location to", 1193 "paste your image and press button 1. Press and hold the", 1194 "button before releasing and an outline of the image will", 1195 "appear to help you identify your location.", 1196 "", 1197 "The actual colors of the pasted image is saved. However,", 1198 "the color that appears in image window may be different.", 1199 "For example, on a monochrome screen image window will appear", 1200 "black or white even though your pasted image may have", 1201 "many colors. If the image is saved to a file it is written", 1202 "with the correct colors. To assure the correct colors are", 1203 "saved in the final image, any PseudoClass image is promoted", 1204 "to DirectClass (see miff(5)). To force a PseudoClass image", 1205 "to remain PseudoClass, use -colors.", 1206 (char *) NULL, 1207 }, 1208 *ImageROIHelp[] = 1209 { 1210 "In region of interest mode, the Command widget has these", 1211 "options:", 1212 "", 1213 " Help", 1214 " Dismiss", 1215 "", 1216 "To define a region of interest, press button 1 and drag.", 1217 "The region of interest is defined by a highlighted rectangle", 1218 "that expands or contracts as it follows the pointer. Once", 1219 "you are satisfied with the region of interest, release the", 1220 "button. You are now in apply mode. In apply mode the", 1221 "Command widget has these options:", 1222 "", 1223 " File", 1224 " Save...", 1225 " Print...", 1226 " Edit", 1227 " Undo", 1228 " Redo", 1229 " Transform", 1230 " Flop", 1231 " Flip", 1232 " Rotate Right", 1233 " Rotate Left", 1234 " Enhance", 1235 " Hue...", 1236 " Saturation...", 1237 " Brightness...", 1238 " Gamma...", 1239 " Spiff", 1240 " Dull", 1241 " Contrast Stretch", 1242 " Sigmoidal Contrast...", 1243 " Normalize", 1244 " Equalize", 1245 " Negate", 1246 " Grayscale", 1247 " Map...", 1248 " Quantize...", 1249 " Effects", 1250 " Despeckle", 1251 " Emboss", 1252 " Reduce Noise", 1253 " Sharpen...", 1254 " Blur...", 1255 " Threshold...", 1256 " Edge Detect...", 1257 " Spread...", 1258 " Shade...", 1259 " Raise...", 1260 " Segment...", 1261 " F/X", 1262 " Solarize...", 1263 " Sepia Tone...", 1264 " Swirl...", 1265 " Implode...", 1266 " Vignette...", 1267 " Wave...", 1268 " Oil Painting...", 1269 " Charcoal Drawing...", 1270 " Miscellany", 1271 " Image Info", 1272 " Zoom Image", 1273 " Show Preview...", 1274 " Show Histogram", 1275 " Show Matte", 1276 " Help", 1277 " Dismiss", 1278 "", 1279 "You can make adjustments to the region of interest by moving", 1280 "the pointer to one of the rectangle corners, pressing a", 1281 "button, and dragging. Finally, choose an image processing", 1282 "technique from the Command widget. You can choose more than", 1283 "one image processing technique to apply to an area.", 1284 "Alternatively, you can move the region of interest before", 1285 "applying another image processing technique. To exit, press", 1286 "Dismiss.", 1287 (char *) NULL, 1288 }, 1289 *ImageRotateHelp[] = 1290 { 1291 "In rotate mode, the Command widget has these options:", 1292 "", 1293 " Pixel Color", 1294 " black", 1295 " blue", 1296 " cyan", 1297 " green", 1298 " gray", 1299 " red", 1300 " magenta", 1301 " yellow", 1302 " white", 1303 " Browser...", 1304 " Direction", 1305 " horizontal", 1306 " vertical", 1307 " Help", 1308 " Dismiss", 1309 "", 1310 "Choose a background color from the Pixel Color sub-menu.", 1311 "Additional background colors can be specified with the color", 1312 "browser. You can change the menu colors by setting the X", 1313 "resources pen1 through pen9.", 1314 "", 1315 "If you choose the color browser and press Grab, you can", 1316 "select the background color by moving the pointer to the", 1317 "desired color on the screen and press any button.", 1318 "", 1319 "Choose a point in the image window and press this button and", 1320 "hold. Next, move the pointer to another location in the", 1321 "image. As you move a line connects the initial location and", 1322 "the pointer. When you release the button, the degree of", 1323 "image rotation is determined by the slope of the line you", 1324 "just drew. The slope is relative to the direction you", 1325 "choose from the Direction sub-menu of the Command widget.", 1326 "", 1327 "To cancel the image rotation, move the pointer back to the", 1328 "starting point of the line and release the button.", 1329 (char *) NULL, 1330 }; 1331 1332/* 1333 Enumeration declarations. 1334*/ 1335typedef enum 1336{ 1337 CopyMode, 1338 CropMode, 1339 CutMode 1340} ClipboardMode; 1341 1342typedef enum 1343{ 1344 OpenCommand, 1345 NextCommand, 1346 FormerCommand, 1347 SelectCommand, 1348 SaveCommand, 1349 PrintCommand, 1350 DeleteCommand, 1351 NewCommand, 1352 VisualDirectoryCommand, 1353 QuitCommand, 1354 UndoCommand, 1355 RedoCommand, 1356 CutCommand, 1357 CopyCommand, 1358 PasteCommand, 1359 HalfSizeCommand, 1360 OriginalSizeCommand, 1361 DoubleSizeCommand, 1362 ResizeCommand, 1363 ApplyCommand, 1364 RefreshCommand, 1365 RestoreCommand, 1366 CropCommand, 1367 ChopCommand, 1368 FlopCommand, 1369 FlipCommand, 1370 RotateRightCommand, 1371 RotateLeftCommand, 1372 RotateCommand, 1373 ShearCommand, 1374 RollCommand, 1375 TrimCommand, 1376 HueCommand, 1377 SaturationCommand, 1378 BrightnessCommand, 1379 GammaCommand, 1380 SpiffCommand, 1381 DullCommand, 1382 ContrastStretchCommand, 1383 SigmoidalContrastCommand, 1384 NormalizeCommand, 1385 EqualizeCommand, 1386 NegateCommand, 1387 GrayscaleCommand, 1388 MapCommand, 1389 QuantizeCommand, 1390 DespeckleCommand, 1391 EmbossCommand, 1392 ReduceNoiseCommand, 1393 AddNoiseCommand, 1394 SharpenCommand, 1395 BlurCommand, 1396 ThresholdCommand, 1397 EdgeDetectCommand, 1398 SpreadCommand, 1399 ShadeCommand, 1400 RaiseCommand, 1401 SegmentCommand, 1402 SolarizeCommand, 1403 SepiaToneCommand, 1404 SwirlCommand, 1405 ImplodeCommand, 1406 VignetteCommand, 1407 WaveCommand, 1408 OilPaintCommand, 1409 CharcoalDrawCommand, 1410 AnnotateCommand, 1411 DrawCommand, 1412 ColorCommand, 1413 MatteCommand, 1414 CompositeCommand, 1415 AddBorderCommand, 1416 AddFrameCommand, 1417 CommentCommand, 1418 LaunchCommand, 1419 RegionofInterestCommand, 1420 ROIHelpCommand, 1421 ROIDismissCommand, 1422 InfoCommand, 1423 ZoomCommand, 1424 ShowPreviewCommand, 1425 ShowHistogramCommand, 1426 ShowMatteCommand, 1427 BackgroundCommand, 1428 SlideShowCommand, 1429 PreferencesCommand, 1430 HelpCommand, 1431 BrowseDocumentationCommand, 1432 VersionCommand, 1433 SaveToUndoBufferCommand, 1434 FreeBuffersCommand, 1435 NullCommand 1436} CommandType; 1437 1438typedef enum 1439{ 1440 AnnotateNameCommand, 1441 AnnotateFontColorCommand, 1442 AnnotateBackgroundColorCommand, 1443 AnnotateRotateCommand, 1444 AnnotateHelpCommand, 1445 AnnotateDismissCommand, 1446 TextHelpCommand, 1447 TextApplyCommand, 1448 ChopDirectionCommand, 1449 ChopHelpCommand, 1450 ChopDismissCommand, 1451 HorizontalChopCommand, 1452 VerticalChopCommand, 1453 ColorEditMethodCommand, 1454 ColorEditColorCommand, 1455 ColorEditBorderCommand, 1456 ColorEditFuzzCommand, 1457 ColorEditUndoCommand, 1458 ColorEditHelpCommand, 1459 ColorEditDismissCommand, 1460 CompositeOperatorsCommand, 1461 CompositeDissolveCommand, 1462 CompositeDisplaceCommand, 1463 CompositeHelpCommand, 1464 CompositeDismissCommand, 1465 CropHelpCommand, 1466 CropDismissCommand, 1467 RectifyCopyCommand, 1468 RectifyHelpCommand, 1469 RectifyDismissCommand, 1470 DrawElementCommand, 1471 DrawColorCommand, 1472 DrawStippleCommand, 1473 DrawWidthCommand, 1474 DrawUndoCommand, 1475 DrawHelpCommand, 1476 DrawDismissCommand, 1477 MatteEditMethod, 1478 MatteEditBorderCommand, 1479 MatteEditFuzzCommand, 1480 MatteEditValueCommand, 1481 MatteEditUndoCommand, 1482 MatteEditHelpCommand, 1483 MatteEditDismissCommand, 1484 PasteOperatorsCommand, 1485 PasteHelpCommand, 1486 PasteDismissCommand, 1487 RotateColorCommand, 1488 RotateDirectionCommand, 1489 RotateCropCommand, 1490 RotateSharpenCommand, 1491 RotateHelpCommand, 1492 RotateDismissCommand, 1493 HorizontalRotateCommand, 1494 VerticalRotateCommand, 1495 TileLoadCommand, 1496 TileNextCommand, 1497 TileFormerCommand, 1498 TileDeleteCommand, 1499 TileUpdateCommand 1500} ModeType; 1501 1502/* 1503 Stipples. 1504*/ 1505#define BricksWidth 20 1506#define BricksHeight 20 1507#define DiagonalWidth 16 1508#define DiagonalHeight 16 1509#define HighlightWidth 8 1510#define HighlightHeight 8 1511#define OpaqueWidth 8 1512#define OpaqueHeight 8 1513#define ScalesWidth 16 1514#define ScalesHeight 16 1515#define ShadowWidth 8 1516#define ShadowHeight 8 1517#define VerticalWidth 16 1518#define VerticalHeight 16 1519#define WavyWidth 16 1520#define WavyHeight 16 1521 1522/* 1523 Constant declaration. 1524*/ 1525static const int 1526 RoiDelta = 8; 1527 1528static const unsigned char 1529 BricksBitmap[] = 1530 { 1531 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1532 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1533 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1534 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1535 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1536 }, 1537 DiagonalBitmap[] = 1538 { 1539 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1540 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1541 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1542 }, 1543 ScalesBitmap[] = 1544 { 1545 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1546 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1547 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1548 }, 1549 VerticalBitmap[] = 1550 { 1551 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1552 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1554 }, 1555 WavyBitmap[] = 1556 { 1557 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1558 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1559 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1560 }; 1561 1562/* 1563 Function prototypes. 1564*/ 1565static CommandType 1566 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1567 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1568 1569static Image 1570 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1571 Image **,ExceptionInfo *), 1572 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1573 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1574 ExceptionInfo *), 1575 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1576 ExceptionInfo *); 1577 1578static MagickBooleanType 1579 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1580 ExceptionInfo *), 1581 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1582 ExceptionInfo *), 1583 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1584 ExceptionInfo *), 1585 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1586 ExceptionInfo *), 1587 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1588 ExceptionInfo *), 1589 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1590 ExceptionInfo *), 1591 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1592 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1593 ExceptionInfo *), 1594 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1595 ExceptionInfo *), 1596 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1597 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1598 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1599 ExceptionInfo *), 1600 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1601 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1602 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1603 1604static void 1605 XDrawPanRectangle(Display *,XWindows *), 1606 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1607 ExceptionInfo *), 1608 XMagnifyImage(Display *,XWindows *,XEvent *), 1609 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1610 XPanImage(Display *,XWindows *,XEvent *), 1611 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1612 const KeySym), 1613 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1614 XScreenEvent(Display *,XWindows *,XEvent *), 1615 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1616 1617/* 1618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1619% % 1620% % 1621% % 1622% D i s p l a y I m a g e s % 1623% % 1624% % 1625% % 1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1627% 1628% DisplayImages() displays an image sequence to any X window screen. It 1629% returns a value other than 0 if successful. Check the exception member 1630% of image to determine the reason for any failure. 1631% 1632% The format of the DisplayImages method is: 1633% 1634% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1635% Image *images,ExceptionInfo *exception) 1636% 1637% A description of each parameter follows: 1638% 1639% o image_info: the image info. 1640% 1641% o image: the image. 1642% 1643% o exception: return any errors or warnings in this structure. 1644% 1645*/ 1646MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1647 Image *images,ExceptionInfo *exception) 1648{ 1649 char 1650 *argv[1]; 1651 1652 Display 1653 *display; 1654 1655 Image 1656 *image; 1657 1658 register ssize_t 1659 i; 1660 1661 size_t 1662 state; 1663 1664 XrmDatabase 1665 resource_database; 1666 1667 XResourceInfo 1668 resource_info; 1669 1670 assert(image_info != (const ImageInfo *) NULL); 1671 assert(image_info->signature == MagickSignature); 1672 assert(images != (Image *) NULL); 1673 assert(images->signature == MagickSignature); 1674 if (images->debug != MagickFalse) 1675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1676 display=XOpenDisplay(image_info->server_name); 1677 if (display == (Display *) NULL) 1678 { 1679 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1680 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1681 return(MagickFalse); 1682 } 1683 if (exception->severity != UndefinedException) 1684 CatchException(exception); 1685 (void) XSetErrorHandler(XError); 1686 resource_database=XGetResourceDatabase(display,GetClientName()); 1687 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1688 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1689 if (image_info->page != (char *) NULL) 1690 resource_info.image_geometry=AcquireString(image_info->page); 1691 resource_info.immutable=MagickTrue; 1692 argv[0]=AcquireString(GetClientName()); 1693 state=DefaultState; 1694 for (i=0; (state & ExitState) == 0; i++) 1695 { 1696 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1697 break; 1698 image=GetImageFromList(images,i % GetImageListLength(images)); 1699 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1700 } 1701 SetErrorHandler((ErrorHandler) NULL); 1702 SetWarningHandler((WarningHandler) NULL); 1703 argv[0]=DestroyString(argv[0]); 1704 (void) XCloseDisplay(display); 1705 XDestroyResourceInfo(&resource_info); 1706 if (exception->severity != UndefinedException) 1707 return(MagickFalse); 1708 return(MagickTrue); 1709} 1710 1711/* 1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1713% % 1714% % 1715% % 1716% R e m o t e D i s p l a y C o m m a n d % 1717% % 1718% % 1719% % 1720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1721% 1722% RemoteDisplayCommand() encourages a remote display program to display the 1723% specified image filename. 1724% 1725% The format of the RemoteDisplayCommand method is: 1726% 1727% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1728% const char *window,const char *filename,ExceptionInfo *exception) 1729% 1730% A description of each parameter follows: 1731% 1732% o image_info: the image info. 1733% 1734% o window: Specifies the name or id of an X window. 1735% 1736% o filename: the name of the image filename to display. 1737% 1738% o exception: return any errors or warnings in this structure. 1739% 1740*/ 1741MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1742 const char *window,const char *filename,ExceptionInfo *exception) 1743{ 1744 Display 1745 *display; 1746 1747 MagickStatusType 1748 status; 1749 1750 assert(image_info != (const ImageInfo *) NULL); 1751 assert(image_info->signature == MagickSignature); 1752 assert(filename != (char *) NULL); 1753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1754 display=XOpenDisplay(image_info->server_name); 1755 if (display == (Display *) NULL) 1756 { 1757 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1758 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1759 return(MagickFalse); 1760 } 1761 (void) XSetErrorHandler(XError); 1762 status=XRemoteCommand(display,window,filename); 1763 (void) XCloseDisplay(display); 1764 return(status != 0 ? MagickTrue : MagickFalse); 1765} 1766 1767/* 1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1769% % 1770% % 1771% % 1772+ X A n n o t a t e E d i t I m a g e % 1773% % 1774% % 1775% % 1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1777% 1778% XAnnotateEditImage() annotates the image with text. 1779% 1780% The format of the XAnnotateEditImage method is: 1781% 1782% MagickBooleanType XAnnotateEditImage(Display *display, 1783% XResourceInfo *resource_info,XWindows *windows,Image *image, 1784% ExceptionInfo *exception) 1785% 1786% A description of each parameter follows: 1787% 1788% o display: Specifies a connection to an X server; returned from 1789% XOpenDisplay. 1790% 1791% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1792% 1793% o windows: Specifies a pointer to a XWindows structure. 1794% 1795% o image: the image; returned from ReadImage. 1796% 1797*/ 1798 1799static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1800{ 1801 if (x > y) 1802 return(x); 1803 return(y); 1804} 1805 1806static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1807{ 1808 if (x < y) 1809 return(x); 1810 return(y); 1811} 1812 1813static MagickBooleanType XAnnotateEditImage(Display *display, 1814 XResourceInfo *resource_info,XWindows *windows,Image *image, 1815 ExceptionInfo *exception) 1816{ 1817 static const char 1818 *AnnotateMenu[] = 1819 { 1820 "Font Name", 1821 "Font Color", 1822 "Box Color", 1823 "Rotate Text", 1824 "Help", 1825 "Dismiss", 1826 (char *) NULL 1827 }, 1828 *TextMenu[] = 1829 { 1830 "Help", 1831 "Apply", 1832 (char *) NULL 1833 }; 1834 1835 static const ModeType 1836 AnnotateCommands[] = 1837 { 1838 AnnotateNameCommand, 1839 AnnotateFontColorCommand, 1840 AnnotateBackgroundColorCommand, 1841 AnnotateRotateCommand, 1842 AnnotateHelpCommand, 1843 AnnotateDismissCommand 1844 }, 1845 TextCommands[] = 1846 { 1847 TextHelpCommand, 1848 TextApplyCommand 1849 }; 1850 1851 static MagickBooleanType 1852 transparent_box = MagickTrue, 1853 transparent_pen = MagickFalse; 1854 1855 static MagickRealType 1856 degrees = 0.0; 1857 1858 static unsigned int 1859 box_id = MaxNumberPens-2, 1860 font_id = 0, 1861 pen_id = 0; 1862 1863 char 1864 command[MaxTextExtent], 1865 text[MaxTextExtent]; 1866 1867 const char 1868 *ColorMenu[MaxNumberPens+1]; 1869 1870 Cursor 1871 cursor; 1872 1873 GC 1874 annotate_context; 1875 1876 int 1877 id, 1878 pen_number, 1879 status, 1880 x, 1881 y; 1882 1883 KeySym 1884 key_symbol; 1885 1886 register char 1887 *p; 1888 1889 register ssize_t 1890 i; 1891 1892 unsigned int 1893 height, 1894 width; 1895 1896 size_t 1897 state; 1898 1899 XAnnotateInfo 1900 *annotate_info, 1901 *previous_info; 1902 1903 XColor 1904 color; 1905 1906 XFontStruct 1907 *font_info; 1908 1909 XEvent 1910 event, 1911 text_event; 1912 1913 /* 1914 Map Command widget. 1915 */ 1916 (void) CloneString(&windows->command.name,"Annotate"); 1917 windows->command.data=4; 1918 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1919 (void) XMapRaised(display,windows->command.id); 1920 XClientMessage(display,windows->image.id,windows->im_protocols, 1921 windows->im_update_widget,CurrentTime); 1922 /* 1923 Track pointer until button 1 is pressed. 1924 */ 1925 XQueryPosition(display,windows->image.id,&x,&y); 1926 (void) XSelectInput(display,windows->image.id, 1927 windows->image.attributes.event_mask | PointerMotionMask); 1928 cursor=XCreateFontCursor(display,XC_left_side); 1929 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1930 state=DefaultState; 1931 do 1932 { 1933 if (windows->info.mapped != MagickFalse) 1934 { 1935 /* 1936 Display pointer position. 1937 */ 1938 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1939 x+windows->image.x,y+windows->image.y); 1940 XInfoWidget(display,windows,text); 1941 } 1942 /* 1943 Wait for next event. 1944 */ 1945 XScreenEvent(display,windows,&event); 1946 if (event.xany.window == windows->command.id) 1947 { 1948 /* 1949 Select a command from the Command widget. 1950 */ 1951 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1952 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1953 if (id < 0) 1954 continue; 1955 switch (AnnotateCommands[id]) 1956 { 1957 case AnnotateNameCommand: 1958 { 1959 const char 1960 *FontMenu[MaxNumberFonts]; 1961 1962 int 1963 font_number; 1964 1965 /* 1966 Initialize menu selections. 1967 */ 1968 for (i=0; i < MaxNumberFonts; i++) 1969 FontMenu[i]=resource_info->font_name[i]; 1970 FontMenu[MaxNumberFonts-2]="Browser..."; 1971 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1972 /* 1973 Select a font name from the pop-up menu. 1974 */ 1975 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1976 (const char **) FontMenu,command); 1977 if (font_number < 0) 1978 break; 1979 if (font_number == (MaxNumberFonts-2)) 1980 { 1981 static char 1982 font_name[MaxTextExtent] = "fixed"; 1983 1984 /* 1985 Select a font name from a browser. 1986 */ 1987 resource_info->font_name[font_number]=font_name; 1988 XFontBrowserWidget(display,windows,"Select",font_name); 1989 if (*font_name == '\0') 1990 break; 1991 } 1992 /* 1993 Initialize font info. 1994 */ 1995 font_info=XLoadQueryFont(display,resource_info->font_name[ 1996 font_number]); 1997 if (font_info == (XFontStruct *) NULL) 1998 { 1999 XNoticeWidget(display,windows,"Unable to load font:", 2000 resource_info->font_name[font_number]); 2001 break; 2002 } 2003 font_id=(unsigned int) font_number; 2004 (void) XFreeFont(display,font_info); 2005 break; 2006 } 2007 case AnnotateFontColorCommand: 2008 { 2009 /* 2010 Initialize menu selections. 2011 */ 2012 for (i=0; i < (int) (MaxNumberPens-2); i++) 2013 ColorMenu[i]=resource_info->pen_colors[i]; 2014 ColorMenu[MaxNumberPens-2]="transparent"; 2015 ColorMenu[MaxNumberPens-1]="Browser..."; 2016 ColorMenu[MaxNumberPens]=(const char *) NULL; 2017 /* 2018 Select a pen color from the pop-up menu. 2019 */ 2020 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2021 (const char **) ColorMenu,command); 2022 if (pen_number < 0) 2023 break; 2024 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2025 MagickFalse; 2026 if (transparent_pen != MagickFalse) 2027 break; 2028 if (pen_number == (MaxNumberPens-1)) 2029 { 2030 static char 2031 color_name[MaxTextExtent] = "gray"; 2032 2033 /* 2034 Select a pen color from a dialog. 2035 */ 2036 resource_info->pen_colors[pen_number]=color_name; 2037 XColorBrowserWidget(display,windows,"Select",color_name); 2038 if (*color_name == '\0') 2039 break; 2040 } 2041 /* 2042 Set pen color. 2043 */ 2044 (void) XParseColor(display,windows->map_info->colormap, 2045 resource_info->pen_colors[pen_number],&color); 2046 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2047 (unsigned int) MaxColors,&color); 2048 windows->pixel_info->pen_colors[pen_number]=color; 2049 pen_id=(unsigned int) pen_number; 2050 break; 2051 } 2052 case AnnotateBackgroundColorCommand: 2053 { 2054 /* 2055 Initialize menu selections. 2056 */ 2057 for (i=0; i < (int) (MaxNumberPens-2); i++) 2058 ColorMenu[i]=resource_info->pen_colors[i]; 2059 ColorMenu[MaxNumberPens-2]="transparent"; 2060 ColorMenu[MaxNumberPens-1]="Browser..."; 2061 ColorMenu[MaxNumberPens]=(const char *) NULL; 2062 /* 2063 Select a pen color from the pop-up menu. 2064 */ 2065 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2066 (const char **) ColorMenu,command); 2067 if (pen_number < 0) 2068 break; 2069 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2070 MagickFalse; 2071 if (transparent_box != MagickFalse) 2072 break; 2073 if (pen_number == (MaxNumberPens-1)) 2074 { 2075 static char 2076 color_name[MaxTextExtent] = "gray"; 2077 2078 /* 2079 Select a pen color from a dialog. 2080 */ 2081 resource_info->pen_colors[pen_number]=color_name; 2082 XColorBrowserWidget(display,windows,"Select",color_name); 2083 if (*color_name == '\0') 2084 break; 2085 } 2086 /* 2087 Set pen color. 2088 */ 2089 (void) XParseColor(display,windows->map_info->colormap, 2090 resource_info->pen_colors[pen_number],&color); 2091 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2092 (unsigned int) MaxColors,&color); 2093 windows->pixel_info->pen_colors[pen_number]=color; 2094 box_id=(unsigned int) pen_number; 2095 break; 2096 } 2097 case AnnotateRotateCommand: 2098 { 2099 int 2100 entry; 2101 2102 static char 2103 angle[MaxTextExtent] = "30.0"; 2104 2105 static const char 2106 *RotateMenu[] = 2107 { 2108 "-90", 2109 "-45", 2110 "-30", 2111 "0", 2112 "30", 2113 "45", 2114 "90", 2115 "180", 2116 "Dialog...", 2117 (char *) NULL, 2118 }; 2119 2120 /* 2121 Select a command from the pop-up menu. 2122 */ 2123 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2124 command); 2125 if (entry < 0) 2126 break; 2127 if (entry != 8) 2128 { 2129 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL); 2130 break; 2131 } 2132 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2133 angle); 2134 if (*angle == '\0') 2135 break; 2136 degrees=InterpretLocaleValue(angle,(char **) NULL); 2137 break; 2138 } 2139 case AnnotateHelpCommand: 2140 { 2141 XTextViewWidget(display,resource_info,windows,MagickFalse, 2142 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2143 break; 2144 } 2145 case AnnotateDismissCommand: 2146 { 2147 /* 2148 Prematurely exit. 2149 */ 2150 state|=EscapeState; 2151 state|=ExitState; 2152 break; 2153 } 2154 default: 2155 break; 2156 } 2157 continue; 2158 } 2159 switch (event.type) 2160 { 2161 case ButtonPress: 2162 { 2163 if (event.xbutton.button != Button1) 2164 break; 2165 if (event.xbutton.window != windows->image.id) 2166 break; 2167 /* 2168 Change to text entering mode. 2169 */ 2170 x=event.xbutton.x; 2171 y=event.xbutton.y; 2172 state|=ExitState; 2173 break; 2174 } 2175 case ButtonRelease: 2176 break; 2177 case Expose: 2178 break; 2179 case KeyPress: 2180 { 2181 if (event.xkey.window != windows->image.id) 2182 break; 2183 /* 2184 Respond to a user key press. 2185 */ 2186 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2187 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2188 switch ((int) key_symbol) 2189 { 2190 case XK_Escape: 2191 case XK_F20: 2192 { 2193 /* 2194 Prematurely exit. 2195 */ 2196 state|=EscapeState; 2197 state|=ExitState; 2198 break; 2199 } 2200 case XK_F1: 2201 case XK_Help: 2202 { 2203 XTextViewWidget(display,resource_info,windows,MagickFalse, 2204 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2205 break; 2206 } 2207 default: 2208 { 2209 (void) XBell(display,0); 2210 break; 2211 } 2212 } 2213 break; 2214 } 2215 case MotionNotify: 2216 { 2217 /* 2218 Map and unmap Info widget as cursor crosses its boundaries. 2219 */ 2220 x=event.xmotion.x; 2221 y=event.xmotion.y; 2222 if (windows->info.mapped != MagickFalse) 2223 { 2224 if ((x < (int) (windows->info.x+windows->info.width)) && 2225 (y < (int) (windows->info.y+windows->info.height))) 2226 (void) XWithdrawWindow(display,windows->info.id, 2227 windows->info.screen); 2228 } 2229 else 2230 if ((x > (int) (windows->info.x+windows->info.width)) || 2231 (y > (int) (windows->info.y+windows->info.height))) 2232 (void) XMapWindow(display,windows->info.id); 2233 break; 2234 } 2235 default: 2236 break; 2237 } 2238 } while ((state & ExitState) == 0); 2239 (void) XSelectInput(display,windows->image.id, 2240 windows->image.attributes.event_mask); 2241 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2242 if ((state & EscapeState) != 0) 2243 return(MagickTrue); 2244 /* 2245 Set font info and check boundary conditions. 2246 */ 2247 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2248 if (font_info == (XFontStruct *) NULL) 2249 { 2250 XNoticeWidget(display,windows,"Unable to load font:", 2251 resource_info->font_name[font_id]); 2252 font_info=windows->font_info; 2253 } 2254 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2255 x=(int) windows->image.width-font_info->max_bounds.width; 2256 if (y < (int) (font_info->ascent+font_info->descent)) 2257 y=(int) font_info->ascent+font_info->descent; 2258 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2259 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2260 return(MagickFalse); 2261 /* 2262 Initialize annotate structure. 2263 */ 2264 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2265 if (annotate_info == (XAnnotateInfo *) NULL) 2266 return(MagickFalse); 2267 XGetAnnotateInfo(annotate_info); 2268 annotate_info->x=x; 2269 annotate_info->y=y; 2270 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2271 annotate_info->stencil=OpaqueStencil; 2272 else 2273 if (transparent_box == MagickFalse) 2274 annotate_info->stencil=BackgroundStencil; 2275 else 2276 annotate_info->stencil=ForegroundStencil; 2277 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2278 annotate_info->degrees=degrees; 2279 annotate_info->font_info=font_info; 2280 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2281 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2282 sizeof(*annotate_info->text)); 2283 if (annotate_info->text == (char *) NULL) 2284 return(MagickFalse); 2285 /* 2286 Create cursor and set graphic context. 2287 */ 2288 cursor=XCreateFontCursor(display,XC_pencil); 2289 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2290 annotate_context=windows->image.annotate_context; 2291 (void) XSetFont(display,annotate_context,font_info->fid); 2292 (void) XSetBackground(display,annotate_context, 2293 windows->pixel_info->pen_colors[box_id].pixel); 2294 (void) XSetForeground(display,annotate_context, 2295 windows->pixel_info->pen_colors[pen_id].pixel); 2296 /* 2297 Begin annotating the image with text. 2298 */ 2299 (void) CloneString(&windows->command.name,"Text"); 2300 windows->command.data=0; 2301 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2302 state=DefaultState; 2303 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2304 text_event.xexpose.width=(int) font_info->max_bounds.width; 2305 text_event.xexpose.height=font_info->max_bounds.ascent+ 2306 font_info->max_bounds.descent; 2307 p=annotate_info->text; 2308 do 2309 { 2310 /* 2311 Display text cursor. 2312 */ 2313 *p='\0'; 2314 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2315 /* 2316 Wait for next event. 2317 */ 2318 XScreenEvent(display,windows,&event); 2319 if (event.xany.window == windows->command.id) 2320 { 2321 /* 2322 Select a command from the Command widget. 2323 */ 2324 (void) XSetBackground(display,annotate_context, 2325 windows->pixel_info->background_color.pixel); 2326 (void) XSetForeground(display,annotate_context, 2327 windows->pixel_info->foreground_color.pixel); 2328 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2329 (void) XSetBackground(display,annotate_context, 2330 windows->pixel_info->pen_colors[box_id].pixel); 2331 (void) XSetForeground(display,annotate_context, 2332 windows->pixel_info->pen_colors[pen_id].pixel); 2333 if (id < 0) 2334 continue; 2335 switch (TextCommands[id]) 2336 { 2337 case TextHelpCommand: 2338 { 2339 XTextViewWidget(display,resource_info,windows,MagickFalse, 2340 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2341 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2342 break; 2343 } 2344 case TextApplyCommand: 2345 { 2346 /* 2347 Finished annotating. 2348 */ 2349 annotate_info->width=(unsigned int) XTextWidth(font_info, 2350 annotate_info->text,(int) strlen(annotate_info->text)); 2351 XRefreshWindow(display,&windows->image,&text_event); 2352 state|=ExitState; 2353 break; 2354 } 2355 default: 2356 break; 2357 } 2358 continue; 2359 } 2360 /* 2361 Erase text cursor. 2362 */ 2363 text_event.xexpose.x=x; 2364 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2365 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2366 (unsigned int) text_event.xexpose.width,(unsigned int) 2367 text_event.xexpose.height,MagickFalse); 2368 XRefreshWindow(display,&windows->image,&text_event); 2369 switch (event.type) 2370 { 2371 case ButtonPress: 2372 { 2373 if (event.xbutton.window != windows->image.id) 2374 break; 2375 if (event.xbutton.button == Button2) 2376 { 2377 /* 2378 Request primary selection. 2379 */ 2380 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2381 windows->image.id,CurrentTime); 2382 break; 2383 } 2384 break; 2385 } 2386 case Expose: 2387 { 2388 if (event.xexpose.count == 0) 2389 { 2390 XAnnotateInfo 2391 *text_info; 2392 2393 /* 2394 Refresh Image window. 2395 */ 2396 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2397 text_info=annotate_info; 2398 while (text_info != (XAnnotateInfo *) NULL) 2399 { 2400 if (annotate_info->stencil == ForegroundStencil) 2401 (void) XDrawString(display,windows->image.id,annotate_context, 2402 text_info->x,text_info->y,text_info->text, 2403 (int) strlen(text_info->text)); 2404 else 2405 (void) XDrawImageString(display,windows->image.id, 2406 annotate_context,text_info->x,text_info->y,text_info->text, 2407 (int) strlen(text_info->text)); 2408 text_info=text_info->previous; 2409 } 2410 (void) XDrawString(display,windows->image.id,annotate_context, 2411 x,y,"_",1); 2412 } 2413 break; 2414 } 2415 case KeyPress: 2416 { 2417 int 2418 length; 2419 2420 if (event.xkey.window != windows->image.id) 2421 break; 2422 /* 2423 Respond to a user key press. 2424 */ 2425 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2426 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2427 *(command+length)='\0'; 2428 if (((event.xkey.state & ControlMask) != 0) || 2429 ((event.xkey.state & Mod1Mask) != 0)) 2430 state|=ModifierState; 2431 if ((state & ModifierState) != 0) 2432 switch ((int) key_symbol) 2433 { 2434 case XK_u: 2435 case XK_U: 2436 { 2437 key_symbol=DeleteCommand; 2438 break; 2439 } 2440 default: 2441 break; 2442 } 2443 switch ((int) key_symbol) 2444 { 2445 case XK_BackSpace: 2446 { 2447 /* 2448 Erase one character. 2449 */ 2450 if (p == annotate_info->text) 2451 { 2452 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2453 break; 2454 else 2455 { 2456 /* 2457 Go to end of the previous line of text. 2458 */ 2459 annotate_info=annotate_info->previous; 2460 p=annotate_info->text; 2461 x=annotate_info->x+annotate_info->width; 2462 y=annotate_info->y; 2463 if (annotate_info->width != 0) 2464 p+=strlen(annotate_info->text); 2465 break; 2466 } 2467 } 2468 p--; 2469 x-=XTextWidth(font_info,p,1); 2470 text_event.xexpose.x=x; 2471 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2472 XRefreshWindow(display,&windows->image,&text_event); 2473 break; 2474 } 2475 case XK_bracketleft: 2476 { 2477 key_symbol=XK_Escape; 2478 break; 2479 } 2480 case DeleteCommand: 2481 { 2482 /* 2483 Erase the entire line of text. 2484 */ 2485 while (p != annotate_info->text) 2486 { 2487 p--; 2488 x-=XTextWidth(font_info,p,1); 2489 text_event.xexpose.x=x; 2490 XRefreshWindow(display,&windows->image,&text_event); 2491 } 2492 break; 2493 } 2494 case XK_Escape: 2495 case XK_F20: 2496 { 2497 /* 2498 Finished annotating. 2499 */ 2500 annotate_info->width=(unsigned int) XTextWidth(font_info, 2501 annotate_info->text,(int) strlen(annotate_info->text)); 2502 XRefreshWindow(display,&windows->image,&text_event); 2503 state|=ExitState; 2504 break; 2505 } 2506 default: 2507 { 2508 /* 2509 Draw a single character on the Image window. 2510 */ 2511 if ((state & ModifierState) != 0) 2512 break; 2513 if (*command == '\0') 2514 break; 2515 *p=(*command); 2516 if (annotate_info->stencil == ForegroundStencil) 2517 (void) XDrawString(display,windows->image.id,annotate_context, 2518 x,y,p,1); 2519 else 2520 (void) XDrawImageString(display,windows->image.id, 2521 annotate_context,x,y,p,1); 2522 x+=XTextWidth(font_info,p,1); 2523 p++; 2524 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2525 break; 2526 } 2527 case XK_Return: 2528 case XK_KP_Enter: 2529 { 2530 /* 2531 Advance to the next line of text. 2532 */ 2533 *p='\0'; 2534 annotate_info->width=(unsigned int) XTextWidth(font_info, 2535 annotate_info->text,(int) strlen(annotate_info->text)); 2536 if (annotate_info->next != (XAnnotateInfo *) NULL) 2537 { 2538 /* 2539 Line of text already exists. 2540 */ 2541 annotate_info=annotate_info->next; 2542 x=annotate_info->x; 2543 y=annotate_info->y; 2544 p=annotate_info->text; 2545 break; 2546 } 2547 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2548 sizeof(*annotate_info->next)); 2549 if (annotate_info->next == (XAnnotateInfo *) NULL) 2550 return(MagickFalse); 2551 *annotate_info->next=(*annotate_info); 2552 annotate_info->next->previous=annotate_info; 2553 annotate_info=annotate_info->next; 2554 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2555 windows->image.width/MagickMax((ssize_t) 2556 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2557 if (annotate_info->text == (char *) NULL) 2558 return(MagickFalse); 2559 annotate_info->y+=annotate_info->height; 2560 if (annotate_info->y > (int) windows->image.height) 2561 annotate_info->y=(int) annotate_info->height; 2562 annotate_info->next=(XAnnotateInfo *) NULL; 2563 x=annotate_info->x; 2564 y=annotate_info->y; 2565 p=annotate_info->text; 2566 break; 2567 } 2568 } 2569 break; 2570 } 2571 case KeyRelease: 2572 { 2573 /* 2574 Respond to a user key release. 2575 */ 2576 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2577 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2578 state&=(~ModifierState); 2579 break; 2580 } 2581 case SelectionNotify: 2582 { 2583 Atom 2584 type; 2585 2586 int 2587 format; 2588 2589 unsigned char 2590 *data; 2591 2592 unsigned long 2593 after, 2594 length; 2595 2596 /* 2597 Obtain response from primary selection. 2598 */ 2599 if (event.xselection.property == (Atom) None) 2600 break; 2601 status=XGetWindowProperty(display,event.xselection.requestor, 2602 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2603 &type,&format,&length,&after,&data); 2604 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2605 (length == 0)) 2606 break; 2607 /* 2608 Annotate Image window with primary selection. 2609 */ 2610 for (i=0; i < (ssize_t) length; i++) 2611 { 2612 if ((char) data[i] != '\n') 2613 { 2614 /* 2615 Draw a single character on the Image window. 2616 */ 2617 *p=(char) data[i]; 2618 (void) XDrawString(display,windows->image.id,annotate_context, 2619 x,y,p,1); 2620 x+=XTextWidth(font_info,p,1); 2621 p++; 2622 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2623 continue; 2624 } 2625 /* 2626 Advance to the next line of text. 2627 */ 2628 *p='\0'; 2629 annotate_info->width=(unsigned int) XTextWidth(font_info, 2630 annotate_info->text,(int) strlen(annotate_info->text)); 2631 if (annotate_info->next != (XAnnotateInfo *) NULL) 2632 { 2633 /* 2634 Line of text already exists. 2635 */ 2636 annotate_info=annotate_info->next; 2637 x=annotate_info->x; 2638 y=annotate_info->y; 2639 p=annotate_info->text; 2640 continue; 2641 } 2642 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2643 sizeof(*annotate_info->next)); 2644 if (annotate_info->next == (XAnnotateInfo *) NULL) 2645 return(MagickFalse); 2646 *annotate_info->next=(*annotate_info); 2647 annotate_info->next->previous=annotate_info; 2648 annotate_info=annotate_info->next; 2649 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2650 windows->image.width/MagickMax((ssize_t) 2651 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2652 if (annotate_info->text == (char *) NULL) 2653 return(MagickFalse); 2654 annotate_info->y+=annotate_info->height; 2655 if (annotate_info->y > (int) windows->image.height) 2656 annotate_info->y=(int) annotate_info->height; 2657 annotate_info->next=(XAnnotateInfo *) NULL; 2658 x=annotate_info->x; 2659 y=annotate_info->y; 2660 p=annotate_info->text; 2661 } 2662 (void) XFree((void *) data); 2663 break; 2664 } 2665 default: 2666 break; 2667 } 2668 } while ((state & ExitState) == 0); 2669 (void) XFreeCursor(display,cursor); 2670 /* 2671 Annotation is relative to image configuration. 2672 */ 2673 width=(unsigned int) image->columns; 2674 height=(unsigned int) image->rows; 2675 x=0; 2676 y=0; 2677 if (windows->image.crop_geometry != (char *) NULL) 2678 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2679 /* 2680 Initialize annotated image. 2681 */ 2682 XSetCursorState(display,windows,MagickTrue); 2683 XCheckRefreshWindows(display,windows); 2684 while (annotate_info != (XAnnotateInfo *) NULL) 2685 { 2686 if (annotate_info->width == 0) 2687 { 2688 /* 2689 No text on this line-- go to the next line of text. 2690 */ 2691 previous_info=annotate_info->previous; 2692 annotate_info->text=(char *) 2693 RelinquishMagickMemory(annotate_info->text); 2694 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2695 annotate_info=previous_info; 2696 continue; 2697 } 2698 /* 2699 Determine pixel index for box and pen color. 2700 */ 2701 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2702 if (windows->pixel_info->colors != 0) 2703 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2704 if (windows->pixel_info->pixels[i] == 2705 windows->pixel_info->pen_colors[box_id].pixel) 2706 { 2707 windows->pixel_info->box_index=(unsigned short) i; 2708 break; 2709 } 2710 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2711 if (windows->pixel_info->colors != 0) 2712 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2713 if (windows->pixel_info->pixels[i] == 2714 windows->pixel_info->pen_colors[pen_id].pixel) 2715 { 2716 windows->pixel_info->pen_index=(unsigned short) i; 2717 break; 2718 } 2719 /* 2720 Define the annotate geometry string. 2721 */ 2722 annotate_info->x=(int) 2723 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2724 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2725 windows->image.y)/windows->image.ximage->height; 2726 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2727 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2728 height*annotate_info->height/windows->image.ximage->height, 2729 annotate_info->x+x,annotate_info->y+y); 2730 /* 2731 Annotate image with text. 2732 */ 2733 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2734 exception); 2735 if (status == 0) 2736 return(MagickFalse); 2737 /* 2738 Free up memory. 2739 */ 2740 previous_info=annotate_info->previous; 2741 annotate_info->text=DestroyString(annotate_info->text); 2742 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2743 annotate_info=previous_info; 2744 } 2745 (void) XSetForeground(display,annotate_context, 2746 windows->pixel_info->foreground_color.pixel); 2747 (void) XSetBackground(display,annotate_context, 2748 windows->pixel_info->background_color.pixel); 2749 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2750 XSetCursorState(display,windows,MagickFalse); 2751 (void) XFreeFont(display,font_info); 2752 /* 2753 Update image configuration. 2754 */ 2755 XConfigureImageColormap(display,resource_info,windows,image); 2756 (void) XConfigureImage(display,resource_info,windows,image,exception); 2757 return(MagickTrue); 2758} 2759 2760/* 2761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2762% % 2763% % 2764% % 2765+ X B a c k g r o u n d I m a g e % 2766% % 2767% % 2768% % 2769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2770% 2771% XBackgroundImage() displays the image in the background of a window. 2772% 2773% The format of the XBackgroundImage method is: 2774% 2775% MagickBooleanType XBackgroundImage(Display *display, 2776% XResourceInfo *resource_info,XWindows *windows,Image **image, 2777% ExceptionInfo *exception) 2778% 2779% A description of each parameter follows: 2780% 2781% o display: Specifies a connection to an X server; returned from 2782% XOpenDisplay. 2783% 2784% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2785% 2786% o windows: Specifies a pointer to a XWindows structure. 2787% 2788% o image: the image. 2789% 2790% o exception: return any errors or warnings in this structure. 2791% 2792*/ 2793static MagickBooleanType XBackgroundImage(Display *display, 2794 XResourceInfo *resource_info,XWindows *windows,Image **image, 2795 ExceptionInfo *exception) 2796{ 2797#define BackgroundImageTag "Background/Image" 2798 2799 int 2800 status; 2801 2802 static char 2803 window_id[MaxTextExtent] = "root"; 2804 2805 XResourceInfo 2806 background_resources; 2807 2808 /* 2809 Put image in background. 2810 */ 2811 status=XDialogWidget(display,windows,"Background", 2812 "Enter window id (id 0x00 selects window with pointer):",window_id); 2813 if (*window_id == '\0') 2814 return(MagickFalse); 2815 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2816 exception); 2817 XInfoWidget(display,windows,BackgroundImageTag); 2818 XSetCursorState(display,windows,MagickTrue); 2819 XCheckRefreshWindows(display,windows); 2820 background_resources=(*resource_info); 2821 background_resources.window_id=window_id; 2822 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2823 status=XDisplayBackgroundImage(display,&background_resources,*image, 2824 exception); 2825 if (status != MagickFalse) 2826 XClientMessage(display,windows->image.id,windows->im_protocols, 2827 windows->im_retain_colors,CurrentTime); 2828 XSetCursorState(display,windows,MagickFalse); 2829 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2830 exception); 2831 return(MagickTrue); 2832} 2833 2834/* 2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2836% % 2837% % 2838% % 2839+ X C h o p I m a g e % 2840% % 2841% % 2842% % 2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2844% 2845% XChopImage() chops the X image. 2846% 2847% The format of the XChopImage method is: 2848% 2849% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2850% XWindows *windows,Image **image,ExceptionInfo *exception) 2851% 2852% A description of each parameter follows: 2853% 2854% o display: Specifies a connection to an X server; returned from 2855% XOpenDisplay. 2856% 2857% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2858% 2859% o windows: Specifies a pointer to a XWindows structure. 2860% 2861% o image: the image. 2862% 2863% o exception: return any errors or warnings in this structure. 2864% 2865*/ 2866static MagickBooleanType XChopImage(Display *display, 2867 XResourceInfo *resource_info,XWindows *windows,Image **image, 2868 ExceptionInfo *exception) 2869{ 2870 static const char 2871 *ChopMenu[] = 2872 { 2873 "Direction", 2874 "Help", 2875 "Dismiss", 2876 (char *) NULL 2877 }; 2878 2879 static ModeType 2880 direction = HorizontalChopCommand; 2881 2882 static const ModeType 2883 ChopCommands[] = 2884 { 2885 ChopDirectionCommand, 2886 ChopHelpCommand, 2887 ChopDismissCommand 2888 }, 2889 DirectionCommands[] = 2890 { 2891 HorizontalChopCommand, 2892 VerticalChopCommand 2893 }; 2894 2895 char 2896 text[MaxTextExtent]; 2897 2898 Image 2899 *chop_image; 2900 2901 int 2902 id, 2903 x, 2904 y; 2905 2906 MagickRealType 2907 scale_factor; 2908 2909 RectangleInfo 2910 chop_info; 2911 2912 unsigned int 2913 distance, 2914 height, 2915 width; 2916 2917 size_t 2918 state; 2919 2920 XEvent 2921 event; 2922 2923 XSegment 2924 segment_info; 2925 2926 /* 2927 Map Command widget. 2928 */ 2929 (void) CloneString(&windows->command.name,"Chop"); 2930 windows->command.data=1; 2931 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2932 (void) XMapRaised(display,windows->command.id); 2933 XClientMessage(display,windows->image.id,windows->im_protocols, 2934 windows->im_update_widget,CurrentTime); 2935 /* 2936 Track pointer until button 1 is pressed. 2937 */ 2938 XQueryPosition(display,windows->image.id,&x,&y); 2939 (void) XSelectInput(display,windows->image.id, 2940 windows->image.attributes.event_mask | PointerMotionMask); 2941 state=DefaultState; 2942 do 2943 { 2944 if (windows->info.mapped != MagickFalse) 2945 { 2946 /* 2947 Display pointer position. 2948 */ 2949 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2950 x+windows->image.x,y+windows->image.y); 2951 XInfoWidget(display,windows,text); 2952 } 2953 /* 2954 Wait for next event. 2955 */ 2956 XScreenEvent(display,windows,&event); 2957 if (event.xany.window == windows->command.id) 2958 { 2959 /* 2960 Select a command from the Command widget. 2961 */ 2962 id=XCommandWidget(display,windows,ChopMenu,&event); 2963 if (id < 0) 2964 continue; 2965 switch (ChopCommands[id]) 2966 { 2967 case ChopDirectionCommand: 2968 { 2969 char 2970 command[MaxTextExtent]; 2971 2972 static const char 2973 *Directions[] = 2974 { 2975 "horizontal", 2976 "vertical", 2977 (char *) NULL, 2978 }; 2979 2980 /* 2981 Select a command from the pop-up menu. 2982 */ 2983 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2984 if (id >= 0) 2985 direction=DirectionCommands[id]; 2986 break; 2987 } 2988 case ChopHelpCommand: 2989 { 2990 XTextViewWidget(display,resource_info,windows,MagickFalse, 2991 "Help Viewer - Image Chop",ImageChopHelp); 2992 break; 2993 } 2994 case ChopDismissCommand: 2995 { 2996 /* 2997 Prematurely exit. 2998 */ 2999 state|=EscapeState; 3000 state|=ExitState; 3001 break; 3002 } 3003 default: 3004 break; 3005 } 3006 continue; 3007 } 3008 switch (event.type) 3009 { 3010 case ButtonPress: 3011 { 3012 if (event.xbutton.button != Button1) 3013 break; 3014 if (event.xbutton.window != windows->image.id) 3015 break; 3016 /* 3017 User has committed to start point of chopping line. 3018 */ 3019 segment_info.x1=(short int) event.xbutton.x; 3020 segment_info.x2=(short int) event.xbutton.x; 3021 segment_info.y1=(short int) event.xbutton.y; 3022 segment_info.y2=(short int) event.xbutton.y; 3023 state|=ExitState; 3024 break; 3025 } 3026 case ButtonRelease: 3027 break; 3028 case Expose: 3029 break; 3030 case KeyPress: 3031 { 3032 char 3033 command[MaxTextExtent]; 3034 3035 KeySym 3036 key_symbol; 3037 3038 if (event.xkey.window != windows->image.id) 3039 break; 3040 /* 3041 Respond to a user key press. 3042 */ 3043 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3044 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3045 switch ((int) key_symbol) 3046 { 3047 case XK_Escape: 3048 case XK_F20: 3049 { 3050 /* 3051 Prematurely exit. 3052 */ 3053 state|=EscapeState; 3054 state|=ExitState; 3055 break; 3056 } 3057 case XK_F1: 3058 case XK_Help: 3059 { 3060 (void) XSetFunction(display,windows->image.highlight_context, 3061 GXcopy); 3062 XTextViewWidget(display,resource_info,windows,MagickFalse, 3063 "Help Viewer - Image Chop",ImageChopHelp); 3064 (void) XSetFunction(display,windows->image.highlight_context, 3065 GXinvert); 3066 break; 3067 } 3068 default: 3069 { 3070 (void) XBell(display,0); 3071 break; 3072 } 3073 } 3074 break; 3075 } 3076 case MotionNotify: 3077 { 3078 /* 3079 Map and unmap Info widget as text cursor crosses its boundaries. 3080 */ 3081 x=event.xmotion.x; 3082 y=event.xmotion.y; 3083 if (windows->info.mapped != MagickFalse) 3084 { 3085 if ((x < (int) (windows->info.x+windows->info.width)) && 3086 (y < (int) (windows->info.y+windows->info.height))) 3087 (void) XWithdrawWindow(display,windows->info.id, 3088 windows->info.screen); 3089 } 3090 else 3091 if ((x > (int) (windows->info.x+windows->info.width)) || 3092 (y > (int) (windows->info.y+windows->info.height))) 3093 (void) XMapWindow(display,windows->info.id); 3094 } 3095 } 3096 } while ((state & ExitState) == 0); 3097 (void) XSelectInput(display,windows->image.id, 3098 windows->image.attributes.event_mask); 3099 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3100 if ((state & EscapeState) != 0) 3101 return(MagickTrue); 3102 /* 3103 Draw line as pointer moves until the mouse button is released. 3104 */ 3105 chop_info.width=0; 3106 chop_info.height=0; 3107 chop_info.x=0; 3108 chop_info.y=0; 3109 distance=0; 3110 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3111 state=DefaultState; 3112 do 3113 { 3114 if (distance > 9) 3115 { 3116 /* 3117 Display info and draw chopping line. 3118 */ 3119 if (windows->info.mapped == MagickFalse) 3120 (void) XMapWindow(display,windows->info.id); 3121 (void) FormatLocaleString(text,MaxTextExtent, 3122 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3123 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3124 XInfoWidget(display,windows,text); 3125 XHighlightLine(display,windows->image.id, 3126 windows->image.highlight_context,&segment_info); 3127 } 3128 else 3129 if (windows->info.mapped != MagickFalse) 3130 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3131 /* 3132 Wait for next event. 3133 */ 3134 XScreenEvent(display,windows,&event); 3135 if (distance > 9) 3136 XHighlightLine(display,windows->image.id, 3137 windows->image.highlight_context,&segment_info); 3138 switch (event.type) 3139 { 3140 case ButtonPress: 3141 { 3142 segment_info.x2=(short int) event.xmotion.x; 3143 segment_info.y2=(short int) event.xmotion.y; 3144 break; 3145 } 3146 case ButtonRelease: 3147 { 3148 /* 3149 User has committed to chopping line. 3150 */ 3151 segment_info.x2=(short int) event.xbutton.x; 3152 segment_info.y2=(short int) event.xbutton.y; 3153 state|=ExitState; 3154 break; 3155 } 3156 case Expose: 3157 break; 3158 case MotionNotify: 3159 { 3160 segment_info.x2=(short int) event.xmotion.x; 3161 segment_info.y2=(short int) event.xmotion.y; 3162 } 3163 default: 3164 break; 3165 } 3166 /* 3167 Check boundary conditions. 3168 */ 3169 if (segment_info.x2 < 0) 3170 segment_info.x2=0; 3171 else 3172 if (segment_info.x2 > windows->image.ximage->width) 3173 segment_info.x2=windows->image.ximage->width; 3174 if (segment_info.y2 < 0) 3175 segment_info.y2=0; 3176 else 3177 if (segment_info.y2 > windows->image.ximage->height) 3178 segment_info.y2=windows->image.ximage->height; 3179 distance=(unsigned int) 3180 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3181 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3182 /* 3183 Compute chopping geometry. 3184 */ 3185 if (direction == HorizontalChopCommand) 3186 { 3187 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3188 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3189 chop_info.height=0; 3190 chop_info.y=0; 3191 if (segment_info.x1 > (int) segment_info.x2) 3192 { 3193 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3194 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3195 } 3196 } 3197 else 3198 { 3199 chop_info.width=0; 3200 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3201 chop_info.x=0; 3202 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3203 if (segment_info.y1 > segment_info.y2) 3204 { 3205 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3206 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3207 } 3208 } 3209 } while ((state & ExitState) == 0); 3210 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3211 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3212 if (distance <= 9) 3213 return(MagickTrue); 3214 /* 3215 Image chopping is relative to image configuration. 3216 */ 3217 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3218 exception); 3219 XSetCursorState(display,windows,MagickTrue); 3220 XCheckRefreshWindows(display,windows); 3221 windows->image.window_changes.width=windows->image.ximage->width- 3222 (unsigned int) chop_info.width; 3223 windows->image.window_changes.height=windows->image.ximage->height- 3224 (unsigned int) chop_info.height; 3225 width=(unsigned int) (*image)->columns; 3226 height=(unsigned int) (*image)->rows; 3227 x=0; 3228 y=0; 3229 if (windows->image.crop_geometry != (char *) NULL) 3230 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3231 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3232 chop_info.x+=x; 3233 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3234 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3235 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3236 chop_info.y+=y; 3237 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3238 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3239 /* 3240 Chop image. 3241 */ 3242 chop_image=ChopImage(*image,&chop_info,exception); 3243 XSetCursorState(display,windows,MagickFalse); 3244 if (chop_image == (Image *) NULL) 3245 return(MagickFalse); 3246 *image=DestroyImage(*image); 3247 *image=chop_image; 3248 /* 3249 Update image configuration. 3250 */ 3251 XConfigureImageColormap(display,resource_info,windows,*image); 3252 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3253 return(MagickTrue); 3254} 3255 3256/* 3257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3258% % 3259% % 3260% % 3261+ X C o l o r E d i t I m a g e % 3262% % 3263% % 3264% % 3265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3266% 3267% XColorEditImage() allows the user to interactively change the color of one 3268% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3269% 3270% The format of the XColorEditImage method is: 3271% 3272% MagickBooleanType XColorEditImage(Display *display, 3273% XResourceInfo *resource_info,XWindows *windows,Image **image, 3274% ExceptionInfo *exception) 3275% 3276% A description of each parameter follows: 3277% 3278% o display: Specifies a connection to an X server; returned from 3279% XOpenDisplay. 3280% 3281% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3282% 3283% o windows: Specifies a pointer to a XWindows structure. 3284% 3285% o image: the image; returned from ReadImage. 3286% 3287% o exception: return any errors or warnings in this structure. 3288% 3289*/ 3290static MagickBooleanType XColorEditImage(Display *display, 3291 XResourceInfo *resource_info,XWindows *windows,Image **image, 3292 ExceptionInfo *exception) 3293{ 3294 static const char 3295 *ColorEditMenu[] = 3296 { 3297 "Method", 3298 "Pixel Color", 3299 "Border Color", 3300 "Fuzz", 3301 "Undo", 3302 "Help", 3303 "Dismiss", 3304 (char *) NULL 3305 }; 3306 3307 static const ModeType 3308 ColorEditCommands[] = 3309 { 3310 ColorEditMethodCommand, 3311 ColorEditColorCommand, 3312 ColorEditBorderCommand, 3313 ColorEditFuzzCommand, 3314 ColorEditUndoCommand, 3315 ColorEditHelpCommand, 3316 ColorEditDismissCommand 3317 }; 3318 3319 static PaintMethod 3320 method = PointMethod; 3321 3322 static unsigned int 3323 pen_id = 0; 3324 3325 static XColor 3326 border_color = { 0, 0, 0, 0, 0, 0 }; 3327 3328 char 3329 command[MaxTextExtent], 3330 text[MaxTextExtent]; 3331 3332 Cursor 3333 cursor; 3334 3335 int 3336 entry, 3337 id, 3338 x, 3339 x_offset, 3340 y, 3341 y_offset; 3342 3343 register Quantum 3344 *q; 3345 3346 register ssize_t 3347 i; 3348 3349 unsigned int 3350 height, 3351 width; 3352 3353 size_t 3354 state; 3355 3356 XColor 3357 color; 3358 3359 XEvent 3360 event; 3361 3362 /* 3363 Map Command widget. 3364 */ 3365 (void) CloneString(&windows->command.name,"Color Edit"); 3366 windows->command.data=4; 3367 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3368 (void) XMapRaised(display,windows->command.id); 3369 XClientMessage(display,windows->image.id,windows->im_protocols, 3370 windows->im_update_widget,CurrentTime); 3371 /* 3372 Make cursor. 3373 */ 3374 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3375 resource_info->background_color,resource_info->foreground_color); 3376 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3377 /* 3378 Track pointer until button 1 is pressed. 3379 */ 3380 XQueryPosition(display,windows->image.id,&x,&y); 3381 (void) XSelectInput(display,windows->image.id, 3382 windows->image.attributes.event_mask | PointerMotionMask); 3383 state=DefaultState; 3384 do 3385 { 3386 if (windows->info.mapped != MagickFalse) 3387 { 3388 /* 3389 Display pointer position. 3390 */ 3391 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3392 x+windows->image.x,y+windows->image.y); 3393 XInfoWidget(display,windows,text); 3394 } 3395 /* 3396 Wait for next event. 3397 */ 3398 XScreenEvent(display,windows,&event); 3399 if (event.xany.window == windows->command.id) 3400 { 3401 /* 3402 Select a command from the Command widget. 3403 */ 3404 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3405 if (id < 0) 3406 { 3407 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3408 continue; 3409 } 3410 switch (ColorEditCommands[id]) 3411 { 3412 case ColorEditMethodCommand: 3413 { 3414 char 3415 **methods; 3416 3417 /* 3418 Select a method from the pop-up menu. 3419 */ 3420 methods=(char **) GetCommandOptions(MagickMethodOptions); 3421 if (methods == (char **) NULL) 3422 break; 3423 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3424 (const char **) methods,command); 3425 if (entry >= 0) 3426 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3427 MagickFalse,methods[entry]); 3428 methods=DestroyStringList(methods); 3429 break; 3430 } 3431 case ColorEditColorCommand: 3432 { 3433 const char 3434 *ColorMenu[MaxNumberPens]; 3435 3436 int 3437 pen_number; 3438 3439 /* 3440 Initialize menu selections. 3441 */ 3442 for (i=0; i < (int) (MaxNumberPens-2); i++) 3443 ColorMenu[i]=resource_info->pen_colors[i]; 3444 ColorMenu[MaxNumberPens-2]="Browser..."; 3445 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3446 /* 3447 Select a pen color from the pop-up menu. 3448 */ 3449 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3450 (const char **) ColorMenu,command); 3451 if (pen_number < 0) 3452 break; 3453 if (pen_number == (MaxNumberPens-2)) 3454 { 3455 static char 3456 color_name[MaxTextExtent] = "gray"; 3457 3458 /* 3459 Select a pen color from a dialog. 3460 */ 3461 resource_info->pen_colors[pen_number]=color_name; 3462 XColorBrowserWidget(display,windows,"Select",color_name); 3463 if (*color_name == '\0') 3464 break; 3465 } 3466 /* 3467 Set pen color. 3468 */ 3469 (void) XParseColor(display,windows->map_info->colormap, 3470 resource_info->pen_colors[pen_number],&color); 3471 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3472 (unsigned int) MaxColors,&color); 3473 windows->pixel_info->pen_colors[pen_number]=color; 3474 pen_id=(unsigned int) pen_number; 3475 break; 3476 } 3477 case ColorEditBorderCommand: 3478 { 3479 const char 3480 *ColorMenu[MaxNumberPens]; 3481 3482 int 3483 pen_number; 3484 3485 /* 3486 Initialize menu selections. 3487 */ 3488 for (i=0; i < (int) (MaxNumberPens-2); i++) 3489 ColorMenu[i]=resource_info->pen_colors[i]; 3490 ColorMenu[MaxNumberPens-2]="Browser..."; 3491 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3492 /* 3493 Select a pen color from the pop-up menu. 3494 */ 3495 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3496 (const char **) ColorMenu,command); 3497 if (pen_number < 0) 3498 break; 3499 if (pen_number == (MaxNumberPens-2)) 3500 { 3501 static char 3502 color_name[MaxTextExtent] = "gray"; 3503 3504 /* 3505 Select a pen color from a dialog. 3506 */ 3507 resource_info->pen_colors[pen_number]=color_name; 3508 XColorBrowserWidget(display,windows,"Select",color_name); 3509 if (*color_name == '\0') 3510 break; 3511 } 3512 /* 3513 Set border color. 3514 */ 3515 (void) XParseColor(display,windows->map_info->colormap, 3516 resource_info->pen_colors[pen_number],&border_color); 3517 break; 3518 } 3519 case ColorEditFuzzCommand: 3520 { 3521 static char 3522 fuzz[MaxTextExtent]; 3523 3524 static const char 3525 *FuzzMenu[] = 3526 { 3527 "0%", 3528 "2%", 3529 "5%", 3530 "10%", 3531 "15%", 3532 "Dialog...", 3533 (char *) NULL, 3534 }; 3535 3536 /* 3537 Select a command from the pop-up menu. 3538 */ 3539 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3540 command); 3541 if (entry < 0) 3542 break; 3543 if (entry != 5) 3544 { 3545 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 3546 QuantumRange+1.0); 3547 break; 3548 } 3549 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3550 (void) XDialogWidget(display,windows,"Ok", 3551 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3552 if (*fuzz == '\0') 3553 break; 3554 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3555 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 3556 break; 3557 } 3558 case ColorEditUndoCommand: 3559 { 3560 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3561 image,exception); 3562 break; 3563 } 3564 case ColorEditHelpCommand: 3565 default: 3566 { 3567 XTextViewWidget(display,resource_info,windows,MagickFalse, 3568 "Help Viewer - Image Annotation",ImageColorEditHelp); 3569 break; 3570 } 3571 case ColorEditDismissCommand: 3572 { 3573 /* 3574 Prematurely exit. 3575 */ 3576 state|=EscapeState; 3577 state|=ExitState; 3578 break; 3579 } 3580 } 3581 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3582 continue; 3583 } 3584 switch (event.type) 3585 { 3586 case ButtonPress: 3587 { 3588 if (event.xbutton.button != Button1) 3589 break; 3590 if ((event.xbutton.window != windows->image.id) && 3591 (event.xbutton.window != windows->magnify.id)) 3592 break; 3593 /* 3594 exit loop. 3595 */ 3596 x=event.xbutton.x; 3597 y=event.xbutton.y; 3598 (void) XMagickCommand(display,resource_info,windows, 3599 SaveToUndoBufferCommand,image,exception); 3600 state|=UpdateConfigurationState; 3601 break; 3602 } 3603 case ButtonRelease: 3604 { 3605 if (event.xbutton.button != Button1) 3606 break; 3607 if ((event.xbutton.window != windows->image.id) && 3608 (event.xbutton.window != windows->magnify.id)) 3609 break; 3610 /* 3611 Update colormap information. 3612 */ 3613 x=event.xbutton.x; 3614 y=event.xbutton.y; 3615 XConfigureImageColormap(display,resource_info,windows,*image); 3616 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3617 XInfoWidget(display,windows,text); 3618 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3619 state&=(~UpdateConfigurationState); 3620 break; 3621 } 3622 case Expose: 3623 break; 3624 case KeyPress: 3625 { 3626 KeySym 3627 key_symbol; 3628 3629 if (event.xkey.window == windows->magnify.id) 3630 { 3631 Window 3632 window; 3633 3634 window=windows->magnify.id; 3635 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3636 } 3637 if (event.xkey.window != windows->image.id) 3638 break; 3639 /* 3640 Respond to a user key press. 3641 */ 3642 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3643 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3644 switch ((int) key_symbol) 3645 { 3646 case XK_Escape: 3647 case XK_F20: 3648 { 3649 /* 3650 Prematurely exit. 3651 */ 3652 state|=ExitState; 3653 break; 3654 } 3655 case XK_F1: 3656 case XK_Help: 3657 { 3658 XTextViewWidget(display,resource_info,windows,MagickFalse, 3659 "Help Viewer - Image Annotation",ImageColorEditHelp); 3660 break; 3661 } 3662 default: 3663 { 3664 (void) XBell(display,0); 3665 break; 3666 } 3667 } 3668 break; 3669 } 3670 case MotionNotify: 3671 { 3672 /* 3673 Map and unmap Info widget as cursor crosses its boundaries. 3674 */ 3675 x=event.xmotion.x; 3676 y=event.xmotion.y; 3677 if (windows->info.mapped != MagickFalse) 3678 { 3679 if ((x < (int) (windows->info.x+windows->info.width)) && 3680 (y < (int) (windows->info.y+windows->info.height))) 3681 (void) XWithdrawWindow(display,windows->info.id, 3682 windows->info.screen); 3683 } 3684 else 3685 if ((x > (int) (windows->info.x+windows->info.width)) || 3686 (y > (int) (windows->info.y+windows->info.height))) 3687 (void) XMapWindow(display,windows->info.id); 3688 break; 3689 } 3690 default: 3691 break; 3692 } 3693 if (event.xany.window == windows->magnify.id) 3694 { 3695 x=windows->magnify.x-windows->image.x; 3696 y=windows->magnify.y-windows->image.y; 3697 } 3698 x_offset=x; 3699 y_offset=y; 3700 if ((state & UpdateConfigurationState) != 0) 3701 { 3702 CacheView 3703 *image_view; 3704 3705 int 3706 x, 3707 y; 3708 3709 /* 3710 Pixel edit is relative to image configuration. 3711 */ 3712 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3713 MagickTrue); 3714 color=windows->pixel_info->pen_colors[pen_id]; 3715 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3716 width=(unsigned int) (*image)->columns; 3717 height=(unsigned int) (*image)->rows; 3718 x=0; 3719 y=0; 3720 if (windows->image.crop_geometry != (char *) NULL) 3721 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3722 &width,&height); 3723 x_offset=(int) 3724 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3725 y_offset=(int) 3726 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3727 if ((x_offset < 0) || (y_offset < 0)) 3728 continue; 3729 if ((x_offset >= (int) (*image)->columns) || 3730 (y_offset >= (int) (*image)->rows)) 3731 continue; 3732 image_view=AcquireCacheView(*image); 3733 switch (method) 3734 { 3735 case PointMethod: 3736 default: 3737 { 3738 /* 3739 Update color information using point algorithm. 3740 */ 3741 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3742 return(MagickFalse); 3743 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3744 (ssize_t) y_offset,1,1,exception); 3745 if (q == (Quantum *) NULL) 3746 break; 3747 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3748 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3749 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3750 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3751 break; 3752 } 3753 case ReplaceMethod: 3754 { 3755 PixelInfo 3756 pixel, 3757 target; 3758 3759 Quantum 3760 virtual_pixel[MaxPixelChannels]; 3761 3762 /* 3763 Update color information using replace algorithm. 3764 */ 3765 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3766 (ssize_t) y_offset,virtual_pixel,exception); 3767 target.red=virtual_pixel[RedPixelChannel]; 3768 target.green=virtual_pixel[GreenPixelChannel]; 3769 target.blue=virtual_pixel[BluePixelChannel]; 3770 target.alpha=virtual_pixel[AlphaPixelChannel]; 3771 if ((*image)->storage_class == DirectClass) 3772 { 3773 for (y=0; y < (int) (*image)->rows; y++) 3774 { 3775 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3776 (*image)->columns,1,exception); 3777 if (q == (Quantum *) NULL) 3778 break; 3779 for (x=0; x < (int) (*image)->columns; x++) 3780 { 3781 GetPixelInfoPixel(*image,q,&pixel); 3782 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3783 { 3784 SetPixelRed(*image,ScaleShortToQuantum( 3785 color.red),q); 3786 SetPixelGreen(*image,ScaleShortToQuantum( 3787 color.green),q); 3788 SetPixelBlue(*image,ScaleShortToQuantum( 3789 color.blue),q); 3790 } 3791 q+=GetPixelChannels(*image); 3792 } 3793 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3794 break; 3795 } 3796 } 3797 else 3798 { 3799 for (i=0; i < (ssize_t) (*image)->colors; i++) 3800 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3801 { 3802 (*image)->colormap[i].red=ScaleShortToQuantum( 3803 color.red); 3804 (*image)->colormap[i].green=ScaleShortToQuantum( 3805 color.green); 3806 (*image)->colormap[i].blue=ScaleShortToQuantum( 3807 color.blue); 3808 } 3809 (void) SyncImage(*image,exception); 3810 } 3811 break; 3812 } 3813 case FloodfillMethod: 3814 case FillToBorderMethod: 3815 { 3816 DrawInfo 3817 *draw_info; 3818 3819 PixelInfo 3820 target; 3821 3822 /* 3823 Update color information using floodfill algorithm. 3824 */ 3825 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 3826 (ssize_t) y_offset,&target,exception); 3827 if (method == FillToBorderMethod) 3828 { 3829 target.red=(MagickRealType) 3830 ScaleShortToQuantum(border_color.red); 3831 target.green=(MagickRealType) 3832 ScaleShortToQuantum(border_color.green); 3833 target.blue=(MagickRealType) 3834 ScaleShortToQuantum(border_color.blue); 3835 } 3836 draw_info=CloneDrawInfo(resource_info->image_info, 3837 (DrawInfo *) NULL); 3838 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3839 AllCompliance,&draw_info->fill,exception); 3840 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3841 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3842 MagickFalse : MagickTrue,exception); 3843 draw_info=DestroyDrawInfo(draw_info); 3844 break; 3845 } 3846 case ResetMethod: 3847 { 3848 /* 3849 Update color information using reset algorithm. 3850 */ 3851 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3852 return(MagickFalse); 3853 for (y=0; y < (int) (*image)->rows; y++) 3854 { 3855 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3856 (*image)->columns,1,exception); 3857 if (q == (Quantum *) NULL) 3858 break; 3859 for (x=0; x < (int) (*image)->columns; x++) 3860 { 3861 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3862 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3863 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3864 q+=GetPixelChannels(*image); 3865 } 3866 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3867 break; 3868 } 3869 break; 3870 } 3871 } 3872 image_view=DestroyCacheView(image_view); 3873 state&=(~UpdateConfigurationState); 3874 } 3875 } while ((state & ExitState) == 0); 3876 (void) XSelectInput(display,windows->image.id, 3877 windows->image.attributes.event_mask); 3878 XSetCursorState(display,windows,MagickFalse); 3879 (void) XFreeCursor(display,cursor); 3880 return(MagickTrue); 3881} 3882 3883/* 3884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3885% % 3886% % 3887% % 3888+ X C o m p o s i t e I m a g e % 3889% % 3890% % 3891% % 3892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3893% 3894% XCompositeImage() requests an image name from the user, reads the image and 3895% composites it with the X window image at a location the user chooses with 3896% the pointer. 3897% 3898% The format of the XCompositeImage method is: 3899% 3900% MagickBooleanType XCompositeImage(Display *display, 3901% XResourceInfo *resource_info,XWindows *windows,Image *image, 3902% ExceptionInfo *exception) 3903% 3904% A description of each parameter follows: 3905% 3906% o display: Specifies a connection to an X server; returned from 3907% XOpenDisplay. 3908% 3909% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3910% 3911% o windows: Specifies a pointer to a XWindows structure. 3912% 3913% o image: the image; returned from ReadImage. 3914% 3915% o exception: return any errors or warnings in this structure. 3916% 3917*/ 3918static MagickBooleanType XCompositeImage(Display *display, 3919 XResourceInfo *resource_info,XWindows *windows,Image *image, 3920 ExceptionInfo *exception) 3921{ 3922 static char 3923 displacement_geometry[MaxTextExtent] = "30x30", 3924 filename[MaxTextExtent] = "\0"; 3925 3926 static const char 3927 *CompositeMenu[] = 3928 { 3929 "Operators", 3930 "Dissolve", 3931 "Displace", 3932 "Help", 3933 "Dismiss", 3934 (char *) NULL 3935 }; 3936 3937 static CompositeOperator 3938 compose = CopyCompositeOp; 3939 3940 static const ModeType 3941 CompositeCommands[] = 3942 { 3943 CompositeOperatorsCommand, 3944 CompositeDissolveCommand, 3945 CompositeDisplaceCommand, 3946 CompositeHelpCommand, 3947 CompositeDismissCommand 3948 }; 3949 3950 char 3951 text[MaxTextExtent]; 3952 3953 Cursor 3954 cursor; 3955 3956 Image 3957 *composite_image; 3958 3959 int 3960 entry, 3961 id, 3962 x, 3963 y; 3964 3965 MagickRealType 3966 blend, 3967 scale_factor; 3968 3969 RectangleInfo 3970 highlight_info, 3971 composite_info; 3972 3973 unsigned int 3974 height, 3975 width; 3976 3977 size_t 3978 state; 3979 3980 XEvent 3981 event; 3982 3983 /* 3984 Request image file name from user. 3985 */ 3986 XFileBrowserWidget(display,windows,"Composite",filename); 3987 if (*filename == '\0') 3988 return(MagickTrue); 3989 /* 3990 Read image. 3991 */ 3992 XSetCursorState(display,windows,MagickTrue); 3993 XCheckRefreshWindows(display,windows); 3994 (void) CopyMagickString(resource_info->image_info->filename,filename, 3995 MaxTextExtent); 3996 composite_image=ReadImage(resource_info->image_info,exception); 3997 CatchException(exception); 3998 XSetCursorState(display,windows,MagickFalse); 3999 if (composite_image == (Image *) NULL) 4000 return(MagickFalse); 4001 /* 4002 Map Command widget. 4003 */ 4004 (void) CloneString(&windows->command.name,"Composite"); 4005 windows->command.data=1; 4006 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4007 (void) XMapRaised(display,windows->command.id); 4008 XClientMessage(display,windows->image.id,windows->im_protocols, 4009 windows->im_update_widget,CurrentTime); 4010 /* 4011 Track pointer until button 1 is pressed. 4012 */ 4013 XQueryPosition(display,windows->image.id,&x,&y); 4014 (void) XSelectInput(display,windows->image.id, 4015 windows->image.attributes.event_mask | PointerMotionMask); 4016 composite_info.x=(ssize_t) windows->image.x+x; 4017 composite_info.y=(ssize_t) windows->image.y+y; 4018 composite_info.width=0; 4019 composite_info.height=0; 4020 cursor=XCreateFontCursor(display,XC_ul_angle); 4021 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4022 blend=0.0; 4023 state=DefaultState; 4024 do 4025 { 4026 if (windows->info.mapped != MagickFalse) 4027 { 4028 /* 4029 Display pointer position. 4030 */ 4031 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4032 (long) composite_info.x,(long) composite_info.y); 4033 XInfoWidget(display,windows,text); 4034 } 4035 highlight_info=composite_info; 4036 highlight_info.x=composite_info.x-windows->image.x; 4037 highlight_info.y=composite_info.y-windows->image.y; 4038 XHighlightRectangle(display,windows->image.id, 4039 windows->image.highlight_context,&highlight_info); 4040 /* 4041 Wait for next event. 4042 */ 4043 XScreenEvent(display,windows,&event); 4044 XHighlightRectangle(display,windows->image.id, 4045 windows->image.highlight_context,&highlight_info); 4046 if (event.xany.window == windows->command.id) 4047 { 4048 /* 4049 Select a command from the Command widget. 4050 */ 4051 id=XCommandWidget(display,windows,CompositeMenu,&event); 4052 if (id < 0) 4053 continue; 4054 switch (CompositeCommands[id]) 4055 { 4056 case CompositeOperatorsCommand: 4057 { 4058 char 4059 command[MaxTextExtent], 4060 **operators; 4061 4062 /* 4063 Select a command from the pop-up menu. 4064 */ 4065 operators=GetCommandOptions(MagickComposeOptions); 4066 if (operators == (char **) NULL) 4067 break; 4068 entry=XMenuWidget(display,windows,CompositeMenu[id], 4069 (const char **) operators,command); 4070 if (entry >= 0) 4071 compose=(CompositeOperator) ParseCommandOption( 4072 MagickComposeOptions,MagickFalse,operators[entry]); 4073 operators=DestroyStringList(operators); 4074 break; 4075 } 4076 case CompositeDissolveCommand: 4077 { 4078 static char 4079 factor[MaxTextExtent] = "20.0"; 4080 4081 /* 4082 Dissolve the two images a given percent. 4083 */ 4084 (void) XSetFunction(display,windows->image.highlight_context, 4085 GXcopy); 4086 (void) XDialogWidget(display,windows,"Dissolve", 4087 "Enter the blend factor (0.0 - 99.9%):",factor); 4088 (void) XSetFunction(display,windows->image.highlight_context, 4089 GXinvert); 4090 if (*factor == '\0') 4091 break; 4092 blend=InterpretLocaleValue(factor,(char **) NULL); 4093 compose=DissolveCompositeOp; 4094 break; 4095 } 4096 case CompositeDisplaceCommand: 4097 { 4098 /* 4099 Get horizontal and vertical scale displacement geometry. 4100 */ 4101 (void) XSetFunction(display,windows->image.highlight_context, 4102 GXcopy); 4103 (void) XDialogWidget(display,windows,"Displace", 4104 "Enter the horizontal and vertical scale:",displacement_geometry); 4105 (void) XSetFunction(display,windows->image.highlight_context, 4106 GXinvert); 4107 if (*displacement_geometry == '\0') 4108 break; 4109 compose=DisplaceCompositeOp; 4110 break; 4111 } 4112 case CompositeHelpCommand: 4113 { 4114 (void) XSetFunction(display,windows->image.highlight_context, 4115 GXcopy); 4116 XTextViewWidget(display,resource_info,windows,MagickFalse, 4117 "Help Viewer - Image Composite",ImageCompositeHelp); 4118 (void) XSetFunction(display,windows->image.highlight_context, 4119 GXinvert); 4120 break; 4121 } 4122 case CompositeDismissCommand: 4123 { 4124 /* 4125 Prematurely exit. 4126 */ 4127 state|=EscapeState; 4128 state|=ExitState; 4129 break; 4130 } 4131 default: 4132 break; 4133 } 4134 continue; 4135 } 4136 switch (event.type) 4137 { 4138 case ButtonPress: 4139 { 4140 if (image->debug != MagickFalse) 4141 (void) LogMagickEvent(X11Event,GetMagickModule(), 4142 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4143 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4144 if (event.xbutton.button != Button1) 4145 break; 4146 if (event.xbutton.window != windows->image.id) 4147 break; 4148 /* 4149 Change cursor. 4150 */ 4151 composite_info.width=composite_image->columns; 4152 composite_info.height=composite_image->rows; 4153 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4154 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4155 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4156 break; 4157 } 4158 case ButtonRelease: 4159 { 4160 if (image->debug != MagickFalse) 4161 (void) LogMagickEvent(X11Event,GetMagickModule(), 4162 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4163 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4164 if (event.xbutton.button != Button1) 4165 break; 4166 if (event.xbutton.window != windows->image.id) 4167 break; 4168 if ((composite_info.width != 0) && (composite_info.height != 0)) 4169 { 4170 /* 4171 User has selected the location of the composite image. 4172 */ 4173 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4174 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4175 state|=ExitState; 4176 } 4177 break; 4178 } 4179 case Expose: 4180 break; 4181 case KeyPress: 4182 { 4183 char 4184 command[MaxTextExtent]; 4185 4186 KeySym 4187 key_symbol; 4188 4189 int 4190 length; 4191 4192 if (event.xkey.window != windows->image.id) 4193 break; 4194 /* 4195 Respond to a user key press. 4196 */ 4197 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4198 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4199 *(command+length)='\0'; 4200 if (image->debug != MagickFalse) 4201 (void) LogMagickEvent(X11Event,GetMagickModule(), 4202 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4203 switch ((int) key_symbol) 4204 { 4205 case XK_Escape: 4206 case XK_F20: 4207 { 4208 /* 4209 Prematurely exit. 4210 */ 4211 composite_image=DestroyImage(composite_image); 4212 state|=EscapeState; 4213 state|=ExitState; 4214 break; 4215 } 4216 case XK_F1: 4217 case XK_Help: 4218 { 4219 (void) XSetFunction(display,windows->image.highlight_context, 4220 GXcopy); 4221 XTextViewWidget(display,resource_info,windows,MagickFalse, 4222 "Help Viewer - Image Composite",ImageCompositeHelp); 4223 (void) XSetFunction(display,windows->image.highlight_context, 4224 GXinvert); 4225 break; 4226 } 4227 default: 4228 { 4229 (void) XBell(display,0); 4230 break; 4231 } 4232 } 4233 break; 4234 } 4235 case MotionNotify: 4236 { 4237 /* 4238 Map and unmap Info widget as text cursor crosses its boundaries. 4239 */ 4240 x=event.xmotion.x; 4241 y=event.xmotion.y; 4242 if (windows->info.mapped != MagickFalse) 4243 { 4244 if ((x < (int) (windows->info.x+windows->info.width)) && 4245 (y < (int) (windows->info.y+windows->info.height))) 4246 (void) XWithdrawWindow(display,windows->info.id, 4247 windows->info.screen); 4248 } 4249 else 4250 if ((x > (int) (windows->info.x+windows->info.width)) || 4251 (y > (int) (windows->info.y+windows->info.height))) 4252 (void) XMapWindow(display,windows->info.id); 4253 composite_info.x=(ssize_t) windows->image.x+x; 4254 composite_info.y=(ssize_t) windows->image.y+y; 4255 break; 4256 } 4257 default: 4258 { 4259 if (image->debug != MagickFalse) 4260 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4261 event.type); 4262 break; 4263 } 4264 } 4265 } while ((state & ExitState) == 0); 4266 (void) XSelectInput(display,windows->image.id, 4267 windows->image.attributes.event_mask); 4268 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4269 XSetCursorState(display,windows,MagickFalse); 4270 (void) XFreeCursor(display,cursor); 4271 if ((state & EscapeState) != 0) 4272 return(MagickTrue); 4273 /* 4274 Image compositing is relative to image configuration. 4275 */ 4276 XSetCursorState(display,windows,MagickTrue); 4277 XCheckRefreshWindows(display,windows); 4278 width=(unsigned int) image->columns; 4279 height=(unsigned int) image->rows; 4280 x=0; 4281 y=0; 4282 if (windows->image.crop_geometry != (char *) NULL) 4283 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4284 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4285 composite_info.x+=x; 4286 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4287 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4288 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4289 composite_info.y+=y; 4290 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4291 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4292 if ((composite_info.width != composite_image->columns) || 4293 (composite_info.height != composite_image->rows)) 4294 { 4295 Image 4296 *resize_image; 4297 4298 /* 4299 Scale composite image. 4300 */ 4301 resize_image=ResizeImage(composite_image,composite_info.width, 4302 composite_info.height,composite_image->filter,composite_image->blur, 4303 exception); 4304 composite_image=DestroyImage(composite_image); 4305 if (resize_image == (Image *) NULL) 4306 { 4307 XSetCursorState(display,windows,MagickFalse); 4308 return(MagickFalse); 4309 } 4310 composite_image=resize_image; 4311 } 4312 if (compose == DisplaceCompositeOp) 4313 (void) SetImageArtifact(composite_image,"compose:args", 4314 displacement_geometry); 4315 if (blend != 0.0) 4316 { 4317 CacheView 4318 *image_view; 4319 4320 int 4321 y; 4322 4323 Quantum 4324 opacity; 4325 4326 register int 4327 x; 4328 4329 register Quantum 4330 *q; 4331 4332 /* 4333 Create mattes for blending. 4334 */ 4335 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4336 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4337 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4338 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4339 return(MagickFalse); 4340 image->matte=MagickTrue; 4341 image_view=AcquireCacheView(image); 4342 for (y=0; y < (int) image->rows; y++) 4343 { 4344 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4345 exception); 4346 if (q == (Quantum *) NULL) 4347 break; 4348 for (x=0; x < (int) image->columns; x++) 4349 { 4350 SetPixelAlpha(image,opacity,q); 4351 q+=GetPixelChannels(image); 4352 } 4353 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4354 break; 4355 } 4356 image_view=DestroyCacheView(image_view); 4357 } 4358 /* 4359 Composite image with X Image window. 4360 */ 4361 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4362 composite_info.y,exception); 4363 composite_image=DestroyImage(composite_image); 4364 XSetCursorState(display,windows,MagickFalse); 4365 /* 4366 Update image configuration. 4367 */ 4368 XConfigureImageColormap(display,resource_info,windows,image); 4369 (void) XConfigureImage(display,resource_info,windows,image,exception); 4370 return(MagickTrue); 4371} 4372 4373/* 4374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4375% % 4376% % 4377% % 4378+ X C o n f i g u r e I m a g e % 4379% % 4380% % 4381% % 4382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4383% 4384% XConfigureImage() creates a new X image. It also notifies the window 4385% manager of the new image size and configures the transient widows. 4386% 4387% The format of the XConfigureImage method is: 4388% 4389% MagickBooleanType XConfigureImage(Display *display, 4390% XResourceInfo *resource_info,XWindows *windows,Image *image, 4391% ExceptionInfo *exception) 4392% 4393% A description of each parameter follows: 4394% 4395% o display: Specifies a connection to an X server; returned from 4396% XOpenDisplay. 4397% 4398% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4399% 4400% o windows: Specifies a pointer to a XWindows structure. 4401% 4402% o image: the image. 4403% 4404% o exception: return any errors or warnings in this structure. 4405% 4406% o exception: return any errors or warnings in this structure. 4407% 4408*/ 4409static MagickBooleanType XConfigureImage(Display *display, 4410 XResourceInfo *resource_info,XWindows *windows,Image *image, 4411 ExceptionInfo *exception) 4412{ 4413 char 4414 geometry[MaxTextExtent]; 4415 4416 MagickStatusType 4417 status; 4418 4419 size_t 4420 mask, 4421 height, 4422 width; 4423 4424 ssize_t 4425 x, 4426 y; 4427 4428 XSizeHints 4429 *size_hints; 4430 4431 XWindowChanges 4432 window_changes; 4433 4434 /* 4435 Dismiss if window dimensions are zero. 4436 */ 4437 width=(unsigned int) windows->image.window_changes.width; 4438 height=(unsigned int) windows->image.window_changes.height; 4439 if (image->debug != MagickFalse) 4440 (void) LogMagickEvent(X11Event,GetMagickModule(), 4441 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4442 windows->image.ximage->height,(double) width,(double) height); 4443 if ((width*height) == 0) 4444 return(MagickTrue); 4445 x=0; 4446 y=0; 4447 /* 4448 Resize image to fit Image window dimensions. 4449 */ 4450 XSetCursorState(display,windows,MagickTrue); 4451 (void) XFlush(display); 4452 if (((int) width != windows->image.ximage->width) || 4453 ((int) height != windows->image.ximage->height)) 4454 image->taint=MagickTrue; 4455 windows->magnify.x=(int) 4456 width*windows->magnify.x/windows->image.ximage->width; 4457 windows->magnify.y=(int) 4458 height*windows->magnify.y/windows->image.ximage->height; 4459 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4460 windows->image.y=(int) 4461 (height*windows->image.y/windows->image.ximage->height); 4462 status=XMakeImage(display,resource_info,&windows->image,image, 4463 (unsigned int) width,(unsigned int) height,exception); 4464 if (status == MagickFalse) 4465 XNoticeWidget(display,windows,"Unable to configure X image:", 4466 windows->image.name); 4467 /* 4468 Notify window manager of the new configuration. 4469 */ 4470 if (resource_info->image_geometry != (char *) NULL) 4471 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4472 resource_info->image_geometry); 4473 else 4474 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4475 XDisplayWidth(display,windows->image.screen), 4476 XDisplayHeight(display,windows->image.screen)); 4477 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4478 window_changes.width=(int) width; 4479 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4480 window_changes.width=XDisplayWidth(display,windows->image.screen); 4481 window_changes.height=(int) height; 4482 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4483 window_changes.height=XDisplayHeight(display,windows->image.screen); 4484 mask=(size_t) (CWWidth | CWHeight); 4485 if (resource_info->backdrop) 4486 { 4487 mask|=CWX | CWY; 4488 window_changes.x=(int) 4489 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4490 window_changes.y=(int) 4491 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4492 } 4493 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4494 (unsigned int) mask,&window_changes); 4495 (void) XClearWindow(display,windows->image.id); 4496 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4497 /* 4498 Update Magnify window configuration. 4499 */ 4500 if (windows->magnify.mapped != MagickFalse) 4501 XMakeMagnifyImage(display,windows); 4502 windows->pan.crop_geometry=windows->image.crop_geometry; 4503 XBestIconSize(display,&windows->pan,image); 4504 while (((windows->pan.width << 1) < MaxIconSize) && 4505 ((windows->pan.height << 1) < MaxIconSize)) 4506 { 4507 windows->pan.width<<=1; 4508 windows->pan.height<<=1; 4509 } 4510 if (windows->pan.geometry != (char *) NULL) 4511 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4512 &windows->pan.width,&windows->pan.height); 4513 window_changes.width=(int) windows->pan.width; 4514 window_changes.height=(int) windows->pan.height; 4515 size_hints=XAllocSizeHints(); 4516 if (size_hints != (XSizeHints *) NULL) 4517 { 4518 /* 4519 Set new size hints. 4520 */ 4521 size_hints->flags=PSize | PMinSize | PMaxSize; 4522 size_hints->width=window_changes.width; 4523 size_hints->height=window_changes.height; 4524 size_hints->min_width=size_hints->width; 4525 size_hints->min_height=size_hints->height; 4526 size_hints->max_width=size_hints->width; 4527 size_hints->max_height=size_hints->height; 4528 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4529 (void) XFree((void *) size_hints); 4530 } 4531 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4532 (unsigned int) (CWWidth | CWHeight),&window_changes); 4533 /* 4534 Update icon window configuration. 4535 */ 4536 windows->icon.crop_geometry=windows->image.crop_geometry; 4537 XBestIconSize(display,&windows->icon,image); 4538 window_changes.width=(int) windows->icon.width; 4539 window_changes.height=(int) windows->icon.height; 4540 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4541 (unsigned int) (CWWidth | CWHeight),&window_changes); 4542 XSetCursorState(display,windows,MagickFalse); 4543 return(status != 0 ? MagickTrue : MagickFalse); 4544} 4545 4546/* 4547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4548% % 4549% % 4550% % 4551+ X C r o p I m a g e % 4552% % 4553% % 4554% % 4555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4556% 4557% XCropImage() allows the user to select a region of the image and crop, copy, 4558% or cut it. For copy or cut, the image can subsequently be composited onto 4559% the image with XPasteImage. 4560% 4561% The format of the XCropImage method is: 4562% 4563% MagickBooleanType XCropImage(Display *display, 4564% XResourceInfo *resource_info,XWindows *windows,Image *image, 4565% const ClipboardMode mode,ExceptionInfo *exception) 4566% 4567% A description of each parameter follows: 4568% 4569% o display: Specifies a connection to an X server; returned from 4570% XOpenDisplay. 4571% 4572% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4573% 4574% o windows: Specifies a pointer to a XWindows structure. 4575% 4576% o image: the image; returned from ReadImage. 4577% 4578% o mode: This unsigned value specified whether the image should be 4579% cropped, copied, or cut. 4580% 4581% o exception: return any errors or warnings in this structure. 4582% 4583*/ 4584static MagickBooleanType XCropImage(Display *display, 4585 XResourceInfo *resource_info,XWindows *windows,Image *image, 4586 const ClipboardMode mode,ExceptionInfo *exception) 4587{ 4588 static const char 4589 *CropModeMenu[] = 4590 { 4591 "Help", 4592 "Dismiss", 4593 (char *) NULL 4594 }, 4595 *RectifyModeMenu[] = 4596 { 4597 "Crop", 4598 "Help", 4599 "Dismiss", 4600 (char *) NULL 4601 }; 4602 4603 static const ModeType 4604 CropCommands[] = 4605 { 4606 CropHelpCommand, 4607 CropDismissCommand 4608 }, 4609 RectifyCommands[] = 4610 { 4611 RectifyCopyCommand, 4612 RectifyHelpCommand, 4613 RectifyDismissCommand 4614 }; 4615 4616 CacheView 4617 *image_view; 4618 4619 char 4620 command[MaxTextExtent], 4621 text[MaxTextExtent]; 4622 4623 Cursor 4624 cursor; 4625 4626 int 4627 id, 4628 x, 4629 y; 4630 4631 KeySym 4632 key_symbol; 4633 4634 Image 4635 *crop_image; 4636 4637 MagickRealType 4638 scale_factor; 4639 4640 RectangleInfo 4641 crop_info, 4642 highlight_info; 4643 4644 register Quantum 4645 *q; 4646 4647 unsigned int 4648 height, 4649 width; 4650 4651 size_t 4652 state; 4653 4654 XEvent 4655 event; 4656 4657 /* 4658 Map Command widget. 4659 */ 4660 switch (mode) 4661 { 4662 case CopyMode: 4663 { 4664 (void) CloneString(&windows->command.name,"Copy"); 4665 break; 4666 } 4667 case CropMode: 4668 { 4669 (void) CloneString(&windows->command.name,"Crop"); 4670 break; 4671 } 4672 case CutMode: 4673 { 4674 (void) CloneString(&windows->command.name,"Cut"); 4675 break; 4676 } 4677 } 4678 RectifyModeMenu[0]=windows->command.name; 4679 windows->command.data=0; 4680 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4681 (void) XMapRaised(display,windows->command.id); 4682 XClientMessage(display,windows->image.id,windows->im_protocols, 4683 windows->im_update_widget,CurrentTime); 4684 /* 4685 Track pointer until button 1 is pressed. 4686 */ 4687 XQueryPosition(display,windows->image.id,&x,&y); 4688 (void) XSelectInput(display,windows->image.id, 4689 windows->image.attributes.event_mask | PointerMotionMask); 4690 crop_info.x=(ssize_t) windows->image.x+x; 4691 crop_info.y=(ssize_t) windows->image.y+y; 4692 crop_info.width=0; 4693 crop_info.height=0; 4694 cursor=XCreateFontCursor(display,XC_fleur); 4695 state=DefaultState; 4696 do 4697 { 4698 if (windows->info.mapped != MagickFalse) 4699 { 4700 /* 4701 Display pointer position. 4702 */ 4703 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4704 (long) crop_info.x,(long) crop_info.y); 4705 XInfoWidget(display,windows,text); 4706 } 4707 /* 4708 Wait for next event. 4709 */ 4710 XScreenEvent(display,windows,&event); 4711 if (event.xany.window == windows->command.id) 4712 { 4713 /* 4714 Select a command from the Command widget. 4715 */ 4716 id=XCommandWidget(display,windows,CropModeMenu,&event); 4717 if (id < 0) 4718 continue; 4719 switch (CropCommands[id]) 4720 { 4721 case CropHelpCommand: 4722 { 4723 switch (mode) 4724 { 4725 case CopyMode: 4726 { 4727 XTextViewWidget(display,resource_info,windows,MagickFalse, 4728 "Help Viewer - Image Copy",ImageCopyHelp); 4729 break; 4730 } 4731 case CropMode: 4732 { 4733 XTextViewWidget(display,resource_info,windows,MagickFalse, 4734 "Help Viewer - Image Crop",ImageCropHelp); 4735 break; 4736 } 4737 case CutMode: 4738 { 4739 XTextViewWidget(display,resource_info,windows,MagickFalse, 4740 "Help Viewer - Image Cut",ImageCutHelp); 4741 break; 4742 } 4743 } 4744 break; 4745 } 4746 case CropDismissCommand: 4747 { 4748 /* 4749 Prematurely exit. 4750 */ 4751 state|=EscapeState; 4752 state|=ExitState; 4753 break; 4754 } 4755 default: 4756 break; 4757 } 4758 continue; 4759 } 4760 switch (event.type) 4761 { 4762 case ButtonPress: 4763 { 4764 if (event.xbutton.button != Button1) 4765 break; 4766 if (event.xbutton.window != windows->image.id) 4767 break; 4768 /* 4769 Note first corner of cropping rectangle-- exit loop. 4770 */ 4771 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4772 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4773 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4774 state|=ExitState; 4775 break; 4776 } 4777 case ButtonRelease: 4778 break; 4779 case Expose: 4780 break; 4781 case KeyPress: 4782 { 4783 if (event.xkey.window != windows->image.id) 4784 break; 4785 /* 4786 Respond to a user key press. 4787 */ 4788 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4789 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4790 switch ((int) key_symbol) 4791 { 4792 case XK_Escape: 4793 case XK_F20: 4794 { 4795 /* 4796 Prematurely exit. 4797 */ 4798 state|=EscapeState; 4799 state|=ExitState; 4800 break; 4801 } 4802 case XK_F1: 4803 case XK_Help: 4804 { 4805 switch (mode) 4806 { 4807 case CopyMode: 4808 { 4809 XTextViewWidget(display,resource_info,windows,MagickFalse, 4810 "Help Viewer - Image Copy",ImageCopyHelp); 4811 break; 4812 } 4813 case CropMode: 4814 { 4815 XTextViewWidget(display,resource_info,windows,MagickFalse, 4816 "Help Viewer - Image Crop",ImageCropHelp); 4817 break; 4818 } 4819 case CutMode: 4820 { 4821 XTextViewWidget(display,resource_info,windows,MagickFalse, 4822 "Help Viewer - Image Cut",ImageCutHelp); 4823 break; 4824 } 4825 } 4826 break; 4827 } 4828 default: 4829 { 4830 (void) XBell(display,0); 4831 break; 4832 } 4833 } 4834 break; 4835 } 4836 case MotionNotify: 4837 { 4838 if (event.xmotion.window != windows->image.id) 4839 break; 4840 /* 4841 Map and unmap Info widget as text cursor crosses its boundaries. 4842 */ 4843 x=event.xmotion.x; 4844 y=event.xmotion.y; 4845 if (windows->info.mapped != MagickFalse) 4846 { 4847 if ((x < (int) (windows->info.x+windows->info.width)) && 4848 (y < (int) (windows->info.y+windows->info.height))) 4849 (void) XWithdrawWindow(display,windows->info.id, 4850 windows->info.screen); 4851 } 4852 else 4853 if ((x > (int) (windows->info.x+windows->info.width)) || 4854 (y > (int) (windows->info.y+windows->info.height))) 4855 (void) XMapWindow(display,windows->info.id); 4856 crop_info.x=(ssize_t) windows->image.x+x; 4857 crop_info.y=(ssize_t) windows->image.y+y; 4858 break; 4859 } 4860 default: 4861 break; 4862 } 4863 } while ((state & ExitState) == 0); 4864 (void) XSelectInput(display,windows->image.id, 4865 windows->image.attributes.event_mask); 4866 if ((state & EscapeState) != 0) 4867 { 4868 /* 4869 User want to exit without cropping. 4870 */ 4871 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4872 (void) XFreeCursor(display,cursor); 4873 return(MagickTrue); 4874 } 4875 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4876 do 4877 { 4878 /* 4879 Size rectangle as pointer moves until the mouse button is released. 4880 */ 4881 x=(int) crop_info.x; 4882 y=(int) crop_info.y; 4883 crop_info.width=0; 4884 crop_info.height=0; 4885 state=DefaultState; 4886 do 4887 { 4888 highlight_info=crop_info; 4889 highlight_info.x=crop_info.x-windows->image.x; 4890 highlight_info.y=crop_info.y-windows->image.y; 4891 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4892 { 4893 /* 4894 Display info and draw cropping rectangle. 4895 */ 4896 if (windows->info.mapped == MagickFalse) 4897 (void) XMapWindow(display,windows->info.id); 4898 (void) FormatLocaleString(text,MaxTextExtent, 4899 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4900 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4901 XInfoWidget(display,windows,text); 4902 XHighlightRectangle(display,windows->image.id, 4903 windows->image.highlight_context,&highlight_info); 4904 } 4905 else 4906 if (windows->info.mapped != MagickFalse) 4907 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4908 /* 4909 Wait for next event. 4910 */ 4911 XScreenEvent(display,windows,&event); 4912 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4913 XHighlightRectangle(display,windows->image.id, 4914 windows->image.highlight_context,&highlight_info); 4915 switch (event.type) 4916 { 4917 case ButtonPress: 4918 { 4919 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4920 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4921 break; 4922 } 4923 case ButtonRelease: 4924 { 4925 /* 4926 User has committed to cropping rectangle. 4927 */ 4928 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4929 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4930 XSetCursorState(display,windows,MagickFalse); 4931 state|=ExitState; 4932 windows->command.data=0; 4933 (void) XCommandWidget(display,windows,RectifyModeMenu, 4934 (XEvent *) NULL); 4935 break; 4936 } 4937 case Expose: 4938 break; 4939 case MotionNotify: 4940 { 4941 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4942 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4943 } 4944 default: 4945 break; 4946 } 4947 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4948 ((state & ExitState) != 0)) 4949 { 4950 /* 4951 Check boundary conditions. 4952 */ 4953 if (crop_info.x < 0) 4954 crop_info.x=0; 4955 else 4956 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4957 crop_info.x=(ssize_t) windows->image.ximage->width; 4958 if ((int) crop_info.x < x) 4959 crop_info.width=(unsigned int) (x-crop_info.x); 4960 else 4961 { 4962 crop_info.width=(unsigned int) (crop_info.x-x); 4963 crop_info.x=(ssize_t) x; 4964 } 4965 if (crop_info.y < 0) 4966 crop_info.y=0; 4967 else 4968 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4969 crop_info.y=(ssize_t) windows->image.ximage->height; 4970 if ((int) crop_info.y < y) 4971 crop_info.height=(unsigned int) (y-crop_info.y); 4972 else 4973 { 4974 crop_info.height=(unsigned int) (crop_info.y-y); 4975 crop_info.y=(ssize_t) y; 4976 } 4977 } 4978 } while ((state & ExitState) == 0); 4979 /* 4980 Wait for user to grab a corner of the rectangle or press return. 4981 */ 4982 state=DefaultState; 4983 (void) XMapWindow(display,windows->info.id); 4984 do 4985 { 4986 if (windows->info.mapped != MagickFalse) 4987 { 4988 /* 4989 Display pointer position. 4990 */ 4991 (void) FormatLocaleString(text,MaxTextExtent, 4992 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4993 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4994 XInfoWidget(display,windows,text); 4995 } 4996 highlight_info=crop_info; 4997 highlight_info.x=crop_info.x-windows->image.x; 4998 highlight_info.y=crop_info.y-windows->image.y; 4999 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5000 { 5001 state|=EscapeState; 5002 state|=ExitState; 5003 break; 5004 } 5005 XHighlightRectangle(display,windows->image.id, 5006 windows->image.highlight_context,&highlight_info); 5007 XScreenEvent(display,windows,&event); 5008 if (event.xany.window == windows->command.id) 5009 { 5010 /* 5011 Select a command from the Command widget. 5012 */ 5013 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5014 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5015 (void) XSetFunction(display,windows->image.highlight_context, 5016 GXinvert); 5017 XHighlightRectangle(display,windows->image.id, 5018 windows->image.highlight_context,&highlight_info); 5019 if (id >= 0) 5020 switch (RectifyCommands[id]) 5021 { 5022 case RectifyCopyCommand: 5023 { 5024 state|=ExitState; 5025 break; 5026 } 5027 case RectifyHelpCommand: 5028 { 5029 (void) XSetFunction(display,windows->image.highlight_context, 5030 GXcopy); 5031 switch (mode) 5032 { 5033 case CopyMode: 5034 { 5035 XTextViewWidget(display,resource_info,windows,MagickFalse, 5036 "Help Viewer - Image Copy",ImageCopyHelp); 5037 break; 5038 } 5039 case CropMode: 5040 { 5041 XTextViewWidget(display,resource_info,windows,MagickFalse, 5042 "Help Viewer - Image Crop",ImageCropHelp); 5043 break; 5044 } 5045 case CutMode: 5046 { 5047 XTextViewWidget(display,resource_info,windows,MagickFalse, 5048 "Help Viewer - Image Cut",ImageCutHelp); 5049 break; 5050 } 5051 } 5052 (void) XSetFunction(display,windows->image.highlight_context, 5053 GXinvert); 5054 break; 5055 } 5056 case RectifyDismissCommand: 5057 { 5058 /* 5059 Prematurely exit. 5060 */ 5061 state|=EscapeState; 5062 state|=ExitState; 5063 break; 5064 } 5065 default: 5066 break; 5067 } 5068 continue; 5069 } 5070 XHighlightRectangle(display,windows->image.id, 5071 windows->image.highlight_context,&highlight_info); 5072 switch (event.type) 5073 { 5074 case ButtonPress: 5075 { 5076 if (event.xbutton.button != Button1) 5077 break; 5078 if (event.xbutton.window != windows->image.id) 5079 break; 5080 x=windows->image.x+event.xbutton.x; 5081 y=windows->image.y+event.xbutton.y; 5082 if ((x < (int) (crop_info.x+RoiDelta)) && 5083 (x > (int) (crop_info.x-RoiDelta)) && 5084 (y < (int) (crop_info.y+RoiDelta)) && 5085 (y > (int) (crop_info.y-RoiDelta))) 5086 { 5087 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5088 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5089 state|=UpdateConfigurationState; 5090 break; 5091 } 5092 if ((x < (int) (crop_info.x+RoiDelta)) && 5093 (x > (int) (crop_info.x-RoiDelta)) && 5094 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5095 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5096 { 5097 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5098 state|=UpdateConfigurationState; 5099 break; 5100 } 5101 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5102 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5103 (y < (int) (crop_info.y+RoiDelta)) && 5104 (y > (int) (crop_info.y-RoiDelta))) 5105 { 5106 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5107 state|=UpdateConfigurationState; 5108 break; 5109 } 5110 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5111 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5112 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5113 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5114 { 5115 state|=UpdateConfigurationState; 5116 break; 5117 } 5118 } 5119 case ButtonRelease: 5120 { 5121 if (event.xbutton.window == windows->pan.id) 5122 if ((highlight_info.x != crop_info.x-windows->image.x) || 5123 (highlight_info.y != crop_info.y-windows->image.y)) 5124 XHighlightRectangle(display,windows->image.id, 5125 windows->image.highlight_context,&highlight_info); 5126 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5127 event.xbutton.time); 5128 break; 5129 } 5130 case Expose: 5131 { 5132 if (event.xexpose.window == windows->image.id) 5133 if (event.xexpose.count == 0) 5134 { 5135 event.xexpose.x=(int) highlight_info.x; 5136 event.xexpose.y=(int) highlight_info.y; 5137 event.xexpose.width=(int) highlight_info.width; 5138 event.xexpose.height=(int) highlight_info.height; 5139 XRefreshWindow(display,&windows->image,&event); 5140 } 5141 if (event.xexpose.window == windows->info.id) 5142 if (event.xexpose.count == 0) 5143 XInfoWidget(display,windows,text); 5144 break; 5145 } 5146 case KeyPress: 5147 { 5148 if (event.xkey.window != windows->image.id) 5149 break; 5150 /* 5151 Respond to a user key press. 5152 */ 5153 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5154 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5155 switch ((int) key_symbol) 5156 { 5157 case XK_Escape: 5158 case XK_F20: 5159 state|=EscapeState; 5160 case XK_Return: 5161 { 5162 state|=ExitState; 5163 break; 5164 } 5165 case XK_Home: 5166 case XK_KP_Home: 5167 { 5168 crop_info.x=(ssize_t) (windows->image.width/2L- 5169 crop_info.width/2L); 5170 crop_info.y=(ssize_t) (windows->image.height/2L- 5171 crop_info.height/2L); 5172 break; 5173 } 5174 case XK_Left: 5175 case XK_KP_Left: 5176 { 5177 crop_info.x--; 5178 break; 5179 } 5180 case XK_Up: 5181 case XK_KP_Up: 5182 case XK_Next: 5183 { 5184 crop_info.y--; 5185 break; 5186 } 5187 case XK_Right: 5188 case XK_KP_Right: 5189 { 5190 crop_info.x++; 5191 break; 5192 } 5193 case XK_Prior: 5194 case XK_Down: 5195 case XK_KP_Down: 5196 { 5197 crop_info.y++; 5198 break; 5199 } 5200 case XK_F1: 5201 case XK_Help: 5202 { 5203 (void) XSetFunction(display,windows->image.highlight_context, 5204 GXcopy); 5205 switch (mode) 5206 { 5207 case CopyMode: 5208 { 5209 XTextViewWidget(display,resource_info,windows,MagickFalse, 5210 "Help Viewer - Image Copy",ImageCopyHelp); 5211 break; 5212 } 5213 case CropMode: 5214 { 5215 XTextViewWidget(display,resource_info,windows,MagickFalse, 5216 "Help Viewer - Image Cropg",ImageCropHelp); 5217 break; 5218 } 5219 case CutMode: 5220 { 5221 XTextViewWidget(display,resource_info,windows,MagickFalse, 5222 "Help Viewer - Image Cutg",ImageCutHelp); 5223 break; 5224 } 5225 } 5226 (void) XSetFunction(display,windows->image.highlight_context, 5227 GXinvert); 5228 break; 5229 } 5230 default: 5231 { 5232 (void) XBell(display,0); 5233 break; 5234 } 5235 } 5236 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5237 event.xkey.time); 5238 break; 5239 } 5240 case KeyRelease: 5241 break; 5242 case MotionNotify: 5243 { 5244 if (event.xmotion.window != windows->image.id) 5245 break; 5246 /* 5247 Map and unmap Info widget as text cursor crosses its boundaries. 5248 */ 5249 x=event.xmotion.x; 5250 y=event.xmotion.y; 5251 if (windows->info.mapped != MagickFalse) 5252 { 5253 if ((x < (int) (windows->info.x+windows->info.width)) && 5254 (y < (int) (windows->info.y+windows->info.height))) 5255 (void) XWithdrawWindow(display,windows->info.id, 5256 windows->info.screen); 5257 } 5258 else 5259 if ((x > (int) (windows->info.x+windows->info.width)) || 5260 (y > (int) (windows->info.y+windows->info.height))) 5261 (void) XMapWindow(display,windows->info.id); 5262 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5263 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5264 break; 5265 } 5266 case SelectionRequest: 5267 { 5268 XSelectionEvent 5269 notify; 5270 5271 XSelectionRequestEvent 5272 *request; 5273 5274 /* 5275 Set primary selection. 5276 */ 5277 (void) FormatLocaleString(text,MaxTextExtent, 5278 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5279 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5280 request=(&(event.xselectionrequest)); 5281 (void) XChangeProperty(request->display,request->requestor, 5282 request->property,request->target,8,PropModeReplace, 5283 (unsigned char *) text,(int) strlen(text)); 5284 notify.type=SelectionNotify; 5285 notify.display=request->display; 5286 notify.requestor=request->requestor; 5287 notify.selection=request->selection; 5288 notify.target=request->target; 5289 notify.time=request->time; 5290 if (request->property == None) 5291 notify.property=request->target; 5292 else 5293 notify.property=request->property; 5294 (void) XSendEvent(request->display,request->requestor,False,0, 5295 (XEvent *) ¬ify); 5296 } 5297 default: 5298 break; 5299 } 5300 if ((state & UpdateConfigurationState) != 0) 5301 { 5302 (void) XPutBackEvent(display,&event); 5303 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5304 break; 5305 } 5306 } while ((state & ExitState) == 0); 5307 } while ((state & ExitState) == 0); 5308 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5309 XSetCursorState(display,windows,MagickFalse); 5310 if ((state & EscapeState) != 0) 5311 return(MagickTrue); 5312 if (mode == CropMode) 5313 if (((int) crop_info.width != windows->image.ximage->width) || 5314 ((int) crop_info.height != windows->image.ximage->height)) 5315 { 5316 /* 5317 Reconfigure Image window as defined by cropping rectangle. 5318 */ 5319 XSetCropGeometry(display,windows,&crop_info,image); 5320 windows->image.window_changes.width=(int) crop_info.width; 5321 windows->image.window_changes.height=(int) crop_info.height; 5322 (void) XConfigureImage(display,resource_info,windows,image,exception); 5323 return(MagickTrue); 5324 } 5325 /* 5326 Copy image before applying image transforms. 5327 */ 5328 XSetCursorState(display,windows,MagickTrue); 5329 XCheckRefreshWindows(display,windows); 5330 width=(unsigned int) image->columns; 5331 height=(unsigned int) image->rows; 5332 x=0; 5333 y=0; 5334 if (windows->image.crop_geometry != (char *) NULL) 5335 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5336 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5337 crop_info.x+=x; 5338 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5339 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5340 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5341 crop_info.y+=y; 5342 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5343 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5344 crop_image=CropImage(image,&crop_info,exception); 5345 XSetCursorState(display,windows,MagickFalse); 5346 if (crop_image == (Image *) NULL) 5347 return(MagickFalse); 5348 if (resource_info->copy_image != (Image *) NULL) 5349 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5350 resource_info->copy_image=crop_image; 5351 if (mode == CopyMode) 5352 { 5353 (void) XConfigureImage(display,resource_info,windows,image,exception); 5354 return(MagickTrue); 5355 } 5356 /* 5357 Cut image. 5358 */ 5359 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5360 return(MagickFalse); 5361 image->matte=MagickTrue; 5362 image_view=AcquireCacheView(image); 5363 for (y=0; y < (int) crop_info.height; y++) 5364 { 5365 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5366 crop_info.width,1,exception); 5367 if (q == (Quantum *) NULL) 5368 break; 5369 for (x=0; x < (int) crop_info.width; x++) 5370 { 5371 SetPixelAlpha(image,TransparentAlpha,q); 5372 q+=GetPixelChannels(image); 5373 } 5374 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5375 break; 5376 } 5377 image_view=DestroyCacheView(image_view); 5378 /* 5379 Update image configuration. 5380 */ 5381 XConfigureImageColormap(display,resource_info,windows,image); 5382 (void) XConfigureImage(display,resource_info,windows,image,exception); 5383 return(MagickTrue); 5384} 5385 5386/* 5387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5388% % 5389% % 5390% % 5391+ X D r a w I m a g e % 5392% % 5393% % 5394% % 5395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5396% 5397% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5398% the image. 5399% 5400% The format of the XDrawEditImage method is: 5401% 5402% MagickBooleanType XDrawEditImage(Display *display, 5403% XResourceInfo *resource_info,XWindows *windows,Image **image, 5404% ExceptionInfo *exception) 5405% 5406% A description of each parameter follows: 5407% 5408% o display: Specifies a connection to an X server; returned from 5409% XOpenDisplay. 5410% 5411% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5412% 5413% o windows: Specifies a pointer to a XWindows structure. 5414% 5415% o image: the image. 5416% 5417% o exception: return any errors or warnings in this structure. 5418% 5419*/ 5420static MagickBooleanType XDrawEditImage(Display *display, 5421 XResourceInfo *resource_info,XWindows *windows,Image **image, 5422 ExceptionInfo *exception) 5423{ 5424 static const char 5425 *DrawMenu[] = 5426 { 5427 "Element", 5428 "Color", 5429 "Stipple", 5430 "Width", 5431 "Undo", 5432 "Help", 5433 "Dismiss", 5434 (char *) NULL 5435 }; 5436 5437 static ElementType 5438 element = PointElement; 5439 5440 static const ModeType 5441 DrawCommands[] = 5442 { 5443 DrawElementCommand, 5444 DrawColorCommand, 5445 DrawStippleCommand, 5446 DrawWidthCommand, 5447 DrawUndoCommand, 5448 DrawHelpCommand, 5449 DrawDismissCommand 5450 }; 5451 5452 static Pixmap 5453 stipple = (Pixmap) NULL; 5454 5455 static unsigned int 5456 pen_id = 0, 5457 line_width = 1; 5458 5459 char 5460 command[MaxTextExtent], 5461 text[MaxTextExtent]; 5462 5463 Cursor 5464 cursor; 5465 5466 int 5467 entry, 5468 id, 5469 number_coordinates, 5470 x, 5471 y; 5472 5473 MagickRealType 5474 degrees; 5475 5476 MagickStatusType 5477 status; 5478 5479 RectangleInfo 5480 rectangle_info; 5481 5482 register int 5483 i; 5484 5485 unsigned int 5486 distance, 5487 height, 5488 max_coordinates, 5489 width; 5490 5491 size_t 5492 state; 5493 5494 Window 5495 root_window; 5496 5497 XDrawInfo 5498 draw_info; 5499 5500 XEvent 5501 event; 5502 5503 XPoint 5504 *coordinate_info; 5505 5506 XSegment 5507 line_info; 5508 5509 /* 5510 Allocate polygon info. 5511 */ 5512 max_coordinates=2048; 5513 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5514 sizeof(*coordinate_info)); 5515 if (coordinate_info == (XPoint *) NULL) 5516 { 5517 (void) ThrowMagickException(exception,GetMagickModule(), 5518 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5519 return(MagickFalse); 5520 } 5521 /* 5522 Map Command widget. 5523 */ 5524 (void) CloneString(&windows->command.name,"Draw"); 5525 windows->command.data=4; 5526 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5527 (void) XMapRaised(display,windows->command.id); 5528 XClientMessage(display,windows->image.id,windows->im_protocols, 5529 windows->im_update_widget,CurrentTime); 5530 /* 5531 Wait for first button press. 5532 */ 5533 root_window=XRootWindow(display,XDefaultScreen(display)); 5534 draw_info.stencil=OpaqueStencil; 5535 status=MagickTrue; 5536 cursor=XCreateFontCursor(display,XC_tcross); 5537 for ( ; ; ) 5538 { 5539 XQueryPosition(display,windows->image.id,&x,&y); 5540 (void) XSelectInput(display,windows->image.id, 5541 windows->image.attributes.event_mask | PointerMotionMask); 5542 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5543 state=DefaultState; 5544 do 5545 { 5546 if (windows->info.mapped != MagickFalse) 5547 { 5548 /* 5549 Display pointer position. 5550 */ 5551 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5552 x+windows->image.x,y+windows->image.y); 5553 XInfoWidget(display,windows,text); 5554 } 5555 /* 5556 Wait for next event. 5557 */ 5558 XScreenEvent(display,windows,&event); 5559 if (event.xany.window == windows->command.id) 5560 { 5561 /* 5562 Select a command from the Command widget. 5563 */ 5564 id=XCommandWidget(display,windows,DrawMenu,&event); 5565 if (id < 0) 5566 continue; 5567 switch (DrawCommands[id]) 5568 { 5569 case DrawElementCommand: 5570 { 5571 static const char 5572 *Elements[] = 5573 { 5574 "point", 5575 "line", 5576 "rectangle", 5577 "fill rectangle", 5578 "circle", 5579 "fill circle", 5580 "ellipse", 5581 "fill ellipse", 5582 "polygon", 5583 "fill polygon", 5584 (char *) NULL, 5585 }; 5586 5587 /* 5588 Select a command from the pop-up menu. 5589 */ 5590 element=(ElementType) (XMenuWidget(display,windows, 5591 DrawMenu[id],Elements,command)+1); 5592 break; 5593 } 5594 case DrawColorCommand: 5595 { 5596 const char 5597 *ColorMenu[MaxNumberPens+1]; 5598 5599 int 5600 pen_number; 5601 5602 MagickBooleanType 5603 transparent; 5604 5605 XColor 5606 color; 5607 5608 /* 5609 Initialize menu selections. 5610 */ 5611 for (i=0; i < (int) (MaxNumberPens-2); i++) 5612 ColorMenu[i]=resource_info->pen_colors[i]; 5613 ColorMenu[MaxNumberPens-2]="transparent"; 5614 ColorMenu[MaxNumberPens-1]="Browser..."; 5615 ColorMenu[MaxNumberPens]=(char *) NULL; 5616 /* 5617 Select a pen color from the pop-up menu. 5618 */ 5619 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5620 (const char **) ColorMenu,command); 5621 if (pen_number < 0) 5622 break; 5623 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5624 MagickFalse; 5625 if (transparent != MagickFalse) 5626 { 5627 draw_info.stencil=TransparentStencil; 5628 break; 5629 } 5630 if (pen_number == (MaxNumberPens-1)) 5631 { 5632 static char 5633 color_name[MaxTextExtent] = "gray"; 5634 5635 /* 5636 Select a pen color from a dialog. 5637 */ 5638 resource_info->pen_colors[pen_number]=color_name; 5639 XColorBrowserWidget(display,windows,"Select",color_name); 5640 if (*color_name == '\0') 5641 break; 5642 } 5643 /* 5644 Set pen color. 5645 */ 5646 (void) XParseColor(display,windows->map_info->colormap, 5647 resource_info->pen_colors[pen_number],&color); 5648 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5649 (unsigned int) MaxColors,&color); 5650 windows->pixel_info->pen_colors[pen_number]=color; 5651 pen_id=(unsigned int) pen_number; 5652 draw_info.stencil=OpaqueStencil; 5653 break; 5654 } 5655 case DrawStippleCommand: 5656 { 5657 Image 5658 *stipple_image; 5659 5660 ImageInfo 5661 *image_info; 5662 5663 int 5664 status; 5665 5666 static char 5667 filename[MaxTextExtent] = "\0"; 5668 5669 static const char 5670 *StipplesMenu[] = 5671 { 5672 "Brick", 5673 "Diagonal", 5674 "Scales", 5675 "Vertical", 5676 "Wavy", 5677 "Translucent", 5678 "Opaque", 5679 (char *) NULL, 5680 (char *) NULL, 5681 }; 5682 5683 /* 5684 Select a command from the pop-up menu. 5685 */ 5686 StipplesMenu[7]="Open..."; 5687 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5688 command); 5689 if (entry < 0) 5690 break; 5691 if (stipple != (Pixmap) NULL) 5692 (void) XFreePixmap(display,stipple); 5693 stipple=(Pixmap) NULL; 5694 if (entry != 7) 5695 { 5696 switch (entry) 5697 { 5698 case 0: 5699 { 5700 stipple=XCreateBitmapFromData(display,root_window, 5701 (char *) BricksBitmap,BricksWidth,BricksHeight); 5702 break; 5703 } 5704 case 1: 5705 { 5706 stipple=XCreateBitmapFromData(display,root_window, 5707 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5708 break; 5709 } 5710 case 2: 5711 { 5712 stipple=XCreateBitmapFromData(display,root_window, 5713 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5714 break; 5715 } 5716 case 3: 5717 { 5718 stipple=XCreateBitmapFromData(display,root_window, 5719 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5720 break; 5721 } 5722 case 4: 5723 { 5724 stipple=XCreateBitmapFromData(display,root_window, 5725 (char *) WavyBitmap,WavyWidth,WavyHeight); 5726 break; 5727 } 5728 case 5: 5729 { 5730 stipple=XCreateBitmapFromData(display,root_window, 5731 (char *) HighlightBitmap,HighlightWidth, 5732 HighlightHeight); 5733 break; 5734 } 5735 case 6: 5736 default: 5737 { 5738 stipple=XCreateBitmapFromData(display,root_window, 5739 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5740 break; 5741 } 5742 } 5743 break; 5744 } 5745 XFileBrowserWidget(display,windows,"Stipple",filename); 5746 if (*filename == '\0') 5747 break; 5748 /* 5749 Read image. 5750 */ 5751 XSetCursorState(display,windows,MagickTrue); 5752 XCheckRefreshWindows(display,windows); 5753 image_info=AcquireImageInfo(); 5754 (void) CopyMagickString(image_info->filename,filename, 5755 MaxTextExtent); 5756 stipple_image=ReadImage(image_info,exception); 5757 CatchException(exception); 5758 XSetCursorState(display,windows,MagickFalse); 5759 if (stipple_image == (Image *) NULL) 5760 break; 5761 (void) AcquireUniqueFileResource(filename); 5762 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5763 "xbm:%s",filename); 5764 (void) WriteImage(image_info,stipple_image,exception); 5765 stipple_image=DestroyImage(stipple_image); 5766 image_info=DestroyImageInfo(image_info); 5767 status=XReadBitmapFile(display,root_window,filename,&width, 5768 &height,&stipple,&x,&y); 5769 (void) RelinquishUniqueFileResource(filename); 5770 if ((status != BitmapSuccess) != 0) 5771 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5772 filename); 5773 break; 5774 } 5775 case DrawWidthCommand: 5776 { 5777 static char 5778 width[MaxTextExtent] = "0"; 5779 5780 static const char 5781 *WidthsMenu[] = 5782 { 5783 "1", 5784 "2", 5785 "4", 5786 "8", 5787 "16", 5788 "Dialog...", 5789 (char *) NULL, 5790 }; 5791 5792 /* 5793 Select a command from the pop-up menu. 5794 */ 5795 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5796 command); 5797 if (entry < 0) 5798 break; 5799 if (entry != 5) 5800 { 5801 line_width=(unsigned int) StringToUnsignedLong( 5802 WidthsMenu[entry]); 5803 break; 5804 } 5805 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5806 width); 5807 if (*width == '\0') 5808 break; 5809 line_width=(unsigned int) StringToUnsignedLong(width); 5810 break; 5811 } 5812 case DrawUndoCommand: 5813 { 5814 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5815 image,exception); 5816 break; 5817 } 5818 case DrawHelpCommand: 5819 { 5820 XTextViewWidget(display,resource_info,windows,MagickFalse, 5821 "Help Viewer - Image Rotation",ImageDrawHelp); 5822 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5823 break; 5824 } 5825 case DrawDismissCommand: 5826 { 5827 /* 5828 Prematurely exit. 5829 */ 5830 state|=EscapeState; 5831 state|=ExitState; 5832 break; 5833 } 5834 default: 5835 break; 5836 } 5837 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5838 continue; 5839 } 5840 switch (event.type) 5841 { 5842 case ButtonPress: 5843 { 5844 if (event.xbutton.button != Button1) 5845 break; 5846 if (event.xbutton.window != windows->image.id) 5847 break; 5848 /* 5849 exit loop. 5850 */ 5851 x=event.xbutton.x; 5852 y=event.xbutton.y; 5853 state|=ExitState; 5854 break; 5855 } 5856 case ButtonRelease: 5857 break; 5858 case Expose: 5859 break; 5860 case KeyPress: 5861 { 5862 KeySym 5863 key_symbol; 5864 5865 if (event.xkey.window != windows->image.id) 5866 break; 5867 /* 5868 Respond to a user key press. 5869 */ 5870 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5871 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5872 switch ((int) key_symbol) 5873 { 5874 case XK_Escape: 5875 case XK_F20: 5876 { 5877 /* 5878 Prematurely exit. 5879 */ 5880 state|=EscapeState; 5881 state|=ExitState; 5882 break; 5883 } 5884 case XK_F1: 5885 case XK_Help: 5886 { 5887 XTextViewWidget(display,resource_info,windows,MagickFalse, 5888 "Help Viewer - Image Rotation",ImageDrawHelp); 5889 break; 5890 } 5891 default: 5892 { 5893 (void) XBell(display,0); 5894 break; 5895 } 5896 } 5897 break; 5898 } 5899 case MotionNotify: 5900 { 5901 /* 5902 Map and unmap Info widget as text cursor crosses its boundaries. 5903 */ 5904 x=event.xmotion.x; 5905 y=event.xmotion.y; 5906 if (windows->info.mapped != MagickFalse) 5907 { 5908 if ((x < (int) (windows->info.x+windows->info.width)) && 5909 (y < (int) (windows->info.y+windows->info.height))) 5910 (void) XWithdrawWindow(display,windows->info.id, 5911 windows->info.screen); 5912 } 5913 else 5914 if ((x > (int) (windows->info.x+windows->info.width)) || 5915 (y > (int) (windows->info.y+windows->info.height))) 5916 (void) XMapWindow(display,windows->info.id); 5917 break; 5918 } 5919 } 5920 } while ((state & ExitState) == 0); 5921 (void) XSelectInput(display,windows->image.id, 5922 windows->image.attributes.event_mask); 5923 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5924 if ((state & EscapeState) != 0) 5925 break; 5926 /* 5927 Draw element as pointer moves until the button is released. 5928 */ 5929 distance=0; 5930 degrees=0.0; 5931 line_info.x1=x; 5932 line_info.y1=y; 5933 line_info.x2=x; 5934 line_info.y2=y; 5935 rectangle_info.x=(ssize_t) x; 5936 rectangle_info.y=(ssize_t) y; 5937 rectangle_info.width=0; 5938 rectangle_info.height=0; 5939 number_coordinates=1; 5940 coordinate_info->x=x; 5941 coordinate_info->y=y; 5942 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5943 state=DefaultState; 5944 do 5945 { 5946 switch (element) 5947 { 5948 case PointElement: 5949 default: 5950 { 5951 if (number_coordinates > 1) 5952 { 5953 (void) XDrawLines(display,windows->image.id, 5954 windows->image.highlight_context,coordinate_info, 5955 number_coordinates,CoordModeOrigin); 5956 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5957 coordinate_info[number_coordinates-1].x, 5958 coordinate_info[number_coordinates-1].y); 5959 XInfoWidget(display,windows,text); 5960 } 5961 break; 5962 } 5963 case LineElement: 5964 { 5965 if (distance > 9) 5966 { 5967 /* 5968 Display angle of the line. 5969 */ 5970 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5971 line_info.y1),(double) (line_info.x2-line_info.x1))); 5972 (void) FormatLocaleString(text,MaxTextExtent," %g", 5973 (double) degrees); 5974 XInfoWidget(display,windows,text); 5975 XHighlightLine(display,windows->image.id, 5976 windows->image.highlight_context,&line_info); 5977 } 5978 else 5979 if (windows->info.mapped != MagickFalse) 5980 (void) XWithdrawWindow(display,windows->info.id, 5981 windows->info.screen); 5982 break; 5983 } 5984 case RectangleElement: 5985 case FillRectangleElement: 5986 { 5987 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5988 { 5989 /* 5990 Display info and draw drawing rectangle. 5991 */ 5992 (void) FormatLocaleString(text,MaxTextExtent, 5993 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5994 (double) rectangle_info.height,(double) rectangle_info.x, 5995 (double) rectangle_info.y); 5996 XInfoWidget(display,windows,text); 5997 XHighlightRectangle(display,windows->image.id, 5998 windows->image.highlight_context,&rectangle_info); 5999 } 6000 else 6001 if (windows->info.mapped != MagickFalse) 6002 (void) XWithdrawWindow(display,windows->info.id, 6003 windows->info.screen); 6004 break; 6005 } 6006 case CircleElement: 6007 case FillCircleElement: 6008 case EllipseElement: 6009 case FillEllipseElement: 6010 { 6011 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6012 { 6013 /* 6014 Display info and draw drawing rectangle. 6015 */ 6016 (void) FormatLocaleString(text,MaxTextExtent, 6017 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6018 (double) rectangle_info.height,(double) rectangle_info.x, 6019 (double) rectangle_info.y); 6020 XInfoWidget(display,windows,text); 6021 XHighlightEllipse(display,windows->image.id, 6022 windows->image.highlight_context,&rectangle_info); 6023 } 6024 else 6025 if (windows->info.mapped != MagickFalse) 6026 (void) XWithdrawWindow(display,windows->info.id, 6027 windows->info.screen); 6028 break; 6029 } 6030 case PolygonElement: 6031 case FillPolygonElement: 6032 { 6033 if (number_coordinates > 1) 6034 (void) XDrawLines(display,windows->image.id, 6035 windows->image.highlight_context,coordinate_info, 6036 number_coordinates,CoordModeOrigin); 6037 if (distance > 9) 6038 { 6039 /* 6040 Display angle of the line. 6041 */ 6042 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6043 line_info.y1),(double) (line_info.x2-line_info.x1))); 6044 (void) FormatLocaleString(text,MaxTextExtent," %g", 6045 (double) degrees); 6046 XInfoWidget(display,windows,text); 6047 XHighlightLine(display,windows->image.id, 6048 windows->image.highlight_context,&line_info); 6049 } 6050 else 6051 if (windows->info.mapped != MagickFalse) 6052 (void) XWithdrawWindow(display,windows->info.id, 6053 windows->info.screen); 6054 break; 6055 } 6056 } 6057 /* 6058 Wait for next event. 6059 */ 6060 XScreenEvent(display,windows,&event); 6061 switch (element) 6062 { 6063 case PointElement: 6064 default: 6065 { 6066 if (number_coordinates > 1) 6067 (void) XDrawLines(display,windows->image.id, 6068 windows->image.highlight_context,coordinate_info, 6069 number_coordinates,CoordModeOrigin); 6070 break; 6071 } 6072 case LineElement: 6073 { 6074 if (distance > 9) 6075 XHighlightLine(display,windows->image.id, 6076 windows->image.highlight_context,&line_info); 6077 break; 6078 } 6079 case RectangleElement: 6080 case FillRectangleElement: 6081 { 6082 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6083 XHighlightRectangle(display,windows->image.id, 6084 windows->image.highlight_context,&rectangle_info); 6085 break; 6086 } 6087 case CircleElement: 6088 case FillCircleElement: 6089 case EllipseElement: 6090 case FillEllipseElement: 6091 { 6092 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6093 XHighlightEllipse(display,windows->image.id, 6094 windows->image.highlight_context,&rectangle_info); 6095 break; 6096 } 6097 case PolygonElement: 6098 case FillPolygonElement: 6099 { 6100 if (number_coordinates > 1) 6101 (void) XDrawLines(display,windows->image.id, 6102 windows->image.highlight_context,coordinate_info, 6103 number_coordinates,CoordModeOrigin); 6104 if (distance > 9) 6105 XHighlightLine(display,windows->image.id, 6106 windows->image.highlight_context,&line_info); 6107 break; 6108 } 6109 } 6110 switch (event.type) 6111 { 6112 case ButtonPress: 6113 break; 6114 case ButtonRelease: 6115 { 6116 /* 6117 User has committed to element. 6118 */ 6119 line_info.x2=event.xbutton.x; 6120 line_info.y2=event.xbutton.y; 6121 rectangle_info.x=(ssize_t) event.xbutton.x; 6122 rectangle_info.y=(ssize_t) event.xbutton.y; 6123 coordinate_info[number_coordinates].x=event.xbutton.x; 6124 coordinate_info[number_coordinates].y=event.xbutton.y; 6125 if (((element != PolygonElement) && 6126 (element != FillPolygonElement)) || (distance <= 9)) 6127 { 6128 state|=ExitState; 6129 break; 6130 } 6131 number_coordinates++; 6132 if (number_coordinates < (int) max_coordinates) 6133 { 6134 line_info.x1=event.xbutton.x; 6135 line_info.y1=event.xbutton.y; 6136 break; 6137 } 6138 max_coordinates<<=1; 6139 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6140 max_coordinates,sizeof(*coordinate_info)); 6141 if (coordinate_info == (XPoint *) NULL) 6142 (void) ThrowMagickException(exception,GetMagickModule(), 6143 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6144 break; 6145 } 6146 case Expose: 6147 break; 6148 case MotionNotify: 6149 { 6150 if (event.xmotion.window != windows->image.id) 6151 break; 6152 if (element != PointElement) 6153 { 6154 line_info.x2=event.xmotion.x; 6155 line_info.y2=event.xmotion.y; 6156 rectangle_info.x=(ssize_t) event.xmotion.x; 6157 rectangle_info.y=(ssize_t) event.xmotion.y; 6158 break; 6159 } 6160 coordinate_info[number_coordinates].x=event.xbutton.x; 6161 coordinate_info[number_coordinates].y=event.xbutton.y; 6162 number_coordinates++; 6163 if (number_coordinates < (int) max_coordinates) 6164 break; 6165 max_coordinates<<=1; 6166 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6167 max_coordinates,sizeof(*coordinate_info)); 6168 if (coordinate_info == (XPoint *) NULL) 6169 (void) ThrowMagickException(exception,GetMagickModule(), 6170 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6171 break; 6172 } 6173 default: 6174 break; 6175 } 6176 /* 6177 Check boundary conditions. 6178 */ 6179 if (line_info.x2 < 0) 6180 line_info.x2=0; 6181 else 6182 if (line_info.x2 > (int) windows->image.width) 6183 line_info.x2=(short) windows->image.width; 6184 if (line_info.y2 < 0) 6185 line_info.y2=0; 6186 else 6187 if (line_info.y2 > (int) windows->image.height) 6188 line_info.y2=(short) windows->image.height; 6189 distance=(unsigned int) 6190 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6191 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6192 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6193 ((state & ExitState) != 0)) 6194 { 6195 if (rectangle_info.x < 0) 6196 rectangle_info.x=0; 6197 else 6198 if (rectangle_info.x > (ssize_t) windows->image.width) 6199 rectangle_info.x=(ssize_t) windows->image.width; 6200 if ((int) rectangle_info.x < x) 6201 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6202 else 6203 { 6204 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6205 rectangle_info.x=(ssize_t) x; 6206 } 6207 if (rectangle_info.y < 0) 6208 rectangle_info.y=0; 6209 else 6210 if (rectangle_info.y > (ssize_t) windows->image.height) 6211 rectangle_info.y=(ssize_t) windows->image.height; 6212 if ((int) rectangle_info.y < y) 6213 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6214 else 6215 { 6216 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6217 rectangle_info.y=(ssize_t) y; 6218 } 6219 } 6220 } while ((state & ExitState) == 0); 6221 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6222 if ((element == PointElement) || (element == PolygonElement) || 6223 (element == FillPolygonElement)) 6224 { 6225 /* 6226 Determine polygon bounding box. 6227 */ 6228 rectangle_info.x=(ssize_t) coordinate_info->x; 6229 rectangle_info.y=(ssize_t) coordinate_info->y; 6230 x=coordinate_info->x; 6231 y=coordinate_info->y; 6232 for (i=1; i < number_coordinates; i++) 6233 { 6234 if (coordinate_info[i].x > x) 6235 x=coordinate_info[i].x; 6236 if (coordinate_info[i].y > y) 6237 y=coordinate_info[i].y; 6238 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6239 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6240 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6241 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6242 } 6243 rectangle_info.width=(size_t) (x-rectangle_info.x); 6244 rectangle_info.height=(size_t) (y-rectangle_info.y); 6245 for (i=0; i < number_coordinates; i++) 6246 { 6247 coordinate_info[i].x-=rectangle_info.x; 6248 coordinate_info[i].y-=rectangle_info.y; 6249 } 6250 } 6251 else 6252 if (distance <= 9) 6253 continue; 6254 else 6255 if ((element == RectangleElement) || 6256 (element == CircleElement) || (element == EllipseElement)) 6257 { 6258 rectangle_info.width--; 6259 rectangle_info.height--; 6260 } 6261 /* 6262 Drawing is relative to image configuration. 6263 */ 6264 draw_info.x=(int) rectangle_info.x; 6265 draw_info.y=(int) rectangle_info.y; 6266 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6267 image,exception); 6268 width=(unsigned int) (*image)->columns; 6269 height=(unsigned int) (*image)->rows; 6270 x=0; 6271 y=0; 6272 if (windows->image.crop_geometry != (char *) NULL) 6273 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6274 draw_info.x+=windows->image.x-(line_width/2); 6275 if (draw_info.x < 0) 6276 draw_info.x=0; 6277 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6278 draw_info.y+=windows->image.y-(line_width/2); 6279 if (draw_info.y < 0) 6280 draw_info.y=0; 6281 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6282 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6283 if (draw_info.width > (unsigned int) (*image)->columns) 6284 draw_info.width=(unsigned int) (*image)->columns; 6285 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6286 if (draw_info.height > (unsigned int) (*image)->rows) 6287 draw_info.height=(unsigned int) (*image)->rows; 6288 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6289 width*draw_info.width/windows->image.ximage->width, 6290 height*draw_info.height/windows->image.ximage->height, 6291 draw_info.x+x,draw_info.y+y); 6292 /* 6293 Initialize drawing attributes. 6294 */ 6295 draw_info.degrees=0.0; 6296 draw_info.element=element; 6297 draw_info.stipple=stipple; 6298 draw_info.line_width=line_width; 6299 draw_info.line_info=line_info; 6300 if (line_info.x1 > (int) (line_width/2)) 6301 draw_info.line_info.x1=(short) line_width/2; 6302 if (line_info.y1 > (int) (line_width/2)) 6303 draw_info.line_info.y1=(short) line_width/2; 6304 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6305 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6306 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6307 { 6308 draw_info.line_info.x2=(-draw_info.line_info.x2); 6309 draw_info.line_info.y2=(-draw_info.line_info.y2); 6310 } 6311 if (draw_info.line_info.x2 < 0) 6312 { 6313 draw_info.line_info.x2=(-draw_info.line_info.x2); 6314 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6315 } 6316 if (draw_info.line_info.y2 < 0) 6317 { 6318 draw_info.line_info.y2=(-draw_info.line_info.y2); 6319 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6320 } 6321 draw_info.rectangle_info=rectangle_info; 6322 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6323 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6324 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6325 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6326 draw_info.number_coordinates=(unsigned int) number_coordinates; 6327 draw_info.coordinate_info=coordinate_info; 6328 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6329 /* 6330 Draw element on image. 6331 */ 6332 XSetCursorState(display,windows,MagickTrue); 6333 XCheckRefreshWindows(display,windows); 6334 status=XDrawImage(display,windows->pixel_info,&draw_info,*image); 6335 XSetCursorState(display,windows,MagickFalse); 6336 /* 6337 Update image colormap and return to image drawing. 6338 */ 6339 XConfigureImageColormap(display,resource_info,windows,*image); 6340 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6341 } 6342 XSetCursorState(display,windows,MagickFalse); 6343 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6344 return(status != 0 ? MagickTrue : MagickFalse); 6345} 6346 6347/* 6348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6349% % 6350% % 6351% % 6352+ X D r a w P a n R e c t a n g l e % 6353% % 6354% % 6355% % 6356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6357% 6358% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6359% displays a zoom image and the rectangle shows which portion of the image is 6360% displayed in the Image window. 6361% 6362% The format of the XDrawPanRectangle method is: 6363% 6364% XDrawPanRectangle(Display *display,XWindows *windows) 6365% 6366% A description of each parameter follows: 6367% 6368% o display: Specifies a connection to an X server; returned from 6369% XOpenDisplay. 6370% 6371% o windows: Specifies a pointer to a XWindows structure. 6372% 6373*/ 6374static void XDrawPanRectangle(Display *display,XWindows *windows) 6375{ 6376 MagickRealType 6377 scale_factor; 6378 6379 RectangleInfo 6380 highlight_info; 6381 6382 /* 6383 Determine dimensions of the panning rectangle. 6384 */ 6385 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6386 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6387 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6388 scale_factor=(MagickRealType) 6389 windows->pan.height/windows->image.ximage->height; 6390 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6391 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6392 /* 6393 Display the panning rectangle. 6394 */ 6395 (void) XClearWindow(display,windows->pan.id); 6396 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6397 &highlight_info); 6398} 6399 6400/* 6401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6402% % 6403% % 6404% % 6405+ X I m a g e C a c h e % 6406% % 6407% % 6408% % 6409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6410% 6411% XImageCache() handles the creation, manipulation, and destruction of the 6412% image cache (undo and redo buffers). 6413% 6414% The format of the XImageCache method is: 6415% 6416% void XImageCache(Display *display,XResourceInfo *resource_info, 6417% XWindows *windows,const CommandType command,Image **image, 6418% ExceptionInfo *exception) 6419% 6420% A description of each parameter follows: 6421% 6422% o display: Specifies a connection to an X server; returned from 6423% XOpenDisplay. 6424% 6425% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6426% 6427% o windows: Specifies a pointer to a XWindows structure. 6428% 6429% o command: Specifies a command to perform. 6430% 6431% o image: the image; XImageCache may transform the image and return a new 6432% image pointer. 6433% 6434% o exception: return any errors or warnings in this structure. 6435% 6436*/ 6437static void XImageCache(Display *display,XResourceInfo *resource_info, 6438 XWindows *windows,const CommandType command,Image **image, 6439 ExceptionInfo *exception) 6440{ 6441 Image 6442 *cache_image; 6443 6444 static Image 6445 *redo_image = (Image *) NULL, 6446 *undo_image = (Image *) NULL; 6447 6448 switch (command) 6449 { 6450 case FreeBuffersCommand: 6451 { 6452 /* 6453 Free memory from the undo and redo cache. 6454 */ 6455 while (undo_image != (Image *) NULL) 6456 { 6457 cache_image=undo_image; 6458 undo_image=GetPreviousImageInList(undo_image); 6459 cache_image->list=DestroyImage(cache_image->list); 6460 cache_image=DestroyImage(cache_image); 6461 } 6462 undo_image=NewImageList(); 6463 if (redo_image != (Image *) NULL) 6464 redo_image=DestroyImage(redo_image); 6465 redo_image=NewImageList(); 6466 return; 6467 } 6468 case UndoCommand: 6469 { 6470 char 6471 image_geometry[MaxTextExtent]; 6472 6473 /* 6474 Undo the last image transformation. 6475 */ 6476 if (undo_image == (Image *) NULL) 6477 { 6478 (void) XBell(display,0); 6479 return; 6480 } 6481 cache_image=undo_image; 6482 undo_image=GetPreviousImageInList(undo_image); 6483 windows->image.window_changes.width=(int) cache_image->columns; 6484 windows->image.window_changes.height=(int) cache_image->rows; 6485 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6486 windows->image.ximage->width,windows->image.ximage->height); 6487 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6488 exception); 6489 if (windows->image.crop_geometry != (char *) NULL) 6490 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6491 windows->image.crop_geometry); 6492 windows->image.crop_geometry=cache_image->geometry; 6493 if (redo_image != (Image *) NULL) 6494 redo_image=DestroyImage(redo_image); 6495 redo_image=(*image); 6496 *image=cache_image->list; 6497 cache_image=DestroyImage(cache_image); 6498 if (windows->image.orphan != MagickFalse) 6499 return; 6500 XConfigureImageColormap(display,resource_info,windows,*image); 6501 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6502 return; 6503 } 6504 case CutCommand: 6505 case PasteCommand: 6506 case ApplyCommand: 6507 case HalfSizeCommand: 6508 case OriginalSizeCommand: 6509 case DoubleSizeCommand: 6510 case ResizeCommand: 6511 case TrimCommand: 6512 case CropCommand: 6513 case ChopCommand: 6514 case FlipCommand: 6515 case FlopCommand: 6516 case RotateRightCommand: 6517 case RotateLeftCommand: 6518 case RotateCommand: 6519 case ShearCommand: 6520 case RollCommand: 6521 case NegateCommand: 6522 case ContrastStretchCommand: 6523 case SigmoidalContrastCommand: 6524 case NormalizeCommand: 6525 case EqualizeCommand: 6526 case HueCommand: 6527 case SaturationCommand: 6528 case BrightnessCommand: 6529 case GammaCommand: 6530 case SpiffCommand: 6531 case DullCommand: 6532 case GrayscaleCommand: 6533 case MapCommand: 6534 case QuantizeCommand: 6535 case DespeckleCommand: 6536 case EmbossCommand: 6537 case ReduceNoiseCommand: 6538 case AddNoiseCommand: 6539 case SharpenCommand: 6540 case BlurCommand: 6541 case ThresholdCommand: 6542 case EdgeDetectCommand: 6543 case SpreadCommand: 6544 case ShadeCommand: 6545 case RaiseCommand: 6546 case SegmentCommand: 6547 case SolarizeCommand: 6548 case SepiaToneCommand: 6549 case SwirlCommand: 6550 case ImplodeCommand: 6551 case VignetteCommand: 6552 case WaveCommand: 6553 case OilPaintCommand: 6554 case CharcoalDrawCommand: 6555 case AnnotateCommand: 6556 case AddBorderCommand: 6557 case AddFrameCommand: 6558 case CompositeCommand: 6559 case CommentCommand: 6560 case LaunchCommand: 6561 case RegionofInterestCommand: 6562 case SaveToUndoBufferCommand: 6563 case RedoCommand: 6564 { 6565 Image 6566 *previous_image; 6567 6568 ssize_t 6569 bytes; 6570 6571 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6572 if (undo_image != (Image *) NULL) 6573 { 6574 /* 6575 Ensure the undo cache has enough memory available. 6576 */ 6577 previous_image=undo_image; 6578 while (previous_image != (Image *) NULL) 6579 { 6580 bytes+=previous_image->list->columns*previous_image->list->rows* 6581 sizeof(PixelInfo); 6582 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6583 { 6584 previous_image=GetPreviousImageInList(previous_image); 6585 continue; 6586 } 6587 bytes-=previous_image->list->columns*previous_image->list->rows* 6588 sizeof(PixelInfo); 6589 if (previous_image == undo_image) 6590 undo_image=NewImageList(); 6591 else 6592 previous_image->next->previous=NewImageList(); 6593 break; 6594 } 6595 while (previous_image != (Image *) NULL) 6596 { 6597 /* 6598 Delete any excess memory from undo cache. 6599 */ 6600 cache_image=previous_image; 6601 previous_image=GetPreviousImageInList(previous_image); 6602 cache_image->list=DestroyImage(cache_image->list); 6603 cache_image=DestroyImage(cache_image); 6604 } 6605 } 6606 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6607 break; 6608 /* 6609 Save image before transformations are applied. 6610 */ 6611 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6612 if (cache_image == (Image *) NULL) 6613 break; 6614 XSetCursorState(display,windows,MagickTrue); 6615 XCheckRefreshWindows(display,windows); 6616 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6617 XSetCursorState(display,windows,MagickFalse); 6618 if (cache_image->list == (Image *) NULL) 6619 { 6620 cache_image=DestroyImage(cache_image); 6621 break; 6622 } 6623 cache_image->columns=(size_t) windows->image.ximage->width; 6624 cache_image->rows=(size_t) windows->image.ximage->height; 6625 cache_image->geometry=windows->image.crop_geometry; 6626 if (windows->image.crop_geometry != (char *) NULL) 6627 { 6628 cache_image->geometry=AcquireString((char *) NULL); 6629 (void) CopyMagickString(cache_image->geometry, 6630 windows->image.crop_geometry,MaxTextExtent); 6631 } 6632 if (undo_image == (Image *) NULL) 6633 { 6634 undo_image=cache_image; 6635 break; 6636 } 6637 undo_image->next=cache_image; 6638 undo_image->next->previous=undo_image; 6639 undo_image=undo_image->next; 6640 break; 6641 } 6642 default: 6643 break; 6644 } 6645 if (command == RedoCommand) 6646 { 6647 /* 6648 Redo the last image transformation. 6649 */ 6650 if (redo_image == (Image *) NULL) 6651 { 6652 (void) XBell(display,0); 6653 return; 6654 } 6655 windows->image.window_changes.width=(int) redo_image->columns; 6656 windows->image.window_changes.height=(int) redo_image->rows; 6657 if (windows->image.crop_geometry != (char *) NULL) 6658 windows->image.crop_geometry=(char *) 6659 RelinquishMagickMemory(windows->image.crop_geometry); 6660 windows->image.crop_geometry=redo_image->geometry; 6661 *image=DestroyImage(*image); 6662 *image=redo_image; 6663 redo_image=NewImageList(); 6664 if (windows->image.orphan != MagickFalse) 6665 return; 6666 XConfigureImageColormap(display,resource_info,windows,*image); 6667 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6668 return; 6669 } 6670 if (command != InfoCommand) 6671 return; 6672 /* 6673 Display image info. 6674 */ 6675 XSetCursorState(display,windows,MagickTrue); 6676 XCheckRefreshWindows(display,windows); 6677 XDisplayImageInfo(display,resource_info,windows,undo_image,*image); 6678 XSetCursorState(display,windows,MagickFalse); 6679} 6680 6681/* 6682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6683% % 6684% % 6685% % 6686+ X I m a g e W i n d o w C o m m a n d % 6687% % 6688% % 6689% % 6690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6691% 6692% XImageWindowCommand() makes a transform to the image or Image window as 6693% specified by a user menu button or keyboard command. 6694% 6695% The format of the XImageWindowCommand method is: 6696% 6697% CommandType XImageWindowCommand(Display *display, 6698% XResourceInfo *resource_info,XWindows *windows, 6699% const MagickStatusType state,KeySym key_symbol,Image **image, 6700% ExceptionInfo *exception) 6701% 6702% A description of each parameter follows: 6703% 6704% o nexus: Method XImageWindowCommand returns an image when the 6705% user chooses 'Open Image' from the command menu. Otherwise a null 6706% image is returned. 6707% 6708% o display: Specifies a connection to an X server; returned from 6709% XOpenDisplay. 6710% 6711% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6712% 6713% o windows: Specifies a pointer to a XWindows structure. 6714% 6715% o state: key mask. 6716% 6717% o key_symbol: Specifies a command to perform. 6718% 6719% o image: the image; XImageWIndowCommand may transform the image and 6720% return a new image pointer. 6721% 6722% o exception: return any errors or warnings in this structure. 6723% 6724*/ 6725static CommandType XImageWindowCommand(Display *display, 6726 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6727 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6728{ 6729 static char 6730 delta[MaxTextExtent] = ""; 6731 6732 static const char 6733 Digits[] = "01234567890"; 6734 6735 static KeySym 6736 last_symbol = XK_0; 6737 6738 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6739 { 6740 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6741 { 6742 *delta='\0'; 6743 resource_info->quantum=1; 6744 } 6745 last_symbol=key_symbol; 6746 delta[strlen(delta)+1]='\0'; 6747 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6748 resource_info->quantum=StringToLong(delta); 6749 return(NullCommand); 6750 } 6751 last_symbol=key_symbol; 6752 if (resource_info->immutable) 6753 { 6754 /* 6755 Virtual image window has a restricted command set. 6756 */ 6757 switch (key_symbol) 6758 { 6759 case XK_question: 6760 return(InfoCommand); 6761 case XK_p: 6762 case XK_Print: 6763 return(PrintCommand); 6764 case XK_space: 6765 return(NextCommand); 6766 case XK_q: 6767 case XK_Escape: 6768 return(QuitCommand); 6769 default: 6770 break; 6771 } 6772 return(NullCommand); 6773 } 6774 switch ((int) key_symbol) 6775 { 6776 case XK_o: 6777 { 6778 if ((state & ControlMask) == 0) 6779 break; 6780 return(OpenCommand); 6781 } 6782 case XK_space: 6783 return(NextCommand); 6784 case XK_BackSpace: 6785 return(FormerCommand); 6786 case XK_s: 6787 { 6788 if ((state & Mod1Mask) != 0) 6789 return(SwirlCommand); 6790 if ((state & ControlMask) == 0) 6791 return(ShearCommand); 6792 return(SaveCommand); 6793 } 6794 case XK_p: 6795 case XK_Print: 6796 { 6797 if ((state & Mod1Mask) != 0) 6798 return(OilPaintCommand); 6799 if ((state & Mod4Mask) != 0) 6800 return(ColorCommand); 6801 if ((state & ControlMask) == 0) 6802 return(NullCommand); 6803 return(PrintCommand); 6804 } 6805 case XK_d: 6806 { 6807 if ((state & Mod4Mask) != 0) 6808 return(DrawCommand); 6809 if ((state & ControlMask) == 0) 6810 return(NullCommand); 6811 return(DeleteCommand); 6812 } 6813 case XK_Select: 6814 { 6815 if ((state & ControlMask) == 0) 6816 return(NullCommand); 6817 return(SelectCommand); 6818 } 6819 case XK_n: 6820 { 6821 if ((state & ControlMask) == 0) 6822 return(NullCommand); 6823 return(NewCommand); 6824 } 6825 case XK_q: 6826 case XK_Escape: 6827 return(QuitCommand); 6828 case XK_z: 6829 case XK_Undo: 6830 { 6831 if ((state & ControlMask) == 0) 6832 return(NullCommand); 6833 return(UndoCommand); 6834 } 6835 case XK_r: 6836 case XK_Redo: 6837 { 6838 if ((state & ControlMask) == 0) 6839 return(RollCommand); 6840 return(RedoCommand); 6841 } 6842 case XK_x: 6843 { 6844 if ((state & ControlMask) == 0) 6845 return(NullCommand); 6846 return(CutCommand); 6847 } 6848 case XK_c: 6849 { 6850 if ((state & Mod1Mask) != 0) 6851 return(CharcoalDrawCommand); 6852 if ((state & ControlMask) == 0) 6853 return(CropCommand); 6854 return(CopyCommand); 6855 } 6856 case XK_v: 6857 case XK_Insert: 6858 { 6859 if ((state & Mod4Mask) != 0) 6860 return(CompositeCommand); 6861 if ((state & ControlMask) == 0) 6862 return(FlipCommand); 6863 return(PasteCommand); 6864 } 6865 case XK_less: 6866 return(HalfSizeCommand); 6867 case XK_minus: 6868 return(OriginalSizeCommand); 6869 case XK_greater: 6870 return(DoubleSizeCommand); 6871 case XK_percent: 6872 return(ResizeCommand); 6873 case XK_at: 6874 return(RefreshCommand); 6875 case XK_bracketleft: 6876 return(ChopCommand); 6877 case XK_h: 6878 return(FlopCommand); 6879 case XK_slash: 6880 return(RotateRightCommand); 6881 case XK_backslash: 6882 return(RotateLeftCommand); 6883 case XK_asterisk: 6884 return(RotateCommand); 6885 case XK_t: 6886 return(TrimCommand); 6887 case XK_H: 6888 return(HueCommand); 6889 case XK_S: 6890 return(SaturationCommand); 6891 case XK_L: 6892 return(BrightnessCommand); 6893 case XK_G: 6894 return(GammaCommand); 6895 case XK_C: 6896 return(SpiffCommand); 6897 case XK_Z: 6898 return(DullCommand); 6899 case XK_N: 6900 return(NormalizeCommand); 6901 case XK_equal: 6902 return(EqualizeCommand); 6903 case XK_asciitilde: 6904 return(NegateCommand); 6905 case XK_period: 6906 return(GrayscaleCommand); 6907 case XK_numbersign: 6908 return(QuantizeCommand); 6909 case XK_F2: 6910 return(DespeckleCommand); 6911 case XK_F3: 6912 return(EmbossCommand); 6913 case XK_F4: 6914 return(ReduceNoiseCommand); 6915 case XK_F5: 6916 return(AddNoiseCommand); 6917 case XK_F6: 6918 return(SharpenCommand); 6919 case XK_F7: 6920 return(BlurCommand); 6921 case XK_F8: 6922 return(ThresholdCommand); 6923 case XK_F9: 6924 return(EdgeDetectCommand); 6925 case XK_F10: 6926 return(SpreadCommand); 6927 case XK_F11: 6928 return(ShadeCommand); 6929 case XK_F12: 6930 return(RaiseCommand); 6931 case XK_F13: 6932 return(SegmentCommand); 6933 case XK_i: 6934 { 6935 if ((state & Mod1Mask) == 0) 6936 return(NullCommand); 6937 return(ImplodeCommand); 6938 } 6939 case XK_w: 6940 { 6941 if ((state & Mod1Mask) == 0) 6942 return(NullCommand); 6943 return(WaveCommand); 6944 } 6945 case XK_m: 6946 { 6947 if ((state & Mod4Mask) == 0) 6948 return(NullCommand); 6949 return(MatteCommand); 6950 } 6951 case XK_b: 6952 { 6953 if ((state & Mod4Mask) == 0) 6954 return(NullCommand); 6955 return(AddBorderCommand); 6956 } 6957 case XK_f: 6958 { 6959 if ((state & Mod4Mask) == 0) 6960 return(NullCommand); 6961 return(AddFrameCommand); 6962 } 6963 case XK_exclam: 6964 { 6965 if ((state & Mod4Mask) == 0) 6966 return(NullCommand); 6967 return(CommentCommand); 6968 } 6969 case XK_a: 6970 { 6971 if ((state & Mod1Mask) != 0) 6972 return(ApplyCommand); 6973 if ((state & Mod4Mask) != 0) 6974 return(AnnotateCommand); 6975 if ((state & ControlMask) == 0) 6976 return(NullCommand); 6977 return(RegionofInterestCommand); 6978 } 6979 case XK_question: 6980 return(InfoCommand); 6981 case XK_plus: 6982 return(ZoomCommand); 6983 case XK_P: 6984 { 6985 if ((state & ShiftMask) == 0) 6986 return(NullCommand); 6987 return(ShowPreviewCommand); 6988 } 6989 case XK_Execute: 6990 return(LaunchCommand); 6991 case XK_F1: 6992 return(HelpCommand); 6993 case XK_Find: 6994 return(BrowseDocumentationCommand); 6995 case XK_Menu: 6996 { 6997 (void) XMapRaised(display,windows->command.id); 6998 return(NullCommand); 6999 } 7000 case XK_Next: 7001 case XK_Prior: 7002 case XK_Home: 7003 case XK_KP_Home: 7004 { 7005 XTranslateImage(display,windows,*image,key_symbol); 7006 return(NullCommand); 7007 } 7008 case XK_Up: 7009 case XK_KP_Up: 7010 case XK_Down: 7011 case XK_KP_Down: 7012 case XK_Left: 7013 case XK_KP_Left: 7014 case XK_Right: 7015 case XK_KP_Right: 7016 { 7017 if ((state & Mod1Mask) != 0) 7018 { 7019 RectangleInfo 7020 crop_info; 7021 7022 /* 7023 Trim one pixel from edge of image. 7024 */ 7025 crop_info.x=0; 7026 crop_info.y=0; 7027 crop_info.width=(size_t) windows->image.ximage->width; 7028 crop_info.height=(size_t) windows->image.ximage->height; 7029 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7030 { 7031 if (resource_info->quantum >= (int) crop_info.height) 7032 resource_info->quantum=(int) crop_info.height-1; 7033 crop_info.height-=resource_info->quantum; 7034 } 7035 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7036 { 7037 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7038 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7039 crop_info.y+=resource_info->quantum; 7040 crop_info.height-=resource_info->quantum; 7041 } 7042 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7043 { 7044 if (resource_info->quantum >= (int) crop_info.width) 7045 resource_info->quantum=(int) crop_info.width-1; 7046 crop_info.width-=resource_info->quantum; 7047 } 7048 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7049 { 7050 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7051 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7052 crop_info.x+=resource_info->quantum; 7053 crop_info.width-=resource_info->quantum; 7054 } 7055 if ((int) (windows->image.x+windows->image.width) > 7056 (int) crop_info.width) 7057 windows->image.x=(int) (crop_info.width-windows->image.width); 7058 if ((int) (windows->image.y+windows->image.height) > 7059 (int) crop_info.height) 7060 windows->image.y=(int) (crop_info.height-windows->image.height); 7061 XSetCropGeometry(display,windows,&crop_info,*image); 7062 windows->image.window_changes.width=(int) crop_info.width; 7063 windows->image.window_changes.height=(int) crop_info.height; 7064 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7065 (void) XConfigureImage(display,resource_info,windows,*image, 7066 exception); 7067 return(NullCommand); 7068 } 7069 XTranslateImage(display,windows,*image,key_symbol); 7070 return(NullCommand); 7071 } 7072 default: 7073 return(NullCommand); 7074 } 7075 return(NullCommand); 7076} 7077 7078/* 7079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7080% % 7081% % 7082% % 7083+ X M a g i c k C o m m a n d % 7084% % 7085% % 7086% % 7087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7088% 7089% XMagickCommand() makes a transform to the image or Image window as 7090% specified by a user menu button or keyboard command. 7091% 7092% The format of the XMagickCommand method is: 7093% 7094% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7095% XWindows *windows,const CommandType command,Image **image, 7096% ExceptionInfo *exception) 7097% 7098% A description of each parameter follows: 7099% 7100% o display: Specifies a connection to an X server; returned from 7101% XOpenDisplay. 7102% 7103% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7104% 7105% o windows: Specifies a pointer to a XWindows structure. 7106% 7107% o command: Specifies a command to perform. 7108% 7109% o image: the image; XMagickCommand may transform the image and return a 7110% new image pointer. 7111% 7112% o exception: return any errors or warnings in this structure. 7113% 7114*/ 7115static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7116 XWindows *windows,const CommandType command,Image **image, 7117 ExceptionInfo *exception) 7118{ 7119 char 7120 filename[MaxTextExtent], 7121 geometry[MaxTextExtent], 7122 modulate_factors[MaxTextExtent]; 7123 7124 GeometryInfo 7125 geometry_info; 7126 7127 Image 7128 *nexus; 7129 7130 ImageInfo 7131 *image_info; 7132 7133 int 7134 x, 7135 y; 7136 7137 MagickStatusType 7138 flags, 7139 status; 7140 7141 QuantizeInfo 7142 quantize_info; 7143 7144 RectangleInfo 7145 page_geometry; 7146 7147 register int 7148 i; 7149 7150 static char 7151 color[MaxTextExtent] = "gray"; 7152 7153 unsigned int 7154 height, 7155 width; 7156 7157 /* 7158 Process user command. 7159 */ 7160 XCheckRefreshWindows(display,windows); 7161 XImageCache(display,resource_info,windows,command,image,exception); 7162 nexus=NewImageList(); 7163 windows->image.window_changes.width=windows->image.ximage->width; 7164 windows->image.window_changes.height=windows->image.ximage->height; 7165 image_info=CloneImageInfo(resource_info->image_info); 7166 SetGeometryInfo(&geometry_info); 7167 GetQuantizeInfo(&quantize_info); 7168 switch (command) 7169 { 7170 case OpenCommand: 7171 { 7172 /* 7173 Load image. 7174 */ 7175 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7176 break; 7177 } 7178 case NextCommand: 7179 { 7180 /* 7181 Display next image. 7182 */ 7183 for (i=0; i < resource_info->quantum; i++) 7184 XClientMessage(display,windows->image.id,windows->im_protocols, 7185 windows->im_next_image,CurrentTime); 7186 break; 7187 } 7188 case FormerCommand: 7189 { 7190 /* 7191 Display former image. 7192 */ 7193 for (i=0; i < resource_info->quantum; i++) 7194 XClientMessage(display,windows->image.id,windows->im_protocols, 7195 windows->im_former_image,CurrentTime); 7196 break; 7197 } 7198 case SelectCommand: 7199 { 7200 int 7201 status; 7202 7203 /* 7204 Select image. 7205 */ 7206 status=chdir(resource_info->home_directory); 7207 if (status == -1) 7208 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7209 "UnableToOpenFile","%s",resource_info->home_directory); 7210 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7211 break; 7212 } 7213 case SaveCommand: 7214 { 7215 /* 7216 Save image. 7217 */ 7218 status=XSaveImage(display,resource_info,windows,*image,exception); 7219 if (status == MagickFalse) 7220 { 7221 char 7222 message[MaxTextExtent]; 7223 7224 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7225 exception->reason != (char *) NULL ? exception->reason : "", 7226 exception->description != (char *) NULL ? exception->description : 7227 ""); 7228 XNoticeWidget(display,windows,"Unable to save file:",message); 7229 break; 7230 } 7231 break; 7232 } 7233 case PrintCommand: 7234 { 7235 /* 7236 Print image. 7237 */ 7238 status=XPrintImage(display,resource_info,windows,*image,exception); 7239 if (status == MagickFalse) 7240 { 7241 char 7242 message[MaxTextExtent]; 7243 7244 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7245 exception->reason != (char *) NULL ? exception->reason : "", 7246 exception->description != (char *) NULL ? exception->description : 7247 ""); 7248 XNoticeWidget(display,windows,"Unable to print file:",message); 7249 break; 7250 } 7251 break; 7252 } 7253 case DeleteCommand: 7254 { 7255 static char 7256 filename[MaxTextExtent] = "\0"; 7257 7258 /* 7259 Delete image file. 7260 */ 7261 XFileBrowserWidget(display,windows,"Delete",filename); 7262 if (*filename == '\0') 7263 break; 7264 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7265 if (status != MagickFalse) 7266 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7267 break; 7268 } 7269 case NewCommand: 7270 { 7271 int 7272 status; 7273 7274 static char 7275 color[MaxTextExtent] = "gray", 7276 geometry[MaxTextExtent] = "640x480"; 7277 7278 static const char 7279 *format = "gradient"; 7280 7281 /* 7282 Query user for canvas geometry. 7283 */ 7284 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7285 geometry); 7286 if (*geometry == '\0') 7287 break; 7288 if (status == 0) 7289 format="xc"; 7290 XColorBrowserWidget(display,windows,"Select",color); 7291 if (*color == '\0') 7292 break; 7293 /* 7294 Create canvas. 7295 */ 7296 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7297 "%s:%s",format,color); 7298 (void) CloneString(&image_info->size,geometry); 7299 nexus=ReadImage(image_info,exception); 7300 CatchException(exception); 7301 XClientMessage(display,windows->image.id,windows->im_protocols, 7302 windows->im_next_image,CurrentTime); 7303 break; 7304 } 7305 case VisualDirectoryCommand: 7306 { 7307 /* 7308 Visual Image directory. 7309 */ 7310 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7311 break; 7312 } 7313 case QuitCommand: 7314 { 7315 /* 7316 exit program. 7317 */ 7318 if (resource_info->confirm_exit == MagickFalse) 7319 XClientMessage(display,windows->image.id,windows->im_protocols, 7320 windows->im_exit,CurrentTime); 7321 else 7322 { 7323 int 7324 status; 7325 7326 /* 7327 Confirm program exit. 7328 */ 7329 status=XConfirmWidget(display,windows,"Do you really want to exit", 7330 resource_info->client_name); 7331 if (status > 0) 7332 XClientMessage(display,windows->image.id,windows->im_protocols, 7333 windows->im_exit,CurrentTime); 7334 } 7335 break; 7336 } 7337 case CutCommand: 7338 { 7339 /* 7340 Cut image. 7341 */ 7342 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7343 break; 7344 } 7345 case CopyCommand: 7346 { 7347 /* 7348 Copy image. 7349 */ 7350 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7351 exception); 7352 break; 7353 } 7354 case PasteCommand: 7355 { 7356 /* 7357 Paste image. 7358 */ 7359 status=XPasteImage(display,resource_info,windows,*image,exception); 7360 if (status == MagickFalse) 7361 { 7362 XNoticeWidget(display,windows,"Unable to paste X image", 7363 (*image)->filename); 7364 break; 7365 } 7366 break; 7367 } 7368 case HalfSizeCommand: 7369 { 7370 /* 7371 Half image size. 7372 */ 7373 windows->image.window_changes.width=windows->image.ximage->width/2; 7374 windows->image.window_changes.height=windows->image.ximage->height/2; 7375 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7376 break; 7377 } 7378 case OriginalSizeCommand: 7379 { 7380 /* 7381 Original image size. 7382 */ 7383 windows->image.window_changes.width=(int) (*image)->columns; 7384 windows->image.window_changes.height=(int) (*image)->rows; 7385 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7386 break; 7387 } 7388 case DoubleSizeCommand: 7389 { 7390 /* 7391 Double the image size. 7392 */ 7393 windows->image.window_changes.width=windows->image.ximage->width << 1; 7394 windows->image.window_changes.height=windows->image.ximage->height << 1; 7395 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7396 break; 7397 } 7398 case ResizeCommand: 7399 { 7400 int 7401 status; 7402 7403 size_t 7404 height, 7405 width; 7406 7407 ssize_t 7408 x, 7409 y; 7410 7411 /* 7412 Resize image. 7413 */ 7414 width=(size_t) windows->image.ximage->width; 7415 height=(size_t) windows->image.ximage->height; 7416 x=0; 7417 y=0; 7418 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7419 (double) width,(double) height); 7420 status=XDialogWidget(display,windows,"Resize", 7421 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7422 if (*geometry == '\0') 7423 break; 7424 if (status == 0) 7425 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7426 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7427 windows->image.window_changes.width=(int) width; 7428 windows->image.window_changes.height=(int) height; 7429 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7430 break; 7431 } 7432 case ApplyCommand: 7433 { 7434 char 7435 image_geometry[MaxTextExtent]; 7436 7437 if ((windows->image.crop_geometry == (char *) NULL) && 7438 ((int) (*image)->columns == windows->image.ximage->width) && 7439 ((int) (*image)->rows == windows->image.ximage->height)) 7440 break; 7441 /* 7442 Apply size transforms to image. 7443 */ 7444 XSetCursorState(display,windows,MagickTrue); 7445 XCheckRefreshWindows(display,windows); 7446 /* 7447 Crop and/or scale displayed image. 7448 */ 7449 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7450 windows->image.ximage->width,windows->image.ximage->height); 7451 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7452 exception); 7453 if (windows->image.crop_geometry != (char *) NULL) 7454 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7455 windows->image.crop_geometry); 7456 windows->image.x=0; 7457 windows->image.y=0; 7458 XConfigureImageColormap(display,resource_info,windows,*image); 7459 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7460 break; 7461 } 7462 case RefreshCommand: 7463 { 7464 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7465 break; 7466 } 7467 case RestoreCommand: 7468 { 7469 /* 7470 Restore Image window to its original size. 7471 */ 7472 if ((windows->image.width == (unsigned int) (*image)->columns) && 7473 (windows->image.height == (unsigned int) (*image)->rows) && 7474 (windows->image.crop_geometry == (char *) NULL)) 7475 { 7476 (void) XBell(display,0); 7477 break; 7478 } 7479 windows->image.window_changes.width=(int) (*image)->columns; 7480 windows->image.window_changes.height=(int) (*image)->rows; 7481 if (windows->image.crop_geometry != (char *) NULL) 7482 { 7483 windows->image.crop_geometry=(char *) 7484 RelinquishMagickMemory(windows->image.crop_geometry); 7485 windows->image.crop_geometry=(char *) NULL; 7486 windows->image.x=0; 7487 windows->image.y=0; 7488 } 7489 XConfigureImageColormap(display,resource_info,windows,*image); 7490 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7491 break; 7492 } 7493 case CropCommand: 7494 { 7495 /* 7496 Crop image. 7497 */ 7498 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7499 exception); 7500 break; 7501 } 7502 case ChopCommand: 7503 { 7504 /* 7505 Chop image. 7506 */ 7507 status=XChopImage(display,resource_info,windows,image,exception); 7508 if (status == MagickFalse) 7509 { 7510 XNoticeWidget(display,windows,"Unable to cut X image", 7511 (*image)->filename); 7512 break; 7513 } 7514 break; 7515 } 7516 case FlopCommand: 7517 { 7518 Image 7519 *flop_image; 7520 7521 /* 7522 Flop image scanlines. 7523 */ 7524 XSetCursorState(display,windows,MagickTrue); 7525 XCheckRefreshWindows(display,windows); 7526 flop_image=FlopImage(*image,exception); 7527 if (flop_image != (Image *) NULL) 7528 { 7529 *image=DestroyImage(*image); 7530 *image=flop_image; 7531 } 7532 CatchException(exception); 7533 XSetCursorState(display,windows,MagickFalse); 7534 if (windows->image.crop_geometry != (char *) NULL) 7535 { 7536 /* 7537 Flop crop geometry. 7538 */ 7539 width=(unsigned int) (*image)->columns; 7540 height=(unsigned int) (*image)->rows; 7541 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7542 &width,&height); 7543 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7544 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7545 } 7546 if (windows->image.orphan != MagickFalse) 7547 break; 7548 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7549 break; 7550 } 7551 case FlipCommand: 7552 { 7553 Image 7554 *flip_image; 7555 7556 /* 7557 Flip image scanlines. 7558 */ 7559 XSetCursorState(display,windows,MagickTrue); 7560 XCheckRefreshWindows(display,windows); 7561 flip_image=FlipImage(*image,exception); 7562 if (flip_image != (Image *) NULL) 7563 { 7564 *image=DestroyImage(*image); 7565 *image=flip_image; 7566 } 7567 CatchException(exception); 7568 XSetCursorState(display,windows,MagickFalse); 7569 if (windows->image.crop_geometry != (char *) NULL) 7570 { 7571 /* 7572 Flip crop geometry. 7573 */ 7574 width=(unsigned int) (*image)->columns; 7575 height=(unsigned int) (*image)->rows; 7576 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7577 &width,&height); 7578 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7579 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7580 } 7581 if (windows->image.orphan != MagickFalse) 7582 break; 7583 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7584 break; 7585 } 7586 case RotateRightCommand: 7587 { 7588 /* 7589 Rotate image 90 degrees clockwise. 7590 */ 7591 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7592 if (status == MagickFalse) 7593 { 7594 XNoticeWidget(display,windows,"Unable to rotate X image", 7595 (*image)->filename); 7596 break; 7597 } 7598 break; 7599 } 7600 case RotateLeftCommand: 7601 { 7602 /* 7603 Rotate image 90 degrees counter-clockwise. 7604 */ 7605 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7606 if (status == MagickFalse) 7607 { 7608 XNoticeWidget(display,windows,"Unable to rotate X image", 7609 (*image)->filename); 7610 break; 7611 } 7612 break; 7613 } 7614 case RotateCommand: 7615 { 7616 /* 7617 Rotate image. 7618 */ 7619 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7620 if (status == MagickFalse) 7621 { 7622 XNoticeWidget(display,windows,"Unable to rotate X image", 7623 (*image)->filename); 7624 break; 7625 } 7626 break; 7627 } 7628 case ShearCommand: 7629 { 7630 Image 7631 *shear_image; 7632 7633 static char 7634 geometry[MaxTextExtent] = "45.0x45.0"; 7635 7636 /* 7637 Query user for shear color and geometry. 7638 */ 7639 XColorBrowserWidget(display,windows,"Select",color); 7640 if (*color == '\0') 7641 break; 7642 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7643 geometry); 7644 if (*geometry == '\0') 7645 break; 7646 /* 7647 Shear image. 7648 */ 7649 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7650 exception); 7651 XSetCursorState(display,windows,MagickTrue); 7652 XCheckRefreshWindows(display,windows); 7653 (void) QueryColorCompliance(color,AllCompliance, 7654 &(*image)->background_color,exception); 7655 flags=ParseGeometry(geometry,&geometry_info); 7656 if ((flags & SigmaValue) == 0) 7657 geometry_info.sigma=geometry_info.rho; 7658 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7659 exception); 7660 if (shear_image != (Image *) NULL) 7661 { 7662 *image=DestroyImage(*image); 7663 *image=shear_image; 7664 } 7665 CatchException(exception); 7666 XSetCursorState(display,windows,MagickFalse); 7667 if (windows->image.orphan != MagickFalse) 7668 break; 7669 windows->image.window_changes.width=(int) (*image)->columns; 7670 windows->image.window_changes.height=(int) (*image)->rows; 7671 XConfigureImageColormap(display,resource_info,windows,*image); 7672 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7673 break; 7674 } 7675 case RollCommand: 7676 { 7677 Image 7678 *roll_image; 7679 7680 static char 7681 geometry[MaxTextExtent] = "+2+2"; 7682 7683 /* 7684 Query user for the roll geometry. 7685 */ 7686 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7687 geometry); 7688 if (*geometry == '\0') 7689 break; 7690 /* 7691 Roll image. 7692 */ 7693 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7694 exception); 7695 XSetCursorState(display,windows,MagickTrue); 7696 XCheckRefreshWindows(display,windows); 7697 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7698 exception); 7699 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7700 exception); 7701 if (roll_image != (Image *) NULL) 7702 { 7703 *image=DestroyImage(*image); 7704 *image=roll_image; 7705 } 7706 CatchException(exception); 7707 XSetCursorState(display,windows,MagickFalse); 7708 if (windows->image.orphan != MagickFalse) 7709 break; 7710 windows->image.window_changes.width=(int) (*image)->columns; 7711 windows->image.window_changes.height=(int) (*image)->rows; 7712 XConfigureImageColormap(display,resource_info,windows,*image); 7713 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7714 break; 7715 } 7716 case TrimCommand: 7717 { 7718 static char 7719 fuzz[MaxTextExtent]; 7720 7721 /* 7722 Query user for the fuzz factor. 7723 */ 7724 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7725 (*image)->fuzz/(QuantumRange+1.0)); 7726 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7727 if (*fuzz == '\0') 7728 break; 7729 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7730 /* 7731 Trim image. 7732 */ 7733 status=XTrimImage(display,resource_info,windows,*image,exception); 7734 if (status == MagickFalse) 7735 { 7736 XNoticeWidget(display,windows,"Unable to trim X image", 7737 (*image)->filename); 7738 break; 7739 } 7740 break; 7741 } 7742 case HueCommand: 7743 { 7744 static char 7745 hue_percent[MaxTextExtent] = "110"; 7746 7747 /* 7748 Query user for percent hue change. 7749 */ 7750 (void) XDialogWidget(display,windows,"Apply", 7751 "Enter percent change in image hue (0-200):",hue_percent); 7752 if (*hue_percent == '\0') 7753 break; 7754 /* 7755 Vary the image hue. 7756 */ 7757 XSetCursorState(display,windows,MagickTrue); 7758 XCheckRefreshWindows(display,windows); 7759 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7760 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7761 MaxTextExtent); 7762 (void) ModulateImage(*image,modulate_factors,exception); 7763 XSetCursorState(display,windows,MagickFalse); 7764 if (windows->image.orphan != MagickFalse) 7765 break; 7766 XConfigureImageColormap(display,resource_info,windows,*image); 7767 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7768 break; 7769 } 7770 case SaturationCommand: 7771 { 7772 static char 7773 saturation_percent[MaxTextExtent] = "110"; 7774 7775 /* 7776 Query user for percent saturation change. 7777 */ 7778 (void) XDialogWidget(display,windows,"Apply", 7779 "Enter percent change in color saturation (0-200):",saturation_percent); 7780 if (*saturation_percent == '\0') 7781 break; 7782 /* 7783 Vary color saturation. 7784 */ 7785 XSetCursorState(display,windows,MagickTrue); 7786 XCheckRefreshWindows(display,windows); 7787 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7788 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7789 MaxTextExtent); 7790 (void) ModulateImage(*image,modulate_factors,exception); 7791 XSetCursorState(display,windows,MagickFalse); 7792 if (windows->image.orphan != MagickFalse) 7793 break; 7794 XConfigureImageColormap(display,resource_info,windows,*image); 7795 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7796 break; 7797 } 7798 case BrightnessCommand: 7799 { 7800 static char 7801 brightness_percent[MaxTextExtent] = "110"; 7802 7803 /* 7804 Query user for percent brightness change. 7805 */ 7806 (void) XDialogWidget(display,windows,"Apply", 7807 "Enter percent change in color brightness (0-200):",brightness_percent); 7808 if (*brightness_percent == '\0') 7809 break; 7810 /* 7811 Vary the color brightness. 7812 */ 7813 XSetCursorState(display,windows,MagickTrue); 7814 XCheckRefreshWindows(display,windows); 7815 (void) CopyMagickString(modulate_factors,brightness_percent, 7816 MaxTextExtent); 7817 (void) ModulateImage(*image,modulate_factors,exception); 7818 XSetCursorState(display,windows,MagickFalse); 7819 if (windows->image.orphan != MagickFalse) 7820 break; 7821 XConfigureImageColormap(display,resource_info,windows,*image); 7822 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7823 break; 7824 } 7825 case GammaCommand: 7826 { 7827 static char 7828 factor[MaxTextExtent] = "1.6"; 7829 7830 /* 7831 Query user for gamma value. 7832 */ 7833 (void) XDialogWidget(display,windows,"Gamma", 7834 "Enter gamma value (e.g. 1.2):",factor); 7835 if (*factor == '\0') 7836 break; 7837 /* 7838 Gamma correct image. 7839 */ 7840 XSetCursorState(display,windows,MagickTrue); 7841 XCheckRefreshWindows(display,windows); 7842 (void) GammaImage(*image,atof(factor),exception); 7843 XSetCursorState(display,windows,MagickFalse); 7844 if (windows->image.orphan != MagickFalse) 7845 break; 7846 XConfigureImageColormap(display,resource_info,windows,*image); 7847 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7848 break; 7849 } 7850 case SpiffCommand: 7851 { 7852 /* 7853 Sharpen the image contrast. 7854 */ 7855 XSetCursorState(display,windows,MagickTrue); 7856 XCheckRefreshWindows(display,windows); 7857 (void) ContrastImage(*image,MagickTrue,exception); 7858 XSetCursorState(display,windows,MagickFalse); 7859 if (windows->image.orphan != MagickFalse) 7860 break; 7861 XConfigureImageColormap(display,resource_info,windows,*image); 7862 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7863 break; 7864 } 7865 case DullCommand: 7866 { 7867 /* 7868 Dull the image contrast. 7869 */ 7870 XSetCursorState(display,windows,MagickTrue); 7871 XCheckRefreshWindows(display,windows); 7872 (void) ContrastImage(*image,MagickFalse,exception); 7873 XSetCursorState(display,windows,MagickFalse); 7874 if (windows->image.orphan != MagickFalse) 7875 break; 7876 XConfigureImageColormap(display,resource_info,windows,*image); 7877 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7878 break; 7879 } 7880 case ContrastStretchCommand: 7881 { 7882 double 7883 black_point, 7884 white_point; 7885 7886 static char 7887 levels[MaxTextExtent] = "1%"; 7888 7889 /* 7890 Query user for gamma value. 7891 */ 7892 (void) XDialogWidget(display,windows,"Contrast Stretch", 7893 "Enter black and white points:",levels); 7894 if (*levels == '\0') 7895 break; 7896 /* 7897 Contrast stretch image. 7898 */ 7899 XSetCursorState(display,windows,MagickTrue); 7900 XCheckRefreshWindows(display,windows); 7901 flags=ParseGeometry(levels,&geometry_info); 7902 black_point=geometry_info.rho; 7903 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7904 if ((flags & PercentValue) != 0) 7905 { 7906 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7907 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7908 } 7909 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7910 (void) ContrastStretchImage(*image,black_point,white_point, 7911 exception); 7912 XSetCursorState(display,windows,MagickFalse); 7913 if (windows->image.orphan != MagickFalse) 7914 break; 7915 XConfigureImageColormap(display,resource_info,windows,*image); 7916 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7917 break; 7918 } 7919 case SigmoidalContrastCommand: 7920 { 7921 GeometryInfo 7922 geometry_info; 7923 7924 MagickStatusType 7925 flags; 7926 7927 static char 7928 levels[MaxTextExtent] = "3x50%"; 7929 7930 /* 7931 Query user for gamma value. 7932 */ 7933 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7934 "Enter contrast and midpoint:",levels); 7935 if (*levels == '\0') 7936 break; 7937 /* 7938 Contrast stretch image. 7939 */ 7940 XSetCursorState(display,windows,MagickTrue); 7941 XCheckRefreshWindows(display,windows); 7942 flags=ParseGeometry(levels,&geometry_info); 7943 if ((flags & SigmaValue) == 0) 7944 geometry_info.sigma=1.0*QuantumRange/2.0; 7945 if ((flags & PercentValue) != 0) 7946 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7947 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7948 geometry_info.sigma,exception); 7949 XSetCursorState(display,windows,MagickFalse); 7950 if (windows->image.orphan != MagickFalse) 7951 break; 7952 XConfigureImageColormap(display,resource_info,windows,*image); 7953 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7954 break; 7955 } 7956 case NormalizeCommand: 7957 { 7958 /* 7959 Perform histogram normalization on the image. 7960 */ 7961 XSetCursorState(display,windows,MagickTrue); 7962 XCheckRefreshWindows(display,windows); 7963 (void) NormalizeImage(*image,exception); 7964 XSetCursorState(display,windows,MagickFalse); 7965 if (windows->image.orphan != MagickFalse) 7966 break; 7967 XConfigureImageColormap(display,resource_info,windows,*image); 7968 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7969 break; 7970 } 7971 case EqualizeCommand: 7972 { 7973 /* 7974 Perform histogram equalization on the image. 7975 */ 7976 XSetCursorState(display,windows,MagickTrue); 7977 XCheckRefreshWindows(display,windows); 7978 (void) EqualizeImage(*image,exception); 7979 XSetCursorState(display,windows,MagickFalse); 7980 if (windows->image.orphan != MagickFalse) 7981 break; 7982 XConfigureImageColormap(display,resource_info,windows,*image); 7983 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7984 break; 7985 } 7986 case NegateCommand: 7987 { 7988 /* 7989 Negate colors in image. 7990 */ 7991 XSetCursorState(display,windows,MagickTrue); 7992 XCheckRefreshWindows(display,windows); 7993 (void) NegateImage(*image,MagickFalse,exception); 7994 XSetCursorState(display,windows,MagickFalse); 7995 if (windows->image.orphan != MagickFalse) 7996 break; 7997 XConfigureImageColormap(display,resource_info,windows,*image); 7998 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7999 break; 8000 } 8001 case GrayscaleCommand: 8002 { 8003 /* 8004 Convert image to grayscale. 8005 */ 8006 XSetCursorState(display,windows,MagickTrue); 8007 XCheckRefreshWindows(display,windows); 8008 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8009 GrayscaleType : GrayscaleMatteType,exception); 8010 XSetCursorState(display,windows,MagickFalse); 8011 if (windows->image.orphan != MagickFalse) 8012 break; 8013 XConfigureImageColormap(display,resource_info,windows,*image); 8014 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8015 break; 8016 } 8017 case MapCommand: 8018 { 8019 Image 8020 *affinity_image; 8021 8022 static char 8023 filename[MaxTextExtent] = "\0"; 8024 8025 /* 8026 Request image file name from user. 8027 */ 8028 XFileBrowserWidget(display,windows,"Map",filename); 8029 if (*filename == '\0') 8030 break; 8031 /* 8032 Map image. 8033 */ 8034 XSetCursorState(display,windows,MagickTrue); 8035 XCheckRefreshWindows(display,windows); 8036 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8037 affinity_image=ReadImage(image_info,exception); 8038 if (affinity_image != (Image *) NULL) 8039 { 8040 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8041 affinity_image=DestroyImage(affinity_image); 8042 } 8043 CatchException(exception); 8044 XSetCursorState(display,windows,MagickFalse); 8045 if (windows->image.orphan != MagickFalse) 8046 break; 8047 XConfigureImageColormap(display,resource_info,windows,*image); 8048 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8049 break; 8050 } 8051 case QuantizeCommand: 8052 { 8053 int 8054 status; 8055 8056 static char 8057 colors[MaxTextExtent] = "256"; 8058 8059 /* 8060 Query user for maximum number of colors. 8061 */ 8062 status=XDialogWidget(display,windows,"Quantize", 8063 "Maximum number of colors:",colors); 8064 if (*colors == '\0') 8065 break; 8066 /* 8067 Color reduce the image. 8068 */ 8069 XSetCursorState(display,windows,MagickTrue); 8070 XCheckRefreshWindows(display,windows); 8071 quantize_info.number_colors=StringToUnsignedLong(colors); 8072 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8073 (void) QuantizeImage(&quantize_info,*image,exception); 8074 XSetCursorState(display,windows,MagickFalse); 8075 if (windows->image.orphan != MagickFalse) 8076 break; 8077 XConfigureImageColormap(display,resource_info,windows,*image); 8078 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8079 break; 8080 } 8081 case DespeckleCommand: 8082 { 8083 Image 8084 *despeckle_image; 8085 8086 /* 8087 Despeckle image. 8088 */ 8089 XSetCursorState(display,windows,MagickTrue); 8090 XCheckRefreshWindows(display,windows); 8091 despeckle_image=DespeckleImage(*image,exception); 8092 if (despeckle_image != (Image *) NULL) 8093 { 8094 *image=DestroyImage(*image); 8095 *image=despeckle_image; 8096 } 8097 CatchException(exception); 8098 XSetCursorState(display,windows,MagickFalse); 8099 if (windows->image.orphan != MagickFalse) 8100 break; 8101 XConfigureImageColormap(display,resource_info,windows,*image); 8102 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8103 break; 8104 } 8105 case EmbossCommand: 8106 { 8107 Image 8108 *emboss_image; 8109 8110 static char 8111 radius[MaxTextExtent] = "0.0x1.0"; 8112 8113 /* 8114 Query user for emboss radius. 8115 */ 8116 (void) XDialogWidget(display,windows,"Emboss", 8117 "Enter the emboss radius and standard deviation:",radius); 8118 if (*radius == '\0') 8119 break; 8120 /* 8121 Reduce noise in the image. 8122 */ 8123 XSetCursorState(display,windows,MagickTrue); 8124 XCheckRefreshWindows(display,windows); 8125 flags=ParseGeometry(radius,&geometry_info); 8126 if ((flags & SigmaValue) == 0) 8127 geometry_info.sigma=1.0; 8128 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8129 exception); 8130 if (emboss_image != (Image *) NULL) 8131 { 8132 *image=DestroyImage(*image); 8133 *image=emboss_image; 8134 } 8135 CatchException(exception); 8136 XSetCursorState(display,windows,MagickFalse); 8137 if (windows->image.orphan != MagickFalse) 8138 break; 8139 XConfigureImageColormap(display,resource_info,windows,*image); 8140 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8141 break; 8142 } 8143 case ReduceNoiseCommand: 8144 { 8145 Image 8146 *noise_image; 8147 8148 static char 8149 radius[MaxTextExtent] = "0"; 8150 8151 /* 8152 Query user for noise radius. 8153 */ 8154 (void) XDialogWidget(display,windows,"Reduce Noise", 8155 "Enter the noise radius:",radius); 8156 if (*radius == '\0') 8157 break; 8158 /* 8159 Reduce noise in the image. 8160 */ 8161 XSetCursorState(display,windows,MagickTrue); 8162 XCheckRefreshWindows(display,windows); 8163 flags=ParseGeometry(radius,&geometry_info); 8164 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8165 geometry_info.rho,(size_t) geometry_info.rho,exception); 8166 if (noise_image != (Image *) NULL) 8167 { 8168 *image=DestroyImage(*image); 8169 *image=noise_image; 8170 } 8171 CatchException(exception); 8172 XSetCursorState(display,windows,MagickFalse); 8173 if (windows->image.orphan != MagickFalse) 8174 break; 8175 XConfigureImageColormap(display,resource_info,windows,*image); 8176 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8177 break; 8178 } 8179 case AddNoiseCommand: 8180 { 8181 char 8182 **noises; 8183 8184 Image 8185 *noise_image; 8186 8187 static char 8188 noise_type[MaxTextExtent] = "Gaussian"; 8189 8190 /* 8191 Add noise to the image. 8192 */ 8193 noises=GetCommandOptions(MagickNoiseOptions); 8194 if (noises == (char **) NULL) 8195 break; 8196 XListBrowserWidget(display,windows,&windows->widget, 8197 (const char **) noises,"Add Noise", 8198 "Select a type of noise to add to your image:",noise_type); 8199 noises=DestroyStringList(noises); 8200 if (*noise_type == '\0') 8201 break; 8202 XSetCursorState(display,windows,MagickTrue); 8203 XCheckRefreshWindows(display,windows); 8204 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8205 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8206 if (noise_image != (Image *) NULL) 8207 { 8208 *image=DestroyImage(*image); 8209 *image=noise_image; 8210 } 8211 CatchException(exception); 8212 XSetCursorState(display,windows,MagickFalse); 8213 if (windows->image.orphan != MagickFalse) 8214 break; 8215 XConfigureImageColormap(display,resource_info,windows,*image); 8216 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8217 break; 8218 } 8219 case SharpenCommand: 8220 { 8221 Image 8222 *sharp_image; 8223 8224 static char 8225 radius[MaxTextExtent] = "0.0x1.0"; 8226 8227 /* 8228 Query user for sharpen radius. 8229 */ 8230 (void) XDialogWidget(display,windows,"Sharpen", 8231 "Enter the sharpen radius and standard deviation:",radius); 8232 if (*radius == '\0') 8233 break; 8234 /* 8235 Sharpen image scanlines. 8236 */ 8237 XSetCursorState(display,windows,MagickTrue); 8238 XCheckRefreshWindows(display,windows); 8239 flags=ParseGeometry(radius,&geometry_info); 8240 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8241 geometry_info.xi,exception); 8242 if (sharp_image != (Image *) NULL) 8243 { 8244 *image=DestroyImage(*image); 8245 *image=sharp_image; 8246 } 8247 CatchException(exception); 8248 XSetCursorState(display,windows,MagickFalse); 8249 if (windows->image.orphan != MagickFalse) 8250 break; 8251 XConfigureImageColormap(display,resource_info,windows,*image); 8252 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8253 break; 8254 } 8255 case BlurCommand: 8256 { 8257 Image 8258 *blur_image; 8259 8260 static char 8261 radius[MaxTextExtent] = "0.0x1.0"; 8262 8263 /* 8264 Query user for blur radius. 8265 */ 8266 (void) XDialogWidget(display,windows,"Blur", 8267 "Enter the blur radius and standard deviation:",radius); 8268 if (*radius == '\0') 8269 break; 8270 /* 8271 Blur an image. 8272 */ 8273 XSetCursorState(display,windows,MagickTrue); 8274 XCheckRefreshWindows(display,windows); 8275 flags=ParseGeometry(radius,&geometry_info); 8276 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8277 geometry_info.xi,exception); 8278 if (blur_image != (Image *) NULL) 8279 { 8280 *image=DestroyImage(*image); 8281 *image=blur_image; 8282 } 8283 CatchException(exception); 8284 XSetCursorState(display,windows,MagickFalse); 8285 if (windows->image.orphan != MagickFalse) 8286 break; 8287 XConfigureImageColormap(display,resource_info,windows,*image); 8288 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8289 break; 8290 } 8291 case ThresholdCommand: 8292 { 8293 double 8294 threshold; 8295 8296 static char 8297 factor[MaxTextExtent] = "128"; 8298 8299 /* 8300 Query user for threshold value. 8301 */ 8302 (void) XDialogWidget(display,windows,"Threshold", 8303 "Enter threshold value:",factor); 8304 if (*factor == '\0') 8305 break; 8306 /* 8307 Gamma correct image. 8308 */ 8309 XSetCursorState(display,windows,MagickTrue); 8310 XCheckRefreshWindows(display,windows); 8311 threshold=SiPrefixToDouble(factor,QuantumRange); 8312 (void) BilevelImage(*image,threshold,exception); 8313 XSetCursorState(display,windows,MagickFalse); 8314 if (windows->image.orphan != MagickFalse) 8315 break; 8316 XConfigureImageColormap(display,resource_info,windows,*image); 8317 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8318 break; 8319 } 8320 case EdgeDetectCommand: 8321 { 8322 Image 8323 *edge_image; 8324 8325 static char 8326 radius[MaxTextExtent] = "0"; 8327 8328 /* 8329 Query user for edge factor. 8330 */ 8331 (void) XDialogWidget(display,windows,"Detect Edges", 8332 "Enter the edge detect radius:",radius); 8333 if (*radius == '\0') 8334 break; 8335 /* 8336 Detect edge in image. 8337 */ 8338 XSetCursorState(display,windows,MagickTrue); 8339 XCheckRefreshWindows(display,windows); 8340 flags=ParseGeometry(radius,&geometry_info); 8341 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8342 exception); 8343 if (edge_image != (Image *) NULL) 8344 { 8345 *image=DestroyImage(*image); 8346 *image=edge_image; 8347 } 8348 CatchException(exception); 8349 XSetCursorState(display,windows,MagickFalse); 8350 if (windows->image.orphan != MagickFalse) 8351 break; 8352 XConfigureImageColormap(display,resource_info,windows,*image); 8353 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8354 break; 8355 } 8356 case SpreadCommand: 8357 { 8358 Image 8359 *spread_image; 8360 8361 static char 8362 amount[MaxTextExtent] = "2"; 8363 8364 /* 8365 Query user for spread amount. 8366 */ 8367 (void) XDialogWidget(display,windows,"Spread", 8368 "Enter the displacement amount:",amount); 8369 if (*amount == '\0') 8370 break; 8371 /* 8372 Displace image pixels by a random amount. 8373 */ 8374 XSetCursorState(display,windows,MagickTrue); 8375 XCheckRefreshWindows(display,windows); 8376 flags=ParseGeometry(amount,&geometry_info); 8377 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8378 exception); 8379 if (spread_image != (Image *) NULL) 8380 { 8381 *image=DestroyImage(*image); 8382 *image=spread_image; 8383 } 8384 CatchException(exception); 8385 XSetCursorState(display,windows,MagickFalse); 8386 if (windows->image.orphan != MagickFalse) 8387 break; 8388 XConfigureImageColormap(display,resource_info,windows,*image); 8389 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8390 break; 8391 } 8392 case ShadeCommand: 8393 { 8394 Image 8395 *shade_image; 8396 8397 int 8398 status; 8399 8400 static char 8401 geometry[MaxTextExtent] = "30x30"; 8402 8403 /* 8404 Query user for the shade geometry. 8405 */ 8406 status=XDialogWidget(display,windows,"Shade", 8407 "Enter the azimuth and elevation of the light source:",geometry); 8408 if (*geometry == '\0') 8409 break; 8410 /* 8411 Shade image pixels. 8412 */ 8413 XSetCursorState(display,windows,MagickTrue); 8414 XCheckRefreshWindows(display,windows); 8415 flags=ParseGeometry(geometry,&geometry_info); 8416 if ((flags & SigmaValue) == 0) 8417 geometry_info.sigma=1.0; 8418 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8419 geometry_info.rho,geometry_info.sigma,exception); 8420 if (shade_image != (Image *) NULL) 8421 { 8422 *image=DestroyImage(*image); 8423 *image=shade_image; 8424 } 8425 CatchException(exception); 8426 XSetCursorState(display,windows,MagickFalse); 8427 if (windows->image.orphan != MagickFalse) 8428 break; 8429 XConfigureImageColormap(display,resource_info,windows,*image); 8430 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8431 break; 8432 } 8433 case RaiseCommand: 8434 { 8435 static char 8436 bevel_width[MaxTextExtent] = "10"; 8437 8438 /* 8439 Query user for bevel width. 8440 */ 8441 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8442 if (*bevel_width == '\0') 8443 break; 8444 /* 8445 Raise an image. 8446 */ 8447 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8448 exception); 8449 XSetCursorState(display,windows,MagickTrue); 8450 XCheckRefreshWindows(display,windows); 8451 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8452 exception); 8453 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8454 XSetCursorState(display,windows,MagickFalse); 8455 if (windows->image.orphan != MagickFalse) 8456 break; 8457 XConfigureImageColormap(display,resource_info,windows,*image); 8458 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8459 break; 8460 } 8461 case SegmentCommand: 8462 { 8463 static char 8464 threshold[MaxTextExtent] = "1.0x1.5"; 8465 8466 /* 8467 Query user for smoothing threshold. 8468 */ 8469 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8470 threshold); 8471 if (*threshold == '\0') 8472 break; 8473 /* 8474 Segment an image. 8475 */ 8476 XSetCursorState(display,windows,MagickTrue); 8477 XCheckRefreshWindows(display,windows); 8478 flags=ParseGeometry(threshold,&geometry_info); 8479 if ((flags & SigmaValue) == 0) 8480 geometry_info.sigma=1.0; 8481 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8482 geometry_info.sigma,exception); 8483 XSetCursorState(display,windows,MagickFalse); 8484 if (windows->image.orphan != MagickFalse) 8485 break; 8486 XConfigureImageColormap(display,resource_info,windows,*image); 8487 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8488 break; 8489 } 8490 case SepiaToneCommand: 8491 { 8492 double 8493 threshold; 8494 8495 Image 8496 *sepia_image; 8497 8498 static char 8499 factor[MaxTextExtent] = "80%"; 8500 8501 /* 8502 Query user for sepia-tone factor. 8503 */ 8504 (void) XDialogWidget(display,windows,"Sepia Tone", 8505 "Enter the sepia tone factor (0 - 99.9%):",factor); 8506 if (*factor == '\0') 8507 break; 8508 /* 8509 Sepia tone image pixels. 8510 */ 8511 XSetCursorState(display,windows,MagickTrue); 8512 XCheckRefreshWindows(display,windows); 8513 threshold=SiPrefixToDouble(factor,QuantumRange); 8514 sepia_image=SepiaToneImage(*image,threshold,exception); 8515 if (sepia_image != (Image *) NULL) 8516 { 8517 *image=DestroyImage(*image); 8518 *image=sepia_image; 8519 } 8520 CatchException(exception); 8521 XSetCursorState(display,windows,MagickFalse); 8522 if (windows->image.orphan != MagickFalse) 8523 break; 8524 XConfigureImageColormap(display,resource_info,windows,*image); 8525 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8526 break; 8527 } 8528 case SolarizeCommand: 8529 { 8530 double 8531 threshold; 8532 8533 static char 8534 factor[MaxTextExtent] = "60%"; 8535 8536 /* 8537 Query user for solarize factor. 8538 */ 8539 (void) XDialogWidget(display,windows,"Solarize", 8540 "Enter the solarize factor (0 - 99.9%):",factor); 8541 if (*factor == '\0') 8542 break; 8543 /* 8544 Solarize image pixels. 8545 */ 8546 XSetCursorState(display,windows,MagickTrue); 8547 XCheckRefreshWindows(display,windows); 8548 threshold=SiPrefixToDouble(factor,QuantumRange); 8549 (void) SolarizeImage(*image,threshold,exception); 8550 XSetCursorState(display,windows,MagickFalse); 8551 if (windows->image.orphan != MagickFalse) 8552 break; 8553 XConfigureImageColormap(display,resource_info,windows,*image); 8554 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8555 break; 8556 } 8557 case SwirlCommand: 8558 { 8559 Image 8560 *swirl_image; 8561 8562 static char 8563 degrees[MaxTextExtent] = "60"; 8564 8565 /* 8566 Query user for swirl angle. 8567 */ 8568 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8569 degrees); 8570 if (*degrees == '\0') 8571 break; 8572 /* 8573 Swirl image pixels about the center. 8574 */ 8575 XSetCursorState(display,windows,MagickTrue); 8576 XCheckRefreshWindows(display,windows); 8577 flags=ParseGeometry(degrees,&geometry_info); 8578 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8579 exception); 8580 if (swirl_image != (Image *) NULL) 8581 { 8582 *image=DestroyImage(*image); 8583 *image=swirl_image; 8584 } 8585 CatchException(exception); 8586 XSetCursorState(display,windows,MagickFalse); 8587 if (windows->image.orphan != MagickFalse) 8588 break; 8589 XConfigureImageColormap(display,resource_info,windows,*image); 8590 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8591 break; 8592 } 8593 case ImplodeCommand: 8594 { 8595 Image 8596 *implode_image; 8597 8598 static char 8599 factor[MaxTextExtent] = "0.3"; 8600 8601 /* 8602 Query user for implode factor. 8603 */ 8604 (void) XDialogWidget(display,windows,"Implode", 8605 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8606 if (*factor == '\0') 8607 break; 8608 /* 8609 Implode image pixels about the center. 8610 */ 8611 XSetCursorState(display,windows,MagickTrue); 8612 XCheckRefreshWindows(display,windows); 8613 flags=ParseGeometry(factor,&geometry_info); 8614 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8615 exception); 8616 if (implode_image != (Image *) NULL) 8617 { 8618 *image=DestroyImage(*image); 8619 *image=implode_image; 8620 } 8621 CatchException(exception); 8622 XSetCursorState(display,windows,MagickFalse); 8623 if (windows->image.orphan != MagickFalse) 8624 break; 8625 XConfigureImageColormap(display,resource_info,windows,*image); 8626 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8627 break; 8628 } 8629 case VignetteCommand: 8630 { 8631 Image 8632 *vignette_image; 8633 8634 static char 8635 geometry[MaxTextExtent] = "0x20"; 8636 8637 /* 8638 Query user for the vignette geometry. 8639 */ 8640 (void) XDialogWidget(display,windows,"Vignette", 8641 "Enter the radius, sigma, and x and y offsets:",geometry); 8642 if (*geometry == '\0') 8643 break; 8644 /* 8645 Soften the edges of the image in vignette style 8646 */ 8647 XSetCursorState(display,windows,MagickTrue); 8648 XCheckRefreshWindows(display,windows); 8649 flags=ParseGeometry(geometry,&geometry_info); 8650 if ((flags & SigmaValue) == 0) 8651 geometry_info.sigma=1.0; 8652 if ((flags & XiValue) == 0) 8653 geometry_info.xi=0.1*(*image)->columns; 8654 if ((flags & PsiValue) == 0) 8655 geometry_info.psi=0.1*(*image)->rows; 8656 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8657 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8658 0.5),exception); 8659 if (vignette_image != (Image *) NULL) 8660 { 8661 *image=DestroyImage(*image); 8662 *image=vignette_image; 8663 } 8664 CatchException(exception); 8665 XSetCursorState(display,windows,MagickFalse); 8666 if (windows->image.orphan != MagickFalse) 8667 break; 8668 XConfigureImageColormap(display,resource_info,windows,*image); 8669 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8670 break; 8671 } 8672 case WaveCommand: 8673 { 8674 Image 8675 *wave_image; 8676 8677 static char 8678 geometry[MaxTextExtent] = "25x150"; 8679 8680 /* 8681 Query user for the wave geometry. 8682 */ 8683 (void) XDialogWidget(display,windows,"Wave", 8684 "Enter the amplitude and length of the wave:",geometry); 8685 if (*geometry == '\0') 8686 break; 8687 /* 8688 Alter an image along a sine wave. 8689 */ 8690 XSetCursorState(display,windows,MagickTrue); 8691 XCheckRefreshWindows(display,windows); 8692 flags=ParseGeometry(geometry,&geometry_info); 8693 if ((flags & SigmaValue) == 0) 8694 geometry_info.sigma=1.0; 8695 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8696 (*image)->interpolate,exception); 8697 if (wave_image != (Image *) NULL) 8698 { 8699 *image=DestroyImage(*image); 8700 *image=wave_image; 8701 } 8702 CatchException(exception); 8703 XSetCursorState(display,windows,MagickFalse); 8704 if (windows->image.orphan != MagickFalse) 8705 break; 8706 XConfigureImageColormap(display,resource_info,windows,*image); 8707 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8708 break; 8709 } 8710 case OilPaintCommand: 8711 { 8712 Image 8713 *paint_image; 8714 8715 static char 8716 radius[MaxTextExtent] = "0"; 8717 8718 /* 8719 Query user for circular neighborhood radius. 8720 */ 8721 (void) XDialogWidget(display,windows,"Oil Paint", 8722 "Enter the mask radius:",radius); 8723 if (*radius == '\0') 8724 break; 8725 /* 8726 OilPaint image scanlines. 8727 */ 8728 XSetCursorState(display,windows,MagickTrue); 8729 XCheckRefreshWindows(display,windows); 8730 flags=ParseGeometry(radius,&geometry_info); 8731 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8732 exception); 8733 if (paint_image != (Image *) NULL) 8734 { 8735 *image=DestroyImage(*image); 8736 *image=paint_image; 8737 } 8738 CatchException(exception); 8739 XSetCursorState(display,windows,MagickFalse); 8740 if (windows->image.orphan != MagickFalse) 8741 break; 8742 XConfigureImageColormap(display,resource_info,windows,*image); 8743 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8744 break; 8745 } 8746 case CharcoalDrawCommand: 8747 { 8748 Image 8749 *charcoal_image; 8750 8751 static char 8752 radius[MaxTextExtent] = "0x1"; 8753 8754 /* 8755 Query user for charcoal radius. 8756 */ 8757 (void) XDialogWidget(display,windows,"Charcoal Draw", 8758 "Enter the charcoal radius and sigma:",radius); 8759 if (*radius == '\0') 8760 break; 8761 /* 8762 Charcoal the image. 8763 */ 8764 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8765 exception); 8766 XSetCursorState(display,windows,MagickTrue); 8767 XCheckRefreshWindows(display,windows); 8768 flags=ParseGeometry(radius,&geometry_info); 8769 if ((flags & SigmaValue) == 0) 8770 geometry_info.sigma=geometry_info.rho; 8771 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8772 geometry_info.xi,exception); 8773 if (charcoal_image != (Image *) NULL) 8774 { 8775 *image=DestroyImage(*image); 8776 *image=charcoal_image; 8777 } 8778 CatchException(exception); 8779 XSetCursorState(display,windows,MagickFalse); 8780 if (windows->image.orphan != MagickFalse) 8781 break; 8782 XConfigureImageColormap(display,resource_info,windows,*image); 8783 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8784 break; 8785 } 8786 case AnnotateCommand: 8787 { 8788 /* 8789 Annotate the image with text. 8790 */ 8791 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8792 if (status == MagickFalse) 8793 { 8794 XNoticeWidget(display,windows,"Unable to annotate X image", 8795 (*image)->filename); 8796 break; 8797 } 8798 break; 8799 } 8800 case DrawCommand: 8801 { 8802 /* 8803 Draw image. 8804 */ 8805 status=XDrawEditImage(display,resource_info,windows,image,exception); 8806 if (status == MagickFalse) 8807 { 8808 XNoticeWidget(display,windows,"Unable to draw on the X image", 8809 (*image)->filename); 8810 break; 8811 } 8812 break; 8813 } 8814 case ColorCommand: 8815 { 8816 /* 8817 Color edit. 8818 */ 8819 status=XColorEditImage(display,resource_info,windows,image,exception); 8820 if (status == MagickFalse) 8821 { 8822 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8823 (*image)->filename); 8824 break; 8825 } 8826 break; 8827 } 8828 case MatteCommand: 8829 { 8830 /* 8831 Matte edit. 8832 */ 8833 status=XMatteEditImage(display,resource_info,windows,image,exception); 8834 if (status == MagickFalse) 8835 { 8836 XNoticeWidget(display,windows,"Unable to matte edit X image", 8837 (*image)->filename); 8838 break; 8839 } 8840 break; 8841 } 8842 case CompositeCommand: 8843 { 8844 /* 8845 Composite image. 8846 */ 8847 status=XCompositeImage(display,resource_info,windows,*image, 8848 exception); 8849 if (status == MagickFalse) 8850 { 8851 XNoticeWidget(display,windows,"Unable to composite X image", 8852 (*image)->filename); 8853 break; 8854 } 8855 break; 8856 } 8857 case AddBorderCommand: 8858 { 8859 Image 8860 *border_image; 8861 8862 static char 8863 geometry[MaxTextExtent] = "6x6"; 8864 8865 /* 8866 Query user for border color and geometry. 8867 */ 8868 XColorBrowserWidget(display,windows,"Select",color); 8869 if (*color == '\0') 8870 break; 8871 (void) XDialogWidget(display,windows,"Add Border", 8872 "Enter border geometry:",geometry); 8873 if (*geometry == '\0') 8874 break; 8875 /* 8876 Add a border to the image. 8877 */ 8878 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8879 exception); 8880 XSetCursorState(display,windows,MagickTrue); 8881 XCheckRefreshWindows(display,windows); 8882 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8883 exception); 8884 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8885 exception); 8886 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8887 exception); 8888 if (border_image != (Image *) NULL) 8889 { 8890 *image=DestroyImage(*image); 8891 *image=border_image; 8892 } 8893 CatchException(exception); 8894 XSetCursorState(display,windows,MagickFalse); 8895 if (windows->image.orphan != MagickFalse) 8896 break; 8897 windows->image.window_changes.width=(int) (*image)->columns; 8898 windows->image.window_changes.height=(int) (*image)->rows; 8899 XConfigureImageColormap(display,resource_info,windows,*image); 8900 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8901 break; 8902 } 8903 case AddFrameCommand: 8904 { 8905 FrameInfo 8906 frame_info; 8907 8908 Image 8909 *frame_image; 8910 8911 static char 8912 geometry[MaxTextExtent] = "6x6"; 8913 8914 /* 8915 Query user for frame color and geometry. 8916 */ 8917 XColorBrowserWidget(display,windows,"Select",color); 8918 if (*color == '\0') 8919 break; 8920 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8921 geometry); 8922 if (*geometry == '\0') 8923 break; 8924 /* 8925 Surround image with an ornamental border. 8926 */ 8927 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8928 exception); 8929 XSetCursorState(display,windows,MagickTrue); 8930 XCheckRefreshWindows(display,windows); 8931 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8932 exception); 8933 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8934 exception); 8935 frame_info.width=page_geometry.width; 8936 frame_info.height=page_geometry.height; 8937 frame_info.outer_bevel=page_geometry.x; 8938 frame_info.inner_bevel=page_geometry.y; 8939 frame_info.x=(ssize_t) frame_info.width; 8940 frame_info.y=(ssize_t) frame_info.height; 8941 frame_info.width=(*image)->columns+2*frame_info.width; 8942 frame_info.height=(*image)->rows+2*frame_info.height; 8943 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8944 if (frame_image != (Image *) NULL) 8945 { 8946 *image=DestroyImage(*image); 8947 *image=frame_image; 8948 } 8949 CatchException(exception); 8950 XSetCursorState(display,windows,MagickFalse); 8951 if (windows->image.orphan != MagickFalse) 8952 break; 8953 windows->image.window_changes.width=(int) (*image)->columns; 8954 windows->image.window_changes.height=(int) (*image)->rows; 8955 XConfigureImageColormap(display,resource_info,windows,*image); 8956 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8957 break; 8958 } 8959 case CommentCommand: 8960 { 8961 const char 8962 *value; 8963 8964 FILE 8965 *file; 8966 8967 int 8968 unique_file; 8969 8970 /* 8971 Edit image comment. 8972 */ 8973 unique_file=AcquireUniqueFileResource(image_info->filename); 8974 if (unique_file == -1) 8975 XNoticeWidget(display,windows,"Unable to edit image comment", 8976 image_info->filename); 8977 value=GetImageProperty(*image,"comment",exception); 8978 if (value == (char *) NULL) 8979 unique_file=close(unique_file)-1; 8980 else 8981 { 8982 register const char 8983 *p; 8984 8985 file=fdopen(unique_file,"w"); 8986 if (file == (FILE *) NULL) 8987 { 8988 XNoticeWidget(display,windows,"Unable to edit image comment", 8989 image_info->filename); 8990 break; 8991 } 8992 for (p=value; *p != '\0'; p++) 8993 (void) fputc((int) *p,file); 8994 (void) fputc('\n',file); 8995 (void) fclose(file); 8996 } 8997 XSetCursorState(display,windows,MagickTrue); 8998 XCheckRefreshWindows(display,windows); 8999 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9000 exception); 9001 if (status == MagickFalse) 9002 XNoticeWidget(display,windows,"Unable to edit image comment", 9003 (char *) NULL); 9004 else 9005 { 9006 char 9007 *comment; 9008 9009 comment=FileToString(image_info->filename,~0UL,exception); 9010 if (comment != (char *) NULL) 9011 { 9012 (void) SetImageProperty(*image,"comment",comment,exception); 9013 (*image)->taint=MagickTrue; 9014 } 9015 } 9016 (void) RelinquishUniqueFileResource(image_info->filename); 9017 XSetCursorState(display,windows,MagickFalse); 9018 break; 9019 } 9020 case LaunchCommand: 9021 { 9022 /* 9023 Launch program. 9024 */ 9025 XSetCursorState(display,windows,MagickTrue); 9026 XCheckRefreshWindows(display,windows); 9027 (void) AcquireUniqueFilename(filename); 9028 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9029 filename); 9030 status=WriteImage(image_info,*image,exception); 9031 if (status == MagickFalse) 9032 XNoticeWidget(display,windows,"Unable to launch image editor", 9033 (char *) NULL); 9034 else 9035 { 9036 nexus=ReadImage(resource_info->image_info,exception); 9037 CatchException(exception); 9038 XClientMessage(display,windows->image.id,windows->im_protocols, 9039 windows->im_next_image,CurrentTime); 9040 } 9041 (void) RelinquishUniqueFileResource(filename); 9042 XSetCursorState(display,windows,MagickFalse); 9043 break; 9044 } 9045 case RegionofInterestCommand: 9046 { 9047 /* 9048 Apply an image processing technique to a region of interest. 9049 */ 9050 (void) XROIImage(display,resource_info,windows,image,exception); 9051 break; 9052 } 9053 case InfoCommand: 9054 break; 9055 case ZoomCommand: 9056 { 9057 /* 9058 Zoom image. 9059 */ 9060 if (windows->magnify.mapped != MagickFalse) 9061 (void) XRaiseWindow(display,windows->magnify.id); 9062 else 9063 { 9064 /* 9065 Make magnify image. 9066 */ 9067 XSetCursorState(display,windows,MagickTrue); 9068 (void) XMapRaised(display,windows->magnify.id); 9069 XSetCursorState(display,windows,MagickFalse); 9070 } 9071 break; 9072 } 9073 case ShowPreviewCommand: 9074 { 9075 char 9076 **previews; 9077 9078 Image 9079 *preview_image; 9080 9081 static char 9082 preview_type[MaxTextExtent] = "Gamma"; 9083 9084 /* 9085 Select preview type from menu. 9086 */ 9087 previews=GetCommandOptions(MagickPreviewOptions); 9088 if (previews == (char **) NULL) 9089 break; 9090 XListBrowserWidget(display,windows,&windows->widget, 9091 (const char **) previews,"Preview", 9092 "Select an enhancement, effect, or F/X:",preview_type); 9093 previews=DestroyStringList(previews); 9094 if (*preview_type == '\0') 9095 break; 9096 /* 9097 Show image preview. 9098 */ 9099 XSetCursorState(display,windows,MagickTrue); 9100 XCheckRefreshWindows(display,windows); 9101 image_info->preview_type=(PreviewType) 9102 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9103 image_info->group=(ssize_t) windows->image.id; 9104 (void) DeleteImageProperty(*image,"label"); 9105 (void) SetImageProperty(*image,"label","Preview",exception); 9106 (void) AcquireUniqueFilename(filename); 9107 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9108 filename); 9109 status=WriteImage(image_info,*image,exception); 9110 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9111 preview_image=ReadImage(image_info,exception); 9112 (void) RelinquishUniqueFileResource(filename); 9113 if (preview_image == (Image *) NULL) 9114 break; 9115 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9116 filename); 9117 status=WriteImage(image_info,preview_image,exception); 9118 preview_image=DestroyImage(preview_image); 9119 if (status == MagickFalse) 9120 XNoticeWidget(display,windows,"Unable to show image preview", 9121 (*image)->filename); 9122 XDelay(display,1500); 9123 XSetCursorState(display,windows,MagickFalse); 9124 break; 9125 } 9126 case ShowHistogramCommand: 9127 { 9128 Image 9129 *histogram_image; 9130 9131 /* 9132 Show image histogram. 9133 */ 9134 XSetCursorState(display,windows,MagickTrue); 9135 XCheckRefreshWindows(display,windows); 9136 image_info->group=(ssize_t) windows->image.id; 9137 (void) DeleteImageProperty(*image,"label"); 9138 (void) SetImageProperty(*image,"label","Histogram",exception); 9139 (void) AcquireUniqueFilename(filename); 9140 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9141 filename); 9142 status=WriteImage(image_info,*image,exception); 9143 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9144 histogram_image=ReadImage(image_info,exception); 9145 (void) RelinquishUniqueFileResource(filename); 9146 if (histogram_image == (Image *) NULL) 9147 break; 9148 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9149 "show:%s",filename); 9150 status=WriteImage(image_info,histogram_image,exception); 9151 histogram_image=DestroyImage(histogram_image); 9152 if (status == MagickFalse) 9153 XNoticeWidget(display,windows,"Unable to show histogram", 9154 (*image)->filename); 9155 XDelay(display,1500); 9156 XSetCursorState(display,windows,MagickFalse); 9157 break; 9158 } 9159 case ShowMatteCommand: 9160 { 9161 Image 9162 *matte_image; 9163 9164 if ((*image)->matte == MagickFalse) 9165 { 9166 XNoticeWidget(display,windows, 9167 "Image does not have any matte information",(*image)->filename); 9168 break; 9169 } 9170 /* 9171 Show image matte. 9172 */ 9173 XSetCursorState(display,windows,MagickTrue); 9174 XCheckRefreshWindows(display,windows); 9175 image_info->group=(ssize_t) windows->image.id; 9176 (void) DeleteImageProperty(*image,"label"); 9177 (void) SetImageProperty(*image,"label","Matte",exception); 9178 (void) AcquireUniqueFilename(filename); 9179 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9180 filename); 9181 status=WriteImage(image_info,*image,exception); 9182 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9183 matte_image=ReadImage(image_info,exception); 9184 (void) RelinquishUniqueFileResource(filename); 9185 if (matte_image == (Image *) NULL) 9186 break; 9187 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9188 filename); 9189 status=WriteImage(image_info,matte_image,exception); 9190 matte_image=DestroyImage(matte_image); 9191 if (status == MagickFalse) 9192 XNoticeWidget(display,windows,"Unable to show matte", 9193 (*image)->filename); 9194 XDelay(display,1500); 9195 XSetCursorState(display,windows,MagickFalse); 9196 break; 9197 } 9198 case BackgroundCommand: 9199 { 9200 /* 9201 Background image. 9202 */ 9203 status=XBackgroundImage(display,resource_info,windows,image,exception); 9204 if (status == MagickFalse) 9205 break; 9206 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9207 if (nexus != (Image *) NULL) 9208 XClientMessage(display,windows->image.id,windows->im_protocols, 9209 windows->im_next_image,CurrentTime); 9210 break; 9211 } 9212 case SlideShowCommand: 9213 { 9214 static char 9215 delay[MaxTextExtent] = "5"; 9216 9217 /* 9218 Display next image after pausing. 9219 */ 9220 (void) XDialogWidget(display,windows,"Slide Show", 9221 "Pause how many 1/100ths of a second between images:",delay); 9222 if (*delay == '\0') 9223 break; 9224 resource_info->delay=StringToUnsignedLong(delay); 9225 XClientMessage(display,windows->image.id,windows->im_protocols, 9226 windows->im_next_image,CurrentTime); 9227 break; 9228 } 9229 case PreferencesCommand: 9230 { 9231 /* 9232 Set user preferences. 9233 */ 9234 status=XPreferencesWidget(display,resource_info,windows); 9235 if (status == MagickFalse) 9236 break; 9237 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9238 if (nexus != (Image *) NULL) 9239 XClientMessage(display,windows->image.id,windows->im_protocols, 9240 windows->im_next_image,CurrentTime); 9241 break; 9242 } 9243 case HelpCommand: 9244 { 9245 /* 9246 User requested help. 9247 */ 9248 XTextViewWidget(display,resource_info,windows,MagickFalse, 9249 "Help Viewer - Display",DisplayHelp); 9250 break; 9251 } 9252 case BrowseDocumentationCommand: 9253 { 9254 Atom 9255 mozilla_atom; 9256 9257 Window 9258 mozilla_window, 9259 root_window; 9260 9261 /* 9262 Browse the ImageMagick documentation. 9263 */ 9264 root_window=XRootWindow(display,XDefaultScreen(display)); 9265 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9266 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9267 if (mozilla_window != (Window) NULL) 9268 { 9269 char 9270 command[MaxTextExtent], 9271 *url; 9272 9273 /* 9274 Display documentation using Netscape remote control. 9275 */ 9276 url=GetMagickHomeURL(); 9277 (void) FormatLocaleString(command,MaxTextExtent, 9278 "openurl(%s,new-tab)",url); 9279 url=DestroyString(url); 9280 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9281 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9282 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9283 XSetCursorState(display,windows,MagickFalse); 9284 break; 9285 } 9286 XSetCursorState(display,windows,MagickTrue); 9287 XCheckRefreshWindows(display,windows); 9288 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9289 exception); 9290 if (status == MagickFalse) 9291 XNoticeWidget(display,windows,"Unable to browse documentation", 9292 (char *) NULL); 9293 XDelay(display,1500); 9294 XSetCursorState(display,windows,MagickFalse); 9295 break; 9296 } 9297 case VersionCommand: 9298 { 9299 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9300 GetMagickCopyright()); 9301 break; 9302 } 9303 case SaveToUndoBufferCommand: 9304 break; 9305 default: 9306 { 9307 (void) XBell(display,0); 9308 break; 9309 } 9310 } 9311 image_info=DestroyImageInfo(image_info); 9312 return(nexus); 9313} 9314 9315/* 9316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9317% % 9318% % 9319% % 9320+ X M a g n i f y I m a g e % 9321% % 9322% % 9323% % 9324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9325% 9326% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9327% The magnified portion is displayed in a separate window. 9328% 9329% The format of the XMagnifyImage method is: 9330% 9331% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9332% 9333% A description of each parameter follows: 9334% 9335% o display: Specifies a connection to an X server; returned from 9336% XOpenDisplay. 9337% 9338% o windows: Specifies a pointer to a XWindows structure. 9339% 9340% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9341% the entire image is refreshed. 9342% 9343*/ 9344static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9345{ 9346 char 9347 text[MaxTextExtent]; 9348 9349 register int 9350 x, 9351 y; 9352 9353 size_t 9354 state; 9355 9356 /* 9357 Update magnified image until the mouse button is released. 9358 */ 9359 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9360 state=DefaultState; 9361 x=event->xbutton.x; 9362 y=event->xbutton.y; 9363 windows->magnify.x=(int) windows->image.x+x; 9364 windows->magnify.y=(int) windows->image.y+y; 9365 do 9366 { 9367 /* 9368 Map and unmap Info widget as text cursor crosses its boundaries. 9369 */ 9370 if (windows->info.mapped != MagickFalse) 9371 { 9372 if ((x < (int) (windows->info.x+windows->info.width)) && 9373 (y < (int) (windows->info.y+windows->info.height))) 9374 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9375 } 9376 else 9377 if ((x > (int) (windows->info.x+windows->info.width)) || 9378 (y > (int) (windows->info.y+windows->info.height))) 9379 (void) XMapWindow(display,windows->info.id); 9380 if (windows->info.mapped != MagickFalse) 9381 { 9382 /* 9383 Display pointer position. 9384 */ 9385 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9386 windows->magnify.x,windows->magnify.y); 9387 XInfoWidget(display,windows,text); 9388 } 9389 /* 9390 Wait for next event. 9391 */ 9392 XScreenEvent(display,windows,event); 9393 switch (event->type) 9394 { 9395 case ButtonPress: 9396 break; 9397 case ButtonRelease: 9398 { 9399 /* 9400 User has finished magnifying image. 9401 */ 9402 x=event->xbutton.x; 9403 y=event->xbutton.y; 9404 state|=ExitState; 9405 break; 9406 } 9407 case Expose: 9408 break; 9409 case MotionNotify: 9410 { 9411 x=event->xmotion.x; 9412 y=event->xmotion.y; 9413 break; 9414 } 9415 default: 9416 break; 9417 } 9418 /* 9419 Check boundary conditions. 9420 */ 9421 if (x < 0) 9422 x=0; 9423 else 9424 if (x >= (int) windows->image.width) 9425 x=(int) windows->image.width-1; 9426 if (y < 0) 9427 y=0; 9428 else 9429 if (y >= (int) windows->image.height) 9430 y=(int) windows->image.height-1; 9431 } while ((state & ExitState) == 0); 9432 /* 9433 Display magnified image. 9434 */ 9435 XSetCursorState(display,windows,MagickFalse); 9436} 9437 9438/* 9439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9440% % 9441% % 9442% % 9443+ X M a g n i f y W i n d o w C o m m a n d % 9444% % 9445% % 9446% % 9447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9448% 9449% XMagnifyWindowCommand() moves the image within an Magnify window by one 9450% pixel as specified by the key symbol. 9451% 9452% The format of the XMagnifyWindowCommand method is: 9453% 9454% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9455% const MagickStatusType state,const KeySym key_symbol) 9456% 9457% A description of each parameter follows: 9458% 9459% o display: Specifies a connection to an X server; returned from 9460% XOpenDisplay. 9461% 9462% o windows: Specifies a pointer to a XWindows structure. 9463% 9464% o state: key mask. 9465% 9466% o key_symbol: Specifies a KeySym which indicates which side of the image 9467% to trim. 9468% 9469*/ 9470static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9471 const MagickStatusType state,const KeySym key_symbol) 9472{ 9473 unsigned int 9474 quantum; 9475 9476 /* 9477 User specified a magnify factor or position. 9478 */ 9479 quantum=1; 9480 if ((state & Mod1Mask) != 0) 9481 quantum=10; 9482 switch ((int) key_symbol) 9483 { 9484 case QuitCommand: 9485 { 9486 (void) XWithdrawWindow(display,windows->magnify.id, 9487 windows->magnify.screen); 9488 break; 9489 } 9490 case XK_Home: 9491 case XK_KP_Home: 9492 { 9493 windows->magnify.x=(int) windows->image.width/2; 9494 windows->magnify.y=(int) windows->image.height/2; 9495 break; 9496 } 9497 case XK_Left: 9498 case XK_KP_Left: 9499 { 9500 if (windows->magnify.x > 0) 9501 windows->magnify.x-=quantum; 9502 break; 9503 } 9504 case XK_Up: 9505 case XK_KP_Up: 9506 { 9507 if (windows->magnify.y > 0) 9508 windows->magnify.y-=quantum; 9509 break; 9510 } 9511 case XK_Right: 9512 case XK_KP_Right: 9513 { 9514 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9515 windows->magnify.x+=quantum; 9516 break; 9517 } 9518 case XK_Down: 9519 case XK_KP_Down: 9520 { 9521 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9522 windows->magnify.y+=quantum; 9523 break; 9524 } 9525 case XK_0: 9526 case XK_1: 9527 case XK_2: 9528 case XK_3: 9529 case XK_4: 9530 case XK_5: 9531 case XK_6: 9532 case XK_7: 9533 case XK_8: 9534 case XK_9: 9535 { 9536 windows->magnify.data=(key_symbol-XK_0); 9537 break; 9538 } 9539 case XK_KP_0: 9540 case XK_KP_1: 9541 case XK_KP_2: 9542 case XK_KP_3: 9543 case XK_KP_4: 9544 case XK_KP_5: 9545 case XK_KP_6: 9546 case XK_KP_7: 9547 case XK_KP_8: 9548 case XK_KP_9: 9549 { 9550 windows->magnify.data=(key_symbol-XK_KP_0); 9551 break; 9552 } 9553 default: 9554 break; 9555 } 9556 XMakeMagnifyImage(display,windows); 9557} 9558 9559/* 9560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9561% % 9562% % 9563% % 9564+ X M a k e P a n I m a g e % 9565% % 9566% % 9567% % 9568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9569% 9570% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9571% icon window. 9572% 9573% The format of the XMakePanImage method is: 9574% 9575% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9576% XWindows *windows,Image *image,ExceptionInfo *exception) 9577% 9578% A description of each parameter follows: 9579% 9580% o display: Specifies a connection to an X server; returned from 9581% XOpenDisplay. 9582% 9583% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9584% 9585% o windows: Specifies a pointer to a XWindows structure. 9586% 9587% o image: the image. 9588% 9589% o exception: return any errors or warnings in this structure. 9590% 9591*/ 9592static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9593 XWindows *windows,Image *image,ExceptionInfo *exception) 9594{ 9595 MagickStatusType 9596 status; 9597 9598 /* 9599 Create and display image for panning icon. 9600 */ 9601 XSetCursorState(display,windows,MagickTrue); 9602 XCheckRefreshWindows(display,windows); 9603 windows->pan.x=(int) windows->image.x; 9604 windows->pan.y=(int) windows->image.y; 9605 status=XMakeImage(display,resource_info,&windows->pan,image, 9606 windows->pan.width,windows->pan.height,exception); 9607 if (status == MagickFalse) 9608 ThrowXWindowFatalException(ResourceLimitError, 9609 "MemoryAllocationFailed",image->filename); 9610 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9611 windows->pan.pixmap); 9612 (void) XClearWindow(display,windows->pan.id); 9613 XDrawPanRectangle(display,windows); 9614 XSetCursorState(display,windows,MagickFalse); 9615} 9616 9617/* 9618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9619% % 9620% % 9621% % 9622+ X M a t t a E d i t I m a g e % 9623% % 9624% % 9625% % 9626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9627% 9628% XMatteEditImage() allows the user to interactively change the Matte channel 9629% of an image. If the image is PseudoClass it is promoted to DirectClass 9630% before the matte information is stored. 9631% 9632% The format of the XMatteEditImage method is: 9633% 9634% MagickBooleanType XMatteEditImage(Display *display, 9635% XResourceInfo *resource_info,XWindows *windows,Image **image, 9636% ExceptionInfo *exception) 9637% 9638% A description of each parameter follows: 9639% 9640% o display: Specifies a connection to an X server; returned from 9641% XOpenDisplay. 9642% 9643% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9644% 9645% o windows: Specifies a pointer to a XWindows structure. 9646% 9647% o image: the image; returned from ReadImage. 9648% 9649% o exception: return any errors or warnings in this structure. 9650% 9651*/ 9652static MagickBooleanType XMatteEditImage(Display *display, 9653 XResourceInfo *resource_info,XWindows *windows,Image **image, 9654 ExceptionInfo *exception) 9655{ 9656 static char 9657 matte[MaxTextExtent] = "0"; 9658 9659 static const char 9660 *MatteEditMenu[] = 9661 { 9662 "Method", 9663 "Border Color", 9664 "Fuzz", 9665 "Matte Value", 9666 "Undo", 9667 "Help", 9668 "Dismiss", 9669 (char *) NULL 9670 }; 9671 9672 static const ModeType 9673 MatteEditCommands[] = 9674 { 9675 MatteEditMethod, 9676 MatteEditBorderCommand, 9677 MatteEditFuzzCommand, 9678 MatteEditValueCommand, 9679 MatteEditUndoCommand, 9680 MatteEditHelpCommand, 9681 MatteEditDismissCommand 9682 }; 9683 9684 static PaintMethod 9685 method = PointMethod; 9686 9687 static XColor 9688 border_color = { 0, 0, 0, 0, 0, 0 }; 9689 9690 char 9691 command[MaxTextExtent], 9692 text[MaxTextExtent]; 9693 9694 Cursor 9695 cursor; 9696 9697 int 9698 entry, 9699 id, 9700 x, 9701 x_offset, 9702 y, 9703 y_offset; 9704 9705 register int 9706 i; 9707 9708 register Quantum 9709 *q; 9710 9711 unsigned int 9712 height, 9713 width; 9714 9715 size_t 9716 state; 9717 9718 XEvent 9719 event; 9720 9721 /* 9722 Map Command widget. 9723 */ 9724 (void) CloneString(&windows->command.name,"Matte Edit"); 9725 windows->command.data=4; 9726 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9727 (void) XMapRaised(display,windows->command.id); 9728 XClientMessage(display,windows->image.id,windows->im_protocols, 9729 windows->im_update_widget,CurrentTime); 9730 /* 9731 Make cursor. 9732 */ 9733 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9734 resource_info->background_color,resource_info->foreground_color); 9735 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9736 /* 9737 Track pointer until button 1 is pressed. 9738 */ 9739 XQueryPosition(display,windows->image.id,&x,&y); 9740 (void) XSelectInput(display,windows->image.id, 9741 windows->image.attributes.event_mask | PointerMotionMask); 9742 state=DefaultState; 9743 do 9744 { 9745 if (windows->info.mapped != MagickFalse) 9746 { 9747 /* 9748 Display pointer position. 9749 */ 9750 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9751 x+windows->image.x,y+windows->image.y); 9752 XInfoWidget(display,windows,text); 9753 } 9754 /* 9755 Wait for next event. 9756 */ 9757 XScreenEvent(display,windows,&event); 9758 if (event.xany.window == windows->command.id) 9759 { 9760 /* 9761 Select a command from the Command widget. 9762 */ 9763 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9764 if (id < 0) 9765 { 9766 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9767 continue; 9768 } 9769 switch (MatteEditCommands[id]) 9770 { 9771 case MatteEditMethod: 9772 { 9773 char 9774 **methods; 9775 9776 /* 9777 Select a method from the pop-up menu. 9778 */ 9779 methods=GetCommandOptions(MagickMethodOptions); 9780 if (methods == (char **) NULL) 9781 break; 9782 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9783 (const char **) methods,command); 9784 if (entry >= 0) 9785 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9786 MagickFalse,methods[entry]); 9787 methods=DestroyStringList(methods); 9788 break; 9789 } 9790 case MatteEditBorderCommand: 9791 { 9792 const char 9793 *ColorMenu[MaxNumberPens]; 9794 9795 int 9796 pen_number; 9797 9798 /* 9799 Initialize menu selections. 9800 */ 9801 for (i=0; i < (int) (MaxNumberPens-2); i++) 9802 ColorMenu[i]=resource_info->pen_colors[i]; 9803 ColorMenu[MaxNumberPens-2]="Browser..."; 9804 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9805 /* 9806 Select a pen color from the pop-up menu. 9807 */ 9808 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9809 (const char **) ColorMenu,command); 9810 if (pen_number < 0) 9811 break; 9812 if (pen_number == (MaxNumberPens-2)) 9813 { 9814 static char 9815 color_name[MaxTextExtent] = "gray"; 9816 9817 /* 9818 Select a pen color from a dialog. 9819 */ 9820 resource_info->pen_colors[pen_number]=color_name; 9821 XColorBrowserWidget(display,windows,"Select",color_name); 9822 if (*color_name == '\0') 9823 break; 9824 } 9825 /* 9826 Set border color. 9827 */ 9828 (void) XParseColor(display,windows->map_info->colormap, 9829 resource_info->pen_colors[pen_number],&border_color); 9830 break; 9831 } 9832 case MatteEditFuzzCommand: 9833 { 9834 static char 9835 fuzz[MaxTextExtent]; 9836 9837 static const char 9838 *FuzzMenu[] = 9839 { 9840 "0%", 9841 "2%", 9842 "5%", 9843 "10%", 9844 "15%", 9845 "Dialog...", 9846 (char *) NULL, 9847 }; 9848 9849 /* 9850 Select a command from the pop-up menu. 9851 */ 9852 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9853 command); 9854 if (entry < 0) 9855 break; 9856 if (entry != 5) 9857 { 9858 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 9859 QuantumRange+1.0); 9860 break; 9861 } 9862 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9863 (void) XDialogWidget(display,windows,"Ok", 9864 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9865 if (*fuzz == '\0') 9866 break; 9867 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9868 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 9869 break; 9870 } 9871 case MatteEditValueCommand: 9872 { 9873 static char 9874 message[MaxTextExtent]; 9875 9876 static const char 9877 *MatteMenu[] = 9878 { 9879 "Opaque", 9880 "Transparent", 9881 "Dialog...", 9882 (char *) NULL, 9883 }; 9884 9885 /* 9886 Select a command from the pop-up menu. 9887 */ 9888 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9889 command); 9890 if (entry < 0) 9891 break; 9892 if (entry != 2) 9893 { 9894 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9895 OpaqueAlpha); 9896 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9897 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9898 (Quantum) TransparentAlpha); 9899 break; 9900 } 9901 (void) FormatLocaleString(message,MaxTextExtent, 9902 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9903 QuantumRange); 9904 (void) XDialogWidget(display,windows,"Matte",message,matte); 9905 if (*matte == '\0') 9906 break; 9907 break; 9908 } 9909 case MatteEditUndoCommand: 9910 { 9911 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9912 image,exception); 9913 break; 9914 } 9915 case MatteEditHelpCommand: 9916 { 9917 XTextViewWidget(display,resource_info,windows,MagickFalse, 9918 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9919 break; 9920 } 9921 case MatteEditDismissCommand: 9922 { 9923 /* 9924 Prematurely exit. 9925 */ 9926 state|=EscapeState; 9927 state|=ExitState; 9928 break; 9929 } 9930 default: 9931 break; 9932 } 9933 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9934 continue; 9935 } 9936 switch (event.type) 9937 { 9938 case ButtonPress: 9939 { 9940 if (event.xbutton.button != Button1) 9941 break; 9942 if ((event.xbutton.window != windows->image.id) && 9943 (event.xbutton.window != windows->magnify.id)) 9944 break; 9945 /* 9946 Update matte data. 9947 */ 9948 x=event.xbutton.x; 9949 y=event.xbutton.y; 9950 (void) XMagickCommand(display,resource_info,windows, 9951 SaveToUndoBufferCommand,image,exception); 9952 state|=UpdateConfigurationState; 9953 break; 9954 } 9955 case ButtonRelease: 9956 { 9957 if (event.xbutton.button != Button1) 9958 break; 9959 if ((event.xbutton.window != windows->image.id) && 9960 (event.xbutton.window != windows->magnify.id)) 9961 break; 9962 /* 9963 Update colormap information. 9964 */ 9965 x=event.xbutton.x; 9966 y=event.xbutton.y; 9967 XConfigureImageColormap(display,resource_info,windows,*image); 9968 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9969 XInfoWidget(display,windows,text); 9970 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9971 state&=(~UpdateConfigurationState); 9972 break; 9973 } 9974 case Expose: 9975 break; 9976 case KeyPress: 9977 { 9978 char 9979 command[MaxTextExtent]; 9980 9981 KeySym 9982 key_symbol; 9983 9984 if (event.xkey.window == windows->magnify.id) 9985 { 9986 Window 9987 window; 9988 9989 window=windows->magnify.id; 9990 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9991 } 9992 if (event.xkey.window != windows->image.id) 9993 break; 9994 /* 9995 Respond to a user key press. 9996 */ 9997 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9998 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9999 switch ((int) key_symbol) 10000 { 10001 case XK_Escape: 10002 case XK_F20: 10003 { 10004 /* 10005 Prematurely exit. 10006 */ 10007 state|=ExitState; 10008 break; 10009 } 10010 case XK_F1: 10011 case XK_Help: 10012 { 10013 XTextViewWidget(display,resource_info,windows,MagickFalse, 10014 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10015 break; 10016 } 10017 default: 10018 { 10019 (void) XBell(display,0); 10020 break; 10021 } 10022 } 10023 break; 10024 } 10025 case MotionNotify: 10026 { 10027 /* 10028 Map and unmap Info widget as cursor crosses its boundaries. 10029 */ 10030 x=event.xmotion.x; 10031 y=event.xmotion.y; 10032 if (windows->info.mapped != MagickFalse) 10033 { 10034 if ((x < (int) (windows->info.x+windows->info.width)) && 10035 (y < (int) (windows->info.y+windows->info.height))) 10036 (void) XWithdrawWindow(display,windows->info.id, 10037 windows->info.screen); 10038 } 10039 else 10040 if ((x > (int) (windows->info.x+windows->info.width)) || 10041 (y > (int) (windows->info.y+windows->info.height))) 10042 (void) XMapWindow(display,windows->info.id); 10043 break; 10044 } 10045 default: 10046 break; 10047 } 10048 if (event.xany.window == windows->magnify.id) 10049 { 10050 x=windows->magnify.x-windows->image.x; 10051 y=windows->magnify.y-windows->image.y; 10052 } 10053 x_offset=x; 10054 y_offset=y; 10055 if ((state & UpdateConfigurationState) != 0) 10056 { 10057 CacheView 10058 *image_view; 10059 10060 int 10061 x, 10062 y; 10063 10064 /* 10065 Matte edit is relative to image configuration. 10066 */ 10067 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10068 MagickTrue); 10069 XPutPixel(windows->image.ximage,x_offset,y_offset, 10070 windows->pixel_info->background_color.pixel); 10071 width=(unsigned int) (*image)->columns; 10072 height=(unsigned int) (*image)->rows; 10073 x=0; 10074 y=0; 10075 if (windows->image.crop_geometry != (char *) NULL) 10076 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10077 &height); 10078 x_offset=(int) (width*(windows->image.x+x_offset)/ 10079 windows->image.ximage->width+x); 10080 y_offset=(int) (height*(windows->image.y+y_offset)/ 10081 windows->image.ximage->height+y); 10082 if ((x_offset < 0) || (y_offset < 0)) 10083 continue; 10084 if ((x_offset >= (int) (*image)->columns) || 10085 (y_offset >= (int) (*image)->rows)) 10086 continue; 10087 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10088 return(MagickFalse); 10089 (*image)->matte=MagickTrue; 10090 image_view=AcquireCacheView(*image); 10091 switch (method) 10092 { 10093 case PointMethod: 10094 default: 10095 { 10096 /* 10097 Update matte information using point algorithm. 10098 */ 10099 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10100 (ssize_t) y_offset,1,1,exception); 10101 if (q == (Quantum *) NULL) 10102 break; 10103 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10104 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10105 break; 10106 } 10107 case ReplaceMethod: 10108 { 10109 PixelInfo 10110 pixel, 10111 target; 10112 10113 Quantum 10114 virtual_pixel[MaxPixelChannels]; 10115 10116 /* 10117 Update matte information using replace algorithm. 10118 */ 10119 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10120 (ssize_t) y_offset,virtual_pixel,exception); 10121 target.red=virtual_pixel[RedPixelChannel]; 10122 target.green=virtual_pixel[GreenPixelChannel]; 10123 target.blue=virtual_pixel[BluePixelChannel]; 10124 target.alpha=virtual_pixel[AlphaPixelChannel]; 10125 for (y=0; y < (int) (*image)->rows; y++) 10126 { 10127 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10128 (*image)->columns,1,exception); 10129 if (q == (Quantum *) NULL) 10130 break; 10131 for (x=0; x < (int) (*image)->columns; x++) 10132 { 10133 GetPixelInfoPixel(*image,q,&pixel); 10134 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10135 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10136 q+=GetPixelChannels(*image); 10137 } 10138 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10139 break; 10140 } 10141 break; 10142 } 10143 case FloodfillMethod: 10144 case FillToBorderMethod: 10145 { 10146 ChannelType 10147 channel_mask; 10148 10149 DrawInfo 10150 *draw_info; 10151 10152 PixelInfo 10153 target; 10154 10155 /* 10156 Update matte information using floodfill algorithm. 10157 */ 10158 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10159 (ssize_t) y_offset,&target,exception); 10160 if (method == FillToBorderMethod) 10161 { 10162 target.red=(MagickRealType) ScaleShortToQuantum( 10163 border_color.red); 10164 target.green=(MagickRealType) ScaleShortToQuantum( 10165 border_color.green); 10166 target.blue=(MagickRealType) ScaleShortToQuantum( 10167 border_color.blue); 10168 } 10169 draw_info=CloneDrawInfo(resource_info->image_info, 10170 (DrawInfo *) NULL); 10171 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10172 (char **) NULL)); 10173 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10174 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10175 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10176 MagickFalse : MagickTrue,exception); 10177 (void) SetPixelChannelMap(*image,channel_mask); 10178 draw_info=DestroyDrawInfo(draw_info); 10179 break; 10180 } 10181 case ResetMethod: 10182 { 10183 /* 10184 Update matte information using reset algorithm. 10185 */ 10186 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10187 return(MagickFalse); 10188 for (y=0; y < (int) (*image)->rows; y++) 10189 { 10190 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10191 (*image)->columns,1,exception); 10192 if (q == (Quantum *) NULL) 10193 break; 10194 for (x=0; x < (int) (*image)->columns; x++) 10195 { 10196 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10197 q+=GetPixelChannels(*image); 10198 } 10199 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10200 break; 10201 } 10202 if (StringToLong(matte) == (long) OpaqueAlpha) 10203 (*image)->matte=MagickFalse; 10204 break; 10205 } 10206 } 10207 image_view=DestroyCacheView(image_view); 10208 state&=(~UpdateConfigurationState); 10209 } 10210 } while ((state & ExitState) == 0); 10211 (void) XSelectInput(display,windows->image.id, 10212 windows->image.attributes.event_mask); 10213 XSetCursorState(display,windows,MagickFalse); 10214 (void) XFreeCursor(display,cursor); 10215 return(MagickTrue); 10216} 10217 10218/* 10219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10220% % 10221% % 10222% % 10223+ X O p e n I m a g e % 10224% % 10225% % 10226% % 10227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10228% 10229% XOpenImage() loads an image from a file. 10230% 10231% The format of the XOpenImage method is: 10232% 10233% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10234% XWindows *windows,const unsigned int command) 10235% 10236% A description of each parameter follows: 10237% 10238% o display: Specifies a connection to an X server; returned from 10239% XOpenDisplay. 10240% 10241% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10242% 10243% o windows: Specifies a pointer to a XWindows structure. 10244% 10245% o command: A value other than zero indicates that the file is selected 10246% from the command line argument list. 10247% 10248*/ 10249static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10250 XWindows *windows,const MagickBooleanType command) 10251{ 10252 const MagickInfo 10253 *magick_info; 10254 10255 ExceptionInfo 10256 *exception; 10257 10258 Image 10259 *nexus; 10260 10261 ImageInfo 10262 *image_info; 10263 10264 static char 10265 filename[MaxTextExtent] = "\0"; 10266 10267 /* 10268 Request file name from user. 10269 */ 10270 if (command == MagickFalse) 10271 XFileBrowserWidget(display,windows,"Open",filename); 10272 else 10273 { 10274 char 10275 **filelist, 10276 **files; 10277 10278 int 10279 count, 10280 status; 10281 10282 register int 10283 i, 10284 j; 10285 10286 /* 10287 Select next image from the command line. 10288 */ 10289 status=XGetCommand(display,windows->image.id,&files,&count); 10290 if (status == 0) 10291 { 10292 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10293 return((Image *) NULL); 10294 } 10295 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10296 if (filelist == (char **) NULL) 10297 { 10298 ThrowXWindowFatalException(ResourceLimitError, 10299 "MemoryAllocationFailed","..."); 10300 (void) XFreeStringList(files); 10301 return((Image *) NULL); 10302 } 10303 j=0; 10304 for (i=1; i < count; i++) 10305 if (*files[i] != '-') 10306 filelist[j++]=files[i]; 10307 filelist[j]=(char *) NULL; 10308 XListBrowserWidget(display,windows,&windows->widget, 10309 (const char **) filelist,"Load","Select Image to Load:",filename); 10310 filelist=(char **) RelinquishMagickMemory(filelist); 10311 (void) XFreeStringList(files); 10312 } 10313 if (*filename == '\0') 10314 return((Image *) NULL); 10315 image_info=CloneImageInfo(resource_info->image_info); 10316 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10317 (void *) NULL); 10318 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10319 exception=AcquireExceptionInfo(); 10320 (void) SetImageInfo(image_info,0,exception); 10321 if (LocaleCompare(image_info->magick,"X") == 0) 10322 { 10323 char 10324 seconds[MaxTextExtent]; 10325 10326 /* 10327 User may want to delay the X server screen grab. 10328 */ 10329 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10330 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10331 seconds); 10332 if (*seconds == '\0') 10333 return((Image *) NULL); 10334 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10335 } 10336 magick_info=GetMagickInfo(image_info->magick,exception); 10337 if ((magick_info != (const MagickInfo *) NULL) && 10338 (magick_info->raw != MagickFalse)) 10339 { 10340 char 10341 geometry[MaxTextExtent]; 10342 10343 /* 10344 Request image size from the user. 10345 */ 10346 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10347 if (image_info->size != (char *) NULL) 10348 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10349 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10350 geometry); 10351 (void) CloneString(&image_info->size,geometry); 10352 } 10353 /* 10354 Load the image. 10355 */ 10356 XSetCursorState(display,windows,MagickTrue); 10357 XCheckRefreshWindows(display,windows); 10358 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10359 nexus=ReadImage(image_info,exception); 10360 CatchException(exception); 10361 XSetCursorState(display,windows,MagickFalse); 10362 if (nexus != (Image *) NULL) 10363 XClientMessage(display,windows->image.id,windows->im_protocols, 10364 windows->im_next_image,CurrentTime); 10365 else 10366 { 10367 char 10368 *text, 10369 **textlist; 10370 10371 /* 10372 Unknown image format. 10373 */ 10374 text=FileToString(filename,~0,exception); 10375 if (text == (char *) NULL) 10376 return((Image *) NULL); 10377 textlist=StringToList(text); 10378 if (textlist != (char **) NULL) 10379 { 10380 char 10381 title[MaxTextExtent]; 10382 10383 register int 10384 i; 10385 10386 (void) FormatLocaleString(title,MaxTextExtent, 10387 "Unknown format: %s",filename); 10388 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10389 (const char **) textlist); 10390 for (i=0; textlist[i] != (char *) NULL; i++) 10391 textlist[i]=DestroyString(textlist[i]); 10392 textlist=(char **) RelinquishMagickMemory(textlist); 10393 } 10394 text=DestroyString(text); 10395 } 10396 exception=DestroyExceptionInfo(exception); 10397 image_info=DestroyImageInfo(image_info); 10398 return(nexus); 10399} 10400 10401/* 10402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10403% % 10404% % 10405% % 10406+ X P a n I m a g e % 10407% % 10408% % 10409% % 10410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10411% 10412% XPanImage() pans the image until the mouse button is released. 10413% 10414% The format of the XPanImage method is: 10415% 10416% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10417% 10418% A description of each parameter follows: 10419% 10420% o display: Specifies a connection to an X server; returned from 10421% XOpenDisplay. 10422% 10423% o windows: Specifies a pointer to a XWindows structure. 10424% 10425% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10426% the entire image is refreshed. 10427% 10428*/ 10429static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10430{ 10431 char 10432 text[MaxTextExtent]; 10433 10434 Cursor 10435 cursor; 10436 10437 MagickRealType 10438 x_factor, 10439 y_factor; 10440 10441 RectangleInfo 10442 pan_info; 10443 10444 size_t 10445 state; 10446 10447 /* 10448 Define cursor. 10449 */ 10450 if ((windows->image.ximage->width > (int) windows->image.width) && 10451 (windows->image.ximage->height > (int) windows->image.height)) 10452 cursor=XCreateFontCursor(display,XC_fleur); 10453 else 10454 if (windows->image.ximage->width > (int) windows->image.width) 10455 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10456 else 10457 if (windows->image.ximage->height > (int) windows->image.height) 10458 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10459 else 10460 cursor=XCreateFontCursor(display,XC_arrow); 10461 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10462 /* 10463 Pan image as pointer moves until the mouse button is released. 10464 */ 10465 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10466 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10467 pan_info.width=windows->pan.width*windows->image.width/ 10468 windows->image.ximage->width; 10469 pan_info.height=windows->pan.height*windows->image.height/ 10470 windows->image.ximage->height; 10471 pan_info.x=0; 10472 pan_info.y=0; 10473 state=UpdateConfigurationState; 10474 do 10475 { 10476 switch (event->type) 10477 { 10478 case ButtonPress: 10479 { 10480 /* 10481 User choose an initial pan location. 10482 */ 10483 pan_info.x=(ssize_t) event->xbutton.x; 10484 pan_info.y=(ssize_t) event->xbutton.y; 10485 state|=UpdateConfigurationState; 10486 break; 10487 } 10488 case ButtonRelease: 10489 { 10490 /* 10491 User has finished panning the image. 10492 */ 10493 pan_info.x=(ssize_t) event->xbutton.x; 10494 pan_info.y=(ssize_t) event->xbutton.y; 10495 state|=UpdateConfigurationState | ExitState; 10496 break; 10497 } 10498 case MotionNotify: 10499 { 10500 pan_info.x=(ssize_t) event->xmotion.x; 10501 pan_info.y=(ssize_t) event->xmotion.y; 10502 state|=UpdateConfigurationState; 10503 } 10504 default: 10505 break; 10506 } 10507 if ((state & UpdateConfigurationState) != 0) 10508 { 10509 /* 10510 Check boundary conditions. 10511 */ 10512 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10513 pan_info.x=0; 10514 else 10515 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10516 if (pan_info.x < 0) 10517 pan_info.x=0; 10518 else 10519 if ((int) (pan_info.x+windows->image.width) > 10520 windows->image.ximage->width) 10521 pan_info.x=(ssize_t) 10522 (windows->image.ximage->width-windows->image.width); 10523 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10524 pan_info.y=0; 10525 else 10526 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10527 if (pan_info.y < 0) 10528 pan_info.y=0; 10529 else 10530 if ((int) (pan_info.y+windows->image.height) > 10531 windows->image.ximage->height) 10532 pan_info.y=(ssize_t) 10533 (windows->image.ximage->height-windows->image.height); 10534 if ((windows->image.x != (int) pan_info.x) || 10535 (windows->image.y != (int) pan_info.y)) 10536 { 10537 /* 10538 Display image pan offset. 10539 */ 10540 windows->image.x=(int) pan_info.x; 10541 windows->image.y=(int) pan_info.y; 10542 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10543 windows->image.width,windows->image.height,windows->image.x, 10544 windows->image.y); 10545 XInfoWidget(display,windows,text); 10546 /* 10547 Refresh Image window. 10548 */ 10549 XDrawPanRectangle(display,windows); 10550 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10551 } 10552 state&=(~UpdateConfigurationState); 10553 } 10554 /* 10555 Wait for next event. 10556 */ 10557 if ((state & ExitState) == 0) 10558 XScreenEvent(display,windows,event); 10559 } while ((state & ExitState) == 0); 10560 /* 10561 Restore cursor. 10562 */ 10563 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10564 (void) XFreeCursor(display,cursor); 10565 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10566} 10567 10568/* 10569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10570% % 10571% % 10572% % 10573+ X P a s t e I m a g e % 10574% % 10575% % 10576% % 10577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10578% 10579% XPasteImage() pastes an image previously saved with XCropImage in the X 10580% window image at a location the user chooses with the pointer. 10581% 10582% The format of the XPasteImage method is: 10583% 10584% MagickBooleanType XPasteImage(Display *display, 10585% XResourceInfo *resource_info,XWindows *windows,Image *image, 10586% ExceptionInfo *exception) 10587% 10588% A description of each parameter follows: 10589% 10590% o display: Specifies a connection to an X server; returned from 10591% XOpenDisplay. 10592% 10593% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10594% 10595% o windows: Specifies a pointer to a XWindows structure. 10596% 10597% o image: the image; returned from ReadImage. 10598% 10599% o exception: return any errors or warnings in this structure. 10600% 10601*/ 10602static MagickBooleanType XPasteImage(Display *display, 10603 XResourceInfo *resource_info,XWindows *windows,Image *image, 10604 ExceptionInfo *exception) 10605{ 10606 static const char 10607 *PasteMenu[] = 10608 { 10609 "Operator", 10610 "Help", 10611 "Dismiss", 10612 (char *) NULL 10613 }; 10614 10615 static const ModeType 10616 PasteCommands[] = 10617 { 10618 PasteOperatorsCommand, 10619 PasteHelpCommand, 10620 PasteDismissCommand 10621 }; 10622 10623 static CompositeOperator 10624 compose = CopyCompositeOp; 10625 10626 char 10627 text[MaxTextExtent]; 10628 10629 Cursor 10630 cursor; 10631 10632 Image 10633 *paste_image; 10634 10635 int 10636 entry, 10637 id, 10638 x, 10639 y; 10640 10641 MagickRealType 10642 scale_factor; 10643 10644 RectangleInfo 10645 highlight_info, 10646 paste_info; 10647 10648 unsigned int 10649 height, 10650 width; 10651 10652 size_t 10653 state; 10654 10655 XEvent 10656 event; 10657 10658 /* 10659 Copy image. 10660 */ 10661 if (resource_info->copy_image == (Image *) NULL) 10662 return(MagickFalse); 10663 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10664 /* 10665 Map Command widget. 10666 */ 10667 (void) CloneString(&windows->command.name,"Paste"); 10668 windows->command.data=1; 10669 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10670 (void) XMapRaised(display,windows->command.id); 10671 XClientMessage(display,windows->image.id,windows->im_protocols, 10672 windows->im_update_widget,CurrentTime); 10673 /* 10674 Track pointer until button 1 is pressed. 10675 */ 10676 XSetCursorState(display,windows,MagickFalse); 10677 XQueryPosition(display,windows->image.id,&x,&y); 10678 (void) XSelectInput(display,windows->image.id, 10679 windows->image.attributes.event_mask | PointerMotionMask); 10680 paste_info.x=(ssize_t) windows->image.x+x; 10681 paste_info.y=(ssize_t) windows->image.y+y; 10682 paste_info.width=0; 10683 paste_info.height=0; 10684 cursor=XCreateFontCursor(display,XC_ul_angle); 10685 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10686 state=DefaultState; 10687 do 10688 { 10689 if (windows->info.mapped != MagickFalse) 10690 { 10691 /* 10692 Display pointer position. 10693 */ 10694 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10695 (long) paste_info.x,(long) paste_info.y); 10696 XInfoWidget(display,windows,text); 10697 } 10698 highlight_info=paste_info; 10699 highlight_info.x=paste_info.x-windows->image.x; 10700 highlight_info.y=paste_info.y-windows->image.y; 10701 XHighlightRectangle(display,windows->image.id, 10702 windows->image.highlight_context,&highlight_info); 10703 /* 10704 Wait for next event. 10705 */ 10706 XScreenEvent(display,windows,&event); 10707 XHighlightRectangle(display,windows->image.id, 10708 windows->image.highlight_context,&highlight_info); 10709 if (event.xany.window == windows->command.id) 10710 { 10711 /* 10712 Select a command from the Command widget. 10713 */ 10714 id=XCommandWidget(display,windows,PasteMenu,&event); 10715 if (id < 0) 10716 continue; 10717 switch (PasteCommands[id]) 10718 { 10719 case PasteOperatorsCommand: 10720 { 10721 char 10722 command[MaxTextExtent], 10723 **operators; 10724 10725 /* 10726 Select a command from the pop-up menu. 10727 */ 10728 operators=GetCommandOptions(MagickComposeOptions); 10729 if (operators == (char **) NULL) 10730 break; 10731 entry=XMenuWidget(display,windows,PasteMenu[id], 10732 (const char **) operators,command); 10733 if (entry >= 0) 10734 compose=(CompositeOperator) ParseCommandOption( 10735 MagickComposeOptions,MagickFalse,operators[entry]); 10736 operators=DestroyStringList(operators); 10737 break; 10738 } 10739 case PasteHelpCommand: 10740 { 10741 XTextViewWidget(display,resource_info,windows,MagickFalse, 10742 "Help Viewer - Image Composite",ImagePasteHelp); 10743 break; 10744 } 10745 case PasteDismissCommand: 10746 { 10747 /* 10748 Prematurely exit. 10749 */ 10750 state|=EscapeState; 10751 state|=ExitState; 10752 break; 10753 } 10754 default: 10755 break; 10756 } 10757 continue; 10758 } 10759 switch (event.type) 10760 { 10761 case ButtonPress: 10762 { 10763 if (image->debug != MagickFalse) 10764 (void) LogMagickEvent(X11Event,GetMagickModule(), 10765 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10766 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10767 if (event.xbutton.button != Button1) 10768 break; 10769 if (event.xbutton.window != windows->image.id) 10770 break; 10771 /* 10772 Paste rectangle is relative to image configuration. 10773 */ 10774 width=(unsigned int) image->columns; 10775 height=(unsigned int) image->rows; 10776 x=0; 10777 y=0; 10778 if (windows->image.crop_geometry != (char *) NULL) 10779 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10780 &width,&height); 10781 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10782 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10783 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10784 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10785 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10786 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10787 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10788 break; 10789 } 10790 case ButtonRelease: 10791 { 10792 if (image->debug != MagickFalse) 10793 (void) LogMagickEvent(X11Event,GetMagickModule(), 10794 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10795 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10796 if (event.xbutton.button != Button1) 10797 break; 10798 if (event.xbutton.window != windows->image.id) 10799 break; 10800 if ((paste_info.width != 0) && (paste_info.height != 0)) 10801 { 10802 /* 10803 User has selected the location of the paste image. 10804 */ 10805 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10806 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10807 state|=ExitState; 10808 } 10809 break; 10810 } 10811 case Expose: 10812 break; 10813 case KeyPress: 10814 { 10815 char 10816 command[MaxTextExtent]; 10817 10818 KeySym 10819 key_symbol; 10820 10821 int 10822 length; 10823 10824 if (event.xkey.window != windows->image.id) 10825 break; 10826 /* 10827 Respond to a user key press. 10828 */ 10829 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10830 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10831 *(command+length)='\0'; 10832 if (image->debug != MagickFalse) 10833 (void) LogMagickEvent(X11Event,GetMagickModule(), 10834 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10835 switch ((int) key_symbol) 10836 { 10837 case XK_Escape: 10838 case XK_F20: 10839 { 10840 /* 10841 Prematurely exit. 10842 */ 10843 paste_image=DestroyImage(paste_image); 10844 state|=EscapeState; 10845 state|=ExitState; 10846 break; 10847 } 10848 case XK_F1: 10849 case XK_Help: 10850 { 10851 (void) XSetFunction(display,windows->image.highlight_context, 10852 GXcopy); 10853 XTextViewWidget(display,resource_info,windows,MagickFalse, 10854 "Help Viewer - Image Composite",ImagePasteHelp); 10855 (void) XSetFunction(display,windows->image.highlight_context, 10856 GXinvert); 10857 break; 10858 } 10859 default: 10860 { 10861 (void) XBell(display,0); 10862 break; 10863 } 10864 } 10865 break; 10866 } 10867 case MotionNotify: 10868 { 10869 /* 10870 Map and unmap Info widget as text cursor crosses its boundaries. 10871 */ 10872 x=event.xmotion.x; 10873 y=event.xmotion.y; 10874 if (windows->info.mapped != MagickFalse) 10875 { 10876 if ((x < (int) (windows->info.x+windows->info.width)) && 10877 (y < (int) (windows->info.y+windows->info.height))) 10878 (void) XWithdrawWindow(display,windows->info.id, 10879 windows->info.screen); 10880 } 10881 else 10882 if ((x > (int) (windows->info.x+windows->info.width)) || 10883 (y > (int) (windows->info.y+windows->info.height))) 10884 (void) XMapWindow(display,windows->info.id); 10885 paste_info.x=(ssize_t) windows->image.x+x; 10886 paste_info.y=(ssize_t) windows->image.y+y; 10887 break; 10888 } 10889 default: 10890 { 10891 if (image->debug != MagickFalse) 10892 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10893 event.type); 10894 break; 10895 } 10896 } 10897 } while ((state & ExitState) == 0); 10898 (void) XSelectInput(display,windows->image.id, 10899 windows->image.attributes.event_mask); 10900 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10901 XSetCursorState(display,windows,MagickFalse); 10902 (void) XFreeCursor(display,cursor); 10903 if ((state & EscapeState) != 0) 10904 return(MagickTrue); 10905 /* 10906 Image pasting is relative to image configuration. 10907 */ 10908 XSetCursorState(display,windows,MagickTrue); 10909 XCheckRefreshWindows(display,windows); 10910 width=(unsigned int) image->columns; 10911 height=(unsigned int) image->rows; 10912 x=0; 10913 y=0; 10914 if (windows->image.crop_geometry != (char *) NULL) 10915 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10916 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10917 paste_info.x+=x; 10918 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10919 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10920 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10921 paste_info.y+=y; 10922 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10923 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10924 /* 10925 Paste image with X Image window. 10926 */ 10927 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10928 exception); 10929 paste_image=DestroyImage(paste_image); 10930 XSetCursorState(display,windows,MagickFalse); 10931 /* 10932 Update image colormap. 10933 */ 10934 XConfigureImageColormap(display,resource_info,windows,image); 10935 (void) XConfigureImage(display,resource_info,windows,image,exception); 10936 return(MagickTrue); 10937} 10938 10939/* 10940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10941% % 10942% % 10943% % 10944+ X P r i n t I m a g e % 10945% % 10946% % 10947% % 10948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10949% 10950% XPrintImage() prints an image to a Postscript printer. 10951% 10952% The format of the XPrintImage method is: 10953% 10954% MagickBooleanType XPrintImage(Display *display, 10955% XResourceInfo *resource_info,XWindows *windows,Image *image, 10956% ExceptionInfo *exception) 10957% 10958% A description of each parameter follows: 10959% 10960% o display: Specifies a connection to an X server; returned from 10961% XOpenDisplay. 10962% 10963% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10964% 10965% o windows: Specifies a pointer to a XWindows structure. 10966% 10967% o image: the image. 10968% 10969% o exception: return any errors or warnings in this structure. 10970% 10971*/ 10972static MagickBooleanType XPrintImage(Display *display, 10973 XResourceInfo *resource_info,XWindows *windows,Image *image, 10974 ExceptionInfo *exception) 10975{ 10976 char 10977 filename[MaxTextExtent], 10978 geometry[MaxTextExtent]; 10979 10980 Image 10981 *print_image; 10982 10983 ImageInfo 10984 *image_info; 10985 10986 MagickStatusType 10987 status; 10988 10989 /* 10990 Request Postscript page geometry from user. 10991 */ 10992 image_info=CloneImageInfo(resource_info->image_info); 10993 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10994 if (image_info->page != (char *) NULL) 10995 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10996 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10997 "Select Postscript Page Geometry:",geometry); 10998 if (*geometry == '\0') 10999 return(MagickTrue); 11000 image_info->page=GetPageGeometry(geometry); 11001 /* 11002 Apply image transforms. 11003 */ 11004 XSetCursorState(display,windows,MagickTrue); 11005 XCheckRefreshWindows(display,windows); 11006 print_image=CloneImage(image,0,0,MagickTrue,exception); 11007 if (print_image == (Image *) NULL) 11008 return(MagickFalse); 11009 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11010 windows->image.ximage->width,windows->image.ximage->height); 11011 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11012 exception); 11013 /* 11014 Print image. 11015 */ 11016 (void) AcquireUniqueFilename(filename); 11017 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11018 filename); 11019 status=WriteImage(image_info,print_image,exception); 11020 (void) RelinquishUniqueFileResource(filename); 11021 print_image=DestroyImage(print_image); 11022 image_info=DestroyImageInfo(image_info); 11023 XSetCursorState(display,windows,MagickFalse); 11024 return(status != 0 ? MagickTrue : MagickFalse); 11025} 11026 11027/* 11028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11029% % 11030% % 11031% % 11032+ X R O I I m a g e % 11033% % 11034% % 11035% % 11036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11037% 11038% XROIImage() applies an image processing technique to a region of interest. 11039% 11040% The format of the XROIImage method is: 11041% 11042% MagickBooleanType XROIImage(Display *display, 11043% XResourceInfo *resource_info,XWindows *windows,Image **image, 11044% ExceptionInfo *exception) 11045% 11046% A description of each parameter follows: 11047% 11048% o display: Specifies a connection to an X server; returned from 11049% XOpenDisplay. 11050% 11051% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11052% 11053% o windows: Specifies a pointer to a XWindows structure. 11054% 11055% o image: the image; returned from ReadImage. 11056% 11057% o exception: return any errors or warnings in this structure. 11058% 11059*/ 11060static MagickBooleanType XROIImage(Display *display, 11061 XResourceInfo *resource_info,XWindows *windows,Image **image, 11062 ExceptionInfo *exception) 11063{ 11064#define ApplyMenus 7 11065 11066 static const char 11067 *ROIMenu[] = 11068 { 11069 "Help", 11070 "Dismiss", 11071 (char *) NULL 11072 }, 11073 *ApplyMenu[] = 11074 { 11075 "File", 11076 "Edit", 11077 "Transform", 11078 "Enhance", 11079 "Effects", 11080 "F/X", 11081 "Miscellany", 11082 "Help", 11083 "Dismiss", 11084 (char *) NULL 11085 }, 11086 *FileMenu[] = 11087 { 11088 "Save...", 11089 "Print...", 11090 (char *) NULL 11091 }, 11092 *EditMenu[] = 11093 { 11094 "Undo", 11095 "Redo", 11096 (char *) NULL 11097 }, 11098 *TransformMenu[] = 11099 { 11100 "Flop", 11101 "Flip", 11102 "Rotate Right", 11103 "Rotate Left", 11104 (char *) NULL 11105 }, 11106 *EnhanceMenu[] = 11107 { 11108 "Hue...", 11109 "Saturation...", 11110 "Brightness...", 11111 "Gamma...", 11112 "Spiff", 11113 "Dull", 11114 "Contrast Stretch...", 11115 "Sigmoidal Contrast...", 11116 "Normalize", 11117 "Equalize", 11118 "Negate", 11119 "Grayscale", 11120 "Map...", 11121 "Quantize...", 11122 (char *) NULL 11123 }, 11124 *EffectsMenu[] = 11125 { 11126 "Despeckle", 11127 "Emboss", 11128 "Reduce Noise", 11129 "Add Noise", 11130 "Sharpen...", 11131 "Blur...", 11132 "Threshold...", 11133 "Edge Detect...", 11134 "Spread...", 11135 "Shade...", 11136 "Raise...", 11137 "Segment...", 11138 (char *) NULL 11139 }, 11140 *FXMenu[] = 11141 { 11142 "Solarize...", 11143 "Sepia Tone...", 11144 "Swirl...", 11145 "Implode...", 11146 "Vignette...", 11147 "Wave...", 11148 "Oil Paint...", 11149 "Charcoal Draw...", 11150 (char *) NULL 11151 }, 11152 *MiscellanyMenu[] = 11153 { 11154 "Image Info", 11155 "Zoom Image", 11156 "Show Preview...", 11157 "Show Histogram", 11158 "Show Matte", 11159 (char *) NULL 11160 }; 11161 11162 static const char 11163 **Menus[ApplyMenus] = 11164 { 11165 FileMenu, 11166 EditMenu, 11167 TransformMenu, 11168 EnhanceMenu, 11169 EffectsMenu, 11170 FXMenu, 11171 MiscellanyMenu 11172 }; 11173 11174 static const CommandType 11175 ApplyCommands[] = 11176 { 11177 NullCommand, 11178 NullCommand, 11179 NullCommand, 11180 NullCommand, 11181 NullCommand, 11182 NullCommand, 11183 NullCommand, 11184 HelpCommand, 11185 QuitCommand 11186 }, 11187 FileCommands[] = 11188 { 11189 SaveCommand, 11190 PrintCommand 11191 }, 11192 EditCommands[] = 11193 { 11194 UndoCommand, 11195 RedoCommand 11196 }, 11197 TransformCommands[] = 11198 { 11199 FlopCommand, 11200 FlipCommand, 11201 RotateRightCommand, 11202 RotateLeftCommand 11203 }, 11204 EnhanceCommands[] = 11205 { 11206 HueCommand, 11207 SaturationCommand, 11208 BrightnessCommand, 11209 GammaCommand, 11210 SpiffCommand, 11211 DullCommand, 11212 ContrastStretchCommand, 11213 SigmoidalContrastCommand, 11214 NormalizeCommand, 11215 EqualizeCommand, 11216 NegateCommand, 11217 GrayscaleCommand, 11218 MapCommand, 11219 QuantizeCommand 11220 }, 11221 EffectsCommands[] = 11222 { 11223 DespeckleCommand, 11224 EmbossCommand, 11225 ReduceNoiseCommand, 11226 AddNoiseCommand, 11227 SharpenCommand, 11228 BlurCommand, 11229 EdgeDetectCommand, 11230 SpreadCommand, 11231 ShadeCommand, 11232 RaiseCommand, 11233 SegmentCommand 11234 }, 11235 FXCommands[] = 11236 { 11237 SolarizeCommand, 11238 SepiaToneCommand, 11239 SwirlCommand, 11240 ImplodeCommand, 11241 VignetteCommand, 11242 WaveCommand, 11243 OilPaintCommand, 11244 CharcoalDrawCommand 11245 }, 11246 MiscellanyCommands[] = 11247 { 11248 InfoCommand, 11249 ZoomCommand, 11250 ShowPreviewCommand, 11251 ShowHistogramCommand, 11252 ShowMatteCommand 11253 }, 11254 ROICommands[] = 11255 { 11256 ROIHelpCommand, 11257 ROIDismissCommand 11258 }; 11259 11260 static const CommandType 11261 *Commands[ApplyMenus] = 11262 { 11263 FileCommands, 11264 EditCommands, 11265 TransformCommands, 11266 EnhanceCommands, 11267 EffectsCommands, 11268 FXCommands, 11269 MiscellanyCommands 11270 }; 11271 11272 char 11273 command[MaxTextExtent], 11274 text[MaxTextExtent]; 11275 11276 CommandType 11277 command_type; 11278 11279 Cursor 11280 cursor; 11281 11282 Image 11283 *roi_image; 11284 11285 int 11286 entry, 11287 id, 11288 x, 11289 y; 11290 11291 MagickRealType 11292 scale_factor; 11293 11294 MagickProgressMonitor 11295 progress_monitor; 11296 11297 RectangleInfo 11298 crop_info, 11299 highlight_info, 11300 roi_info; 11301 11302 unsigned int 11303 height, 11304 width; 11305 11306 size_t 11307 state; 11308 11309 XEvent 11310 event; 11311 11312 /* 11313 Map Command widget. 11314 */ 11315 (void) CloneString(&windows->command.name,"ROI"); 11316 windows->command.data=0; 11317 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11318 (void) XMapRaised(display,windows->command.id); 11319 XClientMessage(display,windows->image.id,windows->im_protocols, 11320 windows->im_update_widget,CurrentTime); 11321 /* 11322 Track pointer until button 1 is pressed. 11323 */ 11324 XQueryPosition(display,windows->image.id,&x,&y); 11325 (void) XSelectInput(display,windows->image.id, 11326 windows->image.attributes.event_mask | PointerMotionMask); 11327 roi_info.x=(ssize_t) windows->image.x+x; 11328 roi_info.y=(ssize_t) windows->image.y+y; 11329 roi_info.width=0; 11330 roi_info.height=0; 11331 cursor=XCreateFontCursor(display,XC_fleur); 11332 state=DefaultState; 11333 do 11334 { 11335 if (windows->info.mapped != MagickFalse) 11336 { 11337 /* 11338 Display pointer position. 11339 */ 11340 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11341 (long) roi_info.x,(long) roi_info.y); 11342 XInfoWidget(display,windows,text); 11343 } 11344 /* 11345 Wait for next event. 11346 */ 11347 XScreenEvent(display,windows,&event); 11348 if (event.xany.window == windows->command.id) 11349 { 11350 /* 11351 Select a command from the Command widget. 11352 */ 11353 id=XCommandWidget(display,windows,ROIMenu,&event); 11354 if (id < 0) 11355 continue; 11356 switch (ROICommands[id]) 11357 { 11358 case ROIHelpCommand: 11359 { 11360 XTextViewWidget(display,resource_info,windows,MagickFalse, 11361 "Help Viewer - Region of Interest",ImageROIHelp); 11362 break; 11363 } 11364 case ROIDismissCommand: 11365 { 11366 /* 11367 Prematurely exit. 11368 */ 11369 state|=EscapeState; 11370 state|=ExitState; 11371 break; 11372 } 11373 default: 11374 break; 11375 } 11376 continue; 11377 } 11378 switch (event.type) 11379 { 11380 case ButtonPress: 11381 { 11382 if (event.xbutton.button != Button1) 11383 break; 11384 if (event.xbutton.window != windows->image.id) 11385 break; 11386 /* 11387 Note first corner of region of interest rectangle-- exit loop. 11388 */ 11389 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11390 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11391 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11392 state|=ExitState; 11393 break; 11394 } 11395 case ButtonRelease: 11396 break; 11397 case Expose: 11398 break; 11399 case KeyPress: 11400 { 11401 KeySym 11402 key_symbol; 11403 11404 if (event.xkey.window != windows->image.id) 11405 break; 11406 /* 11407 Respond to a user key press. 11408 */ 11409 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11410 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11411 switch ((int) key_symbol) 11412 { 11413 case XK_Escape: 11414 case XK_F20: 11415 { 11416 /* 11417 Prematurely exit. 11418 */ 11419 state|=EscapeState; 11420 state|=ExitState; 11421 break; 11422 } 11423 case XK_F1: 11424 case XK_Help: 11425 { 11426 XTextViewWidget(display,resource_info,windows,MagickFalse, 11427 "Help Viewer - Region of Interest",ImageROIHelp); 11428 break; 11429 } 11430 default: 11431 { 11432 (void) XBell(display,0); 11433 break; 11434 } 11435 } 11436 break; 11437 } 11438 case MotionNotify: 11439 { 11440 /* 11441 Map and unmap Info widget as text cursor crosses its boundaries. 11442 */ 11443 x=event.xmotion.x; 11444 y=event.xmotion.y; 11445 if (windows->info.mapped != MagickFalse) 11446 { 11447 if ((x < (int) (windows->info.x+windows->info.width)) && 11448 (y < (int) (windows->info.y+windows->info.height))) 11449 (void) XWithdrawWindow(display,windows->info.id, 11450 windows->info.screen); 11451 } 11452 else 11453 if ((x > (int) (windows->info.x+windows->info.width)) || 11454 (y > (int) (windows->info.y+windows->info.height))) 11455 (void) XMapWindow(display,windows->info.id); 11456 roi_info.x=(ssize_t) windows->image.x+x; 11457 roi_info.y=(ssize_t) windows->image.y+y; 11458 break; 11459 } 11460 default: 11461 break; 11462 } 11463 } while ((state & ExitState) == 0); 11464 (void) XSelectInput(display,windows->image.id, 11465 windows->image.attributes.event_mask); 11466 if ((state & EscapeState) != 0) 11467 { 11468 /* 11469 User want to exit without region of interest. 11470 */ 11471 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11472 (void) XFreeCursor(display,cursor); 11473 return(MagickTrue); 11474 } 11475 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11476 do 11477 { 11478 /* 11479 Size rectangle as pointer moves until the mouse button is released. 11480 */ 11481 x=(int) roi_info.x; 11482 y=(int) roi_info.y; 11483 roi_info.width=0; 11484 roi_info.height=0; 11485 state=DefaultState; 11486 do 11487 { 11488 highlight_info=roi_info; 11489 highlight_info.x=roi_info.x-windows->image.x; 11490 highlight_info.y=roi_info.y-windows->image.y; 11491 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11492 { 11493 /* 11494 Display info and draw region of interest rectangle. 11495 */ 11496 if (windows->info.mapped == MagickFalse) 11497 (void) XMapWindow(display,windows->info.id); 11498 (void) FormatLocaleString(text,MaxTextExtent, 11499 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11500 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11501 XInfoWidget(display,windows,text); 11502 XHighlightRectangle(display,windows->image.id, 11503 windows->image.highlight_context,&highlight_info); 11504 } 11505 else 11506 if (windows->info.mapped != MagickFalse) 11507 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11508 /* 11509 Wait for next event. 11510 */ 11511 XScreenEvent(display,windows,&event); 11512 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11513 XHighlightRectangle(display,windows->image.id, 11514 windows->image.highlight_context,&highlight_info); 11515 switch (event.type) 11516 { 11517 case ButtonPress: 11518 { 11519 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11520 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11521 break; 11522 } 11523 case ButtonRelease: 11524 { 11525 /* 11526 User has committed to region of interest rectangle. 11527 */ 11528 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11529 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11530 XSetCursorState(display,windows,MagickFalse); 11531 state|=ExitState; 11532 if (LocaleCompare(windows->command.name,"Apply") == 0) 11533 break; 11534 (void) CloneString(&windows->command.name,"Apply"); 11535 windows->command.data=ApplyMenus; 11536 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11537 break; 11538 } 11539 case Expose: 11540 break; 11541 case MotionNotify: 11542 { 11543 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11544 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11545 } 11546 default: 11547 break; 11548 } 11549 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11550 ((state & ExitState) != 0)) 11551 { 11552 /* 11553 Check boundary conditions. 11554 */ 11555 if (roi_info.x < 0) 11556 roi_info.x=0; 11557 else 11558 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11559 roi_info.x=(ssize_t) windows->image.ximage->width; 11560 if ((int) roi_info.x < x) 11561 roi_info.width=(unsigned int) (x-roi_info.x); 11562 else 11563 { 11564 roi_info.width=(unsigned int) (roi_info.x-x); 11565 roi_info.x=(ssize_t) x; 11566 } 11567 if (roi_info.y < 0) 11568 roi_info.y=0; 11569 else 11570 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11571 roi_info.y=(ssize_t) windows->image.ximage->height; 11572 if ((int) roi_info.y < y) 11573 roi_info.height=(unsigned int) (y-roi_info.y); 11574 else 11575 { 11576 roi_info.height=(unsigned int) (roi_info.y-y); 11577 roi_info.y=(ssize_t) y; 11578 } 11579 } 11580 } while ((state & ExitState) == 0); 11581 /* 11582 Wait for user to grab a corner of the rectangle or press return. 11583 */ 11584 state=DefaultState; 11585 command_type=NullCommand; 11586 (void) XMapWindow(display,windows->info.id); 11587 do 11588 { 11589 if (windows->info.mapped != MagickFalse) 11590 { 11591 /* 11592 Display pointer position. 11593 */ 11594 (void) FormatLocaleString(text,MaxTextExtent, 11595 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11596 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11597 XInfoWidget(display,windows,text); 11598 } 11599 highlight_info=roi_info; 11600 highlight_info.x=roi_info.x-windows->image.x; 11601 highlight_info.y=roi_info.y-windows->image.y; 11602 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11603 { 11604 state|=EscapeState; 11605 state|=ExitState; 11606 break; 11607 } 11608 if ((state & UpdateRegionState) != 0) 11609 { 11610 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11611 switch (command_type) 11612 { 11613 case UndoCommand: 11614 case RedoCommand: 11615 { 11616 (void) XMagickCommand(display,resource_info,windows,command_type, 11617 image,exception); 11618 break; 11619 } 11620 default: 11621 { 11622 /* 11623 Region of interest is relative to image configuration. 11624 */ 11625 progress_monitor=SetImageProgressMonitor(*image, 11626 (MagickProgressMonitor) NULL,(*image)->client_data); 11627 crop_info=roi_info; 11628 width=(unsigned int) (*image)->columns; 11629 height=(unsigned int) (*image)->rows; 11630 x=0; 11631 y=0; 11632 if (windows->image.crop_geometry != (char *) NULL) 11633 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11634 &width,&height); 11635 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11636 crop_info.x+=x; 11637 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11638 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11639 scale_factor=(MagickRealType) 11640 height/windows->image.ximage->height; 11641 crop_info.y+=y; 11642 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11643 crop_info.height=(unsigned int) 11644 (scale_factor*crop_info.height+0.5); 11645 roi_image=CropImage(*image,&crop_info,exception); 11646 (void) SetImageProgressMonitor(*image,progress_monitor, 11647 (*image)->client_data); 11648 if (roi_image == (Image *) NULL) 11649 continue; 11650 /* 11651 Apply image processing technique to the region of interest. 11652 */ 11653 windows->image.orphan=MagickTrue; 11654 (void) XMagickCommand(display,resource_info,windows,command_type, 11655 &roi_image,exception); 11656 progress_monitor=SetImageProgressMonitor(*image, 11657 (MagickProgressMonitor) NULL,(*image)->client_data); 11658 (void) XMagickCommand(display,resource_info,windows, 11659 SaveToUndoBufferCommand,image,exception); 11660 windows->image.orphan=MagickFalse; 11661 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11662 crop_info.x,crop_info.y,exception); 11663 roi_image=DestroyImage(roi_image); 11664 (void) SetImageProgressMonitor(*image,progress_monitor, 11665 (*image)->client_data); 11666 break; 11667 } 11668 } 11669 if (command_type != InfoCommand) 11670 { 11671 XConfigureImageColormap(display,resource_info,windows,*image); 11672 (void) XConfigureImage(display,resource_info,windows,*image,exception); 11673 } 11674 XCheckRefreshWindows(display,windows); 11675 XInfoWidget(display,windows,text); 11676 (void) XSetFunction(display,windows->image.highlight_context, 11677 GXinvert); 11678 state&=(~UpdateRegionState); 11679 } 11680 XHighlightRectangle(display,windows->image.id, 11681 windows->image.highlight_context,&highlight_info); 11682 XScreenEvent(display,windows,&event); 11683 if (event.xany.window == windows->command.id) 11684 { 11685 /* 11686 Select a command from the Command widget. 11687 */ 11688 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11689 command_type=NullCommand; 11690 id=XCommandWidget(display,windows,ApplyMenu,&event); 11691 if (id >= 0) 11692 { 11693 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11694 command_type=ApplyCommands[id]; 11695 if (id < ApplyMenus) 11696 { 11697 /* 11698 Select a command from a pop-up menu. 11699 */ 11700 entry=XMenuWidget(display,windows,ApplyMenu[id], 11701 (const char **) Menus[id],command); 11702 if (entry >= 0) 11703 { 11704 (void) CopyMagickString(command,Menus[id][entry], 11705 MaxTextExtent); 11706 command_type=Commands[id][entry]; 11707 } 11708 } 11709 } 11710 (void) XSetFunction(display,windows->image.highlight_context, 11711 GXinvert); 11712 XHighlightRectangle(display,windows->image.id, 11713 windows->image.highlight_context,&highlight_info); 11714 if (command_type == HelpCommand) 11715 { 11716 (void) XSetFunction(display,windows->image.highlight_context, 11717 GXcopy); 11718 XTextViewWidget(display,resource_info,windows,MagickFalse, 11719 "Help Viewer - Region of Interest",ImageROIHelp); 11720 (void) XSetFunction(display,windows->image.highlight_context, 11721 GXinvert); 11722 continue; 11723 } 11724 if (command_type == QuitCommand) 11725 { 11726 /* 11727 exit. 11728 */ 11729 state|=EscapeState; 11730 state|=ExitState; 11731 continue; 11732 } 11733 if (command_type != NullCommand) 11734 state|=UpdateRegionState; 11735 continue; 11736 } 11737 XHighlightRectangle(display,windows->image.id, 11738 windows->image.highlight_context,&highlight_info); 11739 switch (event.type) 11740 { 11741 case ButtonPress: 11742 { 11743 x=windows->image.x; 11744 y=windows->image.y; 11745 if (event.xbutton.button != Button1) 11746 break; 11747 if (event.xbutton.window != windows->image.id) 11748 break; 11749 x=windows->image.x+event.xbutton.x; 11750 y=windows->image.y+event.xbutton.y; 11751 if ((x < (int) (roi_info.x+RoiDelta)) && 11752 (x > (int) (roi_info.x-RoiDelta)) && 11753 (y < (int) (roi_info.y+RoiDelta)) && 11754 (y > (int) (roi_info.y-RoiDelta))) 11755 { 11756 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11757 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11758 state|=UpdateConfigurationState; 11759 break; 11760 } 11761 if ((x < (int) (roi_info.x+RoiDelta)) && 11762 (x > (int) (roi_info.x-RoiDelta)) && 11763 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11764 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11765 { 11766 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11767 state|=UpdateConfigurationState; 11768 break; 11769 } 11770 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11771 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11772 (y < (int) (roi_info.y+RoiDelta)) && 11773 (y > (int) (roi_info.y-RoiDelta))) 11774 { 11775 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11776 state|=UpdateConfigurationState; 11777 break; 11778 } 11779 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11780 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11781 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11782 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11783 { 11784 state|=UpdateConfigurationState; 11785 break; 11786 } 11787 } 11788 case ButtonRelease: 11789 { 11790 if (event.xbutton.window == windows->pan.id) 11791 if ((highlight_info.x != crop_info.x-windows->image.x) || 11792 (highlight_info.y != crop_info.y-windows->image.y)) 11793 XHighlightRectangle(display,windows->image.id, 11794 windows->image.highlight_context,&highlight_info); 11795 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11796 event.xbutton.time); 11797 break; 11798 } 11799 case Expose: 11800 { 11801 if (event.xexpose.window == windows->image.id) 11802 if (event.xexpose.count == 0) 11803 { 11804 event.xexpose.x=(int) highlight_info.x; 11805 event.xexpose.y=(int) highlight_info.y; 11806 event.xexpose.width=(int) highlight_info.width; 11807 event.xexpose.height=(int) highlight_info.height; 11808 XRefreshWindow(display,&windows->image,&event); 11809 } 11810 if (event.xexpose.window == windows->info.id) 11811 if (event.xexpose.count == 0) 11812 XInfoWidget(display,windows,text); 11813 break; 11814 } 11815 case KeyPress: 11816 { 11817 KeySym 11818 key_symbol; 11819 11820 if (event.xkey.window != windows->image.id) 11821 break; 11822 /* 11823 Respond to a user key press. 11824 */ 11825 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11826 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11827 switch ((int) key_symbol) 11828 { 11829 case XK_Shift_L: 11830 case XK_Shift_R: 11831 break; 11832 case XK_Escape: 11833 case XK_F20: 11834 state|=EscapeState; 11835 case XK_Return: 11836 { 11837 state|=ExitState; 11838 break; 11839 } 11840 case XK_Home: 11841 case XK_KP_Home: 11842 { 11843 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11844 roi_info.y=(ssize_t) (windows->image.height/2L- 11845 roi_info.height/2L); 11846 break; 11847 } 11848 case XK_Left: 11849 case XK_KP_Left: 11850 { 11851 roi_info.x--; 11852 break; 11853 } 11854 case XK_Up: 11855 case XK_KP_Up: 11856 case XK_Next: 11857 { 11858 roi_info.y--; 11859 break; 11860 } 11861 case XK_Right: 11862 case XK_KP_Right: 11863 { 11864 roi_info.x++; 11865 break; 11866 } 11867 case XK_Prior: 11868 case XK_Down: 11869 case XK_KP_Down: 11870 { 11871 roi_info.y++; 11872 break; 11873 } 11874 case XK_F1: 11875 case XK_Help: 11876 { 11877 (void) XSetFunction(display,windows->image.highlight_context, 11878 GXcopy); 11879 XTextViewWidget(display,resource_info,windows,MagickFalse, 11880 "Help Viewer - Region of Interest",ImageROIHelp); 11881 (void) XSetFunction(display,windows->image.highlight_context, 11882 GXinvert); 11883 break; 11884 } 11885 default: 11886 { 11887 command_type=XImageWindowCommand(display,resource_info,windows, 11888 event.xkey.state,key_symbol,image,exception); 11889 if (command_type != NullCommand) 11890 state|=UpdateRegionState; 11891 break; 11892 } 11893 } 11894 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11895 event.xkey.time); 11896 break; 11897 } 11898 case KeyRelease: 11899 break; 11900 case MotionNotify: 11901 { 11902 if (event.xbutton.window != windows->image.id) 11903 break; 11904 /* 11905 Map and unmap Info widget as text cursor crosses its boundaries. 11906 */ 11907 x=event.xmotion.x; 11908 y=event.xmotion.y; 11909 if (windows->info.mapped != MagickFalse) 11910 { 11911 if ((x < (int) (windows->info.x+windows->info.width)) && 11912 (y < (int) (windows->info.y+windows->info.height))) 11913 (void) XWithdrawWindow(display,windows->info.id, 11914 windows->info.screen); 11915 } 11916 else 11917 if ((x > (int) (windows->info.x+windows->info.width)) || 11918 (y > (int) (windows->info.y+windows->info.height))) 11919 (void) XMapWindow(display,windows->info.id); 11920 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11921 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11922 break; 11923 } 11924 case SelectionRequest: 11925 { 11926 XSelectionEvent 11927 notify; 11928 11929 XSelectionRequestEvent 11930 *request; 11931 11932 /* 11933 Set primary selection. 11934 */ 11935 (void) FormatLocaleString(text,MaxTextExtent, 11936 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11937 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11938 request=(&(event.xselectionrequest)); 11939 (void) XChangeProperty(request->display,request->requestor, 11940 request->property,request->target,8,PropModeReplace, 11941 (unsigned char *) text,(int) strlen(text)); 11942 notify.type=SelectionNotify; 11943 notify.display=request->display; 11944 notify.requestor=request->requestor; 11945 notify.selection=request->selection; 11946 notify.target=request->target; 11947 notify.time=request->time; 11948 if (request->property == None) 11949 notify.property=request->target; 11950 else 11951 notify.property=request->property; 11952 (void) XSendEvent(request->display,request->requestor,False,0, 11953 (XEvent *) ¬ify); 11954 } 11955 default: 11956 break; 11957 } 11958 if ((state & UpdateConfigurationState) != 0) 11959 { 11960 (void) XPutBackEvent(display,&event); 11961 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11962 break; 11963 } 11964 } while ((state & ExitState) == 0); 11965 } while ((state & ExitState) == 0); 11966 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11967 XSetCursorState(display,windows,MagickFalse); 11968 if ((state & EscapeState) != 0) 11969 return(MagickTrue); 11970 return(MagickTrue); 11971} 11972 11973/* 11974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11975% % 11976% % 11977% % 11978+ X R o t a t e I m a g e % 11979% % 11980% % 11981% % 11982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11983% 11984% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11985% rotation angle is computed from the slope of a line drawn by the user. 11986% 11987% The format of the XRotateImage method is: 11988% 11989% MagickBooleanType XRotateImage(Display *display, 11990% XResourceInfo *resource_info,XWindows *windows,double degrees, 11991% Image **image,ExceptionInfo *exception) 11992% 11993% A description of each parameter follows: 11994% 11995% o display: Specifies a connection to an X server; returned from 11996% XOpenDisplay. 11997% 11998% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11999% 12000% o windows: Specifies a pointer to a XWindows structure. 12001% 12002% o degrees: Specifies the number of degrees to rotate the image. 12003% 12004% o image: the image. 12005% 12006% o exception: return any errors or warnings in this structure. 12007% 12008*/ 12009static MagickBooleanType XRotateImage(Display *display, 12010 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12011 ExceptionInfo *exception) 12012{ 12013 static const char 12014 *RotateMenu[] = 12015 { 12016 "Pixel Color", 12017 "Direction", 12018 "Help", 12019 "Dismiss", 12020 (char *) NULL 12021 }; 12022 12023 static ModeType 12024 direction = HorizontalRotateCommand; 12025 12026 static const ModeType 12027 DirectionCommands[] = 12028 { 12029 HorizontalRotateCommand, 12030 VerticalRotateCommand 12031 }, 12032 RotateCommands[] = 12033 { 12034 RotateColorCommand, 12035 RotateDirectionCommand, 12036 RotateHelpCommand, 12037 RotateDismissCommand 12038 }; 12039 12040 static unsigned int 12041 pen_id = 0; 12042 12043 char 12044 command[MaxTextExtent], 12045 text[MaxTextExtent]; 12046 12047 Image 12048 *rotate_image; 12049 12050 int 12051 id, 12052 x, 12053 y; 12054 12055 MagickRealType 12056 normalized_degrees; 12057 12058 register int 12059 i; 12060 12061 unsigned int 12062 height, 12063 rotations, 12064 width; 12065 12066 if (degrees == 0.0) 12067 { 12068 unsigned int 12069 distance; 12070 12071 size_t 12072 state; 12073 12074 XEvent 12075 event; 12076 12077 XSegment 12078 rotate_info; 12079 12080 /* 12081 Map Command widget. 12082 */ 12083 (void) CloneString(&windows->command.name,"Rotate"); 12084 windows->command.data=2; 12085 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12086 (void) XMapRaised(display,windows->command.id); 12087 XClientMessage(display,windows->image.id,windows->im_protocols, 12088 windows->im_update_widget,CurrentTime); 12089 /* 12090 Wait for first button press. 12091 */ 12092 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12093 XQueryPosition(display,windows->image.id,&x,&y); 12094 rotate_info.x1=x; 12095 rotate_info.y1=y; 12096 rotate_info.x2=x; 12097 rotate_info.y2=y; 12098 state=DefaultState; 12099 do 12100 { 12101 XHighlightLine(display,windows->image.id, 12102 windows->image.highlight_context,&rotate_info); 12103 /* 12104 Wait for next event. 12105 */ 12106 XScreenEvent(display,windows,&event); 12107 XHighlightLine(display,windows->image.id, 12108 windows->image.highlight_context,&rotate_info); 12109 if (event.xany.window == windows->command.id) 12110 { 12111 /* 12112 Select a command from the Command widget. 12113 */ 12114 id=XCommandWidget(display,windows,RotateMenu,&event); 12115 if (id < 0) 12116 continue; 12117 (void) XSetFunction(display,windows->image.highlight_context, 12118 GXcopy); 12119 switch (RotateCommands[id]) 12120 { 12121 case RotateColorCommand: 12122 { 12123 const char 12124 *ColorMenu[MaxNumberPens]; 12125 12126 int 12127 pen_number; 12128 12129 XColor 12130 color; 12131 12132 /* 12133 Initialize menu selections. 12134 */ 12135 for (i=0; i < (int) (MaxNumberPens-2); i++) 12136 ColorMenu[i]=resource_info->pen_colors[i]; 12137 ColorMenu[MaxNumberPens-2]="Browser..."; 12138 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12139 /* 12140 Select a pen color from the pop-up menu. 12141 */ 12142 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12143 (const char **) ColorMenu,command); 12144 if (pen_number < 0) 12145 break; 12146 if (pen_number == (MaxNumberPens-2)) 12147 { 12148 static char 12149 color_name[MaxTextExtent] = "gray"; 12150 12151 /* 12152 Select a pen color from a dialog. 12153 */ 12154 resource_info->pen_colors[pen_number]=color_name; 12155 XColorBrowserWidget(display,windows,"Select",color_name); 12156 if (*color_name == '\0') 12157 break; 12158 } 12159 /* 12160 Set pen color. 12161 */ 12162 (void) XParseColor(display,windows->map_info->colormap, 12163 resource_info->pen_colors[pen_number],&color); 12164 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12165 (unsigned int) MaxColors,&color); 12166 windows->pixel_info->pen_colors[pen_number]=color; 12167 pen_id=(unsigned int) pen_number; 12168 break; 12169 } 12170 case RotateDirectionCommand: 12171 { 12172 static const char 12173 *Directions[] = 12174 { 12175 "horizontal", 12176 "vertical", 12177 (char *) NULL, 12178 }; 12179 12180 /* 12181 Select a command from the pop-up menu. 12182 */ 12183 id=XMenuWidget(display,windows,RotateMenu[id], 12184 Directions,command); 12185 if (id >= 0) 12186 direction=DirectionCommands[id]; 12187 break; 12188 } 12189 case RotateHelpCommand: 12190 { 12191 XTextViewWidget(display,resource_info,windows,MagickFalse, 12192 "Help Viewer - Image Rotation",ImageRotateHelp); 12193 break; 12194 } 12195 case RotateDismissCommand: 12196 { 12197 /* 12198 Prematurely exit. 12199 */ 12200 state|=EscapeState; 12201 state|=ExitState; 12202 break; 12203 } 12204 default: 12205 break; 12206 } 12207 (void) XSetFunction(display,windows->image.highlight_context, 12208 GXinvert); 12209 continue; 12210 } 12211 switch (event.type) 12212 { 12213 case ButtonPress: 12214 { 12215 if (event.xbutton.button != Button1) 12216 break; 12217 if (event.xbutton.window != windows->image.id) 12218 break; 12219 /* 12220 exit loop. 12221 */ 12222 (void) XSetFunction(display,windows->image.highlight_context, 12223 GXcopy); 12224 rotate_info.x1=event.xbutton.x; 12225 rotate_info.y1=event.xbutton.y; 12226 state|=ExitState; 12227 break; 12228 } 12229 case ButtonRelease: 12230 break; 12231 case Expose: 12232 break; 12233 case KeyPress: 12234 { 12235 char 12236 command[MaxTextExtent]; 12237 12238 KeySym 12239 key_symbol; 12240 12241 if (event.xkey.window != windows->image.id) 12242 break; 12243 /* 12244 Respond to a user key press. 12245 */ 12246 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12247 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12248 switch ((int) key_symbol) 12249 { 12250 case XK_Escape: 12251 case XK_F20: 12252 { 12253 /* 12254 Prematurely exit. 12255 */ 12256 state|=EscapeState; 12257 state|=ExitState; 12258 break; 12259 } 12260 case XK_F1: 12261 case XK_Help: 12262 { 12263 (void) XSetFunction(display,windows->image.highlight_context, 12264 GXcopy); 12265 XTextViewWidget(display,resource_info,windows,MagickFalse, 12266 "Help Viewer - Image Rotation",ImageRotateHelp); 12267 (void) XSetFunction(display,windows->image.highlight_context, 12268 GXinvert); 12269 break; 12270 } 12271 default: 12272 { 12273 (void) XBell(display,0); 12274 break; 12275 } 12276 } 12277 break; 12278 } 12279 case MotionNotify: 12280 { 12281 rotate_info.x1=event.xmotion.x; 12282 rotate_info.y1=event.xmotion.y; 12283 } 12284 } 12285 rotate_info.x2=rotate_info.x1; 12286 rotate_info.y2=rotate_info.y1; 12287 if (direction == HorizontalRotateCommand) 12288 rotate_info.x2+=32; 12289 else 12290 rotate_info.y2-=32; 12291 } while ((state & ExitState) == 0); 12292 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12293 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12294 if ((state & EscapeState) != 0) 12295 return(MagickTrue); 12296 /* 12297 Draw line as pointer moves until the mouse button is released. 12298 */ 12299 distance=0; 12300 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12301 state=DefaultState; 12302 do 12303 { 12304 if (distance > 9) 12305 { 12306 /* 12307 Display info and draw rotation line. 12308 */ 12309 if (windows->info.mapped == MagickFalse) 12310 (void) XMapWindow(display,windows->info.id); 12311 (void) FormatLocaleString(text,MaxTextExtent," %g", 12312 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12313 XInfoWidget(display,windows,text); 12314 XHighlightLine(display,windows->image.id, 12315 windows->image.highlight_context,&rotate_info); 12316 } 12317 else 12318 if (windows->info.mapped != MagickFalse) 12319 (void) XWithdrawWindow(display,windows->info.id, 12320 windows->info.screen); 12321 /* 12322 Wait for next event. 12323 */ 12324 XScreenEvent(display,windows,&event); 12325 if (distance > 9) 12326 XHighlightLine(display,windows->image.id, 12327 windows->image.highlight_context,&rotate_info); 12328 switch (event.type) 12329 { 12330 case ButtonPress: 12331 break; 12332 case ButtonRelease: 12333 { 12334 /* 12335 User has committed to rotation line. 12336 */ 12337 rotate_info.x2=event.xbutton.x; 12338 rotate_info.y2=event.xbutton.y; 12339 state|=ExitState; 12340 break; 12341 } 12342 case Expose: 12343 break; 12344 case MotionNotify: 12345 { 12346 rotate_info.x2=event.xmotion.x; 12347 rotate_info.y2=event.xmotion.y; 12348 } 12349 default: 12350 break; 12351 } 12352 /* 12353 Check boundary conditions. 12354 */ 12355 if (rotate_info.x2 < 0) 12356 rotate_info.x2=0; 12357 else 12358 if (rotate_info.x2 > (int) windows->image.width) 12359 rotate_info.x2=(short) windows->image.width; 12360 if (rotate_info.y2 < 0) 12361 rotate_info.y2=0; 12362 else 12363 if (rotate_info.y2 > (int) windows->image.height) 12364 rotate_info.y2=(short) windows->image.height; 12365 /* 12366 Compute rotation angle from the slope of the line. 12367 */ 12368 degrees=0.0; 12369 distance=(unsigned int) 12370 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12371 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12372 if (distance > 9) 12373 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12374 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12375 } while ((state & ExitState) == 0); 12376 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12377 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12378 if (distance <= 9) 12379 return(MagickTrue); 12380 } 12381 if (direction == VerticalRotateCommand) 12382 degrees-=90.0; 12383 if (degrees == 0.0) 12384 return(MagickTrue); 12385 /* 12386 Rotate image. 12387 */ 12388 normalized_degrees=degrees; 12389 while (normalized_degrees < -45.0) 12390 normalized_degrees+=360.0; 12391 for (rotations=0; normalized_degrees > 45.0; rotations++) 12392 normalized_degrees-=90.0; 12393 if (normalized_degrees != 0.0) 12394 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12395 exception); 12396 XSetCursorState(display,windows,MagickTrue); 12397 XCheckRefreshWindows(display,windows); 12398 (*image)->background_color.red=ScaleShortToQuantum( 12399 windows->pixel_info->pen_colors[pen_id].red); 12400 (*image)->background_color.green=ScaleShortToQuantum( 12401 windows->pixel_info->pen_colors[pen_id].green); 12402 (*image)->background_color.blue=ScaleShortToQuantum( 12403 windows->pixel_info->pen_colors[pen_id].blue); 12404 rotate_image=RotateImage(*image,degrees,exception); 12405 XSetCursorState(display,windows,MagickFalse); 12406 if (rotate_image == (Image *) NULL) 12407 return(MagickFalse); 12408 *image=DestroyImage(*image); 12409 *image=rotate_image; 12410 if (windows->image.crop_geometry != (char *) NULL) 12411 { 12412 /* 12413 Rotate crop geometry. 12414 */ 12415 width=(unsigned int) (*image)->columns; 12416 height=(unsigned int) (*image)->rows; 12417 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12418 switch (rotations % 4) 12419 { 12420 default: 12421 case 0: 12422 break; 12423 case 1: 12424 { 12425 /* 12426 Rotate 90 degrees. 12427 */ 12428 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12429 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12430 (int) height-y,x); 12431 break; 12432 } 12433 case 2: 12434 { 12435 /* 12436 Rotate 180 degrees. 12437 */ 12438 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12439 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12440 break; 12441 } 12442 case 3: 12443 { 12444 /* 12445 Rotate 270 degrees. 12446 */ 12447 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12448 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12449 break; 12450 } 12451 } 12452 } 12453 if (windows->image.orphan != MagickFalse) 12454 return(MagickTrue); 12455 if (normalized_degrees != 0.0) 12456 { 12457 /* 12458 Update image colormap. 12459 */ 12460 windows->image.window_changes.width=(int) (*image)->columns; 12461 windows->image.window_changes.height=(int) (*image)->rows; 12462 if (windows->image.crop_geometry != (char *) NULL) 12463 { 12464 /* 12465 Obtain dimensions of image from crop geometry. 12466 */ 12467 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12468 &width,&height); 12469 windows->image.window_changes.width=(int) width; 12470 windows->image.window_changes.height=(int) height; 12471 } 12472 XConfigureImageColormap(display,resource_info,windows,*image); 12473 } 12474 else 12475 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12476 { 12477 windows->image.window_changes.width=windows->image.ximage->height; 12478 windows->image.window_changes.height=windows->image.ximage->width; 12479 } 12480 /* 12481 Update image configuration. 12482 */ 12483 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12484 return(MagickTrue); 12485} 12486 12487/* 12488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12489% % 12490% % 12491% % 12492+ X S a v e I m a g e % 12493% % 12494% % 12495% % 12496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12497% 12498% XSaveImage() saves an image to a file. 12499% 12500% The format of the XSaveImage method is: 12501% 12502% MagickBooleanType XSaveImage(Display *display, 12503% XResourceInfo *resource_info,XWindows *windows,Image *image, 12504% ExceptionInfo *exception) 12505% 12506% A description of each parameter follows: 12507% 12508% o display: Specifies a connection to an X server; returned from 12509% XOpenDisplay. 12510% 12511% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12512% 12513% o windows: Specifies a pointer to a XWindows structure. 12514% 12515% o image: the image. 12516% 12517% o exception: return any errors or warnings in this structure. 12518% 12519*/ 12520static MagickBooleanType XSaveImage(Display *display, 12521 XResourceInfo *resource_info,XWindows *windows,Image *image, 12522 ExceptionInfo *exception) 12523{ 12524 char 12525 filename[MaxTextExtent], 12526 geometry[MaxTextExtent]; 12527 12528 Image 12529 *save_image; 12530 12531 ImageInfo 12532 *image_info; 12533 12534 MagickStatusType 12535 status; 12536 12537 /* 12538 Request file name from user. 12539 */ 12540 if (resource_info->write_filename != (char *) NULL) 12541 (void) CopyMagickString(filename,resource_info->write_filename, 12542 MaxTextExtent); 12543 else 12544 { 12545 char 12546 path[MaxTextExtent]; 12547 12548 int 12549 status; 12550 12551 GetPathComponent(image->filename,HeadPath,path); 12552 GetPathComponent(image->filename,TailPath,filename); 12553 if (*path != '\0') 12554 { 12555 status=chdir(path); 12556 if (status == -1) 12557 (void) ThrowMagickException(exception,GetMagickModule(), 12558 FileOpenError,"UnableToOpenFile","%s",path); 12559 } 12560 } 12561 XFileBrowserWidget(display,windows,"Save",filename); 12562 if (*filename == '\0') 12563 return(MagickTrue); 12564 if (IsPathAccessible(filename) != MagickFalse) 12565 { 12566 int 12567 status; 12568 12569 /* 12570 File exists-- seek user's permission before overwriting. 12571 */ 12572 status=XConfirmWidget(display,windows,"Overwrite",filename); 12573 if (status <= 0) 12574 return(MagickTrue); 12575 } 12576 image_info=CloneImageInfo(resource_info->image_info); 12577 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12578 (void) SetImageInfo(image_info,1,exception); 12579 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12580 (LocaleCompare(image_info->magick,"JPG") == 0)) 12581 { 12582 char 12583 quality[MaxTextExtent]; 12584 12585 int 12586 status; 12587 12588 /* 12589 Request JPEG quality from user. 12590 */ 12591 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12592 image->quality); 12593 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12594 quality); 12595 if (*quality == '\0') 12596 return(MagickTrue); 12597 image->quality=StringToUnsignedLong(quality); 12598 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12599 } 12600 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12601 (LocaleCompare(image_info->magick,"PDF") == 0) || 12602 (LocaleCompare(image_info->magick,"PS") == 0) || 12603 (LocaleCompare(image_info->magick,"PS2") == 0)) 12604 { 12605 char 12606 geometry[MaxTextExtent]; 12607 12608 /* 12609 Request page geometry from user. 12610 */ 12611 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12612 if (LocaleCompare(image_info->magick,"PDF") == 0) 12613 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12614 if (image_info->page != (char *) NULL) 12615 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12616 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12617 "Select page geometry:",geometry); 12618 if (*geometry != '\0') 12619 image_info->page=GetPageGeometry(geometry); 12620 } 12621 /* 12622 Apply image transforms. 12623 */ 12624 XSetCursorState(display,windows,MagickTrue); 12625 XCheckRefreshWindows(display,windows); 12626 save_image=CloneImage(image,0,0,MagickTrue,exception); 12627 if (save_image == (Image *) NULL) 12628 return(MagickFalse); 12629 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12630 windows->image.ximage->width,windows->image.ximage->height); 12631 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12632 exception); 12633 /* 12634 Write image. 12635 */ 12636 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12637 status=WriteImage(image_info,save_image,exception); 12638 if (status != MagickFalse) 12639 image->taint=MagickFalse; 12640 save_image=DestroyImage(save_image); 12641 image_info=DestroyImageInfo(image_info); 12642 XSetCursorState(display,windows,MagickFalse); 12643 return(status != 0 ? MagickTrue : MagickFalse); 12644} 12645 12646/* 12647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12648% % 12649% % 12650% % 12651+ X S c r e e n E v e n t % 12652% % 12653% % 12654% % 12655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12656% 12657% XScreenEvent() handles global events associated with the Pan and Magnify 12658% windows. 12659% 12660% The format of the XScreenEvent function is: 12661% 12662% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12663% 12664% A description of each parameter follows: 12665% 12666% o display: Specifies a pointer to the Display structure; returned from 12667% XOpenDisplay. 12668% 12669% o windows: Specifies a pointer to a XWindows structure. 12670% 12671% o event: Specifies a pointer to a X11 XEvent structure. 12672% 12673% 12674*/ 12675 12676#if defined(__cplusplus) || defined(c_plusplus) 12677extern "C" { 12678#endif 12679 12680static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12681{ 12682 register XWindows 12683 *windows; 12684 12685 windows=(XWindows *) data; 12686 if ((event->type == ClientMessage) && 12687 (event->xclient.window == windows->image.id)) 12688 return(MagickFalse); 12689 return(MagickTrue); 12690} 12691 12692#if defined(__cplusplus) || defined(c_plusplus) 12693} 12694#endif 12695 12696static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12697{ 12698 register int 12699 x, 12700 y; 12701 12702 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12703 if (event->xany.window == windows->command.id) 12704 return; 12705 switch (event->type) 12706 { 12707 case ButtonPress: 12708 case ButtonRelease: 12709 { 12710 if ((event->xbutton.button == Button3) && 12711 (event->xbutton.state & Mod1Mask)) 12712 { 12713 /* 12714 Convert Alt-Button3 to Button2. 12715 */ 12716 event->xbutton.button=Button2; 12717 event->xbutton.state&=(~Mod1Mask); 12718 } 12719 if (event->xbutton.window == windows->backdrop.id) 12720 { 12721 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12722 event->xbutton.time); 12723 break; 12724 } 12725 if (event->xbutton.window == windows->pan.id) 12726 { 12727 XPanImage(display,windows,event); 12728 break; 12729 } 12730 if (event->xbutton.window == windows->image.id) 12731 if (event->xbutton.button == Button2) 12732 { 12733 /* 12734 Update magnified image. 12735 */ 12736 x=event->xbutton.x; 12737 y=event->xbutton.y; 12738 if (x < 0) 12739 x=0; 12740 else 12741 if (x >= (int) windows->image.width) 12742 x=(int) (windows->image.width-1); 12743 windows->magnify.x=(int) windows->image.x+x; 12744 if (y < 0) 12745 y=0; 12746 else 12747 if (y >= (int) windows->image.height) 12748 y=(int) (windows->image.height-1); 12749 windows->magnify.y=windows->image.y+y; 12750 if (windows->magnify.mapped == MagickFalse) 12751 (void) XMapRaised(display,windows->magnify.id); 12752 XMakeMagnifyImage(display,windows); 12753 if (event->type == ButtonRelease) 12754 (void) XWithdrawWindow(display,windows->info.id, 12755 windows->info.screen); 12756 break; 12757 } 12758 break; 12759 } 12760 case ClientMessage: 12761 { 12762 /* 12763 If client window delete message, exit. 12764 */ 12765 if (event->xclient.message_type != windows->wm_protocols) 12766 break; 12767 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12768 break; 12769 if (event->xclient.window == windows->magnify.id) 12770 { 12771 (void) XWithdrawWindow(display,windows->magnify.id, 12772 windows->magnify.screen); 12773 break; 12774 } 12775 break; 12776 } 12777 case ConfigureNotify: 12778 { 12779 if (event->xconfigure.window == windows->magnify.id) 12780 { 12781 unsigned int 12782 magnify; 12783 12784 /* 12785 Magnify window has a new configuration. 12786 */ 12787 windows->magnify.width=(unsigned int) event->xconfigure.width; 12788 windows->magnify.height=(unsigned int) event->xconfigure.height; 12789 if (windows->magnify.mapped == MagickFalse) 12790 break; 12791 magnify=1; 12792 while ((int) magnify <= event->xconfigure.width) 12793 magnify<<=1; 12794 while ((int) magnify <= event->xconfigure.height) 12795 magnify<<=1; 12796 magnify>>=1; 12797 if (((int) magnify != event->xconfigure.width) || 12798 ((int) magnify != event->xconfigure.height)) 12799 { 12800 XWindowChanges 12801 window_changes; 12802 12803 window_changes.width=(int) magnify; 12804 window_changes.height=(int) magnify; 12805 (void) XReconfigureWMWindow(display,windows->magnify.id, 12806 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12807 &window_changes); 12808 break; 12809 } 12810 XMakeMagnifyImage(display,windows); 12811 break; 12812 } 12813 break; 12814 } 12815 case Expose: 12816 { 12817 if (event->xexpose.window == windows->image.id) 12818 { 12819 XRefreshWindow(display,&windows->image,event); 12820 break; 12821 } 12822 if (event->xexpose.window == windows->pan.id) 12823 if (event->xexpose.count == 0) 12824 { 12825 XDrawPanRectangle(display,windows); 12826 break; 12827 } 12828 if (event->xexpose.window == windows->magnify.id) 12829 if (event->xexpose.count == 0) 12830 { 12831 XMakeMagnifyImage(display,windows); 12832 break; 12833 } 12834 break; 12835 } 12836 case KeyPress: 12837 { 12838 char 12839 command[MaxTextExtent]; 12840 12841 KeySym 12842 key_symbol; 12843 12844 if (event->xkey.window != windows->magnify.id) 12845 break; 12846 /* 12847 Respond to a user key press. 12848 */ 12849 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12850 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12851 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12852 break; 12853 } 12854 case MapNotify: 12855 { 12856 if (event->xmap.window == windows->magnify.id) 12857 { 12858 windows->magnify.mapped=MagickTrue; 12859 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12860 break; 12861 } 12862 if (event->xmap.window == windows->info.id) 12863 { 12864 windows->info.mapped=MagickTrue; 12865 break; 12866 } 12867 break; 12868 } 12869 case MotionNotify: 12870 { 12871 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12872 if (event->xmotion.window == windows->image.id) 12873 if (windows->magnify.mapped != MagickFalse) 12874 { 12875 /* 12876 Update magnified image. 12877 */ 12878 x=event->xmotion.x; 12879 y=event->xmotion.y; 12880 if (x < 0) 12881 x=0; 12882 else 12883 if (x >= (int) windows->image.width) 12884 x=(int) (windows->image.width-1); 12885 windows->magnify.x=(int) windows->image.x+x; 12886 if (y < 0) 12887 y=0; 12888 else 12889 if (y >= (int) windows->image.height) 12890 y=(int) (windows->image.height-1); 12891 windows->magnify.y=windows->image.y+y; 12892 XMakeMagnifyImage(display,windows); 12893 } 12894 break; 12895 } 12896 case UnmapNotify: 12897 { 12898 if (event->xunmap.window == windows->magnify.id) 12899 { 12900 windows->magnify.mapped=MagickFalse; 12901 break; 12902 } 12903 if (event->xunmap.window == windows->info.id) 12904 { 12905 windows->info.mapped=MagickFalse; 12906 break; 12907 } 12908 break; 12909 } 12910 default: 12911 break; 12912 } 12913} 12914 12915/* 12916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12917% % 12918% % 12919% % 12920+ X S e t C r o p G e o m e t r y % 12921% % 12922% % 12923% % 12924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12925% 12926% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12927% and translates it to a cropping geometry relative to the image. 12928% 12929% The format of the XSetCropGeometry method is: 12930% 12931% void XSetCropGeometry(Display *display,XWindows *windows, 12932% RectangleInfo *crop_info,Image *image) 12933% 12934% A description of each parameter follows: 12935% 12936% o display: Specifies a connection to an X server; returned from 12937% XOpenDisplay. 12938% 12939% o windows: Specifies a pointer to a XWindows structure. 12940% 12941% o crop_info: A pointer to a RectangleInfo that defines a region of the 12942% Image window to crop. 12943% 12944% o image: the image. 12945% 12946*/ 12947static void XSetCropGeometry(Display *display,XWindows *windows, 12948 RectangleInfo *crop_info,Image *image) 12949{ 12950 char 12951 text[MaxTextExtent]; 12952 12953 int 12954 x, 12955 y; 12956 12957 MagickRealType 12958 scale_factor; 12959 12960 unsigned int 12961 height, 12962 width; 12963 12964 if (windows->info.mapped != MagickFalse) 12965 { 12966 /* 12967 Display info on cropping rectangle. 12968 */ 12969 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12970 (double) crop_info->width,(double) crop_info->height,(double) 12971 crop_info->x,(double) crop_info->y); 12972 XInfoWidget(display,windows,text); 12973 } 12974 /* 12975 Cropping geometry is relative to any previous crop geometry. 12976 */ 12977 x=0; 12978 y=0; 12979 width=(unsigned int) image->columns; 12980 height=(unsigned int) image->rows; 12981 if (windows->image.crop_geometry != (char *) NULL) 12982 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12983 else 12984 windows->image.crop_geometry=AcquireString((char *) NULL); 12985 /* 12986 Define the crop geometry string from the cropping rectangle. 12987 */ 12988 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12989 if (crop_info->x > 0) 12990 x+=(int) (scale_factor*crop_info->x+0.5); 12991 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12992 if (width == 0) 12993 width=1; 12994 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12995 if (crop_info->y > 0) 12996 y+=(int) (scale_factor*crop_info->y+0.5); 12997 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12998 if (height == 0) 12999 height=1; 13000 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13001 "%ux%u%+d%+d",width,height,x,y); 13002} 13003 13004/* 13005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13006% % 13007% % 13008% % 13009+ X T i l e I m a g e % 13010% % 13011% % 13012% % 13013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13014% 13015% XTileImage() loads or deletes a selected tile from a visual image directory. 13016% The load or delete command is chosen from a menu. 13017% 13018% The format of the XTileImage method is: 13019% 13020% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13021% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13022% 13023% A description of each parameter follows: 13024% 13025% o tile_image: XTileImage reads or deletes the tile image 13026% and returns it. A null image is returned if an error occurs. 13027% 13028% o display: Specifies a connection to an X server; returned from 13029% XOpenDisplay. 13030% 13031% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13032% 13033% o windows: Specifies a pointer to a XWindows structure. 13034% 13035% o image: the image; returned from ReadImage. 13036% 13037% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13038% the entire image is refreshed. 13039% 13040% o exception: return any errors or warnings in this structure. 13041% 13042*/ 13043static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13044 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13045{ 13046 static const char 13047 *VerbMenu[] = 13048 { 13049 "Load", 13050 "Next", 13051 "Former", 13052 "Delete", 13053 "Update", 13054 (char *) NULL, 13055 }; 13056 13057 static const ModeType 13058 TileCommands[] = 13059 { 13060 TileLoadCommand, 13061 TileNextCommand, 13062 TileFormerCommand, 13063 TileDeleteCommand, 13064 TileUpdateCommand 13065 }; 13066 13067 char 13068 command[MaxTextExtent], 13069 filename[MaxTextExtent]; 13070 13071 Image 13072 *tile_image; 13073 13074 int 13075 id, 13076 status, 13077 tile, 13078 x, 13079 y; 13080 13081 MagickRealType 13082 scale_factor; 13083 13084 register char 13085 *p, 13086 *q; 13087 13088 register int 13089 i; 13090 13091 unsigned int 13092 height, 13093 width; 13094 13095 /* 13096 Tile image is relative to montage image configuration. 13097 */ 13098 x=0; 13099 y=0; 13100 width=(unsigned int) image->columns; 13101 height=(unsigned int) image->rows; 13102 if (windows->image.crop_geometry != (char *) NULL) 13103 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13104 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13105 event->xbutton.x+=windows->image.x; 13106 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13107 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13108 event->xbutton.y+=windows->image.y; 13109 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13110 /* 13111 Determine size and location of each tile in the visual image directory. 13112 */ 13113 width=(unsigned int) image->columns; 13114 height=(unsigned int) image->rows; 13115 x=0; 13116 y=0; 13117 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13118 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13119 (event->xbutton.x-x)/width; 13120 if (tile < 0) 13121 { 13122 /* 13123 Button press is outside any tile. 13124 */ 13125 (void) XBell(display,0); 13126 return((Image *) NULL); 13127 } 13128 /* 13129 Determine file name from the tile directory. 13130 */ 13131 p=image->directory; 13132 for (i=tile; (i != 0) && (*p != '\0'); ) 13133 { 13134 if (*p == '\n') 13135 i--; 13136 p++; 13137 } 13138 if (*p == '\0') 13139 { 13140 /* 13141 Button press is outside any tile. 13142 */ 13143 (void) XBell(display,0); 13144 return((Image *) NULL); 13145 } 13146 /* 13147 Select a command from the pop-up menu. 13148 */ 13149 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13150 if (id < 0) 13151 return((Image *) NULL); 13152 q=p; 13153 while ((*q != '\n') && (*q != '\0')) 13154 q++; 13155 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13156 /* 13157 Perform command for the selected tile. 13158 */ 13159 XSetCursorState(display,windows,MagickTrue); 13160 XCheckRefreshWindows(display,windows); 13161 tile_image=NewImageList(); 13162 switch (TileCommands[id]) 13163 { 13164 case TileLoadCommand: 13165 { 13166 /* 13167 Load tile image. 13168 */ 13169 XCheckRefreshWindows(display,windows); 13170 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13171 MaxTextExtent); 13172 (void) CopyMagickString(resource_info->image_info->filename,filename, 13173 MaxTextExtent); 13174 tile_image=ReadImage(resource_info->image_info,exception); 13175 CatchException(exception); 13176 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13177 break; 13178 } 13179 case TileNextCommand: 13180 { 13181 /* 13182 Display next image. 13183 */ 13184 XClientMessage(display,windows->image.id,windows->im_protocols, 13185 windows->im_next_image,CurrentTime); 13186 break; 13187 } 13188 case TileFormerCommand: 13189 { 13190 /* 13191 Display former image. 13192 */ 13193 XClientMessage(display,windows->image.id,windows->im_protocols, 13194 windows->im_former_image,CurrentTime); 13195 break; 13196 } 13197 case TileDeleteCommand: 13198 { 13199 /* 13200 Delete tile image. 13201 */ 13202 if (IsPathAccessible(filename) == MagickFalse) 13203 { 13204 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13205 break; 13206 } 13207 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13208 if (status <= 0) 13209 break; 13210 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13211 if (status != MagickFalse) 13212 { 13213 XNoticeWidget(display,windows,"Unable to delete image file:", 13214 filename); 13215 break; 13216 } 13217 } 13218 case TileUpdateCommand: 13219 { 13220 int 13221 x_offset, 13222 y_offset; 13223 13224 PixelInfo 13225 pixel; 13226 13227 Quantum 13228 virtual_pixel[MaxPixelChannels]; 13229 13230 register int 13231 j; 13232 13233 register Quantum 13234 *s; 13235 13236 /* 13237 Ensure all the images exist. 13238 */ 13239 tile=0; 13240 GetPixelInfo(image,&pixel); 13241 for (p=image->directory; *p != '\0'; p++) 13242 { 13243 CacheView 13244 *image_view; 13245 13246 q=p; 13247 while ((*q != '\n') && (*q != '\0')) 13248 q++; 13249 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13250 p=q; 13251 if (IsPathAccessible(filename) != MagickFalse) 13252 { 13253 tile++; 13254 continue; 13255 } 13256 /* 13257 Overwrite tile with background color. 13258 */ 13259 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13260 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13261 image_view=AcquireCacheView(image); 13262 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13263 exception); 13264 pixel.red=virtual_pixel[RedPixelChannel]; 13265 pixel.green=virtual_pixel[GreenPixelChannel]; 13266 pixel.blue=virtual_pixel[BluePixelChannel]; 13267 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13268 for (i=0; i < (int) height; i++) 13269 { 13270 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13271 y_offset+i,width,1,exception); 13272 if (s == (Quantum *) NULL) 13273 break; 13274 for (j=0; j < (int) width; j++) 13275 { 13276 SetPixelPixelInfo(image,&pixel,s); 13277 s+=GetPixelChannels(image); 13278 } 13279 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13280 break; 13281 } 13282 image_view=DestroyCacheView(image_view); 13283 tile++; 13284 } 13285 windows->image.window_changes.width=(int) image->columns; 13286 windows->image.window_changes.height=(int) image->rows; 13287 XConfigureImageColormap(display,resource_info,windows,image); 13288 (void) XConfigureImage(display,resource_info,windows,image,exception); 13289 break; 13290 } 13291 default: 13292 break; 13293 } 13294 XSetCursorState(display,windows,MagickFalse); 13295 return(tile_image); 13296} 13297 13298/* 13299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13300% % 13301% % 13302% % 13303+ X T r a n s l a t e I m a g e % 13304% % 13305% % 13306% % 13307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13308% 13309% XTranslateImage() translates the image within an Image window by one pixel 13310% as specified by the key symbol. If the image has a `montage string the 13311% translation is respect to the width and height contained within the string. 13312% 13313% The format of the XTranslateImage method is: 13314% 13315% void XTranslateImage(Display *display,XWindows *windows, 13316% Image *image,const KeySym key_symbol) 13317% 13318% A description of each parameter follows: 13319% 13320% o display: Specifies a connection to an X server; returned from 13321% XOpenDisplay. 13322% 13323% o windows: Specifies a pointer to a XWindows structure. 13324% 13325% o image: the image. 13326% 13327% o key_symbol: Specifies a KeySym which indicates which side of the image 13328% to trim. 13329% 13330*/ 13331static void XTranslateImage(Display *display,XWindows *windows, 13332 Image *image,const KeySym key_symbol) 13333{ 13334 char 13335 text[MaxTextExtent]; 13336 13337 int 13338 x, 13339 y; 13340 13341 unsigned int 13342 x_offset, 13343 y_offset; 13344 13345 /* 13346 User specified a pan position offset. 13347 */ 13348 x_offset=windows->image.width; 13349 y_offset=windows->image.height; 13350 if (image->montage != (char *) NULL) 13351 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13352 switch ((int) key_symbol) 13353 { 13354 case XK_Home: 13355 case XK_KP_Home: 13356 { 13357 windows->image.x=(int) windows->image.width/2; 13358 windows->image.y=(int) windows->image.height/2; 13359 break; 13360 } 13361 case XK_Left: 13362 case XK_KP_Left: 13363 { 13364 windows->image.x-=x_offset; 13365 break; 13366 } 13367 case XK_Next: 13368 case XK_Up: 13369 case XK_KP_Up: 13370 { 13371 windows->image.y-=y_offset; 13372 break; 13373 } 13374 case XK_Right: 13375 case XK_KP_Right: 13376 { 13377 windows->image.x+=x_offset; 13378 break; 13379 } 13380 case XK_Prior: 13381 case XK_Down: 13382 case XK_KP_Down: 13383 { 13384 windows->image.y+=y_offset; 13385 break; 13386 } 13387 default: 13388 return; 13389 } 13390 /* 13391 Check boundary conditions. 13392 */ 13393 if (windows->image.x < 0) 13394 windows->image.x=0; 13395 else 13396 if ((int) (windows->image.x+windows->image.width) > 13397 windows->image.ximage->width) 13398 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13399 if (windows->image.y < 0) 13400 windows->image.y=0; 13401 else 13402 if ((int) (windows->image.y+windows->image.height) > 13403 windows->image.ximage->height) 13404 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13405 /* 13406 Refresh Image window. 13407 */ 13408 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13409 windows->image.width,windows->image.height,windows->image.x, 13410 windows->image.y); 13411 XInfoWidget(display,windows,text); 13412 XCheckRefreshWindows(display,windows); 13413 XDrawPanRectangle(display,windows); 13414 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13415 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13416} 13417 13418/* 13419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13420% % 13421% % 13422% % 13423+ X T r i m I m a g e % 13424% % 13425% % 13426% % 13427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13428% 13429% XTrimImage() trims the edges from the Image window. 13430% 13431% The format of the XTrimImage method is: 13432% 13433% MagickBooleanType XTrimImage(Display *display, 13434% XResourceInfo *resource_info,XWindows *windows,Image *image, 13435% ExceptionInfo *exception) 13436% 13437% A description of each parameter follows: 13438% 13439% o display: Specifies a connection to an X server; returned from 13440% XOpenDisplay. 13441% 13442% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13443% 13444% o windows: Specifies a pointer to a XWindows structure. 13445% 13446% o image: the image. 13447% 13448% o exception: return any errors or warnings in this structure. 13449% 13450*/ 13451static MagickBooleanType XTrimImage(Display *display, 13452 XResourceInfo *resource_info,XWindows *windows,Image *image, 13453 ExceptionInfo *exception) 13454{ 13455 RectangleInfo 13456 trim_info; 13457 13458 register int 13459 x, 13460 y; 13461 13462 size_t 13463 background, 13464 pixel; 13465 13466 /* 13467 Trim edges from image. 13468 */ 13469 XSetCursorState(display,windows,MagickTrue); 13470 XCheckRefreshWindows(display,windows); 13471 /* 13472 Crop the left edge. 13473 */ 13474 background=XGetPixel(windows->image.ximage,0,0); 13475 trim_info.width=(size_t) windows->image.ximage->width; 13476 for (x=0; x < windows->image.ximage->width; x++) 13477 { 13478 for (y=0; y < windows->image.ximage->height; y++) 13479 { 13480 pixel=XGetPixel(windows->image.ximage,x,y); 13481 if (pixel != background) 13482 break; 13483 } 13484 if (y < windows->image.ximage->height) 13485 break; 13486 } 13487 trim_info.x=(ssize_t) x; 13488 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13489 { 13490 XSetCursorState(display,windows,MagickFalse); 13491 return(MagickFalse); 13492 } 13493 /* 13494 Crop the right edge. 13495 */ 13496 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13497 for (x=windows->image.ximage->width-1; x != 0; x--) 13498 { 13499 for (y=0; y < windows->image.ximage->height; y++) 13500 { 13501 pixel=XGetPixel(windows->image.ximage,x,y); 13502 if (pixel != background) 13503 break; 13504 } 13505 if (y < windows->image.ximage->height) 13506 break; 13507 } 13508 trim_info.width=(size_t) (x-trim_info.x+1); 13509 /* 13510 Crop the top edge. 13511 */ 13512 background=XGetPixel(windows->image.ximage,0,0); 13513 trim_info.height=(size_t) windows->image.ximage->height; 13514 for (y=0; y < windows->image.ximage->height; y++) 13515 { 13516 for (x=0; x < windows->image.ximage->width; x++) 13517 { 13518 pixel=XGetPixel(windows->image.ximage,x,y); 13519 if (pixel != background) 13520 break; 13521 } 13522 if (x < windows->image.ximage->width) 13523 break; 13524 } 13525 trim_info.y=(ssize_t) y; 13526 /* 13527 Crop the bottom edge. 13528 */ 13529 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13530 for (y=windows->image.ximage->height-1; y != 0; y--) 13531 { 13532 for (x=0; x < windows->image.ximage->width; x++) 13533 { 13534 pixel=XGetPixel(windows->image.ximage,x,y); 13535 if (pixel != background) 13536 break; 13537 } 13538 if (x < windows->image.ximage->width) 13539 break; 13540 } 13541 trim_info.height=(size_t) y-trim_info.y+1; 13542 if (((unsigned int) trim_info.width != windows->image.width) || 13543 ((unsigned int) trim_info.height != windows->image.height)) 13544 { 13545 /* 13546 Reconfigure Image window as defined by the trimming rectangle. 13547 */ 13548 XSetCropGeometry(display,windows,&trim_info,image); 13549 windows->image.window_changes.width=(int) trim_info.width; 13550 windows->image.window_changes.height=(int) trim_info.height; 13551 (void) XConfigureImage(display,resource_info,windows,image,exception); 13552 } 13553 XSetCursorState(display,windows,MagickFalse); 13554 return(MagickTrue); 13555} 13556 13557/* 13558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13559% % 13560% % 13561% % 13562+ X V i s u a l D i r e c t o r y I m a g e % 13563% % 13564% % 13565% % 13566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13567% 13568% XVisualDirectoryImage() creates a Visual Image Directory. 13569% 13570% The format of the XVisualDirectoryImage method is: 13571% 13572% Image *XVisualDirectoryImage(Display *display, 13573% XResourceInfo *resource_info,XWindows *windows, 13574% ExceptionInfo *exception) 13575% 13576% A description of each parameter follows: 13577% 13578% o display: Specifies a connection to an X server; returned from 13579% XOpenDisplay. 13580% 13581% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13582% 13583% o windows: Specifies a pointer to a XWindows structure. 13584% 13585% o exception: return any errors or warnings in this structure. 13586% 13587*/ 13588static Image *XVisualDirectoryImage(Display *display, 13589 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13590{ 13591#define TileImageTag "Scale/Image" 13592#define XClientName "montage" 13593 13594 char 13595 **filelist; 13596 13597 Image 13598 *images, 13599 *montage_image, 13600 *next_image, 13601 *thumbnail_image; 13602 13603 ImageInfo 13604 *read_info; 13605 13606 int 13607 number_files; 13608 13609 MagickBooleanType 13610 backdrop; 13611 13612 MagickStatusType 13613 status; 13614 13615 MontageInfo 13616 *montage_info; 13617 13618 RectangleInfo 13619 geometry; 13620 13621 register int 13622 i; 13623 13624 static char 13625 filename[MaxTextExtent] = "\0", 13626 filenames[MaxTextExtent] = "*"; 13627 13628 XResourceInfo 13629 background_resources; 13630 13631 /* 13632 Request file name from user. 13633 */ 13634 XFileBrowserWidget(display,windows,"Directory",filenames); 13635 if (*filenames == '\0') 13636 return((Image *) NULL); 13637 /* 13638 Expand the filenames. 13639 */ 13640 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13641 if (filelist == (char **) NULL) 13642 { 13643 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13644 filenames); 13645 return((Image *) NULL); 13646 } 13647 number_files=1; 13648 filelist[0]=filenames; 13649 status=ExpandFilenames(&number_files,&filelist); 13650 if ((status == MagickFalse) || (number_files == 0)) 13651 { 13652 if (number_files == 0) 13653 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13654 else 13655 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13656 filenames); 13657 return((Image *) NULL); 13658 } 13659 /* 13660 Set image background resources. 13661 */ 13662 background_resources=(*resource_info); 13663 background_resources.window_id=AcquireString(""); 13664 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13665 "0x%lx",windows->image.id); 13666 background_resources.backdrop=MagickTrue; 13667 /* 13668 Read each image and convert them to a tile. 13669 */ 13670 backdrop=(windows->visual_info->klass == TrueColor) || 13671 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13672 read_info=CloneImageInfo(resource_info->image_info); 13673 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13674 (void) CloneString(&read_info->size,DefaultTileGeometry); 13675 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13676 (void *) NULL); 13677 images=NewImageList(); 13678 XSetCursorState(display,windows,MagickTrue); 13679 XCheckRefreshWindows(display,windows); 13680 for (i=0; i < (int) number_files; i++) 13681 { 13682 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13683 filelist[i]=DestroyString(filelist[i]); 13684 *read_info->magick='\0'; 13685 next_image=ReadImage(read_info,exception); 13686 CatchException(exception); 13687 if (next_image != (Image *) NULL) 13688 { 13689 (void) DeleteImageProperty(next_image,"label"); 13690 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13691 read_info,next_image,DefaultTileLabel,exception),exception); 13692 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13693 exception); 13694 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13695 geometry.height,exception); 13696 if (thumbnail_image != (Image *) NULL) 13697 { 13698 next_image=DestroyImage(next_image); 13699 next_image=thumbnail_image; 13700 } 13701 if (backdrop) 13702 { 13703 (void) XDisplayBackgroundImage(display,&background_resources, 13704 next_image,exception); 13705 XSetCursorState(display,windows,MagickTrue); 13706 } 13707 AppendImageToList(&images,next_image); 13708 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13709 { 13710 MagickBooleanType 13711 proceed; 13712 13713 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13714 (MagickSizeType) number_files); 13715 if (proceed == MagickFalse) 13716 break; 13717 } 13718 } 13719 } 13720 filelist=(char **) RelinquishMagickMemory(filelist); 13721 if (images == (Image *) NULL) 13722 { 13723 read_info=DestroyImageInfo(read_info); 13724 XSetCursorState(display,windows,MagickFalse); 13725 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13726 return((Image *) NULL); 13727 } 13728 /* 13729 Create the Visual Image Directory. 13730 */ 13731 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13732 montage_info->pointsize=10; 13733 if (resource_info->font != (char *) NULL) 13734 (void) CloneString(&montage_info->font,resource_info->font); 13735 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13736 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13737 images),exception); 13738 images=DestroyImageList(images); 13739 montage_info=DestroyMontageInfo(montage_info); 13740 read_info=DestroyImageInfo(read_info); 13741 XSetCursorState(display,windows,MagickFalse); 13742 if (montage_image == (Image *) NULL) 13743 return(montage_image); 13744 XClientMessage(display,windows->image.id,windows->im_protocols, 13745 windows->im_next_image,CurrentTime); 13746 return(montage_image); 13747} 13748 13749/* 13750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13751% % 13752% % 13753% % 13754% X D i s p l a y B a c k g r o u n d I m a g e % 13755% % 13756% % 13757% % 13758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13759% 13760% XDisplayBackgroundImage() displays an image in the background of a window. 13761% 13762% The format of the XDisplayBackgroundImage method is: 13763% 13764% MagickBooleanType XDisplayBackgroundImage(Display *display, 13765% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13766% 13767% A description of each parameter follows: 13768% 13769% o display: Specifies a connection to an X server; returned from 13770% XOpenDisplay. 13771% 13772% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13773% 13774% o image: the image. 13775% 13776% o exception: return any errors or warnings in this structure. 13777% 13778*/ 13779MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13780 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13781{ 13782 char 13783 geometry[MaxTextExtent], 13784 visual_type[MaxTextExtent]; 13785 13786 int 13787 height, 13788 status, 13789 width; 13790 13791 RectangleInfo 13792 geometry_info; 13793 13794 static XPixelInfo 13795 pixel; 13796 13797 static XStandardColormap 13798 *map_info; 13799 13800 static XVisualInfo 13801 *visual_info = (XVisualInfo *) NULL; 13802 13803 static XWindowInfo 13804 window_info; 13805 13806 size_t 13807 delay; 13808 13809 Window 13810 root_window; 13811 13812 XGCValues 13813 context_values; 13814 13815 XResourceInfo 13816 resources; 13817 13818 XWindowAttributes 13819 window_attributes; 13820 13821 /* 13822 Determine target window. 13823 */ 13824 assert(image != (Image *) NULL); 13825 assert(image->signature == MagickSignature); 13826 if (image->debug != MagickFalse) 13827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13828 resources=(*resource_info); 13829 window_info.id=(Window) NULL; 13830 root_window=XRootWindow(display,XDefaultScreen(display)); 13831 if (LocaleCompare(resources.window_id,"root") == 0) 13832 window_info.id=root_window; 13833 else 13834 { 13835 if (isdigit((unsigned char) *resources.window_id) != 0) 13836 window_info.id=XWindowByID(display,root_window, 13837 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13838 if (window_info.id == (Window) NULL) 13839 window_info.id=XWindowByName(display,root_window,resources.window_id); 13840 } 13841 if (window_info.id == (Window) NULL) 13842 { 13843 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13844 resources.window_id); 13845 return(MagickFalse); 13846 } 13847 /* 13848 Determine window visual id. 13849 */ 13850 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13851 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13852 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13853 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13854 if (status != 0) 13855 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13856 XVisualIDFromVisual(window_attributes.visual)); 13857 if (visual_info == (XVisualInfo *) NULL) 13858 { 13859 /* 13860 Allocate standard colormap. 13861 */ 13862 map_info=XAllocStandardColormap(); 13863 if (map_info == (XStandardColormap *) NULL) 13864 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13865 image->filename); 13866 map_info->colormap=(Colormap) NULL; 13867 pixel.pixels=(unsigned long *) NULL; 13868 /* 13869 Initialize visual info. 13870 */ 13871 resources.map_type=(char *) NULL; 13872 resources.visual_type=visual_type; 13873 visual_info=XBestVisualInfo(display,map_info,&resources); 13874 if (visual_info == (XVisualInfo *) NULL) 13875 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13876 resources.visual_type); 13877 /* 13878 Initialize window info. 13879 */ 13880 window_info.ximage=(XImage *) NULL; 13881 window_info.matte_image=(XImage *) NULL; 13882 window_info.pixmap=(Pixmap) NULL; 13883 window_info.matte_pixmap=(Pixmap) NULL; 13884 } 13885 /* 13886 Free previous root colors. 13887 */ 13888 if (window_info.id == root_window) 13889 (void) XDestroyWindowColors(display,root_window); 13890 /* 13891 Initialize Standard Colormap. 13892 */ 13893 resources.colormap=SharedColormap; 13894 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13895 /* 13896 Graphic context superclass. 13897 */ 13898 context_values.background=pixel.background_color.pixel; 13899 context_values.foreground=pixel.foreground_color.pixel; 13900 pixel.annotate_context=XCreateGC(display,window_info.id, 13901 (size_t) (GCBackground | GCForeground),&context_values); 13902 if (pixel.annotate_context == (GC) NULL) 13903 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13904 image->filename); 13905 /* 13906 Initialize Image window attributes. 13907 */ 13908 window_info.name=AcquireString("\0"); 13909 window_info.icon_name=AcquireString("\0"); 13910 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13911 &resources,&window_info); 13912 /* 13913 Create the X image. 13914 */ 13915 window_info.width=(unsigned int) image->columns; 13916 window_info.height=(unsigned int) image->rows; 13917 if ((image->columns != window_info.width) || 13918 (image->rows != window_info.height)) 13919 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13920 image->filename); 13921 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13922 window_attributes.width,window_attributes.height); 13923 geometry_info.width=window_info.width; 13924 geometry_info.height=window_info.height; 13925 geometry_info.x=(ssize_t) window_info.x; 13926 geometry_info.y=(ssize_t) window_info.y; 13927 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13928 &geometry_info.width,&geometry_info.height); 13929 window_info.width=(unsigned int) geometry_info.width; 13930 window_info.height=(unsigned int) geometry_info.height; 13931 window_info.x=(int) geometry_info.x; 13932 window_info.y=(int) geometry_info.y; 13933 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13934 window_info.height,exception); 13935 if (status == MagickFalse) 13936 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13937 image->filename); 13938 window_info.x=0; 13939 window_info.y=0; 13940 if (image->debug != MagickFalse) 13941 { 13942 (void) LogMagickEvent(X11Event,GetMagickModule(), 13943 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13944 (double) image->columns,(double) image->rows); 13945 if (image->colors != 0) 13946 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13947 image->colors); 13948 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13949 } 13950 /* 13951 Adjust image dimensions as specified by backdrop or geometry options. 13952 */ 13953 width=(int) window_info.width; 13954 height=(int) window_info.height; 13955 if (resources.backdrop != MagickFalse) 13956 { 13957 /* 13958 Center image on window. 13959 */ 13960 window_info.x=(window_attributes.width/2)- 13961 (window_info.ximage->width/2); 13962 window_info.y=(window_attributes.height/2)- 13963 (window_info.ximage->height/2); 13964 width=window_attributes.width; 13965 height=window_attributes.height; 13966 } 13967 if ((resources.image_geometry != (char *) NULL) && 13968 (*resources.image_geometry != '\0')) 13969 { 13970 char 13971 default_geometry[MaxTextExtent]; 13972 13973 int 13974 flags, 13975 gravity; 13976 13977 XSizeHints 13978 *size_hints; 13979 13980 /* 13981 User specified geometry. 13982 */ 13983 size_hints=XAllocSizeHints(); 13984 if (size_hints == (XSizeHints *) NULL) 13985 ThrowXWindowFatalException(ResourceLimitFatalError, 13986 "MemoryAllocationFailed",image->filename); 13987 size_hints->flags=0L; 13988 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13989 width,height); 13990 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13991 default_geometry,window_info.border_width,size_hints,&window_info.x, 13992 &window_info.y,&width,&height,&gravity); 13993 if (flags & (XValue | YValue)) 13994 { 13995 width=window_attributes.width; 13996 height=window_attributes.height; 13997 } 13998 (void) XFree((void *) size_hints); 13999 } 14000 /* 14001 Create the X pixmap. 14002 */ 14003 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14004 (unsigned int) height,window_info.depth); 14005 if (window_info.pixmap == (Pixmap) NULL) 14006 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14007 image->filename); 14008 /* 14009 Display pixmap on the window. 14010 */ 14011 if (((unsigned int) width > window_info.width) || 14012 ((unsigned int) height > window_info.height)) 14013 (void) XFillRectangle(display,window_info.pixmap, 14014 window_info.annotate_context,0,0,(unsigned int) width, 14015 (unsigned int) height); 14016 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14017 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14018 window_info.width,(unsigned int) window_info.height); 14019 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14020 (void) XClearWindow(display,window_info.id); 14021 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14022 XDelay(display,delay == 0UL ? 10UL : delay); 14023 (void) XSync(display,MagickFalse); 14024 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14025} 14026 14027/* 14028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14029% % 14030% % 14031% % 14032+ X D i s p l a y I m a g e % 14033% % 14034% % 14035% % 14036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14037% 14038% XDisplayImage() displays an image via X11. A new image is created and 14039% returned if the user interactively transforms the displayed image. 14040% 14041% The format of the XDisplayImage method is: 14042% 14043% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14044% char **argv,int argc,Image **image,size_t *state, 14045% ExceptionInfo *exception) 14046% 14047% A description of each parameter follows: 14048% 14049% o nexus: Method XDisplayImage returns an image when the 14050% user chooses 'Open Image' from the command menu or picks a tile 14051% from the image directory. Otherwise a null image is returned. 14052% 14053% o display: Specifies a connection to an X server; returned from 14054% XOpenDisplay. 14055% 14056% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14057% 14058% o argv: Specifies the application's argument list. 14059% 14060% o argc: Specifies the number of arguments. 14061% 14062% o image: Specifies an address to an address of an Image structure; 14063% 14064% o exception: return any errors or warnings in this structure. 14065% 14066*/ 14067MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14068 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14069{ 14070#define MagnifySize 256 /* must be a power of 2 */ 14071#define MagickMenus 10 14072#define MagickTitle "Commands" 14073 14074 static const char 14075 *CommandMenu[] = 14076 { 14077 "File", 14078 "Edit", 14079 "View", 14080 "Transform", 14081 "Enhance", 14082 "Effects", 14083 "F/X", 14084 "Image Edit", 14085 "Miscellany", 14086 "Help", 14087 (char *) NULL 14088 }, 14089 *FileMenu[] = 14090 { 14091 "Open...", 14092 "Next", 14093 "Former", 14094 "Select...", 14095 "Save...", 14096 "Print...", 14097 "Delete...", 14098 "New...", 14099 "Visual Directory...", 14100 "Quit", 14101 (char *) NULL 14102 }, 14103 *EditMenu[] = 14104 { 14105 "Undo", 14106 "Redo", 14107 "Cut", 14108 "Copy", 14109 "Paste", 14110 (char *) NULL 14111 }, 14112 *ViewMenu[] = 14113 { 14114 "Half Size", 14115 "Original Size", 14116 "Double Size", 14117 "Resize...", 14118 "Apply", 14119 "Refresh", 14120 "Restore", 14121 (char *) NULL 14122 }, 14123 *TransformMenu[] = 14124 { 14125 "Crop", 14126 "Chop", 14127 "Flop", 14128 "Flip", 14129 "Rotate Right", 14130 "Rotate Left", 14131 "Rotate...", 14132 "Shear...", 14133 "Roll...", 14134 "Trim Edges", 14135 (char *) NULL 14136 }, 14137 *EnhanceMenu[] = 14138 { 14139 "Hue...", 14140 "Saturation...", 14141 "Brightness...", 14142 "Gamma...", 14143 "Spiff", 14144 "Dull", 14145 "Contrast Stretch...", 14146 "Sigmoidal Contrast...", 14147 "Normalize", 14148 "Equalize", 14149 "Negate", 14150 "Grayscale", 14151 "Map...", 14152 "Quantize...", 14153 (char *) NULL 14154 }, 14155 *EffectsMenu[] = 14156 { 14157 "Despeckle", 14158 "Emboss", 14159 "Reduce Noise", 14160 "Add Noise...", 14161 "Sharpen...", 14162 "Blur...", 14163 "Threshold...", 14164 "Edge Detect...", 14165 "Spread...", 14166 "Shade...", 14167 "Raise...", 14168 "Segment...", 14169 (char *) NULL 14170 }, 14171 *FXMenu[] = 14172 { 14173 "Solarize...", 14174 "Sepia Tone...", 14175 "Swirl...", 14176 "Implode...", 14177 "Vignette...", 14178 "Wave...", 14179 "Oil Paint...", 14180 "Charcoal Draw...", 14181 (char *) NULL 14182 }, 14183 *ImageEditMenu[] = 14184 { 14185 "Annotate...", 14186 "Draw...", 14187 "Color...", 14188 "Matte...", 14189 "Composite...", 14190 "Add Border...", 14191 "Add Frame...", 14192 "Comment...", 14193 "Launch...", 14194 "Region of Interest...", 14195 (char *) NULL 14196 }, 14197 *MiscellanyMenu[] = 14198 { 14199 "Image Info", 14200 "Zoom Image", 14201 "Show Preview...", 14202 "Show Histogram", 14203 "Show Matte", 14204 "Background...", 14205 "Slide Show...", 14206 "Preferences...", 14207 (char *) NULL 14208 }, 14209 *HelpMenu[] = 14210 { 14211 "Overview", 14212 "Browse Documentation", 14213 "About Display", 14214 (char *) NULL 14215 }, 14216 *ShortCutsMenu[] = 14217 { 14218 "Next", 14219 "Former", 14220 "Open...", 14221 "Save...", 14222 "Print...", 14223 "Undo", 14224 "Restore", 14225 "Image Info", 14226 "Quit", 14227 (char *) NULL 14228 }, 14229 *VirtualMenu[] = 14230 { 14231 "Image Info", 14232 "Print", 14233 "Next", 14234 "Quit", 14235 (char *) NULL 14236 }; 14237 14238 static const char 14239 **Menus[MagickMenus] = 14240 { 14241 FileMenu, 14242 EditMenu, 14243 ViewMenu, 14244 TransformMenu, 14245 EnhanceMenu, 14246 EffectsMenu, 14247 FXMenu, 14248 ImageEditMenu, 14249 MiscellanyMenu, 14250 HelpMenu 14251 }; 14252 14253 static CommandType 14254 CommandMenus[] = 14255 { 14256 NullCommand, 14257 NullCommand, 14258 NullCommand, 14259 NullCommand, 14260 NullCommand, 14261 NullCommand, 14262 NullCommand, 14263 NullCommand, 14264 NullCommand, 14265 NullCommand, 14266 }, 14267 FileCommands[] = 14268 { 14269 OpenCommand, 14270 NextCommand, 14271 FormerCommand, 14272 SelectCommand, 14273 SaveCommand, 14274 PrintCommand, 14275 DeleteCommand, 14276 NewCommand, 14277 VisualDirectoryCommand, 14278 QuitCommand 14279 }, 14280 EditCommands[] = 14281 { 14282 UndoCommand, 14283 RedoCommand, 14284 CutCommand, 14285 CopyCommand, 14286 PasteCommand 14287 }, 14288 ViewCommands[] = 14289 { 14290 HalfSizeCommand, 14291 OriginalSizeCommand, 14292 DoubleSizeCommand, 14293 ResizeCommand, 14294 ApplyCommand, 14295 RefreshCommand, 14296 RestoreCommand 14297 }, 14298 TransformCommands[] = 14299 { 14300 CropCommand, 14301 ChopCommand, 14302 FlopCommand, 14303 FlipCommand, 14304 RotateRightCommand, 14305 RotateLeftCommand, 14306 RotateCommand, 14307 ShearCommand, 14308 RollCommand, 14309 TrimCommand 14310 }, 14311 EnhanceCommands[] = 14312 { 14313 HueCommand, 14314 SaturationCommand, 14315 BrightnessCommand, 14316 GammaCommand, 14317 SpiffCommand, 14318 DullCommand, 14319 ContrastStretchCommand, 14320 SigmoidalContrastCommand, 14321 NormalizeCommand, 14322 EqualizeCommand, 14323 NegateCommand, 14324 GrayscaleCommand, 14325 MapCommand, 14326 QuantizeCommand 14327 }, 14328 EffectsCommands[] = 14329 { 14330 DespeckleCommand, 14331 EmbossCommand, 14332 ReduceNoiseCommand, 14333 AddNoiseCommand, 14334 SharpenCommand, 14335 BlurCommand, 14336 ThresholdCommand, 14337 EdgeDetectCommand, 14338 SpreadCommand, 14339 ShadeCommand, 14340 RaiseCommand, 14341 SegmentCommand 14342 }, 14343 FXCommands[] = 14344 { 14345 SolarizeCommand, 14346 SepiaToneCommand, 14347 SwirlCommand, 14348 ImplodeCommand, 14349 VignetteCommand, 14350 WaveCommand, 14351 OilPaintCommand, 14352 CharcoalDrawCommand 14353 }, 14354 ImageEditCommands[] = 14355 { 14356 AnnotateCommand, 14357 DrawCommand, 14358 ColorCommand, 14359 MatteCommand, 14360 CompositeCommand, 14361 AddBorderCommand, 14362 AddFrameCommand, 14363 CommentCommand, 14364 LaunchCommand, 14365 RegionofInterestCommand 14366 }, 14367 MiscellanyCommands[] = 14368 { 14369 InfoCommand, 14370 ZoomCommand, 14371 ShowPreviewCommand, 14372 ShowHistogramCommand, 14373 ShowMatteCommand, 14374 BackgroundCommand, 14375 SlideShowCommand, 14376 PreferencesCommand 14377 }, 14378 HelpCommands[] = 14379 { 14380 HelpCommand, 14381 BrowseDocumentationCommand, 14382 VersionCommand 14383 }, 14384 ShortCutsCommands[] = 14385 { 14386 NextCommand, 14387 FormerCommand, 14388 OpenCommand, 14389 SaveCommand, 14390 PrintCommand, 14391 UndoCommand, 14392 RestoreCommand, 14393 InfoCommand, 14394 QuitCommand 14395 }, 14396 VirtualCommands[] = 14397 { 14398 InfoCommand, 14399 PrintCommand, 14400 NextCommand, 14401 QuitCommand 14402 }; 14403 14404 static CommandType 14405 *Commands[MagickMenus] = 14406 { 14407 FileCommands, 14408 EditCommands, 14409 ViewCommands, 14410 TransformCommands, 14411 EnhanceCommands, 14412 EffectsCommands, 14413 FXCommands, 14414 ImageEditCommands, 14415 MiscellanyCommands, 14416 HelpCommands 14417 }; 14418 14419 char 14420 command[MaxTextExtent], 14421 *directory, 14422 geometry[MaxTextExtent], 14423 resource_name[MaxTextExtent]; 14424 14425 CommandType 14426 command_type; 14427 14428 Image 14429 *display_image, 14430 *nexus; 14431 14432 int 14433 entry, 14434 id; 14435 14436 KeySym 14437 key_symbol; 14438 14439 MagickStatusType 14440 context_mask, 14441 status; 14442 14443 RectangleInfo 14444 geometry_info; 14445 14446 register int 14447 i; 14448 14449 static char 14450 working_directory[MaxTextExtent]; 14451 14452 static XPoint 14453 vid_info; 14454 14455 static XWindowInfo 14456 *magick_windows[MaxXWindows]; 14457 14458 static unsigned int 14459 number_windows; 14460 14461 struct stat 14462 attributes; 14463 14464 time_t 14465 timer, 14466 timestamp, 14467 update_time; 14468 14469 unsigned int 14470 height, 14471 width; 14472 14473 size_t 14474 delay; 14475 14476 WarningHandler 14477 warning_handler; 14478 14479 Window 14480 root_window; 14481 14482 XClassHint 14483 *class_hints; 14484 14485 XEvent 14486 event; 14487 14488 XFontStruct 14489 *font_info; 14490 14491 XGCValues 14492 context_values; 14493 14494 XPixelInfo 14495 *icon_pixel, 14496 *pixel; 14497 14498 XResourceInfo 14499 *icon_resources; 14500 14501 XStandardColormap 14502 *icon_map, 14503 *map_info; 14504 14505 XVisualInfo 14506 *icon_visual, 14507 *visual_info; 14508 14509 XWindowChanges 14510 window_changes; 14511 14512 XWindows 14513 *windows; 14514 14515 XWMHints 14516 *manager_hints; 14517 14518 assert(image != (Image **) NULL); 14519 assert((*image)->signature == MagickSignature); 14520 if ((*image)->debug != MagickFalse) 14521 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14522 display_image=(*image); 14523 warning_handler=(WarningHandler) NULL; 14524 windows=XSetWindows((XWindows *) ~0); 14525 if (windows != (XWindows *) NULL) 14526 { 14527 int 14528 status; 14529 14530 status=chdir(working_directory); 14531 if (status == -1) 14532 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14533 "UnableToOpenFile","%s",working_directory); 14534 warning_handler=resource_info->display_warnings ? 14535 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14536 warning_handler=resource_info->display_warnings ? 14537 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14538 } 14539 else 14540 { 14541 /* 14542 Allocate windows structure. 14543 */ 14544 resource_info->colors=display_image->colors; 14545 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14546 if (windows == (XWindows *) NULL) 14547 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14548 (*image)->filename); 14549 /* 14550 Initialize window id's. 14551 */ 14552 number_windows=0; 14553 magick_windows[number_windows++]=(&windows->icon); 14554 magick_windows[number_windows++]=(&windows->backdrop); 14555 magick_windows[number_windows++]=(&windows->image); 14556 magick_windows[number_windows++]=(&windows->info); 14557 magick_windows[number_windows++]=(&windows->command); 14558 magick_windows[number_windows++]=(&windows->widget); 14559 magick_windows[number_windows++]=(&windows->popup); 14560 magick_windows[number_windows++]=(&windows->magnify); 14561 magick_windows[number_windows++]=(&windows->pan); 14562 for (i=0; i < (int) number_windows; i++) 14563 magick_windows[i]->id=(Window) NULL; 14564 vid_info.x=0; 14565 vid_info.y=0; 14566 } 14567 /* 14568 Initialize font info. 14569 */ 14570 if (windows->font_info != (XFontStruct *) NULL) 14571 (void) XFreeFont(display,windows->font_info); 14572 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14573 if (windows->font_info == (XFontStruct *) NULL) 14574 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14575 resource_info->font); 14576 /* 14577 Initialize Standard Colormap. 14578 */ 14579 map_info=windows->map_info; 14580 icon_map=windows->icon_map; 14581 visual_info=windows->visual_info; 14582 icon_visual=windows->icon_visual; 14583 pixel=windows->pixel_info; 14584 icon_pixel=windows->icon_pixel; 14585 font_info=windows->font_info; 14586 icon_resources=windows->icon_resources; 14587 class_hints=windows->class_hints; 14588 manager_hints=windows->manager_hints; 14589 root_window=XRootWindow(display,visual_info->screen); 14590 nexus=NewImageList(); 14591 if (display_image->debug != MagickFalse) 14592 { 14593 (void) LogMagickEvent(X11Event,GetMagickModule(), 14594 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14595 (double) display_image->scene,(double) display_image->columns, 14596 (double) display_image->rows); 14597 if (display_image->colors != 0) 14598 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14599 display_image->colors); 14600 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14601 display_image->magick); 14602 } 14603 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14604 map_info,pixel); 14605 display_image->taint=MagickFalse; 14606 /* 14607 Initialize graphic context. 14608 */ 14609 windows->context.id=(Window) NULL; 14610 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14611 resource_info,&windows->context); 14612 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14613 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14614 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14615 manager_hints->flags=InputHint | StateHint; 14616 manager_hints->input=MagickFalse; 14617 manager_hints->initial_state=WithdrawnState; 14618 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14619 &windows->context); 14620 if (display_image->debug != MagickFalse) 14621 (void) LogMagickEvent(X11Event,GetMagickModule(), 14622 "Window id: 0x%lx (context)",windows->context.id); 14623 context_values.background=pixel->background_color.pixel; 14624 context_values.font=font_info->fid; 14625 context_values.foreground=pixel->foreground_color.pixel; 14626 context_values.graphics_exposures=MagickFalse; 14627 context_mask=(MagickStatusType) 14628 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14629 if (pixel->annotate_context != (GC) NULL) 14630 (void) XFreeGC(display,pixel->annotate_context); 14631 pixel->annotate_context=XCreateGC(display,windows->context.id, 14632 context_mask,&context_values); 14633 if (pixel->annotate_context == (GC) NULL) 14634 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14635 display_image->filename); 14636 context_values.background=pixel->depth_color.pixel; 14637 if (pixel->widget_context != (GC) NULL) 14638 (void) XFreeGC(display,pixel->widget_context); 14639 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14640 &context_values); 14641 if (pixel->widget_context == (GC) NULL) 14642 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14643 display_image->filename); 14644 context_values.background=pixel->foreground_color.pixel; 14645 context_values.foreground=pixel->background_color.pixel; 14646 context_values.plane_mask=context_values.background ^ 14647 context_values.foreground; 14648 if (pixel->highlight_context != (GC) NULL) 14649 (void) XFreeGC(display,pixel->highlight_context); 14650 pixel->highlight_context=XCreateGC(display,windows->context.id, 14651 (size_t) (context_mask | GCPlaneMask),&context_values); 14652 if (pixel->highlight_context == (GC) NULL) 14653 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14654 display_image->filename); 14655 (void) XDestroyWindow(display,windows->context.id); 14656 /* 14657 Initialize icon window. 14658 */ 14659 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14660 icon_resources,&windows->icon); 14661 windows->icon.geometry=resource_info->icon_geometry; 14662 XBestIconSize(display,&windows->icon,display_image); 14663 windows->icon.attributes.colormap=XDefaultColormap(display, 14664 icon_visual->screen); 14665 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14666 manager_hints->flags=InputHint | StateHint; 14667 manager_hints->input=MagickFalse; 14668 manager_hints->initial_state=IconicState; 14669 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14670 &windows->icon); 14671 if (display_image->debug != MagickFalse) 14672 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14673 windows->icon.id); 14674 /* 14675 Initialize graphic context for icon window. 14676 */ 14677 if (icon_pixel->annotate_context != (GC) NULL) 14678 (void) XFreeGC(display,icon_pixel->annotate_context); 14679 context_values.background=icon_pixel->background_color.pixel; 14680 context_values.foreground=icon_pixel->foreground_color.pixel; 14681 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14682 (size_t) (GCBackground | GCForeground),&context_values); 14683 if (icon_pixel->annotate_context == (GC) NULL) 14684 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14685 display_image->filename); 14686 windows->icon.annotate_context=icon_pixel->annotate_context; 14687 /* 14688 Initialize Image window. 14689 */ 14690 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14691 &windows->image); 14692 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14693 if (resource_info->use_shared_memory == MagickFalse) 14694 windows->image.shared_memory=MagickFalse; 14695 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14696 { 14697 char 14698 *title; 14699 14700 title=InterpretImageProperties(resource_info->image_info,display_image, 14701 resource_info->title,exception); 14702 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14703 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14704 title=DestroyString(title); 14705 } 14706 else 14707 { 14708 char 14709 filename[MaxTextExtent]; 14710 14711 /* 14712 Window name is the base of the filename. 14713 */ 14714 GetPathComponent(display_image->magick_filename,TailPath,filename); 14715 if (display_image->scene == 0) 14716 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14717 "%s: %s",MagickPackageName,filename); 14718 else 14719 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14720 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14721 (double) display_image->scene,(double) GetImageListLength( 14722 display_image)); 14723 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14724 } 14725 if (resource_info->immutable) 14726 windows->image.immutable=MagickTrue; 14727 windows->image.use_pixmap=resource_info->use_pixmap; 14728 windows->image.geometry=resource_info->image_geometry; 14729 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14730 XDisplayWidth(display,visual_info->screen), 14731 XDisplayHeight(display,visual_info->screen)); 14732 geometry_info.width=display_image->columns; 14733 geometry_info.height=display_image->rows; 14734 geometry_info.x=0; 14735 geometry_info.y=0; 14736 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14737 &geometry_info.width,&geometry_info.height); 14738 windows->image.width=(unsigned int) geometry_info.width; 14739 windows->image.height=(unsigned int) geometry_info.height; 14740 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14741 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14742 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14743 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14744 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14745 resource_info,&windows->backdrop); 14746 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14747 { 14748 /* 14749 Initialize backdrop window. 14750 */ 14751 windows->backdrop.x=0; 14752 windows->backdrop.y=0; 14753 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14754 windows->backdrop.flags=(size_t) (USSize | USPosition); 14755 windows->backdrop.width=(unsigned int) 14756 XDisplayWidth(display,visual_info->screen); 14757 windows->backdrop.height=(unsigned int) 14758 XDisplayHeight(display,visual_info->screen); 14759 windows->backdrop.border_width=0; 14760 windows->backdrop.immutable=MagickTrue; 14761 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14762 ButtonReleaseMask; 14763 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14764 StructureNotifyMask; 14765 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14766 manager_hints->icon_window=windows->icon.id; 14767 manager_hints->input=MagickTrue; 14768 manager_hints->initial_state=resource_info->iconic ? IconicState : 14769 NormalState; 14770 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14771 &windows->backdrop); 14772 if (display_image->debug != MagickFalse) 14773 (void) LogMagickEvent(X11Event,GetMagickModule(), 14774 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14775 (void) XMapWindow(display,windows->backdrop.id); 14776 (void) XClearWindow(display,windows->backdrop.id); 14777 if (windows->image.id != (Window) NULL) 14778 { 14779 (void) XDestroyWindow(display,windows->image.id); 14780 windows->image.id=(Window) NULL; 14781 } 14782 /* 14783 Position image in the center the backdrop. 14784 */ 14785 windows->image.flags|=USPosition; 14786 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14787 (windows->image.width/2); 14788 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14789 (windows->image.height/2); 14790 } 14791 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14792 manager_hints->icon_window=windows->icon.id; 14793 manager_hints->input=MagickTrue; 14794 manager_hints->initial_state=resource_info->iconic ? IconicState : 14795 NormalState; 14796 if (windows->group_leader.id != (Window) NULL) 14797 { 14798 /* 14799 Follow the leader. 14800 */ 14801 manager_hints->flags|=WindowGroupHint; 14802 manager_hints->window_group=windows->group_leader.id; 14803 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14804 if (display_image->debug != MagickFalse) 14805 (void) LogMagickEvent(X11Event,GetMagickModule(), 14806 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14807 } 14808 XMakeWindow(display, 14809 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14810 argv,argc,class_hints,manager_hints,&windows->image); 14811 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14812 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14813 if (windows->group_leader.id != (Window) NULL) 14814 (void) XSetTransientForHint(display,windows->image.id, 14815 windows->group_leader.id); 14816 if (display_image->debug != MagickFalse) 14817 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14818 windows->image.id); 14819 /* 14820 Initialize Info widget. 14821 */ 14822 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14823 &windows->info); 14824 (void) CloneString(&windows->info.name,"Info"); 14825 (void) CloneString(&windows->info.icon_name,"Info"); 14826 windows->info.border_width=1; 14827 windows->info.x=2; 14828 windows->info.y=2; 14829 windows->info.flags|=PPosition; 14830 windows->info.attributes.win_gravity=UnmapGravity; 14831 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14832 StructureNotifyMask; 14833 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14834 manager_hints->input=MagickFalse; 14835 manager_hints->initial_state=NormalState; 14836 manager_hints->window_group=windows->image.id; 14837 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14838 &windows->info); 14839 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14840 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14841 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14842 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14843 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14844 if (windows->image.mapped != MagickFalse) 14845 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14846 if (display_image->debug != MagickFalse) 14847 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14848 windows->info.id); 14849 /* 14850 Initialize Command widget. 14851 */ 14852 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14853 resource_info,&windows->command); 14854 windows->command.data=MagickMenus; 14855 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14856 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14857 resource_info->client_name); 14858 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14859 resource_name,"geometry",(char *) NULL); 14860 (void) CloneString(&windows->command.name,MagickTitle); 14861 windows->command.border_width=0; 14862 windows->command.flags|=PPosition; 14863 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14864 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14865 OwnerGrabButtonMask | StructureNotifyMask; 14866 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14867 manager_hints->input=MagickTrue; 14868 manager_hints->initial_state=NormalState; 14869 manager_hints->window_group=windows->image.id; 14870 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14871 &windows->command); 14872 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14873 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14874 HighlightHeight); 14875 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14876 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14877 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14878 if (windows->command.mapped != MagickFalse) 14879 (void) XMapRaised(display,windows->command.id); 14880 if (display_image->debug != MagickFalse) 14881 (void) LogMagickEvent(X11Event,GetMagickModule(), 14882 "Window id: 0x%lx (command)",windows->command.id); 14883 /* 14884 Initialize Widget window. 14885 */ 14886 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14887 resource_info,&windows->widget); 14888 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14889 resource_info->client_name); 14890 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14891 resource_name,"geometry",(char *) NULL); 14892 windows->widget.border_width=0; 14893 windows->widget.flags|=PPosition; 14894 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14895 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14896 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14897 StructureNotifyMask; 14898 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14899 manager_hints->input=MagickTrue; 14900 manager_hints->initial_state=NormalState; 14901 manager_hints->window_group=windows->image.id; 14902 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14903 &windows->widget); 14904 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14905 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14906 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14907 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14908 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14909 if (display_image->debug != MagickFalse) 14910 (void) LogMagickEvent(X11Event,GetMagickModule(), 14911 "Window id: 0x%lx (widget)",windows->widget.id); 14912 /* 14913 Initialize popup window. 14914 */ 14915 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14916 resource_info,&windows->popup); 14917 windows->popup.border_width=0; 14918 windows->popup.flags|=PPosition; 14919 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14920 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14921 KeyReleaseMask | LeaveWindowMask | 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->popup); 14928 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14929 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14930 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14931 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14932 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14933 if (display_image->debug != MagickFalse) 14934 (void) LogMagickEvent(X11Event,GetMagickModule(), 14935 "Window id: 0x%lx (pop up)",windows->popup.id); 14936 /* 14937 Initialize Magnify window and cursor. 14938 */ 14939 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14940 resource_info,&windows->magnify); 14941 if (resource_info->use_shared_memory == MagickFalse) 14942 windows->magnify.shared_memory=MagickFalse; 14943 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14944 resource_info->client_name); 14945 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14946 resource_name,"geometry",(char *) NULL); 14947 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14948 resource_info->magnify); 14949 if (windows->magnify.cursor != (Cursor) NULL) 14950 (void) XFreeCursor(display,windows->magnify.cursor); 14951 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14952 map_info->colormap,resource_info->background_color, 14953 resource_info->foreground_color); 14954 if (windows->magnify.cursor == (Cursor) NULL) 14955 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14956 display_image->filename); 14957 windows->magnify.width=MagnifySize; 14958 windows->magnify.height=MagnifySize; 14959 windows->magnify.flags|=PPosition; 14960 windows->magnify.min_width=MagnifySize; 14961 windows->magnify.min_height=MagnifySize; 14962 windows->magnify.width_inc=MagnifySize; 14963 windows->magnify.height_inc=MagnifySize; 14964 windows->magnify.data=resource_info->magnify; 14965 windows->magnify.attributes.cursor=windows->magnify.cursor; 14966 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14967 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14968 StructureNotifyMask; 14969 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14970 manager_hints->input=MagickTrue; 14971 manager_hints->initial_state=NormalState; 14972 manager_hints->window_group=windows->image.id; 14973 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14974 &windows->magnify); 14975 if (display_image->debug != MagickFalse) 14976 (void) LogMagickEvent(X11Event,GetMagickModule(), 14977 "Window id: 0x%lx (magnify)",windows->magnify.id); 14978 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14979 /* 14980 Initialize panning window. 14981 */ 14982 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14983 resource_info,&windows->pan); 14984 (void) CloneString(&windows->pan.name,"Pan Icon"); 14985 windows->pan.width=windows->icon.width; 14986 windows->pan.height=windows->icon.height; 14987 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14988 resource_info->client_name); 14989 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14990 resource_name,"geometry",(char *) NULL); 14991 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14992 &windows->pan.width,&windows->pan.height); 14993 windows->pan.flags|=PPosition; 14994 windows->pan.immutable=MagickTrue; 14995 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14996 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14997 StructureNotifyMask; 14998 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14999 manager_hints->input=MagickFalse; 15000 manager_hints->initial_state=NormalState; 15001 manager_hints->window_group=windows->image.id; 15002 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15003 &windows->pan); 15004 if (display_image->debug != MagickFalse) 15005 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15006 windows->pan.id); 15007 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15008 if (windows->info.mapped != MagickFalse) 15009 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15010 if ((windows->image.mapped == MagickFalse) || 15011 (windows->backdrop.id != (Window) NULL)) 15012 (void) XMapWindow(display,windows->image.id); 15013 /* 15014 Set our progress monitor and warning handlers. 15015 */ 15016 if (warning_handler == (WarningHandler) NULL) 15017 { 15018 warning_handler=resource_info->display_warnings ? 15019 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15020 warning_handler=resource_info->display_warnings ? 15021 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15022 } 15023 /* 15024 Initialize Image and Magnify X images. 15025 */ 15026 windows->image.x=0; 15027 windows->image.y=0; 15028 windows->magnify.shape=MagickFalse; 15029 width=(unsigned int) display_image->columns; 15030 height=(unsigned int) display_image->rows; 15031 if ((display_image->columns != width) || (display_image->rows != height)) 15032 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15033 display_image->filename); 15034 status=XMakeImage(display,resource_info,&windows->image,display_image, 15035 width,height,exception); 15036 if (status == MagickFalse) 15037 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15038 display_image->filename); 15039 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15040 windows->magnify.width,windows->magnify.height,exception); 15041 if (status == MagickFalse) 15042 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15043 display_image->filename); 15044 if (windows->magnify.mapped != MagickFalse) 15045 (void) XMapRaised(display,windows->magnify.id); 15046 if (windows->pan.mapped != MagickFalse) 15047 (void) XMapRaised(display,windows->pan.id); 15048 windows->image.window_changes.width=(int) display_image->columns; 15049 windows->image.window_changes.height=(int) display_image->rows; 15050 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15051 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15052 (void) XSync(display,MagickFalse); 15053 /* 15054 Respond to events. 15055 */ 15056 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15057 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15058 update_time=0; 15059 if (resource_info->update != MagickFalse) 15060 { 15061 MagickBooleanType 15062 status; 15063 15064 /* 15065 Determine when file data was last modified. 15066 */ 15067 status=GetPathAttributes(display_image->filename,&attributes); 15068 if (status != MagickFalse) 15069 update_time=attributes.st_mtime; 15070 } 15071 *state&=(~FormerImageState); 15072 *state&=(~MontageImageState); 15073 *state&=(~NextImageState); 15074 do 15075 { 15076 /* 15077 Handle a window event. 15078 */ 15079 if (windows->image.mapped != MagickFalse) 15080 if ((display_image->delay != 0) || (resource_info->update != 0)) 15081 { 15082 if (timer < time((time_t *) NULL)) 15083 { 15084 if (resource_info->update == MagickFalse) 15085 *state|=NextImageState | ExitState; 15086 else 15087 { 15088 MagickBooleanType 15089 status; 15090 15091 /* 15092 Determine if image file was modified. 15093 */ 15094 status=GetPathAttributes(display_image->filename,&attributes); 15095 if (status != MagickFalse) 15096 if (update_time != attributes.st_mtime) 15097 { 15098 /* 15099 Redisplay image. 15100 */ 15101 (void) FormatLocaleString( 15102 resource_info->image_info->filename,MaxTextExtent, 15103 "%s:%s",display_image->magick, 15104 display_image->filename); 15105 nexus=ReadImage(resource_info->image_info,exception); 15106 if (nexus != (Image *) NULL) 15107 { 15108 nexus=DestroyImage(nexus); 15109 *state|=NextImageState | ExitState; 15110 } 15111 } 15112 delay=display_image->delay/MagickMax( 15113 display_image->ticks_per_second,1L); 15114 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15115 } 15116 } 15117 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15118 { 15119 /* 15120 Do not block if delay > 0. 15121 */ 15122 XDelay(display,SuspendTime << 2); 15123 continue; 15124 } 15125 } 15126 timestamp=time((time_t *) NULL); 15127 (void) XNextEvent(display,&event); 15128 if (windows->image.stasis == MagickFalse) 15129 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15130 MagickTrue : MagickFalse; 15131 if (windows->magnify.stasis == MagickFalse) 15132 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15133 MagickTrue : MagickFalse; 15134 if (event.xany.window == windows->command.id) 15135 { 15136 /* 15137 Select a command from the Command widget. 15138 */ 15139 id=XCommandWidget(display,windows,CommandMenu,&event); 15140 if (id < 0) 15141 continue; 15142 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15143 command_type=CommandMenus[id]; 15144 if (id < MagickMenus) 15145 { 15146 /* 15147 Select a command from a pop-up menu. 15148 */ 15149 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15150 command); 15151 if (entry < 0) 15152 continue; 15153 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15154 command_type=Commands[id][entry]; 15155 } 15156 if (command_type != NullCommand) 15157 nexus=XMagickCommand(display,resource_info,windows,command_type, 15158 &display_image,exception); 15159 continue; 15160 } 15161 switch (event.type) 15162 { 15163 case ButtonPress: 15164 { 15165 if (display_image->debug != MagickFalse) 15166 (void) LogMagickEvent(X11Event,GetMagickModule(), 15167 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15168 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15169 if ((event.xbutton.button == Button3) && 15170 (event.xbutton.state & Mod1Mask)) 15171 { 15172 /* 15173 Convert Alt-Button3 to Button2. 15174 */ 15175 event.xbutton.button=Button2; 15176 event.xbutton.state&=(~Mod1Mask); 15177 } 15178 if (event.xbutton.window == windows->backdrop.id) 15179 { 15180 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15181 event.xbutton.time); 15182 break; 15183 } 15184 if (event.xbutton.window == windows->image.id) 15185 { 15186 switch (event.xbutton.button) 15187 { 15188 case Button1: 15189 { 15190 if (resource_info->immutable) 15191 { 15192 /* 15193 Select a command from the Virtual menu. 15194 */ 15195 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15196 command); 15197 if (entry >= 0) 15198 nexus=XMagickCommand(display,resource_info,windows, 15199 VirtualCommands[entry],&display_image,exception); 15200 break; 15201 } 15202 /* 15203 Map/unmap Command widget. 15204 */ 15205 if (windows->command.mapped != MagickFalse) 15206 (void) XWithdrawWindow(display,windows->command.id, 15207 windows->command.screen); 15208 else 15209 { 15210 (void) XCommandWidget(display,windows,CommandMenu, 15211 (XEvent *) NULL); 15212 (void) XMapRaised(display,windows->command.id); 15213 } 15214 break; 15215 } 15216 case Button2: 15217 { 15218 /* 15219 User pressed the image magnify button. 15220 */ 15221 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15222 &display_image,exception); 15223 XMagnifyImage(display,windows,&event); 15224 break; 15225 } 15226 case Button3: 15227 { 15228 if (resource_info->immutable) 15229 { 15230 /* 15231 Select a command from the Virtual menu. 15232 */ 15233 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15234 command); 15235 if (entry >= 0) 15236 nexus=XMagickCommand(display,resource_info,windows, 15237 VirtualCommands[entry],&display_image,exception); 15238 break; 15239 } 15240 if (display_image->montage != (char *) NULL) 15241 { 15242 /* 15243 Open or delete a tile from a visual image directory. 15244 */ 15245 nexus=XTileImage(display,resource_info,windows, 15246 display_image,&event,exception); 15247 if (nexus != (Image *) NULL) 15248 *state|=MontageImageState | NextImageState | ExitState; 15249 vid_info.x=(short int) windows->image.x; 15250 vid_info.y=(short int) windows->image.y; 15251 break; 15252 } 15253 /* 15254 Select a command from the Short Cuts menu. 15255 */ 15256 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15257 command); 15258 if (entry >= 0) 15259 nexus=XMagickCommand(display,resource_info,windows, 15260 ShortCutsCommands[entry],&display_image,exception); 15261 break; 15262 } 15263 case Button4: 15264 { 15265 /* 15266 Wheel up. 15267 */ 15268 XTranslateImage(display,windows,*image,XK_Up); 15269 break; 15270 } 15271 case Button5: 15272 { 15273 /* 15274 Wheel down. 15275 */ 15276 XTranslateImage(display,windows,*image,XK_Down); 15277 break; 15278 } 15279 default: 15280 break; 15281 } 15282 break; 15283 } 15284 if (event.xbutton.window == windows->magnify.id) 15285 { 15286 int 15287 factor; 15288 15289 static const char 15290 *MagnifyMenu[] = 15291 { 15292 "2", 15293 "4", 15294 "5", 15295 "6", 15296 "7", 15297 "8", 15298 "9", 15299 "3", 15300 (char *) NULL, 15301 }; 15302 15303 static KeySym 15304 MagnifyCommands[] = 15305 { 15306 XK_2, 15307 XK_4, 15308 XK_5, 15309 XK_6, 15310 XK_7, 15311 XK_8, 15312 XK_9, 15313 XK_3 15314 }; 15315 15316 /* 15317 Select a magnify factor from the pop-up menu. 15318 */ 15319 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15320 if (factor >= 0) 15321 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15322 break; 15323 } 15324 if (event.xbutton.window == windows->pan.id) 15325 { 15326 switch (event.xbutton.button) 15327 { 15328 case Button4: 15329 { 15330 /* 15331 Wheel up. 15332 */ 15333 XTranslateImage(display,windows,*image,XK_Up); 15334 break; 15335 } 15336 case Button5: 15337 { 15338 /* 15339 Wheel down. 15340 */ 15341 XTranslateImage(display,windows,*image,XK_Down); 15342 break; 15343 } 15344 default: 15345 { 15346 XPanImage(display,windows,&event); 15347 break; 15348 } 15349 } 15350 break; 15351 } 15352 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15353 1L); 15354 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15355 break; 15356 } 15357 case ButtonRelease: 15358 { 15359 if (display_image->debug != MagickFalse) 15360 (void) LogMagickEvent(X11Event,GetMagickModule(), 15361 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15362 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15363 break; 15364 } 15365 case ClientMessage: 15366 { 15367 if (display_image->debug != MagickFalse) 15368 (void) LogMagickEvent(X11Event,GetMagickModule(), 15369 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15370 event.xclient.message_type,event.xclient.format,(unsigned long) 15371 event.xclient.data.l[0]); 15372 if (event.xclient.message_type == windows->im_protocols) 15373 { 15374 if (*event.xclient.data.l == (long) windows->im_update_widget) 15375 { 15376 (void) CloneString(&windows->command.name,MagickTitle); 15377 windows->command.data=MagickMenus; 15378 (void) XCommandWidget(display,windows,CommandMenu, 15379 (XEvent *) NULL); 15380 break; 15381 } 15382 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15383 { 15384 /* 15385 Update graphic context and window colormap. 15386 */ 15387 for (i=0; i < (int) number_windows; i++) 15388 { 15389 if (magick_windows[i]->id == windows->icon.id) 15390 continue; 15391 context_values.background=pixel->background_color.pixel; 15392 context_values.foreground=pixel->foreground_color.pixel; 15393 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15394 context_mask,&context_values); 15395 (void) XChangeGC(display,magick_windows[i]->widget_context, 15396 context_mask,&context_values); 15397 context_values.background=pixel->foreground_color.pixel; 15398 context_values.foreground=pixel->background_color.pixel; 15399 context_values.plane_mask=context_values.background ^ 15400 context_values.foreground; 15401 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15402 (size_t) (context_mask | GCPlaneMask), 15403 &context_values); 15404 magick_windows[i]->attributes.background_pixel= 15405 pixel->background_color.pixel; 15406 magick_windows[i]->attributes.border_pixel= 15407 pixel->border_color.pixel; 15408 magick_windows[i]->attributes.colormap=map_info->colormap; 15409 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15410 (unsigned long) magick_windows[i]->mask, 15411 &magick_windows[i]->attributes); 15412 } 15413 if (windows->pan.mapped != MagickFalse) 15414 { 15415 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15416 windows->pan.pixmap); 15417 (void) XClearWindow(display,windows->pan.id); 15418 XDrawPanRectangle(display,windows); 15419 } 15420 if (windows->backdrop.id != (Window) NULL) 15421 (void) XInstallColormap(display,map_info->colormap); 15422 break; 15423 } 15424 if (*event.xclient.data.l == (long) windows->im_former_image) 15425 { 15426 *state|=FormerImageState | ExitState; 15427 break; 15428 } 15429 if (*event.xclient.data.l == (long) windows->im_next_image) 15430 { 15431 *state|=NextImageState | ExitState; 15432 break; 15433 } 15434 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15435 { 15436 *state|=RetainColorsState; 15437 break; 15438 } 15439 if (*event.xclient.data.l == (long) windows->im_exit) 15440 { 15441 *state|=ExitState; 15442 break; 15443 } 15444 break; 15445 } 15446 if (event.xclient.message_type == windows->dnd_protocols) 15447 { 15448 Atom 15449 selection, 15450 type; 15451 15452 int 15453 format, 15454 status; 15455 15456 unsigned char 15457 *data; 15458 15459 unsigned long 15460 after, 15461 length; 15462 15463 /* 15464 Display image named by the Drag-and-Drop selection. 15465 */ 15466 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15467 break; 15468 selection=XInternAtom(display,"DndSelection",MagickFalse); 15469 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15470 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15471 &length,&after,&data); 15472 if ((status != Success) || (length == 0)) 15473 break; 15474 if (*event.xclient.data.l == 2) 15475 { 15476 /* 15477 Offix DND. 15478 */ 15479 (void) CopyMagickString(resource_info->image_info->filename, 15480 (char *) data,MaxTextExtent); 15481 } 15482 else 15483 { 15484 /* 15485 XDND. 15486 */ 15487 if (strncmp((char *) data, "file:", 5) != 0) 15488 { 15489 (void) XFree((void *) data); 15490 break; 15491 } 15492 (void) CopyMagickString(resource_info->image_info->filename, 15493 ((char *) data)+5,MaxTextExtent); 15494 } 15495 nexus=ReadImage(resource_info->image_info,exception); 15496 CatchException(exception); 15497 if (nexus != (Image *) NULL) 15498 *state|=NextImageState | ExitState; 15499 (void) XFree((void *) data); 15500 break; 15501 } 15502 /* 15503 If client window delete message, exit. 15504 */ 15505 if (event.xclient.message_type != windows->wm_protocols) 15506 break; 15507 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15508 break; 15509 (void) XWithdrawWindow(display,event.xclient.window, 15510 visual_info->screen); 15511 if (event.xclient.window == windows->image.id) 15512 { 15513 *state|=ExitState; 15514 break; 15515 } 15516 if (event.xclient.window == windows->pan.id) 15517 { 15518 /* 15519 Restore original image size when pan window is deleted. 15520 */ 15521 windows->image.window_changes.width=windows->image.ximage->width; 15522 windows->image.window_changes.height=windows->image.ximage->height; 15523 (void) XConfigureImage(display,resource_info,windows, 15524 display_image,exception); 15525 } 15526 break; 15527 } 15528 case ConfigureNotify: 15529 { 15530 if (display_image->debug != MagickFalse) 15531 (void) LogMagickEvent(X11Event,GetMagickModule(), 15532 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15533 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15534 event.xconfigure.y,event.xconfigure.send_event); 15535 if (event.xconfigure.window == windows->image.id) 15536 { 15537 /* 15538 Image window has a new configuration. 15539 */ 15540 if (event.xconfigure.send_event != 0) 15541 { 15542 XWindowChanges 15543 window_changes; 15544 15545 /* 15546 Position the transient windows relative of the Image window. 15547 */ 15548 if (windows->command.geometry == (char *) NULL) 15549 if (windows->command.mapped == MagickFalse) 15550 { 15551 windows->command.x=event.xconfigure.x- 15552 windows->command.width-25; 15553 windows->command.y=event.xconfigure.y; 15554 XConstrainWindowPosition(display,&windows->command); 15555 window_changes.x=windows->command.x; 15556 window_changes.y=windows->command.y; 15557 (void) XReconfigureWMWindow(display,windows->command.id, 15558 windows->command.screen,(unsigned int) (CWX | CWY), 15559 &window_changes); 15560 } 15561 if (windows->widget.geometry == (char *) NULL) 15562 if (windows->widget.mapped == MagickFalse) 15563 { 15564 windows->widget.x=event.xconfigure.x+ 15565 event.xconfigure.width/10; 15566 windows->widget.y=event.xconfigure.y+ 15567 event.xconfigure.height/10; 15568 XConstrainWindowPosition(display,&windows->widget); 15569 window_changes.x=windows->widget.x; 15570 window_changes.y=windows->widget.y; 15571 (void) XReconfigureWMWindow(display,windows->widget.id, 15572 windows->widget.screen,(unsigned int) (CWX | CWY), 15573 &window_changes); 15574 } 15575 if (windows->magnify.geometry == (char *) NULL) 15576 if (windows->magnify.mapped == MagickFalse) 15577 { 15578 windows->magnify.x=event.xconfigure.x+ 15579 event.xconfigure.width+25; 15580 windows->magnify.y=event.xconfigure.y; 15581 XConstrainWindowPosition(display,&windows->magnify); 15582 window_changes.x=windows->magnify.x; 15583 window_changes.y=windows->magnify.y; 15584 (void) XReconfigureWMWindow(display,windows->magnify.id, 15585 windows->magnify.screen,(unsigned int) (CWX | CWY), 15586 &window_changes); 15587 } 15588 if (windows->pan.geometry == (char *) NULL) 15589 if (windows->pan.mapped == MagickFalse) 15590 { 15591 windows->pan.x=event.xconfigure.x+ 15592 event.xconfigure.width+25; 15593 windows->pan.y=event.xconfigure.y+ 15594 windows->magnify.height+50; 15595 XConstrainWindowPosition(display,&windows->pan); 15596 window_changes.x=windows->pan.x; 15597 window_changes.y=windows->pan.y; 15598 (void) XReconfigureWMWindow(display,windows->pan.id, 15599 windows->pan.screen,(unsigned int) (CWX | CWY), 15600 &window_changes); 15601 } 15602 } 15603 if ((event.xconfigure.width == (int) windows->image.width) && 15604 (event.xconfigure.height == (int) windows->image.height)) 15605 break; 15606 windows->image.width=(unsigned int) event.xconfigure.width; 15607 windows->image.height=(unsigned int) event.xconfigure.height; 15608 windows->image.x=0; 15609 windows->image.y=0; 15610 if (display_image->montage != (char *) NULL) 15611 { 15612 windows->image.x=vid_info.x; 15613 windows->image.y=vid_info.y; 15614 } 15615 if ((windows->image.mapped != MagickFalse) && 15616 (windows->image.stasis != MagickFalse)) 15617 { 15618 /* 15619 Update image window configuration. 15620 */ 15621 windows->image.window_changes.width=event.xconfigure.width; 15622 windows->image.window_changes.height=event.xconfigure.height; 15623 (void) XConfigureImage(display,resource_info,windows, 15624 display_image,exception); 15625 } 15626 /* 15627 Update pan window configuration. 15628 */ 15629 if ((event.xconfigure.width < windows->image.ximage->width) || 15630 (event.xconfigure.height < windows->image.ximage->height)) 15631 { 15632 (void) XMapRaised(display,windows->pan.id); 15633 XDrawPanRectangle(display,windows); 15634 } 15635 else 15636 if (windows->pan.mapped != MagickFalse) 15637 (void) XWithdrawWindow(display,windows->pan.id, 15638 windows->pan.screen); 15639 break; 15640 } 15641 if (event.xconfigure.window == windows->magnify.id) 15642 { 15643 unsigned int 15644 magnify; 15645 15646 /* 15647 Magnify window has a new configuration. 15648 */ 15649 windows->magnify.width=(unsigned int) event.xconfigure.width; 15650 windows->magnify.height=(unsigned int) event.xconfigure.height; 15651 if (windows->magnify.mapped == MagickFalse) 15652 break; 15653 magnify=1; 15654 while ((int) magnify <= event.xconfigure.width) 15655 magnify<<=1; 15656 while ((int) magnify <= event.xconfigure.height) 15657 magnify<<=1; 15658 magnify>>=1; 15659 if (((int) magnify != event.xconfigure.width) || 15660 ((int) magnify != event.xconfigure.height)) 15661 { 15662 window_changes.width=(int) magnify; 15663 window_changes.height=(int) magnify; 15664 (void) XReconfigureWMWindow(display,windows->magnify.id, 15665 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15666 &window_changes); 15667 break; 15668 } 15669 if ((windows->magnify.mapped != MagickFalse) && 15670 (windows->magnify.stasis != MagickFalse)) 15671 { 15672 status=XMakeImage(display,resource_info,&windows->magnify, 15673 display_image,windows->magnify.width,windows->magnify.height, 15674 exception); 15675 XMakeMagnifyImage(display,windows); 15676 } 15677 break; 15678 } 15679 if ((windows->magnify.mapped != MagickFalse) && 15680 (event.xconfigure.window == windows->pan.id)) 15681 { 15682 /* 15683 Pan icon window has a new configuration. 15684 */ 15685 if (event.xconfigure.send_event != 0) 15686 { 15687 windows->pan.x=event.xconfigure.x; 15688 windows->pan.y=event.xconfigure.y; 15689 } 15690 windows->pan.width=(unsigned int) event.xconfigure.width; 15691 windows->pan.height=(unsigned int) event.xconfigure.height; 15692 break; 15693 } 15694 if (event.xconfigure.window == windows->icon.id) 15695 { 15696 /* 15697 Icon window has a new configuration. 15698 */ 15699 windows->icon.width=(unsigned int) event.xconfigure.width; 15700 windows->icon.height=(unsigned int) event.xconfigure.height; 15701 break; 15702 } 15703 break; 15704 } 15705 case DestroyNotify: 15706 { 15707 /* 15708 Group leader has exited. 15709 */ 15710 if (display_image->debug != MagickFalse) 15711 (void) LogMagickEvent(X11Event,GetMagickModule(), 15712 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15713 if (event.xdestroywindow.window == windows->group_leader.id) 15714 { 15715 *state|=ExitState; 15716 break; 15717 } 15718 break; 15719 } 15720 case EnterNotify: 15721 { 15722 /* 15723 Selectively install colormap. 15724 */ 15725 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15726 if (event.xcrossing.mode != NotifyUngrab) 15727 XInstallColormap(display,map_info->colormap); 15728 break; 15729 } 15730 case Expose: 15731 { 15732 if (display_image->debug != MagickFalse) 15733 (void) LogMagickEvent(X11Event,GetMagickModule(), 15734 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15735 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15736 event.xexpose.y); 15737 /* 15738 Refresh windows that are now exposed. 15739 */ 15740 if ((event.xexpose.window == windows->image.id) && 15741 (windows->image.mapped != MagickFalse)) 15742 { 15743 XRefreshWindow(display,&windows->image,&event); 15744 delay=display_image->delay/MagickMax( 15745 display_image->ticks_per_second,1L); 15746 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15747 break; 15748 } 15749 if ((event.xexpose.window == windows->magnify.id) && 15750 (windows->magnify.mapped != MagickFalse)) 15751 { 15752 XMakeMagnifyImage(display,windows); 15753 break; 15754 } 15755 if (event.xexpose.window == windows->pan.id) 15756 { 15757 XDrawPanRectangle(display,windows); 15758 break; 15759 } 15760 if (event.xexpose.window == windows->icon.id) 15761 { 15762 XRefreshWindow(display,&windows->icon,&event); 15763 break; 15764 } 15765 break; 15766 } 15767 case KeyPress: 15768 { 15769 int 15770 length; 15771 15772 /* 15773 Respond to a user key press. 15774 */ 15775 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15776 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15777 *(command+length)='\0'; 15778 if (display_image->debug != MagickFalse) 15779 (void) LogMagickEvent(X11Event,GetMagickModule(), 15780 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15781 key_symbol,command); 15782 if (event.xkey.window == windows->image.id) 15783 { 15784 command_type=XImageWindowCommand(display,resource_info,windows, 15785 event.xkey.state,key_symbol,&display_image,exception); 15786 if (command_type != NullCommand) 15787 nexus=XMagickCommand(display,resource_info,windows,command_type, 15788 &display_image,exception); 15789 } 15790 if (event.xkey.window == windows->magnify.id) 15791 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15792 if (event.xkey.window == windows->pan.id) 15793 { 15794 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15795 (void) XWithdrawWindow(display,windows->pan.id, 15796 windows->pan.screen); 15797 else 15798 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15799 XTextViewWidget(display,resource_info,windows,MagickFalse, 15800 "Help Viewer - Image Pan",ImagePanHelp); 15801 else 15802 XTranslateImage(display,windows,*image,key_symbol); 15803 } 15804 delay=display_image->delay/MagickMax( 15805 display_image->ticks_per_second,1L); 15806 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15807 break; 15808 } 15809 case KeyRelease: 15810 { 15811 /* 15812 Respond to a user key release. 15813 */ 15814 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15815 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15816 if (display_image->debug != MagickFalse) 15817 (void) LogMagickEvent(X11Event,GetMagickModule(), 15818 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15819 break; 15820 } 15821 case LeaveNotify: 15822 { 15823 /* 15824 Selectively uninstall colormap. 15825 */ 15826 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15827 if (event.xcrossing.mode != NotifyUngrab) 15828 XUninstallColormap(display,map_info->colormap); 15829 break; 15830 } 15831 case MapNotify: 15832 { 15833 if (display_image->debug != MagickFalse) 15834 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15835 event.xmap.window); 15836 if (event.xmap.window == windows->backdrop.id) 15837 { 15838 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15839 CurrentTime); 15840 windows->backdrop.mapped=MagickTrue; 15841 break; 15842 } 15843 if (event.xmap.window == windows->image.id) 15844 { 15845 if (windows->backdrop.id != (Window) NULL) 15846 (void) XInstallColormap(display,map_info->colormap); 15847 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15848 { 15849 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15850 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15851 } 15852 if (((int) windows->image.width < windows->image.ximage->width) || 15853 ((int) windows->image.height < windows->image.ximage->height)) 15854 (void) XMapRaised(display,windows->pan.id); 15855 windows->image.mapped=MagickTrue; 15856 break; 15857 } 15858 if (event.xmap.window == windows->magnify.id) 15859 { 15860 XMakeMagnifyImage(display,windows); 15861 windows->magnify.mapped=MagickTrue; 15862 (void) XWithdrawWindow(display,windows->info.id, 15863 windows->info.screen); 15864 break; 15865 } 15866 if (event.xmap.window == windows->pan.id) 15867 { 15868 XMakePanImage(display,resource_info,windows,display_image, 15869 exception); 15870 windows->pan.mapped=MagickTrue; 15871 break; 15872 } 15873 if (event.xmap.window == windows->info.id) 15874 { 15875 windows->info.mapped=MagickTrue; 15876 break; 15877 } 15878 if (event.xmap.window == windows->icon.id) 15879 { 15880 MagickBooleanType 15881 taint; 15882 15883 /* 15884 Create an icon image. 15885 */ 15886 taint=display_image->taint; 15887 XMakeStandardColormap(display,icon_visual,icon_resources, 15888 display_image,icon_map,icon_pixel); 15889 (void) XMakeImage(display,icon_resources,&windows->icon, 15890 display_image,windows->icon.width,windows->icon.height, 15891 exception); 15892 display_image->taint=taint; 15893 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15894 windows->icon.pixmap); 15895 (void) XClearWindow(display,windows->icon.id); 15896 (void) XWithdrawWindow(display,windows->info.id, 15897 windows->info.screen); 15898 windows->icon.mapped=MagickTrue; 15899 break; 15900 } 15901 if (event.xmap.window == windows->command.id) 15902 { 15903 windows->command.mapped=MagickTrue; 15904 break; 15905 } 15906 if (event.xmap.window == windows->popup.id) 15907 { 15908 windows->popup.mapped=MagickTrue; 15909 break; 15910 } 15911 if (event.xmap.window == windows->widget.id) 15912 { 15913 windows->widget.mapped=MagickTrue; 15914 break; 15915 } 15916 break; 15917 } 15918 case MappingNotify: 15919 { 15920 (void) XRefreshKeyboardMapping(&event.xmapping); 15921 break; 15922 } 15923 case NoExpose: 15924 break; 15925 case PropertyNotify: 15926 { 15927 Atom 15928 type; 15929 15930 int 15931 format, 15932 status; 15933 15934 unsigned char 15935 *data; 15936 15937 unsigned long 15938 after, 15939 length; 15940 15941 if (display_image->debug != MagickFalse) 15942 (void) LogMagickEvent(X11Event,GetMagickModule(), 15943 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15944 event.xproperty.atom,event.xproperty.state); 15945 if (event.xproperty.atom != windows->im_remote_command) 15946 break; 15947 /* 15948 Display image named by the remote command protocol. 15949 */ 15950 status=XGetWindowProperty(display,event.xproperty.window, 15951 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15952 AnyPropertyType,&type,&format,&length,&after,&data); 15953 if ((status != Success) || (length == 0)) 15954 break; 15955 if (LocaleCompare((char *) data,"-quit") == 0) 15956 { 15957 XClientMessage(display,windows->image.id,windows->im_protocols, 15958 windows->im_exit,CurrentTime); 15959 (void) XFree((void *) data); 15960 break; 15961 } 15962 (void) CopyMagickString(resource_info->image_info->filename, 15963 (char *) data,MaxTextExtent); 15964 (void) XFree((void *) data); 15965 nexus=ReadImage(resource_info->image_info,exception); 15966 CatchException(exception); 15967 if (nexus != (Image *) NULL) 15968 *state|=NextImageState | ExitState; 15969 break; 15970 } 15971 case ReparentNotify: 15972 { 15973 if (display_image->debug != MagickFalse) 15974 (void) LogMagickEvent(X11Event,GetMagickModule(), 15975 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15976 event.xreparent.window); 15977 break; 15978 } 15979 case UnmapNotify: 15980 { 15981 if (display_image->debug != MagickFalse) 15982 (void) LogMagickEvent(X11Event,GetMagickModule(), 15983 "Unmap Notify: 0x%lx",event.xunmap.window); 15984 if (event.xunmap.window == windows->backdrop.id) 15985 { 15986 windows->backdrop.mapped=MagickFalse; 15987 break; 15988 } 15989 if (event.xunmap.window == windows->image.id) 15990 { 15991 windows->image.mapped=MagickFalse; 15992 break; 15993 } 15994 if (event.xunmap.window == windows->magnify.id) 15995 { 15996 windows->magnify.mapped=MagickFalse; 15997 break; 15998 } 15999 if (event.xunmap.window == windows->pan.id) 16000 { 16001 windows->pan.mapped=MagickFalse; 16002 break; 16003 } 16004 if (event.xunmap.window == windows->info.id) 16005 { 16006 windows->info.mapped=MagickFalse; 16007 break; 16008 } 16009 if (event.xunmap.window == windows->icon.id) 16010 { 16011 if (map_info->colormap == icon_map->colormap) 16012 XConfigureImageColormap(display,resource_info,windows, 16013 display_image); 16014 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16015 icon_pixel); 16016 windows->icon.mapped=MagickFalse; 16017 break; 16018 } 16019 if (event.xunmap.window == windows->command.id) 16020 { 16021 windows->command.mapped=MagickFalse; 16022 break; 16023 } 16024 if (event.xunmap.window == windows->popup.id) 16025 { 16026 if (windows->backdrop.id != (Window) NULL) 16027 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16028 CurrentTime); 16029 windows->popup.mapped=MagickFalse; 16030 break; 16031 } 16032 if (event.xunmap.window == windows->widget.id) 16033 { 16034 if (windows->backdrop.id != (Window) NULL) 16035 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16036 CurrentTime); 16037 windows->widget.mapped=MagickFalse; 16038 break; 16039 } 16040 break; 16041 } 16042 default: 16043 { 16044 if (display_image->debug != MagickFalse) 16045 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16046 event.type); 16047 break; 16048 } 16049 } 16050 } while (!(*state & ExitState)); 16051 if ((*state & ExitState) == 0) 16052 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16053 &display_image,exception); 16054 else 16055 if (resource_info->confirm_edit != MagickFalse) 16056 { 16057 /* 16058 Query user if image has changed. 16059 */ 16060 if ((resource_info->immutable == MagickFalse) && 16061 (display_image->taint != MagickFalse)) 16062 { 16063 int 16064 status; 16065 16066 status=XConfirmWidget(display,windows,"Your image changed.", 16067 "Do you want to save it"); 16068 if (status == 0) 16069 *state&=(~ExitState); 16070 else 16071 if (status > 0) 16072 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16073 &display_image,exception); 16074 } 16075 } 16076 if ((windows->visual_info->klass == GrayScale) || 16077 (windows->visual_info->klass == PseudoColor) || 16078 (windows->visual_info->klass == DirectColor)) 16079 { 16080 /* 16081 Withdraw pan and Magnify window. 16082 */ 16083 if (windows->info.mapped != MagickFalse) 16084 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16085 if (windows->magnify.mapped != MagickFalse) 16086 (void) XWithdrawWindow(display,windows->magnify.id, 16087 windows->magnify.screen); 16088 if (windows->command.mapped != MagickFalse) 16089 (void) XWithdrawWindow(display,windows->command.id, 16090 windows->command.screen); 16091 } 16092 if (windows->pan.mapped != MagickFalse) 16093 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16094 if (resource_info->backdrop == MagickFalse) 16095 if (windows->backdrop.mapped) 16096 { 16097 (void) XWithdrawWindow(display,windows->backdrop.id, 16098 windows->backdrop.screen); 16099 (void) XDestroyWindow(display,windows->backdrop.id); 16100 windows->backdrop.id=(Window) NULL; 16101 (void) XWithdrawWindow(display,windows->image.id, 16102 windows->image.screen); 16103 (void) XDestroyWindow(display,windows->image.id); 16104 windows->image.id=(Window) NULL; 16105 } 16106 XSetCursorState(display,windows,MagickTrue); 16107 XCheckRefreshWindows(display,windows); 16108 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16109 *state&=(~ExitState); 16110 if (*state & ExitState) 16111 { 16112 /* 16113 Free Standard Colormap. 16114 */ 16115 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16116 if (resource_info->map_type == (char *) NULL) 16117 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16118 /* 16119 Free X resources. 16120 */ 16121 if (resource_info->copy_image != (Image *) NULL) 16122 { 16123 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16124 resource_info->copy_image=NewImageList(); 16125 } 16126 DestroyXResources(); 16127 } 16128 (void) XSync(display,MagickFalse); 16129 /* 16130 Restore our progress monitor and warning handlers. 16131 */ 16132 (void) SetErrorHandler(warning_handler); 16133 (void) SetWarningHandler(warning_handler); 16134 /* 16135 Change to home directory. 16136 */ 16137 directory=getcwd(working_directory,MaxTextExtent); 16138 (void) directory; 16139 { 16140 int 16141 status; 16142 16143 status=chdir(resource_info->home_directory); 16144 if (status == -1) 16145 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16146 "UnableToOpenFile","%s",resource_info->home_directory); 16147 } 16148 *image=display_image; 16149 return(nexus); 16150} 16151#else 16152 16153/* 16154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16155% % 16156% % 16157% % 16158+ D i s p l a y I m a g e s % 16159% % 16160% % 16161% % 16162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16163% 16164% DisplayImages() displays an image sequence to any X window screen. It 16165% returns a value other than 0 if successful. Check the exception member 16166% of image to determine the reason for any failure. 16167% 16168% The format of the DisplayImages method is: 16169% 16170% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16171% Image *images,ExceptionInfo *exception) 16172% 16173% A description of each parameter follows: 16174% 16175% o image_info: the image info. 16176% 16177% o image: the image. 16178% 16179% o exception: return any errors or warnings in this structure. 16180% 16181*/ 16182MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16183 Image *image,ExceptionInfo *exception) 16184{ 16185 assert(image_info != (const ImageInfo *) NULL); 16186 assert(image_info->signature == MagickSignature); 16187 assert(image != (Image *) NULL); 16188 assert(image->signature == MagickSignature); 16189 if (image->debug != MagickFalse) 16190 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16191 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16192 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16193 return(MagickFalse); 16194} 16195 16196/* 16197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16198% % 16199% % 16200% % 16201+ R e m o t e D i s p l a y C o m m a n d % 16202% % 16203% % 16204% % 16205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16206% 16207% RemoteDisplayCommand() encourages a remote display program to display the 16208% specified image filename. 16209% 16210% The format of the RemoteDisplayCommand method is: 16211% 16212% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16213% const char *window,const char *filename,ExceptionInfo *exception) 16214% 16215% A description of each parameter follows: 16216% 16217% o image_info: the image info. 16218% 16219% o window: Specifies the name or id of an X window. 16220% 16221% o filename: the name of the image filename to display. 16222% 16223% o exception: return any errors or warnings in this structure. 16224% 16225*/ 16226MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16227 const char *window,const char *filename,ExceptionInfo *exception) 16228{ 16229 assert(image_info != (const ImageInfo *) NULL); 16230 assert(image_info->signature == MagickSignature); 16231 assert(filename != (char *) NULL); 16232 (void) window; 16233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16234 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16235 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16236 return(MagickFalse); 16237} 16238#endif 16239