display.c revision c663dbd90626c1e7389f93b6e4c0814e8efedc20
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 if (status == 0) 2735 return(MagickFalse); 2736 /* 2737 Free up memory. 2738 */ 2739 previous_info=annotate_info->previous; 2740 annotate_info->text=DestroyString(annotate_info->text); 2741 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2742 annotate_info=previous_info; 2743 } 2744 (void) XSetForeground(display,annotate_context, 2745 windows->pixel_info->foreground_color.pixel); 2746 (void) XSetBackground(display,annotate_context, 2747 windows->pixel_info->background_color.pixel); 2748 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2749 XSetCursorState(display,windows,MagickFalse); 2750 (void) XFreeFont(display,font_info); 2751 /* 2752 Update image configuration. 2753 */ 2754 XConfigureImageColormap(display,resource_info,windows,image); 2755 (void) XConfigureImage(display,resource_info,windows,image,exception); 2756 return(MagickTrue); 2757} 2758 2759/* 2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2761% % 2762% % 2763% % 2764+ X B a c k g r o u n d I m a g e % 2765% % 2766% % 2767% % 2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2769% 2770% XBackgroundImage() displays the image in the background of a window. 2771% 2772% The format of the XBackgroundImage method is: 2773% 2774% MagickBooleanType XBackgroundImage(Display *display, 2775% XResourceInfo *resource_info,XWindows *windows,Image **image, 2776% ExceptionInfo *exception) 2777% 2778% A description of each parameter follows: 2779% 2780% o display: Specifies a connection to an X server; returned from 2781% XOpenDisplay. 2782% 2783% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2784% 2785% o windows: Specifies a pointer to a XWindows structure. 2786% 2787% o image: the image. 2788% 2789% o exception: return any errors or warnings in this structure. 2790% 2791*/ 2792static MagickBooleanType XBackgroundImage(Display *display, 2793 XResourceInfo *resource_info,XWindows *windows,Image **image, 2794 ExceptionInfo *exception) 2795{ 2796#define BackgroundImageTag "Background/Image" 2797 2798 int 2799 status; 2800 2801 static char 2802 window_id[MaxTextExtent] = "root"; 2803 2804 XResourceInfo 2805 background_resources; 2806 2807 /* 2808 Put image in background. 2809 */ 2810 status=XDialogWidget(display,windows,"Background", 2811 "Enter window id (id 0x00 selects window with pointer):",window_id); 2812 if (*window_id == '\0') 2813 return(MagickFalse); 2814 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2815 exception); 2816 XInfoWidget(display,windows,BackgroundImageTag); 2817 XSetCursorState(display,windows,MagickTrue); 2818 XCheckRefreshWindows(display,windows); 2819 background_resources=(*resource_info); 2820 background_resources.window_id=window_id; 2821 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2822 status=XDisplayBackgroundImage(display,&background_resources,*image, 2823 exception); 2824 if (status != MagickFalse) 2825 XClientMessage(display,windows->image.id,windows->im_protocols, 2826 windows->im_retain_colors,CurrentTime); 2827 XSetCursorState(display,windows,MagickFalse); 2828 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2829 exception); 2830 return(MagickTrue); 2831} 2832 2833/* 2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2835% % 2836% % 2837% % 2838+ X C h o p I m a g e % 2839% % 2840% % 2841% % 2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2843% 2844% XChopImage() chops the X image. 2845% 2846% The format of the XChopImage method is: 2847% 2848% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2849% XWindows *windows,Image **image,ExceptionInfo *exception) 2850% 2851% A description of each parameter follows: 2852% 2853% o display: Specifies a connection to an X server; returned from 2854% XOpenDisplay. 2855% 2856% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2857% 2858% o windows: Specifies a pointer to a XWindows structure. 2859% 2860% o image: the image. 2861% 2862% o exception: return any errors or warnings in this structure. 2863% 2864*/ 2865static MagickBooleanType XChopImage(Display *display, 2866 XResourceInfo *resource_info,XWindows *windows,Image **image, 2867 ExceptionInfo *exception) 2868{ 2869 static const char 2870 *ChopMenu[] = 2871 { 2872 "Direction", 2873 "Help", 2874 "Dismiss", 2875 (char *) NULL 2876 }; 2877 2878 static ModeType 2879 direction = HorizontalChopCommand; 2880 2881 static const ModeType 2882 ChopCommands[] = 2883 { 2884 ChopDirectionCommand, 2885 ChopHelpCommand, 2886 ChopDismissCommand 2887 }, 2888 DirectionCommands[] = 2889 { 2890 HorizontalChopCommand, 2891 VerticalChopCommand 2892 }; 2893 2894 char 2895 text[MaxTextExtent]; 2896 2897 Image 2898 *chop_image; 2899 2900 int 2901 id, 2902 x, 2903 y; 2904 2905 MagickRealType 2906 scale_factor; 2907 2908 RectangleInfo 2909 chop_info; 2910 2911 unsigned int 2912 distance, 2913 height, 2914 width; 2915 2916 size_t 2917 state; 2918 2919 XEvent 2920 event; 2921 2922 XSegment 2923 segment_info; 2924 2925 /* 2926 Map Command widget. 2927 */ 2928 (void) CloneString(&windows->command.name,"Chop"); 2929 windows->command.data=1; 2930 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2931 (void) XMapRaised(display,windows->command.id); 2932 XClientMessage(display,windows->image.id,windows->im_protocols, 2933 windows->im_update_widget,CurrentTime); 2934 /* 2935 Track pointer until button 1 is pressed. 2936 */ 2937 XQueryPosition(display,windows->image.id,&x,&y); 2938 (void) XSelectInput(display,windows->image.id, 2939 windows->image.attributes.event_mask | PointerMotionMask); 2940 state=DefaultState; 2941 do 2942 { 2943 if (windows->info.mapped != MagickFalse) 2944 { 2945 /* 2946 Display pointer position. 2947 */ 2948 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2949 x+windows->image.x,y+windows->image.y); 2950 XInfoWidget(display,windows,text); 2951 } 2952 /* 2953 Wait for next event. 2954 */ 2955 XScreenEvent(display,windows,&event); 2956 if (event.xany.window == windows->command.id) 2957 { 2958 /* 2959 Select a command from the Command widget. 2960 */ 2961 id=XCommandWidget(display,windows,ChopMenu,&event); 2962 if (id < 0) 2963 continue; 2964 switch (ChopCommands[id]) 2965 { 2966 case ChopDirectionCommand: 2967 { 2968 char 2969 command[MaxTextExtent]; 2970 2971 static const char 2972 *Directions[] = 2973 { 2974 "horizontal", 2975 "vertical", 2976 (char *) NULL, 2977 }; 2978 2979 /* 2980 Select a command from the pop-up menu. 2981 */ 2982 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2983 if (id >= 0) 2984 direction=DirectionCommands[id]; 2985 break; 2986 } 2987 case ChopHelpCommand: 2988 { 2989 XTextViewWidget(display,resource_info,windows,MagickFalse, 2990 "Help Viewer - Image Chop",ImageChopHelp); 2991 break; 2992 } 2993 case ChopDismissCommand: 2994 { 2995 /* 2996 Prematurely exit. 2997 */ 2998 state|=EscapeState; 2999 state|=ExitState; 3000 break; 3001 } 3002 default: 3003 break; 3004 } 3005 continue; 3006 } 3007 switch (event.type) 3008 { 3009 case ButtonPress: 3010 { 3011 if (event.xbutton.button != Button1) 3012 break; 3013 if (event.xbutton.window != windows->image.id) 3014 break; 3015 /* 3016 User has committed to start point of chopping line. 3017 */ 3018 segment_info.x1=(short int) event.xbutton.x; 3019 segment_info.x2=(short int) event.xbutton.x; 3020 segment_info.y1=(short int) event.xbutton.y; 3021 segment_info.y2=(short int) event.xbutton.y; 3022 state|=ExitState; 3023 break; 3024 } 3025 case ButtonRelease: 3026 break; 3027 case Expose: 3028 break; 3029 case KeyPress: 3030 { 3031 char 3032 command[MaxTextExtent]; 3033 3034 KeySym 3035 key_symbol; 3036 3037 if (event.xkey.window != windows->image.id) 3038 break; 3039 /* 3040 Respond to a user key press. 3041 */ 3042 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3043 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3044 switch ((int) key_symbol) 3045 { 3046 case XK_Escape: 3047 case XK_F20: 3048 { 3049 /* 3050 Prematurely exit. 3051 */ 3052 state|=EscapeState; 3053 state|=ExitState; 3054 break; 3055 } 3056 case XK_F1: 3057 case XK_Help: 3058 { 3059 (void) XSetFunction(display,windows->image.highlight_context, 3060 GXcopy); 3061 XTextViewWidget(display,resource_info,windows,MagickFalse, 3062 "Help Viewer - Image Chop",ImageChopHelp); 3063 (void) XSetFunction(display,windows->image.highlight_context, 3064 GXinvert); 3065 break; 3066 } 3067 default: 3068 { 3069 (void) XBell(display,0); 3070 break; 3071 } 3072 } 3073 break; 3074 } 3075 case MotionNotify: 3076 { 3077 /* 3078 Map and unmap Info widget as text cursor crosses its boundaries. 3079 */ 3080 x=event.xmotion.x; 3081 y=event.xmotion.y; 3082 if (windows->info.mapped != MagickFalse) 3083 { 3084 if ((x < (int) (windows->info.x+windows->info.width)) && 3085 (y < (int) (windows->info.y+windows->info.height))) 3086 (void) XWithdrawWindow(display,windows->info.id, 3087 windows->info.screen); 3088 } 3089 else 3090 if ((x > (int) (windows->info.x+windows->info.width)) || 3091 (y > (int) (windows->info.y+windows->info.height))) 3092 (void) XMapWindow(display,windows->info.id); 3093 } 3094 } 3095 } while ((state & ExitState) == 0); 3096 (void) XSelectInput(display,windows->image.id, 3097 windows->image.attributes.event_mask); 3098 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3099 if ((state & EscapeState) != 0) 3100 return(MagickTrue); 3101 /* 3102 Draw line as pointer moves until the mouse button is released. 3103 */ 3104 chop_info.width=0; 3105 chop_info.height=0; 3106 chop_info.x=0; 3107 chop_info.y=0; 3108 distance=0; 3109 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3110 state=DefaultState; 3111 do 3112 { 3113 if (distance > 9) 3114 { 3115 /* 3116 Display info and draw chopping line. 3117 */ 3118 if (windows->info.mapped == MagickFalse) 3119 (void) XMapWindow(display,windows->info.id); 3120 (void) FormatLocaleString(text,MaxTextExtent, 3121 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3122 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3123 XInfoWidget(display,windows,text); 3124 XHighlightLine(display,windows->image.id, 3125 windows->image.highlight_context,&segment_info); 3126 } 3127 else 3128 if (windows->info.mapped != MagickFalse) 3129 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3130 /* 3131 Wait for next event. 3132 */ 3133 XScreenEvent(display,windows,&event); 3134 if (distance > 9) 3135 XHighlightLine(display,windows->image.id, 3136 windows->image.highlight_context,&segment_info); 3137 switch (event.type) 3138 { 3139 case ButtonPress: 3140 { 3141 segment_info.x2=(short int) event.xmotion.x; 3142 segment_info.y2=(short int) event.xmotion.y; 3143 break; 3144 } 3145 case ButtonRelease: 3146 { 3147 /* 3148 User has committed to chopping line. 3149 */ 3150 segment_info.x2=(short int) event.xbutton.x; 3151 segment_info.y2=(short int) event.xbutton.y; 3152 state|=ExitState; 3153 break; 3154 } 3155 case Expose: 3156 break; 3157 case MotionNotify: 3158 { 3159 segment_info.x2=(short int) event.xmotion.x; 3160 segment_info.y2=(short int) event.xmotion.y; 3161 } 3162 default: 3163 break; 3164 } 3165 /* 3166 Check boundary conditions. 3167 */ 3168 if (segment_info.x2 < 0) 3169 segment_info.x2=0; 3170 else 3171 if (segment_info.x2 > windows->image.ximage->width) 3172 segment_info.x2=windows->image.ximage->width; 3173 if (segment_info.y2 < 0) 3174 segment_info.y2=0; 3175 else 3176 if (segment_info.y2 > windows->image.ximage->height) 3177 segment_info.y2=windows->image.ximage->height; 3178 distance=(unsigned int) 3179 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3180 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3181 /* 3182 Compute chopping geometry. 3183 */ 3184 if (direction == HorizontalChopCommand) 3185 { 3186 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3187 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3188 chop_info.height=0; 3189 chop_info.y=0; 3190 if (segment_info.x1 > (int) segment_info.x2) 3191 { 3192 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3193 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3194 } 3195 } 3196 else 3197 { 3198 chop_info.width=0; 3199 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3200 chop_info.x=0; 3201 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3202 if (segment_info.y1 > segment_info.y2) 3203 { 3204 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3205 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3206 } 3207 } 3208 } while ((state & ExitState) == 0); 3209 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3210 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3211 if (distance <= 9) 3212 return(MagickTrue); 3213 /* 3214 Image chopping is relative to image configuration. 3215 */ 3216 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3217 exception); 3218 XSetCursorState(display,windows,MagickTrue); 3219 XCheckRefreshWindows(display,windows); 3220 windows->image.window_changes.width=windows->image.ximage->width- 3221 (unsigned int) chop_info.width; 3222 windows->image.window_changes.height=windows->image.ximage->height- 3223 (unsigned int) chop_info.height; 3224 width=(unsigned int) (*image)->columns; 3225 height=(unsigned int) (*image)->rows; 3226 x=0; 3227 y=0; 3228 if (windows->image.crop_geometry != (char *) NULL) 3229 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3230 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3231 chop_info.x+=x; 3232 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3233 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3234 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3235 chop_info.y+=y; 3236 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3237 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3238 /* 3239 Chop image. 3240 */ 3241 chop_image=ChopImage(*image,&chop_info,exception); 3242 XSetCursorState(display,windows,MagickFalse); 3243 if (chop_image == (Image *) NULL) 3244 return(MagickFalse); 3245 *image=DestroyImage(*image); 3246 *image=chop_image; 3247 /* 3248 Update image configuration. 3249 */ 3250 XConfigureImageColormap(display,resource_info,windows,*image); 3251 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3252 return(MagickTrue); 3253} 3254 3255/* 3256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3257% % 3258% % 3259% % 3260+ X C o l o r E d i t I m a g e % 3261% % 3262% % 3263% % 3264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3265% 3266% XColorEditImage() allows the user to interactively change the color of one 3267% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3268% 3269% The format of the XColorEditImage method is: 3270% 3271% MagickBooleanType XColorEditImage(Display *display, 3272% XResourceInfo *resource_info,XWindows *windows,Image **image, 3273% ExceptionInfo *exception) 3274% 3275% A description of each parameter follows: 3276% 3277% o display: Specifies a connection to an X server; returned from 3278% XOpenDisplay. 3279% 3280% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3281% 3282% o windows: Specifies a pointer to a XWindows structure. 3283% 3284% o image: the image; returned from ReadImage. 3285% 3286% o exception: return any errors or warnings in this structure. 3287% 3288*/ 3289static MagickBooleanType XColorEditImage(Display *display, 3290 XResourceInfo *resource_info,XWindows *windows,Image **image, 3291 ExceptionInfo *exception) 3292{ 3293 static const char 3294 *ColorEditMenu[] = 3295 { 3296 "Method", 3297 "Pixel Color", 3298 "Border Color", 3299 "Fuzz", 3300 "Undo", 3301 "Help", 3302 "Dismiss", 3303 (char *) NULL 3304 }; 3305 3306 static const ModeType 3307 ColorEditCommands[] = 3308 { 3309 ColorEditMethodCommand, 3310 ColorEditColorCommand, 3311 ColorEditBorderCommand, 3312 ColorEditFuzzCommand, 3313 ColorEditUndoCommand, 3314 ColorEditHelpCommand, 3315 ColorEditDismissCommand 3316 }; 3317 3318 static PaintMethod 3319 method = PointMethod; 3320 3321 static unsigned int 3322 pen_id = 0; 3323 3324 static XColor 3325 border_color = { 0, 0, 0, 0, 0, 0 }; 3326 3327 char 3328 command[MaxTextExtent], 3329 text[MaxTextExtent]; 3330 3331 Cursor 3332 cursor; 3333 3334 int 3335 entry, 3336 id, 3337 x, 3338 x_offset, 3339 y, 3340 y_offset; 3341 3342 register Quantum 3343 *q; 3344 3345 register ssize_t 3346 i; 3347 3348 unsigned int 3349 height, 3350 width; 3351 3352 size_t 3353 state; 3354 3355 XColor 3356 color; 3357 3358 XEvent 3359 event; 3360 3361 /* 3362 Map Command widget. 3363 */ 3364 (void) CloneString(&windows->command.name,"Color Edit"); 3365 windows->command.data=4; 3366 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3367 (void) XMapRaised(display,windows->command.id); 3368 XClientMessage(display,windows->image.id,windows->im_protocols, 3369 windows->im_update_widget,CurrentTime); 3370 /* 3371 Make cursor. 3372 */ 3373 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3374 resource_info->background_color,resource_info->foreground_color); 3375 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3376 /* 3377 Track pointer until button 1 is pressed. 3378 */ 3379 XQueryPosition(display,windows->image.id,&x,&y); 3380 (void) XSelectInput(display,windows->image.id, 3381 windows->image.attributes.event_mask | PointerMotionMask); 3382 state=DefaultState; 3383 do 3384 { 3385 if (windows->info.mapped != MagickFalse) 3386 { 3387 /* 3388 Display pointer position. 3389 */ 3390 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3391 x+windows->image.x,y+windows->image.y); 3392 XInfoWidget(display,windows,text); 3393 } 3394 /* 3395 Wait for next event. 3396 */ 3397 XScreenEvent(display,windows,&event); 3398 if (event.xany.window == windows->command.id) 3399 { 3400 /* 3401 Select a command from the Command widget. 3402 */ 3403 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3404 if (id < 0) 3405 { 3406 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3407 continue; 3408 } 3409 switch (ColorEditCommands[id]) 3410 { 3411 case ColorEditMethodCommand: 3412 { 3413 char 3414 **methods; 3415 3416 /* 3417 Select a method from the pop-up menu. 3418 */ 3419 methods=(char **) GetCommandOptions(MagickMethodOptions); 3420 if (methods == (char **) NULL) 3421 break; 3422 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3423 (const char **) methods,command); 3424 if (entry >= 0) 3425 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3426 MagickFalse,methods[entry]); 3427 methods=DestroyStringList(methods); 3428 break; 3429 } 3430 case ColorEditColorCommand: 3431 { 3432 const char 3433 *ColorMenu[MaxNumberPens]; 3434 3435 int 3436 pen_number; 3437 3438 /* 3439 Initialize menu selections. 3440 */ 3441 for (i=0; i < (int) (MaxNumberPens-2); i++) 3442 ColorMenu[i]=resource_info->pen_colors[i]; 3443 ColorMenu[MaxNumberPens-2]="Browser..."; 3444 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3445 /* 3446 Select a pen color from the pop-up menu. 3447 */ 3448 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3449 (const char **) ColorMenu,command); 3450 if (pen_number < 0) 3451 break; 3452 if (pen_number == (MaxNumberPens-2)) 3453 { 3454 static char 3455 color_name[MaxTextExtent] = "gray"; 3456 3457 /* 3458 Select a pen color from a dialog. 3459 */ 3460 resource_info->pen_colors[pen_number]=color_name; 3461 XColorBrowserWidget(display,windows,"Select",color_name); 3462 if (*color_name == '\0') 3463 break; 3464 } 3465 /* 3466 Set pen color. 3467 */ 3468 (void) XParseColor(display,windows->map_info->colormap, 3469 resource_info->pen_colors[pen_number],&color); 3470 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3471 (unsigned int) MaxColors,&color); 3472 windows->pixel_info->pen_colors[pen_number]=color; 3473 pen_id=(unsigned int) pen_number; 3474 break; 3475 } 3476 case ColorEditBorderCommand: 3477 { 3478 const char 3479 *ColorMenu[MaxNumberPens]; 3480 3481 int 3482 pen_number; 3483 3484 /* 3485 Initialize menu selections. 3486 */ 3487 for (i=0; i < (int) (MaxNumberPens-2); i++) 3488 ColorMenu[i]=resource_info->pen_colors[i]; 3489 ColorMenu[MaxNumberPens-2]="Browser..."; 3490 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3491 /* 3492 Select a pen color from the pop-up menu. 3493 */ 3494 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3495 (const char **) ColorMenu,command); 3496 if (pen_number < 0) 3497 break; 3498 if (pen_number == (MaxNumberPens-2)) 3499 { 3500 static char 3501 color_name[MaxTextExtent] = "gray"; 3502 3503 /* 3504 Select a pen color from a dialog. 3505 */ 3506 resource_info->pen_colors[pen_number]=color_name; 3507 XColorBrowserWidget(display,windows,"Select",color_name); 3508 if (*color_name == '\0') 3509 break; 3510 } 3511 /* 3512 Set border color. 3513 */ 3514 (void) XParseColor(display,windows->map_info->colormap, 3515 resource_info->pen_colors[pen_number],&border_color); 3516 break; 3517 } 3518 case ColorEditFuzzCommand: 3519 { 3520 static char 3521 fuzz[MaxTextExtent]; 3522 3523 static const char 3524 *FuzzMenu[] = 3525 { 3526 "0%", 3527 "2%", 3528 "5%", 3529 "10%", 3530 "15%", 3531 "Dialog...", 3532 (char *) NULL, 3533 }; 3534 3535 /* 3536 Select a command from the pop-up menu. 3537 */ 3538 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3539 command); 3540 if (entry < 0) 3541 break; 3542 if (entry != 5) 3543 { 3544 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 3545 QuantumRange+1.0); 3546 break; 3547 } 3548 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3549 (void) XDialogWidget(display,windows,"Ok", 3550 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3551 if (*fuzz == '\0') 3552 break; 3553 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3554 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 3555 break; 3556 } 3557 case ColorEditUndoCommand: 3558 { 3559 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3560 image,exception); 3561 break; 3562 } 3563 case ColorEditHelpCommand: 3564 default: 3565 { 3566 XTextViewWidget(display,resource_info,windows,MagickFalse, 3567 "Help Viewer - Image Annotation",ImageColorEditHelp); 3568 break; 3569 } 3570 case ColorEditDismissCommand: 3571 { 3572 /* 3573 Prematurely exit. 3574 */ 3575 state|=EscapeState; 3576 state|=ExitState; 3577 break; 3578 } 3579 } 3580 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3581 continue; 3582 } 3583 switch (event.type) 3584 { 3585 case ButtonPress: 3586 { 3587 if (event.xbutton.button != Button1) 3588 break; 3589 if ((event.xbutton.window != windows->image.id) && 3590 (event.xbutton.window != windows->magnify.id)) 3591 break; 3592 /* 3593 exit loop. 3594 */ 3595 x=event.xbutton.x; 3596 y=event.xbutton.y; 3597 (void) XMagickCommand(display,resource_info,windows, 3598 SaveToUndoBufferCommand,image,exception); 3599 state|=UpdateConfigurationState; 3600 break; 3601 } 3602 case ButtonRelease: 3603 { 3604 if (event.xbutton.button != Button1) 3605 break; 3606 if ((event.xbutton.window != windows->image.id) && 3607 (event.xbutton.window != windows->magnify.id)) 3608 break; 3609 /* 3610 Update colormap information. 3611 */ 3612 x=event.xbutton.x; 3613 y=event.xbutton.y; 3614 XConfigureImageColormap(display,resource_info,windows,*image); 3615 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3616 XInfoWidget(display,windows,text); 3617 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3618 state&=(~UpdateConfigurationState); 3619 break; 3620 } 3621 case Expose: 3622 break; 3623 case KeyPress: 3624 { 3625 KeySym 3626 key_symbol; 3627 3628 if (event.xkey.window == windows->magnify.id) 3629 { 3630 Window 3631 window; 3632 3633 window=windows->magnify.id; 3634 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3635 } 3636 if (event.xkey.window != windows->image.id) 3637 break; 3638 /* 3639 Respond to a user key press. 3640 */ 3641 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3642 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3643 switch ((int) key_symbol) 3644 { 3645 case XK_Escape: 3646 case XK_F20: 3647 { 3648 /* 3649 Prematurely exit. 3650 */ 3651 state|=ExitState; 3652 break; 3653 } 3654 case XK_F1: 3655 case XK_Help: 3656 { 3657 XTextViewWidget(display,resource_info,windows,MagickFalse, 3658 "Help Viewer - Image Annotation",ImageColorEditHelp); 3659 break; 3660 } 3661 default: 3662 { 3663 (void) XBell(display,0); 3664 break; 3665 } 3666 } 3667 break; 3668 } 3669 case MotionNotify: 3670 { 3671 /* 3672 Map and unmap Info widget as cursor crosses its boundaries. 3673 */ 3674 x=event.xmotion.x; 3675 y=event.xmotion.y; 3676 if (windows->info.mapped != MagickFalse) 3677 { 3678 if ((x < (int) (windows->info.x+windows->info.width)) && 3679 (y < (int) (windows->info.y+windows->info.height))) 3680 (void) XWithdrawWindow(display,windows->info.id, 3681 windows->info.screen); 3682 } 3683 else 3684 if ((x > (int) (windows->info.x+windows->info.width)) || 3685 (y > (int) (windows->info.y+windows->info.height))) 3686 (void) XMapWindow(display,windows->info.id); 3687 break; 3688 } 3689 default: 3690 break; 3691 } 3692 if (event.xany.window == windows->magnify.id) 3693 { 3694 x=windows->magnify.x-windows->image.x; 3695 y=windows->magnify.y-windows->image.y; 3696 } 3697 x_offset=x; 3698 y_offset=y; 3699 if ((state & UpdateConfigurationState) != 0) 3700 { 3701 CacheView 3702 *image_view; 3703 3704 int 3705 x, 3706 y; 3707 3708 /* 3709 Pixel edit is relative to image configuration. 3710 */ 3711 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3712 MagickTrue); 3713 color=windows->pixel_info->pen_colors[pen_id]; 3714 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3715 width=(unsigned int) (*image)->columns; 3716 height=(unsigned int) (*image)->rows; 3717 x=0; 3718 y=0; 3719 if (windows->image.crop_geometry != (char *) NULL) 3720 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3721 &width,&height); 3722 x_offset=(int) 3723 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3724 y_offset=(int) 3725 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3726 if ((x_offset < 0) || (y_offset < 0)) 3727 continue; 3728 if ((x_offset >= (int) (*image)->columns) || 3729 (y_offset >= (int) (*image)->rows)) 3730 continue; 3731 image_view=AcquireCacheView(*image); 3732 switch (method) 3733 { 3734 case PointMethod: 3735 default: 3736 { 3737 /* 3738 Update color information using point algorithm. 3739 */ 3740 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3741 return(MagickFalse); 3742 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3743 (ssize_t) y_offset,1,1,exception); 3744 if (q == (Quantum *) NULL) 3745 break; 3746 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3747 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3748 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3749 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3750 break; 3751 } 3752 case ReplaceMethod: 3753 { 3754 PixelPacket 3755 pixel, 3756 target; 3757 3758 /* 3759 Update color information using replace algorithm. 3760 */ 3761 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3762 (ssize_t) y_offset,&target,exception); 3763 if ((*image)->storage_class == DirectClass) 3764 { 3765 for (y=0; y < (int) (*image)->rows; y++) 3766 { 3767 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3768 (*image)->columns,1,exception); 3769 if (q == (Quantum *) NULL) 3770 break; 3771 for (x=0; x < (int) (*image)->columns; x++) 3772 { 3773 GetPixelPacket(*image,q,&pixel); 3774 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 3775 { 3776 SetPixelRed(*image,ScaleShortToQuantum( 3777 color.red),q); 3778 SetPixelGreen(*image,ScaleShortToQuantum( 3779 color.green),q); 3780 SetPixelBlue(*image,ScaleShortToQuantum( 3781 color.blue),q); 3782 } 3783 q+=GetPixelChannels(*image); 3784 } 3785 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3786 break; 3787 } 3788 } 3789 else 3790 { 3791 for (i=0; i < (ssize_t) (*image)->colors; i++) 3792 if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target)) 3793 { 3794 (*image)->colormap[i].red=ScaleShortToQuantum( 3795 color.red); 3796 (*image)->colormap[i].green=ScaleShortToQuantum( 3797 color.green); 3798 (*image)->colormap[i].blue=ScaleShortToQuantum( 3799 color.blue); 3800 } 3801 (void) SyncImage(*image); 3802 } 3803 break; 3804 } 3805 case FloodfillMethod: 3806 case FillToBorderMethod: 3807 { 3808 DrawInfo 3809 *draw_info; 3810 3811 PixelInfo 3812 target; 3813 3814 /* 3815 Update color information using floodfill algorithm. 3816 */ 3817 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 3818 (ssize_t) y_offset,&target,exception); 3819 if (method == FillToBorderMethod) 3820 { 3821 target.red=(MagickRealType) 3822 ScaleShortToQuantum(border_color.red); 3823 target.green=(MagickRealType) 3824 ScaleShortToQuantum(border_color.green); 3825 target.blue=(MagickRealType) 3826 ScaleShortToQuantum(border_color.blue); 3827 } 3828 draw_info=CloneDrawInfo(resource_info->image_info, 3829 (DrawInfo *) NULL); 3830 (void) QueryColorDatabase(resource_info->pen_colors[pen_id], 3831 &draw_info->fill,exception); 3832 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3833 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3834 MagickFalse : MagickTrue,exception); 3835 draw_info=DestroyDrawInfo(draw_info); 3836 break; 3837 } 3838 case ResetMethod: 3839 { 3840 /* 3841 Update color information using reset algorithm. 3842 */ 3843 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3844 return(MagickFalse); 3845 for (y=0; y < (int) (*image)->rows; y++) 3846 { 3847 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3848 (*image)->columns,1,exception); 3849 if (q == (Quantum *) NULL) 3850 break; 3851 for (x=0; x < (int) (*image)->columns; x++) 3852 { 3853 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3854 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3855 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3856 q+=GetPixelChannels(*image); 3857 } 3858 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3859 break; 3860 } 3861 break; 3862 } 3863 } 3864 image_view=DestroyCacheView(image_view); 3865 state&=(~UpdateConfigurationState); 3866 } 3867 } while ((state & ExitState) == 0); 3868 (void) XSelectInput(display,windows->image.id, 3869 windows->image.attributes.event_mask); 3870 XSetCursorState(display,windows,MagickFalse); 3871 (void) XFreeCursor(display,cursor); 3872 return(MagickTrue); 3873} 3874 3875/* 3876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3877% % 3878% % 3879% % 3880+ X C o m p o s i t e I m a g e % 3881% % 3882% % 3883% % 3884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3885% 3886% XCompositeImage() requests an image name from the user, reads the image and 3887% composites it with the X window image at a location the user chooses with 3888% the pointer. 3889% 3890% The format of the XCompositeImage method is: 3891% 3892% MagickBooleanType XCompositeImage(Display *display, 3893% XResourceInfo *resource_info,XWindows *windows,Image *image, 3894% ExceptionInfo *exception) 3895% 3896% A description of each parameter follows: 3897% 3898% o display: Specifies a connection to an X server; returned from 3899% XOpenDisplay. 3900% 3901% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3902% 3903% o windows: Specifies a pointer to a XWindows structure. 3904% 3905% o image: the image; returned from ReadImage. 3906% 3907% o exception: return any errors or warnings in this structure. 3908% 3909*/ 3910static MagickBooleanType XCompositeImage(Display *display, 3911 XResourceInfo *resource_info,XWindows *windows,Image *image, 3912 ExceptionInfo *exception) 3913{ 3914 static char 3915 displacement_geometry[MaxTextExtent] = "30x30", 3916 filename[MaxTextExtent] = "\0"; 3917 3918 static const char 3919 *CompositeMenu[] = 3920 { 3921 "Operators", 3922 "Dissolve", 3923 "Displace", 3924 "Help", 3925 "Dismiss", 3926 (char *) NULL 3927 }; 3928 3929 static CompositeOperator 3930 compose = CopyCompositeOp; 3931 3932 static const ModeType 3933 CompositeCommands[] = 3934 { 3935 CompositeOperatorsCommand, 3936 CompositeDissolveCommand, 3937 CompositeDisplaceCommand, 3938 CompositeHelpCommand, 3939 CompositeDismissCommand 3940 }; 3941 3942 char 3943 text[MaxTextExtent]; 3944 3945 Cursor 3946 cursor; 3947 3948 Image 3949 *composite_image; 3950 3951 int 3952 entry, 3953 id, 3954 x, 3955 y; 3956 3957 MagickRealType 3958 blend, 3959 scale_factor; 3960 3961 RectangleInfo 3962 highlight_info, 3963 composite_info; 3964 3965 unsigned int 3966 height, 3967 width; 3968 3969 size_t 3970 state; 3971 3972 XEvent 3973 event; 3974 3975 /* 3976 Request image file name from user. 3977 */ 3978 XFileBrowserWidget(display,windows,"Composite",filename); 3979 if (*filename == '\0') 3980 return(MagickTrue); 3981 /* 3982 Read image. 3983 */ 3984 XSetCursorState(display,windows,MagickTrue); 3985 XCheckRefreshWindows(display,windows); 3986 (void) CopyMagickString(resource_info->image_info->filename,filename, 3987 MaxTextExtent); 3988 composite_image=ReadImage(resource_info->image_info,exception); 3989 CatchException(exception); 3990 XSetCursorState(display,windows,MagickFalse); 3991 if (composite_image == (Image *) NULL) 3992 return(MagickFalse); 3993 /* 3994 Map Command widget. 3995 */ 3996 (void) CloneString(&windows->command.name,"Composite"); 3997 windows->command.data=1; 3998 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 3999 (void) XMapRaised(display,windows->command.id); 4000 XClientMessage(display,windows->image.id,windows->im_protocols, 4001 windows->im_update_widget,CurrentTime); 4002 /* 4003 Track pointer until button 1 is pressed. 4004 */ 4005 XQueryPosition(display,windows->image.id,&x,&y); 4006 (void) XSelectInput(display,windows->image.id, 4007 windows->image.attributes.event_mask | PointerMotionMask); 4008 composite_info.x=(ssize_t) windows->image.x+x; 4009 composite_info.y=(ssize_t) windows->image.y+y; 4010 composite_info.width=0; 4011 composite_info.height=0; 4012 cursor=XCreateFontCursor(display,XC_ul_angle); 4013 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4014 blend=0.0; 4015 state=DefaultState; 4016 do 4017 { 4018 if (windows->info.mapped != MagickFalse) 4019 { 4020 /* 4021 Display pointer position. 4022 */ 4023 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4024 (long) composite_info.x,(long) composite_info.y); 4025 XInfoWidget(display,windows,text); 4026 } 4027 highlight_info=composite_info; 4028 highlight_info.x=composite_info.x-windows->image.x; 4029 highlight_info.y=composite_info.y-windows->image.y; 4030 XHighlightRectangle(display,windows->image.id, 4031 windows->image.highlight_context,&highlight_info); 4032 /* 4033 Wait for next event. 4034 */ 4035 XScreenEvent(display,windows,&event); 4036 XHighlightRectangle(display,windows->image.id, 4037 windows->image.highlight_context,&highlight_info); 4038 if (event.xany.window == windows->command.id) 4039 { 4040 /* 4041 Select a command from the Command widget. 4042 */ 4043 id=XCommandWidget(display,windows,CompositeMenu,&event); 4044 if (id < 0) 4045 continue; 4046 switch (CompositeCommands[id]) 4047 { 4048 case CompositeOperatorsCommand: 4049 { 4050 char 4051 command[MaxTextExtent], 4052 **operators; 4053 4054 /* 4055 Select a command from the pop-up menu. 4056 */ 4057 operators=GetCommandOptions(MagickComposeOptions); 4058 if (operators == (char **) NULL) 4059 break; 4060 entry=XMenuWidget(display,windows,CompositeMenu[id], 4061 (const char **) operators,command); 4062 if (entry >= 0) 4063 compose=(CompositeOperator) ParseCommandOption( 4064 MagickComposeOptions,MagickFalse,operators[entry]); 4065 operators=DestroyStringList(operators); 4066 break; 4067 } 4068 case CompositeDissolveCommand: 4069 { 4070 static char 4071 factor[MaxTextExtent] = "20.0"; 4072 4073 /* 4074 Dissolve the two images a given percent. 4075 */ 4076 (void) XSetFunction(display,windows->image.highlight_context, 4077 GXcopy); 4078 (void) XDialogWidget(display,windows,"Dissolve", 4079 "Enter the blend factor (0.0 - 99.9%):",factor); 4080 (void) XSetFunction(display,windows->image.highlight_context, 4081 GXinvert); 4082 if (*factor == '\0') 4083 break; 4084 blend=InterpretLocaleValue(factor,(char **) NULL); 4085 compose=DissolveCompositeOp; 4086 break; 4087 } 4088 case CompositeDisplaceCommand: 4089 { 4090 /* 4091 Get horizontal and vertical scale displacement geometry. 4092 */ 4093 (void) XSetFunction(display,windows->image.highlight_context, 4094 GXcopy); 4095 (void) XDialogWidget(display,windows,"Displace", 4096 "Enter the horizontal and vertical scale:",displacement_geometry); 4097 (void) XSetFunction(display,windows->image.highlight_context, 4098 GXinvert); 4099 if (*displacement_geometry == '\0') 4100 break; 4101 compose=DisplaceCompositeOp; 4102 break; 4103 } 4104 case CompositeHelpCommand: 4105 { 4106 (void) XSetFunction(display,windows->image.highlight_context, 4107 GXcopy); 4108 XTextViewWidget(display,resource_info,windows,MagickFalse, 4109 "Help Viewer - Image Composite",ImageCompositeHelp); 4110 (void) XSetFunction(display,windows->image.highlight_context, 4111 GXinvert); 4112 break; 4113 } 4114 case CompositeDismissCommand: 4115 { 4116 /* 4117 Prematurely exit. 4118 */ 4119 state|=EscapeState; 4120 state|=ExitState; 4121 break; 4122 } 4123 default: 4124 break; 4125 } 4126 continue; 4127 } 4128 switch (event.type) 4129 { 4130 case ButtonPress: 4131 { 4132 if (image->debug != MagickFalse) 4133 (void) LogMagickEvent(X11Event,GetMagickModule(), 4134 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4135 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4136 if (event.xbutton.button != Button1) 4137 break; 4138 if (event.xbutton.window != windows->image.id) 4139 break; 4140 /* 4141 Change cursor. 4142 */ 4143 composite_info.width=composite_image->columns; 4144 composite_info.height=composite_image->rows; 4145 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4146 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4147 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4148 break; 4149 } 4150 case ButtonRelease: 4151 { 4152 if (image->debug != MagickFalse) 4153 (void) LogMagickEvent(X11Event,GetMagickModule(), 4154 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4155 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4156 if (event.xbutton.button != Button1) 4157 break; 4158 if (event.xbutton.window != windows->image.id) 4159 break; 4160 if ((composite_info.width != 0) && (composite_info.height != 0)) 4161 { 4162 /* 4163 User has selected the location of the composite image. 4164 */ 4165 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4166 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4167 state|=ExitState; 4168 } 4169 break; 4170 } 4171 case Expose: 4172 break; 4173 case KeyPress: 4174 { 4175 char 4176 command[MaxTextExtent]; 4177 4178 KeySym 4179 key_symbol; 4180 4181 int 4182 length; 4183 4184 if (event.xkey.window != windows->image.id) 4185 break; 4186 /* 4187 Respond to a user key press. 4188 */ 4189 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4190 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4191 *(command+length)='\0'; 4192 if (image->debug != MagickFalse) 4193 (void) LogMagickEvent(X11Event,GetMagickModule(), 4194 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4195 switch ((int) key_symbol) 4196 { 4197 case XK_Escape: 4198 case XK_F20: 4199 { 4200 /* 4201 Prematurely exit. 4202 */ 4203 composite_image=DestroyImage(composite_image); 4204 state|=EscapeState; 4205 state|=ExitState; 4206 break; 4207 } 4208 case XK_F1: 4209 case XK_Help: 4210 { 4211 (void) XSetFunction(display,windows->image.highlight_context, 4212 GXcopy); 4213 XTextViewWidget(display,resource_info,windows,MagickFalse, 4214 "Help Viewer - Image Composite",ImageCompositeHelp); 4215 (void) XSetFunction(display,windows->image.highlight_context, 4216 GXinvert); 4217 break; 4218 } 4219 default: 4220 { 4221 (void) XBell(display,0); 4222 break; 4223 } 4224 } 4225 break; 4226 } 4227 case MotionNotify: 4228 { 4229 /* 4230 Map and unmap Info widget as text cursor crosses its boundaries. 4231 */ 4232 x=event.xmotion.x; 4233 y=event.xmotion.y; 4234 if (windows->info.mapped != MagickFalse) 4235 { 4236 if ((x < (int) (windows->info.x+windows->info.width)) && 4237 (y < (int) (windows->info.y+windows->info.height))) 4238 (void) XWithdrawWindow(display,windows->info.id, 4239 windows->info.screen); 4240 } 4241 else 4242 if ((x > (int) (windows->info.x+windows->info.width)) || 4243 (y > (int) (windows->info.y+windows->info.height))) 4244 (void) XMapWindow(display,windows->info.id); 4245 composite_info.x=(ssize_t) windows->image.x+x; 4246 composite_info.y=(ssize_t) windows->image.y+y; 4247 break; 4248 } 4249 default: 4250 { 4251 if (image->debug != MagickFalse) 4252 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4253 event.type); 4254 break; 4255 } 4256 } 4257 } while ((state & ExitState) == 0); 4258 (void) XSelectInput(display,windows->image.id, 4259 windows->image.attributes.event_mask); 4260 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4261 XSetCursorState(display,windows,MagickFalse); 4262 (void) XFreeCursor(display,cursor); 4263 if ((state & EscapeState) != 0) 4264 return(MagickTrue); 4265 /* 4266 Image compositing is relative to image configuration. 4267 */ 4268 XSetCursorState(display,windows,MagickTrue); 4269 XCheckRefreshWindows(display,windows); 4270 width=(unsigned int) image->columns; 4271 height=(unsigned int) image->rows; 4272 x=0; 4273 y=0; 4274 if (windows->image.crop_geometry != (char *) NULL) 4275 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4276 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4277 composite_info.x+=x; 4278 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4279 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4280 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4281 composite_info.y+=y; 4282 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4283 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4284 if ((composite_info.width != composite_image->columns) || 4285 (composite_info.height != composite_image->rows)) 4286 { 4287 Image 4288 *resize_image; 4289 4290 /* 4291 Scale composite image. 4292 */ 4293 resize_image=ResizeImage(composite_image,composite_info.width, 4294 composite_info.height,composite_image->filter,composite_image->blur, 4295 exception); 4296 composite_image=DestroyImage(composite_image); 4297 if (resize_image == (Image *) NULL) 4298 { 4299 XSetCursorState(display,windows,MagickFalse); 4300 return(MagickFalse); 4301 } 4302 composite_image=resize_image; 4303 } 4304 if (compose == DisplaceCompositeOp) 4305 (void) SetImageArtifact(composite_image,"compose:args", 4306 displacement_geometry); 4307 if (blend != 0.0) 4308 { 4309 CacheView 4310 *image_view; 4311 4312 int 4313 y; 4314 4315 Quantum 4316 opacity; 4317 4318 register int 4319 x; 4320 4321 register Quantum 4322 *q; 4323 4324 /* 4325 Create mattes for blending. 4326 */ 4327 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4328 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4329 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4330 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4331 return(MagickFalse); 4332 image->matte=MagickTrue; 4333 image_view=AcquireCacheView(image); 4334 for (y=0; y < (int) image->rows; y++) 4335 { 4336 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4337 exception); 4338 if (q == (Quantum *) NULL) 4339 break; 4340 for (x=0; x < (int) image->columns; x++) 4341 { 4342 SetPixelAlpha(image,opacity,q); 4343 q+=GetPixelChannels(image); 4344 } 4345 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4346 break; 4347 } 4348 image_view=DestroyCacheView(image_view); 4349 } 4350 /* 4351 Composite image with X Image window. 4352 */ 4353 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4354 composite_info.y); 4355 composite_image=DestroyImage(composite_image); 4356 XSetCursorState(display,windows,MagickFalse); 4357 /* 4358 Update image configuration. 4359 */ 4360 XConfigureImageColormap(display,resource_info,windows,image); 4361 (void) XConfigureImage(display,resource_info,windows,image,exception); 4362 return(MagickTrue); 4363} 4364 4365/* 4366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4367% % 4368% % 4369% % 4370+ X C o n f i g u r e I m a g e % 4371% % 4372% % 4373% % 4374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4375% 4376% XConfigureImage() creates a new X image. It also notifies the window 4377% manager of the new image size and configures the transient widows. 4378% 4379% The format of the XConfigureImage method is: 4380% 4381% MagickBooleanType XConfigureImage(Display *display, 4382% XResourceInfo *resource_info,XWindows *windows,Image *image, 4383% ExceptionInfo *exception) 4384% 4385% A description of each parameter follows: 4386% 4387% o display: Specifies a connection to an X server; returned from 4388% XOpenDisplay. 4389% 4390% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4391% 4392% o windows: Specifies a pointer to a XWindows structure. 4393% 4394% o image: the image. 4395% 4396% o exception: return any errors or warnings in this structure. 4397% 4398% o exception: return any errors or warnings in this structure. 4399% 4400*/ 4401static MagickBooleanType XConfigureImage(Display *display, 4402 XResourceInfo *resource_info,XWindows *windows,Image *image, 4403 ExceptionInfo *exception) 4404{ 4405 char 4406 geometry[MaxTextExtent]; 4407 4408 MagickStatusType 4409 status; 4410 4411 size_t 4412 mask, 4413 height, 4414 width; 4415 4416 ssize_t 4417 x, 4418 y; 4419 4420 XSizeHints 4421 *size_hints; 4422 4423 XWindowChanges 4424 window_changes; 4425 4426 /* 4427 Dismiss if window dimensions are zero. 4428 */ 4429 width=(unsigned int) windows->image.window_changes.width; 4430 height=(unsigned int) windows->image.window_changes.height; 4431 if (image->debug != MagickFalse) 4432 (void) LogMagickEvent(X11Event,GetMagickModule(), 4433 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4434 windows->image.ximage->height,(double) width,(double) height); 4435 if ((width*height) == 0) 4436 return(MagickTrue); 4437 x=0; 4438 y=0; 4439 /* 4440 Resize image to fit Image window dimensions. 4441 */ 4442 XSetCursorState(display,windows,MagickTrue); 4443 (void) XFlush(display); 4444 if (((int) width != windows->image.ximage->width) || 4445 ((int) height != windows->image.ximage->height)) 4446 image->taint=MagickTrue; 4447 windows->magnify.x=(int) 4448 width*windows->magnify.x/windows->image.ximage->width; 4449 windows->magnify.y=(int) 4450 height*windows->magnify.y/windows->image.ximage->height; 4451 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4452 windows->image.y=(int) 4453 (height*windows->image.y/windows->image.ximage->height); 4454 status=XMakeImage(display,resource_info,&windows->image,image, 4455 (unsigned int) width,(unsigned int) height,exception); 4456 if (status == MagickFalse) 4457 XNoticeWidget(display,windows,"Unable to configure X image:", 4458 windows->image.name); 4459 /* 4460 Notify window manager of the new configuration. 4461 */ 4462 if (resource_info->image_geometry != (char *) NULL) 4463 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4464 resource_info->image_geometry); 4465 else 4466 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4467 XDisplayWidth(display,windows->image.screen), 4468 XDisplayHeight(display,windows->image.screen)); 4469 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4470 window_changes.width=(int) width; 4471 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4472 window_changes.width=XDisplayWidth(display,windows->image.screen); 4473 window_changes.height=(int) height; 4474 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4475 window_changes.height=XDisplayHeight(display,windows->image.screen); 4476 mask=(size_t) (CWWidth | CWHeight); 4477 if (resource_info->backdrop) 4478 { 4479 mask|=CWX | CWY; 4480 window_changes.x=(int) 4481 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4482 window_changes.y=(int) 4483 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4484 } 4485 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4486 (unsigned int) mask,&window_changes); 4487 (void) XClearWindow(display,windows->image.id); 4488 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4489 /* 4490 Update Magnify window configuration. 4491 */ 4492 if (windows->magnify.mapped != MagickFalse) 4493 XMakeMagnifyImage(display,windows); 4494 windows->pan.crop_geometry=windows->image.crop_geometry; 4495 XBestIconSize(display,&windows->pan,image); 4496 while (((windows->pan.width << 1) < MaxIconSize) && 4497 ((windows->pan.height << 1) < MaxIconSize)) 4498 { 4499 windows->pan.width<<=1; 4500 windows->pan.height<<=1; 4501 } 4502 if (windows->pan.geometry != (char *) NULL) 4503 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4504 &windows->pan.width,&windows->pan.height); 4505 window_changes.width=(int) windows->pan.width; 4506 window_changes.height=(int) windows->pan.height; 4507 size_hints=XAllocSizeHints(); 4508 if (size_hints != (XSizeHints *) NULL) 4509 { 4510 /* 4511 Set new size hints. 4512 */ 4513 size_hints->flags=PSize | PMinSize | PMaxSize; 4514 size_hints->width=window_changes.width; 4515 size_hints->height=window_changes.height; 4516 size_hints->min_width=size_hints->width; 4517 size_hints->min_height=size_hints->height; 4518 size_hints->max_width=size_hints->width; 4519 size_hints->max_height=size_hints->height; 4520 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4521 (void) XFree((void *) size_hints); 4522 } 4523 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4524 (unsigned int) (CWWidth | CWHeight),&window_changes); 4525 /* 4526 Update icon window configuration. 4527 */ 4528 windows->icon.crop_geometry=windows->image.crop_geometry; 4529 XBestIconSize(display,&windows->icon,image); 4530 window_changes.width=(int) windows->icon.width; 4531 window_changes.height=(int) windows->icon.height; 4532 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4533 (unsigned int) (CWWidth | CWHeight),&window_changes); 4534 XSetCursorState(display,windows,MagickFalse); 4535 return(status != 0 ? MagickTrue : MagickFalse); 4536} 4537 4538/* 4539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4540% % 4541% % 4542% % 4543+ X C r o p I m a g e % 4544% % 4545% % 4546% % 4547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4548% 4549% XCropImage() allows the user to select a region of the image and crop, copy, 4550% or cut it. For copy or cut, the image can subsequently be composited onto 4551% the image with XPasteImage. 4552% 4553% The format of the XCropImage method is: 4554% 4555% MagickBooleanType XCropImage(Display *display, 4556% XResourceInfo *resource_info,XWindows *windows,Image *image, 4557% const ClipboardMode mode,ExceptionInfo *exception) 4558% 4559% A description of each parameter follows: 4560% 4561% o display: Specifies a connection to an X server; returned from 4562% XOpenDisplay. 4563% 4564% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4565% 4566% o windows: Specifies a pointer to a XWindows structure. 4567% 4568% o image: the image; returned from ReadImage. 4569% 4570% o mode: This unsigned value specified whether the image should be 4571% cropped, copied, or cut. 4572% 4573% o exception: return any errors or warnings in this structure. 4574% 4575*/ 4576static MagickBooleanType XCropImage(Display *display, 4577 XResourceInfo *resource_info,XWindows *windows,Image *image, 4578 const ClipboardMode mode,ExceptionInfo *exception) 4579{ 4580 static const char 4581 *CropModeMenu[] = 4582 { 4583 "Help", 4584 "Dismiss", 4585 (char *) NULL 4586 }, 4587 *RectifyModeMenu[] = 4588 { 4589 "Crop", 4590 "Help", 4591 "Dismiss", 4592 (char *) NULL 4593 }; 4594 4595 static const ModeType 4596 CropCommands[] = 4597 { 4598 CropHelpCommand, 4599 CropDismissCommand 4600 }, 4601 RectifyCommands[] = 4602 { 4603 RectifyCopyCommand, 4604 RectifyHelpCommand, 4605 RectifyDismissCommand 4606 }; 4607 4608 CacheView 4609 *image_view; 4610 4611 char 4612 command[MaxTextExtent], 4613 text[MaxTextExtent]; 4614 4615 Cursor 4616 cursor; 4617 4618 int 4619 id, 4620 x, 4621 y; 4622 4623 KeySym 4624 key_symbol; 4625 4626 Image 4627 *crop_image; 4628 4629 MagickRealType 4630 scale_factor; 4631 4632 RectangleInfo 4633 crop_info, 4634 highlight_info; 4635 4636 register Quantum 4637 *q; 4638 4639 unsigned int 4640 height, 4641 width; 4642 4643 size_t 4644 state; 4645 4646 XEvent 4647 event; 4648 4649 /* 4650 Map Command widget. 4651 */ 4652 switch (mode) 4653 { 4654 case CopyMode: 4655 { 4656 (void) CloneString(&windows->command.name,"Copy"); 4657 break; 4658 } 4659 case CropMode: 4660 { 4661 (void) CloneString(&windows->command.name,"Crop"); 4662 break; 4663 } 4664 case CutMode: 4665 { 4666 (void) CloneString(&windows->command.name,"Cut"); 4667 break; 4668 } 4669 } 4670 RectifyModeMenu[0]=windows->command.name; 4671 windows->command.data=0; 4672 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4673 (void) XMapRaised(display,windows->command.id); 4674 XClientMessage(display,windows->image.id,windows->im_protocols, 4675 windows->im_update_widget,CurrentTime); 4676 /* 4677 Track pointer until button 1 is pressed. 4678 */ 4679 XQueryPosition(display,windows->image.id,&x,&y); 4680 (void) XSelectInput(display,windows->image.id, 4681 windows->image.attributes.event_mask | PointerMotionMask); 4682 crop_info.x=(ssize_t) windows->image.x+x; 4683 crop_info.y=(ssize_t) windows->image.y+y; 4684 crop_info.width=0; 4685 crop_info.height=0; 4686 cursor=XCreateFontCursor(display,XC_fleur); 4687 state=DefaultState; 4688 do 4689 { 4690 if (windows->info.mapped != MagickFalse) 4691 { 4692 /* 4693 Display pointer position. 4694 */ 4695 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4696 (long) crop_info.x,(long) crop_info.y); 4697 XInfoWidget(display,windows,text); 4698 } 4699 /* 4700 Wait for next event. 4701 */ 4702 XScreenEvent(display,windows,&event); 4703 if (event.xany.window == windows->command.id) 4704 { 4705 /* 4706 Select a command from the Command widget. 4707 */ 4708 id=XCommandWidget(display,windows,CropModeMenu,&event); 4709 if (id < 0) 4710 continue; 4711 switch (CropCommands[id]) 4712 { 4713 case CropHelpCommand: 4714 { 4715 switch (mode) 4716 { 4717 case CopyMode: 4718 { 4719 XTextViewWidget(display,resource_info,windows,MagickFalse, 4720 "Help Viewer - Image Copy",ImageCopyHelp); 4721 break; 4722 } 4723 case CropMode: 4724 { 4725 XTextViewWidget(display,resource_info,windows,MagickFalse, 4726 "Help Viewer - Image Crop",ImageCropHelp); 4727 break; 4728 } 4729 case CutMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Cut",ImageCutHelp); 4733 break; 4734 } 4735 } 4736 break; 4737 } 4738 case CropDismissCommand: 4739 { 4740 /* 4741 Prematurely exit. 4742 */ 4743 state|=EscapeState; 4744 state|=ExitState; 4745 break; 4746 } 4747 default: 4748 break; 4749 } 4750 continue; 4751 } 4752 switch (event.type) 4753 { 4754 case ButtonPress: 4755 { 4756 if (event.xbutton.button != Button1) 4757 break; 4758 if (event.xbutton.window != windows->image.id) 4759 break; 4760 /* 4761 Note first corner of cropping rectangle-- exit loop. 4762 */ 4763 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4764 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4765 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4766 state|=ExitState; 4767 break; 4768 } 4769 case ButtonRelease: 4770 break; 4771 case Expose: 4772 break; 4773 case KeyPress: 4774 { 4775 if (event.xkey.window != windows->image.id) 4776 break; 4777 /* 4778 Respond to a user key press. 4779 */ 4780 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4781 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4782 switch ((int) key_symbol) 4783 { 4784 case XK_Escape: 4785 case XK_F20: 4786 { 4787 /* 4788 Prematurely exit. 4789 */ 4790 state|=EscapeState; 4791 state|=ExitState; 4792 break; 4793 } 4794 case XK_F1: 4795 case XK_Help: 4796 { 4797 switch (mode) 4798 { 4799 case CopyMode: 4800 { 4801 XTextViewWidget(display,resource_info,windows,MagickFalse, 4802 "Help Viewer - Image Copy",ImageCopyHelp); 4803 break; 4804 } 4805 case CropMode: 4806 { 4807 XTextViewWidget(display,resource_info,windows,MagickFalse, 4808 "Help Viewer - Image Crop",ImageCropHelp); 4809 break; 4810 } 4811 case CutMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Cut",ImageCutHelp); 4815 break; 4816 } 4817 } 4818 break; 4819 } 4820 default: 4821 { 4822 (void) XBell(display,0); 4823 break; 4824 } 4825 } 4826 break; 4827 } 4828 case MotionNotify: 4829 { 4830 if (event.xmotion.window != windows->image.id) 4831 break; 4832 /* 4833 Map and unmap Info widget as text cursor crosses its boundaries. 4834 */ 4835 x=event.xmotion.x; 4836 y=event.xmotion.y; 4837 if (windows->info.mapped != MagickFalse) 4838 { 4839 if ((x < (int) (windows->info.x+windows->info.width)) && 4840 (y < (int) (windows->info.y+windows->info.height))) 4841 (void) XWithdrawWindow(display,windows->info.id, 4842 windows->info.screen); 4843 } 4844 else 4845 if ((x > (int) (windows->info.x+windows->info.width)) || 4846 (y > (int) (windows->info.y+windows->info.height))) 4847 (void) XMapWindow(display,windows->info.id); 4848 crop_info.x=(ssize_t) windows->image.x+x; 4849 crop_info.y=(ssize_t) windows->image.y+y; 4850 break; 4851 } 4852 default: 4853 break; 4854 } 4855 } while ((state & ExitState) == 0); 4856 (void) XSelectInput(display,windows->image.id, 4857 windows->image.attributes.event_mask); 4858 if ((state & EscapeState) != 0) 4859 { 4860 /* 4861 User want to exit without cropping. 4862 */ 4863 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4864 (void) XFreeCursor(display,cursor); 4865 return(MagickTrue); 4866 } 4867 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4868 do 4869 { 4870 /* 4871 Size rectangle as pointer moves until the mouse button is released. 4872 */ 4873 x=(int) crop_info.x; 4874 y=(int) crop_info.y; 4875 crop_info.width=0; 4876 crop_info.height=0; 4877 state=DefaultState; 4878 do 4879 { 4880 highlight_info=crop_info; 4881 highlight_info.x=crop_info.x-windows->image.x; 4882 highlight_info.y=crop_info.y-windows->image.y; 4883 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4884 { 4885 /* 4886 Display info and draw cropping rectangle. 4887 */ 4888 if (windows->info.mapped == MagickFalse) 4889 (void) XMapWindow(display,windows->info.id); 4890 (void) FormatLocaleString(text,MaxTextExtent, 4891 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4892 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4893 XInfoWidget(display,windows,text); 4894 XHighlightRectangle(display,windows->image.id, 4895 windows->image.highlight_context,&highlight_info); 4896 } 4897 else 4898 if (windows->info.mapped != MagickFalse) 4899 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4900 /* 4901 Wait for next event. 4902 */ 4903 XScreenEvent(display,windows,&event); 4904 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4905 XHighlightRectangle(display,windows->image.id, 4906 windows->image.highlight_context,&highlight_info); 4907 switch (event.type) 4908 { 4909 case ButtonPress: 4910 { 4911 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4912 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4913 break; 4914 } 4915 case ButtonRelease: 4916 { 4917 /* 4918 User has committed to cropping rectangle. 4919 */ 4920 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4921 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4922 XSetCursorState(display,windows,MagickFalse); 4923 state|=ExitState; 4924 windows->command.data=0; 4925 (void) XCommandWidget(display,windows,RectifyModeMenu, 4926 (XEvent *) NULL); 4927 break; 4928 } 4929 case Expose: 4930 break; 4931 case MotionNotify: 4932 { 4933 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4934 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4935 } 4936 default: 4937 break; 4938 } 4939 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4940 ((state & ExitState) != 0)) 4941 { 4942 /* 4943 Check boundary conditions. 4944 */ 4945 if (crop_info.x < 0) 4946 crop_info.x=0; 4947 else 4948 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4949 crop_info.x=(ssize_t) windows->image.ximage->width; 4950 if ((int) crop_info.x < x) 4951 crop_info.width=(unsigned int) (x-crop_info.x); 4952 else 4953 { 4954 crop_info.width=(unsigned int) (crop_info.x-x); 4955 crop_info.x=(ssize_t) x; 4956 } 4957 if (crop_info.y < 0) 4958 crop_info.y=0; 4959 else 4960 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4961 crop_info.y=(ssize_t) windows->image.ximage->height; 4962 if ((int) crop_info.y < y) 4963 crop_info.height=(unsigned int) (y-crop_info.y); 4964 else 4965 { 4966 crop_info.height=(unsigned int) (crop_info.y-y); 4967 crop_info.y=(ssize_t) y; 4968 } 4969 } 4970 } while ((state & ExitState) == 0); 4971 /* 4972 Wait for user to grab a corner of the rectangle or press return. 4973 */ 4974 state=DefaultState; 4975 (void) XMapWindow(display,windows->info.id); 4976 do 4977 { 4978 if (windows->info.mapped != MagickFalse) 4979 { 4980 /* 4981 Display pointer position. 4982 */ 4983 (void) FormatLocaleString(text,MaxTextExtent, 4984 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4985 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4986 XInfoWidget(display,windows,text); 4987 } 4988 highlight_info=crop_info; 4989 highlight_info.x=crop_info.x-windows->image.x; 4990 highlight_info.y=crop_info.y-windows->image.y; 4991 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4992 { 4993 state|=EscapeState; 4994 state|=ExitState; 4995 break; 4996 } 4997 XHighlightRectangle(display,windows->image.id, 4998 windows->image.highlight_context,&highlight_info); 4999 XScreenEvent(display,windows,&event); 5000 if (event.xany.window == windows->command.id) 5001 { 5002 /* 5003 Select a command from the Command widget. 5004 */ 5005 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5006 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5007 (void) XSetFunction(display,windows->image.highlight_context, 5008 GXinvert); 5009 XHighlightRectangle(display,windows->image.id, 5010 windows->image.highlight_context,&highlight_info); 5011 if (id >= 0) 5012 switch (RectifyCommands[id]) 5013 { 5014 case RectifyCopyCommand: 5015 { 5016 state|=ExitState; 5017 break; 5018 } 5019 case RectifyHelpCommand: 5020 { 5021 (void) XSetFunction(display,windows->image.highlight_context, 5022 GXcopy); 5023 switch (mode) 5024 { 5025 case CopyMode: 5026 { 5027 XTextViewWidget(display,resource_info,windows,MagickFalse, 5028 "Help Viewer - Image Copy",ImageCopyHelp); 5029 break; 5030 } 5031 case CropMode: 5032 { 5033 XTextViewWidget(display,resource_info,windows,MagickFalse, 5034 "Help Viewer - Image Crop",ImageCropHelp); 5035 break; 5036 } 5037 case CutMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Cut",ImageCutHelp); 5041 break; 5042 } 5043 } 5044 (void) XSetFunction(display,windows->image.highlight_context, 5045 GXinvert); 5046 break; 5047 } 5048 case RectifyDismissCommand: 5049 { 5050 /* 5051 Prematurely exit. 5052 */ 5053 state|=EscapeState; 5054 state|=ExitState; 5055 break; 5056 } 5057 default: 5058 break; 5059 } 5060 continue; 5061 } 5062 XHighlightRectangle(display,windows->image.id, 5063 windows->image.highlight_context,&highlight_info); 5064 switch (event.type) 5065 { 5066 case ButtonPress: 5067 { 5068 if (event.xbutton.button != Button1) 5069 break; 5070 if (event.xbutton.window != windows->image.id) 5071 break; 5072 x=windows->image.x+event.xbutton.x; 5073 y=windows->image.y+event.xbutton.y; 5074 if ((x < (int) (crop_info.x+RoiDelta)) && 5075 (x > (int) (crop_info.x-RoiDelta)) && 5076 (y < (int) (crop_info.y+RoiDelta)) && 5077 (y > (int) (crop_info.y-RoiDelta))) 5078 { 5079 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5080 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5081 state|=UpdateConfigurationState; 5082 break; 5083 } 5084 if ((x < (int) (crop_info.x+RoiDelta)) && 5085 (x > (int) (crop_info.x-RoiDelta)) && 5086 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5087 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5088 { 5089 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5090 state|=UpdateConfigurationState; 5091 break; 5092 } 5093 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5094 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5095 (y < (int) (crop_info.y+RoiDelta)) && 5096 (y > (int) (crop_info.y-RoiDelta))) 5097 { 5098 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5099 state|=UpdateConfigurationState; 5100 break; 5101 } 5102 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5103 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5104 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5105 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5106 { 5107 state|=UpdateConfigurationState; 5108 break; 5109 } 5110 } 5111 case ButtonRelease: 5112 { 5113 if (event.xbutton.window == windows->pan.id) 5114 if ((highlight_info.x != crop_info.x-windows->image.x) || 5115 (highlight_info.y != crop_info.y-windows->image.y)) 5116 XHighlightRectangle(display,windows->image.id, 5117 windows->image.highlight_context,&highlight_info); 5118 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5119 event.xbutton.time); 5120 break; 5121 } 5122 case Expose: 5123 { 5124 if (event.xexpose.window == windows->image.id) 5125 if (event.xexpose.count == 0) 5126 { 5127 event.xexpose.x=(int) highlight_info.x; 5128 event.xexpose.y=(int) highlight_info.y; 5129 event.xexpose.width=(int) highlight_info.width; 5130 event.xexpose.height=(int) highlight_info.height; 5131 XRefreshWindow(display,&windows->image,&event); 5132 } 5133 if (event.xexpose.window == windows->info.id) 5134 if (event.xexpose.count == 0) 5135 XInfoWidget(display,windows,text); 5136 break; 5137 } 5138 case KeyPress: 5139 { 5140 if (event.xkey.window != windows->image.id) 5141 break; 5142 /* 5143 Respond to a user key press. 5144 */ 5145 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5146 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5147 switch ((int) key_symbol) 5148 { 5149 case XK_Escape: 5150 case XK_F20: 5151 state|=EscapeState; 5152 case XK_Return: 5153 { 5154 state|=ExitState; 5155 break; 5156 } 5157 case XK_Home: 5158 case XK_KP_Home: 5159 { 5160 crop_info.x=(ssize_t) (windows->image.width/2L- 5161 crop_info.width/2L); 5162 crop_info.y=(ssize_t) (windows->image.height/2L- 5163 crop_info.height/2L); 5164 break; 5165 } 5166 case XK_Left: 5167 case XK_KP_Left: 5168 { 5169 crop_info.x--; 5170 break; 5171 } 5172 case XK_Up: 5173 case XK_KP_Up: 5174 case XK_Next: 5175 { 5176 crop_info.y--; 5177 break; 5178 } 5179 case XK_Right: 5180 case XK_KP_Right: 5181 { 5182 crop_info.x++; 5183 break; 5184 } 5185 case XK_Prior: 5186 case XK_Down: 5187 case XK_KP_Down: 5188 { 5189 crop_info.y++; 5190 break; 5191 } 5192 case XK_F1: 5193 case XK_Help: 5194 { 5195 (void) XSetFunction(display,windows->image.highlight_context, 5196 GXcopy); 5197 switch (mode) 5198 { 5199 case CopyMode: 5200 { 5201 XTextViewWidget(display,resource_info,windows,MagickFalse, 5202 "Help Viewer - Image Copy",ImageCopyHelp); 5203 break; 5204 } 5205 case CropMode: 5206 { 5207 XTextViewWidget(display,resource_info,windows,MagickFalse, 5208 "Help Viewer - Image Cropg",ImageCropHelp); 5209 break; 5210 } 5211 case CutMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Cutg",ImageCutHelp); 5215 break; 5216 } 5217 } 5218 (void) XSetFunction(display,windows->image.highlight_context, 5219 GXinvert); 5220 break; 5221 } 5222 default: 5223 { 5224 (void) XBell(display,0); 5225 break; 5226 } 5227 } 5228 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5229 event.xkey.time); 5230 break; 5231 } 5232 case KeyRelease: 5233 break; 5234 case MotionNotify: 5235 { 5236 if (event.xmotion.window != windows->image.id) 5237 break; 5238 /* 5239 Map and unmap Info widget as text cursor crosses its boundaries. 5240 */ 5241 x=event.xmotion.x; 5242 y=event.xmotion.y; 5243 if (windows->info.mapped != MagickFalse) 5244 { 5245 if ((x < (int) (windows->info.x+windows->info.width)) && 5246 (y < (int) (windows->info.y+windows->info.height))) 5247 (void) XWithdrawWindow(display,windows->info.id, 5248 windows->info.screen); 5249 } 5250 else 5251 if ((x > (int) (windows->info.x+windows->info.width)) || 5252 (y > (int) (windows->info.y+windows->info.height))) 5253 (void) XMapWindow(display,windows->info.id); 5254 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5255 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5256 break; 5257 } 5258 case SelectionRequest: 5259 { 5260 XSelectionEvent 5261 notify; 5262 5263 XSelectionRequestEvent 5264 *request; 5265 5266 /* 5267 Set primary selection. 5268 */ 5269 (void) FormatLocaleString(text,MaxTextExtent, 5270 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5271 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5272 request=(&(event.xselectionrequest)); 5273 (void) XChangeProperty(request->display,request->requestor, 5274 request->property,request->target,8,PropModeReplace, 5275 (unsigned char *) text,(int) strlen(text)); 5276 notify.type=SelectionNotify; 5277 notify.display=request->display; 5278 notify.requestor=request->requestor; 5279 notify.selection=request->selection; 5280 notify.target=request->target; 5281 notify.time=request->time; 5282 if (request->property == None) 5283 notify.property=request->target; 5284 else 5285 notify.property=request->property; 5286 (void) XSendEvent(request->display,request->requestor,False,0, 5287 (XEvent *) ¬ify); 5288 } 5289 default: 5290 break; 5291 } 5292 if ((state & UpdateConfigurationState) != 0) 5293 { 5294 (void) XPutBackEvent(display,&event); 5295 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5296 break; 5297 } 5298 } while ((state & ExitState) == 0); 5299 } while ((state & ExitState) == 0); 5300 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5301 XSetCursorState(display,windows,MagickFalse); 5302 if ((state & EscapeState) != 0) 5303 return(MagickTrue); 5304 if (mode == CropMode) 5305 if (((int) crop_info.width != windows->image.ximage->width) || 5306 ((int) crop_info.height != windows->image.ximage->height)) 5307 { 5308 /* 5309 Reconfigure Image window as defined by cropping rectangle. 5310 */ 5311 XSetCropGeometry(display,windows,&crop_info,image); 5312 windows->image.window_changes.width=(int) crop_info.width; 5313 windows->image.window_changes.height=(int) crop_info.height; 5314 (void) XConfigureImage(display,resource_info,windows,image,exception); 5315 return(MagickTrue); 5316 } 5317 /* 5318 Copy image before applying image transforms. 5319 */ 5320 XSetCursorState(display,windows,MagickTrue); 5321 XCheckRefreshWindows(display,windows); 5322 width=(unsigned int) image->columns; 5323 height=(unsigned int) image->rows; 5324 x=0; 5325 y=0; 5326 if (windows->image.crop_geometry != (char *) NULL) 5327 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5328 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5329 crop_info.x+=x; 5330 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5331 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5332 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5333 crop_info.y+=y; 5334 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5335 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5336 crop_image=CropImage(image,&crop_info,exception); 5337 XSetCursorState(display,windows,MagickFalse); 5338 if (crop_image == (Image *) NULL) 5339 return(MagickFalse); 5340 if (resource_info->copy_image != (Image *) NULL) 5341 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5342 resource_info->copy_image=crop_image; 5343 if (mode == CopyMode) 5344 { 5345 (void) XConfigureImage(display,resource_info,windows,image,exception); 5346 return(MagickTrue); 5347 } 5348 /* 5349 Cut image. 5350 */ 5351 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5352 return(MagickFalse); 5353 image->matte=MagickTrue; 5354 image_view=AcquireCacheView(image); 5355 for (y=0; y < (int) crop_info.height; y++) 5356 { 5357 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5358 crop_info.width,1,exception); 5359 if (q == (Quantum *) NULL) 5360 break; 5361 for (x=0; x < (int) crop_info.width; x++) 5362 { 5363 SetPixelAlpha(image,TransparentAlpha,q); 5364 q+=GetPixelChannels(image); 5365 } 5366 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5367 break; 5368 } 5369 image_view=DestroyCacheView(image_view); 5370 /* 5371 Update image configuration. 5372 */ 5373 XConfigureImageColormap(display,resource_info,windows,image); 5374 (void) XConfigureImage(display,resource_info,windows,image,exception); 5375 return(MagickTrue); 5376} 5377 5378/* 5379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5380% % 5381% % 5382% % 5383+ X D r a w I m a g e % 5384% % 5385% % 5386% % 5387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5388% 5389% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5390% the image. 5391% 5392% The format of the XDrawEditImage method is: 5393% 5394% MagickBooleanType XDrawEditImage(Display *display, 5395% XResourceInfo *resource_info,XWindows *windows,Image **image, 5396% ExceptionInfo *exception) 5397% 5398% A description of each parameter follows: 5399% 5400% o display: Specifies a connection to an X server; returned from 5401% XOpenDisplay. 5402% 5403% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5404% 5405% o windows: Specifies a pointer to a XWindows structure. 5406% 5407% o image: the image. 5408% 5409% o exception: return any errors or warnings in this structure. 5410% 5411*/ 5412static MagickBooleanType XDrawEditImage(Display *display, 5413 XResourceInfo *resource_info,XWindows *windows,Image **image, 5414 ExceptionInfo *exception) 5415{ 5416 static const char 5417 *DrawMenu[] = 5418 { 5419 "Element", 5420 "Color", 5421 "Stipple", 5422 "Width", 5423 "Undo", 5424 "Help", 5425 "Dismiss", 5426 (char *) NULL 5427 }; 5428 5429 static ElementType 5430 element = PointElement; 5431 5432 static const ModeType 5433 DrawCommands[] = 5434 { 5435 DrawElementCommand, 5436 DrawColorCommand, 5437 DrawStippleCommand, 5438 DrawWidthCommand, 5439 DrawUndoCommand, 5440 DrawHelpCommand, 5441 DrawDismissCommand 5442 }; 5443 5444 static Pixmap 5445 stipple = (Pixmap) NULL; 5446 5447 static unsigned int 5448 pen_id = 0, 5449 line_width = 1; 5450 5451 char 5452 command[MaxTextExtent], 5453 text[MaxTextExtent]; 5454 5455 Cursor 5456 cursor; 5457 5458 int 5459 entry, 5460 id, 5461 number_coordinates, 5462 x, 5463 y; 5464 5465 MagickRealType 5466 degrees; 5467 5468 MagickStatusType 5469 status; 5470 5471 RectangleInfo 5472 rectangle_info; 5473 5474 register int 5475 i; 5476 5477 unsigned int 5478 distance, 5479 height, 5480 max_coordinates, 5481 width; 5482 5483 size_t 5484 state; 5485 5486 Window 5487 root_window; 5488 5489 XDrawInfo 5490 draw_info; 5491 5492 XEvent 5493 event; 5494 5495 XPoint 5496 *coordinate_info; 5497 5498 XSegment 5499 line_info; 5500 5501 /* 5502 Allocate polygon info. 5503 */ 5504 max_coordinates=2048; 5505 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5506 sizeof(*coordinate_info)); 5507 if (coordinate_info == (XPoint *) NULL) 5508 { 5509 (void) ThrowMagickException(exception,GetMagickModule(), 5510 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5511 return(MagickFalse); 5512 } 5513 /* 5514 Map Command widget. 5515 */ 5516 (void) CloneString(&windows->command.name,"Draw"); 5517 windows->command.data=4; 5518 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5519 (void) XMapRaised(display,windows->command.id); 5520 XClientMessage(display,windows->image.id,windows->im_protocols, 5521 windows->im_update_widget,CurrentTime); 5522 /* 5523 Wait for first button press. 5524 */ 5525 root_window=XRootWindow(display,XDefaultScreen(display)); 5526 draw_info.stencil=OpaqueStencil; 5527 status=MagickTrue; 5528 cursor=XCreateFontCursor(display,XC_tcross); 5529 for ( ; ; ) 5530 { 5531 XQueryPosition(display,windows->image.id,&x,&y); 5532 (void) XSelectInput(display,windows->image.id, 5533 windows->image.attributes.event_mask | PointerMotionMask); 5534 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5535 state=DefaultState; 5536 do 5537 { 5538 if (windows->info.mapped != MagickFalse) 5539 { 5540 /* 5541 Display pointer position. 5542 */ 5543 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5544 x+windows->image.x,y+windows->image.y); 5545 XInfoWidget(display,windows,text); 5546 } 5547 /* 5548 Wait for next event. 5549 */ 5550 XScreenEvent(display,windows,&event); 5551 if (event.xany.window == windows->command.id) 5552 { 5553 /* 5554 Select a command from the Command widget. 5555 */ 5556 id=XCommandWidget(display,windows,DrawMenu,&event); 5557 if (id < 0) 5558 continue; 5559 switch (DrawCommands[id]) 5560 { 5561 case DrawElementCommand: 5562 { 5563 static const char 5564 *Elements[] = 5565 { 5566 "point", 5567 "line", 5568 "rectangle", 5569 "fill rectangle", 5570 "circle", 5571 "fill circle", 5572 "ellipse", 5573 "fill ellipse", 5574 "polygon", 5575 "fill polygon", 5576 (char *) NULL, 5577 }; 5578 5579 /* 5580 Select a command from the pop-up menu. 5581 */ 5582 element=(ElementType) (XMenuWidget(display,windows, 5583 DrawMenu[id],Elements,command)+1); 5584 break; 5585 } 5586 case DrawColorCommand: 5587 { 5588 const char 5589 *ColorMenu[MaxNumberPens+1]; 5590 5591 int 5592 pen_number; 5593 5594 MagickBooleanType 5595 transparent; 5596 5597 XColor 5598 color; 5599 5600 /* 5601 Initialize menu selections. 5602 */ 5603 for (i=0; i < (int) (MaxNumberPens-2); i++) 5604 ColorMenu[i]=resource_info->pen_colors[i]; 5605 ColorMenu[MaxNumberPens-2]="transparent"; 5606 ColorMenu[MaxNumberPens-1]="Browser..."; 5607 ColorMenu[MaxNumberPens]=(char *) NULL; 5608 /* 5609 Select a pen color from the pop-up menu. 5610 */ 5611 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5612 (const char **) ColorMenu,command); 5613 if (pen_number < 0) 5614 break; 5615 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5616 MagickFalse; 5617 if (transparent != MagickFalse) 5618 { 5619 draw_info.stencil=TransparentStencil; 5620 break; 5621 } 5622 if (pen_number == (MaxNumberPens-1)) 5623 { 5624 static char 5625 color_name[MaxTextExtent] = "gray"; 5626 5627 /* 5628 Select a pen color from a dialog. 5629 */ 5630 resource_info->pen_colors[pen_number]=color_name; 5631 XColorBrowserWidget(display,windows,"Select",color_name); 5632 if (*color_name == '\0') 5633 break; 5634 } 5635 /* 5636 Set pen color. 5637 */ 5638 (void) XParseColor(display,windows->map_info->colormap, 5639 resource_info->pen_colors[pen_number],&color); 5640 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5641 (unsigned int) MaxColors,&color); 5642 windows->pixel_info->pen_colors[pen_number]=color; 5643 pen_id=(unsigned int) pen_number; 5644 draw_info.stencil=OpaqueStencil; 5645 break; 5646 } 5647 case DrawStippleCommand: 5648 { 5649 Image 5650 *stipple_image; 5651 5652 ImageInfo 5653 *image_info; 5654 5655 int 5656 status; 5657 5658 static char 5659 filename[MaxTextExtent] = "\0"; 5660 5661 static const char 5662 *StipplesMenu[] = 5663 { 5664 "Brick", 5665 "Diagonal", 5666 "Scales", 5667 "Vertical", 5668 "Wavy", 5669 "Translucent", 5670 "Opaque", 5671 (char *) NULL, 5672 (char *) NULL, 5673 }; 5674 5675 /* 5676 Select a command from the pop-up menu. 5677 */ 5678 StipplesMenu[7]="Open..."; 5679 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5680 command); 5681 if (entry < 0) 5682 break; 5683 if (stipple != (Pixmap) NULL) 5684 (void) XFreePixmap(display,stipple); 5685 stipple=(Pixmap) NULL; 5686 if (entry != 7) 5687 { 5688 switch (entry) 5689 { 5690 case 0: 5691 { 5692 stipple=XCreateBitmapFromData(display,root_window, 5693 (char *) BricksBitmap,BricksWidth,BricksHeight); 5694 break; 5695 } 5696 case 1: 5697 { 5698 stipple=XCreateBitmapFromData(display,root_window, 5699 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5700 break; 5701 } 5702 case 2: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5706 break; 5707 } 5708 case 3: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5712 break; 5713 } 5714 case 4: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) WavyBitmap,WavyWidth,WavyHeight); 5718 break; 5719 } 5720 case 5: 5721 { 5722 stipple=XCreateBitmapFromData(display,root_window, 5723 (char *) HighlightBitmap,HighlightWidth, 5724 HighlightHeight); 5725 break; 5726 } 5727 case 6: 5728 default: 5729 { 5730 stipple=XCreateBitmapFromData(display,root_window, 5731 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5732 break; 5733 } 5734 } 5735 break; 5736 } 5737 XFileBrowserWidget(display,windows,"Stipple",filename); 5738 if (*filename == '\0') 5739 break; 5740 /* 5741 Read image. 5742 */ 5743 XSetCursorState(display,windows,MagickTrue); 5744 XCheckRefreshWindows(display,windows); 5745 image_info=AcquireImageInfo(); 5746 (void) CopyMagickString(image_info->filename,filename, 5747 MaxTextExtent); 5748 stipple_image=ReadImage(image_info,exception); 5749 CatchException(exception); 5750 XSetCursorState(display,windows,MagickFalse); 5751 if (stipple_image == (Image *) NULL) 5752 break; 5753 (void) AcquireUniqueFileResource(filename); 5754 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5755 "xbm:%s",filename); 5756 (void) WriteImage(image_info,stipple_image,exception); 5757 stipple_image=DestroyImage(stipple_image); 5758 image_info=DestroyImageInfo(image_info); 5759 status=XReadBitmapFile(display,root_window,filename,&width, 5760 &height,&stipple,&x,&y); 5761 (void) RelinquishUniqueFileResource(filename); 5762 if ((status != BitmapSuccess) != 0) 5763 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5764 filename); 5765 break; 5766 } 5767 case DrawWidthCommand: 5768 { 5769 static char 5770 width[MaxTextExtent] = "0"; 5771 5772 static const char 5773 *WidthsMenu[] = 5774 { 5775 "1", 5776 "2", 5777 "4", 5778 "8", 5779 "16", 5780 "Dialog...", 5781 (char *) NULL, 5782 }; 5783 5784 /* 5785 Select a command from the pop-up menu. 5786 */ 5787 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5788 command); 5789 if (entry < 0) 5790 break; 5791 if (entry != 5) 5792 { 5793 line_width=(unsigned int) StringToUnsignedLong( 5794 WidthsMenu[entry]); 5795 break; 5796 } 5797 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5798 width); 5799 if (*width == '\0') 5800 break; 5801 line_width=(unsigned int) StringToUnsignedLong(width); 5802 break; 5803 } 5804 case DrawUndoCommand: 5805 { 5806 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5807 image,exception); 5808 break; 5809 } 5810 case DrawHelpCommand: 5811 { 5812 XTextViewWidget(display,resource_info,windows,MagickFalse, 5813 "Help Viewer - Image Rotation",ImageDrawHelp); 5814 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5815 break; 5816 } 5817 case DrawDismissCommand: 5818 { 5819 /* 5820 Prematurely exit. 5821 */ 5822 state|=EscapeState; 5823 state|=ExitState; 5824 break; 5825 } 5826 default: 5827 break; 5828 } 5829 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5830 continue; 5831 } 5832 switch (event.type) 5833 { 5834 case ButtonPress: 5835 { 5836 if (event.xbutton.button != Button1) 5837 break; 5838 if (event.xbutton.window != windows->image.id) 5839 break; 5840 /* 5841 exit loop. 5842 */ 5843 x=event.xbutton.x; 5844 y=event.xbutton.y; 5845 state|=ExitState; 5846 break; 5847 } 5848 case ButtonRelease: 5849 break; 5850 case Expose: 5851 break; 5852 case KeyPress: 5853 { 5854 KeySym 5855 key_symbol; 5856 5857 if (event.xkey.window != windows->image.id) 5858 break; 5859 /* 5860 Respond to a user key press. 5861 */ 5862 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5863 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5864 switch ((int) key_symbol) 5865 { 5866 case XK_Escape: 5867 case XK_F20: 5868 { 5869 /* 5870 Prematurely exit. 5871 */ 5872 state|=EscapeState; 5873 state|=ExitState; 5874 break; 5875 } 5876 case XK_F1: 5877 case XK_Help: 5878 { 5879 XTextViewWidget(display,resource_info,windows,MagickFalse, 5880 "Help Viewer - Image Rotation",ImageDrawHelp); 5881 break; 5882 } 5883 default: 5884 { 5885 (void) XBell(display,0); 5886 break; 5887 } 5888 } 5889 break; 5890 } 5891 case MotionNotify: 5892 { 5893 /* 5894 Map and unmap Info widget as text cursor crosses its boundaries. 5895 */ 5896 x=event.xmotion.x; 5897 y=event.xmotion.y; 5898 if (windows->info.mapped != MagickFalse) 5899 { 5900 if ((x < (int) (windows->info.x+windows->info.width)) && 5901 (y < (int) (windows->info.y+windows->info.height))) 5902 (void) XWithdrawWindow(display,windows->info.id, 5903 windows->info.screen); 5904 } 5905 else 5906 if ((x > (int) (windows->info.x+windows->info.width)) || 5907 (y > (int) (windows->info.y+windows->info.height))) 5908 (void) XMapWindow(display,windows->info.id); 5909 break; 5910 } 5911 } 5912 } while ((state & ExitState) == 0); 5913 (void) XSelectInput(display,windows->image.id, 5914 windows->image.attributes.event_mask); 5915 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5916 if ((state & EscapeState) != 0) 5917 break; 5918 /* 5919 Draw element as pointer moves until the button is released. 5920 */ 5921 distance=0; 5922 degrees=0.0; 5923 line_info.x1=x; 5924 line_info.y1=y; 5925 line_info.x2=x; 5926 line_info.y2=y; 5927 rectangle_info.x=(ssize_t) x; 5928 rectangle_info.y=(ssize_t) y; 5929 rectangle_info.width=0; 5930 rectangle_info.height=0; 5931 number_coordinates=1; 5932 coordinate_info->x=x; 5933 coordinate_info->y=y; 5934 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5935 state=DefaultState; 5936 do 5937 { 5938 switch (element) 5939 { 5940 case PointElement: 5941 default: 5942 { 5943 if (number_coordinates > 1) 5944 { 5945 (void) XDrawLines(display,windows->image.id, 5946 windows->image.highlight_context,coordinate_info, 5947 number_coordinates,CoordModeOrigin); 5948 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5949 coordinate_info[number_coordinates-1].x, 5950 coordinate_info[number_coordinates-1].y); 5951 XInfoWidget(display,windows,text); 5952 } 5953 break; 5954 } 5955 case LineElement: 5956 { 5957 if (distance > 9) 5958 { 5959 /* 5960 Display angle of the line. 5961 */ 5962 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5963 line_info.y1),(double) (line_info.x2-line_info.x1))); 5964 (void) FormatLocaleString(text,MaxTextExtent," %g", 5965 (double) degrees); 5966 XInfoWidget(display,windows,text); 5967 XHighlightLine(display,windows->image.id, 5968 windows->image.highlight_context,&line_info); 5969 } 5970 else 5971 if (windows->info.mapped != MagickFalse) 5972 (void) XWithdrawWindow(display,windows->info.id, 5973 windows->info.screen); 5974 break; 5975 } 5976 case RectangleElement: 5977 case FillRectangleElement: 5978 { 5979 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5980 { 5981 /* 5982 Display info and draw drawing rectangle. 5983 */ 5984 (void) FormatLocaleString(text,MaxTextExtent, 5985 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5986 (double) rectangle_info.height,(double) rectangle_info.x, 5987 (double) rectangle_info.y); 5988 XInfoWidget(display,windows,text); 5989 XHighlightRectangle(display,windows->image.id, 5990 windows->image.highlight_context,&rectangle_info); 5991 } 5992 else 5993 if (windows->info.mapped != MagickFalse) 5994 (void) XWithdrawWindow(display,windows->info.id, 5995 windows->info.screen); 5996 break; 5997 } 5998 case CircleElement: 5999 case FillCircleElement: 6000 case EllipseElement: 6001 case FillEllipseElement: 6002 { 6003 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6004 { 6005 /* 6006 Display info and draw drawing rectangle. 6007 */ 6008 (void) FormatLocaleString(text,MaxTextExtent, 6009 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6010 (double) rectangle_info.height,(double) rectangle_info.x, 6011 (double) rectangle_info.y); 6012 XInfoWidget(display,windows,text); 6013 XHighlightEllipse(display,windows->image.id, 6014 windows->image.highlight_context,&rectangle_info); 6015 } 6016 else 6017 if (windows->info.mapped != MagickFalse) 6018 (void) XWithdrawWindow(display,windows->info.id, 6019 windows->info.screen); 6020 break; 6021 } 6022 case PolygonElement: 6023 case FillPolygonElement: 6024 { 6025 if (number_coordinates > 1) 6026 (void) XDrawLines(display,windows->image.id, 6027 windows->image.highlight_context,coordinate_info, 6028 number_coordinates,CoordModeOrigin); 6029 if (distance > 9) 6030 { 6031 /* 6032 Display angle of the line. 6033 */ 6034 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6035 line_info.y1),(double) (line_info.x2-line_info.x1))); 6036 (void) FormatLocaleString(text,MaxTextExtent," %g", 6037 (double) degrees); 6038 XInfoWidget(display,windows,text); 6039 XHighlightLine(display,windows->image.id, 6040 windows->image.highlight_context,&line_info); 6041 } 6042 else 6043 if (windows->info.mapped != MagickFalse) 6044 (void) XWithdrawWindow(display,windows->info.id, 6045 windows->info.screen); 6046 break; 6047 } 6048 } 6049 /* 6050 Wait for next event. 6051 */ 6052 XScreenEvent(display,windows,&event); 6053 switch (element) 6054 { 6055 case PointElement: 6056 default: 6057 { 6058 if (number_coordinates > 1) 6059 (void) XDrawLines(display,windows->image.id, 6060 windows->image.highlight_context,coordinate_info, 6061 number_coordinates,CoordModeOrigin); 6062 break; 6063 } 6064 case LineElement: 6065 { 6066 if (distance > 9) 6067 XHighlightLine(display,windows->image.id, 6068 windows->image.highlight_context,&line_info); 6069 break; 6070 } 6071 case RectangleElement: 6072 case FillRectangleElement: 6073 { 6074 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6075 XHighlightRectangle(display,windows->image.id, 6076 windows->image.highlight_context,&rectangle_info); 6077 break; 6078 } 6079 case CircleElement: 6080 case FillCircleElement: 6081 case EllipseElement: 6082 case FillEllipseElement: 6083 { 6084 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6085 XHighlightEllipse(display,windows->image.id, 6086 windows->image.highlight_context,&rectangle_info); 6087 break; 6088 } 6089 case PolygonElement: 6090 case FillPolygonElement: 6091 { 6092 if (number_coordinates > 1) 6093 (void) XDrawLines(display,windows->image.id, 6094 windows->image.highlight_context,coordinate_info, 6095 number_coordinates,CoordModeOrigin); 6096 if (distance > 9) 6097 XHighlightLine(display,windows->image.id, 6098 windows->image.highlight_context,&line_info); 6099 break; 6100 } 6101 } 6102 switch (event.type) 6103 { 6104 case ButtonPress: 6105 break; 6106 case ButtonRelease: 6107 { 6108 /* 6109 User has committed to element. 6110 */ 6111 line_info.x2=event.xbutton.x; 6112 line_info.y2=event.xbutton.y; 6113 rectangle_info.x=(ssize_t) event.xbutton.x; 6114 rectangle_info.y=(ssize_t) event.xbutton.y; 6115 coordinate_info[number_coordinates].x=event.xbutton.x; 6116 coordinate_info[number_coordinates].y=event.xbutton.y; 6117 if (((element != PolygonElement) && 6118 (element != FillPolygonElement)) || (distance <= 9)) 6119 { 6120 state|=ExitState; 6121 break; 6122 } 6123 number_coordinates++; 6124 if (number_coordinates < (int) max_coordinates) 6125 { 6126 line_info.x1=event.xbutton.x; 6127 line_info.y1=event.xbutton.y; 6128 break; 6129 } 6130 max_coordinates<<=1; 6131 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6132 max_coordinates,sizeof(*coordinate_info)); 6133 if (coordinate_info == (XPoint *) NULL) 6134 (void) ThrowMagickException(exception,GetMagickModule(), 6135 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6136 break; 6137 } 6138 case Expose: 6139 break; 6140 case MotionNotify: 6141 { 6142 if (event.xmotion.window != windows->image.id) 6143 break; 6144 if (element != PointElement) 6145 { 6146 line_info.x2=event.xmotion.x; 6147 line_info.y2=event.xmotion.y; 6148 rectangle_info.x=(ssize_t) event.xmotion.x; 6149 rectangle_info.y=(ssize_t) event.xmotion.y; 6150 break; 6151 } 6152 coordinate_info[number_coordinates].x=event.xbutton.x; 6153 coordinate_info[number_coordinates].y=event.xbutton.y; 6154 number_coordinates++; 6155 if (number_coordinates < (int) max_coordinates) 6156 break; 6157 max_coordinates<<=1; 6158 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6159 max_coordinates,sizeof(*coordinate_info)); 6160 if (coordinate_info == (XPoint *) NULL) 6161 (void) ThrowMagickException(exception,GetMagickModule(), 6162 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6163 break; 6164 } 6165 default: 6166 break; 6167 } 6168 /* 6169 Check boundary conditions. 6170 */ 6171 if (line_info.x2 < 0) 6172 line_info.x2=0; 6173 else 6174 if (line_info.x2 > (int) windows->image.width) 6175 line_info.x2=(short) windows->image.width; 6176 if (line_info.y2 < 0) 6177 line_info.y2=0; 6178 else 6179 if (line_info.y2 > (int) windows->image.height) 6180 line_info.y2=(short) windows->image.height; 6181 distance=(unsigned int) 6182 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6183 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6184 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6185 ((state & ExitState) != 0)) 6186 { 6187 if (rectangle_info.x < 0) 6188 rectangle_info.x=0; 6189 else 6190 if (rectangle_info.x > (ssize_t) windows->image.width) 6191 rectangle_info.x=(ssize_t) windows->image.width; 6192 if ((int) rectangle_info.x < x) 6193 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6194 else 6195 { 6196 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6197 rectangle_info.x=(ssize_t) x; 6198 } 6199 if (rectangle_info.y < 0) 6200 rectangle_info.y=0; 6201 else 6202 if (rectangle_info.y > (ssize_t) windows->image.height) 6203 rectangle_info.y=(ssize_t) windows->image.height; 6204 if ((int) rectangle_info.y < y) 6205 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6206 else 6207 { 6208 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6209 rectangle_info.y=(ssize_t) y; 6210 } 6211 } 6212 } while ((state & ExitState) == 0); 6213 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6214 if ((element == PointElement) || (element == PolygonElement) || 6215 (element == FillPolygonElement)) 6216 { 6217 /* 6218 Determine polygon bounding box. 6219 */ 6220 rectangle_info.x=(ssize_t) coordinate_info->x; 6221 rectangle_info.y=(ssize_t) coordinate_info->y; 6222 x=coordinate_info->x; 6223 y=coordinate_info->y; 6224 for (i=1; i < number_coordinates; i++) 6225 { 6226 if (coordinate_info[i].x > x) 6227 x=coordinate_info[i].x; 6228 if (coordinate_info[i].y > y) 6229 y=coordinate_info[i].y; 6230 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6231 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6232 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6233 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6234 } 6235 rectangle_info.width=(size_t) (x-rectangle_info.x); 6236 rectangle_info.height=(size_t) (y-rectangle_info.y); 6237 for (i=0; i < number_coordinates; i++) 6238 { 6239 coordinate_info[i].x-=rectangle_info.x; 6240 coordinate_info[i].y-=rectangle_info.y; 6241 } 6242 } 6243 else 6244 if (distance <= 9) 6245 continue; 6246 else 6247 if ((element == RectangleElement) || 6248 (element == CircleElement) || (element == EllipseElement)) 6249 { 6250 rectangle_info.width--; 6251 rectangle_info.height--; 6252 } 6253 /* 6254 Drawing is relative to image configuration. 6255 */ 6256 draw_info.x=(int) rectangle_info.x; 6257 draw_info.y=(int) rectangle_info.y; 6258 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6259 image,exception); 6260 width=(unsigned int) (*image)->columns; 6261 height=(unsigned int) (*image)->rows; 6262 x=0; 6263 y=0; 6264 if (windows->image.crop_geometry != (char *) NULL) 6265 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6266 draw_info.x+=windows->image.x-(line_width/2); 6267 if (draw_info.x < 0) 6268 draw_info.x=0; 6269 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6270 draw_info.y+=windows->image.y-(line_width/2); 6271 if (draw_info.y < 0) 6272 draw_info.y=0; 6273 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6274 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6275 if (draw_info.width > (unsigned int) (*image)->columns) 6276 draw_info.width=(unsigned int) (*image)->columns; 6277 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6278 if (draw_info.height > (unsigned int) (*image)->rows) 6279 draw_info.height=(unsigned int) (*image)->rows; 6280 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6281 width*draw_info.width/windows->image.ximage->width, 6282 height*draw_info.height/windows->image.ximage->height, 6283 draw_info.x+x,draw_info.y+y); 6284 /* 6285 Initialize drawing attributes. 6286 */ 6287 draw_info.degrees=0.0; 6288 draw_info.element=element; 6289 draw_info.stipple=stipple; 6290 draw_info.line_width=line_width; 6291 draw_info.line_info=line_info; 6292 if (line_info.x1 > (int) (line_width/2)) 6293 draw_info.line_info.x1=(short) line_width/2; 6294 if (line_info.y1 > (int) (line_width/2)) 6295 draw_info.line_info.y1=(short) line_width/2; 6296 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6297 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6298 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6299 { 6300 draw_info.line_info.x2=(-draw_info.line_info.x2); 6301 draw_info.line_info.y2=(-draw_info.line_info.y2); 6302 } 6303 if (draw_info.line_info.x2 < 0) 6304 { 6305 draw_info.line_info.x2=(-draw_info.line_info.x2); 6306 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6307 } 6308 if (draw_info.line_info.y2 < 0) 6309 { 6310 draw_info.line_info.y2=(-draw_info.line_info.y2); 6311 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6312 } 6313 draw_info.rectangle_info=rectangle_info; 6314 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6315 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6316 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6317 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6318 draw_info.number_coordinates=(unsigned int) number_coordinates; 6319 draw_info.coordinate_info=coordinate_info; 6320 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6321 /* 6322 Draw element on image. 6323 */ 6324 XSetCursorState(display,windows,MagickTrue); 6325 XCheckRefreshWindows(display,windows); 6326 status=XDrawImage(display,windows->pixel_info,&draw_info,*image); 6327 XSetCursorState(display,windows,MagickFalse); 6328 /* 6329 Update image colormap and return to image drawing. 6330 */ 6331 XConfigureImageColormap(display,resource_info,windows,*image); 6332 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6333 } 6334 XSetCursorState(display,windows,MagickFalse); 6335 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6336 return(status != 0 ? MagickTrue : MagickFalse); 6337} 6338 6339/* 6340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6341% % 6342% % 6343% % 6344+ X D r a w P a n R e c t a n g l e % 6345% % 6346% % 6347% % 6348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6349% 6350% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6351% displays a zoom image and the rectangle shows which portion of the image is 6352% displayed in the Image window. 6353% 6354% The format of the XDrawPanRectangle method is: 6355% 6356% XDrawPanRectangle(Display *display,XWindows *windows) 6357% 6358% A description of each parameter follows: 6359% 6360% o display: Specifies a connection to an X server; returned from 6361% XOpenDisplay. 6362% 6363% o windows: Specifies a pointer to a XWindows structure. 6364% 6365*/ 6366static void XDrawPanRectangle(Display *display,XWindows *windows) 6367{ 6368 MagickRealType 6369 scale_factor; 6370 6371 RectangleInfo 6372 highlight_info; 6373 6374 /* 6375 Determine dimensions of the panning rectangle. 6376 */ 6377 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6378 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6379 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6380 scale_factor=(MagickRealType) 6381 windows->pan.height/windows->image.ximage->height; 6382 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6383 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6384 /* 6385 Display the panning rectangle. 6386 */ 6387 (void) XClearWindow(display,windows->pan.id); 6388 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6389 &highlight_info); 6390} 6391 6392/* 6393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6394% % 6395% % 6396% % 6397+ X I m a g e C a c h e % 6398% % 6399% % 6400% % 6401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6402% 6403% XImageCache() handles the creation, manipulation, and destruction of the 6404% image cache (undo and redo buffers). 6405% 6406% The format of the XImageCache method is: 6407% 6408% void XImageCache(Display *display,XResourceInfo *resource_info, 6409% XWindows *windows,const CommandType command,Image **image, 6410% ExceptionInfo *exception) 6411% 6412% A description of each parameter follows: 6413% 6414% o display: Specifies a connection to an X server; returned from 6415% XOpenDisplay. 6416% 6417% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6418% 6419% o windows: Specifies a pointer to a XWindows structure. 6420% 6421% o command: Specifies a command to perform. 6422% 6423% o image: the image; XImageCache may transform the image and return a new 6424% image pointer. 6425% 6426% o exception: return any errors or warnings in this structure. 6427% 6428*/ 6429static void XImageCache(Display *display,XResourceInfo *resource_info, 6430 XWindows *windows,const CommandType command,Image **image, 6431 ExceptionInfo *exception) 6432{ 6433 Image 6434 *cache_image; 6435 6436 static Image 6437 *redo_image = (Image *) NULL, 6438 *undo_image = (Image *) NULL; 6439 6440 switch (command) 6441 { 6442 case FreeBuffersCommand: 6443 { 6444 /* 6445 Free memory from the undo and redo cache. 6446 */ 6447 while (undo_image != (Image *) NULL) 6448 { 6449 cache_image=undo_image; 6450 undo_image=GetPreviousImageInList(undo_image); 6451 cache_image->list=DestroyImage(cache_image->list); 6452 cache_image=DestroyImage(cache_image); 6453 } 6454 undo_image=NewImageList(); 6455 if (redo_image != (Image *) NULL) 6456 redo_image=DestroyImage(redo_image); 6457 redo_image=NewImageList(); 6458 return; 6459 } 6460 case UndoCommand: 6461 { 6462 char 6463 image_geometry[MaxTextExtent]; 6464 6465 /* 6466 Undo the last image transformation. 6467 */ 6468 if (undo_image == (Image *) NULL) 6469 { 6470 (void) XBell(display,0); 6471 return; 6472 } 6473 cache_image=undo_image; 6474 undo_image=GetPreviousImageInList(undo_image); 6475 windows->image.window_changes.width=(int) cache_image->columns; 6476 windows->image.window_changes.height=(int) cache_image->rows; 6477 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6478 windows->image.ximage->width,windows->image.ximage->height); 6479 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 6480 if (windows->image.crop_geometry != (char *) NULL) 6481 windows->image.crop_geometry=(char *) 6482 RelinquishMagickMemory(windows->image.crop_geometry); 6483 windows->image.crop_geometry=cache_image->geometry; 6484 if (redo_image != (Image *) NULL) 6485 redo_image=DestroyImage(redo_image); 6486 redo_image=(*image); 6487 *image=cache_image->list; 6488 cache_image=DestroyImage(cache_image); 6489 if (windows->image.orphan != MagickFalse) 6490 return; 6491 XConfigureImageColormap(display,resource_info,windows,*image); 6492 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6493 return; 6494 } 6495 case CutCommand: 6496 case PasteCommand: 6497 case ApplyCommand: 6498 case HalfSizeCommand: 6499 case OriginalSizeCommand: 6500 case DoubleSizeCommand: 6501 case ResizeCommand: 6502 case TrimCommand: 6503 case CropCommand: 6504 case ChopCommand: 6505 case FlipCommand: 6506 case FlopCommand: 6507 case RotateRightCommand: 6508 case RotateLeftCommand: 6509 case RotateCommand: 6510 case ShearCommand: 6511 case RollCommand: 6512 case NegateCommand: 6513 case ContrastStretchCommand: 6514 case SigmoidalContrastCommand: 6515 case NormalizeCommand: 6516 case EqualizeCommand: 6517 case HueCommand: 6518 case SaturationCommand: 6519 case BrightnessCommand: 6520 case GammaCommand: 6521 case SpiffCommand: 6522 case DullCommand: 6523 case GrayscaleCommand: 6524 case MapCommand: 6525 case QuantizeCommand: 6526 case DespeckleCommand: 6527 case EmbossCommand: 6528 case ReduceNoiseCommand: 6529 case AddNoiseCommand: 6530 case SharpenCommand: 6531 case BlurCommand: 6532 case ThresholdCommand: 6533 case EdgeDetectCommand: 6534 case SpreadCommand: 6535 case ShadeCommand: 6536 case RaiseCommand: 6537 case SegmentCommand: 6538 case SolarizeCommand: 6539 case SepiaToneCommand: 6540 case SwirlCommand: 6541 case ImplodeCommand: 6542 case VignetteCommand: 6543 case WaveCommand: 6544 case OilPaintCommand: 6545 case CharcoalDrawCommand: 6546 case AnnotateCommand: 6547 case AddBorderCommand: 6548 case AddFrameCommand: 6549 case CompositeCommand: 6550 case CommentCommand: 6551 case LaunchCommand: 6552 case RegionofInterestCommand: 6553 case SaveToUndoBufferCommand: 6554 case RedoCommand: 6555 { 6556 Image 6557 *previous_image; 6558 6559 ssize_t 6560 bytes; 6561 6562 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket)); 6563 if (undo_image != (Image *) NULL) 6564 { 6565 /* 6566 Ensure the undo cache has enough memory available. 6567 */ 6568 previous_image=undo_image; 6569 while (previous_image != (Image *) NULL) 6570 { 6571 bytes+=previous_image->list->columns*previous_image->list->rows* 6572 sizeof(PixelPacket); 6573 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6574 { 6575 previous_image=GetPreviousImageInList(previous_image); 6576 continue; 6577 } 6578 bytes-=previous_image->list->columns*previous_image->list->rows* 6579 sizeof(PixelPacket); 6580 if (previous_image == undo_image) 6581 undo_image=NewImageList(); 6582 else 6583 previous_image->next->previous=NewImageList(); 6584 break; 6585 } 6586 while (previous_image != (Image *) NULL) 6587 { 6588 /* 6589 Delete any excess memory from undo cache. 6590 */ 6591 cache_image=previous_image; 6592 previous_image=GetPreviousImageInList(previous_image); 6593 cache_image->list=DestroyImage(cache_image->list); 6594 cache_image=DestroyImage(cache_image); 6595 } 6596 } 6597 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6598 break; 6599 /* 6600 Save image before transformations are applied. 6601 */ 6602 cache_image=AcquireImage((ImageInfo *) NULL); 6603 if (cache_image == (Image *) NULL) 6604 break; 6605 XSetCursorState(display,windows,MagickTrue); 6606 XCheckRefreshWindows(display,windows); 6607 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6608 XSetCursorState(display,windows,MagickFalse); 6609 if (cache_image->list == (Image *) NULL) 6610 { 6611 cache_image=DestroyImage(cache_image); 6612 break; 6613 } 6614 cache_image->columns=(size_t) windows->image.ximage->width; 6615 cache_image->rows=(size_t) windows->image.ximage->height; 6616 cache_image->geometry=windows->image.crop_geometry; 6617 if (windows->image.crop_geometry != (char *) NULL) 6618 { 6619 cache_image->geometry=AcquireString((char *) NULL); 6620 (void) CopyMagickString(cache_image->geometry, 6621 windows->image.crop_geometry,MaxTextExtent); 6622 } 6623 if (undo_image == (Image *) NULL) 6624 { 6625 undo_image=cache_image; 6626 break; 6627 } 6628 undo_image->next=cache_image; 6629 undo_image->next->previous=undo_image; 6630 undo_image=undo_image->next; 6631 break; 6632 } 6633 default: 6634 break; 6635 } 6636 if (command == RedoCommand) 6637 { 6638 /* 6639 Redo the last image transformation. 6640 */ 6641 if (redo_image == (Image *) NULL) 6642 { 6643 (void) XBell(display,0); 6644 return; 6645 } 6646 windows->image.window_changes.width=(int) redo_image->columns; 6647 windows->image.window_changes.height=(int) redo_image->rows; 6648 if (windows->image.crop_geometry != (char *) NULL) 6649 windows->image.crop_geometry=(char *) 6650 RelinquishMagickMemory(windows->image.crop_geometry); 6651 windows->image.crop_geometry=redo_image->geometry; 6652 *image=DestroyImage(*image); 6653 *image=redo_image; 6654 redo_image=NewImageList(); 6655 if (windows->image.orphan != MagickFalse) 6656 return; 6657 XConfigureImageColormap(display,resource_info,windows,*image); 6658 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6659 return; 6660 } 6661 if (command != InfoCommand) 6662 return; 6663 /* 6664 Display image info. 6665 */ 6666 XSetCursorState(display,windows,MagickTrue); 6667 XCheckRefreshWindows(display,windows); 6668 XDisplayImageInfo(display,resource_info,windows,undo_image,*image); 6669 XSetCursorState(display,windows,MagickFalse); 6670} 6671 6672/* 6673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6674% % 6675% % 6676% % 6677+ X I m a g e W i n d o w C o m m a n d % 6678% % 6679% % 6680% % 6681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6682% 6683% XImageWindowCommand() makes a transform to the image or Image window as 6684% specified by a user menu button or keyboard command. 6685% 6686% The format of the XImageWindowCommand method is: 6687% 6688% CommandType XImageWindowCommand(Display *display, 6689% XResourceInfo *resource_info,XWindows *windows, 6690% const MagickStatusType state,KeySym key_symbol,Image **image, 6691% ExceptionInfo *exception) 6692% 6693% A description of each parameter follows: 6694% 6695% o nexus: Method XImageWindowCommand returns an image when the 6696% user chooses 'Open Image' from the command menu. Otherwise a null 6697% image is returned. 6698% 6699% o display: Specifies a connection to an X server; returned from 6700% XOpenDisplay. 6701% 6702% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6703% 6704% o windows: Specifies a pointer to a XWindows structure. 6705% 6706% o state: key mask. 6707% 6708% o key_symbol: Specifies a command to perform. 6709% 6710% o image: the image; XImageWIndowCommand may transform the image and 6711% return a new image pointer. 6712% 6713% o exception: return any errors or warnings in this structure. 6714% 6715*/ 6716static CommandType XImageWindowCommand(Display *display, 6717 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6718 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6719{ 6720 static char 6721 delta[MaxTextExtent] = ""; 6722 6723 static const char 6724 Digits[] = "01234567890"; 6725 6726 static KeySym 6727 last_symbol = XK_0; 6728 6729 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6730 { 6731 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6732 { 6733 *delta='\0'; 6734 resource_info->quantum=1; 6735 } 6736 last_symbol=key_symbol; 6737 delta[strlen(delta)+1]='\0'; 6738 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6739 resource_info->quantum=StringToLong(delta); 6740 return(NullCommand); 6741 } 6742 last_symbol=key_symbol; 6743 if (resource_info->immutable) 6744 { 6745 /* 6746 Virtual image window has a restricted command set. 6747 */ 6748 switch (key_symbol) 6749 { 6750 case XK_question: 6751 return(InfoCommand); 6752 case XK_p: 6753 case XK_Print: 6754 return(PrintCommand); 6755 case XK_space: 6756 return(NextCommand); 6757 case XK_q: 6758 case XK_Escape: 6759 return(QuitCommand); 6760 default: 6761 break; 6762 } 6763 return(NullCommand); 6764 } 6765 switch ((int) key_symbol) 6766 { 6767 case XK_o: 6768 { 6769 if ((state & ControlMask) == 0) 6770 break; 6771 return(OpenCommand); 6772 } 6773 case XK_space: 6774 return(NextCommand); 6775 case XK_BackSpace: 6776 return(FormerCommand); 6777 case XK_s: 6778 { 6779 if ((state & Mod1Mask) != 0) 6780 return(SwirlCommand); 6781 if ((state & ControlMask) == 0) 6782 return(ShearCommand); 6783 return(SaveCommand); 6784 } 6785 case XK_p: 6786 case XK_Print: 6787 { 6788 if ((state & Mod1Mask) != 0) 6789 return(OilPaintCommand); 6790 if ((state & Mod4Mask) != 0) 6791 return(ColorCommand); 6792 if ((state & ControlMask) == 0) 6793 return(NullCommand); 6794 return(PrintCommand); 6795 } 6796 case XK_d: 6797 { 6798 if ((state & Mod4Mask) != 0) 6799 return(DrawCommand); 6800 if ((state & ControlMask) == 0) 6801 return(NullCommand); 6802 return(DeleteCommand); 6803 } 6804 case XK_Select: 6805 { 6806 if ((state & ControlMask) == 0) 6807 return(NullCommand); 6808 return(SelectCommand); 6809 } 6810 case XK_n: 6811 { 6812 if ((state & ControlMask) == 0) 6813 return(NullCommand); 6814 return(NewCommand); 6815 } 6816 case XK_q: 6817 case XK_Escape: 6818 return(QuitCommand); 6819 case XK_z: 6820 case XK_Undo: 6821 { 6822 if ((state & ControlMask) == 0) 6823 return(NullCommand); 6824 return(UndoCommand); 6825 } 6826 case XK_r: 6827 case XK_Redo: 6828 { 6829 if ((state & ControlMask) == 0) 6830 return(RollCommand); 6831 return(RedoCommand); 6832 } 6833 case XK_x: 6834 { 6835 if ((state & ControlMask) == 0) 6836 return(NullCommand); 6837 return(CutCommand); 6838 } 6839 case XK_c: 6840 { 6841 if ((state & Mod1Mask) != 0) 6842 return(CharcoalDrawCommand); 6843 if ((state & ControlMask) == 0) 6844 return(CropCommand); 6845 return(CopyCommand); 6846 } 6847 case XK_v: 6848 case XK_Insert: 6849 { 6850 if ((state & Mod4Mask) != 0) 6851 return(CompositeCommand); 6852 if ((state & ControlMask) == 0) 6853 return(FlipCommand); 6854 return(PasteCommand); 6855 } 6856 case XK_less: 6857 return(HalfSizeCommand); 6858 case XK_minus: 6859 return(OriginalSizeCommand); 6860 case XK_greater: 6861 return(DoubleSizeCommand); 6862 case XK_percent: 6863 return(ResizeCommand); 6864 case XK_at: 6865 return(RefreshCommand); 6866 case XK_bracketleft: 6867 return(ChopCommand); 6868 case XK_h: 6869 return(FlopCommand); 6870 case XK_slash: 6871 return(RotateRightCommand); 6872 case XK_backslash: 6873 return(RotateLeftCommand); 6874 case XK_asterisk: 6875 return(RotateCommand); 6876 case XK_t: 6877 return(TrimCommand); 6878 case XK_H: 6879 return(HueCommand); 6880 case XK_S: 6881 return(SaturationCommand); 6882 case XK_L: 6883 return(BrightnessCommand); 6884 case XK_G: 6885 return(GammaCommand); 6886 case XK_C: 6887 return(SpiffCommand); 6888 case XK_Z: 6889 return(DullCommand); 6890 case XK_N: 6891 return(NormalizeCommand); 6892 case XK_equal: 6893 return(EqualizeCommand); 6894 case XK_asciitilde: 6895 return(NegateCommand); 6896 case XK_period: 6897 return(GrayscaleCommand); 6898 case XK_numbersign: 6899 return(QuantizeCommand); 6900 case XK_F2: 6901 return(DespeckleCommand); 6902 case XK_F3: 6903 return(EmbossCommand); 6904 case XK_F4: 6905 return(ReduceNoiseCommand); 6906 case XK_F5: 6907 return(AddNoiseCommand); 6908 case XK_F6: 6909 return(SharpenCommand); 6910 case XK_F7: 6911 return(BlurCommand); 6912 case XK_F8: 6913 return(ThresholdCommand); 6914 case XK_F9: 6915 return(EdgeDetectCommand); 6916 case XK_F10: 6917 return(SpreadCommand); 6918 case XK_F11: 6919 return(ShadeCommand); 6920 case XK_F12: 6921 return(RaiseCommand); 6922 case XK_F13: 6923 return(SegmentCommand); 6924 case XK_i: 6925 { 6926 if ((state & Mod1Mask) == 0) 6927 return(NullCommand); 6928 return(ImplodeCommand); 6929 } 6930 case XK_w: 6931 { 6932 if ((state & Mod1Mask) == 0) 6933 return(NullCommand); 6934 return(WaveCommand); 6935 } 6936 case XK_m: 6937 { 6938 if ((state & Mod4Mask) == 0) 6939 return(NullCommand); 6940 return(MatteCommand); 6941 } 6942 case XK_b: 6943 { 6944 if ((state & Mod4Mask) == 0) 6945 return(NullCommand); 6946 return(AddBorderCommand); 6947 } 6948 case XK_f: 6949 { 6950 if ((state & Mod4Mask) == 0) 6951 return(NullCommand); 6952 return(AddFrameCommand); 6953 } 6954 case XK_exclam: 6955 { 6956 if ((state & Mod4Mask) == 0) 6957 return(NullCommand); 6958 return(CommentCommand); 6959 } 6960 case XK_a: 6961 { 6962 if ((state & Mod1Mask) != 0) 6963 return(ApplyCommand); 6964 if ((state & Mod4Mask) != 0) 6965 return(AnnotateCommand); 6966 if ((state & ControlMask) == 0) 6967 return(NullCommand); 6968 return(RegionofInterestCommand); 6969 } 6970 case XK_question: 6971 return(InfoCommand); 6972 case XK_plus: 6973 return(ZoomCommand); 6974 case XK_P: 6975 { 6976 if ((state & ShiftMask) == 0) 6977 return(NullCommand); 6978 return(ShowPreviewCommand); 6979 } 6980 case XK_Execute: 6981 return(LaunchCommand); 6982 case XK_F1: 6983 return(HelpCommand); 6984 case XK_Find: 6985 return(BrowseDocumentationCommand); 6986 case XK_Menu: 6987 { 6988 (void) XMapRaised(display,windows->command.id); 6989 return(NullCommand); 6990 } 6991 case XK_Next: 6992 case XK_Prior: 6993 case XK_Home: 6994 case XK_KP_Home: 6995 { 6996 XTranslateImage(display,windows,*image,key_symbol); 6997 return(NullCommand); 6998 } 6999 case XK_Up: 7000 case XK_KP_Up: 7001 case XK_Down: 7002 case XK_KP_Down: 7003 case XK_Left: 7004 case XK_KP_Left: 7005 case XK_Right: 7006 case XK_KP_Right: 7007 { 7008 if ((state & Mod1Mask) != 0) 7009 { 7010 RectangleInfo 7011 crop_info; 7012 7013 /* 7014 Trim one pixel from edge of image. 7015 */ 7016 crop_info.x=0; 7017 crop_info.y=0; 7018 crop_info.width=(size_t) windows->image.ximage->width; 7019 crop_info.height=(size_t) windows->image.ximage->height; 7020 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7021 { 7022 if (resource_info->quantum >= (int) crop_info.height) 7023 resource_info->quantum=(int) crop_info.height-1; 7024 crop_info.height-=resource_info->quantum; 7025 } 7026 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7027 { 7028 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7029 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7030 crop_info.y+=resource_info->quantum; 7031 crop_info.height-=resource_info->quantum; 7032 } 7033 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7034 { 7035 if (resource_info->quantum >= (int) crop_info.width) 7036 resource_info->quantum=(int) crop_info.width-1; 7037 crop_info.width-=resource_info->quantum; 7038 } 7039 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7040 { 7041 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7042 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7043 crop_info.x+=resource_info->quantum; 7044 crop_info.width-=resource_info->quantum; 7045 } 7046 if ((int) (windows->image.x+windows->image.width) > 7047 (int) crop_info.width) 7048 windows->image.x=(int) (crop_info.width-windows->image.width); 7049 if ((int) (windows->image.y+windows->image.height) > 7050 (int) crop_info.height) 7051 windows->image.y=(int) (crop_info.height-windows->image.height); 7052 XSetCropGeometry(display,windows,&crop_info,*image); 7053 windows->image.window_changes.width=(int) crop_info.width; 7054 windows->image.window_changes.height=(int) crop_info.height; 7055 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7056 (void) XConfigureImage(display,resource_info,windows,*image, 7057 exception); 7058 return(NullCommand); 7059 } 7060 XTranslateImage(display,windows,*image,key_symbol); 7061 return(NullCommand); 7062 } 7063 default: 7064 return(NullCommand); 7065 } 7066 return(NullCommand); 7067} 7068 7069/* 7070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7071% % 7072% % 7073% % 7074+ X M a g i c k C o m m a n d % 7075% % 7076% % 7077% % 7078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7079% 7080% XMagickCommand() makes a transform to the image or Image window as 7081% specified by a user menu button or keyboard command. 7082% 7083% The format of the XMagickCommand method is: 7084% 7085% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7086% XWindows *windows,const CommandType command,Image **image, 7087% ExceptionInfo *exception) 7088% 7089% A description of each parameter follows: 7090% 7091% o display: Specifies a connection to an X server; returned from 7092% XOpenDisplay. 7093% 7094% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7095% 7096% o windows: Specifies a pointer to a XWindows structure. 7097% 7098% o command: Specifies a command to perform. 7099% 7100% o image: the image; XMagickCommand may transform the image and return a 7101% new image pointer. 7102% 7103% o exception: return any errors or warnings in this structure. 7104% 7105*/ 7106static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7107 XWindows *windows,const CommandType command,Image **image, 7108 ExceptionInfo *exception) 7109{ 7110 char 7111 filename[MaxTextExtent], 7112 geometry[MaxTextExtent], 7113 modulate_factors[MaxTextExtent]; 7114 7115 GeometryInfo 7116 geometry_info; 7117 7118 Image 7119 *nexus; 7120 7121 ImageInfo 7122 *image_info; 7123 7124 int 7125 x, 7126 y; 7127 7128 MagickStatusType 7129 flags, 7130 status; 7131 7132 QuantizeInfo 7133 quantize_info; 7134 7135 RectangleInfo 7136 page_geometry; 7137 7138 register int 7139 i; 7140 7141 static char 7142 color[MaxTextExtent] = "gray"; 7143 7144 unsigned int 7145 height, 7146 width; 7147 7148 /* 7149 Process user command. 7150 */ 7151 XCheckRefreshWindows(display,windows); 7152 XImageCache(display,resource_info,windows,command,image,exception); 7153 nexus=NewImageList(); 7154 windows->image.window_changes.width=windows->image.ximage->width; 7155 windows->image.window_changes.height=windows->image.ximage->height; 7156 image_info=CloneImageInfo(resource_info->image_info); 7157 SetGeometryInfo(&geometry_info); 7158 GetQuantizeInfo(&quantize_info); 7159 switch (command) 7160 { 7161 case OpenCommand: 7162 { 7163 /* 7164 Load image. 7165 */ 7166 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7167 break; 7168 } 7169 case NextCommand: 7170 { 7171 /* 7172 Display next image. 7173 */ 7174 for (i=0; i < resource_info->quantum; i++) 7175 XClientMessage(display,windows->image.id,windows->im_protocols, 7176 windows->im_next_image,CurrentTime); 7177 break; 7178 } 7179 case FormerCommand: 7180 { 7181 /* 7182 Display former image. 7183 */ 7184 for (i=0; i < resource_info->quantum; i++) 7185 XClientMessage(display,windows->image.id,windows->im_protocols, 7186 windows->im_former_image,CurrentTime); 7187 break; 7188 } 7189 case SelectCommand: 7190 { 7191 int 7192 status; 7193 7194 /* 7195 Select image. 7196 */ 7197 status=chdir(resource_info->home_directory); 7198 if (status == -1) 7199 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7200 "UnableToOpenFile","%s",resource_info->home_directory); 7201 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7202 break; 7203 } 7204 case SaveCommand: 7205 { 7206 /* 7207 Save image. 7208 */ 7209 status=XSaveImage(display,resource_info,windows,*image,exception); 7210 if (status == MagickFalse) 7211 { 7212 char 7213 message[MaxTextExtent]; 7214 7215 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7216 exception->reason != (char *) NULL ? exception->reason : "", 7217 exception->description != (char *) NULL ? exception->description : 7218 ""); 7219 XNoticeWidget(display,windows,"Unable to save file:",message); 7220 break; 7221 } 7222 break; 7223 } 7224 case PrintCommand: 7225 { 7226 /* 7227 Print image. 7228 */ 7229 status=XPrintImage(display,resource_info,windows,*image,exception); 7230 if (status == MagickFalse) 7231 { 7232 char 7233 message[MaxTextExtent]; 7234 7235 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7236 exception->reason != (char *) NULL ? exception->reason : "", 7237 exception->description != (char *) NULL ? exception->description : 7238 ""); 7239 XNoticeWidget(display,windows,"Unable to print file:",message); 7240 break; 7241 } 7242 break; 7243 } 7244 case DeleteCommand: 7245 { 7246 static char 7247 filename[MaxTextExtent] = "\0"; 7248 7249 /* 7250 Delete image file. 7251 */ 7252 XFileBrowserWidget(display,windows,"Delete",filename); 7253 if (*filename == '\0') 7254 break; 7255 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 7256 if (status != MagickFalse) 7257 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7258 break; 7259 } 7260 case NewCommand: 7261 { 7262 int 7263 status; 7264 7265 static char 7266 color[MaxTextExtent] = "gray", 7267 geometry[MaxTextExtent] = "640x480"; 7268 7269 static const char 7270 *format = "gradient"; 7271 7272 /* 7273 Query user for canvas geometry. 7274 */ 7275 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7276 geometry); 7277 if (*geometry == '\0') 7278 break; 7279 if (status == 0) 7280 format="xc"; 7281 XColorBrowserWidget(display,windows,"Select",color); 7282 if (*color == '\0') 7283 break; 7284 /* 7285 Create canvas. 7286 */ 7287 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7288 "%s:%s",format,color); 7289 (void) CloneString(&image_info->size,geometry); 7290 nexus=ReadImage(image_info,exception); 7291 CatchException(exception); 7292 XClientMessage(display,windows->image.id,windows->im_protocols, 7293 windows->im_next_image,CurrentTime); 7294 break; 7295 } 7296 case VisualDirectoryCommand: 7297 { 7298 /* 7299 Visual Image directory. 7300 */ 7301 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7302 break; 7303 } 7304 case QuitCommand: 7305 { 7306 /* 7307 exit program. 7308 */ 7309 if (resource_info->confirm_exit == MagickFalse) 7310 XClientMessage(display,windows->image.id,windows->im_protocols, 7311 windows->im_exit,CurrentTime); 7312 else 7313 { 7314 int 7315 status; 7316 7317 /* 7318 Confirm program exit. 7319 */ 7320 status=XConfirmWidget(display,windows,"Do you really want to exit", 7321 resource_info->client_name); 7322 if (status > 0) 7323 XClientMessage(display,windows->image.id,windows->im_protocols, 7324 windows->im_exit,CurrentTime); 7325 } 7326 break; 7327 } 7328 case CutCommand: 7329 { 7330 /* 7331 Cut image. 7332 */ 7333 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7334 break; 7335 } 7336 case CopyCommand: 7337 { 7338 /* 7339 Copy image. 7340 */ 7341 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7342 exception); 7343 break; 7344 } 7345 case PasteCommand: 7346 { 7347 /* 7348 Paste image. 7349 */ 7350 status=XPasteImage(display,resource_info,windows,*image,exception); 7351 if (status == MagickFalse) 7352 { 7353 XNoticeWidget(display,windows,"Unable to paste X image", 7354 (*image)->filename); 7355 break; 7356 } 7357 break; 7358 } 7359 case HalfSizeCommand: 7360 { 7361 /* 7362 Half image size. 7363 */ 7364 windows->image.window_changes.width=windows->image.ximage->width/2; 7365 windows->image.window_changes.height=windows->image.ximage->height/2; 7366 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7367 break; 7368 } 7369 case OriginalSizeCommand: 7370 { 7371 /* 7372 Original image size. 7373 */ 7374 windows->image.window_changes.width=(int) (*image)->columns; 7375 windows->image.window_changes.height=(int) (*image)->rows; 7376 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7377 break; 7378 } 7379 case DoubleSizeCommand: 7380 { 7381 /* 7382 Double the image size. 7383 */ 7384 windows->image.window_changes.width=windows->image.ximage->width << 1; 7385 windows->image.window_changes.height=windows->image.ximage->height << 1; 7386 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7387 break; 7388 } 7389 case ResizeCommand: 7390 { 7391 int 7392 status; 7393 7394 size_t 7395 height, 7396 width; 7397 7398 ssize_t 7399 x, 7400 y; 7401 7402 /* 7403 Resize image. 7404 */ 7405 width=(size_t) windows->image.ximage->width; 7406 height=(size_t) windows->image.ximage->height; 7407 x=0; 7408 y=0; 7409 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7410 (double) width,(double) height); 7411 status=XDialogWidget(display,windows,"Resize", 7412 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7413 if (*geometry == '\0') 7414 break; 7415 if (status == 0) 7416 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7417 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7418 windows->image.window_changes.width=(int) width; 7419 windows->image.window_changes.height=(int) height; 7420 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7421 break; 7422 } 7423 case ApplyCommand: 7424 { 7425 char 7426 image_geometry[MaxTextExtent]; 7427 7428 if ((windows->image.crop_geometry == (char *) NULL) && 7429 ((int) (*image)->columns == windows->image.ximage->width) && 7430 ((int) (*image)->rows == windows->image.ximage->height)) 7431 break; 7432 /* 7433 Apply size transforms to image. 7434 */ 7435 XSetCursorState(display,windows,MagickTrue); 7436 XCheckRefreshWindows(display,windows); 7437 /* 7438 Crop and/or scale displayed image. 7439 */ 7440 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7441 windows->image.ximage->width,windows->image.ximage->height); 7442 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 7443 if (windows->image.crop_geometry != (char *) NULL) 7444 windows->image.crop_geometry=(char *) 7445 RelinquishMagickMemory(windows->image.crop_geometry); 7446 windows->image.x=0; 7447 windows->image.y=0; 7448 XConfigureImageColormap(display,resource_info,windows,*image); 7449 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7450 break; 7451 } 7452 case RefreshCommand: 7453 { 7454 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7455 break; 7456 } 7457 case RestoreCommand: 7458 { 7459 /* 7460 Restore Image window to its original size. 7461 */ 7462 if ((windows->image.width == (unsigned int) (*image)->columns) && 7463 (windows->image.height == (unsigned int) (*image)->rows) && 7464 (windows->image.crop_geometry == (char *) NULL)) 7465 { 7466 (void) XBell(display,0); 7467 break; 7468 } 7469 windows->image.window_changes.width=(int) (*image)->columns; 7470 windows->image.window_changes.height=(int) (*image)->rows; 7471 if (windows->image.crop_geometry != (char *) NULL) 7472 { 7473 windows->image.crop_geometry=(char *) 7474 RelinquishMagickMemory(windows->image.crop_geometry); 7475 windows->image.crop_geometry=(char *) NULL; 7476 windows->image.x=0; 7477 windows->image.y=0; 7478 } 7479 XConfigureImageColormap(display,resource_info,windows,*image); 7480 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7481 break; 7482 } 7483 case CropCommand: 7484 { 7485 /* 7486 Crop image. 7487 */ 7488 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7489 exception); 7490 break; 7491 } 7492 case ChopCommand: 7493 { 7494 /* 7495 Chop image. 7496 */ 7497 status=XChopImage(display,resource_info,windows,image,exception); 7498 if (status == MagickFalse) 7499 { 7500 XNoticeWidget(display,windows,"Unable to cut X image", 7501 (*image)->filename); 7502 break; 7503 } 7504 break; 7505 } 7506 case FlopCommand: 7507 { 7508 Image 7509 *flop_image; 7510 7511 /* 7512 Flop image scanlines. 7513 */ 7514 XSetCursorState(display,windows,MagickTrue); 7515 XCheckRefreshWindows(display,windows); 7516 flop_image=FlopImage(*image,exception); 7517 if (flop_image != (Image *) NULL) 7518 { 7519 *image=DestroyImage(*image); 7520 *image=flop_image; 7521 } 7522 CatchException(exception); 7523 XSetCursorState(display,windows,MagickFalse); 7524 if (windows->image.crop_geometry != (char *) NULL) 7525 { 7526 /* 7527 Flop crop geometry. 7528 */ 7529 width=(unsigned int) (*image)->columns; 7530 height=(unsigned int) (*image)->rows; 7531 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7532 &width,&height); 7533 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7534 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7535 } 7536 if (windows->image.orphan != MagickFalse) 7537 break; 7538 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7539 break; 7540 } 7541 case FlipCommand: 7542 { 7543 Image 7544 *flip_image; 7545 7546 /* 7547 Flip image scanlines. 7548 */ 7549 XSetCursorState(display,windows,MagickTrue); 7550 XCheckRefreshWindows(display,windows); 7551 flip_image=FlipImage(*image,exception); 7552 if (flip_image != (Image *) NULL) 7553 { 7554 *image=DestroyImage(*image); 7555 *image=flip_image; 7556 } 7557 CatchException(exception); 7558 XSetCursorState(display,windows,MagickFalse); 7559 if (windows->image.crop_geometry != (char *) NULL) 7560 { 7561 /* 7562 Flip crop geometry. 7563 */ 7564 width=(unsigned int) (*image)->columns; 7565 height=(unsigned int) (*image)->rows; 7566 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7567 &width,&height); 7568 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7569 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7570 } 7571 if (windows->image.orphan != MagickFalse) 7572 break; 7573 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7574 break; 7575 } 7576 case RotateRightCommand: 7577 { 7578 /* 7579 Rotate image 90 degrees clockwise. 7580 */ 7581 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7582 if (status == MagickFalse) 7583 { 7584 XNoticeWidget(display,windows,"Unable to rotate X image", 7585 (*image)->filename); 7586 break; 7587 } 7588 break; 7589 } 7590 case RotateLeftCommand: 7591 { 7592 /* 7593 Rotate image 90 degrees counter-clockwise. 7594 */ 7595 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7596 if (status == MagickFalse) 7597 { 7598 XNoticeWidget(display,windows,"Unable to rotate X image", 7599 (*image)->filename); 7600 break; 7601 } 7602 break; 7603 } 7604 case RotateCommand: 7605 { 7606 /* 7607 Rotate image. 7608 */ 7609 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7610 if (status == MagickFalse) 7611 { 7612 XNoticeWidget(display,windows,"Unable to rotate X image", 7613 (*image)->filename); 7614 break; 7615 } 7616 break; 7617 } 7618 case ShearCommand: 7619 { 7620 Image 7621 *shear_image; 7622 7623 static char 7624 geometry[MaxTextExtent] = "45.0x45.0"; 7625 7626 /* 7627 Query user for shear color and geometry. 7628 */ 7629 XColorBrowserWidget(display,windows,"Select",color); 7630 if (*color == '\0') 7631 break; 7632 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7633 geometry); 7634 if (*geometry == '\0') 7635 break; 7636 /* 7637 Shear image. 7638 */ 7639 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7640 exception); 7641 XSetCursorState(display,windows,MagickTrue); 7642 XCheckRefreshWindows(display,windows); 7643 (void) QueryColorDatabase(color,&(*image)->background_color, 7644 exception); 7645 flags=ParseGeometry(geometry,&geometry_info); 7646 if ((flags & SigmaValue) == 0) 7647 geometry_info.sigma=geometry_info.rho; 7648 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7649 exception); 7650 if (shear_image != (Image *) NULL) 7651 { 7652 *image=DestroyImage(*image); 7653 *image=shear_image; 7654 } 7655 CatchException(exception); 7656 XSetCursorState(display,windows,MagickFalse); 7657 if (windows->image.orphan != MagickFalse) 7658 break; 7659 windows->image.window_changes.width=(int) (*image)->columns; 7660 windows->image.window_changes.height=(int) (*image)->rows; 7661 XConfigureImageColormap(display,resource_info,windows,*image); 7662 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7663 break; 7664 } 7665 case RollCommand: 7666 { 7667 Image 7668 *roll_image; 7669 7670 static char 7671 geometry[MaxTextExtent] = "+2+2"; 7672 7673 /* 7674 Query user for the roll geometry. 7675 */ 7676 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7677 geometry); 7678 if (*geometry == '\0') 7679 break; 7680 /* 7681 Roll image. 7682 */ 7683 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7684 exception); 7685 XSetCursorState(display,windows,MagickTrue); 7686 XCheckRefreshWindows(display,windows); 7687 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7688 exception); 7689 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7690 exception); 7691 if (roll_image != (Image *) NULL) 7692 { 7693 *image=DestroyImage(*image); 7694 *image=roll_image; 7695 } 7696 CatchException(exception); 7697 XSetCursorState(display,windows,MagickFalse); 7698 if (windows->image.orphan != MagickFalse) 7699 break; 7700 windows->image.window_changes.width=(int) (*image)->columns; 7701 windows->image.window_changes.height=(int) (*image)->rows; 7702 XConfigureImageColormap(display,resource_info,windows,*image); 7703 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7704 break; 7705 } 7706 case TrimCommand: 7707 { 7708 static char 7709 fuzz[MaxTextExtent]; 7710 7711 /* 7712 Query user for the fuzz factor. 7713 */ 7714 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7715 (*image)->fuzz/(QuantumRange+1.0)); 7716 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7717 if (*fuzz == '\0') 7718 break; 7719 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7720 /* 7721 Trim image. 7722 */ 7723 status=XTrimImage(display,resource_info,windows,*image,exception); 7724 if (status == MagickFalse) 7725 { 7726 XNoticeWidget(display,windows,"Unable to trim X image", 7727 (*image)->filename); 7728 break; 7729 } 7730 break; 7731 } 7732 case HueCommand: 7733 { 7734 static char 7735 hue_percent[MaxTextExtent] = "110"; 7736 7737 /* 7738 Query user for percent hue change. 7739 */ 7740 (void) XDialogWidget(display,windows,"Apply", 7741 "Enter percent change in image hue (0-200):",hue_percent); 7742 if (*hue_percent == '\0') 7743 break; 7744 /* 7745 Vary the image hue. 7746 */ 7747 XSetCursorState(display,windows,MagickTrue); 7748 XCheckRefreshWindows(display,windows); 7749 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7750 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7751 MaxTextExtent); 7752 (void) ModulateImage(*image,modulate_factors,exception); 7753 XSetCursorState(display,windows,MagickFalse); 7754 if (windows->image.orphan != MagickFalse) 7755 break; 7756 XConfigureImageColormap(display,resource_info,windows,*image); 7757 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7758 break; 7759 } 7760 case SaturationCommand: 7761 { 7762 static char 7763 saturation_percent[MaxTextExtent] = "110"; 7764 7765 /* 7766 Query user for percent saturation change. 7767 */ 7768 (void) XDialogWidget(display,windows,"Apply", 7769 "Enter percent change in color saturation (0-200):",saturation_percent); 7770 if (*saturation_percent == '\0') 7771 break; 7772 /* 7773 Vary color saturation. 7774 */ 7775 XSetCursorState(display,windows,MagickTrue); 7776 XCheckRefreshWindows(display,windows); 7777 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7778 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7779 MaxTextExtent); 7780 (void) ModulateImage(*image,modulate_factors,exception); 7781 XSetCursorState(display,windows,MagickFalse); 7782 if (windows->image.orphan != MagickFalse) 7783 break; 7784 XConfigureImageColormap(display,resource_info,windows,*image); 7785 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7786 break; 7787 } 7788 case BrightnessCommand: 7789 { 7790 static char 7791 brightness_percent[MaxTextExtent] = "110"; 7792 7793 /* 7794 Query user for percent brightness change. 7795 */ 7796 (void) XDialogWidget(display,windows,"Apply", 7797 "Enter percent change in color brightness (0-200):",brightness_percent); 7798 if (*brightness_percent == '\0') 7799 break; 7800 /* 7801 Vary the color brightness. 7802 */ 7803 XSetCursorState(display,windows,MagickTrue); 7804 XCheckRefreshWindows(display,windows); 7805 (void) CopyMagickString(modulate_factors,brightness_percent, 7806 MaxTextExtent); 7807 (void) ModulateImage(*image,modulate_factors,exception); 7808 XSetCursorState(display,windows,MagickFalse); 7809 if (windows->image.orphan != MagickFalse) 7810 break; 7811 XConfigureImageColormap(display,resource_info,windows,*image); 7812 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7813 break; 7814 } 7815 case GammaCommand: 7816 { 7817 static char 7818 factor[MaxTextExtent] = "1.6"; 7819 7820 /* 7821 Query user for gamma value. 7822 */ 7823 (void) XDialogWidget(display,windows,"Gamma", 7824 "Enter gamma value (e.g. 1.2):",factor); 7825 if (*factor == '\0') 7826 break; 7827 /* 7828 Gamma correct image. 7829 */ 7830 XSetCursorState(display,windows,MagickTrue); 7831 XCheckRefreshWindows(display,windows); 7832 (void) GammaImage(*image,atof(factor),exception); 7833 XSetCursorState(display,windows,MagickFalse); 7834 if (windows->image.orphan != MagickFalse) 7835 break; 7836 XConfigureImageColormap(display,resource_info,windows,*image); 7837 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7838 break; 7839 } 7840 case SpiffCommand: 7841 { 7842 /* 7843 Sharpen the image contrast. 7844 */ 7845 XSetCursorState(display,windows,MagickTrue); 7846 XCheckRefreshWindows(display,windows); 7847 (void) ContrastImage(*image,MagickTrue,exception); 7848 XSetCursorState(display,windows,MagickFalse); 7849 if (windows->image.orphan != MagickFalse) 7850 break; 7851 XConfigureImageColormap(display,resource_info,windows,*image); 7852 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7853 break; 7854 } 7855 case DullCommand: 7856 { 7857 /* 7858 Dull the image contrast. 7859 */ 7860 XSetCursorState(display,windows,MagickTrue); 7861 XCheckRefreshWindows(display,windows); 7862 (void) ContrastImage(*image,MagickFalse,exception); 7863 XSetCursorState(display,windows,MagickFalse); 7864 if (windows->image.orphan != MagickFalse) 7865 break; 7866 XConfigureImageColormap(display,resource_info,windows,*image); 7867 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7868 break; 7869 } 7870 case ContrastStretchCommand: 7871 { 7872 double 7873 black_point, 7874 white_point; 7875 7876 static char 7877 levels[MaxTextExtent] = "1%"; 7878 7879 /* 7880 Query user for gamma value. 7881 */ 7882 (void) XDialogWidget(display,windows,"Contrast Stretch", 7883 "Enter black and white points:",levels); 7884 if (*levels == '\0') 7885 break; 7886 /* 7887 Contrast stretch image. 7888 */ 7889 XSetCursorState(display,windows,MagickTrue); 7890 XCheckRefreshWindows(display,windows); 7891 flags=ParseGeometry(levels,&geometry_info); 7892 black_point=geometry_info.rho; 7893 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7894 if ((flags & PercentValue) != 0) 7895 { 7896 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7897 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7898 } 7899 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7900 (void) ContrastStretchImage(*image,black_point,white_point, 7901 exception); 7902 XSetCursorState(display,windows,MagickFalse); 7903 if (windows->image.orphan != MagickFalse) 7904 break; 7905 XConfigureImageColormap(display,resource_info,windows,*image); 7906 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7907 break; 7908 } 7909 case SigmoidalContrastCommand: 7910 { 7911 GeometryInfo 7912 geometry_info; 7913 7914 MagickStatusType 7915 flags; 7916 7917 static char 7918 levels[MaxTextExtent] = "3x50%"; 7919 7920 /* 7921 Query user for gamma value. 7922 */ 7923 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7924 "Enter contrast and midpoint:",levels); 7925 if (*levels == '\0') 7926 break; 7927 /* 7928 Contrast stretch image. 7929 */ 7930 XSetCursorState(display,windows,MagickTrue); 7931 XCheckRefreshWindows(display,windows); 7932 flags=ParseGeometry(levels,&geometry_info); 7933 if ((flags & SigmaValue) == 0) 7934 geometry_info.sigma=1.0*QuantumRange/2.0; 7935 if ((flags & PercentValue) != 0) 7936 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7937 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7938 geometry_info.sigma,exception); 7939 XSetCursorState(display,windows,MagickFalse); 7940 if (windows->image.orphan != MagickFalse) 7941 break; 7942 XConfigureImageColormap(display,resource_info,windows,*image); 7943 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7944 break; 7945 } 7946 case NormalizeCommand: 7947 { 7948 /* 7949 Perform histogram normalization on the image. 7950 */ 7951 XSetCursorState(display,windows,MagickTrue); 7952 XCheckRefreshWindows(display,windows); 7953 (void) NormalizeImage(*image,exception); 7954 XSetCursorState(display,windows,MagickFalse); 7955 if (windows->image.orphan != MagickFalse) 7956 break; 7957 XConfigureImageColormap(display,resource_info,windows,*image); 7958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7959 break; 7960 } 7961 case EqualizeCommand: 7962 { 7963 /* 7964 Perform histogram equalization on the image. 7965 */ 7966 XSetCursorState(display,windows,MagickTrue); 7967 XCheckRefreshWindows(display,windows); 7968 (void) EqualizeImage(*image,exception); 7969 XSetCursorState(display,windows,MagickFalse); 7970 if (windows->image.orphan != MagickFalse) 7971 break; 7972 XConfigureImageColormap(display,resource_info,windows,*image); 7973 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7974 break; 7975 } 7976 case NegateCommand: 7977 { 7978 /* 7979 Negate colors in image. 7980 */ 7981 XSetCursorState(display,windows,MagickTrue); 7982 XCheckRefreshWindows(display,windows); 7983 (void) NegateImage(*image,MagickFalse,exception); 7984 XSetCursorState(display,windows,MagickFalse); 7985 if (windows->image.orphan != MagickFalse) 7986 break; 7987 XConfigureImageColormap(display,resource_info,windows,*image); 7988 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7989 break; 7990 } 7991 case GrayscaleCommand: 7992 { 7993 /* 7994 Convert image to grayscale. 7995 */ 7996 XSetCursorState(display,windows,MagickTrue); 7997 XCheckRefreshWindows(display,windows); 7998 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 7999 GrayscaleType : GrayscaleMatteType,exception); 8000 XSetCursorState(display,windows,MagickFalse); 8001 if (windows->image.orphan != MagickFalse) 8002 break; 8003 XConfigureImageColormap(display,resource_info,windows,*image); 8004 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8005 break; 8006 } 8007 case MapCommand: 8008 { 8009 Image 8010 *affinity_image; 8011 8012 static char 8013 filename[MaxTextExtent] = "\0"; 8014 8015 /* 8016 Request image file name from user. 8017 */ 8018 XFileBrowserWidget(display,windows,"Map",filename); 8019 if (*filename == '\0') 8020 break; 8021 /* 8022 Map image. 8023 */ 8024 XSetCursorState(display,windows,MagickTrue); 8025 XCheckRefreshWindows(display,windows); 8026 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8027 affinity_image=ReadImage(image_info,exception); 8028 if (affinity_image != (Image *) NULL) 8029 { 8030 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8031 affinity_image=DestroyImage(affinity_image); 8032 } 8033 CatchException(exception); 8034 XSetCursorState(display,windows,MagickFalse); 8035 if (windows->image.orphan != MagickFalse) 8036 break; 8037 XConfigureImageColormap(display,resource_info,windows,*image); 8038 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8039 break; 8040 } 8041 case QuantizeCommand: 8042 { 8043 int 8044 status; 8045 8046 static char 8047 colors[MaxTextExtent] = "256"; 8048 8049 /* 8050 Query user for maximum number of colors. 8051 */ 8052 status=XDialogWidget(display,windows,"Quantize", 8053 "Maximum number of colors:",colors); 8054 if (*colors == '\0') 8055 break; 8056 /* 8057 Color reduce the image. 8058 */ 8059 XSetCursorState(display,windows,MagickTrue); 8060 XCheckRefreshWindows(display,windows); 8061 quantize_info.number_colors=StringToUnsignedLong(colors); 8062 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8063 (void) QuantizeImage(&quantize_info,*image,exception); 8064 XSetCursorState(display,windows,MagickFalse); 8065 if (windows->image.orphan != MagickFalse) 8066 break; 8067 XConfigureImageColormap(display,resource_info,windows,*image); 8068 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8069 break; 8070 } 8071 case DespeckleCommand: 8072 { 8073 Image 8074 *despeckle_image; 8075 8076 /* 8077 Despeckle image. 8078 */ 8079 XSetCursorState(display,windows,MagickTrue); 8080 XCheckRefreshWindows(display,windows); 8081 despeckle_image=DespeckleImage(*image,exception); 8082 if (despeckle_image != (Image *) NULL) 8083 { 8084 *image=DestroyImage(*image); 8085 *image=despeckle_image; 8086 } 8087 CatchException(exception); 8088 XSetCursorState(display,windows,MagickFalse); 8089 if (windows->image.orphan != MagickFalse) 8090 break; 8091 XConfigureImageColormap(display,resource_info,windows,*image); 8092 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8093 break; 8094 } 8095 case EmbossCommand: 8096 { 8097 Image 8098 *emboss_image; 8099 8100 static char 8101 radius[MaxTextExtent] = "0.0x1.0"; 8102 8103 /* 8104 Query user for emboss radius. 8105 */ 8106 (void) XDialogWidget(display,windows,"Emboss", 8107 "Enter the emboss radius and standard deviation:",radius); 8108 if (*radius == '\0') 8109 break; 8110 /* 8111 Reduce noise in the image. 8112 */ 8113 XSetCursorState(display,windows,MagickTrue); 8114 XCheckRefreshWindows(display,windows); 8115 flags=ParseGeometry(radius,&geometry_info); 8116 if ((flags & SigmaValue) == 0) 8117 geometry_info.sigma=1.0; 8118 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8119 exception); 8120 if (emboss_image != (Image *) NULL) 8121 { 8122 *image=DestroyImage(*image); 8123 *image=emboss_image; 8124 } 8125 CatchException(exception); 8126 XSetCursorState(display,windows,MagickFalse); 8127 if (windows->image.orphan != MagickFalse) 8128 break; 8129 XConfigureImageColormap(display,resource_info,windows,*image); 8130 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8131 break; 8132 } 8133 case ReduceNoiseCommand: 8134 { 8135 Image 8136 *noise_image; 8137 8138 static char 8139 radius[MaxTextExtent] = "0"; 8140 8141 /* 8142 Query user for noise radius. 8143 */ 8144 (void) XDialogWidget(display,windows,"Reduce Noise", 8145 "Enter the noise radius:",radius); 8146 if (*radius == '\0') 8147 break; 8148 /* 8149 Reduce noise in the image. 8150 */ 8151 XSetCursorState(display,windows,MagickTrue); 8152 XCheckRefreshWindows(display,windows); 8153 flags=ParseGeometry(radius,&geometry_info); 8154 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8155 geometry_info.rho,(size_t) geometry_info.rho,exception); 8156 if (noise_image != (Image *) NULL) 8157 { 8158 *image=DestroyImage(*image); 8159 *image=noise_image; 8160 } 8161 CatchException(exception); 8162 XSetCursorState(display,windows,MagickFalse); 8163 if (windows->image.orphan != MagickFalse) 8164 break; 8165 XConfigureImageColormap(display,resource_info,windows,*image); 8166 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8167 break; 8168 } 8169 case AddNoiseCommand: 8170 { 8171 char 8172 **noises; 8173 8174 Image 8175 *noise_image; 8176 8177 static char 8178 noise_type[MaxTextExtent] = "Gaussian"; 8179 8180 /* 8181 Add noise to the image. 8182 */ 8183 noises=GetCommandOptions(MagickNoiseOptions); 8184 if (noises == (char **) NULL) 8185 break; 8186 XListBrowserWidget(display,windows,&windows->widget, 8187 (const char **) noises,"Add Noise", 8188 "Select a type of noise to add to your image:",noise_type); 8189 noises=DestroyStringList(noises); 8190 if (*noise_type == '\0') 8191 break; 8192 XSetCursorState(display,windows,MagickTrue); 8193 XCheckRefreshWindows(display,windows); 8194 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8195 MagickNoiseOptions,MagickFalse,noise_type),exception); 8196 if (noise_image != (Image *) NULL) 8197 { 8198 *image=DestroyImage(*image); 8199 *image=noise_image; 8200 } 8201 CatchException(exception); 8202 XSetCursorState(display,windows,MagickFalse); 8203 if (windows->image.orphan != MagickFalse) 8204 break; 8205 XConfigureImageColormap(display,resource_info,windows,*image); 8206 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8207 break; 8208 } 8209 case SharpenCommand: 8210 { 8211 Image 8212 *sharp_image; 8213 8214 static char 8215 radius[MaxTextExtent] = "0.0x1.0"; 8216 8217 /* 8218 Query user for sharpen radius. 8219 */ 8220 (void) XDialogWidget(display,windows,"Sharpen", 8221 "Enter the sharpen radius and standard deviation:",radius); 8222 if (*radius == '\0') 8223 break; 8224 /* 8225 Sharpen image scanlines. 8226 */ 8227 XSetCursorState(display,windows,MagickTrue); 8228 XCheckRefreshWindows(display,windows); 8229 flags=ParseGeometry(radius,&geometry_info); 8230 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8231 geometry_info.xi,exception); 8232 if (sharp_image != (Image *) NULL) 8233 { 8234 *image=DestroyImage(*image); 8235 *image=sharp_image; 8236 } 8237 CatchException(exception); 8238 XSetCursorState(display,windows,MagickFalse); 8239 if (windows->image.orphan != MagickFalse) 8240 break; 8241 XConfigureImageColormap(display,resource_info,windows,*image); 8242 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8243 break; 8244 } 8245 case BlurCommand: 8246 { 8247 Image 8248 *blur_image; 8249 8250 static char 8251 radius[MaxTextExtent] = "0.0x1.0"; 8252 8253 /* 8254 Query user for blur radius. 8255 */ 8256 (void) XDialogWidget(display,windows,"Blur", 8257 "Enter the blur radius and standard deviation:",radius); 8258 if (*radius == '\0') 8259 break; 8260 /* 8261 Blur an image. 8262 */ 8263 XSetCursorState(display,windows,MagickTrue); 8264 XCheckRefreshWindows(display,windows); 8265 flags=ParseGeometry(radius,&geometry_info); 8266 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8267 geometry_info.xi,exception); 8268 if (blur_image != (Image *) NULL) 8269 { 8270 *image=DestroyImage(*image); 8271 *image=blur_image; 8272 } 8273 CatchException(exception); 8274 XSetCursorState(display,windows,MagickFalse); 8275 if (windows->image.orphan != MagickFalse) 8276 break; 8277 XConfigureImageColormap(display,resource_info,windows,*image); 8278 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8279 break; 8280 } 8281 case ThresholdCommand: 8282 { 8283 double 8284 threshold; 8285 8286 static char 8287 factor[MaxTextExtent] = "128"; 8288 8289 /* 8290 Query user for threshold value. 8291 */ 8292 (void) XDialogWidget(display,windows,"Threshold", 8293 "Enter threshold value:",factor); 8294 if (*factor == '\0') 8295 break; 8296 /* 8297 Gamma correct image. 8298 */ 8299 XSetCursorState(display,windows,MagickTrue); 8300 XCheckRefreshWindows(display,windows); 8301 threshold=SiPrefixToDouble(factor,QuantumRange); 8302 (void) BilevelImage(*image,threshold); 8303 XSetCursorState(display,windows,MagickFalse); 8304 if (windows->image.orphan != MagickFalse) 8305 break; 8306 XConfigureImageColormap(display,resource_info,windows,*image); 8307 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8308 break; 8309 } 8310 case EdgeDetectCommand: 8311 { 8312 Image 8313 *edge_image; 8314 8315 static char 8316 radius[MaxTextExtent] = "0"; 8317 8318 /* 8319 Query user for edge factor. 8320 */ 8321 (void) XDialogWidget(display,windows,"Detect Edges", 8322 "Enter the edge detect radius:",radius); 8323 if (*radius == '\0') 8324 break; 8325 /* 8326 Detect edge in image. 8327 */ 8328 XSetCursorState(display,windows,MagickTrue); 8329 XCheckRefreshWindows(display,windows); 8330 flags=ParseGeometry(radius,&geometry_info); 8331 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8332 exception); 8333 if (edge_image != (Image *) NULL) 8334 { 8335 *image=DestroyImage(*image); 8336 *image=edge_image; 8337 } 8338 CatchException(exception); 8339 XSetCursorState(display,windows,MagickFalse); 8340 if (windows->image.orphan != MagickFalse) 8341 break; 8342 XConfigureImageColormap(display,resource_info,windows,*image); 8343 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8344 break; 8345 } 8346 case SpreadCommand: 8347 { 8348 Image 8349 *spread_image; 8350 8351 static char 8352 amount[MaxTextExtent] = "2"; 8353 8354 /* 8355 Query user for spread amount. 8356 */ 8357 (void) XDialogWidget(display,windows,"Spread", 8358 "Enter the displacement amount:",amount); 8359 if (*amount == '\0') 8360 break; 8361 /* 8362 Displace image pixels by a random amount. 8363 */ 8364 XSetCursorState(display,windows,MagickTrue); 8365 XCheckRefreshWindows(display,windows); 8366 flags=ParseGeometry(amount,&geometry_info); 8367 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8368 exception); 8369 if (spread_image != (Image *) NULL) 8370 { 8371 *image=DestroyImage(*image); 8372 *image=spread_image; 8373 } 8374 CatchException(exception); 8375 XSetCursorState(display,windows,MagickFalse); 8376 if (windows->image.orphan != MagickFalse) 8377 break; 8378 XConfigureImageColormap(display,resource_info,windows,*image); 8379 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8380 break; 8381 } 8382 case ShadeCommand: 8383 { 8384 Image 8385 *shade_image; 8386 8387 int 8388 status; 8389 8390 static char 8391 geometry[MaxTextExtent] = "30x30"; 8392 8393 /* 8394 Query user for the shade geometry. 8395 */ 8396 status=XDialogWidget(display,windows,"Shade", 8397 "Enter the azimuth and elevation of the light source:",geometry); 8398 if (*geometry == '\0') 8399 break; 8400 /* 8401 Shade image pixels. 8402 */ 8403 XSetCursorState(display,windows,MagickTrue); 8404 XCheckRefreshWindows(display,windows); 8405 flags=ParseGeometry(geometry,&geometry_info); 8406 if ((flags & SigmaValue) == 0) 8407 geometry_info.sigma=1.0; 8408 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8409 geometry_info.rho,geometry_info.sigma,exception); 8410 if (shade_image != (Image *) NULL) 8411 { 8412 *image=DestroyImage(*image); 8413 *image=shade_image; 8414 } 8415 CatchException(exception); 8416 XSetCursorState(display,windows,MagickFalse); 8417 if (windows->image.orphan != MagickFalse) 8418 break; 8419 XConfigureImageColormap(display,resource_info,windows,*image); 8420 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8421 break; 8422 } 8423 case RaiseCommand: 8424 { 8425 static char 8426 bevel_width[MaxTextExtent] = "10"; 8427 8428 /* 8429 Query user for bevel width. 8430 */ 8431 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8432 if (*bevel_width == '\0') 8433 break; 8434 /* 8435 Raise an image. 8436 */ 8437 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8438 exception); 8439 XSetCursorState(display,windows,MagickTrue); 8440 XCheckRefreshWindows(display,windows); 8441 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8442 exception); 8443 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8444 XSetCursorState(display,windows,MagickFalse); 8445 if (windows->image.orphan != MagickFalse) 8446 break; 8447 XConfigureImageColormap(display,resource_info,windows,*image); 8448 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8449 break; 8450 } 8451 case SegmentCommand: 8452 { 8453 static char 8454 threshold[MaxTextExtent] = "1.0x1.5"; 8455 8456 /* 8457 Query user for smoothing threshold. 8458 */ 8459 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8460 threshold); 8461 if (*threshold == '\0') 8462 break; 8463 /* 8464 Segment an image. 8465 */ 8466 XSetCursorState(display,windows,MagickTrue); 8467 XCheckRefreshWindows(display,windows); 8468 flags=ParseGeometry(threshold,&geometry_info); 8469 if ((flags & SigmaValue) == 0) 8470 geometry_info.sigma=1.0; 8471 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8472 geometry_info.sigma,exception); 8473 XSetCursorState(display,windows,MagickFalse); 8474 if (windows->image.orphan != MagickFalse) 8475 break; 8476 XConfigureImageColormap(display,resource_info,windows,*image); 8477 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8478 break; 8479 } 8480 case SepiaToneCommand: 8481 { 8482 double 8483 threshold; 8484 8485 Image 8486 *sepia_image; 8487 8488 static char 8489 factor[MaxTextExtent] = "80%"; 8490 8491 /* 8492 Query user for sepia-tone factor. 8493 */ 8494 (void) XDialogWidget(display,windows,"Sepia Tone", 8495 "Enter the sepia tone factor (0 - 99.9%):",factor); 8496 if (*factor == '\0') 8497 break; 8498 /* 8499 Sepia tone image pixels. 8500 */ 8501 XSetCursorState(display,windows,MagickTrue); 8502 XCheckRefreshWindows(display,windows); 8503 threshold=SiPrefixToDouble(factor,QuantumRange); 8504 sepia_image=SepiaToneImage(*image,threshold,exception); 8505 if (sepia_image != (Image *) NULL) 8506 { 8507 *image=DestroyImage(*image); 8508 *image=sepia_image; 8509 } 8510 CatchException(exception); 8511 XSetCursorState(display,windows,MagickFalse); 8512 if (windows->image.orphan != MagickFalse) 8513 break; 8514 XConfigureImageColormap(display,resource_info,windows,*image); 8515 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8516 break; 8517 } 8518 case SolarizeCommand: 8519 { 8520 double 8521 threshold; 8522 8523 static char 8524 factor[MaxTextExtent] = "60%"; 8525 8526 /* 8527 Query user for solarize factor. 8528 */ 8529 (void) XDialogWidget(display,windows,"Solarize", 8530 "Enter the solarize factor (0 - 99.9%):",factor); 8531 if (*factor == '\0') 8532 break; 8533 /* 8534 Solarize image pixels. 8535 */ 8536 XSetCursorState(display,windows,MagickTrue); 8537 XCheckRefreshWindows(display,windows); 8538 threshold=SiPrefixToDouble(factor,QuantumRange); 8539 (void) SolarizeImage(*image,threshold,exception); 8540 XSetCursorState(display,windows,MagickFalse); 8541 if (windows->image.orphan != MagickFalse) 8542 break; 8543 XConfigureImageColormap(display,resource_info,windows,*image); 8544 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8545 break; 8546 } 8547 case SwirlCommand: 8548 { 8549 Image 8550 *swirl_image; 8551 8552 static char 8553 degrees[MaxTextExtent] = "60"; 8554 8555 /* 8556 Query user for swirl angle. 8557 */ 8558 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8559 degrees); 8560 if (*degrees == '\0') 8561 break; 8562 /* 8563 Swirl image pixels about the center. 8564 */ 8565 XSetCursorState(display,windows,MagickTrue); 8566 XCheckRefreshWindows(display,windows); 8567 flags=ParseGeometry(degrees,&geometry_info); 8568 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8569 exception); 8570 if (swirl_image != (Image *) NULL) 8571 { 8572 *image=DestroyImage(*image); 8573 *image=swirl_image; 8574 } 8575 CatchException(exception); 8576 XSetCursorState(display,windows,MagickFalse); 8577 if (windows->image.orphan != MagickFalse) 8578 break; 8579 XConfigureImageColormap(display,resource_info,windows,*image); 8580 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8581 break; 8582 } 8583 case ImplodeCommand: 8584 { 8585 Image 8586 *implode_image; 8587 8588 static char 8589 factor[MaxTextExtent] = "0.3"; 8590 8591 /* 8592 Query user for implode factor. 8593 */ 8594 (void) XDialogWidget(display,windows,"Implode", 8595 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8596 if (*factor == '\0') 8597 break; 8598 /* 8599 Implode image pixels about the center. 8600 */ 8601 XSetCursorState(display,windows,MagickTrue); 8602 XCheckRefreshWindows(display,windows); 8603 flags=ParseGeometry(factor,&geometry_info); 8604 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8605 exception); 8606 if (implode_image != (Image *) NULL) 8607 { 8608 *image=DestroyImage(*image); 8609 *image=implode_image; 8610 } 8611 CatchException(exception); 8612 XSetCursorState(display,windows,MagickFalse); 8613 if (windows->image.orphan != MagickFalse) 8614 break; 8615 XConfigureImageColormap(display,resource_info,windows,*image); 8616 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8617 break; 8618 } 8619 case VignetteCommand: 8620 { 8621 Image 8622 *vignette_image; 8623 8624 static char 8625 geometry[MaxTextExtent] = "0x20"; 8626 8627 /* 8628 Query user for the vignette geometry. 8629 */ 8630 (void) XDialogWidget(display,windows,"Vignette", 8631 "Enter the radius, sigma, and x and y offsets:",geometry); 8632 if (*geometry == '\0') 8633 break; 8634 /* 8635 Soften the edges of the image in vignette style 8636 */ 8637 XSetCursorState(display,windows,MagickTrue); 8638 XCheckRefreshWindows(display,windows); 8639 flags=ParseGeometry(geometry,&geometry_info); 8640 if ((flags & SigmaValue) == 0) 8641 geometry_info.sigma=1.0; 8642 if ((flags & XiValue) == 0) 8643 geometry_info.xi=0.1*(*image)->columns; 8644 if ((flags & PsiValue) == 0) 8645 geometry_info.psi=0.1*(*image)->rows; 8646 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8647 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8648 0.5),exception); 8649 if (vignette_image != (Image *) NULL) 8650 { 8651 *image=DestroyImage(*image); 8652 *image=vignette_image; 8653 } 8654 CatchException(exception); 8655 XSetCursorState(display,windows,MagickFalse); 8656 if (windows->image.orphan != MagickFalse) 8657 break; 8658 XConfigureImageColormap(display,resource_info,windows,*image); 8659 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8660 break; 8661 } 8662 case WaveCommand: 8663 { 8664 Image 8665 *wave_image; 8666 8667 static char 8668 geometry[MaxTextExtent] = "25x150"; 8669 8670 /* 8671 Query user for the wave geometry. 8672 */ 8673 (void) XDialogWidget(display,windows,"Wave", 8674 "Enter the amplitude and length of the wave:",geometry); 8675 if (*geometry == '\0') 8676 break; 8677 /* 8678 Alter an image along a sine wave. 8679 */ 8680 XSetCursorState(display,windows,MagickTrue); 8681 XCheckRefreshWindows(display,windows); 8682 flags=ParseGeometry(geometry,&geometry_info); 8683 if ((flags & SigmaValue) == 0) 8684 geometry_info.sigma=1.0; 8685 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8686 (*image)->interpolate,exception); 8687 if (wave_image != (Image *) NULL) 8688 { 8689 *image=DestroyImage(*image); 8690 *image=wave_image; 8691 } 8692 CatchException(exception); 8693 XSetCursorState(display,windows,MagickFalse); 8694 if (windows->image.orphan != MagickFalse) 8695 break; 8696 XConfigureImageColormap(display,resource_info,windows,*image); 8697 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8698 break; 8699 } 8700 case OilPaintCommand: 8701 { 8702 Image 8703 *paint_image; 8704 8705 static char 8706 radius[MaxTextExtent] = "0"; 8707 8708 /* 8709 Query user for circular neighborhood radius. 8710 */ 8711 (void) XDialogWidget(display,windows,"Oil Paint", 8712 "Enter the mask radius:",radius); 8713 if (*radius == '\0') 8714 break; 8715 /* 8716 OilPaint image scanlines. 8717 */ 8718 XSetCursorState(display,windows,MagickTrue); 8719 XCheckRefreshWindows(display,windows); 8720 flags=ParseGeometry(radius,&geometry_info); 8721 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8722 exception); 8723 if (paint_image != (Image *) NULL) 8724 { 8725 *image=DestroyImage(*image); 8726 *image=paint_image; 8727 } 8728 CatchException(exception); 8729 XSetCursorState(display,windows,MagickFalse); 8730 if (windows->image.orphan != MagickFalse) 8731 break; 8732 XConfigureImageColormap(display,resource_info,windows,*image); 8733 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8734 break; 8735 } 8736 case CharcoalDrawCommand: 8737 { 8738 Image 8739 *charcoal_image; 8740 8741 static char 8742 radius[MaxTextExtent] = "0x1"; 8743 8744 /* 8745 Query user for charcoal radius. 8746 */ 8747 (void) XDialogWidget(display,windows,"Charcoal Draw", 8748 "Enter the charcoal radius and sigma:",radius); 8749 if (*radius == '\0') 8750 break; 8751 /* 8752 Charcoal the image. 8753 */ 8754 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8755 exception); 8756 XSetCursorState(display,windows,MagickTrue); 8757 XCheckRefreshWindows(display,windows); 8758 flags=ParseGeometry(radius,&geometry_info); 8759 if ((flags & SigmaValue) == 0) 8760 geometry_info.sigma=geometry_info.rho; 8761 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8762 geometry_info.xi,exception); 8763 if (charcoal_image != (Image *) NULL) 8764 { 8765 *image=DestroyImage(*image); 8766 *image=charcoal_image; 8767 } 8768 CatchException(exception); 8769 XSetCursorState(display,windows,MagickFalse); 8770 if (windows->image.orphan != MagickFalse) 8771 break; 8772 XConfigureImageColormap(display,resource_info,windows,*image); 8773 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8774 break; 8775 } 8776 case AnnotateCommand: 8777 { 8778 /* 8779 Annotate the image with text. 8780 */ 8781 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8782 if (status == MagickFalse) 8783 { 8784 XNoticeWidget(display,windows,"Unable to annotate X image", 8785 (*image)->filename); 8786 break; 8787 } 8788 break; 8789 } 8790 case DrawCommand: 8791 { 8792 /* 8793 Draw image. 8794 */ 8795 status=XDrawEditImage(display,resource_info,windows,image,exception); 8796 if (status == MagickFalse) 8797 { 8798 XNoticeWidget(display,windows,"Unable to draw on the X image", 8799 (*image)->filename); 8800 break; 8801 } 8802 break; 8803 } 8804 case ColorCommand: 8805 { 8806 /* 8807 Color edit. 8808 */ 8809 status=XColorEditImage(display,resource_info,windows,image,exception); 8810 if (status == MagickFalse) 8811 { 8812 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8813 (*image)->filename); 8814 break; 8815 } 8816 break; 8817 } 8818 case MatteCommand: 8819 { 8820 /* 8821 Matte edit. 8822 */ 8823 status=XMatteEditImage(display,resource_info,windows,image,exception); 8824 if (status == MagickFalse) 8825 { 8826 XNoticeWidget(display,windows,"Unable to matte edit X image", 8827 (*image)->filename); 8828 break; 8829 } 8830 break; 8831 } 8832 case CompositeCommand: 8833 { 8834 /* 8835 Composite image. 8836 */ 8837 status=XCompositeImage(display,resource_info,windows,*image, 8838 exception); 8839 if (status == MagickFalse) 8840 { 8841 XNoticeWidget(display,windows,"Unable to composite X image", 8842 (*image)->filename); 8843 break; 8844 } 8845 break; 8846 } 8847 case AddBorderCommand: 8848 { 8849 Image 8850 *border_image; 8851 8852 static char 8853 geometry[MaxTextExtent] = "6x6"; 8854 8855 /* 8856 Query user for border color and geometry. 8857 */ 8858 XColorBrowserWidget(display,windows,"Select",color); 8859 if (*color == '\0') 8860 break; 8861 (void) XDialogWidget(display,windows,"Add Border", 8862 "Enter border geometry:",geometry); 8863 if (*geometry == '\0') 8864 break; 8865 /* 8866 Add a border to the image. 8867 */ 8868 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8869 exception); 8870 XSetCursorState(display,windows,MagickTrue); 8871 XCheckRefreshWindows(display,windows); 8872 (void) QueryColorDatabase(color,&(*image)->border_color, 8873 exception); 8874 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8875 exception); 8876 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8877 exception); 8878 if (border_image != (Image *) NULL) 8879 { 8880 *image=DestroyImage(*image); 8881 *image=border_image; 8882 } 8883 CatchException(exception); 8884 XSetCursorState(display,windows,MagickFalse); 8885 if (windows->image.orphan != MagickFalse) 8886 break; 8887 windows->image.window_changes.width=(int) (*image)->columns; 8888 windows->image.window_changes.height=(int) (*image)->rows; 8889 XConfigureImageColormap(display,resource_info,windows,*image); 8890 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8891 break; 8892 } 8893 case AddFrameCommand: 8894 { 8895 FrameInfo 8896 frame_info; 8897 8898 Image 8899 *frame_image; 8900 8901 static char 8902 geometry[MaxTextExtent] = "6x6"; 8903 8904 /* 8905 Query user for frame color and geometry. 8906 */ 8907 XColorBrowserWidget(display,windows,"Select",color); 8908 if (*color == '\0') 8909 break; 8910 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8911 geometry); 8912 if (*geometry == '\0') 8913 break; 8914 /* 8915 Surround image with an ornamental border. 8916 */ 8917 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8918 exception); 8919 XSetCursorState(display,windows,MagickTrue); 8920 XCheckRefreshWindows(display,windows); 8921 (void) QueryColorDatabase(color,&(*image)->matte_color, 8922 exception); 8923 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8924 exception); 8925 frame_info.width=page_geometry.width; 8926 frame_info.height=page_geometry.height; 8927 frame_info.outer_bevel=page_geometry.x; 8928 frame_info.inner_bevel=page_geometry.y; 8929 frame_info.x=(ssize_t) frame_info.width; 8930 frame_info.y=(ssize_t) frame_info.height; 8931 frame_info.width=(*image)->columns+2*frame_info.width; 8932 frame_info.height=(*image)->rows+2*frame_info.height; 8933 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8934 if (frame_image != (Image *) NULL) 8935 { 8936 *image=DestroyImage(*image); 8937 *image=frame_image; 8938 } 8939 CatchException(exception); 8940 XSetCursorState(display,windows,MagickFalse); 8941 if (windows->image.orphan != MagickFalse) 8942 break; 8943 windows->image.window_changes.width=(int) (*image)->columns; 8944 windows->image.window_changes.height=(int) (*image)->rows; 8945 XConfigureImageColormap(display,resource_info,windows,*image); 8946 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8947 break; 8948 } 8949 case CommentCommand: 8950 { 8951 const char 8952 *value; 8953 8954 FILE 8955 *file; 8956 8957 int 8958 unique_file; 8959 8960 /* 8961 Edit image comment. 8962 */ 8963 unique_file=AcquireUniqueFileResource(image_info->filename); 8964 if (unique_file == -1) 8965 XNoticeWidget(display,windows,"Unable to edit image comment", 8966 image_info->filename); 8967 value=GetImageProperty(*image,"comment"); 8968 if (value == (char *) NULL) 8969 unique_file=close(unique_file)-1; 8970 else 8971 { 8972 register const char 8973 *p; 8974 8975 file=fdopen(unique_file,"w"); 8976 if (file == (FILE *) NULL) 8977 { 8978 XNoticeWidget(display,windows,"Unable to edit image comment", 8979 image_info->filename); 8980 break; 8981 } 8982 for (p=value; *p != '\0'; p++) 8983 (void) fputc((int) *p,file); 8984 (void) fputc('\n',file); 8985 (void) fclose(file); 8986 } 8987 XSetCursorState(display,windows,MagickTrue); 8988 XCheckRefreshWindows(display,windows); 8989 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8990 exception); 8991 if (status == MagickFalse) 8992 XNoticeWidget(display,windows,"Unable to edit image comment", 8993 (char *) NULL); 8994 else 8995 { 8996 char 8997 *comment; 8998 8999 comment=FileToString(image_info->filename,~0UL,exception); 9000 if (comment != (char *) NULL) 9001 { 9002 (void) SetImageProperty(*image,"comment",comment); 9003 (*image)->taint=MagickTrue; 9004 } 9005 } 9006 (void) RelinquishUniqueFileResource(image_info->filename); 9007 XSetCursorState(display,windows,MagickFalse); 9008 break; 9009 } 9010 case LaunchCommand: 9011 { 9012 /* 9013 Launch program. 9014 */ 9015 XSetCursorState(display,windows,MagickTrue); 9016 XCheckRefreshWindows(display,windows); 9017 (void) AcquireUniqueFilename(filename); 9018 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9019 filename); 9020 status=WriteImage(image_info,*image,exception); 9021 if (status == MagickFalse) 9022 XNoticeWidget(display,windows,"Unable to launch image editor", 9023 (char *) NULL); 9024 else 9025 { 9026 nexus=ReadImage(resource_info->image_info,exception); 9027 CatchException(exception); 9028 XClientMessage(display,windows->image.id,windows->im_protocols, 9029 windows->im_next_image,CurrentTime); 9030 } 9031 (void) RelinquishUniqueFileResource(filename); 9032 XSetCursorState(display,windows,MagickFalse); 9033 break; 9034 } 9035 case RegionofInterestCommand: 9036 { 9037 /* 9038 Apply an image processing technique to a region of interest. 9039 */ 9040 (void) XROIImage(display,resource_info,windows,image,exception); 9041 break; 9042 } 9043 case InfoCommand: 9044 break; 9045 case ZoomCommand: 9046 { 9047 /* 9048 Zoom image. 9049 */ 9050 if (windows->magnify.mapped != MagickFalse) 9051 (void) XRaiseWindow(display,windows->magnify.id); 9052 else 9053 { 9054 /* 9055 Make magnify image. 9056 */ 9057 XSetCursorState(display,windows,MagickTrue); 9058 (void) XMapRaised(display,windows->magnify.id); 9059 XSetCursorState(display,windows,MagickFalse); 9060 } 9061 break; 9062 } 9063 case ShowPreviewCommand: 9064 { 9065 char 9066 **previews; 9067 9068 Image 9069 *preview_image; 9070 9071 static char 9072 preview_type[MaxTextExtent] = "Gamma"; 9073 9074 /* 9075 Select preview type from menu. 9076 */ 9077 previews=GetCommandOptions(MagickPreviewOptions); 9078 if (previews == (char **) NULL) 9079 break; 9080 XListBrowserWidget(display,windows,&windows->widget, 9081 (const char **) previews,"Preview", 9082 "Select an enhancement, effect, or F/X:",preview_type); 9083 previews=DestroyStringList(previews); 9084 if (*preview_type == '\0') 9085 break; 9086 /* 9087 Show image preview. 9088 */ 9089 XSetCursorState(display,windows,MagickTrue); 9090 XCheckRefreshWindows(display,windows); 9091 image_info->preview_type=(PreviewType) 9092 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9093 image_info->group=(ssize_t) windows->image.id; 9094 (void) DeleteImageProperty(*image,"label"); 9095 (void) SetImageProperty(*image,"label","Preview"); 9096 (void) AcquireUniqueFilename(filename); 9097 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9098 filename); 9099 status=WriteImage(image_info,*image,exception); 9100 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9101 preview_image=ReadImage(image_info,exception); 9102 (void) RelinquishUniqueFileResource(filename); 9103 if (preview_image == (Image *) NULL) 9104 break; 9105 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9106 filename); 9107 status=WriteImage(image_info,preview_image,exception); 9108 preview_image=DestroyImage(preview_image); 9109 if (status == MagickFalse) 9110 XNoticeWidget(display,windows,"Unable to show image preview", 9111 (*image)->filename); 9112 XDelay(display,1500); 9113 XSetCursorState(display,windows,MagickFalse); 9114 break; 9115 } 9116 case ShowHistogramCommand: 9117 { 9118 Image 9119 *histogram_image; 9120 9121 /* 9122 Show image histogram. 9123 */ 9124 XSetCursorState(display,windows,MagickTrue); 9125 XCheckRefreshWindows(display,windows); 9126 image_info->group=(ssize_t) windows->image.id; 9127 (void) DeleteImageProperty(*image,"label"); 9128 (void) SetImageProperty(*image,"label","Histogram"); 9129 (void) AcquireUniqueFilename(filename); 9130 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9131 filename); 9132 status=WriteImage(image_info,*image,exception); 9133 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9134 histogram_image=ReadImage(image_info,exception); 9135 (void) RelinquishUniqueFileResource(filename); 9136 if (histogram_image == (Image *) NULL) 9137 break; 9138 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9139 "show:%s",filename); 9140 status=WriteImage(image_info,histogram_image,exception); 9141 histogram_image=DestroyImage(histogram_image); 9142 if (status == MagickFalse) 9143 XNoticeWidget(display,windows,"Unable to show histogram", 9144 (*image)->filename); 9145 XDelay(display,1500); 9146 XSetCursorState(display,windows,MagickFalse); 9147 break; 9148 } 9149 case ShowMatteCommand: 9150 { 9151 Image 9152 *matte_image; 9153 9154 if ((*image)->matte == MagickFalse) 9155 { 9156 XNoticeWidget(display,windows, 9157 "Image does not have any matte information",(*image)->filename); 9158 break; 9159 } 9160 /* 9161 Show image matte. 9162 */ 9163 XSetCursorState(display,windows,MagickTrue); 9164 XCheckRefreshWindows(display,windows); 9165 image_info->group=(ssize_t) windows->image.id; 9166 (void) DeleteImageProperty(*image,"label"); 9167 (void) SetImageProperty(*image,"label","Matte"); 9168 (void) AcquireUniqueFilename(filename); 9169 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9170 filename); 9171 status=WriteImage(image_info,*image,exception); 9172 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9173 matte_image=ReadImage(image_info,exception); 9174 (void) RelinquishUniqueFileResource(filename); 9175 if (matte_image == (Image *) NULL) 9176 break; 9177 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9178 filename); 9179 status=WriteImage(image_info,matte_image,exception); 9180 matte_image=DestroyImage(matte_image); 9181 if (status == MagickFalse) 9182 XNoticeWidget(display,windows,"Unable to show matte", 9183 (*image)->filename); 9184 XDelay(display,1500); 9185 XSetCursorState(display,windows,MagickFalse); 9186 break; 9187 } 9188 case BackgroundCommand: 9189 { 9190 /* 9191 Background image. 9192 */ 9193 status=XBackgroundImage(display,resource_info,windows,image,exception); 9194 if (status == MagickFalse) 9195 break; 9196 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9197 if (nexus != (Image *) NULL) 9198 XClientMessage(display,windows->image.id,windows->im_protocols, 9199 windows->im_next_image,CurrentTime); 9200 break; 9201 } 9202 case SlideShowCommand: 9203 { 9204 static char 9205 delay[MaxTextExtent] = "5"; 9206 9207 /* 9208 Display next image after pausing. 9209 */ 9210 (void) XDialogWidget(display,windows,"Slide Show", 9211 "Pause how many 1/100ths of a second between images:",delay); 9212 if (*delay == '\0') 9213 break; 9214 resource_info->delay=StringToUnsignedLong(delay); 9215 XClientMessage(display,windows->image.id,windows->im_protocols, 9216 windows->im_next_image,CurrentTime); 9217 break; 9218 } 9219 case PreferencesCommand: 9220 { 9221 /* 9222 Set user preferences. 9223 */ 9224 status=XPreferencesWidget(display,resource_info,windows); 9225 if (status == MagickFalse) 9226 break; 9227 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9228 if (nexus != (Image *) NULL) 9229 XClientMessage(display,windows->image.id,windows->im_protocols, 9230 windows->im_next_image,CurrentTime); 9231 break; 9232 } 9233 case HelpCommand: 9234 { 9235 /* 9236 User requested help. 9237 */ 9238 XTextViewWidget(display,resource_info,windows,MagickFalse, 9239 "Help Viewer - Display",DisplayHelp); 9240 break; 9241 } 9242 case BrowseDocumentationCommand: 9243 { 9244 Atom 9245 mozilla_atom; 9246 9247 Window 9248 mozilla_window, 9249 root_window; 9250 9251 /* 9252 Browse the ImageMagick documentation. 9253 */ 9254 root_window=XRootWindow(display,XDefaultScreen(display)); 9255 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9256 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9257 if (mozilla_window != (Window) NULL) 9258 { 9259 char 9260 command[MaxTextExtent], 9261 *url; 9262 9263 /* 9264 Display documentation using Netscape remote control. 9265 */ 9266 url=GetMagickHomeURL(); 9267 (void) FormatLocaleString(command,MaxTextExtent, 9268 "openurl(%s,new-tab)",url); 9269 url=DestroyString(url); 9270 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9271 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9272 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9273 XSetCursorState(display,windows,MagickFalse); 9274 break; 9275 } 9276 XSetCursorState(display,windows,MagickTrue); 9277 XCheckRefreshWindows(display,windows); 9278 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9279 exception); 9280 if (status == MagickFalse) 9281 XNoticeWidget(display,windows,"Unable to browse documentation", 9282 (char *) NULL); 9283 XDelay(display,1500); 9284 XSetCursorState(display,windows,MagickFalse); 9285 break; 9286 } 9287 case VersionCommand: 9288 { 9289 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9290 GetMagickCopyright()); 9291 break; 9292 } 9293 case SaveToUndoBufferCommand: 9294 break; 9295 default: 9296 { 9297 (void) XBell(display,0); 9298 break; 9299 } 9300 } 9301 image_info=DestroyImageInfo(image_info); 9302 return(nexus); 9303} 9304 9305/* 9306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9307% % 9308% % 9309% % 9310+ X M a g n i f y I m a g e % 9311% % 9312% % 9313% % 9314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9315% 9316% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9317% The magnified portion is displayed in a separate window. 9318% 9319% The format of the XMagnifyImage method is: 9320% 9321% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9322% 9323% A description of each parameter follows: 9324% 9325% o display: Specifies a connection to an X server; returned from 9326% XOpenDisplay. 9327% 9328% o windows: Specifies a pointer to a XWindows structure. 9329% 9330% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9331% the entire image is refreshed. 9332% 9333*/ 9334static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9335{ 9336 char 9337 text[MaxTextExtent]; 9338 9339 register int 9340 x, 9341 y; 9342 9343 size_t 9344 state; 9345 9346 /* 9347 Update magnified image until the mouse button is released. 9348 */ 9349 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9350 state=DefaultState; 9351 x=event->xbutton.x; 9352 y=event->xbutton.y; 9353 windows->magnify.x=(int) windows->image.x+x; 9354 windows->magnify.y=(int) windows->image.y+y; 9355 do 9356 { 9357 /* 9358 Map and unmap Info widget as text cursor crosses its boundaries. 9359 */ 9360 if (windows->info.mapped != MagickFalse) 9361 { 9362 if ((x < (int) (windows->info.x+windows->info.width)) && 9363 (y < (int) (windows->info.y+windows->info.height))) 9364 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9365 } 9366 else 9367 if ((x > (int) (windows->info.x+windows->info.width)) || 9368 (y > (int) (windows->info.y+windows->info.height))) 9369 (void) XMapWindow(display,windows->info.id); 9370 if (windows->info.mapped != MagickFalse) 9371 { 9372 /* 9373 Display pointer position. 9374 */ 9375 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9376 windows->magnify.x,windows->magnify.y); 9377 XInfoWidget(display,windows,text); 9378 } 9379 /* 9380 Wait for next event. 9381 */ 9382 XScreenEvent(display,windows,event); 9383 switch (event->type) 9384 { 9385 case ButtonPress: 9386 break; 9387 case ButtonRelease: 9388 { 9389 /* 9390 User has finished magnifying image. 9391 */ 9392 x=event->xbutton.x; 9393 y=event->xbutton.y; 9394 state|=ExitState; 9395 break; 9396 } 9397 case Expose: 9398 break; 9399 case MotionNotify: 9400 { 9401 x=event->xmotion.x; 9402 y=event->xmotion.y; 9403 break; 9404 } 9405 default: 9406 break; 9407 } 9408 /* 9409 Check boundary conditions. 9410 */ 9411 if (x < 0) 9412 x=0; 9413 else 9414 if (x >= (int) windows->image.width) 9415 x=(int) windows->image.width-1; 9416 if (y < 0) 9417 y=0; 9418 else 9419 if (y >= (int) windows->image.height) 9420 y=(int) windows->image.height-1; 9421 } while ((state & ExitState) == 0); 9422 /* 9423 Display magnified image. 9424 */ 9425 XSetCursorState(display,windows,MagickFalse); 9426} 9427 9428/* 9429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9430% % 9431% % 9432% % 9433+ X M a g n i f y W i n d o w C o m m a n d % 9434% % 9435% % 9436% % 9437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9438% 9439% XMagnifyWindowCommand() moves the image within an Magnify window by one 9440% pixel as specified by the key symbol. 9441% 9442% The format of the XMagnifyWindowCommand method is: 9443% 9444% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9445% const MagickStatusType state,const KeySym key_symbol) 9446% 9447% A description of each parameter follows: 9448% 9449% o display: Specifies a connection to an X server; returned from 9450% XOpenDisplay. 9451% 9452% o windows: Specifies a pointer to a XWindows structure. 9453% 9454% o state: key mask. 9455% 9456% o key_symbol: Specifies a KeySym which indicates which side of the image 9457% to trim. 9458% 9459*/ 9460static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9461 const MagickStatusType state,const KeySym key_symbol) 9462{ 9463 unsigned int 9464 quantum; 9465 9466 /* 9467 User specified a magnify factor or position. 9468 */ 9469 quantum=1; 9470 if ((state & Mod1Mask) != 0) 9471 quantum=10; 9472 switch ((int) key_symbol) 9473 { 9474 case QuitCommand: 9475 { 9476 (void) XWithdrawWindow(display,windows->magnify.id, 9477 windows->magnify.screen); 9478 break; 9479 } 9480 case XK_Home: 9481 case XK_KP_Home: 9482 { 9483 windows->magnify.x=(int) windows->image.width/2; 9484 windows->magnify.y=(int) windows->image.height/2; 9485 break; 9486 } 9487 case XK_Left: 9488 case XK_KP_Left: 9489 { 9490 if (windows->magnify.x > 0) 9491 windows->magnify.x-=quantum; 9492 break; 9493 } 9494 case XK_Up: 9495 case XK_KP_Up: 9496 { 9497 if (windows->magnify.y > 0) 9498 windows->magnify.y-=quantum; 9499 break; 9500 } 9501 case XK_Right: 9502 case XK_KP_Right: 9503 { 9504 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9505 windows->magnify.x+=quantum; 9506 break; 9507 } 9508 case XK_Down: 9509 case XK_KP_Down: 9510 { 9511 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9512 windows->magnify.y+=quantum; 9513 break; 9514 } 9515 case XK_0: 9516 case XK_1: 9517 case XK_2: 9518 case XK_3: 9519 case XK_4: 9520 case XK_5: 9521 case XK_6: 9522 case XK_7: 9523 case XK_8: 9524 case XK_9: 9525 { 9526 windows->magnify.data=(key_symbol-XK_0); 9527 break; 9528 } 9529 case XK_KP_0: 9530 case XK_KP_1: 9531 case XK_KP_2: 9532 case XK_KP_3: 9533 case XK_KP_4: 9534 case XK_KP_5: 9535 case XK_KP_6: 9536 case XK_KP_7: 9537 case XK_KP_8: 9538 case XK_KP_9: 9539 { 9540 windows->magnify.data=(key_symbol-XK_KP_0); 9541 break; 9542 } 9543 default: 9544 break; 9545 } 9546 XMakeMagnifyImage(display,windows); 9547} 9548 9549/* 9550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9551% % 9552% % 9553% % 9554+ X M a k e P a n I m a g e % 9555% % 9556% % 9557% % 9558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9559% 9560% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9561% icon window. 9562% 9563% The format of the XMakePanImage method is: 9564% 9565% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9566% XWindows *windows,Image *image,ExceptionInfo *exception) 9567% 9568% A description of each parameter follows: 9569% 9570% o display: Specifies a connection to an X server; returned from 9571% XOpenDisplay. 9572% 9573% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9574% 9575% o windows: Specifies a pointer to a XWindows structure. 9576% 9577% o image: the image. 9578% 9579% o exception: return any errors or warnings in this structure. 9580% 9581*/ 9582static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9583 XWindows *windows,Image *image,ExceptionInfo *exception) 9584{ 9585 MagickStatusType 9586 status; 9587 9588 /* 9589 Create and display image for panning icon. 9590 */ 9591 XSetCursorState(display,windows,MagickTrue); 9592 XCheckRefreshWindows(display,windows); 9593 windows->pan.x=(int) windows->image.x; 9594 windows->pan.y=(int) windows->image.y; 9595 status=XMakeImage(display,resource_info,&windows->pan,image, 9596 windows->pan.width,windows->pan.height,exception); 9597 if (status == MagickFalse) 9598 ThrowXWindowFatalException(ResourceLimitError, 9599 "MemoryAllocationFailed",image->filename); 9600 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9601 windows->pan.pixmap); 9602 (void) XClearWindow(display,windows->pan.id); 9603 XDrawPanRectangle(display,windows); 9604 XSetCursorState(display,windows,MagickFalse); 9605} 9606 9607/* 9608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9609% % 9610% % 9611% % 9612+ X M a t t a E d i t I m a g e % 9613% % 9614% % 9615% % 9616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9617% 9618% XMatteEditImage() allows the user to interactively change the Matte channel 9619% of an image. If the image is PseudoClass it is promoted to DirectClass 9620% before the matte information is stored. 9621% 9622% The format of the XMatteEditImage method is: 9623% 9624% MagickBooleanType XMatteEditImage(Display *display, 9625% XResourceInfo *resource_info,XWindows *windows,Image **image, 9626% ExceptionInfo *exception) 9627% 9628% A description of each parameter follows: 9629% 9630% o display: Specifies a connection to an X server; returned from 9631% XOpenDisplay. 9632% 9633% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9634% 9635% o windows: Specifies a pointer to a XWindows structure. 9636% 9637% o image: the image; returned from ReadImage. 9638% 9639% o exception: return any errors or warnings in this structure. 9640% 9641*/ 9642static MagickBooleanType XMatteEditImage(Display *display, 9643 XResourceInfo *resource_info,XWindows *windows,Image **image, 9644 ExceptionInfo *exception) 9645{ 9646 static char 9647 matte[MaxTextExtent] = "0"; 9648 9649 static const char 9650 *MatteEditMenu[] = 9651 { 9652 "Method", 9653 "Border Color", 9654 "Fuzz", 9655 "Matte Value", 9656 "Undo", 9657 "Help", 9658 "Dismiss", 9659 (char *) NULL 9660 }; 9661 9662 static const ModeType 9663 MatteEditCommands[] = 9664 { 9665 MatteEditMethod, 9666 MatteEditBorderCommand, 9667 MatteEditFuzzCommand, 9668 MatteEditValueCommand, 9669 MatteEditUndoCommand, 9670 MatteEditHelpCommand, 9671 MatteEditDismissCommand 9672 }; 9673 9674 static PaintMethod 9675 method = PointMethod; 9676 9677 static XColor 9678 border_color = { 0, 0, 0, 0, 0, 0 }; 9679 9680 char 9681 command[MaxTextExtent], 9682 text[MaxTextExtent]; 9683 9684 Cursor 9685 cursor; 9686 9687 int 9688 entry, 9689 id, 9690 x, 9691 x_offset, 9692 y, 9693 y_offset; 9694 9695 register int 9696 i; 9697 9698 register Quantum 9699 *q; 9700 9701 unsigned int 9702 height, 9703 width; 9704 9705 size_t 9706 state; 9707 9708 XEvent 9709 event; 9710 9711 /* 9712 Map Command widget. 9713 */ 9714 (void) CloneString(&windows->command.name,"Matte Edit"); 9715 windows->command.data=4; 9716 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9717 (void) XMapRaised(display,windows->command.id); 9718 XClientMessage(display,windows->image.id,windows->im_protocols, 9719 windows->im_update_widget,CurrentTime); 9720 /* 9721 Make cursor. 9722 */ 9723 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9724 resource_info->background_color,resource_info->foreground_color); 9725 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9726 /* 9727 Track pointer until button 1 is pressed. 9728 */ 9729 XQueryPosition(display,windows->image.id,&x,&y); 9730 (void) XSelectInput(display,windows->image.id, 9731 windows->image.attributes.event_mask | PointerMotionMask); 9732 state=DefaultState; 9733 do 9734 { 9735 if (windows->info.mapped != MagickFalse) 9736 { 9737 /* 9738 Display pointer position. 9739 */ 9740 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9741 x+windows->image.x,y+windows->image.y); 9742 XInfoWidget(display,windows,text); 9743 } 9744 /* 9745 Wait for next event. 9746 */ 9747 XScreenEvent(display,windows,&event); 9748 if (event.xany.window == windows->command.id) 9749 { 9750 /* 9751 Select a command from the Command widget. 9752 */ 9753 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9754 if (id < 0) 9755 { 9756 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9757 continue; 9758 } 9759 switch (MatteEditCommands[id]) 9760 { 9761 case MatteEditMethod: 9762 { 9763 char 9764 **methods; 9765 9766 /* 9767 Select a method from the pop-up menu. 9768 */ 9769 methods=GetCommandOptions(MagickMethodOptions); 9770 if (methods == (char **) NULL) 9771 break; 9772 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9773 (const char **) methods,command); 9774 if (entry >= 0) 9775 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9776 MagickFalse,methods[entry]); 9777 methods=DestroyStringList(methods); 9778 break; 9779 } 9780 case MatteEditBorderCommand: 9781 { 9782 const char 9783 *ColorMenu[MaxNumberPens]; 9784 9785 int 9786 pen_number; 9787 9788 /* 9789 Initialize menu selections. 9790 */ 9791 for (i=0; i < (int) (MaxNumberPens-2); i++) 9792 ColorMenu[i]=resource_info->pen_colors[i]; 9793 ColorMenu[MaxNumberPens-2]="Browser..."; 9794 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9795 /* 9796 Select a pen color from the pop-up menu. 9797 */ 9798 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9799 (const char **) ColorMenu,command); 9800 if (pen_number < 0) 9801 break; 9802 if (pen_number == (MaxNumberPens-2)) 9803 { 9804 static char 9805 color_name[MaxTextExtent] = "gray"; 9806 9807 /* 9808 Select a pen color from a dialog. 9809 */ 9810 resource_info->pen_colors[pen_number]=color_name; 9811 XColorBrowserWidget(display,windows,"Select",color_name); 9812 if (*color_name == '\0') 9813 break; 9814 } 9815 /* 9816 Set border color. 9817 */ 9818 (void) XParseColor(display,windows->map_info->colormap, 9819 resource_info->pen_colors[pen_number],&border_color); 9820 break; 9821 } 9822 case MatteEditFuzzCommand: 9823 { 9824 static char 9825 fuzz[MaxTextExtent]; 9826 9827 static const char 9828 *FuzzMenu[] = 9829 { 9830 "0%", 9831 "2%", 9832 "5%", 9833 "10%", 9834 "15%", 9835 "Dialog...", 9836 (char *) NULL, 9837 }; 9838 9839 /* 9840 Select a command from the pop-up menu. 9841 */ 9842 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9843 command); 9844 if (entry < 0) 9845 break; 9846 if (entry != 5) 9847 { 9848 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 9849 QuantumRange+1.0); 9850 break; 9851 } 9852 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9853 (void) XDialogWidget(display,windows,"Ok", 9854 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9855 if (*fuzz == '\0') 9856 break; 9857 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9858 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 9859 break; 9860 } 9861 case MatteEditValueCommand: 9862 { 9863 static char 9864 message[MaxTextExtent]; 9865 9866 static const char 9867 *MatteMenu[] = 9868 { 9869 "Opaque", 9870 "Transparent", 9871 "Dialog...", 9872 (char *) NULL, 9873 }; 9874 9875 /* 9876 Select a command from the pop-up menu. 9877 */ 9878 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9879 command); 9880 if (entry < 0) 9881 break; 9882 if (entry != 2) 9883 { 9884 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9885 OpaqueAlpha); 9886 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9887 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9888 (Quantum) TransparentAlpha); 9889 break; 9890 } 9891 (void) FormatLocaleString(message,MaxTextExtent, 9892 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9893 QuantumRange); 9894 (void) XDialogWidget(display,windows,"Matte",message,matte); 9895 if (*matte == '\0') 9896 break; 9897 break; 9898 } 9899 case MatteEditUndoCommand: 9900 { 9901 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9902 image,exception); 9903 break; 9904 } 9905 case MatteEditHelpCommand: 9906 { 9907 XTextViewWidget(display,resource_info,windows,MagickFalse, 9908 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9909 break; 9910 } 9911 case MatteEditDismissCommand: 9912 { 9913 /* 9914 Prematurely exit. 9915 */ 9916 state|=EscapeState; 9917 state|=ExitState; 9918 break; 9919 } 9920 default: 9921 break; 9922 } 9923 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9924 continue; 9925 } 9926 switch (event.type) 9927 { 9928 case ButtonPress: 9929 { 9930 if (event.xbutton.button != Button1) 9931 break; 9932 if ((event.xbutton.window != windows->image.id) && 9933 (event.xbutton.window != windows->magnify.id)) 9934 break; 9935 /* 9936 Update matte data. 9937 */ 9938 x=event.xbutton.x; 9939 y=event.xbutton.y; 9940 (void) XMagickCommand(display,resource_info,windows, 9941 SaveToUndoBufferCommand,image,exception); 9942 state|=UpdateConfigurationState; 9943 break; 9944 } 9945 case ButtonRelease: 9946 { 9947 if (event.xbutton.button != Button1) 9948 break; 9949 if ((event.xbutton.window != windows->image.id) && 9950 (event.xbutton.window != windows->magnify.id)) 9951 break; 9952 /* 9953 Update colormap information. 9954 */ 9955 x=event.xbutton.x; 9956 y=event.xbutton.y; 9957 XConfigureImageColormap(display,resource_info,windows,*image); 9958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9959 XInfoWidget(display,windows,text); 9960 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9961 state&=(~UpdateConfigurationState); 9962 break; 9963 } 9964 case Expose: 9965 break; 9966 case KeyPress: 9967 { 9968 char 9969 command[MaxTextExtent]; 9970 9971 KeySym 9972 key_symbol; 9973 9974 if (event.xkey.window == windows->magnify.id) 9975 { 9976 Window 9977 window; 9978 9979 window=windows->magnify.id; 9980 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9981 } 9982 if (event.xkey.window != windows->image.id) 9983 break; 9984 /* 9985 Respond to a user key press. 9986 */ 9987 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9988 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9989 switch ((int) key_symbol) 9990 { 9991 case XK_Escape: 9992 case XK_F20: 9993 { 9994 /* 9995 Prematurely exit. 9996 */ 9997 state|=ExitState; 9998 break; 9999 } 10000 case XK_F1: 10001 case XK_Help: 10002 { 10003 XTextViewWidget(display,resource_info,windows,MagickFalse, 10004 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10005 break; 10006 } 10007 default: 10008 { 10009 (void) XBell(display,0); 10010 break; 10011 } 10012 } 10013 break; 10014 } 10015 case MotionNotify: 10016 { 10017 /* 10018 Map and unmap Info widget as cursor crosses its boundaries. 10019 */ 10020 x=event.xmotion.x; 10021 y=event.xmotion.y; 10022 if (windows->info.mapped != MagickFalse) 10023 { 10024 if ((x < (int) (windows->info.x+windows->info.width)) && 10025 (y < (int) (windows->info.y+windows->info.height))) 10026 (void) XWithdrawWindow(display,windows->info.id, 10027 windows->info.screen); 10028 } 10029 else 10030 if ((x > (int) (windows->info.x+windows->info.width)) || 10031 (y > (int) (windows->info.y+windows->info.height))) 10032 (void) XMapWindow(display,windows->info.id); 10033 break; 10034 } 10035 default: 10036 break; 10037 } 10038 if (event.xany.window == windows->magnify.id) 10039 { 10040 x=windows->magnify.x-windows->image.x; 10041 y=windows->magnify.y-windows->image.y; 10042 } 10043 x_offset=x; 10044 y_offset=y; 10045 if ((state & UpdateConfigurationState) != 0) 10046 { 10047 CacheView 10048 *image_view; 10049 10050 int 10051 x, 10052 y; 10053 10054 /* 10055 Matte edit is relative to image configuration. 10056 */ 10057 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10058 MagickTrue); 10059 XPutPixel(windows->image.ximage,x_offset,y_offset, 10060 windows->pixel_info->background_color.pixel); 10061 width=(unsigned int) (*image)->columns; 10062 height=(unsigned int) (*image)->rows; 10063 x=0; 10064 y=0; 10065 if (windows->image.crop_geometry != (char *) NULL) 10066 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10067 &height); 10068 x_offset=(int) (width*(windows->image.x+x_offset)/ 10069 windows->image.ximage->width+x); 10070 y_offset=(int) (height*(windows->image.y+y_offset)/ 10071 windows->image.ximage->height+y); 10072 if ((x_offset < 0) || (y_offset < 0)) 10073 continue; 10074 if ((x_offset >= (int) (*image)->columns) || 10075 (y_offset >= (int) (*image)->rows)) 10076 continue; 10077 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10078 return(MagickFalse); 10079 (*image)->matte=MagickTrue; 10080 image_view=AcquireCacheView(*image); 10081 switch (method) 10082 { 10083 case PointMethod: 10084 default: 10085 { 10086 /* 10087 Update matte information using point algorithm. 10088 */ 10089 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10090 (ssize_t) y_offset,1,1,exception); 10091 if (q == (Quantum *) NULL) 10092 break; 10093 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10094 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10095 break; 10096 } 10097 case ReplaceMethod: 10098 { 10099 PixelPacket 10100 pixel, 10101 target; 10102 10103 /* 10104 Update matte information using replace algorithm. 10105 */ 10106 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10107 (ssize_t) y_offset,&target,exception); 10108 for (y=0; y < (int) (*image)->rows; y++) 10109 { 10110 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10111 (*image)->columns,1,exception); 10112 if (q == (Quantum *) NULL) 10113 break; 10114 for (x=0; x < (int) (*image)->columns; x++) 10115 { 10116 GetPixelPacket(*image,q,&pixel); 10117 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 10118 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10119 q+=GetPixelChannels(*image); 10120 } 10121 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10122 break; 10123 } 10124 break; 10125 } 10126 case FloodfillMethod: 10127 case FillToBorderMethod: 10128 { 10129 ChannelType 10130 channel_mask; 10131 10132 DrawInfo 10133 *draw_info; 10134 10135 PixelInfo 10136 target; 10137 10138 /* 10139 Update matte information using floodfill algorithm. 10140 */ 10141 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10142 (ssize_t) y_offset,&target,exception); 10143 if (method == FillToBorderMethod) 10144 { 10145 target.red=(MagickRealType) ScaleShortToQuantum( 10146 border_color.red); 10147 target.green=(MagickRealType) ScaleShortToQuantum( 10148 border_color.green); 10149 target.blue=(MagickRealType) ScaleShortToQuantum( 10150 border_color.blue); 10151 } 10152 draw_info=CloneDrawInfo(resource_info->image_info, 10153 (DrawInfo *) NULL); 10154 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10155 (char **) NULL)); 10156 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10157 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10158 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10159 MagickFalse : MagickTrue,exception); 10160 (void) SetPixelChannelMap(*image,channel_mask); 10161 draw_info=DestroyDrawInfo(draw_info); 10162 break; 10163 } 10164 case ResetMethod: 10165 { 10166 /* 10167 Update matte information using reset algorithm. 10168 */ 10169 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10170 return(MagickFalse); 10171 for (y=0; y < (int) (*image)->rows; y++) 10172 { 10173 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10174 (*image)->columns,1,exception); 10175 if (q == (Quantum *) NULL) 10176 break; 10177 for (x=0; x < (int) (*image)->columns; x++) 10178 { 10179 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10180 q+=GetPixelChannels(*image); 10181 } 10182 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10183 break; 10184 } 10185 if (StringToLong(matte) == (long) OpaqueAlpha) 10186 (*image)->matte=MagickFalse; 10187 break; 10188 } 10189 } 10190 image_view=DestroyCacheView(image_view); 10191 state&=(~UpdateConfigurationState); 10192 } 10193 } while ((state & ExitState) == 0); 10194 (void) XSelectInput(display,windows->image.id, 10195 windows->image.attributes.event_mask); 10196 XSetCursorState(display,windows,MagickFalse); 10197 (void) XFreeCursor(display,cursor); 10198 return(MagickTrue); 10199} 10200 10201/* 10202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10203% % 10204% % 10205% % 10206+ X O p e n I m a g e % 10207% % 10208% % 10209% % 10210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10211% 10212% XOpenImage() loads an image from a file. 10213% 10214% The format of the XOpenImage method is: 10215% 10216% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10217% XWindows *windows,const unsigned int command) 10218% 10219% A description of each parameter follows: 10220% 10221% o display: Specifies a connection to an X server; returned from 10222% XOpenDisplay. 10223% 10224% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10225% 10226% o windows: Specifies a pointer to a XWindows structure. 10227% 10228% o command: A value other than zero indicates that the file is selected 10229% from the command line argument list. 10230% 10231*/ 10232static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10233 XWindows *windows,const MagickBooleanType command) 10234{ 10235 const MagickInfo 10236 *magick_info; 10237 10238 ExceptionInfo 10239 *exception; 10240 10241 Image 10242 *nexus; 10243 10244 ImageInfo 10245 *image_info; 10246 10247 static char 10248 filename[MaxTextExtent] = "\0"; 10249 10250 /* 10251 Request file name from user. 10252 */ 10253 if (command == MagickFalse) 10254 XFileBrowserWidget(display,windows,"Open",filename); 10255 else 10256 { 10257 char 10258 **filelist, 10259 **files; 10260 10261 int 10262 count, 10263 status; 10264 10265 register int 10266 i, 10267 j; 10268 10269 /* 10270 Select next image from the command line. 10271 */ 10272 status=XGetCommand(display,windows->image.id,&files,&count); 10273 if (status == 0) 10274 { 10275 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10276 return((Image *) NULL); 10277 } 10278 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10279 if (filelist == (char **) NULL) 10280 { 10281 ThrowXWindowFatalException(ResourceLimitError, 10282 "MemoryAllocationFailed","..."); 10283 (void) XFreeStringList(files); 10284 return((Image *) NULL); 10285 } 10286 j=0; 10287 for (i=1; i < count; i++) 10288 if (*files[i] != '-') 10289 filelist[j++]=files[i]; 10290 filelist[j]=(char *) NULL; 10291 XListBrowserWidget(display,windows,&windows->widget, 10292 (const char **) filelist,"Load","Select Image to Load:",filename); 10293 filelist=(char **) RelinquishMagickMemory(filelist); 10294 (void) XFreeStringList(files); 10295 } 10296 if (*filename == '\0') 10297 return((Image *) NULL); 10298 image_info=CloneImageInfo(resource_info->image_info); 10299 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10300 (void *) NULL); 10301 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10302 exception=AcquireExceptionInfo(); 10303 (void) SetImageInfo(image_info,0,exception); 10304 if (LocaleCompare(image_info->magick,"X") == 0) 10305 { 10306 char 10307 seconds[MaxTextExtent]; 10308 10309 /* 10310 User may want to delay the X server screen grab. 10311 */ 10312 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10313 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10314 seconds); 10315 if (*seconds == '\0') 10316 return((Image *) NULL); 10317 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10318 } 10319 magick_info=GetMagickInfo(image_info->magick,exception); 10320 if ((magick_info != (const MagickInfo *) NULL) && 10321 (magick_info->raw != MagickFalse)) 10322 { 10323 char 10324 geometry[MaxTextExtent]; 10325 10326 /* 10327 Request image size from the user. 10328 */ 10329 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10330 if (image_info->size != (char *) NULL) 10331 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10332 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10333 geometry); 10334 (void) CloneString(&image_info->size,geometry); 10335 } 10336 /* 10337 Load the image. 10338 */ 10339 XSetCursorState(display,windows,MagickTrue); 10340 XCheckRefreshWindows(display,windows); 10341 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10342 nexus=ReadImage(image_info,exception); 10343 CatchException(exception); 10344 XSetCursorState(display,windows,MagickFalse); 10345 if (nexus != (Image *) NULL) 10346 XClientMessage(display,windows->image.id,windows->im_protocols, 10347 windows->im_next_image,CurrentTime); 10348 else 10349 { 10350 char 10351 *text, 10352 **textlist; 10353 10354 /* 10355 Unknown image format. 10356 */ 10357 text=FileToString(filename,~0,exception); 10358 if (text == (char *) NULL) 10359 return((Image *) NULL); 10360 textlist=StringToList(text); 10361 if (textlist != (char **) NULL) 10362 { 10363 char 10364 title[MaxTextExtent]; 10365 10366 register int 10367 i; 10368 10369 (void) FormatLocaleString(title,MaxTextExtent, 10370 "Unknown format: %s",filename); 10371 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10372 (const char **) textlist); 10373 for (i=0; textlist[i] != (char *) NULL; i++) 10374 textlist[i]=DestroyString(textlist[i]); 10375 textlist=(char **) RelinquishMagickMemory(textlist); 10376 } 10377 text=DestroyString(text); 10378 } 10379 exception=DestroyExceptionInfo(exception); 10380 image_info=DestroyImageInfo(image_info); 10381 return(nexus); 10382} 10383 10384/* 10385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10386% % 10387% % 10388% % 10389+ X P a n I m a g e % 10390% % 10391% % 10392% % 10393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10394% 10395% XPanImage() pans the image until the mouse button is released. 10396% 10397% The format of the XPanImage method is: 10398% 10399% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10400% 10401% A description of each parameter follows: 10402% 10403% o display: Specifies a connection to an X server; returned from 10404% XOpenDisplay. 10405% 10406% o windows: Specifies a pointer to a XWindows structure. 10407% 10408% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10409% the entire image is refreshed. 10410% 10411*/ 10412static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10413{ 10414 char 10415 text[MaxTextExtent]; 10416 10417 Cursor 10418 cursor; 10419 10420 MagickRealType 10421 x_factor, 10422 y_factor; 10423 10424 RectangleInfo 10425 pan_info; 10426 10427 size_t 10428 state; 10429 10430 /* 10431 Define cursor. 10432 */ 10433 if ((windows->image.ximage->width > (int) windows->image.width) && 10434 (windows->image.ximage->height > (int) windows->image.height)) 10435 cursor=XCreateFontCursor(display,XC_fleur); 10436 else 10437 if (windows->image.ximage->width > (int) windows->image.width) 10438 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10439 else 10440 if (windows->image.ximage->height > (int) windows->image.height) 10441 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10442 else 10443 cursor=XCreateFontCursor(display,XC_arrow); 10444 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10445 /* 10446 Pan image as pointer moves until the mouse button is released. 10447 */ 10448 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10449 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10450 pan_info.width=windows->pan.width*windows->image.width/ 10451 windows->image.ximage->width; 10452 pan_info.height=windows->pan.height*windows->image.height/ 10453 windows->image.ximage->height; 10454 pan_info.x=0; 10455 pan_info.y=0; 10456 state=UpdateConfigurationState; 10457 do 10458 { 10459 switch (event->type) 10460 { 10461 case ButtonPress: 10462 { 10463 /* 10464 User choose an initial pan location. 10465 */ 10466 pan_info.x=(ssize_t) event->xbutton.x; 10467 pan_info.y=(ssize_t) event->xbutton.y; 10468 state|=UpdateConfigurationState; 10469 break; 10470 } 10471 case ButtonRelease: 10472 { 10473 /* 10474 User has finished panning the image. 10475 */ 10476 pan_info.x=(ssize_t) event->xbutton.x; 10477 pan_info.y=(ssize_t) event->xbutton.y; 10478 state|=UpdateConfigurationState | ExitState; 10479 break; 10480 } 10481 case MotionNotify: 10482 { 10483 pan_info.x=(ssize_t) event->xmotion.x; 10484 pan_info.y=(ssize_t) event->xmotion.y; 10485 state|=UpdateConfigurationState; 10486 } 10487 default: 10488 break; 10489 } 10490 if ((state & UpdateConfigurationState) != 0) 10491 { 10492 /* 10493 Check boundary conditions. 10494 */ 10495 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10496 pan_info.x=0; 10497 else 10498 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10499 if (pan_info.x < 0) 10500 pan_info.x=0; 10501 else 10502 if ((int) (pan_info.x+windows->image.width) > 10503 windows->image.ximage->width) 10504 pan_info.x=(ssize_t) 10505 (windows->image.ximage->width-windows->image.width); 10506 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10507 pan_info.y=0; 10508 else 10509 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10510 if (pan_info.y < 0) 10511 pan_info.y=0; 10512 else 10513 if ((int) (pan_info.y+windows->image.height) > 10514 windows->image.ximage->height) 10515 pan_info.y=(ssize_t) 10516 (windows->image.ximage->height-windows->image.height); 10517 if ((windows->image.x != (int) pan_info.x) || 10518 (windows->image.y != (int) pan_info.y)) 10519 { 10520 /* 10521 Display image pan offset. 10522 */ 10523 windows->image.x=(int) pan_info.x; 10524 windows->image.y=(int) pan_info.y; 10525 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10526 windows->image.width,windows->image.height,windows->image.x, 10527 windows->image.y); 10528 XInfoWidget(display,windows,text); 10529 /* 10530 Refresh Image window. 10531 */ 10532 XDrawPanRectangle(display,windows); 10533 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10534 } 10535 state&=(~UpdateConfigurationState); 10536 } 10537 /* 10538 Wait for next event. 10539 */ 10540 if ((state & ExitState) == 0) 10541 XScreenEvent(display,windows,event); 10542 } while ((state & ExitState) == 0); 10543 /* 10544 Restore cursor. 10545 */ 10546 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10547 (void) XFreeCursor(display,cursor); 10548 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10549} 10550 10551/* 10552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10553% % 10554% % 10555% % 10556+ X P a s t e I m a g e % 10557% % 10558% % 10559% % 10560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10561% 10562% XPasteImage() pastes an image previously saved with XCropImage in the X 10563% window image at a location the user chooses with the pointer. 10564% 10565% The format of the XPasteImage method is: 10566% 10567% MagickBooleanType XPasteImage(Display *display, 10568% XResourceInfo *resource_info,XWindows *windows,Image *image, 10569% ExceptionInfo *exception) 10570% 10571% A description of each parameter follows: 10572% 10573% o display: Specifies a connection to an X server; returned from 10574% XOpenDisplay. 10575% 10576% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10577% 10578% o windows: Specifies a pointer to a XWindows structure. 10579% 10580% o image: the image; returned from ReadImage. 10581% 10582% o exception: return any errors or warnings in this structure. 10583% 10584*/ 10585static MagickBooleanType XPasteImage(Display *display, 10586 XResourceInfo *resource_info,XWindows *windows,Image *image, 10587 ExceptionInfo *exception) 10588{ 10589 static const char 10590 *PasteMenu[] = 10591 { 10592 "Operator", 10593 "Help", 10594 "Dismiss", 10595 (char *) NULL 10596 }; 10597 10598 static const ModeType 10599 PasteCommands[] = 10600 { 10601 PasteOperatorsCommand, 10602 PasteHelpCommand, 10603 PasteDismissCommand 10604 }; 10605 10606 static CompositeOperator 10607 compose = CopyCompositeOp; 10608 10609 char 10610 text[MaxTextExtent]; 10611 10612 Cursor 10613 cursor; 10614 10615 Image 10616 *paste_image; 10617 10618 int 10619 entry, 10620 id, 10621 x, 10622 y; 10623 10624 MagickRealType 10625 scale_factor; 10626 10627 RectangleInfo 10628 highlight_info, 10629 paste_info; 10630 10631 unsigned int 10632 height, 10633 width; 10634 10635 size_t 10636 state; 10637 10638 XEvent 10639 event; 10640 10641 /* 10642 Copy image. 10643 */ 10644 if (resource_info->copy_image == (Image *) NULL) 10645 return(MagickFalse); 10646 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10647 /* 10648 Map Command widget. 10649 */ 10650 (void) CloneString(&windows->command.name,"Paste"); 10651 windows->command.data=1; 10652 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10653 (void) XMapRaised(display,windows->command.id); 10654 XClientMessage(display,windows->image.id,windows->im_protocols, 10655 windows->im_update_widget,CurrentTime); 10656 /* 10657 Track pointer until button 1 is pressed. 10658 */ 10659 XSetCursorState(display,windows,MagickFalse); 10660 XQueryPosition(display,windows->image.id,&x,&y); 10661 (void) XSelectInput(display,windows->image.id, 10662 windows->image.attributes.event_mask | PointerMotionMask); 10663 paste_info.x=(ssize_t) windows->image.x+x; 10664 paste_info.y=(ssize_t) windows->image.y+y; 10665 paste_info.width=0; 10666 paste_info.height=0; 10667 cursor=XCreateFontCursor(display,XC_ul_angle); 10668 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10669 state=DefaultState; 10670 do 10671 { 10672 if (windows->info.mapped != MagickFalse) 10673 { 10674 /* 10675 Display pointer position. 10676 */ 10677 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10678 (long) paste_info.x,(long) paste_info.y); 10679 XInfoWidget(display,windows,text); 10680 } 10681 highlight_info=paste_info; 10682 highlight_info.x=paste_info.x-windows->image.x; 10683 highlight_info.y=paste_info.y-windows->image.y; 10684 XHighlightRectangle(display,windows->image.id, 10685 windows->image.highlight_context,&highlight_info); 10686 /* 10687 Wait for next event. 10688 */ 10689 XScreenEvent(display,windows,&event); 10690 XHighlightRectangle(display,windows->image.id, 10691 windows->image.highlight_context,&highlight_info); 10692 if (event.xany.window == windows->command.id) 10693 { 10694 /* 10695 Select a command from the Command widget. 10696 */ 10697 id=XCommandWidget(display,windows,PasteMenu,&event); 10698 if (id < 0) 10699 continue; 10700 switch (PasteCommands[id]) 10701 { 10702 case PasteOperatorsCommand: 10703 { 10704 char 10705 command[MaxTextExtent], 10706 **operators; 10707 10708 /* 10709 Select a command from the pop-up menu. 10710 */ 10711 operators=GetCommandOptions(MagickComposeOptions); 10712 if (operators == (char **) NULL) 10713 break; 10714 entry=XMenuWidget(display,windows,PasteMenu[id], 10715 (const char **) operators,command); 10716 if (entry >= 0) 10717 compose=(CompositeOperator) ParseCommandOption( 10718 MagickComposeOptions,MagickFalse,operators[entry]); 10719 operators=DestroyStringList(operators); 10720 break; 10721 } 10722 case PasteHelpCommand: 10723 { 10724 XTextViewWidget(display,resource_info,windows,MagickFalse, 10725 "Help Viewer - Image Composite",ImagePasteHelp); 10726 break; 10727 } 10728 case PasteDismissCommand: 10729 { 10730 /* 10731 Prematurely exit. 10732 */ 10733 state|=EscapeState; 10734 state|=ExitState; 10735 break; 10736 } 10737 default: 10738 break; 10739 } 10740 continue; 10741 } 10742 switch (event.type) 10743 { 10744 case ButtonPress: 10745 { 10746 if (image->debug != MagickFalse) 10747 (void) LogMagickEvent(X11Event,GetMagickModule(), 10748 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10749 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10750 if (event.xbutton.button != Button1) 10751 break; 10752 if (event.xbutton.window != windows->image.id) 10753 break; 10754 /* 10755 Paste rectangle is relative to image configuration. 10756 */ 10757 width=(unsigned int) image->columns; 10758 height=(unsigned int) image->rows; 10759 x=0; 10760 y=0; 10761 if (windows->image.crop_geometry != (char *) NULL) 10762 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10763 &width,&height); 10764 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10765 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10766 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10767 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10768 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10769 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10770 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10771 break; 10772 } 10773 case ButtonRelease: 10774 { 10775 if (image->debug != MagickFalse) 10776 (void) LogMagickEvent(X11Event,GetMagickModule(), 10777 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10778 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10779 if (event.xbutton.button != Button1) 10780 break; 10781 if (event.xbutton.window != windows->image.id) 10782 break; 10783 if ((paste_info.width != 0) && (paste_info.height != 0)) 10784 { 10785 /* 10786 User has selected the location of the paste image. 10787 */ 10788 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10789 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10790 state|=ExitState; 10791 } 10792 break; 10793 } 10794 case Expose: 10795 break; 10796 case KeyPress: 10797 { 10798 char 10799 command[MaxTextExtent]; 10800 10801 KeySym 10802 key_symbol; 10803 10804 int 10805 length; 10806 10807 if (event.xkey.window != windows->image.id) 10808 break; 10809 /* 10810 Respond to a user key press. 10811 */ 10812 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10813 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10814 *(command+length)='\0'; 10815 if (image->debug != MagickFalse) 10816 (void) LogMagickEvent(X11Event,GetMagickModule(), 10817 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10818 switch ((int) key_symbol) 10819 { 10820 case XK_Escape: 10821 case XK_F20: 10822 { 10823 /* 10824 Prematurely exit. 10825 */ 10826 paste_image=DestroyImage(paste_image); 10827 state|=EscapeState; 10828 state|=ExitState; 10829 break; 10830 } 10831 case XK_F1: 10832 case XK_Help: 10833 { 10834 (void) XSetFunction(display,windows->image.highlight_context, 10835 GXcopy); 10836 XTextViewWidget(display,resource_info,windows,MagickFalse, 10837 "Help Viewer - Image Composite",ImagePasteHelp); 10838 (void) XSetFunction(display,windows->image.highlight_context, 10839 GXinvert); 10840 break; 10841 } 10842 default: 10843 { 10844 (void) XBell(display,0); 10845 break; 10846 } 10847 } 10848 break; 10849 } 10850 case MotionNotify: 10851 { 10852 /* 10853 Map and unmap Info widget as text cursor crosses its boundaries. 10854 */ 10855 x=event.xmotion.x; 10856 y=event.xmotion.y; 10857 if (windows->info.mapped != MagickFalse) 10858 { 10859 if ((x < (int) (windows->info.x+windows->info.width)) && 10860 (y < (int) (windows->info.y+windows->info.height))) 10861 (void) XWithdrawWindow(display,windows->info.id, 10862 windows->info.screen); 10863 } 10864 else 10865 if ((x > (int) (windows->info.x+windows->info.width)) || 10866 (y > (int) (windows->info.y+windows->info.height))) 10867 (void) XMapWindow(display,windows->info.id); 10868 paste_info.x=(ssize_t) windows->image.x+x; 10869 paste_info.y=(ssize_t) windows->image.y+y; 10870 break; 10871 } 10872 default: 10873 { 10874 if (image->debug != MagickFalse) 10875 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10876 event.type); 10877 break; 10878 } 10879 } 10880 } while ((state & ExitState) == 0); 10881 (void) XSelectInput(display,windows->image.id, 10882 windows->image.attributes.event_mask); 10883 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10884 XSetCursorState(display,windows,MagickFalse); 10885 (void) XFreeCursor(display,cursor); 10886 if ((state & EscapeState) != 0) 10887 return(MagickTrue); 10888 /* 10889 Image pasting is relative to image configuration. 10890 */ 10891 XSetCursorState(display,windows,MagickTrue); 10892 XCheckRefreshWindows(display,windows); 10893 width=(unsigned int) image->columns; 10894 height=(unsigned int) image->rows; 10895 x=0; 10896 y=0; 10897 if (windows->image.crop_geometry != (char *) NULL) 10898 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10899 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10900 paste_info.x+=x; 10901 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10902 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10903 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10904 paste_info.y+=y; 10905 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10906 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10907 /* 10908 Paste image with X Image window. 10909 */ 10910 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y); 10911 paste_image=DestroyImage(paste_image); 10912 XSetCursorState(display,windows,MagickFalse); 10913 /* 10914 Update image colormap. 10915 */ 10916 XConfigureImageColormap(display,resource_info,windows,image); 10917 (void) XConfigureImage(display,resource_info,windows,image,exception); 10918 return(MagickTrue); 10919} 10920 10921/* 10922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10923% % 10924% % 10925% % 10926+ X P r i n t I m a g e % 10927% % 10928% % 10929% % 10930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10931% 10932% XPrintImage() prints an image to a Postscript printer. 10933% 10934% The format of the XPrintImage method is: 10935% 10936% MagickBooleanType XPrintImage(Display *display, 10937% XResourceInfo *resource_info,XWindows *windows,Image *image, 10938% ExceptionInfo *exception) 10939% 10940% A description of each parameter follows: 10941% 10942% o display: Specifies a connection to an X server; returned from 10943% XOpenDisplay. 10944% 10945% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10946% 10947% o windows: Specifies a pointer to a XWindows structure. 10948% 10949% o image: the image. 10950% 10951% o exception: return any errors or warnings in this structure. 10952% 10953*/ 10954static MagickBooleanType XPrintImage(Display *display, 10955 XResourceInfo *resource_info,XWindows *windows,Image *image, 10956 ExceptionInfo *exception) 10957{ 10958 char 10959 filename[MaxTextExtent], 10960 geometry[MaxTextExtent]; 10961 10962 Image 10963 *print_image; 10964 10965 ImageInfo 10966 *image_info; 10967 10968 MagickStatusType 10969 status; 10970 10971 /* 10972 Request Postscript page geometry from user. 10973 */ 10974 image_info=CloneImageInfo(resource_info->image_info); 10975 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10976 if (image_info->page != (char *) NULL) 10977 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10978 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10979 "Select Postscript Page Geometry:",geometry); 10980 if (*geometry == '\0') 10981 return(MagickTrue); 10982 image_info->page=GetPageGeometry(geometry); 10983 /* 10984 Apply image transforms. 10985 */ 10986 XSetCursorState(display,windows,MagickTrue); 10987 XCheckRefreshWindows(display,windows); 10988 print_image=CloneImage(image,0,0,MagickTrue,exception); 10989 if (print_image == (Image *) NULL) 10990 return(MagickFalse); 10991 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 10992 windows->image.ximage->width,windows->image.ximage->height); 10993 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry); 10994 /* 10995 Print image. 10996 */ 10997 (void) AcquireUniqueFilename(filename); 10998 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 10999 filename); 11000 status=WriteImage(image_info,print_image,exception); 11001 (void) RelinquishUniqueFileResource(filename); 11002 print_image=DestroyImage(print_image); 11003 image_info=DestroyImageInfo(image_info); 11004 XSetCursorState(display,windows,MagickFalse); 11005 return(status != 0 ? MagickTrue : MagickFalse); 11006} 11007 11008/* 11009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11010% % 11011% % 11012% % 11013+ X R O I I m a g e % 11014% % 11015% % 11016% % 11017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11018% 11019% XROIImage() applies an image processing technique to a region of interest. 11020% 11021% The format of the XROIImage method is: 11022% 11023% MagickBooleanType XROIImage(Display *display, 11024% XResourceInfo *resource_info,XWindows *windows,Image **image, 11025% ExceptionInfo *exception) 11026% 11027% A description of each parameter follows: 11028% 11029% o display: Specifies a connection to an X server; returned from 11030% XOpenDisplay. 11031% 11032% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11033% 11034% o windows: Specifies a pointer to a XWindows structure. 11035% 11036% o image: the image; returned from ReadImage. 11037% 11038% o exception: return any errors or warnings in this structure. 11039% 11040*/ 11041static MagickBooleanType XROIImage(Display *display, 11042 XResourceInfo *resource_info,XWindows *windows,Image **image, 11043 ExceptionInfo *exception) 11044{ 11045#define ApplyMenus 7 11046 11047 static const char 11048 *ROIMenu[] = 11049 { 11050 "Help", 11051 "Dismiss", 11052 (char *) NULL 11053 }, 11054 *ApplyMenu[] = 11055 { 11056 "File", 11057 "Edit", 11058 "Transform", 11059 "Enhance", 11060 "Effects", 11061 "F/X", 11062 "Miscellany", 11063 "Help", 11064 "Dismiss", 11065 (char *) NULL 11066 }, 11067 *FileMenu[] = 11068 { 11069 "Save...", 11070 "Print...", 11071 (char *) NULL 11072 }, 11073 *EditMenu[] = 11074 { 11075 "Undo", 11076 "Redo", 11077 (char *) NULL 11078 }, 11079 *TransformMenu[] = 11080 { 11081 "Flop", 11082 "Flip", 11083 "Rotate Right", 11084 "Rotate Left", 11085 (char *) NULL 11086 }, 11087 *EnhanceMenu[] = 11088 { 11089 "Hue...", 11090 "Saturation...", 11091 "Brightness...", 11092 "Gamma...", 11093 "Spiff", 11094 "Dull", 11095 "Contrast Stretch...", 11096 "Sigmoidal Contrast...", 11097 "Normalize", 11098 "Equalize", 11099 "Negate", 11100 "Grayscale", 11101 "Map...", 11102 "Quantize...", 11103 (char *) NULL 11104 }, 11105 *EffectsMenu[] = 11106 { 11107 "Despeckle", 11108 "Emboss", 11109 "Reduce Noise", 11110 "Add Noise", 11111 "Sharpen...", 11112 "Blur...", 11113 "Threshold...", 11114 "Edge Detect...", 11115 "Spread...", 11116 "Shade...", 11117 "Raise...", 11118 "Segment...", 11119 (char *) NULL 11120 }, 11121 *FXMenu[] = 11122 { 11123 "Solarize...", 11124 "Sepia Tone...", 11125 "Swirl...", 11126 "Implode...", 11127 "Vignette...", 11128 "Wave...", 11129 "Oil Paint...", 11130 "Charcoal Draw...", 11131 (char *) NULL 11132 }, 11133 *MiscellanyMenu[] = 11134 { 11135 "Image Info", 11136 "Zoom Image", 11137 "Show Preview...", 11138 "Show Histogram", 11139 "Show Matte", 11140 (char *) NULL 11141 }; 11142 11143 static const char 11144 **Menus[ApplyMenus] = 11145 { 11146 FileMenu, 11147 EditMenu, 11148 TransformMenu, 11149 EnhanceMenu, 11150 EffectsMenu, 11151 FXMenu, 11152 MiscellanyMenu 11153 }; 11154 11155 static const CommandType 11156 ApplyCommands[] = 11157 { 11158 NullCommand, 11159 NullCommand, 11160 NullCommand, 11161 NullCommand, 11162 NullCommand, 11163 NullCommand, 11164 NullCommand, 11165 HelpCommand, 11166 QuitCommand 11167 }, 11168 FileCommands[] = 11169 { 11170 SaveCommand, 11171 PrintCommand 11172 }, 11173 EditCommands[] = 11174 { 11175 UndoCommand, 11176 RedoCommand 11177 }, 11178 TransformCommands[] = 11179 { 11180 FlopCommand, 11181 FlipCommand, 11182 RotateRightCommand, 11183 RotateLeftCommand 11184 }, 11185 EnhanceCommands[] = 11186 { 11187 HueCommand, 11188 SaturationCommand, 11189 BrightnessCommand, 11190 GammaCommand, 11191 SpiffCommand, 11192 DullCommand, 11193 ContrastStretchCommand, 11194 SigmoidalContrastCommand, 11195 NormalizeCommand, 11196 EqualizeCommand, 11197 NegateCommand, 11198 GrayscaleCommand, 11199 MapCommand, 11200 QuantizeCommand 11201 }, 11202 EffectsCommands[] = 11203 { 11204 DespeckleCommand, 11205 EmbossCommand, 11206 ReduceNoiseCommand, 11207 AddNoiseCommand, 11208 SharpenCommand, 11209 BlurCommand, 11210 EdgeDetectCommand, 11211 SpreadCommand, 11212 ShadeCommand, 11213 RaiseCommand, 11214 SegmentCommand 11215 }, 11216 FXCommands[] = 11217 { 11218 SolarizeCommand, 11219 SepiaToneCommand, 11220 SwirlCommand, 11221 ImplodeCommand, 11222 VignetteCommand, 11223 WaveCommand, 11224 OilPaintCommand, 11225 CharcoalDrawCommand 11226 }, 11227 MiscellanyCommands[] = 11228 { 11229 InfoCommand, 11230 ZoomCommand, 11231 ShowPreviewCommand, 11232 ShowHistogramCommand, 11233 ShowMatteCommand 11234 }, 11235 ROICommands[] = 11236 { 11237 ROIHelpCommand, 11238 ROIDismissCommand 11239 }; 11240 11241 static const CommandType 11242 *Commands[ApplyMenus] = 11243 { 11244 FileCommands, 11245 EditCommands, 11246 TransformCommands, 11247 EnhanceCommands, 11248 EffectsCommands, 11249 FXCommands, 11250 MiscellanyCommands 11251 }; 11252 11253 char 11254 command[MaxTextExtent], 11255 text[MaxTextExtent]; 11256 11257 CommandType 11258 command_type; 11259 11260 Cursor 11261 cursor; 11262 11263 Image 11264 *roi_image; 11265 11266 int 11267 entry, 11268 id, 11269 x, 11270 y; 11271 11272 MagickRealType 11273 scale_factor; 11274 11275 MagickProgressMonitor 11276 progress_monitor; 11277 11278 RectangleInfo 11279 crop_info, 11280 highlight_info, 11281 roi_info; 11282 11283 unsigned int 11284 height, 11285 width; 11286 11287 size_t 11288 state; 11289 11290 XEvent 11291 event; 11292 11293 /* 11294 Map Command widget. 11295 */ 11296 (void) CloneString(&windows->command.name,"ROI"); 11297 windows->command.data=0; 11298 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11299 (void) XMapRaised(display,windows->command.id); 11300 XClientMessage(display,windows->image.id,windows->im_protocols, 11301 windows->im_update_widget,CurrentTime); 11302 /* 11303 Track pointer until button 1 is pressed. 11304 */ 11305 XQueryPosition(display,windows->image.id,&x,&y); 11306 (void) XSelectInput(display,windows->image.id, 11307 windows->image.attributes.event_mask | PointerMotionMask); 11308 roi_info.x=(ssize_t) windows->image.x+x; 11309 roi_info.y=(ssize_t) windows->image.y+y; 11310 roi_info.width=0; 11311 roi_info.height=0; 11312 cursor=XCreateFontCursor(display,XC_fleur); 11313 state=DefaultState; 11314 do 11315 { 11316 if (windows->info.mapped != MagickFalse) 11317 { 11318 /* 11319 Display pointer position. 11320 */ 11321 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11322 (long) roi_info.x,(long) roi_info.y); 11323 XInfoWidget(display,windows,text); 11324 } 11325 /* 11326 Wait for next event. 11327 */ 11328 XScreenEvent(display,windows,&event); 11329 if (event.xany.window == windows->command.id) 11330 { 11331 /* 11332 Select a command from the Command widget. 11333 */ 11334 id=XCommandWidget(display,windows,ROIMenu,&event); 11335 if (id < 0) 11336 continue; 11337 switch (ROICommands[id]) 11338 { 11339 case ROIHelpCommand: 11340 { 11341 XTextViewWidget(display,resource_info,windows,MagickFalse, 11342 "Help Viewer - Region of Interest",ImageROIHelp); 11343 break; 11344 } 11345 case ROIDismissCommand: 11346 { 11347 /* 11348 Prematurely exit. 11349 */ 11350 state|=EscapeState; 11351 state|=ExitState; 11352 break; 11353 } 11354 default: 11355 break; 11356 } 11357 continue; 11358 } 11359 switch (event.type) 11360 { 11361 case ButtonPress: 11362 { 11363 if (event.xbutton.button != Button1) 11364 break; 11365 if (event.xbutton.window != windows->image.id) 11366 break; 11367 /* 11368 Note first corner of region of interest rectangle-- exit loop. 11369 */ 11370 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11371 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11372 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11373 state|=ExitState; 11374 break; 11375 } 11376 case ButtonRelease: 11377 break; 11378 case Expose: 11379 break; 11380 case KeyPress: 11381 { 11382 KeySym 11383 key_symbol; 11384 11385 if (event.xkey.window != windows->image.id) 11386 break; 11387 /* 11388 Respond to a user key press. 11389 */ 11390 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11391 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11392 switch ((int) key_symbol) 11393 { 11394 case XK_Escape: 11395 case XK_F20: 11396 { 11397 /* 11398 Prematurely exit. 11399 */ 11400 state|=EscapeState; 11401 state|=ExitState; 11402 break; 11403 } 11404 case XK_F1: 11405 case XK_Help: 11406 { 11407 XTextViewWidget(display,resource_info,windows,MagickFalse, 11408 "Help Viewer - Region of Interest",ImageROIHelp); 11409 break; 11410 } 11411 default: 11412 { 11413 (void) XBell(display,0); 11414 break; 11415 } 11416 } 11417 break; 11418 } 11419 case MotionNotify: 11420 { 11421 /* 11422 Map and unmap Info widget as text cursor crosses its boundaries. 11423 */ 11424 x=event.xmotion.x; 11425 y=event.xmotion.y; 11426 if (windows->info.mapped != MagickFalse) 11427 { 11428 if ((x < (int) (windows->info.x+windows->info.width)) && 11429 (y < (int) (windows->info.y+windows->info.height))) 11430 (void) XWithdrawWindow(display,windows->info.id, 11431 windows->info.screen); 11432 } 11433 else 11434 if ((x > (int) (windows->info.x+windows->info.width)) || 11435 (y > (int) (windows->info.y+windows->info.height))) 11436 (void) XMapWindow(display,windows->info.id); 11437 roi_info.x=(ssize_t) windows->image.x+x; 11438 roi_info.y=(ssize_t) windows->image.y+y; 11439 break; 11440 } 11441 default: 11442 break; 11443 } 11444 } while ((state & ExitState) == 0); 11445 (void) XSelectInput(display,windows->image.id, 11446 windows->image.attributes.event_mask); 11447 if ((state & EscapeState) != 0) 11448 { 11449 /* 11450 User want to exit without region of interest. 11451 */ 11452 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11453 (void) XFreeCursor(display,cursor); 11454 return(MagickTrue); 11455 } 11456 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11457 do 11458 { 11459 /* 11460 Size rectangle as pointer moves until the mouse button is released. 11461 */ 11462 x=(int) roi_info.x; 11463 y=(int) roi_info.y; 11464 roi_info.width=0; 11465 roi_info.height=0; 11466 state=DefaultState; 11467 do 11468 { 11469 highlight_info=roi_info; 11470 highlight_info.x=roi_info.x-windows->image.x; 11471 highlight_info.y=roi_info.y-windows->image.y; 11472 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11473 { 11474 /* 11475 Display info and draw region of interest rectangle. 11476 */ 11477 if (windows->info.mapped == MagickFalse) 11478 (void) XMapWindow(display,windows->info.id); 11479 (void) FormatLocaleString(text,MaxTextExtent, 11480 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11481 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11482 XInfoWidget(display,windows,text); 11483 XHighlightRectangle(display,windows->image.id, 11484 windows->image.highlight_context,&highlight_info); 11485 } 11486 else 11487 if (windows->info.mapped != MagickFalse) 11488 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11489 /* 11490 Wait for next event. 11491 */ 11492 XScreenEvent(display,windows,&event); 11493 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11494 XHighlightRectangle(display,windows->image.id, 11495 windows->image.highlight_context,&highlight_info); 11496 switch (event.type) 11497 { 11498 case ButtonPress: 11499 { 11500 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11501 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11502 break; 11503 } 11504 case ButtonRelease: 11505 { 11506 /* 11507 User has committed to region of interest rectangle. 11508 */ 11509 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11510 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11511 XSetCursorState(display,windows,MagickFalse); 11512 state|=ExitState; 11513 if (LocaleCompare(windows->command.name,"Apply") == 0) 11514 break; 11515 (void) CloneString(&windows->command.name,"Apply"); 11516 windows->command.data=ApplyMenus; 11517 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11518 break; 11519 } 11520 case Expose: 11521 break; 11522 case MotionNotify: 11523 { 11524 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11525 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11526 } 11527 default: 11528 break; 11529 } 11530 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11531 ((state & ExitState) != 0)) 11532 { 11533 /* 11534 Check boundary conditions. 11535 */ 11536 if (roi_info.x < 0) 11537 roi_info.x=0; 11538 else 11539 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11540 roi_info.x=(ssize_t) windows->image.ximage->width; 11541 if ((int) roi_info.x < x) 11542 roi_info.width=(unsigned int) (x-roi_info.x); 11543 else 11544 { 11545 roi_info.width=(unsigned int) (roi_info.x-x); 11546 roi_info.x=(ssize_t) x; 11547 } 11548 if (roi_info.y < 0) 11549 roi_info.y=0; 11550 else 11551 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11552 roi_info.y=(ssize_t) windows->image.ximage->height; 11553 if ((int) roi_info.y < y) 11554 roi_info.height=(unsigned int) (y-roi_info.y); 11555 else 11556 { 11557 roi_info.height=(unsigned int) (roi_info.y-y); 11558 roi_info.y=(ssize_t) y; 11559 } 11560 } 11561 } while ((state & ExitState) == 0); 11562 /* 11563 Wait for user to grab a corner of the rectangle or press return. 11564 */ 11565 state=DefaultState; 11566 command_type=NullCommand; 11567 (void) XMapWindow(display,windows->info.id); 11568 do 11569 { 11570 if (windows->info.mapped != MagickFalse) 11571 { 11572 /* 11573 Display pointer position. 11574 */ 11575 (void) FormatLocaleString(text,MaxTextExtent, 11576 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11577 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11578 XInfoWidget(display,windows,text); 11579 } 11580 highlight_info=roi_info; 11581 highlight_info.x=roi_info.x-windows->image.x; 11582 highlight_info.y=roi_info.y-windows->image.y; 11583 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11584 { 11585 state|=EscapeState; 11586 state|=ExitState; 11587 break; 11588 } 11589 if ((state & UpdateRegionState) != 0) 11590 { 11591 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11592 switch (command_type) 11593 { 11594 case UndoCommand: 11595 case RedoCommand: 11596 { 11597 (void) XMagickCommand(display,resource_info,windows,command_type, 11598 image,exception); 11599 break; 11600 } 11601 default: 11602 { 11603 /* 11604 Region of interest is relative to image configuration. 11605 */ 11606 progress_monitor=SetImageProgressMonitor(*image, 11607 (MagickProgressMonitor) NULL,(*image)->client_data); 11608 crop_info=roi_info; 11609 width=(unsigned int) (*image)->columns; 11610 height=(unsigned int) (*image)->rows; 11611 x=0; 11612 y=0; 11613 if (windows->image.crop_geometry != (char *) NULL) 11614 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11615 &width,&height); 11616 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11617 crop_info.x+=x; 11618 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11619 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11620 scale_factor=(MagickRealType) 11621 height/windows->image.ximage->height; 11622 crop_info.y+=y; 11623 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11624 crop_info.height=(unsigned int) 11625 (scale_factor*crop_info.height+0.5); 11626 roi_image=CropImage(*image,&crop_info,exception); 11627 (void) SetImageProgressMonitor(*image,progress_monitor, 11628 (*image)->client_data); 11629 if (roi_image == (Image *) NULL) 11630 continue; 11631 /* 11632 Apply image processing technique to the region of interest. 11633 */ 11634 windows->image.orphan=MagickTrue; 11635 (void) XMagickCommand(display,resource_info,windows,command_type, 11636 &roi_image,exception); 11637 progress_monitor=SetImageProgressMonitor(*image, 11638 (MagickProgressMonitor) NULL,(*image)->client_data); 11639 (void) XMagickCommand(display,resource_info,windows, 11640 SaveToUndoBufferCommand,image,exception); 11641 windows->image.orphan=MagickFalse; 11642 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11643 crop_info.x,crop_info.y); 11644 roi_image=DestroyImage(roi_image); 11645 (void) SetImageProgressMonitor(*image,progress_monitor, 11646 (*image)->client_data); 11647 break; 11648 } 11649 } 11650 if (command_type != InfoCommand) 11651 { 11652 XConfigureImageColormap(display,resource_info,windows,*image); 11653 (void) XConfigureImage(display,resource_info,windows,*image,exception); 11654 } 11655 XCheckRefreshWindows(display,windows); 11656 XInfoWidget(display,windows,text); 11657 (void) XSetFunction(display,windows->image.highlight_context, 11658 GXinvert); 11659 state&=(~UpdateRegionState); 11660 } 11661 XHighlightRectangle(display,windows->image.id, 11662 windows->image.highlight_context,&highlight_info); 11663 XScreenEvent(display,windows,&event); 11664 if (event.xany.window == windows->command.id) 11665 { 11666 /* 11667 Select a command from the Command widget. 11668 */ 11669 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11670 command_type=NullCommand; 11671 id=XCommandWidget(display,windows,ApplyMenu,&event); 11672 if (id >= 0) 11673 { 11674 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11675 command_type=ApplyCommands[id]; 11676 if (id < ApplyMenus) 11677 { 11678 /* 11679 Select a command from a pop-up menu. 11680 */ 11681 entry=XMenuWidget(display,windows,ApplyMenu[id], 11682 (const char **) Menus[id],command); 11683 if (entry >= 0) 11684 { 11685 (void) CopyMagickString(command,Menus[id][entry], 11686 MaxTextExtent); 11687 command_type=Commands[id][entry]; 11688 } 11689 } 11690 } 11691 (void) XSetFunction(display,windows->image.highlight_context, 11692 GXinvert); 11693 XHighlightRectangle(display,windows->image.id, 11694 windows->image.highlight_context,&highlight_info); 11695 if (command_type == HelpCommand) 11696 { 11697 (void) XSetFunction(display,windows->image.highlight_context, 11698 GXcopy); 11699 XTextViewWidget(display,resource_info,windows,MagickFalse, 11700 "Help Viewer - Region of Interest",ImageROIHelp); 11701 (void) XSetFunction(display,windows->image.highlight_context, 11702 GXinvert); 11703 continue; 11704 } 11705 if (command_type == QuitCommand) 11706 { 11707 /* 11708 exit. 11709 */ 11710 state|=EscapeState; 11711 state|=ExitState; 11712 continue; 11713 } 11714 if (command_type != NullCommand) 11715 state|=UpdateRegionState; 11716 continue; 11717 } 11718 XHighlightRectangle(display,windows->image.id, 11719 windows->image.highlight_context,&highlight_info); 11720 switch (event.type) 11721 { 11722 case ButtonPress: 11723 { 11724 x=windows->image.x; 11725 y=windows->image.y; 11726 if (event.xbutton.button != Button1) 11727 break; 11728 if (event.xbutton.window != windows->image.id) 11729 break; 11730 x=windows->image.x+event.xbutton.x; 11731 y=windows->image.y+event.xbutton.y; 11732 if ((x < (int) (roi_info.x+RoiDelta)) && 11733 (x > (int) (roi_info.x-RoiDelta)) && 11734 (y < (int) (roi_info.y+RoiDelta)) && 11735 (y > (int) (roi_info.y-RoiDelta))) 11736 { 11737 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11738 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11739 state|=UpdateConfigurationState; 11740 break; 11741 } 11742 if ((x < (int) (roi_info.x+RoiDelta)) && 11743 (x > (int) (roi_info.x-RoiDelta)) && 11744 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11745 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11746 { 11747 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11748 state|=UpdateConfigurationState; 11749 break; 11750 } 11751 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11752 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11753 (y < (int) (roi_info.y+RoiDelta)) && 11754 (y > (int) (roi_info.y-RoiDelta))) 11755 { 11756 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11757 state|=UpdateConfigurationState; 11758 break; 11759 } 11760 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11761 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11762 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11763 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11764 { 11765 state|=UpdateConfigurationState; 11766 break; 11767 } 11768 } 11769 case ButtonRelease: 11770 { 11771 if (event.xbutton.window == windows->pan.id) 11772 if ((highlight_info.x != crop_info.x-windows->image.x) || 11773 (highlight_info.y != crop_info.y-windows->image.y)) 11774 XHighlightRectangle(display,windows->image.id, 11775 windows->image.highlight_context,&highlight_info); 11776 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11777 event.xbutton.time); 11778 break; 11779 } 11780 case Expose: 11781 { 11782 if (event.xexpose.window == windows->image.id) 11783 if (event.xexpose.count == 0) 11784 { 11785 event.xexpose.x=(int) highlight_info.x; 11786 event.xexpose.y=(int) highlight_info.y; 11787 event.xexpose.width=(int) highlight_info.width; 11788 event.xexpose.height=(int) highlight_info.height; 11789 XRefreshWindow(display,&windows->image,&event); 11790 } 11791 if (event.xexpose.window == windows->info.id) 11792 if (event.xexpose.count == 0) 11793 XInfoWidget(display,windows,text); 11794 break; 11795 } 11796 case KeyPress: 11797 { 11798 KeySym 11799 key_symbol; 11800 11801 if (event.xkey.window != windows->image.id) 11802 break; 11803 /* 11804 Respond to a user key press. 11805 */ 11806 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11807 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11808 switch ((int) key_symbol) 11809 { 11810 case XK_Shift_L: 11811 case XK_Shift_R: 11812 break; 11813 case XK_Escape: 11814 case XK_F20: 11815 state|=EscapeState; 11816 case XK_Return: 11817 { 11818 state|=ExitState; 11819 break; 11820 } 11821 case XK_Home: 11822 case XK_KP_Home: 11823 { 11824 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11825 roi_info.y=(ssize_t) (windows->image.height/2L- 11826 roi_info.height/2L); 11827 break; 11828 } 11829 case XK_Left: 11830 case XK_KP_Left: 11831 { 11832 roi_info.x--; 11833 break; 11834 } 11835 case XK_Up: 11836 case XK_KP_Up: 11837 case XK_Next: 11838 { 11839 roi_info.y--; 11840 break; 11841 } 11842 case XK_Right: 11843 case XK_KP_Right: 11844 { 11845 roi_info.x++; 11846 break; 11847 } 11848 case XK_Prior: 11849 case XK_Down: 11850 case XK_KP_Down: 11851 { 11852 roi_info.y++; 11853 break; 11854 } 11855 case XK_F1: 11856 case XK_Help: 11857 { 11858 (void) XSetFunction(display,windows->image.highlight_context, 11859 GXcopy); 11860 XTextViewWidget(display,resource_info,windows,MagickFalse, 11861 "Help Viewer - Region of Interest",ImageROIHelp); 11862 (void) XSetFunction(display,windows->image.highlight_context, 11863 GXinvert); 11864 break; 11865 } 11866 default: 11867 { 11868 command_type=XImageWindowCommand(display,resource_info,windows, 11869 event.xkey.state,key_symbol,image,exception); 11870 if (command_type != NullCommand) 11871 state|=UpdateRegionState; 11872 break; 11873 } 11874 } 11875 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11876 event.xkey.time); 11877 break; 11878 } 11879 case KeyRelease: 11880 break; 11881 case MotionNotify: 11882 { 11883 if (event.xbutton.window != windows->image.id) 11884 break; 11885 /* 11886 Map and unmap Info widget as text cursor crosses its boundaries. 11887 */ 11888 x=event.xmotion.x; 11889 y=event.xmotion.y; 11890 if (windows->info.mapped != MagickFalse) 11891 { 11892 if ((x < (int) (windows->info.x+windows->info.width)) && 11893 (y < (int) (windows->info.y+windows->info.height))) 11894 (void) XWithdrawWindow(display,windows->info.id, 11895 windows->info.screen); 11896 } 11897 else 11898 if ((x > (int) (windows->info.x+windows->info.width)) || 11899 (y > (int) (windows->info.y+windows->info.height))) 11900 (void) XMapWindow(display,windows->info.id); 11901 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11902 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11903 break; 11904 } 11905 case SelectionRequest: 11906 { 11907 XSelectionEvent 11908 notify; 11909 11910 XSelectionRequestEvent 11911 *request; 11912 11913 /* 11914 Set primary selection. 11915 */ 11916 (void) FormatLocaleString(text,MaxTextExtent, 11917 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11918 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11919 request=(&(event.xselectionrequest)); 11920 (void) XChangeProperty(request->display,request->requestor, 11921 request->property,request->target,8,PropModeReplace, 11922 (unsigned char *) text,(int) strlen(text)); 11923 notify.type=SelectionNotify; 11924 notify.display=request->display; 11925 notify.requestor=request->requestor; 11926 notify.selection=request->selection; 11927 notify.target=request->target; 11928 notify.time=request->time; 11929 if (request->property == None) 11930 notify.property=request->target; 11931 else 11932 notify.property=request->property; 11933 (void) XSendEvent(request->display,request->requestor,False,0, 11934 (XEvent *) ¬ify); 11935 } 11936 default: 11937 break; 11938 } 11939 if ((state & UpdateConfigurationState) != 0) 11940 { 11941 (void) XPutBackEvent(display,&event); 11942 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11943 break; 11944 } 11945 } while ((state & ExitState) == 0); 11946 } while ((state & ExitState) == 0); 11947 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11948 XSetCursorState(display,windows,MagickFalse); 11949 if ((state & EscapeState) != 0) 11950 return(MagickTrue); 11951 return(MagickTrue); 11952} 11953 11954/* 11955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11956% % 11957% % 11958% % 11959+ X R o t a t e I m a g e % 11960% % 11961% % 11962% % 11963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11964% 11965% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11966% rotation angle is computed from the slope of a line drawn by the user. 11967% 11968% The format of the XRotateImage method is: 11969% 11970% MagickBooleanType XRotateImage(Display *display, 11971% XResourceInfo *resource_info,XWindows *windows,double degrees, 11972% Image **image,ExceptionInfo *exception) 11973% 11974% A description of each parameter follows: 11975% 11976% o display: Specifies a connection to an X server; returned from 11977% XOpenDisplay. 11978% 11979% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11980% 11981% o windows: Specifies a pointer to a XWindows structure. 11982% 11983% o degrees: Specifies the number of degrees to rotate the image. 11984% 11985% o image: the image. 11986% 11987% o exception: return any errors or warnings in this structure. 11988% 11989*/ 11990static MagickBooleanType XRotateImage(Display *display, 11991 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 11992 ExceptionInfo *exception) 11993{ 11994 static const char 11995 *RotateMenu[] = 11996 { 11997 "Pixel Color", 11998 "Direction", 11999 "Help", 12000 "Dismiss", 12001 (char *) NULL 12002 }; 12003 12004 static ModeType 12005 direction = HorizontalRotateCommand; 12006 12007 static const ModeType 12008 DirectionCommands[] = 12009 { 12010 HorizontalRotateCommand, 12011 VerticalRotateCommand 12012 }, 12013 RotateCommands[] = 12014 { 12015 RotateColorCommand, 12016 RotateDirectionCommand, 12017 RotateHelpCommand, 12018 RotateDismissCommand 12019 }; 12020 12021 static unsigned int 12022 pen_id = 0; 12023 12024 char 12025 command[MaxTextExtent], 12026 text[MaxTextExtent]; 12027 12028 Image 12029 *rotate_image; 12030 12031 int 12032 id, 12033 x, 12034 y; 12035 12036 MagickRealType 12037 normalized_degrees; 12038 12039 register int 12040 i; 12041 12042 unsigned int 12043 height, 12044 rotations, 12045 width; 12046 12047 if (degrees == 0.0) 12048 { 12049 unsigned int 12050 distance; 12051 12052 size_t 12053 state; 12054 12055 XEvent 12056 event; 12057 12058 XSegment 12059 rotate_info; 12060 12061 /* 12062 Map Command widget. 12063 */ 12064 (void) CloneString(&windows->command.name,"Rotate"); 12065 windows->command.data=2; 12066 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12067 (void) XMapRaised(display,windows->command.id); 12068 XClientMessage(display,windows->image.id,windows->im_protocols, 12069 windows->im_update_widget,CurrentTime); 12070 /* 12071 Wait for first button press. 12072 */ 12073 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12074 XQueryPosition(display,windows->image.id,&x,&y); 12075 rotate_info.x1=x; 12076 rotate_info.y1=y; 12077 rotate_info.x2=x; 12078 rotate_info.y2=y; 12079 state=DefaultState; 12080 do 12081 { 12082 XHighlightLine(display,windows->image.id, 12083 windows->image.highlight_context,&rotate_info); 12084 /* 12085 Wait for next event. 12086 */ 12087 XScreenEvent(display,windows,&event); 12088 XHighlightLine(display,windows->image.id, 12089 windows->image.highlight_context,&rotate_info); 12090 if (event.xany.window == windows->command.id) 12091 { 12092 /* 12093 Select a command from the Command widget. 12094 */ 12095 id=XCommandWidget(display,windows,RotateMenu,&event); 12096 if (id < 0) 12097 continue; 12098 (void) XSetFunction(display,windows->image.highlight_context, 12099 GXcopy); 12100 switch (RotateCommands[id]) 12101 { 12102 case RotateColorCommand: 12103 { 12104 const char 12105 *ColorMenu[MaxNumberPens]; 12106 12107 int 12108 pen_number; 12109 12110 XColor 12111 color; 12112 12113 /* 12114 Initialize menu selections. 12115 */ 12116 for (i=0; i < (int) (MaxNumberPens-2); i++) 12117 ColorMenu[i]=resource_info->pen_colors[i]; 12118 ColorMenu[MaxNumberPens-2]="Browser..."; 12119 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12120 /* 12121 Select a pen color from the pop-up menu. 12122 */ 12123 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12124 (const char **) ColorMenu,command); 12125 if (pen_number < 0) 12126 break; 12127 if (pen_number == (MaxNumberPens-2)) 12128 { 12129 static char 12130 color_name[MaxTextExtent] = "gray"; 12131 12132 /* 12133 Select a pen color from a dialog. 12134 */ 12135 resource_info->pen_colors[pen_number]=color_name; 12136 XColorBrowserWidget(display,windows,"Select",color_name); 12137 if (*color_name == '\0') 12138 break; 12139 } 12140 /* 12141 Set pen color. 12142 */ 12143 (void) XParseColor(display,windows->map_info->colormap, 12144 resource_info->pen_colors[pen_number],&color); 12145 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12146 (unsigned int) MaxColors,&color); 12147 windows->pixel_info->pen_colors[pen_number]=color; 12148 pen_id=(unsigned int) pen_number; 12149 break; 12150 } 12151 case RotateDirectionCommand: 12152 { 12153 static const char 12154 *Directions[] = 12155 { 12156 "horizontal", 12157 "vertical", 12158 (char *) NULL, 12159 }; 12160 12161 /* 12162 Select a command from the pop-up menu. 12163 */ 12164 id=XMenuWidget(display,windows,RotateMenu[id], 12165 Directions,command); 12166 if (id >= 0) 12167 direction=DirectionCommands[id]; 12168 break; 12169 } 12170 case RotateHelpCommand: 12171 { 12172 XTextViewWidget(display,resource_info,windows,MagickFalse, 12173 "Help Viewer - Image Rotation",ImageRotateHelp); 12174 break; 12175 } 12176 case RotateDismissCommand: 12177 { 12178 /* 12179 Prematurely exit. 12180 */ 12181 state|=EscapeState; 12182 state|=ExitState; 12183 break; 12184 } 12185 default: 12186 break; 12187 } 12188 (void) XSetFunction(display,windows->image.highlight_context, 12189 GXinvert); 12190 continue; 12191 } 12192 switch (event.type) 12193 { 12194 case ButtonPress: 12195 { 12196 if (event.xbutton.button != Button1) 12197 break; 12198 if (event.xbutton.window != windows->image.id) 12199 break; 12200 /* 12201 exit loop. 12202 */ 12203 (void) XSetFunction(display,windows->image.highlight_context, 12204 GXcopy); 12205 rotate_info.x1=event.xbutton.x; 12206 rotate_info.y1=event.xbutton.y; 12207 state|=ExitState; 12208 break; 12209 } 12210 case ButtonRelease: 12211 break; 12212 case Expose: 12213 break; 12214 case KeyPress: 12215 { 12216 char 12217 command[MaxTextExtent]; 12218 12219 KeySym 12220 key_symbol; 12221 12222 if (event.xkey.window != windows->image.id) 12223 break; 12224 /* 12225 Respond to a user key press. 12226 */ 12227 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12228 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12229 switch ((int) key_symbol) 12230 { 12231 case XK_Escape: 12232 case XK_F20: 12233 { 12234 /* 12235 Prematurely exit. 12236 */ 12237 state|=EscapeState; 12238 state|=ExitState; 12239 break; 12240 } 12241 case XK_F1: 12242 case XK_Help: 12243 { 12244 (void) XSetFunction(display,windows->image.highlight_context, 12245 GXcopy); 12246 XTextViewWidget(display,resource_info,windows,MagickFalse, 12247 "Help Viewer - Image Rotation",ImageRotateHelp); 12248 (void) XSetFunction(display,windows->image.highlight_context, 12249 GXinvert); 12250 break; 12251 } 12252 default: 12253 { 12254 (void) XBell(display,0); 12255 break; 12256 } 12257 } 12258 break; 12259 } 12260 case MotionNotify: 12261 { 12262 rotate_info.x1=event.xmotion.x; 12263 rotate_info.y1=event.xmotion.y; 12264 } 12265 } 12266 rotate_info.x2=rotate_info.x1; 12267 rotate_info.y2=rotate_info.y1; 12268 if (direction == HorizontalRotateCommand) 12269 rotate_info.x2+=32; 12270 else 12271 rotate_info.y2-=32; 12272 } while ((state & ExitState) == 0); 12273 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12274 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12275 if ((state & EscapeState) != 0) 12276 return(MagickTrue); 12277 /* 12278 Draw line as pointer moves until the mouse button is released. 12279 */ 12280 distance=0; 12281 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12282 state=DefaultState; 12283 do 12284 { 12285 if (distance > 9) 12286 { 12287 /* 12288 Display info and draw rotation line. 12289 */ 12290 if (windows->info.mapped == MagickFalse) 12291 (void) XMapWindow(display,windows->info.id); 12292 (void) FormatLocaleString(text,MaxTextExtent," %g", 12293 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12294 XInfoWidget(display,windows,text); 12295 XHighlightLine(display,windows->image.id, 12296 windows->image.highlight_context,&rotate_info); 12297 } 12298 else 12299 if (windows->info.mapped != MagickFalse) 12300 (void) XWithdrawWindow(display,windows->info.id, 12301 windows->info.screen); 12302 /* 12303 Wait for next event. 12304 */ 12305 XScreenEvent(display,windows,&event); 12306 if (distance > 9) 12307 XHighlightLine(display,windows->image.id, 12308 windows->image.highlight_context,&rotate_info); 12309 switch (event.type) 12310 { 12311 case ButtonPress: 12312 break; 12313 case ButtonRelease: 12314 { 12315 /* 12316 User has committed to rotation line. 12317 */ 12318 rotate_info.x2=event.xbutton.x; 12319 rotate_info.y2=event.xbutton.y; 12320 state|=ExitState; 12321 break; 12322 } 12323 case Expose: 12324 break; 12325 case MotionNotify: 12326 { 12327 rotate_info.x2=event.xmotion.x; 12328 rotate_info.y2=event.xmotion.y; 12329 } 12330 default: 12331 break; 12332 } 12333 /* 12334 Check boundary conditions. 12335 */ 12336 if (rotate_info.x2 < 0) 12337 rotate_info.x2=0; 12338 else 12339 if (rotate_info.x2 > (int) windows->image.width) 12340 rotate_info.x2=(short) windows->image.width; 12341 if (rotate_info.y2 < 0) 12342 rotate_info.y2=0; 12343 else 12344 if (rotate_info.y2 > (int) windows->image.height) 12345 rotate_info.y2=(short) windows->image.height; 12346 /* 12347 Compute rotation angle from the slope of the line. 12348 */ 12349 degrees=0.0; 12350 distance=(unsigned int) 12351 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12352 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12353 if (distance > 9) 12354 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12355 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12356 } while ((state & ExitState) == 0); 12357 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12358 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12359 if (distance <= 9) 12360 return(MagickTrue); 12361 } 12362 if (direction == VerticalRotateCommand) 12363 degrees-=90.0; 12364 if (degrees == 0.0) 12365 return(MagickTrue); 12366 /* 12367 Rotate image. 12368 */ 12369 normalized_degrees=degrees; 12370 while (normalized_degrees < -45.0) 12371 normalized_degrees+=360.0; 12372 for (rotations=0; normalized_degrees > 45.0; rotations++) 12373 normalized_degrees-=90.0; 12374 if (normalized_degrees != 0.0) 12375 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12376 exception); 12377 XSetCursorState(display,windows,MagickTrue); 12378 XCheckRefreshWindows(display,windows); 12379 (*image)->background_color.red=ScaleShortToQuantum( 12380 windows->pixel_info->pen_colors[pen_id].red); 12381 (*image)->background_color.green=ScaleShortToQuantum( 12382 windows->pixel_info->pen_colors[pen_id].green); 12383 (*image)->background_color.blue=ScaleShortToQuantum( 12384 windows->pixel_info->pen_colors[pen_id].blue); 12385 rotate_image=RotateImage(*image,degrees,exception); 12386 XSetCursorState(display,windows,MagickFalse); 12387 if (rotate_image == (Image *) NULL) 12388 return(MagickFalse); 12389 *image=DestroyImage(*image); 12390 *image=rotate_image; 12391 if (windows->image.crop_geometry != (char *) NULL) 12392 { 12393 /* 12394 Rotate crop geometry. 12395 */ 12396 width=(unsigned int) (*image)->columns; 12397 height=(unsigned int) (*image)->rows; 12398 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12399 switch (rotations % 4) 12400 { 12401 default: 12402 case 0: 12403 break; 12404 case 1: 12405 { 12406 /* 12407 Rotate 90 degrees. 12408 */ 12409 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12410 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12411 (int) height-y,x); 12412 break; 12413 } 12414 case 2: 12415 { 12416 /* 12417 Rotate 180 degrees. 12418 */ 12419 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12420 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12421 break; 12422 } 12423 case 3: 12424 { 12425 /* 12426 Rotate 270 degrees. 12427 */ 12428 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12429 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12430 break; 12431 } 12432 } 12433 } 12434 if (windows->image.orphan != MagickFalse) 12435 return(MagickTrue); 12436 if (normalized_degrees != 0.0) 12437 { 12438 /* 12439 Update image colormap. 12440 */ 12441 windows->image.window_changes.width=(int) (*image)->columns; 12442 windows->image.window_changes.height=(int) (*image)->rows; 12443 if (windows->image.crop_geometry != (char *) NULL) 12444 { 12445 /* 12446 Obtain dimensions of image from crop geometry. 12447 */ 12448 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12449 &width,&height); 12450 windows->image.window_changes.width=(int) width; 12451 windows->image.window_changes.height=(int) height; 12452 } 12453 XConfigureImageColormap(display,resource_info,windows,*image); 12454 } 12455 else 12456 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12457 { 12458 windows->image.window_changes.width=windows->image.ximage->height; 12459 windows->image.window_changes.height=windows->image.ximage->width; 12460 } 12461 /* 12462 Update image configuration. 12463 */ 12464 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12465 return(MagickTrue); 12466} 12467 12468/* 12469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12470% % 12471% % 12472% % 12473+ X S a v e I m a g e % 12474% % 12475% % 12476% % 12477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12478% 12479% XSaveImage() saves an image to a file. 12480% 12481% The format of the XSaveImage method is: 12482% 12483% MagickBooleanType XSaveImage(Display *display, 12484% XResourceInfo *resource_info,XWindows *windows,Image *image, 12485% ExceptionInfo *exception) 12486% 12487% A description of each parameter follows: 12488% 12489% o display: Specifies a connection to an X server; returned from 12490% XOpenDisplay. 12491% 12492% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12493% 12494% o windows: Specifies a pointer to a XWindows structure. 12495% 12496% o image: the image. 12497% 12498% o exception: return any errors or warnings in this structure. 12499% 12500*/ 12501static MagickBooleanType XSaveImage(Display *display, 12502 XResourceInfo *resource_info,XWindows *windows,Image *image, 12503 ExceptionInfo *exception) 12504{ 12505 char 12506 filename[MaxTextExtent], 12507 geometry[MaxTextExtent]; 12508 12509 Image 12510 *save_image; 12511 12512 ImageInfo 12513 *image_info; 12514 12515 MagickStatusType 12516 status; 12517 12518 /* 12519 Request file name from user. 12520 */ 12521 if (resource_info->write_filename != (char *) NULL) 12522 (void) CopyMagickString(filename,resource_info->write_filename, 12523 MaxTextExtent); 12524 else 12525 { 12526 char 12527 path[MaxTextExtent]; 12528 12529 int 12530 status; 12531 12532 GetPathComponent(image->filename,HeadPath,path); 12533 GetPathComponent(image->filename,TailPath,filename); 12534 if (*path != '\0') 12535 { 12536 status=chdir(path); 12537 if (status == -1) 12538 (void) ThrowMagickException(exception,GetMagickModule(), 12539 FileOpenError,"UnableToOpenFile","%s",path); 12540 } 12541 } 12542 XFileBrowserWidget(display,windows,"Save",filename); 12543 if (*filename == '\0') 12544 return(MagickTrue); 12545 if (IsPathAccessible(filename) != MagickFalse) 12546 { 12547 int 12548 status; 12549 12550 /* 12551 File exists-- seek user's permission before overwriting. 12552 */ 12553 status=XConfirmWidget(display,windows,"Overwrite",filename); 12554 if (status <= 0) 12555 return(MagickTrue); 12556 } 12557 image_info=CloneImageInfo(resource_info->image_info); 12558 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12559 (void) SetImageInfo(image_info,1,exception); 12560 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12561 (LocaleCompare(image_info->magick,"JPG") == 0)) 12562 { 12563 char 12564 quality[MaxTextExtent]; 12565 12566 int 12567 status; 12568 12569 /* 12570 Request JPEG quality from user. 12571 */ 12572 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12573 image->quality); 12574 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12575 quality); 12576 if (*quality == '\0') 12577 return(MagickTrue); 12578 image->quality=StringToUnsignedLong(quality); 12579 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12580 } 12581 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12582 (LocaleCompare(image_info->magick,"PDF") == 0) || 12583 (LocaleCompare(image_info->magick,"PS") == 0) || 12584 (LocaleCompare(image_info->magick,"PS2") == 0)) 12585 { 12586 char 12587 geometry[MaxTextExtent]; 12588 12589 /* 12590 Request page geometry from user. 12591 */ 12592 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12593 if (LocaleCompare(image_info->magick,"PDF") == 0) 12594 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12595 if (image_info->page != (char *) NULL) 12596 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12597 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12598 "Select page geometry:",geometry); 12599 if (*geometry != '\0') 12600 image_info->page=GetPageGeometry(geometry); 12601 } 12602 /* 12603 Apply image transforms. 12604 */ 12605 XSetCursorState(display,windows,MagickTrue); 12606 XCheckRefreshWindows(display,windows); 12607 save_image=CloneImage(image,0,0,MagickTrue,exception); 12608 if (save_image == (Image *) NULL) 12609 return(MagickFalse); 12610 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12611 windows->image.ximage->width,windows->image.ximage->height); 12612 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry); 12613 /* 12614 Write image. 12615 */ 12616 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12617 status=WriteImage(image_info,save_image,exception); 12618 if (status != MagickFalse) 12619 image->taint=MagickFalse; 12620 save_image=DestroyImage(save_image); 12621 image_info=DestroyImageInfo(image_info); 12622 XSetCursorState(display,windows,MagickFalse); 12623 return(status != 0 ? MagickTrue : MagickFalse); 12624} 12625 12626/* 12627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12628% % 12629% % 12630% % 12631+ X S c r e e n E v e n t % 12632% % 12633% % 12634% % 12635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12636% 12637% XScreenEvent() handles global events associated with the Pan and Magnify 12638% windows. 12639% 12640% The format of the XScreenEvent function is: 12641% 12642% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12643% 12644% A description of each parameter follows: 12645% 12646% o display: Specifies a pointer to the Display structure; returned from 12647% XOpenDisplay. 12648% 12649% o windows: Specifies a pointer to a XWindows structure. 12650% 12651% o event: Specifies a pointer to a X11 XEvent structure. 12652% 12653% 12654*/ 12655 12656#if defined(__cplusplus) || defined(c_plusplus) 12657extern "C" { 12658#endif 12659 12660static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12661{ 12662 register XWindows 12663 *windows; 12664 12665 windows=(XWindows *) data; 12666 if ((event->type == ClientMessage) && 12667 (event->xclient.window == windows->image.id)) 12668 return(MagickFalse); 12669 return(MagickTrue); 12670} 12671 12672#if defined(__cplusplus) || defined(c_plusplus) 12673} 12674#endif 12675 12676static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12677{ 12678 register int 12679 x, 12680 y; 12681 12682 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12683 if (event->xany.window == windows->command.id) 12684 return; 12685 switch (event->type) 12686 { 12687 case ButtonPress: 12688 case ButtonRelease: 12689 { 12690 if ((event->xbutton.button == Button3) && 12691 (event->xbutton.state & Mod1Mask)) 12692 { 12693 /* 12694 Convert Alt-Button3 to Button2. 12695 */ 12696 event->xbutton.button=Button2; 12697 event->xbutton.state&=(~Mod1Mask); 12698 } 12699 if (event->xbutton.window == windows->backdrop.id) 12700 { 12701 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12702 event->xbutton.time); 12703 break; 12704 } 12705 if (event->xbutton.window == windows->pan.id) 12706 { 12707 XPanImage(display,windows,event); 12708 break; 12709 } 12710 if (event->xbutton.window == windows->image.id) 12711 if (event->xbutton.button == Button2) 12712 { 12713 /* 12714 Update magnified image. 12715 */ 12716 x=event->xbutton.x; 12717 y=event->xbutton.y; 12718 if (x < 0) 12719 x=0; 12720 else 12721 if (x >= (int) windows->image.width) 12722 x=(int) (windows->image.width-1); 12723 windows->magnify.x=(int) windows->image.x+x; 12724 if (y < 0) 12725 y=0; 12726 else 12727 if (y >= (int) windows->image.height) 12728 y=(int) (windows->image.height-1); 12729 windows->magnify.y=windows->image.y+y; 12730 if (windows->magnify.mapped == MagickFalse) 12731 (void) XMapRaised(display,windows->magnify.id); 12732 XMakeMagnifyImage(display,windows); 12733 if (event->type == ButtonRelease) 12734 (void) XWithdrawWindow(display,windows->info.id, 12735 windows->info.screen); 12736 break; 12737 } 12738 break; 12739 } 12740 case ClientMessage: 12741 { 12742 /* 12743 If client window delete message, exit. 12744 */ 12745 if (event->xclient.message_type != windows->wm_protocols) 12746 break; 12747 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12748 break; 12749 if (event->xclient.window == windows->magnify.id) 12750 { 12751 (void) XWithdrawWindow(display,windows->magnify.id, 12752 windows->magnify.screen); 12753 break; 12754 } 12755 break; 12756 } 12757 case ConfigureNotify: 12758 { 12759 if (event->xconfigure.window == windows->magnify.id) 12760 { 12761 unsigned int 12762 magnify; 12763 12764 /* 12765 Magnify window has a new configuration. 12766 */ 12767 windows->magnify.width=(unsigned int) event->xconfigure.width; 12768 windows->magnify.height=(unsigned int) event->xconfigure.height; 12769 if (windows->magnify.mapped == MagickFalse) 12770 break; 12771 magnify=1; 12772 while ((int) magnify <= event->xconfigure.width) 12773 magnify<<=1; 12774 while ((int) magnify <= event->xconfigure.height) 12775 magnify<<=1; 12776 magnify>>=1; 12777 if (((int) magnify != event->xconfigure.width) || 12778 ((int) magnify != event->xconfigure.height)) 12779 { 12780 XWindowChanges 12781 window_changes; 12782 12783 window_changes.width=(int) magnify; 12784 window_changes.height=(int) magnify; 12785 (void) XReconfigureWMWindow(display,windows->magnify.id, 12786 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12787 &window_changes); 12788 break; 12789 } 12790 XMakeMagnifyImage(display,windows); 12791 break; 12792 } 12793 break; 12794 } 12795 case Expose: 12796 { 12797 if (event->xexpose.window == windows->image.id) 12798 { 12799 XRefreshWindow(display,&windows->image,event); 12800 break; 12801 } 12802 if (event->xexpose.window == windows->pan.id) 12803 if (event->xexpose.count == 0) 12804 { 12805 XDrawPanRectangle(display,windows); 12806 break; 12807 } 12808 if (event->xexpose.window == windows->magnify.id) 12809 if (event->xexpose.count == 0) 12810 { 12811 XMakeMagnifyImage(display,windows); 12812 break; 12813 } 12814 break; 12815 } 12816 case KeyPress: 12817 { 12818 char 12819 command[MaxTextExtent]; 12820 12821 KeySym 12822 key_symbol; 12823 12824 if (event->xkey.window != windows->magnify.id) 12825 break; 12826 /* 12827 Respond to a user key press. 12828 */ 12829 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12830 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12831 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12832 break; 12833 } 12834 case MapNotify: 12835 { 12836 if (event->xmap.window == windows->magnify.id) 12837 { 12838 windows->magnify.mapped=MagickTrue; 12839 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12840 break; 12841 } 12842 if (event->xmap.window == windows->info.id) 12843 { 12844 windows->info.mapped=MagickTrue; 12845 break; 12846 } 12847 break; 12848 } 12849 case MotionNotify: 12850 { 12851 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12852 if (event->xmotion.window == windows->image.id) 12853 if (windows->magnify.mapped != MagickFalse) 12854 { 12855 /* 12856 Update magnified image. 12857 */ 12858 x=event->xmotion.x; 12859 y=event->xmotion.y; 12860 if (x < 0) 12861 x=0; 12862 else 12863 if (x >= (int) windows->image.width) 12864 x=(int) (windows->image.width-1); 12865 windows->magnify.x=(int) windows->image.x+x; 12866 if (y < 0) 12867 y=0; 12868 else 12869 if (y >= (int) windows->image.height) 12870 y=(int) (windows->image.height-1); 12871 windows->magnify.y=windows->image.y+y; 12872 XMakeMagnifyImage(display,windows); 12873 } 12874 break; 12875 } 12876 case UnmapNotify: 12877 { 12878 if (event->xunmap.window == windows->magnify.id) 12879 { 12880 windows->magnify.mapped=MagickFalse; 12881 break; 12882 } 12883 if (event->xunmap.window == windows->info.id) 12884 { 12885 windows->info.mapped=MagickFalse; 12886 break; 12887 } 12888 break; 12889 } 12890 default: 12891 break; 12892 } 12893} 12894 12895/* 12896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12897% % 12898% % 12899% % 12900+ X S e t C r o p G e o m e t r y % 12901% % 12902% % 12903% % 12904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12905% 12906% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12907% and translates it to a cropping geometry relative to the image. 12908% 12909% The format of the XSetCropGeometry method is: 12910% 12911% void XSetCropGeometry(Display *display,XWindows *windows, 12912% RectangleInfo *crop_info,Image *image) 12913% 12914% A description of each parameter follows: 12915% 12916% o display: Specifies a connection to an X server; returned from 12917% XOpenDisplay. 12918% 12919% o windows: Specifies a pointer to a XWindows structure. 12920% 12921% o crop_info: A pointer to a RectangleInfo that defines a region of the 12922% Image window to crop. 12923% 12924% o image: the image. 12925% 12926*/ 12927static void XSetCropGeometry(Display *display,XWindows *windows, 12928 RectangleInfo *crop_info,Image *image) 12929{ 12930 char 12931 text[MaxTextExtent]; 12932 12933 int 12934 x, 12935 y; 12936 12937 MagickRealType 12938 scale_factor; 12939 12940 unsigned int 12941 height, 12942 width; 12943 12944 if (windows->info.mapped != MagickFalse) 12945 { 12946 /* 12947 Display info on cropping rectangle. 12948 */ 12949 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12950 (double) crop_info->width,(double) crop_info->height,(double) 12951 crop_info->x,(double) crop_info->y); 12952 XInfoWidget(display,windows,text); 12953 } 12954 /* 12955 Cropping geometry is relative to any previous crop geometry. 12956 */ 12957 x=0; 12958 y=0; 12959 width=(unsigned int) image->columns; 12960 height=(unsigned int) image->rows; 12961 if (windows->image.crop_geometry != (char *) NULL) 12962 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12963 else 12964 windows->image.crop_geometry=AcquireString((char *) NULL); 12965 /* 12966 Define the crop geometry string from the cropping rectangle. 12967 */ 12968 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12969 if (crop_info->x > 0) 12970 x+=(int) (scale_factor*crop_info->x+0.5); 12971 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12972 if (width == 0) 12973 width=1; 12974 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12975 if (crop_info->y > 0) 12976 y+=(int) (scale_factor*crop_info->y+0.5); 12977 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12978 if (height == 0) 12979 height=1; 12980 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12981 "%ux%u%+d%+d",width,height,x,y); 12982} 12983 12984/* 12985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12986% % 12987% % 12988% % 12989+ X T i l e I m a g e % 12990% % 12991% % 12992% % 12993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12994% 12995% XTileImage() loads or deletes a selected tile from a visual image directory. 12996% The load or delete command is chosen from a menu. 12997% 12998% The format of the XTileImage method is: 12999% 13000% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13001% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13002% 13003% A description of each parameter follows: 13004% 13005% o tile_image: XTileImage reads or deletes the tile image 13006% and returns it. A null image is returned if an error occurs. 13007% 13008% o display: Specifies a connection to an X server; returned from 13009% XOpenDisplay. 13010% 13011% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13012% 13013% o windows: Specifies a pointer to a XWindows structure. 13014% 13015% o image: the image; returned from ReadImage. 13016% 13017% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13018% the entire image is refreshed. 13019% 13020% o exception: return any errors or warnings in this structure. 13021% 13022*/ 13023static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13024 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13025{ 13026 static const char 13027 *VerbMenu[] = 13028 { 13029 "Load", 13030 "Next", 13031 "Former", 13032 "Delete", 13033 "Update", 13034 (char *) NULL, 13035 }; 13036 13037 static const ModeType 13038 TileCommands[] = 13039 { 13040 TileLoadCommand, 13041 TileNextCommand, 13042 TileFormerCommand, 13043 TileDeleteCommand, 13044 TileUpdateCommand 13045 }; 13046 13047 char 13048 command[MaxTextExtent], 13049 filename[MaxTextExtent]; 13050 13051 Image 13052 *tile_image; 13053 13054 int 13055 id, 13056 status, 13057 tile, 13058 x, 13059 y; 13060 13061 MagickRealType 13062 scale_factor; 13063 13064 register char 13065 *p, 13066 *q; 13067 13068 register int 13069 i; 13070 13071 unsigned int 13072 height, 13073 width; 13074 13075 /* 13076 Tile image is relative to montage image configuration. 13077 */ 13078 x=0; 13079 y=0; 13080 width=(unsigned int) image->columns; 13081 height=(unsigned int) image->rows; 13082 if (windows->image.crop_geometry != (char *) NULL) 13083 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13084 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13085 event->xbutton.x+=windows->image.x; 13086 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13087 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13088 event->xbutton.y+=windows->image.y; 13089 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13090 /* 13091 Determine size and location of each tile in the visual image directory. 13092 */ 13093 width=(unsigned int) image->columns; 13094 height=(unsigned int) image->rows; 13095 x=0; 13096 y=0; 13097 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13098 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13099 (event->xbutton.x-x)/width; 13100 if (tile < 0) 13101 { 13102 /* 13103 Button press is outside any tile. 13104 */ 13105 (void) XBell(display,0); 13106 return((Image *) NULL); 13107 } 13108 /* 13109 Determine file name from the tile directory. 13110 */ 13111 p=image->directory; 13112 for (i=tile; (i != 0) && (*p != '\0'); ) 13113 { 13114 if (*p == '\n') 13115 i--; 13116 p++; 13117 } 13118 if (*p == '\0') 13119 { 13120 /* 13121 Button press is outside any tile. 13122 */ 13123 (void) XBell(display,0); 13124 return((Image *) NULL); 13125 } 13126 /* 13127 Select a command from the pop-up menu. 13128 */ 13129 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13130 if (id < 0) 13131 return((Image *) NULL); 13132 q=p; 13133 while ((*q != '\n') && (*q != '\0')) 13134 q++; 13135 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13136 /* 13137 Perform command for the selected tile. 13138 */ 13139 XSetCursorState(display,windows,MagickTrue); 13140 XCheckRefreshWindows(display,windows); 13141 tile_image=NewImageList(); 13142 switch (TileCommands[id]) 13143 { 13144 case TileLoadCommand: 13145 { 13146 /* 13147 Load tile image. 13148 */ 13149 XCheckRefreshWindows(display,windows); 13150 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13151 MaxTextExtent); 13152 (void) CopyMagickString(resource_info->image_info->filename,filename, 13153 MaxTextExtent); 13154 tile_image=ReadImage(resource_info->image_info,exception); 13155 CatchException(exception); 13156 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13157 break; 13158 } 13159 case TileNextCommand: 13160 { 13161 /* 13162 Display next image. 13163 */ 13164 XClientMessage(display,windows->image.id,windows->im_protocols, 13165 windows->im_next_image,CurrentTime); 13166 break; 13167 } 13168 case TileFormerCommand: 13169 { 13170 /* 13171 Display former image. 13172 */ 13173 XClientMessage(display,windows->image.id,windows->im_protocols, 13174 windows->im_former_image,CurrentTime); 13175 break; 13176 } 13177 case TileDeleteCommand: 13178 { 13179 /* 13180 Delete tile image. 13181 */ 13182 if (IsPathAccessible(filename) == MagickFalse) 13183 { 13184 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13185 break; 13186 } 13187 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13188 if (status <= 0) 13189 break; 13190 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 13191 if (status != MagickFalse) 13192 { 13193 XNoticeWidget(display,windows,"Unable to delete image file:", 13194 filename); 13195 break; 13196 } 13197 } 13198 case TileUpdateCommand: 13199 { 13200 int 13201 x_offset, 13202 y_offset; 13203 13204 PixelPacket 13205 pixel; 13206 13207 register int 13208 j; 13209 13210 register Quantum 13211 *s; 13212 13213 /* 13214 Ensure all the images exist. 13215 */ 13216 tile=0; 13217 for (p=image->directory; *p != '\0'; p++) 13218 { 13219 CacheView 13220 *image_view; 13221 13222 q=p; 13223 while ((*q != '\n') && (*q != '\0')) 13224 q++; 13225 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13226 p=q; 13227 if (IsPathAccessible(filename) != MagickFalse) 13228 { 13229 tile++; 13230 continue; 13231 } 13232 /* 13233 Overwrite tile with background color. 13234 */ 13235 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13236 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13237 image_view=AcquireCacheView(image); 13238 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception); 13239 for (i=0; i < (int) height; i++) 13240 { 13241 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13242 y_offset+i,width,1,exception); 13243 if (s == (Quantum *) NULL) 13244 break; 13245 for (j=0; j < (int) width; j++) 13246 { 13247 SetPixelPacket(image,&pixel,s); 13248 s+=GetPixelChannels(image); 13249 } 13250 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13251 break; 13252 } 13253 image_view=DestroyCacheView(image_view); 13254 tile++; 13255 } 13256 windows->image.window_changes.width=(int) image->columns; 13257 windows->image.window_changes.height=(int) image->rows; 13258 XConfigureImageColormap(display,resource_info,windows,image); 13259 (void) XConfigureImage(display,resource_info,windows,image,exception); 13260 break; 13261 } 13262 default: 13263 break; 13264 } 13265 XSetCursorState(display,windows,MagickFalse); 13266 return(tile_image); 13267} 13268 13269/* 13270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13271% % 13272% % 13273% % 13274+ X T r a n s l a t e I m a g e % 13275% % 13276% % 13277% % 13278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13279% 13280% XTranslateImage() translates the image within an Image window by one pixel 13281% as specified by the key symbol. If the image has a `montage string the 13282% translation is respect to the width and height contained within the string. 13283% 13284% The format of the XTranslateImage method is: 13285% 13286% void XTranslateImage(Display *display,XWindows *windows, 13287% Image *image,const KeySym key_symbol) 13288% 13289% A description of each parameter follows: 13290% 13291% o display: Specifies a connection to an X server; returned from 13292% XOpenDisplay. 13293% 13294% o windows: Specifies a pointer to a XWindows structure. 13295% 13296% o image: the image. 13297% 13298% o key_symbol: Specifies a KeySym which indicates which side of the image 13299% to trim. 13300% 13301*/ 13302static void XTranslateImage(Display *display,XWindows *windows, 13303 Image *image,const KeySym key_symbol) 13304{ 13305 char 13306 text[MaxTextExtent]; 13307 13308 int 13309 x, 13310 y; 13311 13312 unsigned int 13313 x_offset, 13314 y_offset; 13315 13316 /* 13317 User specified a pan position offset. 13318 */ 13319 x_offset=windows->image.width; 13320 y_offset=windows->image.height; 13321 if (image->montage != (char *) NULL) 13322 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13323 switch ((int) key_symbol) 13324 { 13325 case XK_Home: 13326 case XK_KP_Home: 13327 { 13328 windows->image.x=(int) windows->image.width/2; 13329 windows->image.y=(int) windows->image.height/2; 13330 break; 13331 } 13332 case XK_Left: 13333 case XK_KP_Left: 13334 { 13335 windows->image.x-=x_offset; 13336 break; 13337 } 13338 case XK_Next: 13339 case XK_Up: 13340 case XK_KP_Up: 13341 { 13342 windows->image.y-=y_offset; 13343 break; 13344 } 13345 case XK_Right: 13346 case XK_KP_Right: 13347 { 13348 windows->image.x+=x_offset; 13349 break; 13350 } 13351 case XK_Prior: 13352 case XK_Down: 13353 case XK_KP_Down: 13354 { 13355 windows->image.y+=y_offset; 13356 break; 13357 } 13358 default: 13359 return; 13360 } 13361 /* 13362 Check boundary conditions. 13363 */ 13364 if (windows->image.x < 0) 13365 windows->image.x=0; 13366 else 13367 if ((int) (windows->image.x+windows->image.width) > 13368 windows->image.ximage->width) 13369 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13370 if (windows->image.y < 0) 13371 windows->image.y=0; 13372 else 13373 if ((int) (windows->image.y+windows->image.height) > 13374 windows->image.ximage->height) 13375 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13376 /* 13377 Refresh Image window. 13378 */ 13379 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13380 windows->image.width,windows->image.height,windows->image.x, 13381 windows->image.y); 13382 XInfoWidget(display,windows,text); 13383 XCheckRefreshWindows(display,windows); 13384 XDrawPanRectangle(display,windows); 13385 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13386 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13387} 13388 13389/* 13390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13391% % 13392% % 13393% % 13394+ X T r i m I m a g e % 13395% % 13396% % 13397% % 13398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13399% 13400% XTrimImage() trims the edges from the Image window. 13401% 13402% The format of the XTrimImage method is: 13403% 13404% MagickBooleanType XTrimImage(Display *display, 13405% XResourceInfo *resource_info,XWindows *windows,Image *image, 13406% ExceptionInfo *exception) 13407% 13408% A description of each parameter follows: 13409% 13410% o display: Specifies a connection to an X server; returned from 13411% XOpenDisplay. 13412% 13413% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13414% 13415% o windows: Specifies a pointer to a XWindows structure. 13416% 13417% o image: the image. 13418% 13419% o exception: return any errors or warnings in this structure. 13420% 13421*/ 13422static MagickBooleanType XTrimImage(Display *display, 13423 XResourceInfo *resource_info,XWindows *windows,Image *image, 13424 ExceptionInfo *exception) 13425{ 13426 RectangleInfo 13427 trim_info; 13428 13429 register int 13430 x, 13431 y; 13432 13433 size_t 13434 background, 13435 pixel; 13436 13437 /* 13438 Trim edges from image. 13439 */ 13440 XSetCursorState(display,windows,MagickTrue); 13441 XCheckRefreshWindows(display,windows); 13442 /* 13443 Crop the left edge. 13444 */ 13445 background=XGetPixel(windows->image.ximage,0,0); 13446 trim_info.width=(size_t) windows->image.ximage->width; 13447 for (x=0; x < windows->image.ximage->width; x++) 13448 { 13449 for (y=0; y < windows->image.ximage->height; y++) 13450 { 13451 pixel=XGetPixel(windows->image.ximage,x,y); 13452 if (pixel != background) 13453 break; 13454 } 13455 if (y < windows->image.ximage->height) 13456 break; 13457 } 13458 trim_info.x=(ssize_t) x; 13459 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13460 { 13461 XSetCursorState(display,windows,MagickFalse); 13462 return(MagickFalse); 13463 } 13464 /* 13465 Crop the right edge. 13466 */ 13467 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13468 for (x=windows->image.ximage->width-1; x != 0; x--) 13469 { 13470 for (y=0; y < windows->image.ximage->height; y++) 13471 { 13472 pixel=XGetPixel(windows->image.ximage,x,y); 13473 if (pixel != background) 13474 break; 13475 } 13476 if (y < windows->image.ximage->height) 13477 break; 13478 } 13479 trim_info.width=(size_t) (x-trim_info.x+1); 13480 /* 13481 Crop the top edge. 13482 */ 13483 background=XGetPixel(windows->image.ximage,0,0); 13484 trim_info.height=(size_t) windows->image.ximage->height; 13485 for (y=0; y < windows->image.ximage->height; y++) 13486 { 13487 for (x=0; x < windows->image.ximage->width; x++) 13488 { 13489 pixel=XGetPixel(windows->image.ximage,x,y); 13490 if (pixel != background) 13491 break; 13492 } 13493 if (x < windows->image.ximage->width) 13494 break; 13495 } 13496 trim_info.y=(ssize_t) y; 13497 /* 13498 Crop the bottom edge. 13499 */ 13500 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13501 for (y=windows->image.ximage->height-1; y != 0; y--) 13502 { 13503 for (x=0; x < windows->image.ximage->width; x++) 13504 { 13505 pixel=XGetPixel(windows->image.ximage,x,y); 13506 if (pixel != background) 13507 break; 13508 } 13509 if (x < windows->image.ximage->width) 13510 break; 13511 } 13512 trim_info.height=(size_t) y-trim_info.y+1; 13513 if (((unsigned int) trim_info.width != windows->image.width) || 13514 ((unsigned int) trim_info.height != windows->image.height)) 13515 { 13516 /* 13517 Reconfigure Image window as defined by the trimming rectangle. 13518 */ 13519 XSetCropGeometry(display,windows,&trim_info,image); 13520 windows->image.window_changes.width=(int) trim_info.width; 13521 windows->image.window_changes.height=(int) trim_info.height; 13522 (void) XConfigureImage(display,resource_info,windows,image,exception); 13523 } 13524 XSetCursorState(display,windows,MagickFalse); 13525 return(MagickTrue); 13526} 13527 13528/* 13529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13530% % 13531% % 13532% % 13533+ X V i s u a l D i r e c t o r y I m a g e % 13534% % 13535% % 13536% % 13537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13538% 13539% XVisualDirectoryImage() creates a Visual Image Directory. 13540% 13541% The format of the XVisualDirectoryImage method is: 13542% 13543% Image *XVisualDirectoryImage(Display *display, 13544% XResourceInfo *resource_info,XWindows *windows, 13545% ExceptionInfo *exception) 13546% 13547% A description of each parameter follows: 13548% 13549% o display: Specifies a connection to an X server; returned from 13550% XOpenDisplay. 13551% 13552% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13553% 13554% o windows: Specifies a pointer to a XWindows structure. 13555% 13556% o exception: return any errors or warnings in this structure. 13557% 13558*/ 13559static Image *XVisualDirectoryImage(Display *display, 13560 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13561{ 13562#define TileImageTag "Scale/Image" 13563#define XClientName "montage" 13564 13565 char 13566 **filelist; 13567 13568 Image 13569 *images, 13570 *montage_image, 13571 *next_image, 13572 *thumbnail_image; 13573 13574 ImageInfo 13575 *read_info; 13576 13577 int 13578 number_files; 13579 13580 MagickBooleanType 13581 backdrop; 13582 13583 MagickStatusType 13584 status; 13585 13586 MontageInfo 13587 *montage_info; 13588 13589 RectangleInfo 13590 geometry; 13591 13592 register int 13593 i; 13594 13595 static char 13596 filename[MaxTextExtent] = "\0", 13597 filenames[MaxTextExtent] = "*"; 13598 13599 XResourceInfo 13600 background_resources; 13601 13602 /* 13603 Request file name from user. 13604 */ 13605 XFileBrowserWidget(display,windows,"Directory",filenames); 13606 if (*filenames == '\0') 13607 return((Image *) NULL); 13608 /* 13609 Expand the filenames. 13610 */ 13611 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13612 if (filelist == (char **) NULL) 13613 { 13614 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13615 filenames); 13616 return((Image *) NULL); 13617 } 13618 number_files=1; 13619 filelist[0]=filenames; 13620 status=ExpandFilenames(&number_files,&filelist); 13621 if ((status == MagickFalse) || (number_files == 0)) 13622 { 13623 if (number_files == 0) 13624 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13625 else 13626 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13627 filenames); 13628 return((Image *) NULL); 13629 } 13630 /* 13631 Set image background resources. 13632 */ 13633 background_resources=(*resource_info); 13634 background_resources.window_id=AcquireString(""); 13635 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13636 "0x%lx",windows->image.id); 13637 background_resources.backdrop=MagickTrue; 13638 /* 13639 Read each image and convert them to a tile. 13640 */ 13641 backdrop=(windows->visual_info->klass == TrueColor) || 13642 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13643 read_info=CloneImageInfo(resource_info->image_info); 13644 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13645 (void) CloneString(&read_info->size,DefaultTileGeometry); 13646 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13647 (void *) NULL); 13648 images=NewImageList(); 13649 XSetCursorState(display,windows,MagickTrue); 13650 XCheckRefreshWindows(display,windows); 13651 for (i=0; i < (int) number_files; i++) 13652 { 13653 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13654 filelist[i]=DestroyString(filelist[i]); 13655 *read_info->magick='\0'; 13656 next_image=ReadImage(read_info,exception); 13657 CatchException(exception); 13658 if (next_image != (Image *) NULL) 13659 { 13660 (void) DeleteImageProperty(next_image,"label"); 13661 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13662 read_info,next_image,DefaultTileLabel,exception)); 13663 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13664 exception); 13665 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13666 geometry.height,exception); 13667 if (thumbnail_image != (Image *) NULL) 13668 { 13669 next_image=DestroyImage(next_image); 13670 next_image=thumbnail_image; 13671 } 13672 if (backdrop) 13673 { 13674 (void) XDisplayBackgroundImage(display,&background_resources, 13675 next_image,exception); 13676 XSetCursorState(display,windows,MagickTrue); 13677 } 13678 AppendImageToList(&images,next_image); 13679 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13680 { 13681 MagickBooleanType 13682 proceed; 13683 13684 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13685 (MagickSizeType) number_files); 13686 if (proceed == MagickFalse) 13687 break; 13688 } 13689 } 13690 } 13691 filelist=(char **) RelinquishMagickMemory(filelist); 13692 if (images == (Image *) NULL) 13693 { 13694 read_info=DestroyImageInfo(read_info); 13695 XSetCursorState(display,windows,MagickFalse); 13696 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13697 return((Image *) NULL); 13698 } 13699 /* 13700 Create the Visual Image Directory. 13701 */ 13702 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13703 montage_info->pointsize=10; 13704 if (resource_info->font != (char *) NULL) 13705 (void) CloneString(&montage_info->font,resource_info->font); 13706 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13707 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13708 images),exception); 13709 images=DestroyImageList(images); 13710 montage_info=DestroyMontageInfo(montage_info); 13711 read_info=DestroyImageInfo(read_info); 13712 XSetCursorState(display,windows,MagickFalse); 13713 if (montage_image == (Image *) NULL) 13714 return(montage_image); 13715 XClientMessage(display,windows->image.id,windows->im_protocols, 13716 windows->im_next_image,CurrentTime); 13717 return(montage_image); 13718} 13719 13720/* 13721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13722% % 13723% % 13724% % 13725% X D i s p l a y B a c k g r o u n d I m a g e % 13726% % 13727% % 13728% % 13729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13730% 13731% XDisplayBackgroundImage() displays an image in the background of a window. 13732% 13733% The format of the XDisplayBackgroundImage method is: 13734% 13735% MagickBooleanType XDisplayBackgroundImage(Display *display, 13736% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13737% 13738% A description of each parameter follows: 13739% 13740% o display: Specifies a connection to an X server; returned from 13741% XOpenDisplay. 13742% 13743% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13744% 13745% o image: the image. 13746% 13747% o exception: return any errors or warnings in this structure. 13748% 13749*/ 13750MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13751 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13752{ 13753 char 13754 geometry[MaxTextExtent], 13755 visual_type[MaxTextExtent]; 13756 13757 int 13758 height, 13759 status, 13760 width; 13761 13762 RectangleInfo 13763 geometry_info; 13764 13765 static XPixelInfo 13766 pixel; 13767 13768 static XStandardColormap 13769 *map_info; 13770 13771 static XVisualInfo 13772 *visual_info = (XVisualInfo *) NULL; 13773 13774 static XWindowInfo 13775 window_info; 13776 13777 size_t 13778 delay; 13779 13780 Window 13781 root_window; 13782 13783 XGCValues 13784 context_values; 13785 13786 XResourceInfo 13787 resources; 13788 13789 XWindowAttributes 13790 window_attributes; 13791 13792 /* 13793 Determine target window. 13794 */ 13795 assert(image != (Image *) NULL); 13796 assert(image->signature == MagickSignature); 13797 if (image->debug != MagickFalse) 13798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13799 resources=(*resource_info); 13800 window_info.id=(Window) NULL; 13801 root_window=XRootWindow(display,XDefaultScreen(display)); 13802 if (LocaleCompare(resources.window_id,"root") == 0) 13803 window_info.id=root_window; 13804 else 13805 { 13806 if (isdigit((unsigned char) *resources.window_id) != 0) 13807 window_info.id=XWindowByID(display,root_window, 13808 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13809 if (window_info.id == (Window) NULL) 13810 window_info.id=XWindowByName(display,root_window,resources.window_id); 13811 } 13812 if (window_info.id == (Window) NULL) 13813 { 13814 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13815 resources.window_id); 13816 return(MagickFalse); 13817 } 13818 /* 13819 Determine window visual id. 13820 */ 13821 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13822 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13823 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13824 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13825 if (status != 0) 13826 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13827 XVisualIDFromVisual(window_attributes.visual)); 13828 if (visual_info == (XVisualInfo *) NULL) 13829 { 13830 /* 13831 Allocate standard colormap. 13832 */ 13833 map_info=XAllocStandardColormap(); 13834 if (map_info == (XStandardColormap *) NULL) 13835 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13836 image->filename); 13837 map_info->colormap=(Colormap) NULL; 13838 pixel.pixels=(unsigned long *) NULL; 13839 /* 13840 Initialize visual info. 13841 */ 13842 resources.map_type=(char *) NULL; 13843 resources.visual_type=visual_type; 13844 visual_info=XBestVisualInfo(display,map_info,&resources); 13845 if (visual_info == (XVisualInfo *) NULL) 13846 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13847 resources.visual_type); 13848 /* 13849 Initialize window info. 13850 */ 13851 window_info.ximage=(XImage *) NULL; 13852 window_info.matte_image=(XImage *) NULL; 13853 window_info.pixmap=(Pixmap) NULL; 13854 window_info.matte_pixmap=(Pixmap) NULL; 13855 } 13856 /* 13857 Free previous root colors. 13858 */ 13859 if (window_info.id == root_window) 13860 (void) XDestroyWindowColors(display,root_window); 13861 /* 13862 Initialize Standard Colormap. 13863 */ 13864 resources.colormap=SharedColormap; 13865 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13866 /* 13867 Graphic context superclass. 13868 */ 13869 context_values.background=pixel.background_color.pixel; 13870 context_values.foreground=pixel.foreground_color.pixel; 13871 pixel.annotate_context=XCreateGC(display,window_info.id, 13872 (size_t) (GCBackground | GCForeground),&context_values); 13873 if (pixel.annotate_context == (GC) NULL) 13874 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13875 image->filename); 13876 /* 13877 Initialize Image window attributes. 13878 */ 13879 window_info.name=AcquireString("\0"); 13880 window_info.icon_name=AcquireString("\0"); 13881 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13882 &resources,&window_info); 13883 /* 13884 Create the X image. 13885 */ 13886 window_info.width=(unsigned int) image->columns; 13887 window_info.height=(unsigned int) image->rows; 13888 if ((image->columns != window_info.width) || 13889 (image->rows != window_info.height)) 13890 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13891 image->filename); 13892 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13893 window_attributes.width,window_attributes.height); 13894 geometry_info.width=window_info.width; 13895 geometry_info.height=window_info.height; 13896 geometry_info.x=(ssize_t) window_info.x; 13897 geometry_info.y=(ssize_t) window_info.y; 13898 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13899 &geometry_info.width,&geometry_info.height); 13900 window_info.width=(unsigned int) geometry_info.width; 13901 window_info.height=(unsigned int) geometry_info.height; 13902 window_info.x=(int) geometry_info.x; 13903 window_info.y=(int) geometry_info.y; 13904 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13905 window_info.height,exception); 13906 if (status == MagickFalse) 13907 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13908 image->filename); 13909 window_info.x=0; 13910 window_info.y=0; 13911 if (image->debug != MagickFalse) 13912 { 13913 (void) LogMagickEvent(X11Event,GetMagickModule(), 13914 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13915 (double) image->columns,(double) image->rows); 13916 if (image->colors != 0) 13917 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13918 image->colors); 13919 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13920 } 13921 /* 13922 Adjust image dimensions as specified by backdrop or geometry options. 13923 */ 13924 width=(int) window_info.width; 13925 height=(int) window_info.height; 13926 if (resources.backdrop != MagickFalse) 13927 { 13928 /* 13929 Center image on window. 13930 */ 13931 window_info.x=(window_attributes.width/2)- 13932 (window_info.ximage->width/2); 13933 window_info.y=(window_attributes.height/2)- 13934 (window_info.ximage->height/2); 13935 width=window_attributes.width; 13936 height=window_attributes.height; 13937 } 13938 if ((resources.image_geometry != (char *) NULL) && 13939 (*resources.image_geometry != '\0')) 13940 { 13941 char 13942 default_geometry[MaxTextExtent]; 13943 13944 int 13945 flags, 13946 gravity; 13947 13948 XSizeHints 13949 *size_hints; 13950 13951 /* 13952 User specified geometry. 13953 */ 13954 size_hints=XAllocSizeHints(); 13955 if (size_hints == (XSizeHints *) NULL) 13956 ThrowXWindowFatalException(ResourceLimitFatalError, 13957 "MemoryAllocationFailed",image->filename); 13958 size_hints->flags=0L; 13959 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13960 width,height); 13961 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13962 default_geometry,window_info.border_width,size_hints,&window_info.x, 13963 &window_info.y,&width,&height,&gravity); 13964 if (flags & (XValue | YValue)) 13965 { 13966 width=window_attributes.width; 13967 height=window_attributes.height; 13968 } 13969 (void) XFree((void *) size_hints); 13970 } 13971 /* 13972 Create the X pixmap. 13973 */ 13974 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 13975 (unsigned int) height,window_info.depth); 13976 if (window_info.pixmap == (Pixmap) NULL) 13977 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 13978 image->filename); 13979 /* 13980 Display pixmap on the window. 13981 */ 13982 if (((unsigned int) width > window_info.width) || 13983 ((unsigned int) height > window_info.height)) 13984 (void) XFillRectangle(display,window_info.pixmap, 13985 window_info.annotate_context,0,0,(unsigned int) width, 13986 (unsigned int) height); 13987 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 13988 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 13989 window_info.width,(unsigned int) window_info.height); 13990 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 13991 (void) XClearWindow(display,window_info.id); 13992 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 13993 XDelay(display,delay == 0UL ? 10UL : delay); 13994 (void) XSync(display,MagickFalse); 13995 return(window_info.id == root_window ? MagickTrue : MagickFalse); 13996} 13997 13998/* 13999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14000% % 14001% % 14002% % 14003+ X D i s p l a y I m a g e % 14004% % 14005% % 14006% % 14007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14008% 14009% XDisplayImage() displays an image via X11. A new image is created and 14010% returned if the user interactively transforms the displayed image. 14011% 14012% The format of the XDisplayImage method is: 14013% 14014% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14015% char **argv,int argc,Image **image,size_t *state, 14016% ExceptionInfo *exception) 14017% 14018% A description of each parameter follows: 14019% 14020% o nexus: Method XDisplayImage returns an image when the 14021% user chooses 'Open Image' from the command menu or picks a tile 14022% from the image directory. Otherwise a null image is returned. 14023% 14024% o display: Specifies a connection to an X server; returned from 14025% XOpenDisplay. 14026% 14027% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14028% 14029% o argv: Specifies the application's argument list. 14030% 14031% o argc: Specifies the number of arguments. 14032% 14033% o image: Specifies an address to an address of an Image structure; 14034% 14035% o exception: return any errors or warnings in this structure. 14036% 14037*/ 14038MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14039 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14040{ 14041#define MagnifySize 256 /* must be a power of 2 */ 14042#define MagickMenus 10 14043#define MagickTitle "Commands" 14044 14045 static const char 14046 *CommandMenu[] = 14047 { 14048 "File", 14049 "Edit", 14050 "View", 14051 "Transform", 14052 "Enhance", 14053 "Effects", 14054 "F/X", 14055 "Image Edit", 14056 "Miscellany", 14057 "Help", 14058 (char *) NULL 14059 }, 14060 *FileMenu[] = 14061 { 14062 "Open...", 14063 "Next", 14064 "Former", 14065 "Select...", 14066 "Save...", 14067 "Print...", 14068 "Delete...", 14069 "New...", 14070 "Visual Directory...", 14071 "Quit", 14072 (char *) NULL 14073 }, 14074 *EditMenu[] = 14075 { 14076 "Undo", 14077 "Redo", 14078 "Cut", 14079 "Copy", 14080 "Paste", 14081 (char *) NULL 14082 }, 14083 *ViewMenu[] = 14084 { 14085 "Half Size", 14086 "Original Size", 14087 "Double Size", 14088 "Resize...", 14089 "Apply", 14090 "Refresh", 14091 "Restore", 14092 (char *) NULL 14093 }, 14094 *TransformMenu[] = 14095 { 14096 "Crop", 14097 "Chop", 14098 "Flop", 14099 "Flip", 14100 "Rotate Right", 14101 "Rotate Left", 14102 "Rotate...", 14103 "Shear...", 14104 "Roll...", 14105 "Trim Edges", 14106 (char *) NULL 14107 }, 14108 *EnhanceMenu[] = 14109 { 14110 "Hue...", 14111 "Saturation...", 14112 "Brightness...", 14113 "Gamma...", 14114 "Spiff", 14115 "Dull", 14116 "Contrast Stretch...", 14117 "Sigmoidal Contrast...", 14118 "Normalize", 14119 "Equalize", 14120 "Negate", 14121 "Grayscale", 14122 "Map...", 14123 "Quantize...", 14124 (char *) NULL 14125 }, 14126 *EffectsMenu[] = 14127 { 14128 "Despeckle", 14129 "Emboss", 14130 "Reduce Noise", 14131 "Add Noise...", 14132 "Sharpen...", 14133 "Blur...", 14134 "Threshold...", 14135 "Edge Detect...", 14136 "Spread...", 14137 "Shade...", 14138 "Raise...", 14139 "Segment...", 14140 (char *) NULL 14141 }, 14142 *FXMenu[] = 14143 { 14144 "Solarize...", 14145 "Sepia Tone...", 14146 "Swirl...", 14147 "Implode...", 14148 "Vignette...", 14149 "Wave...", 14150 "Oil Paint...", 14151 "Charcoal Draw...", 14152 (char *) NULL 14153 }, 14154 *ImageEditMenu[] = 14155 { 14156 "Annotate...", 14157 "Draw...", 14158 "Color...", 14159 "Matte...", 14160 "Composite...", 14161 "Add Border...", 14162 "Add Frame...", 14163 "Comment...", 14164 "Launch...", 14165 "Region of Interest...", 14166 (char *) NULL 14167 }, 14168 *MiscellanyMenu[] = 14169 { 14170 "Image Info", 14171 "Zoom Image", 14172 "Show Preview...", 14173 "Show Histogram", 14174 "Show Matte", 14175 "Background...", 14176 "Slide Show...", 14177 "Preferences...", 14178 (char *) NULL 14179 }, 14180 *HelpMenu[] = 14181 { 14182 "Overview", 14183 "Browse Documentation", 14184 "About Display", 14185 (char *) NULL 14186 }, 14187 *ShortCutsMenu[] = 14188 { 14189 "Next", 14190 "Former", 14191 "Open...", 14192 "Save...", 14193 "Print...", 14194 "Undo", 14195 "Restore", 14196 "Image Info", 14197 "Quit", 14198 (char *) NULL 14199 }, 14200 *VirtualMenu[] = 14201 { 14202 "Image Info", 14203 "Print", 14204 "Next", 14205 "Quit", 14206 (char *) NULL 14207 }; 14208 14209 static const char 14210 **Menus[MagickMenus] = 14211 { 14212 FileMenu, 14213 EditMenu, 14214 ViewMenu, 14215 TransformMenu, 14216 EnhanceMenu, 14217 EffectsMenu, 14218 FXMenu, 14219 ImageEditMenu, 14220 MiscellanyMenu, 14221 HelpMenu 14222 }; 14223 14224 static CommandType 14225 CommandMenus[] = 14226 { 14227 NullCommand, 14228 NullCommand, 14229 NullCommand, 14230 NullCommand, 14231 NullCommand, 14232 NullCommand, 14233 NullCommand, 14234 NullCommand, 14235 NullCommand, 14236 NullCommand, 14237 }, 14238 FileCommands[] = 14239 { 14240 OpenCommand, 14241 NextCommand, 14242 FormerCommand, 14243 SelectCommand, 14244 SaveCommand, 14245 PrintCommand, 14246 DeleteCommand, 14247 NewCommand, 14248 VisualDirectoryCommand, 14249 QuitCommand 14250 }, 14251 EditCommands[] = 14252 { 14253 UndoCommand, 14254 RedoCommand, 14255 CutCommand, 14256 CopyCommand, 14257 PasteCommand 14258 }, 14259 ViewCommands[] = 14260 { 14261 HalfSizeCommand, 14262 OriginalSizeCommand, 14263 DoubleSizeCommand, 14264 ResizeCommand, 14265 ApplyCommand, 14266 RefreshCommand, 14267 RestoreCommand 14268 }, 14269 TransformCommands[] = 14270 { 14271 CropCommand, 14272 ChopCommand, 14273 FlopCommand, 14274 FlipCommand, 14275 RotateRightCommand, 14276 RotateLeftCommand, 14277 RotateCommand, 14278 ShearCommand, 14279 RollCommand, 14280 TrimCommand 14281 }, 14282 EnhanceCommands[] = 14283 { 14284 HueCommand, 14285 SaturationCommand, 14286 BrightnessCommand, 14287 GammaCommand, 14288 SpiffCommand, 14289 DullCommand, 14290 ContrastStretchCommand, 14291 SigmoidalContrastCommand, 14292 NormalizeCommand, 14293 EqualizeCommand, 14294 NegateCommand, 14295 GrayscaleCommand, 14296 MapCommand, 14297 QuantizeCommand 14298 }, 14299 EffectsCommands[] = 14300 { 14301 DespeckleCommand, 14302 EmbossCommand, 14303 ReduceNoiseCommand, 14304 AddNoiseCommand, 14305 SharpenCommand, 14306 BlurCommand, 14307 ThresholdCommand, 14308 EdgeDetectCommand, 14309 SpreadCommand, 14310 ShadeCommand, 14311 RaiseCommand, 14312 SegmentCommand 14313 }, 14314 FXCommands[] = 14315 { 14316 SolarizeCommand, 14317 SepiaToneCommand, 14318 SwirlCommand, 14319 ImplodeCommand, 14320 VignetteCommand, 14321 WaveCommand, 14322 OilPaintCommand, 14323 CharcoalDrawCommand 14324 }, 14325 ImageEditCommands[] = 14326 { 14327 AnnotateCommand, 14328 DrawCommand, 14329 ColorCommand, 14330 MatteCommand, 14331 CompositeCommand, 14332 AddBorderCommand, 14333 AddFrameCommand, 14334 CommentCommand, 14335 LaunchCommand, 14336 RegionofInterestCommand 14337 }, 14338 MiscellanyCommands[] = 14339 { 14340 InfoCommand, 14341 ZoomCommand, 14342 ShowPreviewCommand, 14343 ShowHistogramCommand, 14344 ShowMatteCommand, 14345 BackgroundCommand, 14346 SlideShowCommand, 14347 PreferencesCommand 14348 }, 14349 HelpCommands[] = 14350 { 14351 HelpCommand, 14352 BrowseDocumentationCommand, 14353 VersionCommand 14354 }, 14355 ShortCutsCommands[] = 14356 { 14357 NextCommand, 14358 FormerCommand, 14359 OpenCommand, 14360 SaveCommand, 14361 PrintCommand, 14362 UndoCommand, 14363 RestoreCommand, 14364 InfoCommand, 14365 QuitCommand 14366 }, 14367 VirtualCommands[] = 14368 { 14369 InfoCommand, 14370 PrintCommand, 14371 NextCommand, 14372 QuitCommand 14373 }; 14374 14375 static CommandType 14376 *Commands[MagickMenus] = 14377 { 14378 FileCommands, 14379 EditCommands, 14380 ViewCommands, 14381 TransformCommands, 14382 EnhanceCommands, 14383 EffectsCommands, 14384 FXCommands, 14385 ImageEditCommands, 14386 MiscellanyCommands, 14387 HelpCommands 14388 }; 14389 14390 char 14391 command[MaxTextExtent], 14392 *directory, 14393 geometry[MaxTextExtent], 14394 resource_name[MaxTextExtent]; 14395 14396 CommandType 14397 command_type; 14398 14399 Image 14400 *display_image, 14401 *nexus; 14402 14403 int 14404 entry, 14405 id; 14406 14407 KeySym 14408 key_symbol; 14409 14410 MagickStatusType 14411 context_mask, 14412 status; 14413 14414 RectangleInfo 14415 geometry_info; 14416 14417 register int 14418 i; 14419 14420 static char 14421 working_directory[MaxTextExtent]; 14422 14423 static XPoint 14424 vid_info; 14425 14426 static XWindowInfo 14427 *magick_windows[MaxXWindows]; 14428 14429 static unsigned int 14430 number_windows; 14431 14432 struct stat 14433 attributes; 14434 14435 time_t 14436 timer, 14437 timestamp, 14438 update_time; 14439 14440 unsigned int 14441 height, 14442 width; 14443 14444 size_t 14445 delay; 14446 14447 WarningHandler 14448 warning_handler; 14449 14450 Window 14451 root_window; 14452 14453 XClassHint 14454 *class_hints; 14455 14456 XEvent 14457 event; 14458 14459 XFontStruct 14460 *font_info; 14461 14462 XGCValues 14463 context_values; 14464 14465 XPixelInfo 14466 *icon_pixel, 14467 *pixel; 14468 14469 XResourceInfo 14470 *icon_resources; 14471 14472 XStandardColormap 14473 *icon_map, 14474 *map_info; 14475 14476 XVisualInfo 14477 *icon_visual, 14478 *visual_info; 14479 14480 XWindowChanges 14481 window_changes; 14482 14483 XWindows 14484 *windows; 14485 14486 XWMHints 14487 *manager_hints; 14488 14489 assert(image != (Image **) NULL); 14490 assert((*image)->signature == MagickSignature); 14491 if ((*image)->debug != MagickFalse) 14492 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14493 display_image=(*image); 14494 warning_handler=(WarningHandler) NULL; 14495 windows=XSetWindows((XWindows *) ~0); 14496 if (windows != (XWindows *) NULL) 14497 { 14498 int 14499 status; 14500 14501 status=chdir(working_directory); 14502 if (status == -1) 14503 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14504 "UnableToOpenFile","%s",working_directory); 14505 warning_handler=resource_info->display_warnings ? 14506 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14507 warning_handler=resource_info->display_warnings ? 14508 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14509 } 14510 else 14511 { 14512 /* 14513 Allocate windows structure. 14514 */ 14515 resource_info->colors=display_image->colors; 14516 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14517 if (windows == (XWindows *) NULL) 14518 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14519 (*image)->filename); 14520 /* 14521 Initialize window id's. 14522 */ 14523 number_windows=0; 14524 magick_windows[number_windows++]=(&windows->icon); 14525 magick_windows[number_windows++]=(&windows->backdrop); 14526 magick_windows[number_windows++]=(&windows->image); 14527 magick_windows[number_windows++]=(&windows->info); 14528 magick_windows[number_windows++]=(&windows->command); 14529 magick_windows[number_windows++]=(&windows->widget); 14530 magick_windows[number_windows++]=(&windows->popup); 14531 magick_windows[number_windows++]=(&windows->magnify); 14532 magick_windows[number_windows++]=(&windows->pan); 14533 for (i=0; i < (int) number_windows; i++) 14534 magick_windows[i]->id=(Window) NULL; 14535 vid_info.x=0; 14536 vid_info.y=0; 14537 } 14538 /* 14539 Initialize font info. 14540 */ 14541 if (windows->font_info != (XFontStruct *) NULL) 14542 (void) XFreeFont(display,windows->font_info); 14543 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14544 if (windows->font_info == (XFontStruct *) NULL) 14545 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14546 resource_info->font); 14547 /* 14548 Initialize Standard Colormap. 14549 */ 14550 map_info=windows->map_info; 14551 icon_map=windows->icon_map; 14552 visual_info=windows->visual_info; 14553 icon_visual=windows->icon_visual; 14554 pixel=windows->pixel_info; 14555 icon_pixel=windows->icon_pixel; 14556 font_info=windows->font_info; 14557 icon_resources=windows->icon_resources; 14558 class_hints=windows->class_hints; 14559 manager_hints=windows->manager_hints; 14560 root_window=XRootWindow(display,visual_info->screen); 14561 nexus=NewImageList(); 14562 if (display_image->debug != MagickFalse) 14563 { 14564 (void) LogMagickEvent(X11Event,GetMagickModule(), 14565 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14566 (double) display_image->scene,(double) display_image->columns, 14567 (double) display_image->rows); 14568 if (display_image->colors != 0) 14569 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14570 display_image->colors); 14571 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14572 display_image->magick); 14573 } 14574 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14575 map_info,pixel); 14576 display_image->taint=MagickFalse; 14577 /* 14578 Initialize graphic context. 14579 */ 14580 windows->context.id=(Window) NULL; 14581 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14582 resource_info,&windows->context); 14583 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14584 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14585 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14586 manager_hints->flags=InputHint | StateHint; 14587 manager_hints->input=MagickFalse; 14588 manager_hints->initial_state=WithdrawnState; 14589 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14590 &windows->context); 14591 if (display_image->debug != MagickFalse) 14592 (void) LogMagickEvent(X11Event,GetMagickModule(), 14593 "Window id: 0x%lx (context)",windows->context.id); 14594 context_values.background=pixel->background_color.pixel; 14595 context_values.font=font_info->fid; 14596 context_values.foreground=pixel->foreground_color.pixel; 14597 context_values.graphics_exposures=MagickFalse; 14598 context_mask=(MagickStatusType) 14599 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14600 if (pixel->annotate_context != (GC) NULL) 14601 (void) XFreeGC(display,pixel->annotate_context); 14602 pixel->annotate_context=XCreateGC(display,windows->context.id, 14603 context_mask,&context_values); 14604 if (pixel->annotate_context == (GC) NULL) 14605 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14606 display_image->filename); 14607 context_values.background=pixel->depth_color.pixel; 14608 if (pixel->widget_context != (GC) NULL) 14609 (void) XFreeGC(display,pixel->widget_context); 14610 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14611 &context_values); 14612 if (pixel->widget_context == (GC) NULL) 14613 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14614 display_image->filename); 14615 context_values.background=pixel->foreground_color.pixel; 14616 context_values.foreground=pixel->background_color.pixel; 14617 context_values.plane_mask=context_values.background ^ 14618 context_values.foreground; 14619 if (pixel->highlight_context != (GC) NULL) 14620 (void) XFreeGC(display,pixel->highlight_context); 14621 pixel->highlight_context=XCreateGC(display,windows->context.id, 14622 (size_t) (context_mask | GCPlaneMask),&context_values); 14623 if (pixel->highlight_context == (GC) NULL) 14624 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14625 display_image->filename); 14626 (void) XDestroyWindow(display,windows->context.id); 14627 /* 14628 Initialize icon window. 14629 */ 14630 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14631 icon_resources,&windows->icon); 14632 windows->icon.geometry=resource_info->icon_geometry; 14633 XBestIconSize(display,&windows->icon,display_image); 14634 windows->icon.attributes.colormap=XDefaultColormap(display, 14635 icon_visual->screen); 14636 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14637 manager_hints->flags=InputHint | StateHint; 14638 manager_hints->input=MagickFalse; 14639 manager_hints->initial_state=IconicState; 14640 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14641 &windows->icon); 14642 if (display_image->debug != MagickFalse) 14643 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14644 windows->icon.id); 14645 /* 14646 Initialize graphic context for icon window. 14647 */ 14648 if (icon_pixel->annotate_context != (GC) NULL) 14649 (void) XFreeGC(display,icon_pixel->annotate_context); 14650 context_values.background=icon_pixel->background_color.pixel; 14651 context_values.foreground=icon_pixel->foreground_color.pixel; 14652 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14653 (size_t) (GCBackground | GCForeground),&context_values); 14654 if (icon_pixel->annotate_context == (GC) NULL) 14655 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14656 display_image->filename); 14657 windows->icon.annotate_context=icon_pixel->annotate_context; 14658 /* 14659 Initialize Image window. 14660 */ 14661 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14662 &windows->image); 14663 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14664 if (resource_info->use_shared_memory == MagickFalse) 14665 windows->image.shared_memory=MagickFalse; 14666 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14667 { 14668 char 14669 *title; 14670 14671 title=InterpretImageProperties(resource_info->image_info,display_image, 14672 resource_info->title,exception); 14673 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14674 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14675 title=DestroyString(title); 14676 } 14677 else 14678 { 14679 char 14680 filename[MaxTextExtent]; 14681 14682 /* 14683 Window name is the base of the filename. 14684 */ 14685 GetPathComponent(display_image->magick_filename,TailPath,filename); 14686 if (GetImageListLength(display_image) == 1) 14687 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14688 "%s: %s",MagickPackageName,filename); 14689 else 14690 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14691 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14692 (double) display_image->scene,(double) GetImageListLength( 14693 display_image)); 14694 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14695 } 14696 if (resource_info->immutable) 14697 windows->image.immutable=MagickTrue; 14698 windows->image.use_pixmap=resource_info->use_pixmap; 14699 windows->image.geometry=resource_info->image_geometry; 14700 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14701 XDisplayWidth(display,visual_info->screen), 14702 XDisplayHeight(display,visual_info->screen)); 14703 geometry_info.width=display_image->columns; 14704 geometry_info.height=display_image->rows; 14705 geometry_info.x=0; 14706 geometry_info.y=0; 14707 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14708 &geometry_info.width,&geometry_info.height); 14709 windows->image.width=(unsigned int) geometry_info.width; 14710 windows->image.height=(unsigned int) geometry_info.height; 14711 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14712 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14713 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14714 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14715 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14716 resource_info,&windows->backdrop); 14717 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14718 { 14719 /* 14720 Initialize backdrop window. 14721 */ 14722 windows->backdrop.x=0; 14723 windows->backdrop.y=0; 14724 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14725 windows->backdrop.flags=(size_t) (USSize | USPosition); 14726 windows->backdrop.width=(unsigned int) 14727 XDisplayWidth(display,visual_info->screen); 14728 windows->backdrop.height=(unsigned int) 14729 XDisplayHeight(display,visual_info->screen); 14730 windows->backdrop.border_width=0; 14731 windows->backdrop.immutable=MagickTrue; 14732 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14733 ButtonReleaseMask; 14734 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14735 StructureNotifyMask; 14736 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14737 manager_hints->icon_window=windows->icon.id; 14738 manager_hints->input=MagickTrue; 14739 manager_hints->initial_state=resource_info->iconic ? IconicState : 14740 NormalState; 14741 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14742 &windows->backdrop); 14743 if (display_image->debug != MagickFalse) 14744 (void) LogMagickEvent(X11Event,GetMagickModule(), 14745 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14746 (void) XMapWindow(display,windows->backdrop.id); 14747 (void) XClearWindow(display,windows->backdrop.id); 14748 if (windows->image.id != (Window) NULL) 14749 { 14750 (void) XDestroyWindow(display,windows->image.id); 14751 windows->image.id=(Window) NULL; 14752 } 14753 /* 14754 Position image in the center the backdrop. 14755 */ 14756 windows->image.flags|=USPosition; 14757 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14758 (windows->image.width/2); 14759 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14760 (windows->image.height/2); 14761 } 14762 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14763 manager_hints->icon_window=windows->icon.id; 14764 manager_hints->input=MagickTrue; 14765 manager_hints->initial_state=resource_info->iconic ? IconicState : 14766 NormalState; 14767 if (windows->group_leader.id != (Window) NULL) 14768 { 14769 /* 14770 Follow the leader. 14771 */ 14772 manager_hints->flags|=WindowGroupHint; 14773 manager_hints->window_group=windows->group_leader.id; 14774 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14775 if (display_image->debug != MagickFalse) 14776 (void) LogMagickEvent(X11Event,GetMagickModule(), 14777 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14778 } 14779 XMakeWindow(display, 14780 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14781 argv,argc,class_hints,manager_hints,&windows->image); 14782 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14783 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14784 if (windows->group_leader.id != (Window) NULL) 14785 (void) XSetTransientForHint(display,windows->image.id, 14786 windows->group_leader.id); 14787 if (display_image->debug != MagickFalse) 14788 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14789 windows->image.id); 14790 /* 14791 Initialize Info widget. 14792 */ 14793 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14794 &windows->info); 14795 (void) CloneString(&windows->info.name,"Info"); 14796 (void) CloneString(&windows->info.icon_name,"Info"); 14797 windows->info.border_width=1; 14798 windows->info.x=2; 14799 windows->info.y=2; 14800 windows->info.flags|=PPosition; 14801 windows->info.attributes.win_gravity=UnmapGravity; 14802 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14803 StructureNotifyMask; 14804 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14805 manager_hints->input=MagickFalse; 14806 manager_hints->initial_state=NormalState; 14807 manager_hints->window_group=windows->image.id; 14808 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14809 &windows->info); 14810 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14811 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14812 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14813 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14814 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14815 if (windows->image.mapped != MagickFalse) 14816 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14817 if (display_image->debug != MagickFalse) 14818 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14819 windows->info.id); 14820 /* 14821 Initialize Command widget. 14822 */ 14823 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14824 resource_info,&windows->command); 14825 windows->command.data=MagickMenus; 14826 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14827 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14828 resource_info->client_name); 14829 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14830 resource_name,"geometry",(char *) NULL); 14831 (void) CloneString(&windows->command.name,MagickTitle); 14832 windows->command.border_width=0; 14833 windows->command.flags|=PPosition; 14834 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14835 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14836 OwnerGrabButtonMask | StructureNotifyMask; 14837 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14838 manager_hints->input=MagickTrue; 14839 manager_hints->initial_state=NormalState; 14840 manager_hints->window_group=windows->image.id; 14841 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14842 &windows->command); 14843 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14844 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14845 HighlightHeight); 14846 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14847 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14848 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14849 if (windows->command.mapped != MagickFalse) 14850 (void) XMapRaised(display,windows->command.id); 14851 if (display_image->debug != MagickFalse) 14852 (void) LogMagickEvent(X11Event,GetMagickModule(), 14853 "Window id: 0x%lx (command)",windows->command.id); 14854 /* 14855 Initialize Widget window. 14856 */ 14857 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14858 resource_info,&windows->widget); 14859 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14860 resource_info->client_name); 14861 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14862 resource_name,"geometry",(char *) NULL); 14863 windows->widget.border_width=0; 14864 windows->widget.flags|=PPosition; 14865 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14866 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14867 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14868 StructureNotifyMask; 14869 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14870 manager_hints->input=MagickTrue; 14871 manager_hints->initial_state=NormalState; 14872 manager_hints->window_group=windows->image.id; 14873 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14874 &windows->widget); 14875 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14876 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14877 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14878 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14879 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14880 if (display_image->debug != MagickFalse) 14881 (void) LogMagickEvent(X11Event,GetMagickModule(), 14882 "Window id: 0x%lx (widget)",windows->widget.id); 14883 /* 14884 Initialize popup window. 14885 */ 14886 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14887 resource_info,&windows->popup); 14888 windows->popup.border_width=0; 14889 windows->popup.flags|=PPosition; 14890 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14891 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14892 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14893 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14894 manager_hints->input=MagickTrue; 14895 manager_hints->initial_state=NormalState; 14896 manager_hints->window_group=windows->image.id; 14897 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14898 &windows->popup); 14899 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14900 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14901 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14902 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14903 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14904 if (display_image->debug != MagickFalse) 14905 (void) LogMagickEvent(X11Event,GetMagickModule(), 14906 "Window id: 0x%lx (pop up)",windows->popup.id); 14907 /* 14908 Initialize Magnify window and cursor. 14909 */ 14910 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14911 resource_info,&windows->magnify); 14912 if (resource_info->use_shared_memory == MagickFalse) 14913 windows->magnify.shared_memory=MagickFalse; 14914 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14915 resource_info->client_name); 14916 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14917 resource_name,"geometry",(char *) NULL); 14918 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14919 resource_info->magnify); 14920 if (windows->magnify.cursor != (Cursor) NULL) 14921 (void) XFreeCursor(display,windows->magnify.cursor); 14922 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14923 map_info->colormap,resource_info->background_color, 14924 resource_info->foreground_color); 14925 if (windows->magnify.cursor == (Cursor) NULL) 14926 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14927 display_image->filename); 14928 windows->magnify.width=MagnifySize; 14929 windows->magnify.height=MagnifySize; 14930 windows->magnify.flags|=PPosition; 14931 windows->magnify.min_width=MagnifySize; 14932 windows->magnify.min_height=MagnifySize; 14933 windows->magnify.width_inc=MagnifySize; 14934 windows->magnify.height_inc=MagnifySize; 14935 windows->magnify.data=resource_info->magnify; 14936 windows->magnify.attributes.cursor=windows->magnify.cursor; 14937 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14938 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14939 StructureNotifyMask; 14940 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14941 manager_hints->input=MagickTrue; 14942 manager_hints->initial_state=NormalState; 14943 manager_hints->window_group=windows->image.id; 14944 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14945 &windows->magnify); 14946 if (display_image->debug != MagickFalse) 14947 (void) LogMagickEvent(X11Event,GetMagickModule(), 14948 "Window id: 0x%lx (magnify)",windows->magnify.id); 14949 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14950 /* 14951 Initialize panning window. 14952 */ 14953 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14954 resource_info,&windows->pan); 14955 (void) CloneString(&windows->pan.name,"Pan Icon"); 14956 windows->pan.width=windows->icon.width; 14957 windows->pan.height=windows->icon.height; 14958 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14959 resource_info->client_name); 14960 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14961 resource_name,"geometry",(char *) NULL); 14962 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14963 &windows->pan.width,&windows->pan.height); 14964 windows->pan.flags|=PPosition; 14965 windows->pan.immutable=MagickTrue; 14966 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14967 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14968 StructureNotifyMask; 14969 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14970 manager_hints->input=MagickFalse; 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->pan); 14975 if (display_image->debug != MagickFalse) 14976 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 14977 windows->pan.id); 14978 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 14979 if (windows->info.mapped != MagickFalse) 14980 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14981 if ((windows->image.mapped == MagickFalse) || 14982 (windows->backdrop.id != (Window) NULL)) 14983 (void) XMapWindow(display,windows->image.id); 14984 /* 14985 Set our progress monitor and warning handlers. 14986 */ 14987 if (warning_handler == (WarningHandler) NULL) 14988 { 14989 warning_handler=resource_info->display_warnings ? 14990 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14991 warning_handler=resource_info->display_warnings ? 14992 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14993 } 14994 /* 14995 Initialize Image and Magnify X images. 14996 */ 14997 windows->image.x=0; 14998 windows->image.y=0; 14999 windows->magnify.shape=MagickFalse; 15000 width=(unsigned int) display_image->columns; 15001 height=(unsigned int) display_image->rows; 15002 if ((display_image->columns != width) || (display_image->rows != height)) 15003 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15004 display_image->filename); 15005 status=XMakeImage(display,resource_info,&windows->image,display_image, 15006 width,height,exception); 15007 if (status == MagickFalse) 15008 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15009 display_image->filename); 15010 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15011 windows->magnify.width,windows->magnify.height,exception); 15012 if (status == MagickFalse) 15013 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15014 display_image->filename); 15015 if (windows->magnify.mapped != MagickFalse) 15016 (void) XMapRaised(display,windows->magnify.id); 15017 if (windows->pan.mapped != MagickFalse) 15018 (void) XMapRaised(display,windows->pan.id); 15019 windows->image.window_changes.width=(int) display_image->columns; 15020 windows->image.window_changes.height=(int) display_image->rows; 15021 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15022 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15023 (void) XSync(display,MagickFalse); 15024 /* 15025 Respond to events. 15026 */ 15027 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15028 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15029 update_time=0; 15030 if (resource_info->update != MagickFalse) 15031 { 15032 MagickBooleanType 15033 status; 15034 15035 /* 15036 Determine when file data was last modified. 15037 */ 15038 status=GetPathAttributes(display_image->filename,&attributes); 15039 if (status != MagickFalse) 15040 update_time=attributes.st_mtime; 15041 } 15042 *state&=(~FormerImageState); 15043 *state&=(~MontageImageState); 15044 *state&=(~NextImageState); 15045 do 15046 { 15047 /* 15048 Handle a window event. 15049 */ 15050 if (windows->image.mapped != MagickFalse) 15051 if ((display_image->delay != 0) || (resource_info->update != 0)) 15052 { 15053 if (timer < time((time_t *) NULL)) 15054 { 15055 if (resource_info->update == MagickFalse) 15056 *state|=NextImageState | ExitState; 15057 else 15058 { 15059 MagickBooleanType 15060 status; 15061 15062 /* 15063 Determine if image file was modified. 15064 */ 15065 status=GetPathAttributes(display_image->filename,&attributes); 15066 if (status != MagickFalse) 15067 if (update_time != attributes.st_mtime) 15068 { 15069 /* 15070 Redisplay image. 15071 */ 15072 (void) FormatLocaleString( 15073 resource_info->image_info->filename,MaxTextExtent, 15074 "%s:%s",display_image->magick, 15075 display_image->filename); 15076 nexus=ReadImage(resource_info->image_info, 15077 &display_image->exception); 15078 if (nexus != (Image *) NULL) 15079 { 15080 nexus=DestroyImage(nexus); 15081 *state|=NextImageState | ExitState; 15082 } 15083 } 15084 delay=display_image->delay/MagickMax( 15085 display_image->ticks_per_second,1L); 15086 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15087 } 15088 } 15089 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15090 { 15091 /* 15092 Do not block if delay > 0. 15093 */ 15094 XDelay(display,SuspendTime << 2); 15095 continue; 15096 } 15097 } 15098 timestamp=time((time_t *) NULL); 15099 (void) XNextEvent(display,&event); 15100 if (windows->image.stasis == MagickFalse) 15101 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15102 MagickTrue : MagickFalse; 15103 if (windows->magnify.stasis == MagickFalse) 15104 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15105 MagickTrue : MagickFalse; 15106 if (event.xany.window == windows->command.id) 15107 { 15108 /* 15109 Select a command from the Command widget. 15110 */ 15111 id=XCommandWidget(display,windows,CommandMenu,&event); 15112 if (id < 0) 15113 continue; 15114 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15115 command_type=CommandMenus[id]; 15116 if (id < MagickMenus) 15117 { 15118 /* 15119 Select a command from a pop-up menu. 15120 */ 15121 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15122 command); 15123 if (entry < 0) 15124 continue; 15125 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15126 command_type=Commands[id][entry]; 15127 } 15128 if (command_type != NullCommand) 15129 nexus=XMagickCommand(display,resource_info,windows,command_type, 15130 &display_image,exception); 15131 continue; 15132 } 15133 switch (event.type) 15134 { 15135 case ButtonPress: 15136 { 15137 if (display_image->debug != MagickFalse) 15138 (void) LogMagickEvent(X11Event,GetMagickModule(), 15139 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15140 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15141 if ((event.xbutton.button == Button3) && 15142 (event.xbutton.state & Mod1Mask)) 15143 { 15144 /* 15145 Convert Alt-Button3 to Button2. 15146 */ 15147 event.xbutton.button=Button2; 15148 event.xbutton.state&=(~Mod1Mask); 15149 } 15150 if (event.xbutton.window == windows->backdrop.id) 15151 { 15152 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15153 event.xbutton.time); 15154 break; 15155 } 15156 if (event.xbutton.window == windows->image.id) 15157 { 15158 switch (event.xbutton.button) 15159 { 15160 case Button1: 15161 { 15162 if (resource_info->immutable) 15163 { 15164 /* 15165 Select a command from the Virtual menu. 15166 */ 15167 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15168 command); 15169 if (entry >= 0) 15170 nexus=XMagickCommand(display,resource_info,windows, 15171 VirtualCommands[entry],&display_image,exception); 15172 break; 15173 } 15174 /* 15175 Map/unmap Command widget. 15176 */ 15177 if (windows->command.mapped != MagickFalse) 15178 (void) XWithdrawWindow(display,windows->command.id, 15179 windows->command.screen); 15180 else 15181 { 15182 (void) XCommandWidget(display,windows,CommandMenu, 15183 (XEvent *) NULL); 15184 (void) XMapRaised(display,windows->command.id); 15185 } 15186 break; 15187 } 15188 case Button2: 15189 { 15190 /* 15191 User pressed the image magnify button. 15192 */ 15193 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15194 &display_image,exception); 15195 XMagnifyImage(display,windows,&event); 15196 break; 15197 } 15198 case Button3: 15199 { 15200 if (resource_info->immutable) 15201 { 15202 /* 15203 Select a command from the Virtual menu. 15204 */ 15205 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15206 command); 15207 if (entry >= 0) 15208 nexus=XMagickCommand(display,resource_info,windows, 15209 VirtualCommands[entry],&display_image,exception); 15210 break; 15211 } 15212 if (display_image->montage != (char *) NULL) 15213 { 15214 /* 15215 Open or delete a tile from a visual image directory. 15216 */ 15217 nexus=XTileImage(display,resource_info,windows, 15218 display_image,&event,exception); 15219 if (nexus != (Image *) NULL) 15220 *state|=MontageImageState | NextImageState | ExitState; 15221 vid_info.x=(short int) windows->image.x; 15222 vid_info.y=(short int) windows->image.y; 15223 break; 15224 } 15225 /* 15226 Select a command from the Short Cuts menu. 15227 */ 15228 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15229 command); 15230 if (entry >= 0) 15231 nexus=XMagickCommand(display,resource_info,windows, 15232 ShortCutsCommands[entry],&display_image,exception); 15233 break; 15234 } 15235 case Button4: 15236 { 15237 /* 15238 Wheel up. 15239 */ 15240 XTranslateImage(display,windows,*image,XK_Up); 15241 break; 15242 } 15243 case Button5: 15244 { 15245 /* 15246 Wheel down. 15247 */ 15248 XTranslateImage(display,windows,*image,XK_Down); 15249 break; 15250 } 15251 default: 15252 break; 15253 } 15254 break; 15255 } 15256 if (event.xbutton.window == windows->magnify.id) 15257 { 15258 int 15259 factor; 15260 15261 static const char 15262 *MagnifyMenu[] = 15263 { 15264 "2", 15265 "4", 15266 "5", 15267 "6", 15268 "7", 15269 "8", 15270 "9", 15271 "3", 15272 (char *) NULL, 15273 }; 15274 15275 static KeySym 15276 MagnifyCommands[] = 15277 { 15278 XK_2, 15279 XK_4, 15280 XK_5, 15281 XK_6, 15282 XK_7, 15283 XK_8, 15284 XK_9, 15285 XK_3 15286 }; 15287 15288 /* 15289 Select a magnify factor from the pop-up menu. 15290 */ 15291 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15292 if (factor >= 0) 15293 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15294 break; 15295 } 15296 if (event.xbutton.window == windows->pan.id) 15297 { 15298 switch (event.xbutton.button) 15299 { 15300 case Button4: 15301 { 15302 /* 15303 Wheel up. 15304 */ 15305 XTranslateImage(display,windows,*image,XK_Up); 15306 break; 15307 } 15308 case Button5: 15309 { 15310 /* 15311 Wheel down. 15312 */ 15313 XTranslateImage(display,windows,*image,XK_Down); 15314 break; 15315 } 15316 default: 15317 { 15318 XPanImage(display,windows,&event); 15319 break; 15320 } 15321 } 15322 break; 15323 } 15324 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15325 1L); 15326 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15327 break; 15328 } 15329 case ButtonRelease: 15330 { 15331 if (display_image->debug != MagickFalse) 15332 (void) LogMagickEvent(X11Event,GetMagickModule(), 15333 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15334 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15335 break; 15336 } 15337 case ClientMessage: 15338 { 15339 if (display_image->debug != MagickFalse) 15340 (void) LogMagickEvent(X11Event,GetMagickModule(), 15341 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15342 event.xclient.message_type,event.xclient.format,(unsigned long) 15343 event.xclient.data.l[0]); 15344 if (event.xclient.message_type == windows->im_protocols) 15345 { 15346 if (*event.xclient.data.l == (long) windows->im_update_widget) 15347 { 15348 (void) CloneString(&windows->command.name,MagickTitle); 15349 windows->command.data=MagickMenus; 15350 (void) XCommandWidget(display,windows,CommandMenu, 15351 (XEvent *) NULL); 15352 break; 15353 } 15354 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15355 { 15356 /* 15357 Update graphic context and window colormap. 15358 */ 15359 for (i=0; i < (int) number_windows; i++) 15360 { 15361 if (magick_windows[i]->id == windows->icon.id) 15362 continue; 15363 context_values.background=pixel->background_color.pixel; 15364 context_values.foreground=pixel->foreground_color.pixel; 15365 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15366 context_mask,&context_values); 15367 (void) XChangeGC(display,magick_windows[i]->widget_context, 15368 context_mask,&context_values); 15369 context_values.background=pixel->foreground_color.pixel; 15370 context_values.foreground=pixel->background_color.pixel; 15371 context_values.plane_mask=context_values.background ^ 15372 context_values.foreground; 15373 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15374 (size_t) (context_mask | GCPlaneMask), 15375 &context_values); 15376 magick_windows[i]->attributes.background_pixel= 15377 pixel->background_color.pixel; 15378 magick_windows[i]->attributes.border_pixel= 15379 pixel->border_color.pixel; 15380 magick_windows[i]->attributes.colormap=map_info->colormap; 15381 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15382 (unsigned long) magick_windows[i]->mask, 15383 &magick_windows[i]->attributes); 15384 } 15385 if (windows->pan.mapped != MagickFalse) 15386 { 15387 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15388 windows->pan.pixmap); 15389 (void) XClearWindow(display,windows->pan.id); 15390 XDrawPanRectangle(display,windows); 15391 } 15392 if (windows->backdrop.id != (Window) NULL) 15393 (void) XInstallColormap(display,map_info->colormap); 15394 break; 15395 } 15396 if (*event.xclient.data.l == (long) windows->im_former_image) 15397 { 15398 *state|=FormerImageState | ExitState; 15399 break; 15400 } 15401 if (*event.xclient.data.l == (long) windows->im_next_image) 15402 { 15403 *state|=NextImageState | ExitState; 15404 break; 15405 } 15406 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15407 { 15408 *state|=RetainColorsState; 15409 break; 15410 } 15411 if (*event.xclient.data.l == (long) windows->im_exit) 15412 { 15413 *state|=ExitState; 15414 break; 15415 } 15416 break; 15417 } 15418 if (event.xclient.message_type == windows->dnd_protocols) 15419 { 15420 Atom 15421 selection, 15422 type; 15423 15424 int 15425 format, 15426 status; 15427 15428 unsigned char 15429 *data; 15430 15431 unsigned long 15432 after, 15433 length; 15434 15435 /* 15436 Display image named by the Drag-and-Drop selection. 15437 */ 15438 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15439 break; 15440 selection=XInternAtom(display,"DndSelection",MagickFalse); 15441 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15442 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15443 &length,&after,&data); 15444 if ((status != Success) || (length == 0)) 15445 break; 15446 if (*event.xclient.data.l == 2) 15447 { 15448 /* 15449 Offix DND. 15450 */ 15451 (void) CopyMagickString(resource_info->image_info->filename, 15452 (char *) data,MaxTextExtent); 15453 } 15454 else 15455 { 15456 /* 15457 XDND. 15458 */ 15459 if (strncmp((char *) data, "file:", 5) != 0) 15460 { 15461 (void) XFree((void *) data); 15462 break; 15463 } 15464 (void) CopyMagickString(resource_info->image_info->filename, 15465 ((char *) data)+5,MaxTextExtent); 15466 } 15467 nexus=ReadImage(resource_info->image_info, 15468 &display_image->exception); 15469 CatchException(&display_image->exception); 15470 if (nexus != (Image *) NULL) 15471 *state|=NextImageState | ExitState; 15472 (void) XFree((void *) data); 15473 break; 15474 } 15475 /* 15476 If client window delete message, exit. 15477 */ 15478 if (event.xclient.message_type != windows->wm_protocols) 15479 break; 15480 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15481 break; 15482 (void) XWithdrawWindow(display,event.xclient.window, 15483 visual_info->screen); 15484 if (event.xclient.window == windows->image.id) 15485 { 15486 *state|=ExitState; 15487 break; 15488 } 15489 if (event.xclient.window == windows->pan.id) 15490 { 15491 /* 15492 Restore original image size when pan window is deleted. 15493 */ 15494 windows->image.window_changes.width=windows->image.ximage->width; 15495 windows->image.window_changes.height=windows->image.ximage->height; 15496 (void) XConfigureImage(display,resource_info,windows, 15497 display_image,exception); 15498 } 15499 break; 15500 } 15501 case ConfigureNotify: 15502 { 15503 if (display_image->debug != MagickFalse) 15504 (void) LogMagickEvent(X11Event,GetMagickModule(), 15505 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15506 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15507 event.xconfigure.y,event.xconfigure.send_event); 15508 if (event.xconfigure.window == windows->image.id) 15509 { 15510 /* 15511 Image window has a new configuration. 15512 */ 15513 if (event.xconfigure.send_event != 0) 15514 { 15515 XWindowChanges 15516 window_changes; 15517 15518 /* 15519 Position the transient windows relative of the Image window. 15520 */ 15521 if (windows->command.geometry == (char *) NULL) 15522 if (windows->command.mapped == MagickFalse) 15523 { 15524 windows->command.x=event.xconfigure.x- 15525 windows->command.width-25; 15526 windows->command.y=event.xconfigure.y; 15527 XConstrainWindowPosition(display,&windows->command); 15528 window_changes.x=windows->command.x; 15529 window_changes.y=windows->command.y; 15530 (void) XReconfigureWMWindow(display,windows->command.id, 15531 windows->command.screen,(unsigned int) (CWX | CWY), 15532 &window_changes); 15533 } 15534 if (windows->widget.geometry == (char *) NULL) 15535 if (windows->widget.mapped == MagickFalse) 15536 { 15537 windows->widget.x=event.xconfigure.x+ 15538 event.xconfigure.width/10; 15539 windows->widget.y=event.xconfigure.y+ 15540 event.xconfigure.height/10; 15541 XConstrainWindowPosition(display,&windows->widget); 15542 window_changes.x=windows->widget.x; 15543 window_changes.y=windows->widget.y; 15544 (void) XReconfigureWMWindow(display,windows->widget.id, 15545 windows->widget.screen,(unsigned int) (CWX | CWY), 15546 &window_changes); 15547 } 15548 if (windows->magnify.geometry == (char *) NULL) 15549 if (windows->magnify.mapped == MagickFalse) 15550 { 15551 windows->magnify.x=event.xconfigure.x+ 15552 event.xconfigure.width+25; 15553 windows->magnify.y=event.xconfigure.y; 15554 XConstrainWindowPosition(display,&windows->magnify); 15555 window_changes.x=windows->magnify.x; 15556 window_changes.y=windows->magnify.y; 15557 (void) XReconfigureWMWindow(display,windows->magnify.id, 15558 windows->magnify.screen,(unsigned int) (CWX | CWY), 15559 &window_changes); 15560 } 15561 if (windows->pan.geometry == (char *) NULL) 15562 if (windows->pan.mapped == MagickFalse) 15563 { 15564 windows->pan.x=event.xconfigure.x+ 15565 event.xconfigure.width+25; 15566 windows->pan.y=event.xconfigure.y+ 15567 windows->magnify.height+50; 15568 XConstrainWindowPosition(display,&windows->pan); 15569 window_changes.x=windows->pan.x; 15570 window_changes.y=windows->pan.y; 15571 (void) XReconfigureWMWindow(display,windows->pan.id, 15572 windows->pan.screen,(unsigned int) (CWX | CWY), 15573 &window_changes); 15574 } 15575 } 15576 if ((event.xconfigure.width == (int) windows->image.width) && 15577 (event.xconfigure.height == (int) windows->image.height)) 15578 break; 15579 windows->image.width=(unsigned int) event.xconfigure.width; 15580 windows->image.height=(unsigned int) event.xconfigure.height; 15581 windows->image.x=0; 15582 windows->image.y=0; 15583 if (display_image->montage != (char *) NULL) 15584 { 15585 windows->image.x=vid_info.x; 15586 windows->image.y=vid_info.y; 15587 } 15588 if ((windows->image.mapped != MagickFalse) && 15589 (windows->image.stasis != MagickFalse)) 15590 { 15591 /* 15592 Update image window configuration. 15593 */ 15594 windows->image.window_changes.width=event.xconfigure.width; 15595 windows->image.window_changes.height=event.xconfigure.height; 15596 (void) XConfigureImage(display,resource_info,windows, 15597 display_image,exception); 15598 } 15599 /* 15600 Update pan window configuration. 15601 */ 15602 if ((event.xconfigure.width < windows->image.ximage->width) || 15603 (event.xconfigure.height < windows->image.ximage->height)) 15604 { 15605 (void) XMapRaised(display,windows->pan.id); 15606 XDrawPanRectangle(display,windows); 15607 } 15608 else 15609 if (windows->pan.mapped != MagickFalse) 15610 (void) XWithdrawWindow(display,windows->pan.id, 15611 windows->pan.screen); 15612 break; 15613 } 15614 if (event.xconfigure.window == windows->magnify.id) 15615 { 15616 unsigned int 15617 magnify; 15618 15619 /* 15620 Magnify window has a new configuration. 15621 */ 15622 windows->magnify.width=(unsigned int) event.xconfigure.width; 15623 windows->magnify.height=(unsigned int) event.xconfigure.height; 15624 if (windows->magnify.mapped == MagickFalse) 15625 break; 15626 magnify=1; 15627 while ((int) magnify <= event.xconfigure.width) 15628 magnify<<=1; 15629 while ((int) magnify <= event.xconfigure.height) 15630 magnify<<=1; 15631 magnify>>=1; 15632 if (((int) magnify != event.xconfigure.width) || 15633 ((int) magnify != event.xconfigure.height)) 15634 { 15635 window_changes.width=(int) magnify; 15636 window_changes.height=(int) magnify; 15637 (void) XReconfigureWMWindow(display,windows->magnify.id, 15638 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15639 &window_changes); 15640 break; 15641 } 15642 if ((windows->magnify.mapped != MagickFalse) && 15643 (windows->magnify.stasis != MagickFalse)) 15644 { 15645 status=XMakeImage(display,resource_info,&windows->magnify, 15646 display_image,windows->magnify.width,windows->magnify.height, 15647 exception); 15648 XMakeMagnifyImage(display,windows); 15649 } 15650 break; 15651 } 15652 if ((windows->magnify.mapped != MagickFalse) && 15653 (event.xconfigure.window == windows->pan.id)) 15654 { 15655 /* 15656 Pan icon window has a new configuration. 15657 */ 15658 if (event.xconfigure.send_event != 0) 15659 { 15660 windows->pan.x=event.xconfigure.x; 15661 windows->pan.y=event.xconfigure.y; 15662 } 15663 windows->pan.width=(unsigned int) event.xconfigure.width; 15664 windows->pan.height=(unsigned int) event.xconfigure.height; 15665 break; 15666 } 15667 if (event.xconfigure.window == windows->icon.id) 15668 { 15669 /* 15670 Icon window has a new configuration. 15671 */ 15672 windows->icon.width=(unsigned int) event.xconfigure.width; 15673 windows->icon.height=(unsigned int) event.xconfigure.height; 15674 break; 15675 } 15676 break; 15677 } 15678 case DestroyNotify: 15679 { 15680 /* 15681 Group leader has exited. 15682 */ 15683 if (display_image->debug != MagickFalse) 15684 (void) LogMagickEvent(X11Event,GetMagickModule(), 15685 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15686 if (event.xdestroywindow.window == windows->group_leader.id) 15687 { 15688 *state|=ExitState; 15689 break; 15690 } 15691 break; 15692 } 15693 case EnterNotify: 15694 { 15695 /* 15696 Selectively install colormap. 15697 */ 15698 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15699 if (event.xcrossing.mode != NotifyUngrab) 15700 XInstallColormap(display,map_info->colormap); 15701 break; 15702 } 15703 case Expose: 15704 { 15705 if (display_image->debug != MagickFalse) 15706 (void) LogMagickEvent(X11Event,GetMagickModule(), 15707 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15708 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15709 event.xexpose.y); 15710 /* 15711 Refresh windows that are now exposed. 15712 */ 15713 if ((event.xexpose.window == windows->image.id) && 15714 (windows->image.mapped != MagickFalse)) 15715 { 15716 XRefreshWindow(display,&windows->image,&event); 15717 delay=display_image->delay/MagickMax( 15718 display_image->ticks_per_second,1L); 15719 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15720 break; 15721 } 15722 if ((event.xexpose.window == windows->magnify.id) && 15723 (windows->magnify.mapped != MagickFalse)) 15724 { 15725 XMakeMagnifyImage(display,windows); 15726 break; 15727 } 15728 if (event.xexpose.window == windows->pan.id) 15729 { 15730 XDrawPanRectangle(display,windows); 15731 break; 15732 } 15733 if (event.xexpose.window == windows->icon.id) 15734 { 15735 XRefreshWindow(display,&windows->icon,&event); 15736 break; 15737 } 15738 break; 15739 } 15740 case KeyPress: 15741 { 15742 int 15743 length; 15744 15745 /* 15746 Respond to a user key press. 15747 */ 15748 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15749 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15750 *(command+length)='\0'; 15751 if (display_image->debug != MagickFalse) 15752 (void) LogMagickEvent(X11Event,GetMagickModule(), 15753 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15754 key_symbol,command); 15755 if (event.xkey.window == windows->image.id) 15756 { 15757 command_type=XImageWindowCommand(display,resource_info,windows, 15758 event.xkey.state,key_symbol,&display_image,exception); 15759 if (command_type != NullCommand) 15760 nexus=XMagickCommand(display,resource_info,windows,command_type, 15761 &display_image,exception); 15762 } 15763 if (event.xkey.window == windows->magnify.id) 15764 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15765 if (event.xkey.window == windows->pan.id) 15766 { 15767 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15768 (void) XWithdrawWindow(display,windows->pan.id, 15769 windows->pan.screen); 15770 else 15771 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15772 XTextViewWidget(display,resource_info,windows,MagickFalse, 15773 "Help Viewer - Image Pan",ImagePanHelp); 15774 else 15775 XTranslateImage(display,windows,*image,key_symbol); 15776 } 15777 delay=display_image->delay/MagickMax( 15778 display_image->ticks_per_second,1L); 15779 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15780 break; 15781 } 15782 case KeyRelease: 15783 { 15784 /* 15785 Respond to a user key release. 15786 */ 15787 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15788 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15789 if (display_image->debug != MagickFalse) 15790 (void) LogMagickEvent(X11Event,GetMagickModule(), 15791 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15792 break; 15793 } 15794 case LeaveNotify: 15795 { 15796 /* 15797 Selectively uninstall colormap. 15798 */ 15799 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15800 if (event.xcrossing.mode != NotifyUngrab) 15801 XUninstallColormap(display,map_info->colormap); 15802 break; 15803 } 15804 case MapNotify: 15805 { 15806 if (display_image->debug != MagickFalse) 15807 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15808 event.xmap.window); 15809 if (event.xmap.window == windows->backdrop.id) 15810 { 15811 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15812 CurrentTime); 15813 windows->backdrop.mapped=MagickTrue; 15814 break; 15815 } 15816 if (event.xmap.window == windows->image.id) 15817 { 15818 if (windows->backdrop.id != (Window) NULL) 15819 (void) XInstallColormap(display,map_info->colormap); 15820 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15821 { 15822 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15823 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15824 } 15825 if (((int) windows->image.width < windows->image.ximage->width) || 15826 ((int) windows->image.height < windows->image.ximage->height)) 15827 (void) XMapRaised(display,windows->pan.id); 15828 windows->image.mapped=MagickTrue; 15829 break; 15830 } 15831 if (event.xmap.window == windows->magnify.id) 15832 { 15833 XMakeMagnifyImage(display,windows); 15834 windows->magnify.mapped=MagickTrue; 15835 (void) XWithdrawWindow(display,windows->info.id, 15836 windows->info.screen); 15837 break; 15838 } 15839 if (event.xmap.window == windows->pan.id) 15840 { 15841 XMakePanImage(display,resource_info,windows,display_image, 15842 exception); 15843 windows->pan.mapped=MagickTrue; 15844 break; 15845 } 15846 if (event.xmap.window == windows->info.id) 15847 { 15848 windows->info.mapped=MagickTrue; 15849 break; 15850 } 15851 if (event.xmap.window == windows->icon.id) 15852 { 15853 MagickBooleanType 15854 taint; 15855 15856 /* 15857 Create an icon image. 15858 */ 15859 taint=display_image->taint; 15860 XMakeStandardColormap(display,icon_visual,icon_resources, 15861 display_image,icon_map,icon_pixel); 15862 (void) XMakeImage(display,icon_resources,&windows->icon, 15863 display_image,windows->icon.width,windows->icon.height, 15864 exception); 15865 display_image->taint=taint; 15866 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15867 windows->icon.pixmap); 15868 (void) XClearWindow(display,windows->icon.id); 15869 (void) XWithdrawWindow(display,windows->info.id, 15870 windows->info.screen); 15871 windows->icon.mapped=MagickTrue; 15872 break; 15873 } 15874 if (event.xmap.window == windows->command.id) 15875 { 15876 windows->command.mapped=MagickTrue; 15877 break; 15878 } 15879 if (event.xmap.window == windows->popup.id) 15880 { 15881 windows->popup.mapped=MagickTrue; 15882 break; 15883 } 15884 if (event.xmap.window == windows->widget.id) 15885 { 15886 windows->widget.mapped=MagickTrue; 15887 break; 15888 } 15889 break; 15890 } 15891 case MappingNotify: 15892 { 15893 (void) XRefreshKeyboardMapping(&event.xmapping); 15894 break; 15895 } 15896 case NoExpose: 15897 break; 15898 case PropertyNotify: 15899 { 15900 Atom 15901 type; 15902 15903 int 15904 format, 15905 status; 15906 15907 unsigned char 15908 *data; 15909 15910 unsigned long 15911 after, 15912 length; 15913 15914 if (display_image->debug != MagickFalse) 15915 (void) LogMagickEvent(X11Event,GetMagickModule(), 15916 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15917 event.xproperty.atom,event.xproperty.state); 15918 if (event.xproperty.atom != windows->im_remote_command) 15919 break; 15920 /* 15921 Display image named by the remote command protocol. 15922 */ 15923 status=XGetWindowProperty(display,event.xproperty.window, 15924 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15925 AnyPropertyType,&type,&format,&length,&after,&data); 15926 if ((status != Success) || (length == 0)) 15927 break; 15928 if (LocaleCompare((char *) data,"-quit") == 0) 15929 { 15930 XClientMessage(display,windows->image.id,windows->im_protocols, 15931 windows->im_exit,CurrentTime); 15932 (void) XFree((void *) data); 15933 break; 15934 } 15935 (void) CopyMagickString(resource_info->image_info->filename, 15936 (char *) data,MaxTextExtent); 15937 (void) XFree((void *) data); 15938 nexus=ReadImage(resource_info->image_info,&display_image->exception); 15939 CatchException(&display_image->exception); 15940 if (nexus != (Image *) NULL) 15941 *state|=NextImageState | ExitState; 15942 break; 15943 } 15944 case ReparentNotify: 15945 { 15946 if (display_image->debug != MagickFalse) 15947 (void) LogMagickEvent(X11Event,GetMagickModule(), 15948 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15949 event.xreparent.window); 15950 break; 15951 } 15952 case UnmapNotify: 15953 { 15954 if (display_image->debug != MagickFalse) 15955 (void) LogMagickEvent(X11Event,GetMagickModule(), 15956 "Unmap Notify: 0x%lx",event.xunmap.window); 15957 if (event.xunmap.window == windows->backdrop.id) 15958 { 15959 windows->backdrop.mapped=MagickFalse; 15960 break; 15961 } 15962 if (event.xunmap.window == windows->image.id) 15963 { 15964 windows->image.mapped=MagickFalse; 15965 break; 15966 } 15967 if (event.xunmap.window == windows->magnify.id) 15968 { 15969 windows->magnify.mapped=MagickFalse; 15970 break; 15971 } 15972 if (event.xunmap.window == windows->pan.id) 15973 { 15974 windows->pan.mapped=MagickFalse; 15975 break; 15976 } 15977 if (event.xunmap.window == windows->info.id) 15978 { 15979 windows->info.mapped=MagickFalse; 15980 break; 15981 } 15982 if (event.xunmap.window == windows->icon.id) 15983 { 15984 if (map_info->colormap == icon_map->colormap) 15985 XConfigureImageColormap(display,resource_info,windows, 15986 display_image); 15987 (void) XFreeStandardColormap(display,icon_visual,icon_map, 15988 icon_pixel); 15989 windows->icon.mapped=MagickFalse; 15990 break; 15991 } 15992 if (event.xunmap.window == windows->command.id) 15993 { 15994 windows->command.mapped=MagickFalse; 15995 break; 15996 } 15997 if (event.xunmap.window == windows->popup.id) 15998 { 15999 if (windows->backdrop.id != (Window) NULL) 16000 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16001 CurrentTime); 16002 windows->popup.mapped=MagickFalse; 16003 break; 16004 } 16005 if (event.xunmap.window == windows->widget.id) 16006 { 16007 if (windows->backdrop.id != (Window) NULL) 16008 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16009 CurrentTime); 16010 windows->widget.mapped=MagickFalse; 16011 break; 16012 } 16013 break; 16014 } 16015 default: 16016 { 16017 if (display_image->debug != MagickFalse) 16018 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16019 event.type); 16020 break; 16021 } 16022 } 16023 } while (!(*state & ExitState)); 16024 if ((*state & ExitState) == 0) 16025 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16026 &display_image,exception); 16027 else 16028 if (resource_info->confirm_edit != MagickFalse) 16029 { 16030 /* 16031 Query user if image has changed. 16032 */ 16033 if ((resource_info->immutable == MagickFalse) && 16034 (display_image->taint != MagickFalse)) 16035 { 16036 int 16037 status; 16038 16039 status=XConfirmWidget(display,windows,"Your image changed.", 16040 "Do you want to save it"); 16041 if (status == 0) 16042 *state&=(~ExitState); 16043 else 16044 if (status > 0) 16045 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16046 &display_image,exception); 16047 } 16048 } 16049 if ((windows->visual_info->klass == GrayScale) || 16050 (windows->visual_info->klass == PseudoColor) || 16051 (windows->visual_info->klass == DirectColor)) 16052 { 16053 /* 16054 Withdraw pan and Magnify window. 16055 */ 16056 if (windows->info.mapped != MagickFalse) 16057 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16058 if (windows->magnify.mapped != MagickFalse) 16059 (void) XWithdrawWindow(display,windows->magnify.id, 16060 windows->magnify.screen); 16061 if (windows->command.mapped != MagickFalse) 16062 (void) XWithdrawWindow(display,windows->command.id, 16063 windows->command.screen); 16064 } 16065 if (windows->pan.mapped != MagickFalse) 16066 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16067 if (resource_info->backdrop == MagickFalse) 16068 if (windows->backdrop.mapped) 16069 { 16070 (void) XWithdrawWindow(display,windows->backdrop.id, 16071 windows->backdrop.screen); 16072 (void) XDestroyWindow(display,windows->backdrop.id); 16073 windows->backdrop.id=(Window) NULL; 16074 (void) XWithdrawWindow(display,windows->image.id, 16075 windows->image.screen); 16076 (void) XDestroyWindow(display,windows->image.id); 16077 windows->image.id=(Window) NULL; 16078 } 16079 XSetCursorState(display,windows,MagickTrue); 16080 XCheckRefreshWindows(display,windows); 16081 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16082 *state&=(~ExitState); 16083 if (*state & ExitState) 16084 { 16085 /* 16086 Free Standard Colormap. 16087 */ 16088 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16089 if (resource_info->map_type == (char *) NULL) 16090 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16091 /* 16092 Free X resources. 16093 */ 16094 if (resource_info->copy_image != (Image *) NULL) 16095 { 16096 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16097 resource_info->copy_image=NewImageList(); 16098 } 16099 DestroyXResources(); 16100 } 16101 (void) XSync(display,MagickFalse); 16102 /* 16103 Restore our progress monitor and warning handlers. 16104 */ 16105 (void) SetErrorHandler(warning_handler); 16106 (void) SetWarningHandler(warning_handler); 16107 /* 16108 Change to home directory. 16109 */ 16110 directory=getcwd(working_directory,MaxTextExtent); 16111 (void) directory; 16112 { 16113 int 16114 status; 16115 16116 status=chdir(resource_info->home_directory); 16117 if (status == -1) 16118 (void) ThrowMagickException(&display_image->exception,GetMagickModule(), 16119 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 16120 } 16121 *image=display_image; 16122 return(nexus); 16123} 16124#else 16125 16126/* 16127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16128% % 16129% % 16130% % 16131+ D i s p l a y I m a g e s % 16132% % 16133% % 16134% % 16135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16136% 16137% DisplayImages() displays an image sequence to any X window screen. It 16138% returns a value other than 0 if successful. Check the exception member 16139% of image to determine the reason for any failure. 16140% 16141% The format of the DisplayImages method is: 16142% 16143% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16144% Image *images,ExceptionInfo *exception) 16145% 16146% A description of each parameter follows: 16147% 16148% o image_info: the image info. 16149% 16150% o image: the image. 16151% 16152% o exception: return any errors or warnings in this structure. 16153% 16154*/ 16155MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16156 Image *image,ExceptionInfo *exception) 16157{ 16158 assert(image_info != (const ImageInfo *) NULL); 16159 assert(image_info->signature == MagickSignature); 16160 assert(image != (Image *) NULL); 16161 assert(image->signature == MagickSignature); 16162 if (image->debug != MagickFalse) 16163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16164 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16165 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16166 return(MagickFalse); 16167} 16168 16169/* 16170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16171% % 16172% % 16173% % 16174+ R e m o t e D i s p l a y C o m m a n d % 16175% % 16176% % 16177% % 16178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16179% 16180% RemoteDisplayCommand() encourages a remote display program to display the 16181% specified image filename. 16182% 16183% The format of the RemoteDisplayCommand method is: 16184% 16185% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16186% const char *window,const char *filename,ExceptionInfo *exception) 16187% 16188% A description of each parameter follows: 16189% 16190% o image_info: the image info. 16191% 16192% o window: Specifies the name or id of an X window. 16193% 16194% o filename: the name of the image filename to display. 16195% 16196% o exception: return any errors or warnings in this structure. 16197% 16198*/ 16199MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16200 const char *window,const char *filename,ExceptionInfo *exception) 16201{ 16202 assert(image_info != (const ImageInfo *) NULL); 16203 assert(image_info->signature == MagickSignature); 16204 assert(filename != (char *) NULL); 16205 (void) window; 16206 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16207 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16208 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16209 return(MagickFalse); 16210} 16211#endif 16212