display.c revision 05c0c9ada50c0973e9449f1f1c3ea3717d248eb5
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 XNoticeWidget(display,windows,"Unable to write X image:", 7213 (*image)->filename); 7214 break; 7215 } 7216 break; 7217 } 7218 case PrintCommand: 7219 { 7220 /* 7221 Print image. 7222 */ 7223 status=XPrintImage(display,resource_info,windows,*image,exception); 7224 if (status == MagickFalse) 7225 { 7226 XNoticeWidget(display,windows,"Unable to print X image:", 7227 (*image)->filename); 7228 break; 7229 } 7230 break; 7231 } 7232 case DeleteCommand: 7233 { 7234 static char 7235 filename[MaxTextExtent] = "\0"; 7236 7237 /* 7238 Delete image file. 7239 */ 7240 XFileBrowserWidget(display,windows,"Delete",filename); 7241 if (*filename == '\0') 7242 break; 7243 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 7244 if (status != MagickFalse) 7245 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7246 break; 7247 } 7248 case NewCommand: 7249 { 7250 int 7251 status; 7252 7253 static char 7254 color[MaxTextExtent] = "gray", 7255 geometry[MaxTextExtent] = "640x480"; 7256 7257 static const char 7258 *format = "gradient"; 7259 7260 /* 7261 Query user for canvas geometry. 7262 */ 7263 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7264 geometry); 7265 if (*geometry == '\0') 7266 break; 7267 if (status == 0) 7268 format="xc"; 7269 XColorBrowserWidget(display,windows,"Select",color); 7270 if (*color == '\0') 7271 break; 7272 /* 7273 Create canvas. 7274 */ 7275 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7276 "%s:%s",format,color); 7277 (void) CloneString(&image_info->size,geometry); 7278 nexus=ReadImage(image_info,exception); 7279 CatchException(exception); 7280 XClientMessage(display,windows->image.id,windows->im_protocols, 7281 windows->im_next_image,CurrentTime); 7282 break; 7283 } 7284 case VisualDirectoryCommand: 7285 { 7286 /* 7287 Visual Image directory. 7288 */ 7289 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7290 break; 7291 } 7292 case QuitCommand: 7293 { 7294 /* 7295 exit program. 7296 */ 7297 if (resource_info->confirm_exit == MagickFalse) 7298 XClientMessage(display,windows->image.id,windows->im_protocols, 7299 windows->im_exit,CurrentTime); 7300 else 7301 { 7302 int 7303 status; 7304 7305 /* 7306 Confirm program exit. 7307 */ 7308 status=XConfirmWidget(display,windows,"Do you really want to exit", 7309 resource_info->client_name); 7310 if (status > 0) 7311 XClientMessage(display,windows->image.id,windows->im_protocols, 7312 windows->im_exit,CurrentTime); 7313 } 7314 break; 7315 } 7316 case CutCommand: 7317 { 7318 /* 7319 Cut image. 7320 */ 7321 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7322 break; 7323 } 7324 case CopyCommand: 7325 { 7326 /* 7327 Copy image. 7328 */ 7329 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7330 exception); 7331 break; 7332 } 7333 case PasteCommand: 7334 { 7335 /* 7336 Paste image. 7337 */ 7338 status=XPasteImage(display,resource_info,windows,*image,exception); 7339 if (status == MagickFalse) 7340 { 7341 XNoticeWidget(display,windows,"Unable to paste X image", 7342 (*image)->filename); 7343 break; 7344 } 7345 break; 7346 } 7347 case HalfSizeCommand: 7348 { 7349 /* 7350 Half image size. 7351 */ 7352 windows->image.window_changes.width=windows->image.ximage->width/2; 7353 windows->image.window_changes.height=windows->image.ximage->height/2; 7354 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7355 break; 7356 } 7357 case OriginalSizeCommand: 7358 { 7359 /* 7360 Original image size. 7361 */ 7362 windows->image.window_changes.width=(int) (*image)->columns; 7363 windows->image.window_changes.height=(int) (*image)->rows; 7364 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7365 break; 7366 } 7367 case DoubleSizeCommand: 7368 { 7369 /* 7370 Double the image size. 7371 */ 7372 windows->image.window_changes.width=windows->image.ximage->width << 1; 7373 windows->image.window_changes.height=windows->image.ximage->height << 1; 7374 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7375 break; 7376 } 7377 case ResizeCommand: 7378 { 7379 int 7380 status; 7381 7382 size_t 7383 height, 7384 width; 7385 7386 ssize_t 7387 x, 7388 y; 7389 7390 /* 7391 Resize image. 7392 */ 7393 width=(size_t) windows->image.ximage->width; 7394 height=(size_t) windows->image.ximage->height; 7395 x=0; 7396 y=0; 7397 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7398 (double) width,(double) height); 7399 status=XDialogWidget(display,windows,"Resize", 7400 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7401 if (*geometry == '\0') 7402 break; 7403 if (status == 0) 7404 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7405 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7406 windows->image.window_changes.width=(int) width; 7407 windows->image.window_changes.height=(int) height; 7408 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7409 break; 7410 } 7411 case ApplyCommand: 7412 { 7413 char 7414 image_geometry[MaxTextExtent]; 7415 7416 if ((windows->image.crop_geometry == (char *) NULL) && 7417 ((int) (*image)->columns == windows->image.ximage->width) && 7418 ((int) (*image)->rows == windows->image.ximage->height)) 7419 break; 7420 /* 7421 Apply size transforms to image. 7422 */ 7423 XSetCursorState(display,windows,MagickTrue); 7424 XCheckRefreshWindows(display,windows); 7425 /* 7426 Crop and/or scale displayed image. 7427 */ 7428 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7429 windows->image.ximage->width,windows->image.ximage->height); 7430 (void) TransformImage(image,windows->image.crop_geometry,image_geometry); 7431 if (windows->image.crop_geometry != (char *) NULL) 7432 windows->image.crop_geometry=(char *) 7433 RelinquishMagickMemory(windows->image.crop_geometry); 7434 windows->image.x=0; 7435 windows->image.y=0; 7436 XConfigureImageColormap(display,resource_info,windows,*image); 7437 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7438 break; 7439 } 7440 case RefreshCommand: 7441 { 7442 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7443 break; 7444 } 7445 case RestoreCommand: 7446 { 7447 /* 7448 Restore Image window to its original size. 7449 */ 7450 if ((windows->image.width == (unsigned int) (*image)->columns) && 7451 (windows->image.height == (unsigned int) (*image)->rows) && 7452 (windows->image.crop_geometry == (char *) NULL)) 7453 { 7454 (void) XBell(display,0); 7455 break; 7456 } 7457 windows->image.window_changes.width=(int) (*image)->columns; 7458 windows->image.window_changes.height=(int) (*image)->rows; 7459 if (windows->image.crop_geometry != (char *) NULL) 7460 { 7461 windows->image.crop_geometry=(char *) 7462 RelinquishMagickMemory(windows->image.crop_geometry); 7463 windows->image.crop_geometry=(char *) NULL; 7464 windows->image.x=0; 7465 windows->image.y=0; 7466 } 7467 XConfigureImageColormap(display,resource_info,windows,*image); 7468 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7469 break; 7470 } 7471 case CropCommand: 7472 { 7473 /* 7474 Crop image. 7475 */ 7476 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7477 exception); 7478 break; 7479 } 7480 case ChopCommand: 7481 { 7482 /* 7483 Chop image. 7484 */ 7485 status=XChopImage(display,resource_info,windows,image,exception); 7486 if (status == MagickFalse) 7487 { 7488 XNoticeWidget(display,windows,"Unable to cut X image", 7489 (*image)->filename); 7490 break; 7491 } 7492 break; 7493 } 7494 case FlopCommand: 7495 { 7496 Image 7497 *flop_image; 7498 7499 /* 7500 Flop image scanlines. 7501 */ 7502 XSetCursorState(display,windows,MagickTrue); 7503 XCheckRefreshWindows(display,windows); 7504 flop_image=FlopImage(*image,exception); 7505 if (flop_image != (Image *) NULL) 7506 { 7507 *image=DestroyImage(*image); 7508 *image=flop_image; 7509 } 7510 CatchException(exception); 7511 XSetCursorState(display,windows,MagickFalse); 7512 if (windows->image.crop_geometry != (char *) NULL) 7513 { 7514 /* 7515 Flop crop geometry. 7516 */ 7517 width=(unsigned int) (*image)->columns; 7518 height=(unsigned int) (*image)->rows; 7519 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7520 &width,&height); 7521 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7522 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7523 } 7524 if (windows->image.orphan != MagickFalse) 7525 break; 7526 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7527 break; 7528 } 7529 case FlipCommand: 7530 { 7531 Image 7532 *flip_image; 7533 7534 /* 7535 Flip image scanlines. 7536 */ 7537 XSetCursorState(display,windows,MagickTrue); 7538 XCheckRefreshWindows(display,windows); 7539 flip_image=FlipImage(*image,exception); 7540 if (flip_image != (Image *) NULL) 7541 { 7542 *image=DestroyImage(*image); 7543 *image=flip_image; 7544 } 7545 CatchException(exception); 7546 XSetCursorState(display,windows,MagickFalse); 7547 if (windows->image.crop_geometry != (char *) NULL) 7548 { 7549 /* 7550 Flip crop geometry. 7551 */ 7552 width=(unsigned int) (*image)->columns; 7553 height=(unsigned int) (*image)->rows; 7554 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7555 &width,&height); 7556 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7557 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7558 } 7559 if (windows->image.orphan != MagickFalse) 7560 break; 7561 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7562 break; 7563 } 7564 case RotateRightCommand: 7565 { 7566 /* 7567 Rotate image 90 degrees clockwise. 7568 */ 7569 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7570 if (status == MagickFalse) 7571 { 7572 XNoticeWidget(display,windows,"Unable to rotate X image", 7573 (*image)->filename); 7574 break; 7575 } 7576 break; 7577 } 7578 case RotateLeftCommand: 7579 { 7580 /* 7581 Rotate image 90 degrees counter-clockwise. 7582 */ 7583 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7584 if (status == MagickFalse) 7585 { 7586 XNoticeWidget(display,windows,"Unable to rotate X image", 7587 (*image)->filename); 7588 break; 7589 } 7590 break; 7591 } 7592 case RotateCommand: 7593 { 7594 /* 7595 Rotate image. 7596 */ 7597 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7598 if (status == MagickFalse) 7599 { 7600 XNoticeWidget(display,windows,"Unable to rotate X image", 7601 (*image)->filename); 7602 break; 7603 } 7604 break; 7605 } 7606 case ShearCommand: 7607 { 7608 Image 7609 *shear_image; 7610 7611 static char 7612 geometry[MaxTextExtent] = "45.0x45.0"; 7613 7614 /* 7615 Query user for shear color and geometry. 7616 */ 7617 XColorBrowserWidget(display,windows,"Select",color); 7618 if (*color == '\0') 7619 break; 7620 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7621 geometry); 7622 if (*geometry == '\0') 7623 break; 7624 /* 7625 Shear image. 7626 */ 7627 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7628 exception); 7629 XSetCursorState(display,windows,MagickTrue); 7630 XCheckRefreshWindows(display,windows); 7631 (void) QueryColorDatabase(color,&(*image)->background_color, 7632 exception); 7633 flags=ParseGeometry(geometry,&geometry_info); 7634 if ((flags & SigmaValue) == 0) 7635 geometry_info.sigma=geometry_info.rho; 7636 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7637 exception); 7638 if (shear_image != (Image *) NULL) 7639 { 7640 *image=DestroyImage(*image); 7641 *image=shear_image; 7642 } 7643 CatchException(exception); 7644 XSetCursorState(display,windows,MagickFalse); 7645 if (windows->image.orphan != MagickFalse) 7646 break; 7647 windows->image.window_changes.width=(int) (*image)->columns; 7648 windows->image.window_changes.height=(int) (*image)->rows; 7649 XConfigureImageColormap(display,resource_info,windows,*image); 7650 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7651 break; 7652 } 7653 case RollCommand: 7654 { 7655 Image 7656 *roll_image; 7657 7658 static char 7659 geometry[MaxTextExtent] = "+2+2"; 7660 7661 /* 7662 Query user for the roll geometry. 7663 */ 7664 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7665 geometry); 7666 if (*geometry == '\0') 7667 break; 7668 /* 7669 Roll image. 7670 */ 7671 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7672 exception); 7673 XSetCursorState(display,windows,MagickTrue); 7674 XCheckRefreshWindows(display,windows); 7675 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7676 exception); 7677 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7678 exception); 7679 if (roll_image != (Image *) NULL) 7680 { 7681 *image=DestroyImage(*image); 7682 *image=roll_image; 7683 } 7684 CatchException(exception); 7685 XSetCursorState(display,windows,MagickFalse); 7686 if (windows->image.orphan != MagickFalse) 7687 break; 7688 windows->image.window_changes.width=(int) (*image)->columns; 7689 windows->image.window_changes.height=(int) (*image)->rows; 7690 XConfigureImageColormap(display,resource_info,windows,*image); 7691 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7692 break; 7693 } 7694 case TrimCommand: 7695 { 7696 static char 7697 fuzz[MaxTextExtent]; 7698 7699 /* 7700 Query user for the fuzz factor. 7701 */ 7702 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7703 (*image)->fuzz/(QuantumRange+1.0)); 7704 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7705 if (*fuzz == '\0') 7706 break; 7707 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7708 /* 7709 Trim image. 7710 */ 7711 status=XTrimImage(display,resource_info,windows,*image,exception); 7712 if (status == MagickFalse) 7713 { 7714 XNoticeWidget(display,windows,"Unable to trim X image", 7715 (*image)->filename); 7716 break; 7717 } 7718 break; 7719 } 7720 case HueCommand: 7721 { 7722 static char 7723 hue_percent[MaxTextExtent] = "110"; 7724 7725 /* 7726 Query user for percent hue change. 7727 */ 7728 (void) XDialogWidget(display,windows,"Apply", 7729 "Enter percent change in image hue (0-200):",hue_percent); 7730 if (*hue_percent == '\0') 7731 break; 7732 /* 7733 Vary the image hue. 7734 */ 7735 XSetCursorState(display,windows,MagickTrue); 7736 XCheckRefreshWindows(display,windows); 7737 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7738 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7739 MaxTextExtent); 7740 (void) ModulateImage(*image,modulate_factors,exception); 7741 XSetCursorState(display,windows,MagickFalse); 7742 if (windows->image.orphan != MagickFalse) 7743 break; 7744 XConfigureImageColormap(display,resource_info,windows,*image); 7745 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7746 break; 7747 } 7748 case SaturationCommand: 7749 { 7750 static char 7751 saturation_percent[MaxTextExtent] = "110"; 7752 7753 /* 7754 Query user for percent saturation change. 7755 */ 7756 (void) XDialogWidget(display,windows,"Apply", 7757 "Enter percent change in color saturation (0-200):",saturation_percent); 7758 if (*saturation_percent == '\0') 7759 break; 7760 /* 7761 Vary color saturation. 7762 */ 7763 XSetCursorState(display,windows,MagickTrue); 7764 XCheckRefreshWindows(display,windows); 7765 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7766 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7767 MaxTextExtent); 7768 (void) ModulateImage(*image,modulate_factors,exception); 7769 XSetCursorState(display,windows,MagickFalse); 7770 if (windows->image.orphan != MagickFalse) 7771 break; 7772 XConfigureImageColormap(display,resource_info,windows,*image); 7773 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7774 break; 7775 } 7776 case BrightnessCommand: 7777 { 7778 static char 7779 brightness_percent[MaxTextExtent] = "110"; 7780 7781 /* 7782 Query user for percent brightness change. 7783 */ 7784 (void) XDialogWidget(display,windows,"Apply", 7785 "Enter percent change in color brightness (0-200):",brightness_percent); 7786 if (*brightness_percent == '\0') 7787 break; 7788 /* 7789 Vary the color brightness. 7790 */ 7791 XSetCursorState(display,windows,MagickTrue); 7792 XCheckRefreshWindows(display,windows); 7793 (void) CopyMagickString(modulate_factors,brightness_percent, 7794 MaxTextExtent); 7795 (void) ModulateImage(*image,modulate_factors,exception); 7796 XSetCursorState(display,windows,MagickFalse); 7797 if (windows->image.orphan != MagickFalse) 7798 break; 7799 XConfigureImageColormap(display,resource_info,windows,*image); 7800 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7801 break; 7802 } 7803 case GammaCommand: 7804 { 7805 static char 7806 factor[MaxTextExtent] = "1.6"; 7807 7808 /* 7809 Query user for gamma value. 7810 */ 7811 (void) XDialogWidget(display,windows,"Gamma", 7812 "Enter gamma value (e.g. 1.2):",factor); 7813 if (*factor == '\0') 7814 break; 7815 /* 7816 Gamma correct image. 7817 */ 7818 XSetCursorState(display,windows,MagickTrue); 7819 XCheckRefreshWindows(display,windows); 7820 (void) GammaImage(*image,atof(factor),exception); 7821 XSetCursorState(display,windows,MagickFalse); 7822 if (windows->image.orphan != MagickFalse) 7823 break; 7824 XConfigureImageColormap(display,resource_info,windows,*image); 7825 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7826 break; 7827 } 7828 case SpiffCommand: 7829 { 7830 /* 7831 Sharpen the image contrast. 7832 */ 7833 XSetCursorState(display,windows,MagickTrue); 7834 XCheckRefreshWindows(display,windows); 7835 (void) ContrastImage(*image,MagickTrue,exception); 7836 XSetCursorState(display,windows,MagickFalse); 7837 if (windows->image.orphan != MagickFalse) 7838 break; 7839 XConfigureImageColormap(display,resource_info,windows,*image); 7840 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7841 break; 7842 } 7843 case DullCommand: 7844 { 7845 /* 7846 Dull the image contrast. 7847 */ 7848 XSetCursorState(display,windows,MagickTrue); 7849 XCheckRefreshWindows(display,windows); 7850 (void) ContrastImage(*image,MagickFalse,exception); 7851 XSetCursorState(display,windows,MagickFalse); 7852 if (windows->image.orphan != MagickFalse) 7853 break; 7854 XConfigureImageColormap(display,resource_info,windows,*image); 7855 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7856 break; 7857 } 7858 case ContrastStretchCommand: 7859 { 7860 double 7861 black_point, 7862 white_point; 7863 7864 static char 7865 levels[MaxTextExtent] = "1%"; 7866 7867 /* 7868 Query user for gamma value. 7869 */ 7870 (void) XDialogWidget(display,windows,"Contrast Stretch", 7871 "Enter black and white points:",levels); 7872 if (*levels == '\0') 7873 break; 7874 /* 7875 Contrast stretch image. 7876 */ 7877 XSetCursorState(display,windows,MagickTrue); 7878 XCheckRefreshWindows(display,windows); 7879 flags=ParseGeometry(levels,&geometry_info); 7880 black_point=geometry_info.rho; 7881 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7882 if ((flags & PercentValue) != 0) 7883 { 7884 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7885 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7886 } 7887 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7888 (void) ContrastStretchImage(*image,black_point,white_point, 7889 exception); 7890 XSetCursorState(display,windows,MagickFalse); 7891 if (windows->image.orphan != MagickFalse) 7892 break; 7893 XConfigureImageColormap(display,resource_info,windows,*image); 7894 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7895 break; 7896 } 7897 case SigmoidalContrastCommand: 7898 { 7899 GeometryInfo 7900 geometry_info; 7901 7902 MagickStatusType 7903 flags; 7904 7905 static char 7906 levels[MaxTextExtent] = "3x50%"; 7907 7908 /* 7909 Query user for gamma value. 7910 */ 7911 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7912 "Enter contrast and midpoint:",levels); 7913 if (*levels == '\0') 7914 break; 7915 /* 7916 Contrast stretch image. 7917 */ 7918 XSetCursorState(display,windows,MagickTrue); 7919 XCheckRefreshWindows(display,windows); 7920 flags=ParseGeometry(levels,&geometry_info); 7921 if ((flags & SigmaValue) == 0) 7922 geometry_info.sigma=1.0*QuantumRange/2.0; 7923 if ((flags & PercentValue) != 0) 7924 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7925 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7926 geometry_info.sigma,exception); 7927 XSetCursorState(display,windows,MagickFalse); 7928 if (windows->image.orphan != MagickFalse) 7929 break; 7930 XConfigureImageColormap(display,resource_info,windows,*image); 7931 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7932 break; 7933 } 7934 case NormalizeCommand: 7935 { 7936 /* 7937 Perform histogram normalization on the image. 7938 */ 7939 XSetCursorState(display,windows,MagickTrue); 7940 XCheckRefreshWindows(display,windows); 7941 (void) NormalizeImage(*image,exception); 7942 XSetCursorState(display,windows,MagickFalse); 7943 if (windows->image.orphan != MagickFalse) 7944 break; 7945 XConfigureImageColormap(display,resource_info,windows,*image); 7946 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7947 break; 7948 } 7949 case EqualizeCommand: 7950 { 7951 /* 7952 Perform histogram equalization on the image. 7953 */ 7954 XSetCursorState(display,windows,MagickTrue); 7955 XCheckRefreshWindows(display,windows); 7956 (void) EqualizeImage(*image,exception); 7957 XSetCursorState(display,windows,MagickFalse); 7958 if (windows->image.orphan != MagickFalse) 7959 break; 7960 XConfigureImageColormap(display,resource_info,windows,*image); 7961 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7962 break; 7963 } 7964 case NegateCommand: 7965 { 7966 /* 7967 Negate colors in image. 7968 */ 7969 XSetCursorState(display,windows,MagickTrue); 7970 XCheckRefreshWindows(display,windows); 7971 (void) NegateImage(*image,MagickFalse,exception); 7972 XSetCursorState(display,windows,MagickFalse); 7973 if (windows->image.orphan != MagickFalse) 7974 break; 7975 XConfigureImageColormap(display,resource_info,windows,*image); 7976 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7977 break; 7978 } 7979 case GrayscaleCommand: 7980 { 7981 /* 7982 Convert image to grayscale. 7983 */ 7984 XSetCursorState(display,windows,MagickTrue); 7985 XCheckRefreshWindows(display,windows); 7986 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 7987 GrayscaleType : GrayscaleMatteType,exception); 7988 XSetCursorState(display,windows,MagickFalse); 7989 if (windows->image.orphan != MagickFalse) 7990 break; 7991 XConfigureImageColormap(display,resource_info,windows,*image); 7992 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7993 break; 7994 } 7995 case MapCommand: 7996 { 7997 Image 7998 *affinity_image; 7999 8000 static char 8001 filename[MaxTextExtent] = "\0"; 8002 8003 /* 8004 Request image file name from user. 8005 */ 8006 XFileBrowserWidget(display,windows,"Map",filename); 8007 if (*filename == '\0') 8008 break; 8009 /* 8010 Map image. 8011 */ 8012 XSetCursorState(display,windows,MagickTrue); 8013 XCheckRefreshWindows(display,windows); 8014 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8015 affinity_image=ReadImage(image_info,exception); 8016 if (affinity_image != (Image *) NULL) 8017 { 8018 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8019 affinity_image=DestroyImage(affinity_image); 8020 } 8021 CatchException(exception); 8022 XSetCursorState(display,windows,MagickFalse); 8023 if (windows->image.orphan != MagickFalse) 8024 break; 8025 XConfigureImageColormap(display,resource_info,windows,*image); 8026 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8027 break; 8028 } 8029 case QuantizeCommand: 8030 { 8031 int 8032 status; 8033 8034 static char 8035 colors[MaxTextExtent] = "256"; 8036 8037 /* 8038 Query user for maximum number of colors. 8039 */ 8040 status=XDialogWidget(display,windows,"Quantize", 8041 "Maximum number of colors:",colors); 8042 if (*colors == '\0') 8043 break; 8044 /* 8045 Color reduce the image. 8046 */ 8047 XSetCursorState(display,windows,MagickTrue); 8048 XCheckRefreshWindows(display,windows); 8049 quantize_info.number_colors=StringToUnsignedLong(colors); 8050 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8051 (void) QuantizeImage(&quantize_info,*image,exception); 8052 XSetCursorState(display,windows,MagickFalse); 8053 if (windows->image.orphan != MagickFalse) 8054 break; 8055 XConfigureImageColormap(display,resource_info,windows,*image); 8056 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8057 break; 8058 } 8059 case DespeckleCommand: 8060 { 8061 Image 8062 *despeckle_image; 8063 8064 /* 8065 Despeckle image. 8066 */ 8067 XSetCursorState(display,windows,MagickTrue); 8068 XCheckRefreshWindows(display,windows); 8069 despeckle_image=DespeckleImage(*image,exception); 8070 if (despeckle_image != (Image *) NULL) 8071 { 8072 *image=DestroyImage(*image); 8073 *image=despeckle_image; 8074 } 8075 CatchException(exception); 8076 XSetCursorState(display,windows,MagickFalse); 8077 if (windows->image.orphan != MagickFalse) 8078 break; 8079 XConfigureImageColormap(display,resource_info,windows,*image); 8080 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8081 break; 8082 } 8083 case EmbossCommand: 8084 { 8085 Image 8086 *emboss_image; 8087 8088 static char 8089 radius[MaxTextExtent] = "0.0x1.0"; 8090 8091 /* 8092 Query user for emboss radius. 8093 */ 8094 (void) XDialogWidget(display,windows,"Emboss", 8095 "Enter the emboss radius and standard deviation:",radius); 8096 if (*radius == '\0') 8097 break; 8098 /* 8099 Reduce noise in the image. 8100 */ 8101 XSetCursorState(display,windows,MagickTrue); 8102 XCheckRefreshWindows(display,windows); 8103 flags=ParseGeometry(radius,&geometry_info); 8104 if ((flags & SigmaValue) == 0) 8105 geometry_info.sigma=1.0; 8106 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8107 exception); 8108 if (emboss_image != (Image *) NULL) 8109 { 8110 *image=DestroyImage(*image); 8111 *image=emboss_image; 8112 } 8113 CatchException(exception); 8114 XSetCursorState(display,windows,MagickFalse); 8115 if (windows->image.orphan != MagickFalse) 8116 break; 8117 XConfigureImageColormap(display,resource_info,windows,*image); 8118 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8119 break; 8120 } 8121 case ReduceNoiseCommand: 8122 { 8123 Image 8124 *noise_image; 8125 8126 static char 8127 radius[MaxTextExtent] = "0"; 8128 8129 /* 8130 Query user for noise radius. 8131 */ 8132 (void) XDialogWidget(display,windows,"Reduce Noise", 8133 "Enter the noise radius:",radius); 8134 if (*radius == '\0') 8135 break; 8136 /* 8137 Reduce noise in the image. 8138 */ 8139 XSetCursorState(display,windows,MagickTrue); 8140 XCheckRefreshWindows(display,windows); 8141 flags=ParseGeometry(radius,&geometry_info); 8142 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8143 geometry_info.rho,(size_t) geometry_info.rho,exception); 8144 if (noise_image != (Image *) NULL) 8145 { 8146 *image=DestroyImage(*image); 8147 *image=noise_image; 8148 } 8149 CatchException(exception); 8150 XSetCursorState(display,windows,MagickFalse); 8151 if (windows->image.orphan != MagickFalse) 8152 break; 8153 XConfigureImageColormap(display,resource_info,windows,*image); 8154 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8155 break; 8156 } 8157 case AddNoiseCommand: 8158 { 8159 char 8160 **noises; 8161 8162 Image 8163 *noise_image; 8164 8165 static char 8166 noise_type[MaxTextExtent] = "Gaussian"; 8167 8168 /* 8169 Add noise to the image. 8170 */ 8171 noises=GetCommandOptions(MagickNoiseOptions); 8172 if (noises == (char **) NULL) 8173 break; 8174 XListBrowserWidget(display,windows,&windows->widget, 8175 (const char **) noises,"Add Noise", 8176 "Select a type of noise to add to your image:",noise_type); 8177 noises=DestroyStringList(noises); 8178 if (*noise_type == '\0') 8179 break; 8180 XSetCursorState(display,windows,MagickTrue); 8181 XCheckRefreshWindows(display,windows); 8182 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8183 MagickNoiseOptions,MagickFalse,noise_type),exception); 8184 if (noise_image != (Image *) NULL) 8185 { 8186 *image=DestroyImage(*image); 8187 *image=noise_image; 8188 } 8189 CatchException(exception); 8190 XSetCursorState(display,windows,MagickFalse); 8191 if (windows->image.orphan != MagickFalse) 8192 break; 8193 XConfigureImageColormap(display,resource_info,windows,*image); 8194 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8195 break; 8196 } 8197 case SharpenCommand: 8198 { 8199 Image 8200 *sharp_image; 8201 8202 static char 8203 radius[MaxTextExtent] = "0.0x1.0"; 8204 8205 /* 8206 Query user for sharpen radius. 8207 */ 8208 (void) XDialogWidget(display,windows,"Sharpen", 8209 "Enter the sharpen radius and standard deviation:",radius); 8210 if (*radius == '\0') 8211 break; 8212 /* 8213 Sharpen image scanlines. 8214 */ 8215 XSetCursorState(display,windows,MagickTrue); 8216 XCheckRefreshWindows(display,windows); 8217 flags=ParseGeometry(radius,&geometry_info); 8218 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8219 geometry_info.xi,exception); 8220 if (sharp_image != (Image *) NULL) 8221 { 8222 *image=DestroyImage(*image); 8223 *image=sharp_image; 8224 } 8225 CatchException(exception); 8226 XSetCursorState(display,windows,MagickFalse); 8227 if (windows->image.orphan != MagickFalse) 8228 break; 8229 XConfigureImageColormap(display,resource_info,windows,*image); 8230 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8231 break; 8232 } 8233 case BlurCommand: 8234 { 8235 Image 8236 *blur_image; 8237 8238 static char 8239 radius[MaxTextExtent] = "0.0x1.0"; 8240 8241 /* 8242 Query user for blur radius. 8243 */ 8244 (void) XDialogWidget(display,windows,"Blur", 8245 "Enter the blur radius and standard deviation:",radius); 8246 if (*radius == '\0') 8247 break; 8248 /* 8249 Blur an image. 8250 */ 8251 XSetCursorState(display,windows,MagickTrue); 8252 XCheckRefreshWindows(display,windows); 8253 flags=ParseGeometry(radius,&geometry_info); 8254 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8255 geometry_info.xi,exception); 8256 if (blur_image != (Image *) NULL) 8257 { 8258 *image=DestroyImage(*image); 8259 *image=blur_image; 8260 } 8261 CatchException(exception); 8262 XSetCursorState(display,windows,MagickFalse); 8263 if (windows->image.orphan != MagickFalse) 8264 break; 8265 XConfigureImageColormap(display,resource_info,windows,*image); 8266 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8267 break; 8268 } 8269 case ThresholdCommand: 8270 { 8271 double 8272 threshold; 8273 8274 static char 8275 factor[MaxTextExtent] = "128"; 8276 8277 /* 8278 Query user for threshold value. 8279 */ 8280 (void) XDialogWidget(display,windows,"Threshold", 8281 "Enter threshold value:",factor); 8282 if (*factor == '\0') 8283 break; 8284 /* 8285 Gamma correct image. 8286 */ 8287 XSetCursorState(display,windows,MagickTrue); 8288 XCheckRefreshWindows(display,windows); 8289 threshold=SiPrefixToDouble(factor,QuantumRange); 8290 (void) BilevelImage(*image,threshold); 8291 XSetCursorState(display,windows,MagickFalse); 8292 if (windows->image.orphan != MagickFalse) 8293 break; 8294 XConfigureImageColormap(display,resource_info,windows,*image); 8295 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8296 break; 8297 } 8298 case EdgeDetectCommand: 8299 { 8300 Image 8301 *edge_image; 8302 8303 static char 8304 radius[MaxTextExtent] = "0"; 8305 8306 /* 8307 Query user for edge factor. 8308 */ 8309 (void) XDialogWidget(display,windows,"Detect Edges", 8310 "Enter the edge detect radius:",radius); 8311 if (*radius == '\0') 8312 break; 8313 /* 8314 Detect edge in image. 8315 */ 8316 XSetCursorState(display,windows,MagickTrue); 8317 XCheckRefreshWindows(display,windows); 8318 flags=ParseGeometry(radius,&geometry_info); 8319 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8320 exception); 8321 if (edge_image != (Image *) NULL) 8322 { 8323 *image=DestroyImage(*image); 8324 *image=edge_image; 8325 } 8326 CatchException(exception); 8327 XSetCursorState(display,windows,MagickFalse); 8328 if (windows->image.orphan != MagickFalse) 8329 break; 8330 XConfigureImageColormap(display,resource_info,windows,*image); 8331 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8332 break; 8333 } 8334 case SpreadCommand: 8335 { 8336 Image 8337 *spread_image; 8338 8339 static char 8340 amount[MaxTextExtent] = "2"; 8341 8342 /* 8343 Query user for spread amount. 8344 */ 8345 (void) XDialogWidget(display,windows,"Spread", 8346 "Enter the displacement amount:",amount); 8347 if (*amount == '\0') 8348 break; 8349 /* 8350 Displace image pixels by a random amount. 8351 */ 8352 XSetCursorState(display,windows,MagickTrue); 8353 XCheckRefreshWindows(display,windows); 8354 flags=ParseGeometry(amount,&geometry_info); 8355 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8356 exception); 8357 if (spread_image != (Image *) NULL) 8358 { 8359 *image=DestroyImage(*image); 8360 *image=spread_image; 8361 } 8362 CatchException(exception); 8363 XSetCursorState(display,windows,MagickFalse); 8364 if (windows->image.orphan != MagickFalse) 8365 break; 8366 XConfigureImageColormap(display,resource_info,windows,*image); 8367 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8368 break; 8369 } 8370 case ShadeCommand: 8371 { 8372 Image 8373 *shade_image; 8374 8375 int 8376 status; 8377 8378 static char 8379 geometry[MaxTextExtent] = "30x30"; 8380 8381 /* 8382 Query user for the shade geometry. 8383 */ 8384 status=XDialogWidget(display,windows,"Shade", 8385 "Enter the azimuth and elevation of the light source:",geometry); 8386 if (*geometry == '\0') 8387 break; 8388 /* 8389 Shade image pixels. 8390 */ 8391 XSetCursorState(display,windows,MagickTrue); 8392 XCheckRefreshWindows(display,windows); 8393 flags=ParseGeometry(geometry,&geometry_info); 8394 if ((flags & SigmaValue) == 0) 8395 geometry_info.sigma=1.0; 8396 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8397 geometry_info.rho,geometry_info.sigma,exception); 8398 if (shade_image != (Image *) NULL) 8399 { 8400 *image=DestroyImage(*image); 8401 *image=shade_image; 8402 } 8403 CatchException(exception); 8404 XSetCursorState(display,windows,MagickFalse); 8405 if (windows->image.orphan != MagickFalse) 8406 break; 8407 XConfigureImageColormap(display,resource_info,windows,*image); 8408 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8409 break; 8410 } 8411 case RaiseCommand: 8412 { 8413 static char 8414 bevel_width[MaxTextExtent] = "10"; 8415 8416 /* 8417 Query user for bevel width. 8418 */ 8419 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8420 if (*bevel_width == '\0') 8421 break; 8422 /* 8423 Raise an image. 8424 */ 8425 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8426 exception); 8427 XSetCursorState(display,windows,MagickTrue); 8428 XCheckRefreshWindows(display,windows); 8429 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8430 exception); 8431 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8432 XSetCursorState(display,windows,MagickFalse); 8433 if (windows->image.orphan != MagickFalse) 8434 break; 8435 XConfigureImageColormap(display,resource_info,windows,*image); 8436 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8437 break; 8438 } 8439 case SegmentCommand: 8440 { 8441 static char 8442 threshold[MaxTextExtent] = "1.0x1.5"; 8443 8444 /* 8445 Query user for smoothing threshold. 8446 */ 8447 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8448 threshold); 8449 if (*threshold == '\0') 8450 break; 8451 /* 8452 Segment an image. 8453 */ 8454 XSetCursorState(display,windows,MagickTrue); 8455 XCheckRefreshWindows(display,windows); 8456 flags=ParseGeometry(threshold,&geometry_info); 8457 if ((flags & SigmaValue) == 0) 8458 geometry_info.sigma=1.0; 8459 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8460 geometry_info.sigma,exception); 8461 XSetCursorState(display,windows,MagickFalse); 8462 if (windows->image.orphan != MagickFalse) 8463 break; 8464 XConfigureImageColormap(display,resource_info,windows,*image); 8465 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8466 break; 8467 } 8468 case SepiaToneCommand: 8469 { 8470 double 8471 threshold; 8472 8473 Image 8474 *sepia_image; 8475 8476 static char 8477 factor[MaxTextExtent] = "80%"; 8478 8479 /* 8480 Query user for sepia-tone factor. 8481 */ 8482 (void) XDialogWidget(display,windows,"Sepia Tone", 8483 "Enter the sepia tone factor (0 - 99.9%):",factor); 8484 if (*factor == '\0') 8485 break; 8486 /* 8487 Sepia tone image pixels. 8488 */ 8489 XSetCursorState(display,windows,MagickTrue); 8490 XCheckRefreshWindows(display,windows); 8491 threshold=SiPrefixToDouble(factor,QuantumRange); 8492 sepia_image=SepiaToneImage(*image,threshold,exception); 8493 if (sepia_image != (Image *) NULL) 8494 { 8495 *image=DestroyImage(*image); 8496 *image=sepia_image; 8497 } 8498 CatchException(exception); 8499 XSetCursorState(display,windows,MagickFalse); 8500 if (windows->image.orphan != MagickFalse) 8501 break; 8502 XConfigureImageColormap(display,resource_info,windows,*image); 8503 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8504 break; 8505 } 8506 case SolarizeCommand: 8507 { 8508 double 8509 threshold; 8510 8511 static char 8512 factor[MaxTextExtent] = "60%"; 8513 8514 /* 8515 Query user for solarize factor. 8516 */ 8517 (void) XDialogWidget(display,windows,"Solarize", 8518 "Enter the solarize factor (0 - 99.9%):",factor); 8519 if (*factor == '\0') 8520 break; 8521 /* 8522 Solarize image pixels. 8523 */ 8524 XSetCursorState(display,windows,MagickTrue); 8525 XCheckRefreshWindows(display,windows); 8526 threshold=SiPrefixToDouble(factor,QuantumRange); 8527 (void) SolarizeImage(*image,threshold,exception); 8528 XSetCursorState(display,windows,MagickFalse); 8529 if (windows->image.orphan != MagickFalse) 8530 break; 8531 XConfigureImageColormap(display,resource_info,windows,*image); 8532 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8533 break; 8534 } 8535 case SwirlCommand: 8536 { 8537 Image 8538 *swirl_image; 8539 8540 static char 8541 degrees[MaxTextExtent] = "60"; 8542 8543 /* 8544 Query user for swirl angle. 8545 */ 8546 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8547 degrees); 8548 if (*degrees == '\0') 8549 break; 8550 /* 8551 Swirl image pixels about the center. 8552 */ 8553 XSetCursorState(display,windows,MagickTrue); 8554 XCheckRefreshWindows(display,windows); 8555 flags=ParseGeometry(degrees,&geometry_info); 8556 swirl_image=SwirlImage(*image,geometry_info.rho,exception); 8557 if (swirl_image != (Image *) NULL) 8558 { 8559 *image=DestroyImage(*image); 8560 *image=swirl_image; 8561 } 8562 CatchException(exception); 8563 XSetCursorState(display,windows,MagickFalse); 8564 if (windows->image.orphan != MagickFalse) 8565 break; 8566 XConfigureImageColormap(display,resource_info,windows,*image); 8567 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8568 break; 8569 } 8570 case ImplodeCommand: 8571 { 8572 Image 8573 *implode_image; 8574 8575 static char 8576 factor[MaxTextExtent] = "0.3"; 8577 8578 /* 8579 Query user for implode factor. 8580 */ 8581 (void) XDialogWidget(display,windows,"Implode", 8582 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8583 if (*factor == '\0') 8584 break; 8585 /* 8586 Implode image pixels about the center. 8587 */ 8588 XSetCursorState(display,windows,MagickTrue); 8589 XCheckRefreshWindows(display,windows); 8590 flags=ParseGeometry(factor,&geometry_info); 8591 implode_image=ImplodeImage(*image,geometry_info.rho,exception); 8592 if (implode_image != (Image *) NULL) 8593 { 8594 *image=DestroyImage(*image); 8595 *image=implode_image; 8596 } 8597 CatchException(exception); 8598 XSetCursorState(display,windows,MagickFalse); 8599 if (windows->image.orphan != MagickFalse) 8600 break; 8601 XConfigureImageColormap(display,resource_info,windows,*image); 8602 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8603 break; 8604 } 8605 case VignetteCommand: 8606 { 8607 Image 8608 *vignette_image; 8609 8610 static char 8611 geometry[MaxTextExtent] = "0x20"; 8612 8613 /* 8614 Query user for the vignette geometry. 8615 */ 8616 (void) XDialogWidget(display,windows,"Vignette", 8617 "Enter the radius, sigma, and x and y offsets:",geometry); 8618 if (*geometry == '\0') 8619 break; 8620 /* 8621 Soften the edges of the image in vignette style 8622 */ 8623 XSetCursorState(display,windows,MagickTrue); 8624 XCheckRefreshWindows(display,windows); 8625 flags=ParseGeometry(geometry,&geometry_info); 8626 if ((flags & SigmaValue) == 0) 8627 geometry_info.sigma=1.0; 8628 if ((flags & XiValue) == 0) 8629 geometry_info.xi=0.1*(*image)->columns; 8630 if ((flags & PsiValue) == 0) 8631 geometry_info.psi=0.1*(*image)->rows; 8632 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8633 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8634 0.5),exception); 8635 if (vignette_image != (Image *) NULL) 8636 { 8637 *image=DestroyImage(*image); 8638 *image=vignette_image; 8639 } 8640 CatchException(exception); 8641 XSetCursorState(display,windows,MagickFalse); 8642 if (windows->image.orphan != MagickFalse) 8643 break; 8644 XConfigureImageColormap(display,resource_info,windows,*image); 8645 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8646 break; 8647 } 8648 case WaveCommand: 8649 { 8650 Image 8651 *wave_image; 8652 8653 static char 8654 geometry[MaxTextExtent] = "25x150"; 8655 8656 /* 8657 Query user for the wave geometry. 8658 */ 8659 (void) XDialogWidget(display,windows,"Wave", 8660 "Enter the amplitude and length of the wave:",geometry); 8661 if (*geometry == '\0') 8662 break; 8663 /* 8664 Alter an image along a sine wave. 8665 */ 8666 XSetCursorState(display,windows,MagickTrue); 8667 XCheckRefreshWindows(display,windows); 8668 flags=ParseGeometry(geometry,&geometry_info); 8669 if ((flags & SigmaValue) == 0) 8670 geometry_info.sigma=1.0; 8671 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8672 exception); 8673 if (wave_image != (Image *) NULL) 8674 { 8675 *image=DestroyImage(*image); 8676 *image=wave_image; 8677 } 8678 CatchException(exception); 8679 XSetCursorState(display,windows,MagickFalse); 8680 if (windows->image.orphan != MagickFalse) 8681 break; 8682 XConfigureImageColormap(display,resource_info,windows,*image); 8683 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8684 break; 8685 } 8686 case OilPaintCommand: 8687 { 8688 Image 8689 *paint_image; 8690 8691 static char 8692 radius[MaxTextExtent] = "0"; 8693 8694 /* 8695 Query user for circular neighborhood radius. 8696 */ 8697 (void) XDialogWidget(display,windows,"Oil Paint", 8698 "Enter the mask radius:",radius); 8699 if (*radius == '\0') 8700 break; 8701 /* 8702 OilPaint image scanlines. 8703 */ 8704 XSetCursorState(display,windows,MagickTrue); 8705 XCheckRefreshWindows(display,windows); 8706 flags=ParseGeometry(radius,&geometry_info); 8707 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8708 exception); 8709 if (paint_image != (Image *) NULL) 8710 { 8711 *image=DestroyImage(*image); 8712 *image=paint_image; 8713 } 8714 CatchException(exception); 8715 XSetCursorState(display,windows,MagickFalse); 8716 if (windows->image.orphan != MagickFalse) 8717 break; 8718 XConfigureImageColormap(display,resource_info,windows,*image); 8719 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8720 break; 8721 } 8722 case CharcoalDrawCommand: 8723 { 8724 Image 8725 *charcoal_image; 8726 8727 static char 8728 radius[MaxTextExtent] = "0x1"; 8729 8730 /* 8731 Query user for charcoal radius. 8732 */ 8733 (void) XDialogWidget(display,windows,"Charcoal Draw", 8734 "Enter the charcoal radius and sigma:",radius); 8735 if (*radius == '\0') 8736 break; 8737 /* 8738 Charcoal the image. 8739 */ 8740 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8741 exception); 8742 XSetCursorState(display,windows,MagickTrue); 8743 XCheckRefreshWindows(display,windows); 8744 flags=ParseGeometry(radius,&geometry_info); 8745 if ((flags & SigmaValue) == 0) 8746 geometry_info.sigma=geometry_info.rho; 8747 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8748 geometry_info.xi,exception); 8749 if (charcoal_image != (Image *) NULL) 8750 { 8751 *image=DestroyImage(*image); 8752 *image=charcoal_image; 8753 } 8754 CatchException(exception); 8755 XSetCursorState(display,windows,MagickFalse); 8756 if (windows->image.orphan != MagickFalse) 8757 break; 8758 XConfigureImageColormap(display,resource_info,windows,*image); 8759 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8760 break; 8761 } 8762 case AnnotateCommand: 8763 { 8764 /* 8765 Annotate the image with text. 8766 */ 8767 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8768 if (status == MagickFalse) 8769 { 8770 XNoticeWidget(display,windows,"Unable to annotate X image", 8771 (*image)->filename); 8772 break; 8773 } 8774 break; 8775 } 8776 case DrawCommand: 8777 { 8778 /* 8779 Draw image. 8780 */ 8781 status=XDrawEditImage(display,resource_info,windows,image,exception); 8782 if (status == MagickFalse) 8783 { 8784 XNoticeWidget(display,windows,"Unable to draw on the X image", 8785 (*image)->filename); 8786 break; 8787 } 8788 break; 8789 } 8790 case ColorCommand: 8791 { 8792 /* 8793 Color edit. 8794 */ 8795 status=XColorEditImage(display,resource_info,windows,image,exception); 8796 if (status == MagickFalse) 8797 { 8798 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8799 (*image)->filename); 8800 break; 8801 } 8802 break; 8803 } 8804 case MatteCommand: 8805 { 8806 /* 8807 Matte edit. 8808 */ 8809 status=XMatteEditImage(display,resource_info,windows,image,exception); 8810 if (status == MagickFalse) 8811 { 8812 XNoticeWidget(display,windows,"Unable to matte edit X image", 8813 (*image)->filename); 8814 break; 8815 } 8816 break; 8817 } 8818 case CompositeCommand: 8819 { 8820 /* 8821 Composite image. 8822 */ 8823 status=XCompositeImage(display,resource_info,windows,*image, 8824 exception); 8825 if (status == MagickFalse) 8826 { 8827 XNoticeWidget(display,windows,"Unable to composite X image", 8828 (*image)->filename); 8829 break; 8830 } 8831 break; 8832 } 8833 case AddBorderCommand: 8834 { 8835 Image 8836 *border_image; 8837 8838 static char 8839 geometry[MaxTextExtent] = "6x6"; 8840 8841 /* 8842 Query user for border color and geometry. 8843 */ 8844 XColorBrowserWidget(display,windows,"Select",color); 8845 if (*color == '\0') 8846 break; 8847 (void) XDialogWidget(display,windows,"Add Border", 8848 "Enter border geometry:",geometry); 8849 if (*geometry == '\0') 8850 break; 8851 /* 8852 Add a border to the image. 8853 */ 8854 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8855 exception); 8856 XSetCursorState(display,windows,MagickTrue); 8857 XCheckRefreshWindows(display,windows); 8858 (void) QueryColorDatabase(color,&(*image)->border_color, 8859 exception); 8860 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8861 exception); 8862 border_image=BorderImage(*image,&page_geometry,exception); 8863 if (border_image != (Image *) NULL) 8864 { 8865 *image=DestroyImage(*image); 8866 *image=border_image; 8867 } 8868 CatchException(exception); 8869 XSetCursorState(display,windows,MagickFalse); 8870 if (windows->image.orphan != MagickFalse) 8871 break; 8872 windows->image.window_changes.width=(int) (*image)->columns; 8873 windows->image.window_changes.height=(int) (*image)->rows; 8874 XConfigureImageColormap(display,resource_info,windows,*image); 8875 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8876 break; 8877 } 8878 case AddFrameCommand: 8879 { 8880 FrameInfo 8881 frame_info; 8882 8883 Image 8884 *frame_image; 8885 8886 static char 8887 geometry[MaxTextExtent] = "6x6"; 8888 8889 /* 8890 Query user for frame color and geometry. 8891 */ 8892 XColorBrowserWidget(display,windows,"Select",color); 8893 if (*color == '\0') 8894 break; 8895 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8896 geometry); 8897 if (*geometry == '\0') 8898 break; 8899 /* 8900 Surround image with an ornamental border. 8901 */ 8902 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8903 exception); 8904 XSetCursorState(display,windows,MagickTrue); 8905 XCheckRefreshWindows(display,windows); 8906 (void) QueryColorDatabase(color,&(*image)->matte_color, 8907 exception); 8908 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8909 exception); 8910 frame_info.width=page_geometry.width; 8911 frame_info.height=page_geometry.height; 8912 frame_info.outer_bevel=page_geometry.x; 8913 frame_info.inner_bevel=page_geometry.y; 8914 frame_info.x=(ssize_t) frame_info.width; 8915 frame_info.y=(ssize_t) frame_info.height; 8916 frame_info.width=(*image)->columns+2*frame_info.width; 8917 frame_info.height=(*image)->rows+2*frame_info.height; 8918 frame_image=FrameImage(*image,&frame_info,exception); 8919 if (frame_image != (Image *) NULL) 8920 { 8921 *image=DestroyImage(*image); 8922 *image=frame_image; 8923 } 8924 CatchException(exception); 8925 XSetCursorState(display,windows,MagickFalse); 8926 if (windows->image.orphan != MagickFalse) 8927 break; 8928 windows->image.window_changes.width=(int) (*image)->columns; 8929 windows->image.window_changes.height=(int) (*image)->rows; 8930 XConfigureImageColormap(display,resource_info,windows,*image); 8931 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8932 break; 8933 } 8934 case CommentCommand: 8935 { 8936 const char 8937 *value; 8938 8939 FILE 8940 *file; 8941 8942 int 8943 unique_file; 8944 8945 /* 8946 Edit image comment. 8947 */ 8948 unique_file=AcquireUniqueFileResource(image_info->filename); 8949 if (unique_file == -1) 8950 XNoticeWidget(display,windows,"Unable to edit image comment", 8951 image_info->filename); 8952 value=GetImageProperty(*image,"comment"); 8953 if (value == (char *) NULL) 8954 unique_file=close(unique_file)-1; 8955 else 8956 { 8957 register const char 8958 *p; 8959 8960 file=fdopen(unique_file,"w"); 8961 if (file == (FILE *) NULL) 8962 { 8963 XNoticeWidget(display,windows,"Unable to edit image comment", 8964 image_info->filename); 8965 break; 8966 } 8967 for (p=value; *p != '\0'; p++) 8968 (void) fputc((int) *p,file); 8969 (void) fputc('\n',file); 8970 (void) fclose(file); 8971 } 8972 XSetCursorState(display,windows,MagickTrue); 8973 XCheckRefreshWindows(display,windows); 8974 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8975 exception); 8976 if (status == MagickFalse) 8977 XNoticeWidget(display,windows,"Unable to edit image comment", 8978 (char *) NULL); 8979 else 8980 { 8981 char 8982 *comment; 8983 8984 comment=FileToString(image_info->filename,~0UL,exception); 8985 if (comment != (char *) NULL) 8986 { 8987 (void) SetImageProperty(*image,"comment",comment); 8988 (*image)->taint=MagickTrue; 8989 } 8990 } 8991 (void) RelinquishUniqueFileResource(image_info->filename); 8992 XSetCursorState(display,windows,MagickFalse); 8993 break; 8994 } 8995 case LaunchCommand: 8996 { 8997 /* 8998 Launch program. 8999 */ 9000 XSetCursorState(display,windows,MagickTrue); 9001 XCheckRefreshWindows(display,windows); 9002 (void) AcquireUniqueFilename(filename); 9003 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9004 filename); 9005 status=WriteImage(image_info,*image,exception); 9006 if (status == MagickFalse) 9007 XNoticeWidget(display,windows,"Unable to launch image editor", 9008 (char *) NULL); 9009 else 9010 { 9011 nexus=ReadImage(resource_info->image_info,exception); 9012 CatchException(exception); 9013 XClientMessage(display,windows->image.id,windows->im_protocols, 9014 windows->im_next_image,CurrentTime); 9015 } 9016 (void) RelinquishUniqueFileResource(filename); 9017 XSetCursorState(display,windows,MagickFalse); 9018 break; 9019 } 9020 case RegionofInterestCommand: 9021 { 9022 /* 9023 Apply an image processing technique to a region of interest. 9024 */ 9025 (void) XROIImage(display,resource_info,windows,image,exception); 9026 break; 9027 } 9028 case InfoCommand: 9029 break; 9030 case ZoomCommand: 9031 { 9032 /* 9033 Zoom image. 9034 */ 9035 if (windows->magnify.mapped != MagickFalse) 9036 (void) XRaiseWindow(display,windows->magnify.id); 9037 else 9038 { 9039 /* 9040 Make magnify image. 9041 */ 9042 XSetCursorState(display,windows,MagickTrue); 9043 (void) XMapRaised(display,windows->magnify.id); 9044 XSetCursorState(display,windows,MagickFalse); 9045 } 9046 break; 9047 } 9048 case ShowPreviewCommand: 9049 { 9050 char 9051 **previews; 9052 9053 Image 9054 *preview_image; 9055 9056 static char 9057 preview_type[MaxTextExtent] = "Gamma"; 9058 9059 /* 9060 Select preview type from menu. 9061 */ 9062 previews=GetCommandOptions(MagickPreviewOptions); 9063 if (previews == (char **) NULL) 9064 break; 9065 XListBrowserWidget(display,windows,&windows->widget, 9066 (const char **) previews,"Preview", 9067 "Select an enhancement, effect, or F/X:",preview_type); 9068 previews=DestroyStringList(previews); 9069 if (*preview_type == '\0') 9070 break; 9071 /* 9072 Show image preview. 9073 */ 9074 XSetCursorState(display,windows,MagickTrue); 9075 XCheckRefreshWindows(display,windows); 9076 image_info->preview_type=(PreviewType) 9077 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9078 image_info->group=(ssize_t) windows->image.id; 9079 (void) DeleteImageProperty(*image,"label"); 9080 (void) SetImageProperty(*image,"label","Preview"); 9081 (void) AcquireUniqueFilename(filename); 9082 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9083 filename); 9084 status=WriteImage(image_info,*image,exception); 9085 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9086 preview_image=ReadImage(image_info,exception); 9087 (void) RelinquishUniqueFileResource(filename); 9088 if (preview_image == (Image *) NULL) 9089 break; 9090 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9091 filename); 9092 status=WriteImage(image_info,preview_image,exception); 9093 preview_image=DestroyImage(preview_image); 9094 if (status == MagickFalse) 9095 XNoticeWidget(display,windows,"Unable to show image preview", 9096 (*image)->filename); 9097 XDelay(display,1500); 9098 XSetCursorState(display,windows,MagickFalse); 9099 break; 9100 } 9101 case ShowHistogramCommand: 9102 { 9103 Image 9104 *histogram_image; 9105 9106 /* 9107 Show image histogram. 9108 */ 9109 XSetCursorState(display,windows,MagickTrue); 9110 XCheckRefreshWindows(display,windows); 9111 image_info->group=(ssize_t) windows->image.id; 9112 (void) DeleteImageProperty(*image,"label"); 9113 (void) SetImageProperty(*image,"label","Histogram"); 9114 (void) AcquireUniqueFilename(filename); 9115 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9116 filename); 9117 status=WriteImage(image_info,*image,exception); 9118 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9119 histogram_image=ReadImage(image_info,exception); 9120 (void) RelinquishUniqueFileResource(filename); 9121 if (histogram_image == (Image *) NULL) 9122 break; 9123 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9124 "show:%s",filename); 9125 status=WriteImage(image_info,histogram_image,exception); 9126 histogram_image=DestroyImage(histogram_image); 9127 if (status == MagickFalse) 9128 XNoticeWidget(display,windows,"Unable to show histogram", 9129 (*image)->filename); 9130 XDelay(display,1500); 9131 XSetCursorState(display,windows,MagickFalse); 9132 break; 9133 } 9134 case ShowMatteCommand: 9135 { 9136 Image 9137 *matte_image; 9138 9139 if ((*image)->matte == MagickFalse) 9140 { 9141 XNoticeWidget(display,windows, 9142 "Image does not have any matte information",(*image)->filename); 9143 break; 9144 } 9145 /* 9146 Show image matte. 9147 */ 9148 XSetCursorState(display,windows,MagickTrue); 9149 XCheckRefreshWindows(display,windows); 9150 image_info->group=(ssize_t) windows->image.id; 9151 (void) DeleteImageProperty(*image,"label"); 9152 (void) SetImageProperty(*image,"label","Matte"); 9153 (void) AcquireUniqueFilename(filename); 9154 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9155 filename); 9156 status=WriteImage(image_info,*image,exception); 9157 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9158 matte_image=ReadImage(image_info,exception); 9159 (void) RelinquishUniqueFileResource(filename); 9160 if (matte_image == (Image *) NULL) 9161 break; 9162 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9163 filename); 9164 status=WriteImage(image_info,matte_image,exception); 9165 matte_image=DestroyImage(matte_image); 9166 if (status == MagickFalse) 9167 XNoticeWidget(display,windows,"Unable to show matte", 9168 (*image)->filename); 9169 XDelay(display,1500); 9170 XSetCursorState(display,windows,MagickFalse); 9171 break; 9172 } 9173 case BackgroundCommand: 9174 { 9175 /* 9176 Background image. 9177 */ 9178 status=XBackgroundImage(display,resource_info,windows,image,exception); 9179 if (status == MagickFalse) 9180 break; 9181 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9182 if (nexus != (Image *) NULL) 9183 XClientMessage(display,windows->image.id,windows->im_protocols, 9184 windows->im_next_image,CurrentTime); 9185 break; 9186 } 9187 case SlideShowCommand: 9188 { 9189 static char 9190 delay[MaxTextExtent] = "5"; 9191 9192 /* 9193 Display next image after pausing. 9194 */ 9195 (void) XDialogWidget(display,windows,"Slide Show", 9196 "Pause how many 1/100ths of a second between images:",delay); 9197 if (*delay == '\0') 9198 break; 9199 resource_info->delay=StringToUnsignedLong(delay); 9200 XClientMessage(display,windows->image.id,windows->im_protocols, 9201 windows->im_next_image,CurrentTime); 9202 break; 9203 } 9204 case PreferencesCommand: 9205 { 9206 /* 9207 Set user preferences. 9208 */ 9209 status=XPreferencesWidget(display,resource_info,windows); 9210 if (status == MagickFalse) 9211 break; 9212 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9213 if (nexus != (Image *) NULL) 9214 XClientMessage(display,windows->image.id,windows->im_protocols, 9215 windows->im_next_image,CurrentTime); 9216 break; 9217 } 9218 case HelpCommand: 9219 { 9220 /* 9221 User requested help. 9222 */ 9223 XTextViewWidget(display,resource_info,windows,MagickFalse, 9224 "Help Viewer - Display",DisplayHelp); 9225 break; 9226 } 9227 case BrowseDocumentationCommand: 9228 { 9229 Atom 9230 mozilla_atom; 9231 9232 Window 9233 mozilla_window, 9234 root_window; 9235 9236 /* 9237 Browse the ImageMagick documentation. 9238 */ 9239 root_window=XRootWindow(display,XDefaultScreen(display)); 9240 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9241 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9242 if (mozilla_window != (Window) NULL) 9243 { 9244 char 9245 command[MaxTextExtent], 9246 *url; 9247 9248 /* 9249 Display documentation using Netscape remote control. 9250 */ 9251 url=GetMagickHomeURL(); 9252 (void) FormatLocaleString(command,MaxTextExtent, 9253 "openurl(%s,new-tab)",url); 9254 url=DestroyString(url); 9255 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9256 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9257 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9258 XSetCursorState(display,windows,MagickFalse); 9259 break; 9260 } 9261 XSetCursorState(display,windows,MagickTrue); 9262 XCheckRefreshWindows(display,windows); 9263 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9264 exception); 9265 if (status == MagickFalse) 9266 XNoticeWidget(display,windows,"Unable to browse documentation", 9267 (char *) NULL); 9268 XDelay(display,1500); 9269 XSetCursorState(display,windows,MagickFalse); 9270 break; 9271 } 9272 case VersionCommand: 9273 { 9274 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9275 GetMagickCopyright()); 9276 break; 9277 } 9278 case SaveToUndoBufferCommand: 9279 break; 9280 default: 9281 { 9282 (void) XBell(display,0); 9283 break; 9284 } 9285 } 9286 image_info=DestroyImageInfo(image_info); 9287 return(nexus); 9288} 9289 9290/* 9291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9292% % 9293% % 9294% % 9295+ X M a g n i f y I m a g e % 9296% % 9297% % 9298% % 9299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9300% 9301% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9302% The magnified portion is displayed in a separate window. 9303% 9304% The format of the XMagnifyImage method is: 9305% 9306% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9307% 9308% A description of each parameter follows: 9309% 9310% o display: Specifies a connection to an X server; returned from 9311% XOpenDisplay. 9312% 9313% o windows: Specifies a pointer to a XWindows structure. 9314% 9315% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9316% the entire image is refreshed. 9317% 9318*/ 9319static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9320{ 9321 char 9322 text[MaxTextExtent]; 9323 9324 register int 9325 x, 9326 y; 9327 9328 size_t 9329 state; 9330 9331 /* 9332 Update magnified image until the mouse button is released. 9333 */ 9334 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9335 state=DefaultState; 9336 x=event->xbutton.x; 9337 y=event->xbutton.y; 9338 windows->magnify.x=(int) windows->image.x+x; 9339 windows->magnify.y=(int) windows->image.y+y; 9340 do 9341 { 9342 /* 9343 Map and unmap Info widget as text cursor crosses its boundaries. 9344 */ 9345 if (windows->info.mapped != MagickFalse) 9346 { 9347 if ((x < (int) (windows->info.x+windows->info.width)) && 9348 (y < (int) (windows->info.y+windows->info.height))) 9349 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9350 } 9351 else 9352 if ((x > (int) (windows->info.x+windows->info.width)) || 9353 (y > (int) (windows->info.y+windows->info.height))) 9354 (void) XMapWindow(display,windows->info.id); 9355 if (windows->info.mapped != MagickFalse) 9356 { 9357 /* 9358 Display pointer position. 9359 */ 9360 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9361 windows->magnify.x,windows->magnify.y); 9362 XInfoWidget(display,windows,text); 9363 } 9364 /* 9365 Wait for next event. 9366 */ 9367 XScreenEvent(display,windows,event); 9368 switch (event->type) 9369 { 9370 case ButtonPress: 9371 break; 9372 case ButtonRelease: 9373 { 9374 /* 9375 User has finished magnifying image. 9376 */ 9377 x=event->xbutton.x; 9378 y=event->xbutton.y; 9379 state|=ExitState; 9380 break; 9381 } 9382 case Expose: 9383 break; 9384 case MotionNotify: 9385 { 9386 x=event->xmotion.x; 9387 y=event->xmotion.y; 9388 break; 9389 } 9390 default: 9391 break; 9392 } 9393 /* 9394 Check boundary conditions. 9395 */ 9396 if (x < 0) 9397 x=0; 9398 else 9399 if (x >= (int) windows->image.width) 9400 x=(int) windows->image.width-1; 9401 if (y < 0) 9402 y=0; 9403 else 9404 if (y >= (int) windows->image.height) 9405 y=(int) windows->image.height-1; 9406 } while ((state & ExitState) == 0); 9407 /* 9408 Display magnified image. 9409 */ 9410 XSetCursorState(display,windows,MagickFalse); 9411} 9412 9413/* 9414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9415% % 9416% % 9417% % 9418+ X M a g n i f y W i n d o w C o m m a n d % 9419% % 9420% % 9421% % 9422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9423% 9424% XMagnifyWindowCommand() moves the image within an Magnify window by one 9425% pixel as specified by the key symbol. 9426% 9427% The format of the XMagnifyWindowCommand method is: 9428% 9429% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9430% const MagickStatusType state,const KeySym key_symbol) 9431% 9432% A description of each parameter follows: 9433% 9434% o display: Specifies a connection to an X server; returned from 9435% XOpenDisplay. 9436% 9437% o windows: Specifies a pointer to a XWindows structure. 9438% 9439% o state: key mask. 9440% 9441% o key_symbol: Specifies a KeySym which indicates which side of the image 9442% to trim. 9443% 9444*/ 9445static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9446 const MagickStatusType state,const KeySym key_symbol) 9447{ 9448 unsigned int 9449 quantum; 9450 9451 /* 9452 User specified a magnify factor or position. 9453 */ 9454 quantum=1; 9455 if ((state & Mod1Mask) != 0) 9456 quantum=10; 9457 switch ((int) key_symbol) 9458 { 9459 case QuitCommand: 9460 { 9461 (void) XWithdrawWindow(display,windows->magnify.id, 9462 windows->magnify.screen); 9463 break; 9464 } 9465 case XK_Home: 9466 case XK_KP_Home: 9467 { 9468 windows->magnify.x=(int) windows->image.width/2; 9469 windows->magnify.y=(int) windows->image.height/2; 9470 break; 9471 } 9472 case XK_Left: 9473 case XK_KP_Left: 9474 { 9475 if (windows->magnify.x > 0) 9476 windows->magnify.x-=quantum; 9477 break; 9478 } 9479 case XK_Up: 9480 case XK_KP_Up: 9481 { 9482 if (windows->magnify.y > 0) 9483 windows->magnify.y-=quantum; 9484 break; 9485 } 9486 case XK_Right: 9487 case XK_KP_Right: 9488 { 9489 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9490 windows->magnify.x+=quantum; 9491 break; 9492 } 9493 case XK_Down: 9494 case XK_KP_Down: 9495 { 9496 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9497 windows->magnify.y+=quantum; 9498 break; 9499 } 9500 case XK_0: 9501 case XK_1: 9502 case XK_2: 9503 case XK_3: 9504 case XK_4: 9505 case XK_5: 9506 case XK_6: 9507 case XK_7: 9508 case XK_8: 9509 case XK_9: 9510 { 9511 windows->magnify.data=(key_symbol-XK_0); 9512 break; 9513 } 9514 case XK_KP_0: 9515 case XK_KP_1: 9516 case XK_KP_2: 9517 case XK_KP_3: 9518 case XK_KP_4: 9519 case XK_KP_5: 9520 case XK_KP_6: 9521 case XK_KP_7: 9522 case XK_KP_8: 9523 case XK_KP_9: 9524 { 9525 windows->magnify.data=(key_symbol-XK_KP_0); 9526 break; 9527 } 9528 default: 9529 break; 9530 } 9531 XMakeMagnifyImage(display,windows); 9532} 9533 9534/* 9535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9536% % 9537% % 9538% % 9539+ X M a k e P a n I m a g e % 9540% % 9541% % 9542% % 9543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9544% 9545% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9546% icon window. 9547% 9548% The format of the XMakePanImage method is: 9549% 9550% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9551% XWindows *windows,Image *image,ExceptionInfo *exception) 9552% 9553% A description of each parameter follows: 9554% 9555% o display: Specifies a connection to an X server; returned from 9556% XOpenDisplay. 9557% 9558% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9559% 9560% o windows: Specifies a pointer to a XWindows structure. 9561% 9562% o image: the image. 9563% 9564% o exception: return any errors or warnings in this structure. 9565% 9566*/ 9567static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9568 XWindows *windows,Image *image,ExceptionInfo *exception) 9569{ 9570 MagickStatusType 9571 status; 9572 9573 /* 9574 Create and display image for panning icon. 9575 */ 9576 XSetCursorState(display,windows,MagickTrue); 9577 XCheckRefreshWindows(display,windows); 9578 windows->pan.x=(int) windows->image.x; 9579 windows->pan.y=(int) windows->image.y; 9580 status=XMakeImage(display,resource_info,&windows->pan,image, 9581 windows->pan.width,windows->pan.height,exception); 9582 if (status == MagickFalse) 9583 ThrowXWindowFatalException(ResourceLimitError, 9584 "MemoryAllocationFailed",image->filename); 9585 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9586 windows->pan.pixmap); 9587 (void) XClearWindow(display,windows->pan.id); 9588 XDrawPanRectangle(display,windows); 9589 XSetCursorState(display,windows,MagickFalse); 9590} 9591 9592/* 9593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9594% % 9595% % 9596% % 9597+ X M a t t a E d i t I m a g e % 9598% % 9599% % 9600% % 9601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9602% 9603% XMatteEditImage() allows the user to interactively change the Matte channel 9604% of an image. If the image is PseudoClass it is promoted to DirectClass 9605% before the matte information is stored. 9606% 9607% The format of the XMatteEditImage method is: 9608% 9609% MagickBooleanType XMatteEditImage(Display *display, 9610% XResourceInfo *resource_info,XWindows *windows,Image **image, 9611% ExceptionInfo *exception) 9612% 9613% A description of each parameter follows: 9614% 9615% o display: Specifies a connection to an X server; returned from 9616% XOpenDisplay. 9617% 9618% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9619% 9620% o windows: Specifies a pointer to a XWindows structure. 9621% 9622% o image: the image; returned from ReadImage. 9623% 9624% o exception: return any errors or warnings in this structure. 9625% 9626*/ 9627static MagickBooleanType XMatteEditImage(Display *display, 9628 XResourceInfo *resource_info,XWindows *windows,Image **image, 9629 ExceptionInfo *exception) 9630{ 9631 static char 9632 matte[MaxTextExtent] = "0"; 9633 9634 static const char 9635 *MatteEditMenu[] = 9636 { 9637 "Method", 9638 "Border Color", 9639 "Fuzz", 9640 "Matte Value", 9641 "Undo", 9642 "Help", 9643 "Dismiss", 9644 (char *) NULL 9645 }; 9646 9647 static const ModeType 9648 MatteEditCommands[] = 9649 { 9650 MatteEditMethod, 9651 MatteEditBorderCommand, 9652 MatteEditFuzzCommand, 9653 MatteEditValueCommand, 9654 MatteEditUndoCommand, 9655 MatteEditHelpCommand, 9656 MatteEditDismissCommand 9657 }; 9658 9659 static PaintMethod 9660 method = PointMethod; 9661 9662 static XColor 9663 border_color = { 0, 0, 0, 0, 0, 0 }; 9664 9665 char 9666 command[MaxTextExtent], 9667 text[MaxTextExtent]; 9668 9669 Cursor 9670 cursor; 9671 9672 int 9673 entry, 9674 id, 9675 x, 9676 x_offset, 9677 y, 9678 y_offset; 9679 9680 register int 9681 i; 9682 9683 register Quantum 9684 *q; 9685 9686 unsigned int 9687 height, 9688 width; 9689 9690 size_t 9691 state; 9692 9693 XEvent 9694 event; 9695 9696 /* 9697 Map Command widget. 9698 */ 9699 (void) CloneString(&windows->command.name,"Matte Edit"); 9700 windows->command.data=4; 9701 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9702 (void) XMapRaised(display,windows->command.id); 9703 XClientMessage(display,windows->image.id,windows->im_protocols, 9704 windows->im_update_widget,CurrentTime); 9705 /* 9706 Make cursor. 9707 */ 9708 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9709 resource_info->background_color,resource_info->foreground_color); 9710 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9711 /* 9712 Track pointer until button 1 is pressed. 9713 */ 9714 XQueryPosition(display,windows->image.id,&x,&y); 9715 (void) XSelectInput(display,windows->image.id, 9716 windows->image.attributes.event_mask | PointerMotionMask); 9717 state=DefaultState; 9718 do 9719 { 9720 if (windows->info.mapped != MagickFalse) 9721 { 9722 /* 9723 Display pointer position. 9724 */ 9725 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9726 x+windows->image.x,y+windows->image.y); 9727 XInfoWidget(display,windows,text); 9728 } 9729 /* 9730 Wait for next event. 9731 */ 9732 XScreenEvent(display,windows,&event); 9733 if (event.xany.window == windows->command.id) 9734 { 9735 /* 9736 Select a command from the Command widget. 9737 */ 9738 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9739 if (id < 0) 9740 { 9741 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9742 continue; 9743 } 9744 switch (MatteEditCommands[id]) 9745 { 9746 case MatteEditMethod: 9747 { 9748 char 9749 **methods; 9750 9751 /* 9752 Select a method from the pop-up menu. 9753 */ 9754 methods=GetCommandOptions(MagickMethodOptions); 9755 if (methods == (char **) NULL) 9756 break; 9757 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9758 (const char **) methods,command); 9759 if (entry >= 0) 9760 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9761 MagickFalse,methods[entry]); 9762 methods=DestroyStringList(methods); 9763 break; 9764 } 9765 case MatteEditBorderCommand: 9766 { 9767 const char 9768 *ColorMenu[MaxNumberPens]; 9769 9770 int 9771 pen_number; 9772 9773 /* 9774 Initialize menu selections. 9775 */ 9776 for (i=0; i < (int) (MaxNumberPens-2); i++) 9777 ColorMenu[i]=resource_info->pen_colors[i]; 9778 ColorMenu[MaxNumberPens-2]="Browser..."; 9779 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9780 /* 9781 Select a pen color from the pop-up menu. 9782 */ 9783 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9784 (const char **) ColorMenu,command); 9785 if (pen_number < 0) 9786 break; 9787 if (pen_number == (MaxNumberPens-2)) 9788 { 9789 static char 9790 color_name[MaxTextExtent] = "gray"; 9791 9792 /* 9793 Select a pen color from a dialog. 9794 */ 9795 resource_info->pen_colors[pen_number]=color_name; 9796 XColorBrowserWidget(display,windows,"Select",color_name); 9797 if (*color_name == '\0') 9798 break; 9799 } 9800 /* 9801 Set border color. 9802 */ 9803 (void) XParseColor(display,windows->map_info->colormap, 9804 resource_info->pen_colors[pen_number],&border_color); 9805 break; 9806 } 9807 case MatteEditFuzzCommand: 9808 { 9809 static char 9810 fuzz[MaxTextExtent]; 9811 9812 static const char 9813 *FuzzMenu[] = 9814 { 9815 "0%", 9816 "2%", 9817 "5%", 9818 "10%", 9819 "15%", 9820 "Dialog...", 9821 (char *) NULL, 9822 }; 9823 9824 /* 9825 Select a command from the pop-up menu. 9826 */ 9827 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9828 command); 9829 if (entry < 0) 9830 break; 9831 if (entry != 5) 9832 { 9833 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0* 9834 QuantumRange+1.0); 9835 break; 9836 } 9837 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9838 (void) XDialogWidget(display,windows,"Ok", 9839 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9840 if (*fuzz == '\0') 9841 break; 9842 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9843 (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0); 9844 break; 9845 } 9846 case MatteEditValueCommand: 9847 { 9848 static char 9849 message[MaxTextExtent]; 9850 9851 static const char 9852 *MatteMenu[] = 9853 { 9854 "Opaque", 9855 "Transparent", 9856 "Dialog...", 9857 (char *) NULL, 9858 }; 9859 9860 /* 9861 Select a command from the pop-up menu. 9862 */ 9863 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9864 command); 9865 if (entry < 0) 9866 break; 9867 if (entry != 2) 9868 { 9869 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9870 OpaqueAlpha); 9871 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9872 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9873 (Quantum) TransparentAlpha); 9874 break; 9875 } 9876 (void) FormatLocaleString(message,MaxTextExtent, 9877 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9878 QuantumRange); 9879 (void) XDialogWidget(display,windows,"Matte",message,matte); 9880 if (*matte == '\0') 9881 break; 9882 break; 9883 } 9884 case MatteEditUndoCommand: 9885 { 9886 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9887 image,exception); 9888 break; 9889 } 9890 case MatteEditHelpCommand: 9891 { 9892 XTextViewWidget(display,resource_info,windows,MagickFalse, 9893 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9894 break; 9895 } 9896 case MatteEditDismissCommand: 9897 { 9898 /* 9899 Prematurely exit. 9900 */ 9901 state|=EscapeState; 9902 state|=ExitState; 9903 break; 9904 } 9905 default: 9906 break; 9907 } 9908 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9909 continue; 9910 } 9911 switch (event.type) 9912 { 9913 case ButtonPress: 9914 { 9915 if (event.xbutton.button != Button1) 9916 break; 9917 if ((event.xbutton.window != windows->image.id) && 9918 (event.xbutton.window != windows->magnify.id)) 9919 break; 9920 /* 9921 Update matte data. 9922 */ 9923 x=event.xbutton.x; 9924 y=event.xbutton.y; 9925 (void) XMagickCommand(display,resource_info,windows, 9926 SaveToUndoBufferCommand,image,exception); 9927 state|=UpdateConfigurationState; 9928 break; 9929 } 9930 case ButtonRelease: 9931 { 9932 if (event.xbutton.button != Button1) 9933 break; 9934 if ((event.xbutton.window != windows->image.id) && 9935 (event.xbutton.window != windows->magnify.id)) 9936 break; 9937 /* 9938 Update colormap information. 9939 */ 9940 x=event.xbutton.x; 9941 y=event.xbutton.y; 9942 XConfigureImageColormap(display,resource_info,windows,*image); 9943 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9944 XInfoWidget(display,windows,text); 9945 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9946 state&=(~UpdateConfigurationState); 9947 break; 9948 } 9949 case Expose: 9950 break; 9951 case KeyPress: 9952 { 9953 char 9954 command[MaxTextExtent]; 9955 9956 KeySym 9957 key_symbol; 9958 9959 if (event.xkey.window == windows->magnify.id) 9960 { 9961 Window 9962 window; 9963 9964 window=windows->magnify.id; 9965 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9966 } 9967 if (event.xkey.window != windows->image.id) 9968 break; 9969 /* 9970 Respond to a user key press. 9971 */ 9972 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9973 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9974 switch ((int) key_symbol) 9975 { 9976 case XK_Escape: 9977 case XK_F20: 9978 { 9979 /* 9980 Prematurely exit. 9981 */ 9982 state|=ExitState; 9983 break; 9984 } 9985 case XK_F1: 9986 case XK_Help: 9987 { 9988 XTextViewWidget(display,resource_info,windows,MagickFalse, 9989 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9990 break; 9991 } 9992 default: 9993 { 9994 (void) XBell(display,0); 9995 break; 9996 } 9997 } 9998 break; 9999 } 10000 case MotionNotify: 10001 { 10002 /* 10003 Map and unmap Info widget as cursor crosses its boundaries. 10004 */ 10005 x=event.xmotion.x; 10006 y=event.xmotion.y; 10007 if (windows->info.mapped != MagickFalse) 10008 { 10009 if ((x < (int) (windows->info.x+windows->info.width)) && 10010 (y < (int) (windows->info.y+windows->info.height))) 10011 (void) XWithdrawWindow(display,windows->info.id, 10012 windows->info.screen); 10013 } 10014 else 10015 if ((x > (int) (windows->info.x+windows->info.width)) || 10016 (y > (int) (windows->info.y+windows->info.height))) 10017 (void) XMapWindow(display,windows->info.id); 10018 break; 10019 } 10020 default: 10021 break; 10022 } 10023 if (event.xany.window == windows->magnify.id) 10024 { 10025 x=windows->magnify.x-windows->image.x; 10026 y=windows->magnify.y-windows->image.y; 10027 } 10028 x_offset=x; 10029 y_offset=y; 10030 if ((state & UpdateConfigurationState) != 0) 10031 { 10032 CacheView 10033 *image_view; 10034 10035 int 10036 x, 10037 y; 10038 10039 /* 10040 Matte edit is relative to image configuration. 10041 */ 10042 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10043 MagickTrue); 10044 XPutPixel(windows->image.ximage,x_offset,y_offset, 10045 windows->pixel_info->background_color.pixel); 10046 width=(unsigned int) (*image)->columns; 10047 height=(unsigned int) (*image)->rows; 10048 x=0; 10049 y=0; 10050 if (windows->image.crop_geometry != (char *) NULL) 10051 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10052 &height); 10053 x_offset=(int) (width*(windows->image.x+x_offset)/ 10054 windows->image.ximage->width+x); 10055 y_offset=(int) (height*(windows->image.y+y_offset)/ 10056 windows->image.ximage->height+y); 10057 if ((x_offset < 0) || (y_offset < 0)) 10058 continue; 10059 if ((x_offset >= (int) (*image)->columns) || 10060 (y_offset >= (int) (*image)->rows)) 10061 continue; 10062 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10063 return(MagickFalse); 10064 (*image)->matte=MagickTrue; 10065 image_view=AcquireCacheView(*image); 10066 switch (method) 10067 { 10068 case PointMethod: 10069 default: 10070 { 10071 /* 10072 Update matte information using point algorithm. 10073 */ 10074 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10075 (ssize_t) y_offset,1,1,exception); 10076 if (q == (Quantum *) NULL) 10077 break; 10078 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10079 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10080 break; 10081 } 10082 case ReplaceMethod: 10083 { 10084 PixelPacket 10085 pixel, 10086 target; 10087 10088 /* 10089 Update matte information using replace algorithm. 10090 */ 10091 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10092 (ssize_t) y_offset,&target,exception); 10093 for (y=0; y < (int) (*image)->rows; y++) 10094 { 10095 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10096 (*image)->columns,1,exception); 10097 if (q == (Quantum *) NULL) 10098 break; 10099 for (x=0; x < (int) (*image)->columns; x++) 10100 { 10101 GetPixelPacket(*image,q,&pixel); 10102 if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target)) 10103 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10104 q+=GetPixelChannels(*image); 10105 } 10106 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10107 break; 10108 } 10109 break; 10110 } 10111 case FloodfillMethod: 10112 case FillToBorderMethod: 10113 { 10114 ChannelType 10115 channel_mask; 10116 10117 DrawInfo 10118 *draw_info; 10119 10120 PixelInfo 10121 target; 10122 10123 /* 10124 Update matte information using floodfill algorithm. 10125 */ 10126 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10127 (ssize_t) y_offset,&target,exception); 10128 if (method == FillToBorderMethod) 10129 { 10130 target.red=(MagickRealType) ScaleShortToQuantum( 10131 border_color.red); 10132 target.green=(MagickRealType) ScaleShortToQuantum( 10133 border_color.green); 10134 target.blue=(MagickRealType) ScaleShortToQuantum( 10135 border_color.blue); 10136 } 10137 draw_info=CloneDrawInfo(resource_info->image_info, 10138 (DrawInfo *) NULL); 10139 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10140 (char **) NULL)); 10141 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10142 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10143 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10144 MagickFalse : MagickTrue,exception); 10145 (void) SetPixelChannelMap(*image,channel_mask); 10146 draw_info=DestroyDrawInfo(draw_info); 10147 break; 10148 } 10149 case ResetMethod: 10150 { 10151 /* 10152 Update matte information using reset algorithm. 10153 */ 10154 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10155 return(MagickFalse); 10156 for (y=0; y < (int) (*image)->rows; y++) 10157 { 10158 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10159 (*image)->columns,1,exception); 10160 if (q == (Quantum *) NULL) 10161 break; 10162 for (x=0; x < (int) (*image)->columns; x++) 10163 { 10164 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10165 q+=GetPixelChannels(*image); 10166 } 10167 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10168 break; 10169 } 10170 if (StringToLong(matte) == (long) OpaqueAlpha) 10171 (*image)->matte=MagickFalse; 10172 break; 10173 } 10174 } 10175 image_view=DestroyCacheView(image_view); 10176 state&=(~UpdateConfigurationState); 10177 } 10178 } while ((state & ExitState) == 0); 10179 (void) XSelectInput(display,windows->image.id, 10180 windows->image.attributes.event_mask); 10181 XSetCursorState(display,windows,MagickFalse); 10182 (void) XFreeCursor(display,cursor); 10183 return(MagickTrue); 10184} 10185 10186/* 10187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10188% % 10189% % 10190% % 10191+ X O p e n I m a g e % 10192% % 10193% % 10194% % 10195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10196% 10197% XOpenImage() loads an image from a file. 10198% 10199% The format of the XOpenImage method is: 10200% 10201% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10202% XWindows *windows,const unsigned int command) 10203% 10204% A description of each parameter follows: 10205% 10206% o display: Specifies a connection to an X server; returned from 10207% XOpenDisplay. 10208% 10209% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10210% 10211% o windows: Specifies a pointer to a XWindows structure. 10212% 10213% o command: A value other than zero indicates that the file is selected 10214% from the command line argument list. 10215% 10216*/ 10217static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10218 XWindows *windows,const MagickBooleanType command) 10219{ 10220 const MagickInfo 10221 *magick_info; 10222 10223 ExceptionInfo 10224 *exception; 10225 10226 Image 10227 *nexus; 10228 10229 ImageInfo 10230 *image_info; 10231 10232 static char 10233 filename[MaxTextExtent] = "\0"; 10234 10235 /* 10236 Request file name from user. 10237 */ 10238 if (command == MagickFalse) 10239 XFileBrowserWidget(display,windows,"Open",filename); 10240 else 10241 { 10242 char 10243 **filelist, 10244 **files; 10245 10246 int 10247 count, 10248 status; 10249 10250 register int 10251 i, 10252 j; 10253 10254 /* 10255 Select next image from the command line. 10256 */ 10257 status=XGetCommand(display,windows->image.id,&files,&count); 10258 if (status == 0) 10259 { 10260 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10261 return((Image *) NULL); 10262 } 10263 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10264 if (filelist == (char **) NULL) 10265 { 10266 ThrowXWindowFatalException(ResourceLimitError, 10267 "MemoryAllocationFailed","..."); 10268 (void) XFreeStringList(files); 10269 return((Image *) NULL); 10270 } 10271 j=0; 10272 for (i=1; i < count; i++) 10273 if (*files[i] != '-') 10274 filelist[j++]=files[i]; 10275 filelist[j]=(char *) NULL; 10276 XListBrowserWidget(display,windows,&windows->widget, 10277 (const char **) filelist,"Load","Select Image to Load:",filename); 10278 filelist=(char **) RelinquishMagickMemory(filelist); 10279 (void) XFreeStringList(files); 10280 } 10281 if (*filename == '\0') 10282 return((Image *) NULL); 10283 image_info=CloneImageInfo(resource_info->image_info); 10284 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10285 (void *) NULL); 10286 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10287 exception=AcquireExceptionInfo(); 10288 (void) SetImageInfo(image_info,0,exception); 10289 if (LocaleCompare(image_info->magick,"X") == 0) 10290 { 10291 char 10292 seconds[MaxTextExtent]; 10293 10294 /* 10295 User may want to delay the X server screen grab. 10296 */ 10297 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10298 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10299 seconds); 10300 if (*seconds == '\0') 10301 return((Image *) NULL); 10302 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10303 } 10304 magick_info=GetMagickInfo(image_info->magick,exception); 10305 if ((magick_info != (const MagickInfo *) NULL) && 10306 (magick_info->raw != MagickFalse)) 10307 { 10308 char 10309 geometry[MaxTextExtent]; 10310 10311 /* 10312 Request image size from the user. 10313 */ 10314 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10315 if (image_info->size != (char *) NULL) 10316 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10317 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10318 geometry); 10319 (void) CloneString(&image_info->size,geometry); 10320 } 10321 /* 10322 Load the image. 10323 */ 10324 XSetCursorState(display,windows,MagickTrue); 10325 XCheckRefreshWindows(display,windows); 10326 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10327 nexus=ReadImage(image_info,exception); 10328 CatchException(exception); 10329 XSetCursorState(display,windows,MagickFalse); 10330 if (nexus != (Image *) NULL) 10331 XClientMessage(display,windows->image.id,windows->im_protocols, 10332 windows->im_next_image,CurrentTime); 10333 else 10334 { 10335 char 10336 *text, 10337 **textlist; 10338 10339 /* 10340 Unknown image format. 10341 */ 10342 text=FileToString(filename,~0,exception); 10343 if (text == (char *) NULL) 10344 return((Image *) NULL); 10345 textlist=StringToList(text); 10346 if (textlist != (char **) NULL) 10347 { 10348 char 10349 title[MaxTextExtent]; 10350 10351 register int 10352 i; 10353 10354 (void) FormatLocaleString(title,MaxTextExtent, 10355 "Unknown format: %s",filename); 10356 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10357 (const char **) textlist); 10358 for (i=0; textlist[i] != (char *) NULL; i++) 10359 textlist[i]=DestroyString(textlist[i]); 10360 textlist=(char **) RelinquishMagickMemory(textlist); 10361 } 10362 text=DestroyString(text); 10363 } 10364 exception=DestroyExceptionInfo(exception); 10365 image_info=DestroyImageInfo(image_info); 10366 return(nexus); 10367} 10368 10369/* 10370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10371% % 10372% % 10373% % 10374+ X P a n I m a g e % 10375% % 10376% % 10377% % 10378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10379% 10380% XPanImage() pans the image until the mouse button is released. 10381% 10382% The format of the XPanImage method is: 10383% 10384% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10385% 10386% A description of each parameter follows: 10387% 10388% o display: Specifies a connection to an X server; returned from 10389% XOpenDisplay. 10390% 10391% o windows: Specifies a pointer to a XWindows structure. 10392% 10393% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10394% the entire image is refreshed. 10395% 10396*/ 10397static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10398{ 10399 char 10400 text[MaxTextExtent]; 10401 10402 Cursor 10403 cursor; 10404 10405 MagickRealType 10406 x_factor, 10407 y_factor; 10408 10409 RectangleInfo 10410 pan_info; 10411 10412 size_t 10413 state; 10414 10415 /* 10416 Define cursor. 10417 */ 10418 if ((windows->image.ximage->width > (int) windows->image.width) && 10419 (windows->image.ximage->height > (int) windows->image.height)) 10420 cursor=XCreateFontCursor(display,XC_fleur); 10421 else 10422 if (windows->image.ximage->width > (int) windows->image.width) 10423 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10424 else 10425 if (windows->image.ximage->height > (int) windows->image.height) 10426 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10427 else 10428 cursor=XCreateFontCursor(display,XC_arrow); 10429 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10430 /* 10431 Pan image as pointer moves until the mouse button is released. 10432 */ 10433 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10434 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10435 pan_info.width=windows->pan.width*windows->image.width/ 10436 windows->image.ximage->width; 10437 pan_info.height=windows->pan.height*windows->image.height/ 10438 windows->image.ximage->height; 10439 pan_info.x=0; 10440 pan_info.y=0; 10441 state=UpdateConfigurationState; 10442 do 10443 { 10444 switch (event->type) 10445 { 10446 case ButtonPress: 10447 { 10448 /* 10449 User choose an initial pan location. 10450 */ 10451 pan_info.x=(ssize_t) event->xbutton.x; 10452 pan_info.y=(ssize_t) event->xbutton.y; 10453 state|=UpdateConfigurationState; 10454 break; 10455 } 10456 case ButtonRelease: 10457 { 10458 /* 10459 User has finished panning the image. 10460 */ 10461 pan_info.x=(ssize_t) event->xbutton.x; 10462 pan_info.y=(ssize_t) event->xbutton.y; 10463 state|=UpdateConfigurationState | ExitState; 10464 break; 10465 } 10466 case MotionNotify: 10467 { 10468 pan_info.x=(ssize_t) event->xmotion.x; 10469 pan_info.y=(ssize_t) event->xmotion.y; 10470 state|=UpdateConfigurationState; 10471 } 10472 default: 10473 break; 10474 } 10475 if ((state & UpdateConfigurationState) != 0) 10476 { 10477 /* 10478 Check boundary conditions. 10479 */ 10480 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10481 pan_info.x=0; 10482 else 10483 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10484 if (pan_info.x < 0) 10485 pan_info.x=0; 10486 else 10487 if ((int) (pan_info.x+windows->image.width) > 10488 windows->image.ximage->width) 10489 pan_info.x=(ssize_t) 10490 (windows->image.ximage->width-windows->image.width); 10491 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10492 pan_info.y=0; 10493 else 10494 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10495 if (pan_info.y < 0) 10496 pan_info.y=0; 10497 else 10498 if ((int) (pan_info.y+windows->image.height) > 10499 windows->image.ximage->height) 10500 pan_info.y=(ssize_t) 10501 (windows->image.ximage->height-windows->image.height); 10502 if ((windows->image.x != (int) pan_info.x) || 10503 (windows->image.y != (int) pan_info.y)) 10504 { 10505 /* 10506 Display image pan offset. 10507 */ 10508 windows->image.x=(int) pan_info.x; 10509 windows->image.y=(int) pan_info.y; 10510 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10511 windows->image.width,windows->image.height,windows->image.x, 10512 windows->image.y); 10513 XInfoWidget(display,windows,text); 10514 /* 10515 Refresh Image window. 10516 */ 10517 XDrawPanRectangle(display,windows); 10518 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10519 } 10520 state&=(~UpdateConfigurationState); 10521 } 10522 /* 10523 Wait for next event. 10524 */ 10525 if ((state & ExitState) == 0) 10526 XScreenEvent(display,windows,event); 10527 } while ((state & ExitState) == 0); 10528 /* 10529 Restore cursor. 10530 */ 10531 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10532 (void) XFreeCursor(display,cursor); 10533 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10534} 10535 10536/* 10537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10538% % 10539% % 10540% % 10541+ X P a s t e I m a g e % 10542% % 10543% % 10544% % 10545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10546% 10547% XPasteImage() pastes an image previously saved with XCropImage in the X 10548% window image at a location the user chooses with the pointer. 10549% 10550% The format of the XPasteImage method is: 10551% 10552% MagickBooleanType XPasteImage(Display *display, 10553% XResourceInfo *resource_info,XWindows *windows,Image *image, 10554% ExceptionInfo *exception) 10555% 10556% A description of each parameter follows: 10557% 10558% o display: Specifies a connection to an X server; returned from 10559% XOpenDisplay. 10560% 10561% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10562% 10563% o windows: Specifies a pointer to a XWindows structure. 10564% 10565% o image: the image; returned from ReadImage. 10566% 10567% o exception: return any errors or warnings in this structure. 10568% 10569*/ 10570static MagickBooleanType XPasteImage(Display *display, 10571 XResourceInfo *resource_info,XWindows *windows,Image *image, 10572 ExceptionInfo *exception) 10573{ 10574 static const char 10575 *PasteMenu[] = 10576 { 10577 "Operator", 10578 "Help", 10579 "Dismiss", 10580 (char *) NULL 10581 }; 10582 10583 static const ModeType 10584 PasteCommands[] = 10585 { 10586 PasteOperatorsCommand, 10587 PasteHelpCommand, 10588 PasteDismissCommand 10589 }; 10590 10591 static CompositeOperator 10592 compose = CopyCompositeOp; 10593 10594 char 10595 text[MaxTextExtent]; 10596 10597 Cursor 10598 cursor; 10599 10600 Image 10601 *paste_image; 10602 10603 int 10604 entry, 10605 id, 10606 x, 10607 y; 10608 10609 MagickRealType 10610 scale_factor; 10611 10612 RectangleInfo 10613 highlight_info, 10614 paste_info; 10615 10616 unsigned int 10617 height, 10618 width; 10619 10620 size_t 10621 state; 10622 10623 XEvent 10624 event; 10625 10626 /* 10627 Copy image. 10628 */ 10629 if (resource_info->copy_image == (Image *) NULL) 10630 return(MagickFalse); 10631 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10632 /* 10633 Map Command widget. 10634 */ 10635 (void) CloneString(&windows->command.name,"Paste"); 10636 windows->command.data=1; 10637 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10638 (void) XMapRaised(display,windows->command.id); 10639 XClientMessage(display,windows->image.id,windows->im_protocols, 10640 windows->im_update_widget,CurrentTime); 10641 /* 10642 Track pointer until button 1 is pressed. 10643 */ 10644 XSetCursorState(display,windows,MagickFalse); 10645 XQueryPosition(display,windows->image.id,&x,&y); 10646 (void) XSelectInput(display,windows->image.id, 10647 windows->image.attributes.event_mask | PointerMotionMask); 10648 paste_info.x=(ssize_t) windows->image.x+x; 10649 paste_info.y=(ssize_t) windows->image.y+y; 10650 paste_info.width=0; 10651 paste_info.height=0; 10652 cursor=XCreateFontCursor(display,XC_ul_angle); 10653 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10654 state=DefaultState; 10655 do 10656 { 10657 if (windows->info.mapped != MagickFalse) 10658 { 10659 /* 10660 Display pointer position. 10661 */ 10662 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10663 (long) paste_info.x,(long) paste_info.y); 10664 XInfoWidget(display,windows,text); 10665 } 10666 highlight_info=paste_info; 10667 highlight_info.x=paste_info.x-windows->image.x; 10668 highlight_info.y=paste_info.y-windows->image.y; 10669 XHighlightRectangle(display,windows->image.id, 10670 windows->image.highlight_context,&highlight_info); 10671 /* 10672 Wait for next event. 10673 */ 10674 XScreenEvent(display,windows,&event); 10675 XHighlightRectangle(display,windows->image.id, 10676 windows->image.highlight_context,&highlight_info); 10677 if (event.xany.window == windows->command.id) 10678 { 10679 /* 10680 Select a command from the Command widget. 10681 */ 10682 id=XCommandWidget(display,windows,PasteMenu,&event); 10683 if (id < 0) 10684 continue; 10685 switch (PasteCommands[id]) 10686 { 10687 case PasteOperatorsCommand: 10688 { 10689 char 10690 command[MaxTextExtent], 10691 **operators; 10692 10693 /* 10694 Select a command from the pop-up menu. 10695 */ 10696 operators=GetCommandOptions(MagickComposeOptions); 10697 if (operators == (char **) NULL) 10698 break; 10699 entry=XMenuWidget(display,windows,PasteMenu[id], 10700 (const char **) operators,command); 10701 if (entry >= 0) 10702 compose=(CompositeOperator) ParseCommandOption( 10703 MagickComposeOptions,MagickFalse,operators[entry]); 10704 operators=DestroyStringList(operators); 10705 break; 10706 } 10707 case PasteHelpCommand: 10708 { 10709 XTextViewWidget(display,resource_info,windows,MagickFalse, 10710 "Help Viewer - Image Composite",ImagePasteHelp); 10711 break; 10712 } 10713 case PasteDismissCommand: 10714 { 10715 /* 10716 Prematurely exit. 10717 */ 10718 state|=EscapeState; 10719 state|=ExitState; 10720 break; 10721 } 10722 default: 10723 break; 10724 } 10725 continue; 10726 } 10727 switch (event.type) 10728 { 10729 case ButtonPress: 10730 { 10731 if (image->debug != MagickFalse) 10732 (void) LogMagickEvent(X11Event,GetMagickModule(), 10733 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10734 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10735 if (event.xbutton.button != Button1) 10736 break; 10737 if (event.xbutton.window != windows->image.id) 10738 break; 10739 /* 10740 Paste rectangle is relative to image configuration. 10741 */ 10742 width=(unsigned int) image->columns; 10743 height=(unsigned int) image->rows; 10744 x=0; 10745 y=0; 10746 if (windows->image.crop_geometry != (char *) NULL) 10747 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10748 &width,&height); 10749 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10750 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10751 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10752 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10753 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10754 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10755 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10756 break; 10757 } 10758 case ButtonRelease: 10759 { 10760 if (image->debug != MagickFalse) 10761 (void) LogMagickEvent(X11Event,GetMagickModule(), 10762 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10763 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10764 if (event.xbutton.button != Button1) 10765 break; 10766 if (event.xbutton.window != windows->image.id) 10767 break; 10768 if ((paste_info.width != 0) && (paste_info.height != 0)) 10769 { 10770 /* 10771 User has selected the location of the paste image. 10772 */ 10773 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10774 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10775 state|=ExitState; 10776 } 10777 break; 10778 } 10779 case Expose: 10780 break; 10781 case KeyPress: 10782 { 10783 char 10784 command[MaxTextExtent]; 10785 10786 KeySym 10787 key_symbol; 10788 10789 int 10790 length; 10791 10792 if (event.xkey.window != windows->image.id) 10793 break; 10794 /* 10795 Respond to a user key press. 10796 */ 10797 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10798 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10799 *(command+length)='\0'; 10800 if (image->debug != MagickFalse) 10801 (void) LogMagickEvent(X11Event,GetMagickModule(), 10802 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10803 switch ((int) key_symbol) 10804 { 10805 case XK_Escape: 10806 case XK_F20: 10807 { 10808 /* 10809 Prematurely exit. 10810 */ 10811 paste_image=DestroyImage(paste_image); 10812 state|=EscapeState; 10813 state|=ExitState; 10814 break; 10815 } 10816 case XK_F1: 10817 case XK_Help: 10818 { 10819 (void) XSetFunction(display,windows->image.highlight_context, 10820 GXcopy); 10821 XTextViewWidget(display,resource_info,windows,MagickFalse, 10822 "Help Viewer - Image Composite",ImagePasteHelp); 10823 (void) XSetFunction(display,windows->image.highlight_context, 10824 GXinvert); 10825 break; 10826 } 10827 default: 10828 { 10829 (void) XBell(display,0); 10830 break; 10831 } 10832 } 10833 break; 10834 } 10835 case MotionNotify: 10836 { 10837 /* 10838 Map and unmap Info widget as text cursor crosses its boundaries. 10839 */ 10840 x=event.xmotion.x; 10841 y=event.xmotion.y; 10842 if (windows->info.mapped != MagickFalse) 10843 { 10844 if ((x < (int) (windows->info.x+windows->info.width)) && 10845 (y < (int) (windows->info.y+windows->info.height))) 10846 (void) XWithdrawWindow(display,windows->info.id, 10847 windows->info.screen); 10848 } 10849 else 10850 if ((x > (int) (windows->info.x+windows->info.width)) || 10851 (y > (int) (windows->info.y+windows->info.height))) 10852 (void) XMapWindow(display,windows->info.id); 10853 paste_info.x=(ssize_t) windows->image.x+x; 10854 paste_info.y=(ssize_t) windows->image.y+y; 10855 break; 10856 } 10857 default: 10858 { 10859 if (image->debug != MagickFalse) 10860 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10861 event.type); 10862 break; 10863 } 10864 } 10865 } while ((state & ExitState) == 0); 10866 (void) XSelectInput(display,windows->image.id, 10867 windows->image.attributes.event_mask); 10868 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10869 XSetCursorState(display,windows,MagickFalse); 10870 (void) XFreeCursor(display,cursor); 10871 if ((state & EscapeState) != 0) 10872 return(MagickTrue); 10873 /* 10874 Image pasting is relative to image configuration. 10875 */ 10876 XSetCursorState(display,windows,MagickTrue); 10877 XCheckRefreshWindows(display,windows); 10878 width=(unsigned int) image->columns; 10879 height=(unsigned int) image->rows; 10880 x=0; 10881 y=0; 10882 if (windows->image.crop_geometry != (char *) NULL) 10883 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10884 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10885 paste_info.x+=x; 10886 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10887 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10888 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10889 paste_info.y+=y; 10890 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10891 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10892 /* 10893 Paste image with X Image window. 10894 */ 10895 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y); 10896 paste_image=DestroyImage(paste_image); 10897 XSetCursorState(display,windows,MagickFalse); 10898 /* 10899 Update image colormap. 10900 */ 10901 XConfigureImageColormap(display,resource_info,windows,image); 10902 (void) XConfigureImage(display,resource_info,windows,image,exception); 10903 return(MagickTrue); 10904} 10905 10906/* 10907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10908% % 10909% % 10910% % 10911+ X P r i n t I m a g e % 10912% % 10913% % 10914% % 10915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10916% 10917% XPrintImage() prints an image to a Postscript printer. 10918% 10919% The format of the XPrintImage method is: 10920% 10921% MagickBooleanType XPrintImage(Display *display, 10922% XResourceInfo *resource_info,XWindows *windows,Image *image, 10923% ExceptionInfo *exception) 10924% 10925% A description of each parameter follows: 10926% 10927% o display: Specifies a connection to an X server; returned from 10928% XOpenDisplay. 10929% 10930% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10931% 10932% o windows: Specifies a pointer to a XWindows structure. 10933% 10934% o image: the image. 10935% 10936% o exception: return any errors or warnings in this structure. 10937% 10938*/ 10939static MagickBooleanType XPrintImage(Display *display, 10940 XResourceInfo *resource_info,XWindows *windows,Image *image, 10941 ExceptionInfo *exception) 10942{ 10943 char 10944 filename[MaxTextExtent], 10945 geometry[MaxTextExtent]; 10946 10947 Image 10948 *print_image; 10949 10950 ImageInfo 10951 *image_info; 10952 10953 MagickStatusType 10954 status; 10955 10956 /* 10957 Request Postscript page geometry from user. 10958 */ 10959 image_info=CloneImageInfo(resource_info->image_info); 10960 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10961 if (image_info->page != (char *) NULL) 10962 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10963 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10964 "Select Postscript Page Geometry:",geometry); 10965 if (*geometry == '\0') 10966 return(MagickTrue); 10967 image_info->page=GetPageGeometry(geometry); 10968 /* 10969 Apply image transforms. 10970 */ 10971 XSetCursorState(display,windows,MagickTrue); 10972 XCheckRefreshWindows(display,windows); 10973 print_image=CloneImage(image,0,0,MagickTrue,exception); 10974 if (print_image == (Image *) NULL) 10975 return(MagickFalse); 10976 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 10977 windows->image.ximage->width,windows->image.ximage->height); 10978 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry); 10979 /* 10980 Print image. 10981 */ 10982 (void) AcquireUniqueFilename(filename); 10983 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 10984 filename); 10985 status=WriteImage(image_info,print_image,exception); 10986 (void) RelinquishUniqueFileResource(filename); 10987 print_image=DestroyImage(print_image); 10988 image_info=DestroyImageInfo(image_info); 10989 XSetCursorState(display,windows,MagickFalse); 10990 return(status != 0 ? MagickTrue : MagickFalse); 10991} 10992 10993/* 10994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10995% % 10996% % 10997% % 10998+ X R O I I m a g e % 10999% % 11000% % 11001% % 11002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11003% 11004% XROIImage() applies an image processing technique to a region of interest. 11005% 11006% The format of the XROIImage method is: 11007% 11008% MagickBooleanType XROIImage(Display *display, 11009% XResourceInfo *resource_info,XWindows *windows,Image **image, 11010% ExceptionInfo *exception) 11011% 11012% A description of each parameter follows: 11013% 11014% o display: Specifies a connection to an X server; returned from 11015% XOpenDisplay. 11016% 11017% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11018% 11019% o windows: Specifies a pointer to a XWindows structure. 11020% 11021% o image: the image; returned from ReadImage. 11022% 11023% o exception: return any errors or warnings in this structure. 11024% 11025*/ 11026static MagickBooleanType XROIImage(Display *display, 11027 XResourceInfo *resource_info,XWindows *windows,Image **image, 11028 ExceptionInfo *exception) 11029{ 11030#define ApplyMenus 7 11031 11032 static const char 11033 *ROIMenu[] = 11034 { 11035 "Help", 11036 "Dismiss", 11037 (char *) NULL 11038 }, 11039 *ApplyMenu[] = 11040 { 11041 "File", 11042 "Edit", 11043 "Transform", 11044 "Enhance", 11045 "Effects", 11046 "F/X", 11047 "Miscellany", 11048 "Help", 11049 "Dismiss", 11050 (char *) NULL 11051 }, 11052 *FileMenu[] = 11053 { 11054 "Save...", 11055 "Print...", 11056 (char *) NULL 11057 }, 11058 *EditMenu[] = 11059 { 11060 "Undo", 11061 "Redo", 11062 (char *) NULL 11063 }, 11064 *TransformMenu[] = 11065 { 11066 "Flop", 11067 "Flip", 11068 "Rotate Right", 11069 "Rotate Left", 11070 (char *) NULL 11071 }, 11072 *EnhanceMenu[] = 11073 { 11074 "Hue...", 11075 "Saturation...", 11076 "Brightness...", 11077 "Gamma...", 11078 "Spiff", 11079 "Dull", 11080 "Contrast Stretch...", 11081 "Sigmoidal Contrast...", 11082 "Normalize", 11083 "Equalize", 11084 "Negate", 11085 "Grayscale", 11086 "Map...", 11087 "Quantize...", 11088 (char *) NULL 11089 }, 11090 *EffectsMenu[] = 11091 { 11092 "Despeckle", 11093 "Emboss", 11094 "Reduce Noise", 11095 "Add Noise", 11096 "Sharpen...", 11097 "Blur...", 11098 "Threshold...", 11099 "Edge Detect...", 11100 "Spread...", 11101 "Shade...", 11102 "Raise...", 11103 "Segment...", 11104 (char *) NULL 11105 }, 11106 *FXMenu[] = 11107 { 11108 "Solarize...", 11109 "Sepia Tone...", 11110 "Swirl...", 11111 "Implode...", 11112 "Vignette...", 11113 "Wave...", 11114 "Oil Paint...", 11115 "Charcoal Draw...", 11116 (char *) NULL 11117 }, 11118 *MiscellanyMenu[] = 11119 { 11120 "Image Info", 11121 "Zoom Image", 11122 "Show Preview...", 11123 "Show Histogram", 11124 "Show Matte", 11125 (char *) NULL 11126 }; 11127 11128 static const char 11129 **Menus[ApplyMenus] = 11130 { 11131 FileMenu, 11132 EditMenu, 11133 TransformMenu, 11134 EnhanceMenu, 11135 EffectsMenu, 11136 FXMenu, 11137 MiscellanyMenu 11138 }; 11139 11140 static const CommandType 11141 ApplyCommands[] = 11142 { 11143 NullCommand, 11144 NullCommand, 11145 NullCommand, 11146 NullCommand, 11147 NullCommand, 11148 NullCommand, 11149 NullCommand, 11150 HelpCommand, 11151 QuitCommand 11152 }, 11153 FileCommands[] = 11154 { 11155 SaveCommand, 11156 PrintCommand 11157 }, 11158 EditCommands[] = 11159 { 11160 UndoCommand, 11161 RedoCommand 11162 }, 11163 TransformCommands[] = 11164 { 11165 FlopCommand, 11166 FlipCommand, 11167 RotateRightCommand, 11168 RotateLeftCommand 11169 }, 11170 EnhanceCommands[] = 11171 { 11172 HueCommand, 11173 SaturationCommand, 11174 BrightnessCommand, 11175 GammaCommand, 11176 SpiffCommand, 11177 DullCommand, 11178 ContrastStretchCommand, 11179 SigmoidalContrastCommand, 11180 NormalizeCommand, 11181 EqualizeCommand, 11182 NegateCommand, 11183 GrayscaleCommand, 11184 MapCommand, 11185 QuantizeCommand 11186 }, 11187 EffectsCommands[] = 11188 { 11189 DespeckleCommand, 11190 EmbossCommand, 11191 ReduceNoiseCommand, 11192 AddNoiseCommand, 11193 SharpenCommand, 11194 BlurCommand, 11195 EdgeDetectCommand, 11196 SpreadCommand, 11197 ShadeCommand, 11198 RaiseCommand, 11199 SegmentCommand 11200 }, 11201 FXCommands[] = 11202 { 11203 SolarizeCommand, 11204 SepiaToneCommand, 11205 SwirlCommand, 11206 ImplodeCommand, 11207 VignetteCommand, 11208 WaveCommand, 11209 OilPaintCommand, 11210 CharcoalDrawCommand 11211 }, 11212 MiscellanyCommands[] = 11213 { 11214 InfoCommand, 11215 ZoomCommand, 11216 ShowPreviewCommand, 11217 ShowHistogramCommand, 11218 ShowMatteCommand 11219 }, 11220 ROICommands[] = 11221 { 11222 ROIHelpCommand, 11223 ROIDismissCommand 11224 }; 11225 11226 static const CommandType 11227 *Commands[ApplyMenus] = 11228 { 11229 FileCommands, 11230 EditCommands, 11231 TransformCommands, 11232 EnhanceCommands, 11233 EffectsCommands, 11234 FXCommands, 11235 MiscellanyCommands 11236 }; 11237 11238 char 11239 command[MaxTextExtent], 11240 text[MaxTextExtent]; 11241 11242 CommandType 11243 command_type; 11244 11245 Cursor 11246 cursor; 11247 11248 Image 11249 *roi_image; 11250 11251 int 11252 entry, 11253 id, 11254 x, 11255 y; 11256 11257 MagickRealType 11258 scale_factor; 11259 11260 MagickProgressMonitor 11261 progress_monitor; 11262 11263 RectangleInfo 11264 crop_info, 11265 highlight_info, 11266 roi_info; 11267 11268 unsigned int 11269 height, 11270 width; 11271 11272 size_t 11273 state; 11274 11275 XEvent 11276 event; 11277 11278 /* 11279 Map Command widget. 11280 */ 11281 (void) CloneString(&windows->command.name,"ROI"); 11282 windows->command.data=0; 11283 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11284 (void) XMapRaised(display,windows->command.id); 11285 XClientMessage(display,windows->image.id,windows->im_protocols, 11286 windows->im_update_widget,CurrentTime); 11287 /* 11288 Track pointer until button 1 is pressed. 11289 */ 11290 XQueryPosition(display,windows->image.id,&x,&y); 11291 (void) XSelectInput(display,windows->image.id, 11292 windows->image.attributes.event_mask | PointerMotionMask); 11293 roi_info.x=(ssize_t) windows->image.x+x; 11294 roi_info.y=(ssize_t) windows->image.y+y; 11295 roi_info.width=0; 11296 roi_info.height=0; 11297 cursor=XCreateFontCursor(display,XC_fleur); 11298 state=DefaultState; 11299 do 11300 { 11301 if (windows->info.mapped != MagickFalse) 11302 { 11303 /* 11304 Display pointer position. 11305 */ 11306 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11307 (long) roi_info.x,(long) roi_info.y); 11308 XInfoWidget(display,windows,text); 11309 } 11310 /* 11311 Wait for next event. 11312 */ 11313 XScreenEvent(display,windows,&event); 11314 if (event.xany.window == windows->command.id) 11315 { 11316 /* 11317 Select a command from the Command widget. 11318 */ 11319 id=XCommandWidget(display,windows,ROIMenu,&event); 11320 if (id < 0) 11321 continue; 11322 switch (ROICommands[id]) 11323 { 11324 case ROIHelpCommand: 11325 { 11326 XTextViewWidget(display,resource_info,windows,MagickFalse, 11327 "Help Viewer - Region of Interest",ImageROIHelp); 11328 break; 11329 } 11330 case ROIDismissCommand: 11331 { 11332 /* 11333 Prematurely exit. 11334 */ 11335 state|=EscapeState; 11336 state|=ExitState; 11337 break; 11338 } 11339 default: 11340 break; 11341 } 11342 continue; 11343 } 11344 switch (event.type) 11345 { 11346 case ButtonPress: 11347 { 11348 if (event.xbutton.button != Button1) 11349 break; 11350 if (event.xbutton.window != windows->image.id) 11351 break; 11352 /* 11353 Note first corner of region of interest rectangle-- exit loop. 11354 */ 11355 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11356 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11357 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11358 state|=ExitState; 11359 break; 11360 } 11361 case ButtonRelease: 11362 break; 11363 case Expose: 11364 break; 11365 case KeyPress: 11366 { 11367 KeySym 11368 key_symbol; 11369 11370 if (event.xkey.window != windows->image.id) 11371 break; 11372 /* 11373 Respond to a user key press. 11374 */ 11375 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11376 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11377 switch ((int) key_symbol) 11378 { 11379 case XK_Escape: 11380 case XK_F20: 11381 { 11382 /* 11383 Prematurely exit. 11384 */ 11385 state|=EscapeState; 11386 state|=ExitState; 11387 break; 11388 } 11389 case XK_F1: 11390 case XK_Help: 11391 { 11392 XTextViewWidget(display,resource_info,windows,MagickFalse, 11393 "Help Viewer - Region of Interest",ImageROIHelp); 11394 break; 11395 } 11396 default: 11397 { 11398 (void) XBell(display,0); 11399 break; 11400 } 11401 } 11402 break; 11403 } 11404 case MotionNotify: 11405 { 11406 /* 11407 Map and unmap Info widget as text cursor crosses its boundaries. 11408 */ 11409 x=event.xmotion.x; 11410 y=event.xmotion.y; 11411 if (windows->info.mapped != MagickFalse) 11412 { 11413 if ((x < (int) (windows->info.x+windows->info.width)) && 11414 (y < (int) (windows->info.y+windows->info.height))) 11415 (void) XWithdrawWindow(display,windows->info.id, 11416 windows->info.screen); 11417 } 11418 else 11419 if ((x > (int) (windows->info.x+windows->info.width)) || 11420 (y > (int) (windows->info.y+windows->info.height))) 11421 (void) XMapWindow(display,windows->info.id); 11422 roi_info.x=(ssize_t) windows->image.x+x; 11423 roi_info.y=(ssize_t) windows->image.y+y; 11424 break; 11425 } 11426 default: 11427 break; 11428 } 11429 } while ((state & ExitState) == 0); 11430 (void) XSelectInput(display,windows->image.id, 11431 windows->image.attributes.event_mask); 11432 if ((state & EscapeState) != 0) 11433 { 11434 /* 11435 User want to exit without region of interest. 11436 */ 11437 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11438 (void) XFreeCursor(display,cursor); 11439 return(MagickTrue); 11440 } 11441 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11442 do 11443 { 11444 /* 11445 Size rectangle as pointer moves until the mouse button is released. 11446 */ 11447 x=(int) roi_info.x; 11448 y=(int) roi_info.y; 11449 roi_info.width=0; 11450 roi_info.height=0; 11451 state=DefaultState; 11452 do 11453 { 11454 highlight_info=roi_info; 11455 highlight_info.x=roi_info.x-windows->image.x; 11456 highlight_info.y=roi_info.y-windows->image.y; 11457 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11458 { 11459 /* 11460 Display info and draw region of interest rectangle. 11461 */ 11462 if (windows->info.mapped == MagickFalse) 11463 (void) XMapWindow(display,windows->info.id); 11464 (void) FormatLocaleString(text,MaxTextExtent, 11465 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11466 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11467 XInfoWidget(display,windows,text); 11468 XHighlightRectangle(display,windows->image.id, 11469 windows->image.highlight_context,&highlight_info); 11470 } 11471 else 11472 if (windows->info.mapped != MagickFalse) 11473 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11474 /* 11475 Wait for next event. 11476 */ 11477 XScreenEvent(display,windows,&event); 11478 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11479 XHighlightRectangle(display,windows->image.id, 11480 windows->image.highlight_context,&highlight_info); 11481 switch (event.type) 11482 { 11483 case ButtonPress: 11484 { 11485 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11486 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11487 break; 11488 } 11489 case ButtonRelease: 11490 { 11491 /* 11492 User has committed to region of interest rectangle. 11493 */ 11494 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11495 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11496 XSetCursorState(display,windows,MagickFalse); 11497 state|=ExitState; 11498 if (LocaleCompare(windows->command.name,"Apply") == 0) 11499 break; 11500 (void) CloneString(&windows->command.name,"Apply"); 11501 windows->command.data=ApplyMenus; 11502 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11503 break; 11504 } 11505 case Expose: 11506 break; 11507 case MotionNotify: 11508 { 11509 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11510 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11511 } 11512 default: 11513 break; 11514 } 11515 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11516 ((state & ExitState) != 0)) 11517 { 11518 /* 11519 Check boundary conditions. 11520 */ 11521 if (roi_info.x < 0) 11522 roi_info.x=0; 11523 else 11524 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11525 roi_info.x=(ssize_t) windows->image.ximage->width; 11526 if ((int) roi_info.x < x) 11527 roi_info.width=(unsigned int) (x-roi_info.x); 11528 else 11529 { 11530 roi_info.width=(unsigned int) (roi_info.x-x); 11531 roi_info.x=(ssize_t) x; 11532 } 11533 if (roi_info.y < 0) 11534 roi_info.y=0; 11535 else 11536 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11537 roi_info.y=(ssize_t) windows->image.ximage->height; 11538 if ((int) roi_info.y < y) 11539 roi_info.height=(unsigned int) (y-roi_info.y); 11540 else 11541 { 11542 roi_info.height=(unsigned int) (roi_info.y-y); 11543 roi_info.y=(ssize_t) y; 11544 } 11545 } 11546 } while ((state & ExitState) == 0); 11547 /* 11548 Wait for user to grab a corner of the rectangle or press return. 11549 */ 11550 state=DefaultState; 11551 command_type=NullCommand; 11552 (void) XMapWindow(display,windows->info.id); 11553 do 11554 { 11555 if (windows->info.mapped != MagickFalse) 11556 { 11557 /* 11558 Display pointer position. 11559 */ 11560 (void) FormatLocaleString(text,MaxTextExtent, 11561 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11562 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11563 XInfoWidget(display,windows,text); 11564 } 11565 highlight_info=roi_info; 11566 highlight_info.x=roi_info.x-windows->image.x; 11567 highlight_info.y=roi_info.y-windows->image.y; 11568 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11569 { 11570 state|=EscapeState; 11571 state|=ExitState; 11572 break; 11573 } 11574 if ((state & UpdateRegionState) != 0) 11575 { 11576 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11577 switch (command_type) 11578 { 11579 case UndoCommand: 11580 case RedoCommand: 11581 { 11582 (void) XMagickCommand(display,resource_info,windows,command_type, 11583 image,exception); 11584 break; 11585 } 11586 default: 11587 { 11588 /* 11589 Region of interest is relative to image configuration. 11590 */ 11591 progress_monitor=SetImageProgressMonitor(*image, 11592 (MagickProgressMonitor) NULL,(*image)->client_data); 11593 crop_info=roi_info; 11594 width=(unsigned int) (*image)->columns; 11595 height=(unsigned int) (*image)->rows; 11596 x=0; 11597 y=0; 11598 if (windows->image.crop_geometry != (char *) NULL) 11599 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11600 &width,&height); 11601 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11602 crop_info.x+=x; 11603 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11604 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11605 scale_factor=(MagickRealType) 11606 height/windows->image.ximage->height; 11607 crop_info.y+=y; 11608 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11609 crop_info.height=(unsigned int) 11610 (scale_factor*crop_info.height+0.5); 11611 roi_image=CropImage(*image,&crop_info,exception); 11612 (void) SetImageProgressMonitor(*image,progress_monitor, 11613 (*image)->client_data); 11614 if (roi_image == (Image *) NULL) 11615 continue; 11616 /* 11617 Apply image processing technique to the region of interest. 11618 */ 11619 windows->image.orphan=MagickTrue; 11620 (void) XMagickCommand(display,resource_info,windows,command_type, 11621 &roi_image,exception); 11622 progress_monitor=SetImageProgressMonitor(*image, 11623 (MagickProgressMonitor) NULL,(*image)->client_data); 11624 (void) XMagickCommand(display,resource_info,windows, 11625 SaveToUndoBufferCommand,image,exception); 11626 windows->image.orphan=MagickFalse; 11627 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11628 crop_info.x,crop_info.y); 11629 roi_image=DestroyImage(roi_image); 11630 (void) SetImageProgressMonitor(*image,progress_monitor, 11631 (*image)->client_data); 11632 break; 11633 } 11634 } 11635 if (command_type != InfoCommand) 11636 { 11637 XConfigureImageColormap(display,resource_info,windows,*image); 11638 (void) XConfigureImage(display,resource_info,windows,*image,exception); 11639 } 11640 XCheckRefreshWindows(display,windows); 11641 XInfoWidget(display,windows,text); 11642 (void) XSetFunction(display,windows->image.highlight_context, 11643 GXinvert); 11644 state&=(~UpdateRegionState); 11645 } 11646 XHighlightRectangle(display,windows->image.id, 11647 windows->image.highlight_context,&highlight_info); 11648 XScreenEvent(display,windows,&event); 11649 if (event.xany.window == windows->command.id) 11650 { 11651 /* 11652 Select a command from the Command widget. 11653 */ 11654 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11655 command_type=NullCommand; 11656 id=XCommandWidget(display,windows,ApplyMenu,&event); 11657 if (id >= 0) 11658 { 11659 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11660 command_type=ApplyCommands[id]; 11661 if (id < ApplyMenus) 11662 { 11663 /* 11664 Select a command from a pop-up menu. 11665 */ 11666 entry=XMenuWidget(display,windows,ApplyMenu[id], 11667 (const char **) Menus[id],command); 11668 if (entry >= 0) 11669 { 11670 (void) CopyMagickString(command,Menus[id][entry], 11671 MaxTextExtent); 11672 command_type=Commands[id][entry]; 11673 } 11674 } 11675 } 11676 (void) XSetFunction(display,windows->image.highlight_context, 11677 GXinvert); 11678 XHighlightRectangle(display,windows->image.id, 11679 windows->image.highlight_context,&highlight_info); 11680 if (command_type == HelpCommand) 11681 { 11682 (void) XSetFunction(display,windows->image.highlight_context, 11683 GXcopy); 11684 XTextViewWidget(display,resource_info,windows,MagickFalse, 11685 "Help Viewer - Region of Interest",ImageROIHelp); 11686 (void) XSetFunction(display,windows->image.highlight_context, 11687 GXinvert); 11688 continue; 11689 } 11690 if (command_type == QuitCommand) 11691 { 11692 /* 11693 exit. 11694 */ 11695 state|=EscapeState; 11696 state|=ExitState; 11697 continue; 11698 } 11699 if (command_type != NullCommand) 11700 state|=UpdateRegionState; 11701 continue; 11702 } 11703 XHighlightRectangle(display,windows->image.id, 11704 windows->image.highlight_context,&highlight_info); 11705 switch (event.type) 11706 { 11707 case ButtonPress: 11708 { 11709 x=windows->image.x; 11710 y=windows->image.y; 11711 if (event.xbutton.button != Button1) 11712 break; 11713 if (event.xbutton.window != windows->image.id) 11714 break; 11715 x=windows->image.x+event.xbutton.x; 11716 y=windows->image.y+event.xbutton.y; 11717 if ((x < (int) (roi_info.x+RoiDelta)) && 11718 (x > (int) (roi_info.x-RoiDelta)) && 11719 (y < (int) (roi_info.y+RoiDelta)) && 11720 (y > (int) (roi_info.y-RoiDelta))) 11721 { 11722 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11723 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11724 state|=UpdateConfigurationState; 11725 break; 11726 } 11727 if ((x < (int) (roi_info.x+RoiDelta)) && 11728 (x > (int) (roi_info.x-RoiDelta)) && 11729 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11730 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11731 { 11732 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11733 state|=UpdateConfigurationState; 11734 break; 11735 } 11736 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11737 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11738 (y < (int) (roi_info.y+RoiDelta)) && 11739 (y > (int) (roi_info.y-RoiDelta))) 11740 { 11741 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11742 state|=UpdateConfigurationState; 11743 break; 11744 } 11745 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11746 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11747 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11748 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11749 { 11750 state|=UpdateConfigurationState; 11751 break; 11752 } 11753 } 11754 case ButtonRelease: 11755 { 11756 if (event.xbutton.window == windows->pan.id) 11757 if ((highlight_info.x != crop_info.x-windows->image.x) || 11758 (highlight_info.y != crop_info.y-windows->image.y)) 11759 XHighlightRectangle(display,windows->image.id, 11760 windows->image.highlight_context,&highlight_info); 11761 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11762 event.xbutton.time); 11763 break; 11764 } 11765 case Expose: 11766 { 11767 if (event.xexpose.window == windows->image.id) 11768 if (event.xexpose.count == 0) 11769 { 11770 event.xexpose.x=(int) highlight_info.x; 11771 event.xexpose.y=(int) highlight_info.y; 11772 event.xexpose.width=(int) highlight_info.width; 11773 event.xexpose.height=(int) highlight_info.height; 11774 XRefreshWindow(display,&windows->image,&event); 11775 } 11776 if (event.xexpose.window == windows->info.id) 11777 if (event.xexpose.count == 0) 11778 XInfoWidget(display,windows,text); 11779 break; 11780 } 11781 case KeyPress: 11782 { 11783 KeySym 11784 key_symbol; 11785 11786 if (event.xkey.window != windows->image.id) 11787 break; 11788 /* 11789 Respond to a user key press. 11790 */ 11791 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11792 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11793 switch ((int) key_symbol) 11794 { 11795 case XK_Shift_L: 11796 case XK_Shift_R: 11797 break; 11798 case XK_Escape: 11799 case XK_F20: 11800 state|=EscapeState; 11801 case XK_Return: 11802 { 11803 state|=ExitState; 11804 break; 11805 } 11806 case XK_Home: 11807 case XK_KP_Home: 11808 { 11809 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11810 roi_info.y=(ssize_t) (windows->image.height/2L- 11811 roi_info.height/2L); 11812 break; 11813 } 11814 case XK_Left: 11815 case XK_KP_Left: 11816 { 11817 roi_info.x--; 11818 break; 11819 } 11820 case XK_Up: 11821 case XK_KP_Up: 11822 case XK_Next: 11823 { 11824 roi_info.y--; 11825 break; 11826 } 11827 case XK_Right: 11828 case XK_KP_Right: 11829 { 11830 roi_info.x++; 11831 break; 11832 } 11833 case XK_Prior: 11834 case XK_Down: 11835 case XK_KP_Down: 11836 { 11837 roi_info.y++; 11838 break; 11839 } 11840 case XK_F1: 11841 case XK_Help: 11842 { 11843 (void) XSetFunction(display,windows->image.highlight_context, 11844 GXcopy); 11845 XTextViewWidget(display,resource_info,windows,MagickFalse, 11846 "Help Viewer - Region of Interest",ImageROIHelp); 11847 (void) XSetFunction(display,windows->image.highlight_context, 11848 GXinvert); 11849 break; 11850 } 11851 default: 11852 { 11853 command_type=XImageWindowCommand(display,resource_info,windows, 11854 event.xkey.state,key_symbol,image,exception); 11855 if (command_type != NullCommand) 11856 state|=UpdateRegionState; 11857 break; 11858 } 11859 } 11860 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11861 event.xkey.time); 11862 break; 11863 } 11864 case KeyRelease: 11865 break; 11866 case MotionNotify: 11867 { 11868 if (event.xbutton.window != windows->image.id) 11869 break; 11870 /* 11871 Map and unmap Info widget as text cursor crosses its boundaries. 11872 */ 11873 x=event.xmotion.x; 11874 y=event.xmotion.y; 11875 if (windows->info.mapped != MagickFalse) 11876 { 11877 if ((x < (int) (windows->info.x+windows->info.width)) && 11878 (y < (int) (windows->info.y+windows->info.height))) 11879 (void) XWithdrawWindow(display,windows->info.id, 11880 windows->info.screen); 11881 } 11882 else 11883 if ((x > (int) (windows->info.x+windows->info.width)) || 11884 (y > (int) (windows->info.y+windows->info.height))) 11885 (void) XMapWindow(display,windows->info.id); 11886 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11887 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11888 break; 11889 } 11890 case SelectionRequest: 11891 { 11892 XSelectionEvent 11893 notify; 11894 11895 XSelectionRequestEvent 11896 *request; 11897 11898 /* 11899 Set primary selection. 11900 */ 11901 (void) FormatLocaleString(text,MaxTextExtent, 11902 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11903 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11904 request=(&(event.xselectionrequest)); 11905 (void) XChangeProperty(request->display,request->requestor, 11906 request->property,request->target,8,PropModeReplace, 11907 (unsigned char *) text,(int) strlen(text)); 11908 notify.type=SelectionNotify; 11909 notify.display=request->display; 11910 notify.requestor=request->requestor; 11911 notify.selection=request->selection; 11912 notify.target=request->target; 11913 notify.time=request->time; 11914 if (request->property == None) 11915 notify.property=request->target; 11916 else 11917 notify.property=request->property; 11918 (void) XSendEvent(request->display,request->requestor,False,0, 11919 (XEvent *) ¬ify); 11920 } 11921 default: 11922 break; 11923 } 11924 if ((state & UpdateConfigurationState) != 0) 11925 { 11926 (void) XPutBackEvent(display,&event); 11927 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11928 break; 11929 } 11930 } while ((state & ExitState) == 0); 11931 } while ((state & ExitState) == 0); 11932 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11933 XSetCursorState(display,windows,MagickFalse); 11934 if ((state & EscapeState) != 0) 11935 return(MagickTrue); 11936 return(MagickTrue); 11937} 11938 11939/* 11940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11941% % 11942% % 11943% % 11944+ X R o t a t e I m a g e % 11945% % 11946% % 11947% % 11948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11949% 11950% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11951% rotation angle is computed from the slope of a line drawn by the user. 11952% 11953% The format of the XRotateImage method is: 11954% 11955% MagickBooleanType XRotateImage(Display *display, 11956% XResourceInfo *resource_info,XWindows *windows,double degrees, 11957% Image **image,ExceptionInfo *exception) 11958% 11959% A description of each parameter follows: 11960% 11961% o display: Specifies a connection to an X server; returned from 11962% XOpenDisplay. 11963% 11964% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11965% 11966% o windows: Specifies a pointer to a XWindows structure. 11967% 11968% o degrees: Specifies the number of degrees to rotate the image. 11969% 11970% o image: the image. 11971% 11972% o exception: return any errors or warnings in this structure. 11973% 11974*/ 11975static MagickBooleanType XRotateImage(Display *display, 11976 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 11977 ExceptionInfo *exception) 11978{ 11979 static const char 11980 *RotateMenu[] = 11981 { 11982 "Pixel Color", 11983 "Direction", 11984 "Help", 11985 "Dismiss", 11986 (char *) NULL 11987 }; 11988 11989 static ModeType 11990 direction = HorizontalRotateCommand; 11991 11992 static const ModeType 11993 DirectionCommands[] = 11994 { 11995 HorizontalRotateCommand, 11996 VerticalRotateCommand 11997 }, 11998 RotateCommands[] = 11999 { 12000 RotateColorCommand, 12001 RotateDirectionCommand, 12002 RotateHelpCommand, 12003 RotateDismissCommand 12004 }; 12005 12006 static unsigned int 12007 pen_id = 0; 12008 12009 char 12010 command[MaxTextExtent], 12011 text[MaxTextExtent]; 12012 12013 Image 12014 *rotate_image; 12015 12016 int 12017 id, 12018 x, 12019 y; 12020 12021 MagickRealType 12022 normalized_degrees; 12023 12024 register int 12025 i; 12026 12027 unsigned int 12028 height, 12029 rotations, 12030 width; 12031 12032 if (degrees == 0.0) 12033 { 12034 unsigned int 12035 distance; 12036 12037 size_t 12038 state; 12039 12040 XEvent 12041 event; 12042 12043 XSegment 12044 rotate_info; 12045 12046 /* 12047 Map Command widget. 12048 */ 12049 (void) CloneString(&windows->command.name,"Rotate"); 12050 windows->command.data=2; 12051 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12052 (void) XMapRaised(display,windows->command.id); 12053 XClientMessage(display,windows->image.id,windows->im_protocols, 12054 windows->im_update_widget,CurrentTime); 12055 /* 12056 Wait for first button press. 12057 */ 12058 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12059 XQueryPosition(display,windows->image.id,&x,&y); 12060 rotate_info.x1=x; 12061 rotate_info.y1=y; 12062 rotate_info.x2=x; 12063 rotate_info.y2=y; 12064 state=DefaultState; 12065 do 12066 { 12067 XHighlightLine(display,windows->image.id, 12068 windows->image.highlight_context,&rotate_info); 12069 /* 12070 Wait for next event. 12071 */ 12072 XScreenEvent(display,windows,&event); 12073 XHighlightLine(display,windows->image.id, 12074 windows->image.highlight_context,&rotate_info); 12075 if (event.xany.window == windows->command.id) 12076 { 12077 /* 12078 Select a command from the Command widget. 12079 */ 12080 id=XCommandWidget(display,windows,RotateMenu,&event); 12081 if (id < 0) 12082 continue; 12083 (void) XSetFunction(display,windows->image.highlight_context, 12084 GXcopy); 12085 switch (RotateCommands[id]) 12086 { 12087 case RotateColorCommand: 12088 { 12089 const char 12090 *ColorMenu[MaxNumberPens]; 12091 12092 int 12093 pen_number; 12094 12095 XColor 12096 color; 12097 12098 /* 12099 Initialize menu selections. 12100 */ 12101 for (i=0; i < (int) (MaxNumberPens-2); i++) 12102 ColorMenu[i]=resource_info->pen_colors[i]; 12103 ColorMenu[MaxNumberPens-2]="Browser..."; 12104 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12105 /* 12106 Select a pen color from the pop-up menu. 12107 */ 12108 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12109 (const char **) ColorMenu,command); 12110 if (pen_number < 0) 12111 break; 12112 if (pen_number == (MaxNumberPens-2)) 12113 { 12114 static char 12115 color_name[MaxTextExtent] = "gray"; 12116 12117 /* 12118 Select a pen color from a dialog. 12119 */ 12120 resource_info->pen_colors[pen_number]=color_name; 12121 XColorBrowserWidget(display,windows,"Select",color_name); 12122 if (*color_name == '\0') 12123 break; 12124 } 12125 /* 12126 Set pen color. 12127 */ 12128 (void) XParseColor(display,windows->map_info->colormap, 12129 resource_info->pen_colors[pen_number],&color); 12130 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12131 (unsigned int) MaxColors,&color); 12132 windows->pixel_info->pen_colors[pen_number]=color; 12133 pen_id=(unsigned int) pen_number; 12134 break; 12135 } 12136 case RotateDirectionCommand: 12137 { 12138 static const char 12139 *Directions[] = 12140 { 12141 "horizontal", 12142 "vertical", 12143 (char *) NULL, 12144 }; 12145 12146 /* 12147 Select a command from the pop-up menu. 12148 */ 12149 id=XMenuWidget(display,windows,RotateMenu[id], 12150 Directions,command); 12151 if (id >= 0) 12152 direction=DirectionCommands[id]; 12153 break; 12154 } 12155 case RotateHelpCommand: 12156 { 12157 XTextViewWidget(display,resource_info,windows,MagickFalse, 12158 "Help Viewer - Image Rotation",ImageRotateHelp); 12159 break; 12160 } 12161 case RotateDismissCommand: 12162 { 12163 /* 12164 Prematurely exit. 12165 */ 12166 state|=EscapeState; 12167 state|=ExitState; 12168 break; 12169 } 12170 default: 12171 break; 12172 } 12173 (void) XSetFunction(display,windows->image.highlight_context, 12174 GXinvert); 12175 continue; 12176 } 12177 switch (event.type) 12178 { 12179 case ButtonPress: 12180 { 12181 if (event.xbutton.button != Button1) 12182 break; 12183 if (event.xbutton.window != windows->image.id) 12184 break; 12185 /* 12186 exit loop. 12187 */ 12188 (void) XSetFunction(display,windows->image.highlight_context, 12189 GXcopy); 12190 rotate_info.x1=event.xbutton.x; 12191 rotate_info.y1=event.xbutton.y; 12192 state|=ExitState; 12193 break; 12194 } 12195 case ButtonRelease: 12196 break; 12197 case Expose: 12198 break; 12199 case KeyPress: 12200 { 12201 char 12202 command[MaxTextExtent]; 12203 12204 KeySym 12205 key_symbol; 12206 12207 if (event.xkey.window != windows->image.id) 12208 break; 12209 /* 12210 Respond to a user key press. 12211 */ 12212 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12213 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12214 switch ((int) key_symbol) 12215 { 12216 case XK_Escape: 12217 case XK_F20: 12218 { 12219 /* 12220 Prematurely exit. 12221 */ 12222 state|=EscapeState; 12223 state|=ExitState; 12224 break; 12225 } 12226 case XK_F1: 12227 case XK_Help: 12228 { 12229 (void) XSetFunction(display,windows->image.highlight_context, 12230 GXcopy); 12231 XTextViewWidget(display,resource_info,windows,MagickFalse, 12232 "Help Viewer - Image Rotation",ImageRotateHelp); 12233 (void) XSetFunction(display,windows->image.highlight_context, 12234 GXinvert); 12235 break; 12236 } 12237 default: 12238 { 12239 (void) XBell(display,0); 12240 break; 12241 } 12242 } 12243 break; 12244 } 12245 case MotionNotify: 12246 { 12247 rotate_info.x1=event.xmotion.x; 12248 rotate_info.y1=event.xmotion.y; 12249 } 12250 } 12251 rotate_info.x2=rotate_info.x1; 12252 rotate_info.y2=rotate_info.y1; 12253 if (direction == HorizontalRotateCommand) 12254 rotate_info.x2+=32; 12255 else 12256 rotate_info.y2-=32; 12257 } while ((state & ExitState) == 0); 12258 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12259 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12260 if ((state & EscapeState) != 0) 12261 return(MagickTrue); 12262 /* 12263 Draw line as pointer moves until the mouse button is released. 12264 */ 12265 distance=0; 12266 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12267 state=DefaultState; 12268 do 12269 { 12270 if (distance > 9) 12271 { 12272 /* 12273 Display info and draw rotation line. 12274 */ 12275 if (windows->info.mapped == MagickFalse) 12276 (void) XMapWindow(display,windows->info.id); 12277 (void) FormatLocaleString(text,MaxTextExtent," %g", 12278 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12279 XInfoWidget(display,windows,text); 12280 XHighlightLine(display,windows->image.id, 12281 windows->image.highlight_context,&rotate_info); 12282 } 12283 else 12284 if (windows->info.mapped != MagickFalse) 12285 (void) XWithdrawWindow(display,windows->info.id, 12286 windows->info.screen); 12287 /* 12288 Wait for next event. 12289 */ 12290 XScreenEvent(display,windows,&event); 12291 if (distance > 9) 12292 XHighlightLine(display,windows->image.id, 12293 windows->image.highlight_context,&rotate_info); 12294 switch (event.type) 12295 { 12296 case ButtonPress: 12297 break; 12298 case ButtonRelease: 12299 { 12300 /* 12301 User has committed to rotation line. 12302 */ 12303 rotate_info.x2=event.xbutton.x; 12304 rotate_info.y2=event.xbutton.y; 12305 state|=ExitState; 12306 break; 12307 } 12308 case Expose: 12309 break; 12310 case MotionNotify: 12311 { 12312 rotate_info.x2=event.xmotion.x; 12313 rotate_info.y2=event.xmotion.y; 12314 } 12315 default: 12316 break; 12317 } 12318 /* 12319 Check boundary conditions. 12320 */ 12321 if (rotate_info.x2 < 0) 12322 rotate_info.x2=0; 12323 else 12324 if (rotate_info.x2 > (int) windows->image.width) 12325 rotate_info.x2=(short) windows->image.width; 12326 if (rotate_info.y2 < 0) 12327 rotate_info.y2=0; 12328 else 12329 if (rotate_info.y2 > (int) windows->image.height) 12330 rotate_info.y2=(short) windows->image.height; 12331 /* 12332 Compute rotation angle from the slope of the line. 12333 */ 12334 degrees=0.0; 12335 distance=(unsigned int) 12336 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12337 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12338 if (distance > 9) 12339 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12340 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12341 } while ((state & ExitState) == 0); 12342 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12343 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12344 if (distance <= 9) 12345 return(MagickTrue); 12346 } 12347 if (direction == VerticalRotateCommand) 12348 degrees-=90.0; 12349 if (degrees == 0.0) 12350 return(MagickTrue); 12351 /* 12352 Rotate image. 12353 */ 12354 normalized_degrees=degrees; 12355 while (normalized_degrees < -45.0) 12356 normalized_degrees+=360.0; 12357 for (rotations=0; normalized_degrees > 45.0; rotations++) 12358 normalized_degrees-=90.0; 12359 if (normalized_degrees != 0.0) 12360 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12361 exception); 12362 XSetCursorState(display,windows,MagickTrue); 12363 XCheckRefreshWindows(display,windows); 12364 (*image)->background_color.red=ScaleShortToQuantum( 12365 windows->pixel_info->pen_colors[pen_id].red); 12366 (*image)->background_color.green=ScaleShortToQuantum( 12367 windows->pixel_info->pen_colors[pen_id].green); 12368 (*image)->background_color.blue=ScaleShortToQuantum( 12369 windows->pixel_info->pen_colors[pen_id].blue); 12370 rotate_image=RotateImage(*image,degrees,exception); 12371 XSetCursorState(display,windows,MagickFalse); 12372 if (rotate_image == (Image *) NULL) 12373 return(MagickFalse); 12374 *image=DestroyImage(*image); 12375 *image=rotate_image; 12376 if (windows->image.crop_geometry != (char *) NULL) 12377 { 12378 /* 12379 Rotate crop geometry. 12380 */ 12381 width=(unsigned int) (*image)->columns; 12382 height=(unsigned int) (*image)->rows; 12383 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12384 switch (rotations % 4) 12385 { 12386 default: 12387 case 0: 12388 break; 12389 case 1: 12390 { 12391 /* 12392 Rotate 90 degrees. 12393 */ 12394 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12395 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12396 (int) height-y,x); 12397 break; 12398 } 12399 case 2: 12400 { 12401 /* 12402 Rotate 180 degrees. 12403 */ 12404 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12405 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12406 break; 12407 } 12408 case 3: 12409 { 12410 /* 12411 Rotate 270 degrees. 12412 */ 12413 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12414 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12415 break; 12416 } 12417 } 12418 } 12419 if (windows->image.orphan != MagickFalse) 12420 return(MagickTrue); 12421 if (normalized_degrees != 0.0) 12422 { 12423 /* 12424 Update image colormap. 12425 */ 12426 windows->image.window_changes.width=(int) (*image)->columns; 12427 windows->image.window_changes.height=(int) (*image)->rows; 12428 if (windows->image.crop_geometry != (char *) NULL) 12429 { 12430 /* 12431 Obtain dimensions of image from crop geometry. 12432 */ 12433 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12434 &width,&height); 12435 windows->image.window_changes.width=(int) width; 12436 windows->image.window_changes.height=(int) height; 12437 } 12438 XConfigureImageColormap(display,resource_info,windows,*image); 12439 } 12440 else 12441 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12442 { 12443 windows->image.window_changes.width=windows->image.ximage->height; 12444 windows->image.window_changes.height=windows->image.ximage->width; 12445 } 12446 /* 12447 Update image configuration. 12448 */ 12449 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12450 return(MagickTrue); 12451} 12452 12453/* 12454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12455% % 12456% % 12457% % 12458+ X S a v e I m a g e % 12459% % 12460% % 12461% % 12462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12463% 12464% XSaveImage() saves an image to a file. 12465% 12466% The format of the XSaveImage method is: 12467% 12468% MagickBooleanType XSaveImage(Display *display, 12469% XResourceInfo *resource_info,XWindows *windows,Image *image, 12470% ExceptionInfo *exception) 12471% 12472% A description of each parameter follows: 12473% 12474% o display: Specifies a connection to an X server; returned from 12475% XOpenDisplay. 12476% 12477% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12478% 12479% o windows: Specifies a pointer to a XWindows structure. 12480% 12481% o image: the image. 12482% 12483% o exception: return any errors or warnings in this structure. 12484% 12485*/ 12486static MagickBooleanType XSaveImage(Display *display, 12487 XResourceInfo *resource_info,XWindows *windows,Image *image, 12488 ExceptionInfo *exception) 12489{ 12490 char 12491 filename[MaxTextExtent], 12492 geometry[MaxTextExtent]; 12493 12494 Image 12495 *save_image; 12496 12497 ImageInfo 12498 *image_info; 12499 12500 MagickStatusType 12501 status; 12502 12503 /* 12504 Request file name from user. 12505 */ 12506 if (resource_info->write_filename != (char *) NULL) 12507 (void) CopyMagickString(filename,resource_info->write_filename, 12508 MaxTextExtent); 12509 else 12510 { 12511 char 12512 path[MaxTextExtent]; 12513 12514 int 12515 status; 12516 12517 GetPathComponent(image->filename,HeadPath,path); 12518 GetPathComponent(image->filename,TailPath,filename); 12519 if (*path != '\0') 12520 { 12521 status=chdir(path); 12522 if (status == -1) 12523 (void) ThrowMagickException(exception,GetMagickModule(), 12524 FileOpenError,"UnableToOpenFile","%s",path); 12525 } 12526 } 12527 XFileBrowserWidget(display,windows,"Save",filename); 12528 if (*filename == '\0') 12529 return(MagickTrue); 12530 if (IsPathAccessible(filename) != MagickFalse) 12531 { 12532 int 12533 status; 12534 12535 /* 12536 File exists-- seek user's permission before overwriting. 12537 */ 12538 status=XConfirmWidget(display,windows,"Overwrite",filename); 12539 if (status <= 0) 12540 return(MagickTrue); 12541 } 12542 image_info=CloneImageInfo(resource_info->image_info); 12543 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12544 (void) SetImageInfo(image_info,1,exception); 12545 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12546 (LocaleCompare(image_info->magick,"JPG") == 0)) 12547 { 12548 char 12549 quality[MaxTextExtent]; 12550 12551 int 12552 status; 12553 12554 /* 12555 Request JPEG quality from user. 12556 */ 12557 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12558 image->quality); 12559 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12560 quality); 12561 if (*quality == '\0') 12562 return(MagickTrue); 12563 image->quality=StringToUnsignedLong(quality); 12564 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12565 } 12566 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12567 (LocaleCompare(image_info->magick,"PDF") == 0) || 12568 (LocaleCompare(image_info->magick,"PS") == 0) || 12569 (LocaleCompare(image_info->magick,"PS2") == 0)) 12570 { 12571 char 12572 geometry[MaxTextExtent]; 12573 12574 /* 12575 Request page geometry from user. 12576 */ 12577 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12578 if (LocaleCompare(image_info->magick,"PDF") == 0) 12579 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12580 if (image_info->page != (char *) NULL) 12581 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12582 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12583 "Select page geometry:",geometry); 12584 if (*geometry != '\0') 12585 image_info->page=GetPageGeometry(geometry); 12586 } 12587 /* 12588 Apply image transforms. 12589 */ 12590 XSetCursorState(display,windows,MagickTrue); 12591 XCheckRefreshWindows(display,windows); 12592 save_image=CloneImage(image,0,0,MagickTrue,exception); 12593 if (save_image == (Image *) NULL) 12594 return(MagickFalse); 12595 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12596 windows->image.ximage->width,windows->image.ximage->height); 12597 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry); 12598 /* 12599 Write image. 12600 */ 12601 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12602 status=WriteImage(image_info,save_image,exception); 12603 if (status != MagickFalse) 12604 image->taint=MagickFalse; 12605 save_image=DestroyImage(save_image); 12606 image_info=DestroyImageInfo(image_info); 12607 XSetCursorState(display,windows,MagickFalse); 12608 return(status != 0 ? MagickTrue : MagickFalse); 12609} 12610 12611/* 12612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12613% % 12614% % 12615% % 12616+ X S c r e e n E v e n t % 12617% % 12618% % 12619% % 12620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12621% 12622% XScreenEvent() handles global events associated with the Pan and Magnify 12623% windows. 12624% 12625% The format of the XScreenEvent function is: 12626% 12627% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12628% 12629% A description of each parameter follows: 12630% 12631% o display: Specifies a pointer to the Display structure; returned from 12632% XOpenDisplay. 12633% 12634% o windows: Specifies a pointer to a XWindows structure. 12635% 12636% o event: Specifies a pointer to a X11 XEvent structure. 12637% 12638% 12639*/ 12640 12641#if defined(__cplusplus) || defined(c_plusplus) 12642extern "C" { 12643#endif 12644 12645static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12646{ 12647 register XWindows 12648 *windows; 12649 12650 windows=(XWindows *) data; 12651 if ((event->type == ClientMessage) && 12652 (event->xclient.window == windows->image.id)) 12653 return(MagickFalse); 12654 return(MagickTrue); 12655} 12656 12657#if defined(__cplusplus) || defined(c_plusplus) 12658} 12659#endif 12660 12661static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12662{ 12663 register int 12664 x, 12665 y; 12666 12667 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12668 if (event->xany.window == windows->command.id) 12669 return; 12670 switch (event->type) 12671 { 12672 case ButtonPress: 12673 case ButtonRelease: 12674 { 12675 if ((event->xbutton.button == Button3) && 12676 (event->xbutton.state & Mod1Mask)) 12677 { 12678 /* 12679 Convert Alt-Button3 to Button2. 12680 */ 12681 event->xbutton.button=Button2; 12682 event->xbutton.state&=(~Mod1Mask); 12683 } 12684 if (event->xbutton.window == windows->backdrop.id) 12685 { 12686 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12687 event->xbutton.time); 12688 break; 12689 } 12690 if (event->xbutton.window == windows->pan.id) 12691 { 12692 XPanImage(display,windows,event); 12693 break; 12694 } 12695 if (event->xbutton.window == windows->image.id) 12696 if (event->xbutton.button == Button2) 12697 { 12698 /* 12699 Update magnified image. 12700 */ 12701 x=event->xbutton.x; 12702 y=event->xbutton.y; 12703 if (x < 0) 12704 x=0; 12705 else 12706 if (x >= (int) windows->image.width) 12707 x=(int) (windows->image.width-1); 12708 windows->magnify.x=(int) windows->image.x+x; 12709 if (y < 0) 12710 y=0; 12711 else 12712 if (y >= (int) windows->image.height) 12713 y=(int) (windows->image.height-1); 12714 windows->magnify.y=windows->image.y+y; 12715 if (windows->magnify.mapped == MagickFalse) 12716 (void) XMapRaised(display,windows->magnify.id); 12717 XMakeMagnifyImage(display,windows); 12718 if (event->type == ButtonRelease) 12719 (void) XWithdrawWindow(display,windows->info.id, 12720 windows->info.screen); 12721 break; 12722 } 12723 break; 12724 } 12725 case ClientMessage: 12726 { 12727 /* 12728 If client window delete message, exit. 12729 */ 12730 if (event->xclient.message_type != windows->wm_protocols) 12731 break; 12732 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12733 break; 12734 if (event->xclient.window == windows->magnify.id) 12735 { 12736 (void) XWithdrawWindow(display,windows->magnify.id, 12737 windows->magnify.screen); 12738 break; 12739 } 12740 break; 12741 } 12742 case ConfigureNotify: 12743 { 12744 if (event->xconfigure.window == windows->magnify.id) 12745 { 12746 unsigned int 12747 magnify; 12748 12749 /* 12750 Magnify window has a new configuration. 12751 */ 12752 windows->magnify.width=(unsigned int) event->xconfigure.width; 12753 windows->magnify.height=(unsigned int) event->xconfigure.height; 12754 if (windows->magnify.mapped == MagickFalse) 12755 break; 12756 magnify=1; 12757 while ((int) magnify <= event->xconfigure.width) 12758 magnify<<=1; 12759 while ((int) magnify <= event->xconfigure.height) 12760 magnify<<=1; 12761 magnify>>=1; 12762 if (((int) magnify != event->xconfigure.width) || 12763 ((int) magnify != event->xconfigure.height)) 12764 { 12765 XWindowChanges 12766 window_changes; 12767 12768 window_changes.width=(int) magnify; 12769 window_changes.height=(int) magnify; 12770 (void) XReconfigureWMWindow(display,windows->magnify.id, 12771 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12772 &window_changes); 12773 break; 12774 } 12775 XMakeMagnifyImage(display,windows); 12776 break; 12777 } 12778 break; 12779 } 12780 case Expose: 12781 { 12782 if (event->xexpose.window == windows->image.id) 12783 { 12784 XRefreshWindow(display,&windows->image,event); 12785 break; 12786 } 12787 if (event->xexpose.window == windows->pan.id) 12788 if (event->xexpose.count == 0) 12789 { 12790 XDrawPanRectangle(display,windows); 12791 break; 12792 } 12793 if (event->xexpose.window == windows->magnify.id) 12794 if (event->xexpose.count == 0) 12795 { 12796 XMakeMagnifyImage(display,windows); 12797 break; 12798 } 12799 break; 12800 } 12801 case KeyPress: 12802 { 12803 char 12804 command[MaxTextExtent]; 12805 12806 KeySym 12807 key_symbol; 12808 12809 if (event->xkey.window != windows->magnify.id) 12810 break; 12811 /* 12812 Respond to a user key press. 12813 */ 12814 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12815 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12816 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12817 break; 12818 } 12819 case MapNotify: 12820 { 12821 if (event->xmap.window == windows->magnify.id) 12822 { 12823 windows->magnify.mapped=MagickTrue; 12824 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12825 break; 12826 } 12827 if (event->xmap.window == windows->info.id) 12828 { 12829 windows->info.mapped=MagickTrue; 12830 break; 12831 } 12832 break; 12833 } 12834 case MotionNotify: 12835 { 12836 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12837 if (event->xmotion.window == windows->image.id) 12838 if (windows->magnify.mapped != MagickFalse) 12839 { 12840 /* 12841 Update magnified image. 12842 */ 12843 x=event->xmotion.x; 12844 y=event->xmotion.y; 12845 if (x < 0) 12846 x=0; 12847 else 12848 if (x >= (int) windows->image.width) 12849 x=(int) (windows->image.width-1); 12850 windows->magnify.x=(int) windows->image.x+x; 12851 if (y < 0) 12852 y=0; 12853 else 12854 if (y >= (int) windows->image.height) 12855 y=(int) (windows->image.height-1); 12856 windows->magnify.y=windows->image.y+y; 12857 XMakeMagnifyImage(display,windows); 12858 } 12859 break; 12860 } 12861 case UnmapNotify: 12862 { 12863 if (event->xunmap.window == windows->magnify.id) 12864 { 12865 windows->magnify.mapped=MagickFalse; 12866 break; 12867 } 12868 if (event->xunmap.window == windows->info.id) 12869 { 12870 windows->info.mapped=MagickFalse; 12871 break; 12872 } 12873 break; 12874 } 12875 default: 12876 break; 12877 } 12878} 12879 12880/* 12881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12882% % 12883% % 12884% % 12885+ X S e t C r o p G e o m e t r y % 12886% % 12887% % 12888% % 12889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12890% 12891% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12892% and translates it to a cropping geometry relative to the image. 12893% 12894% The format of the XSetCropGeometry method is: 12895% 12896% void XSetCropGeometry(Display *display,XWindows *windows, 12897% RectangleInfo *crop_info,Image *image) 12898% 12899% A description of each parameter follows: 12900% 12901% o display: Specifies a connection to an X server; returned from 12902% XOpenDisplay. 12903% 12904% o windows: Specifies a pointer to a XWindows structure. 12905% 12906% o crop_info: A pointer to a RectangleInfo that defines a region of the 12907% Image window to crop. 12908% 12909% o image: the image. 12910% 12911*/ 12912static void XSetCropGeometry(Display *display,XWindows *windows, 12913 RectangleInfo *crop_info,Image *image) 12914{ 12915 char 12916 text[MaxTextExtent]; 12917 12918 int 12919 x, 12920 y; 12921 12922 MagickRealType 12923 scale_factor; 12924 12925 unsigned int 12926 height, 12927 width; 12928 12929 if (windows->info.mapped != MagickFalse) 12930 { 12931 /* 12932 Display info on cropping rectangle. 12933 */ 12934 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12935 (double) crop_info->width,(double) crop_info->height,(double) 12936 crop_info->x,(double) crop_info->y); 12937 XInfoWidget(display,windows,text); 12938 } 12939 /* 12940 Cropping geometry is relative to any previous crop geometry. 12941 */ 12942 x=0; 12943 y=0; 12944 width=(unsigned int) image->columns; 12945 height=(unsigned int) image->rows; 12946 if (windows->image.crop_geometry != (char *) NULL) 12947 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12948 else 12949 windows->image.crop_geometry=AcquireString((char *) NULL); 12950 /* 12951 Define the crop geometry string from the cropping rectangle. 12952 */ 12953 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12954 if (crop_info->x > 0) 12955 x+=(int) (scale_factor*crop_info->x+0.5); 12956 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12957 if (width == 0) 12958 width=1; 12959 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12960 if (crop_info->y > 0) 12961 y+=(int) (scale_factor*crop_info->y+0.5); 12962 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12963 if (height == 0) 12964 height=1; 12965 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12966 "%ux%u%+d%+d",width,height,x,y); 12967} 12968 12969/* 12970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12971% % 12972% % 12973% % 12974+ X T i l e I m a g e % 12975% % 12976% % 12977% % 12978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12979% 12980% XTileImage() loads or deletes a selected tile from a visual image directory. 12981% The load or delete command is chosen from a menu. 12982% 12983% The format of the XTileImage method is: 12984% 12985% Image *XTileImage(Display *display,XResourceInfo *resource_info, 12986% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 12987% 12988% A description of each parameter follows: 12989% 12990% o tile_image: XTileImage reads or deletes the tile image 12991% and returns it. A null image is returned if an error occurs. 12992% 12993% o display: Specifies a connection to an X server; returned from 12994% XOpenDisplay. 12995% 12996% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12997% 12998% o windows: Specifies a pointer to a XWindows structure. 12999% 13000% o image: the image; returned from ReadImage. 13001% 13002% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13003% the entire image is refreshed. 13004% 13005% o exception: return any errors or warnings in this structure. 13006% 13007*/ 13008static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13009 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13010{ 13011 static const char 13012 *VerbMenu[] = 13013 { 13014 "Load", 13015 "Next", 13016 "Former", 13017 "Delete", 13018 "Update", 13019 (char *) NULL, 13020 }; 13021 13022 static const ModeType 13023 TileCommands[] = 13024 { 13025 TileLoadCommand, 13026 TileNextCommand, 13027 TileFormerCommand, 13028 TileDeleteCommand, 13029 TileUpdateCommand 13030 }; 13031 13032 char 13033 command[MaxTextExtent], 13034 filename[MaxTextExtent]; 13035 13036 Image 13037 *tile_image; 13038 13039 int 13040 id, 13041 status, 13042 tile, 13043 x, 13044 y; 13045 13046 MagickRealType 13047 scale_factor; 13048 13049 register char 13050 *p, 13051 *q; 13052 13053 register int 13054 i; 13055 13056 unsigned int 13057 height, 13058 width; 13059 13060 /* 13061 Tile image is relative to montage image configuration. 13062 */ 13063 x=0; 13064 y=0; 13065 width=(unsigned int) image->columns; 13066 height=(unsigned int) image->rows; 13067 if (windows->image.crop_geometry != (char *) NULL) 13068 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13069 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13070 event->xbutton.x+=windows->image.x; 13071 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13072 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13073 event->xbutton.y+=windows->image.y; 13074 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13075 /* 13076 Determine size and location of each tile in the visual image directory. 13077 */ 13078 width=(unsigned int) image->columns; 13079 height=(unsigned int) image->rows; 13080 x=0; 13081 y=0; 13082 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13083 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13084 (event->xbutton.x-x)/width; 13085 if (tile < 0) 13086 { 13087 /* 13088 Button press is outside any tile. 13089 */ 13090 (void) XBell(display,0); 13091 return((Image *) NULL); 13092 } 13093 /* 13094 Determine file name from the tile directory. 13095 */ 13096 p=image->directory; 13097 for (i=tile; (i != 0) && (*p != '\0'); ) 13098 { 13099 if (*p == '\n') 13100 i--; 13101 p++; 13102 } 13103 if (*p == '\0') 13104 { 13105 /* 13106 Button press is outside any tile. 13107 */ 13108 (void) XBell(display,0); 13109 return((Image *) NULL); 13110 } 13111 /* 13112 Select a command from the pop-up menu. 13113 */ 13114 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13115 if (id < 0) 13116 return((Image *) NULL); 13117 q=p; 13118 while ((*q != '\n') && (*q != '\0')) 13119 q++; 13120 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13121 /* 13122 Perform command for the selected tile. 13123 */ 13124 XSetCursorState(display,windows,MagickTrue); 13125 XCheckRefreshWindows(display,windows); 13126 tile_image=NewImageList(); 13127 switch (TileCommands[id]) 13128 { 13129 case TileLoadCommand: 13130 { 13131 /* 13132 Load tile image. 13133 */ 13134 XCheckRefreshWindows(display,windows); 13135 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13136 MaxTextExtent); 13137 (void) CopyMagickString(resource_info->image_info->filename,filename, 13138 MaxTextExtent); 13139 tile_image=ReadImage(resource_info->image_info,exception); 13140 CatchException(exception); 13141 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13142 break; 13143 } 13144 case TileNextCommand: 13145 { 13146 /* 13147 Display next image. 13148 */ 13149 XClientMessage(display,windows->image.id,windows->im_protocols, 13150 windows->im_next_image,CurrentTime); 13151 break; 13152 } 13153 case TileFormerCommand: 13154 { 13155 /* 13156 Display former image. 13157 */ 13158 XClientMessage(display,windows->image.id,windows->im_protocols, 13159 windows->im_former_image,CurrentTime); 13160 break; 13161 } 13162 case TileDeleteCommand: 13163 { 13164 /* 13165 Delete tile image. 13166 */ 13167 if (IsPathAccessible(filename) == MagickFalse) 13168 { 13169 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13170 break; 13171 } 13172 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13173 if (status <= 0) 13174 break; 13175 status=remove(filename) != 0 ? MagickTrue : MagickFalse; 13176 if (status != MagickFalse) 13177 { 13178 XNoticeWidget(display,windows,"Unable to delete image file:", 13179 filename); 13180 break; 13181 } 13182 } 13183 case TileUpdateCommand: 13184 { 13185 int 13186 x_offset, 13187 y_offset; 13188 13189 PixelPacket 13190 pixel; 13191 13192 register int 13193 j; 13194 13195 register Quantum 13196 *s; 13197 13198 /* 13199 Ensure all the images exist. 13200 */ 13201 tile=0; 13202 for (p=image->directory; *p != '\0'; p++) 13203 { 13204 CacheView 13205 *image_view; 13206 13207 q=p; 13208 while ((*q != '\n') && (*q != '\0')) 13209 q++; 13210 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13211 p=q; 13212 if (IsPathAccessible(filename) != MagickFalse) 13213 { 13214 tile++; 13215 continue; 13216 } 13217 /* 13218 Overwrite tile with background color. 13219 */ 13220 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13221 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13222 image_view=AcquireCacheView(image); 13223 (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception); 13224 for (i=0; i < (int) height; i++) 13225 { 13226 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13227 y_offset+i,width,1,exception); 13228 if (s == (Quantum *) NULL) 13229 break; 13230 for (j=0; j < (int) width; j++) 13231 { 13232 SetPixelPacket(image,&pixel,s); 13233 s+=GetPixelChannels(image); 13234 } 13235 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13236 break; 13237 } 13238 image_view=DestroyCacheView(image_view); 13239 tile++; 13240 } 13241 windows->image.window_changes.width=(int) image->columns; 13242 windows->image.window_changes.height=(int) image->rows; 13243 XConfigureImageColormap(display,resource_info,windows,image); 13244 (void) XConfigureImage(display,resource_info,windows,image,exception); 13245 break; 13246 } 13247 default: 13248 break; 13249 } 13250 XSetCursorState(display,windows,MagickFalse); 13251 return(tile_image); 13252} 13253 13254/* 13255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13256% % 13257% % 13258% % 13259+ X T r a n s l a t e I m a g e % 13260% % 13261% % 13262% % 13263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13264% 13265% XTranslateImage() translates the image within an Image window by one pixel 13266% as specified by the key symbol. If the image has a `montage string the 13267% translation is respect to the width and height contained within the string. 13268% 13269% The format of the XTranslateImage method is: 13270% 13271% void XTranslateImage(Display *display,XWindows *windows, 13272% Image *image,const KeySym key_symbol) 13273% 13274% A description of each parameter follows: 13275% 13276% o display: Specifies a connection to an X server; returned from 13277% XOpenDisplay. 13278% 13279% o windows: Specifies a pointer to a XWindows structure. 13280% 13281% o image: the image. 13282% 13283% o key_symbol: Specifies a KeySym which indicates which side of the image 13284% to trim. 13285% 13286*/ 13287static void XTranslateImage(Display *display,XWindows *windows, 13288 Image *image,const KeySym key_symbol) 13289{ 13290 char 13291 text[MaxTextExtent]; 13292 13293 int 13294 x, 13295 y; 13296 13297 unsigned int 13298 x_offset, 13299 y_offset; 13300 13301 /* 13302 User specified a pan position offset. 13303 */ 13304 x_offset=windows->image.width; 13305 y_offset=windows->image.height; 13306 if (image->montage != (char *) NULL) 13307 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13308 switch ((int) key_symbol) 13309 { 13310 case XK_Home: 13311 case XK_KP_Home: 13312 { 13313 windows->image.x=(int) windows->image.width/2; 13314 windows->image.y=(int) windows->image.height/2; 13315 break; 13316 } 13317 case XK_Left: 13318 case XK_KP_Left: 13319 { 13320 windows->image.x-=x_offset; 13321 break; 13322 } 13323 case XK_Next: 13324 case XK_Up: 13325 case XK_KP_Up: 13326 { 13327 windows->image.y-=y_offset; 13328 break; 13329 } 13330 case XK_Right: 13331 case XK_KP_Right: 13332 { 13333 windows->image.x+=x_offset; 13334 break; 13335 } 13336 case XK_Prior: 13337 case XK_Down: 13338 case XK_KP_Down: 13339 { 13340 windows->image.y+=y_offset; 13341 break; 13342 } 13343 default: 13344 return; 13345 } 13346 /* 13347 Check boundary conditions. 13348 */ 13349 if (windows->image.x < 0) 13350 windows->image.x=0; 13351 else 13352 if ((int) (windows->image.x+windows->image.width) > 13353 windows->image.ximage->width) 13354 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13355 if (windows->image.y < 0) 13356 windows->image.y=0; 13357 else 13358 if ((int) (windows->image.y+windows->image.height) > 13359 windows->image.ximage->height) 13360 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13361 /* 13362 Refresh Image window. 13363 */ 13364 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13365 windows->image.width,windows->image.height,windows->image.x, 13366 windows->image.y); 13367 XInfoWidget(display,windows,text); 13368 XCheckRefreshWindows(display,windows); 13369 XDrawPanRectangle(display,windows); 13370 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13371 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13372} 13373 13374/* 13375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13376% % 13377% % 13378% % 13379+ X T r i m I m a g e % 13380% % 13381% % 13382% % 13383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13384% 13385% XTrimImage() trims the edges from the Image window. 13386% 13387% The format of the XTrimImage method is: 13388% 13389% MagickBooleanType XTrimImage(Display *display, 13390% XResourceInfo *resource_info,XWindows *windows,Image *image, 13391% ExceptionInfo *exception) 13392% 13393% A description of each parameter follows: 13394% 13395% o display: Specifies a connection to an X server; returned from 13396% XOpenDisplay. 13397% 13398% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13399% 13400% o windows: Specifies a pointer to a XWindows structure. 13401% 13402% o image: the image. 13403% 13404% o exception: return any errors or warnings in this structure. 13405% 13406*/ 13407static MagickBooleanType XTrimImage(Display *display, 13408 XResourceInfo *resource_info,XWindows *windows,Image *image, 13409 ExceptionInfo *exception) 13410{ 13411 RectangleInfo 13412 trim_info; 13413 13414 register int 13415 x, 13416 y; 13417 13418 size_t 13419 background, 13420 pixel; 13421 13422 /* 13423 Trim edges from image. 13424 */ 13425 XSetCursorState(display,windows,MagickTrue); 13426 XCheckRefreshWindows(display,windows); 13427 /* 13428 Crop the left edge. 13429 */ 13430 background=XGetPixel(windows->image.ximage,0,0); 13431 trim_info.width=(size_t) windows->image.ximage->width; 13432 for (x=0; x < windows->image.ximage->width; x++) 13433 { 13434 for (y=0; y < windows->image.ximage->height; y++) 13435 { 13436 pixel=XGetPixel(windows->image.ximage,x,y); 13437 if (pixel != background) 13438 break; 13439 } 13440 if (y < windows->image.ximage->height) 13441 break; 13442 } 13443 trim_info.x=(ssize_t) x; 13444 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13445 { 13446 XSetCursorState(display,windows,MagickFalse); 13447 return(MagickFalse); 13448 } 13449 /* 13450 Crop the right edge. 13451 */ 13452 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13453 for (x=windows->image.ximage->width-1; x != 0; x--) 13454 { 13455 for (y=0; y < windows->image.ximage->height; y++) 13456 { 13457 pixel=XGetPixel(windows->image.ximage,x,y); 13458 if (pixel != background) 13459 break; 13460 } 13461 if (y < windows->image.ximage->height) 13462 break; 13463 } 13464 trim_info.width=(size_t) (x-trim_info.x+1); 13465 /* 13466 Crop the top edge. 13467 */ 13468 background=XGetPixel(windows->image.ximage,0,0); 13469 trim_info.height=(size_t) windows->image.ximage->height; 13470 for (y=0; y < windows->image.ximage->height; y++) 13471 { 13472 for (x=0; x < windows->image.ximage->width; x++) 13473 { 13474 pixel=XGetPixel(windows->image.ximage,x,y); 13475 if (pixel != background) 13476 break; 13477 } 13478 if (x < windows->image.ximage->width) 13479 break; 13480 } 13481 trim_info.y=(ssize_t) y; 13482 /* 13483 Crop the bottom edge. 13484 */ 13485 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13486 for (y=windows->image.ximage->height-1; y != 0; y--) 13487 { 13488 for (x=0; x < windows->image.ximage->width; x++) 13489 { 13490 pixel=XGetPixel(windows->image.ximage,x,y); 13491 if (pixel != background) 13492 break; 13493 } 13494 if (x < windows->image.ximage->width) 13495 break; 13496 } 13497 trim_info.height=(size_t) y-trim_info.y+1; 13498 if (((unsigned int) trim_info.width != windows->image.width) || 13499 ((unsigned int) trim_info.height != windows->image.height)) 13500 { 13501 /* 13502 Reconfigure Image window as defined by the trimming rectangle. 13503 */ 13504 XSetCropGeometry(display,windows,&trim_info,image); 13505 windows->image.window_changes.width=(int) trim_info.width; 13506 windows->image.window_changes.height=(int) trim_info.height; 13507 (void) XConfigureImage(display,resource_info,windows,image,exception); 13508 } 13509 XSetCursorState(display,windows,MagickFalse); 13510 return(MagickTrue); 13511} 13512 13513/* 13514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13515% % 13516% % 13517% % 13518+ X V i s u a l D i r e c t o r y I m a g e % 13519% % 13520% % 13521% % 13522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13523% 13524% XVisualDirectoryImage() creates a Visual Image Directory. 13525% 13526% The format of the XVisualDirectoryImage method is: 13527% 13528% Image *XVisualDirectoryImage(Display *display, 13529% XResourceInfo *resource_info,XWindows *windows, 13530% ExceptionInfo *exception) 13531% 13532% A description of each parameter follows: 13533% 13534% o display: Specifies a connection to an X server; returned from 13535% XOpenDisplay. 13536% 13537% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13538% 13539% o windows: Specifies a pointer to a XWindows structure. 13540% 13541% o exception: return any errors or warnings in this structure. 13542% 13543*/ 13544static Image *XVisualDirectoryImage(Display *display, 13545 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13546{ 13547#define TileImageTag "Scale/Image" 13548#define XClientName "montage" 13549 13550 char 13551 **filelist; 13552 13553 Image 13554 *images, 13555 *montage_image, 13556 *next_image, 13557 *thumbnail_image; 13558 13559 ImageInfo 13560 *read_info; 13561 13562 int 13563 number_files; 13564 13565 MagickBooleanType 13566 backdrop; 13567 13568 MagickStatusType 13569 status; 13570 13571 MontageInfo 13572 *montage_info; 13573 13574 RectangleInfo 13575 geometry; 13576 13577 register int 13578 i; 13579 13580 static char 13581 filename[MaxTextExtent] = "\0", 13582 filenames[MaxTextExtent] = "*"; 13583 13584 XResourceInfo 13585 background_resources; 13586 13587 /* 13588 Request file name from user. 13589 */ 13590 XFileBrowserWidget(display,windows,"Directory",filenames); 13591 if (*filenames == '\0') 13592 return((Image *) NULL); 13593 /* 13594 Expand the filenames. 13595 */ 13596 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13597 if (filelist == (char **) NULL) 13598 { 13599 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13600 filenames); 13601 return((Image *) NULL); 13602 } 13603 number_files=1; 13604 filelist[0]=filenames; 13605 status=ExpandFilenames(&number_files,&filelist); 13606 if ((status == MagickFalse) || (number_files == 0)) 13607 { 13608 if (number_files == 0) 13609 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13610 else 13611 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13612 filenames); 13613 return((Image *) NULL); 13614 } 13615 /* 13616 Set image background resources. 13617 */ 13618 background_resources=(*resource_info); 13619 background_resources.window_id=AcquireString(""); 13620 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13621 "0x%lx",windows->image.id); 13622 background_resources.backdrop=MagickTrue; 13623 /* 13624 Read each image and convert them to a tile. 13625 */ 13626 backdrop=(windows->visual_info->klass == TrueColor) || 13627 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13628 read_info=CloneImageInfo(resource_info->image_info); 13629 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13630 (void) CloneString(&read_info->size,DefaultTileGeometry); 13631 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13632 (void *) NULL); 13633 images=NewImageList(); 13634 XSetCursorState(display,windows,MagickTrue); 13635 XCheckRefreshWindows(display,windows); 13636 for (i=0; i < (int) number_files; i++) 13637 { 13638 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13639 filelist[i]=DestroyString(filelist[i]); 13640 *read_info->magick='\0'; 13641 next_image=ReadImage(read_info,exception); 13642 CatchException(exception); 13643 if (next_image != (Image *) NULL) 13644 { 13645 (void) DeleteImageProperty(next_image,"label"); 13646 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13647 read_info,next_image,DefaultTileLabel,exception)); 13648 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13649 exception); 13650 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13651 geometry.height,exception); 13652 if (thumbnail_image != (Image *) NULL) 13653 { 13654 next_image=DestroyImage(next_image); 13655 next_image=thumbnail_image; 13656 } 13657 if (backdrop) 13658 { 13659 (void) XDisplayBackgroundImage(display,&background_resources, 13660 next_image,exception); 13661 XSetCursorState(display,windows,MagickTrue); 13662 } 13663 AppendImageToList(&images,next_image); 13664 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13665 { 13666 MagickBooleanType 13667 proceed; 13668 13669 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13670 (MagickSizeType) number_files); 13671 if (proceed == MagickFalse) 13672 break; 13673 } 13674 } 13675 } 13676 filelist=(char **) RelinquishMagickMemory(filelist); 13677 if (images == (Image *) NULL) 13678 { 13679 read_info=DestroyImageInfo(read_info); 13680 XSetCursorState(display,windows,MagickFalse); 13681 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13682 return((Image *) NULL); 13683 } 13684 /* 13685 Create the Visual Image Directory. 13686 */ 13687 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13688 montage_info->pointsize=10; 13689 if (resource_info->font != (char *) NULL) 13690 (void) CloneString(&montage_info->font,resource_info->font); 13691 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13692 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13693 images),exception); 13694 images=DestroyImageList(images); 13695 montage_info=DestroyMontageInfo(montage_info); 13696 read_info=DestroyImageInfo(read_info); 13697 XSetCursorState(display,windows,MagickFalse); 13698 if (montage_image == (Image *) NULL) 13699 return(montage_image); 13700 XClientMessage(display,windows->image.id,windows->im_protocols, 13701 windows->im_next_image,CurrentTime); 13702 return(montage_image); 13703} 13704 13705/* 13706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13707% % 13708% % 13709% % 13710% X D i s p l a y B a c k g r o u n d I m a g e % 13711% % 13712% % 13713% % 13714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13715% 13716% XDisplayBackgroundImage() displays an image in the background of a window. 13717% 13718% The format of the XDisplayBackgroundImage method is: 13719% 13720% MagickBooleanType XDisplayBackgroundImage(Display *display, 13721% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13722% 13723% A description of each parameter follows: 13724% 13725% o display: Specifies a connection to an X server; returned from 13726% XOpenDisplay. 13727% 13728% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13729% 13730% o image: the image. 13731% 13732% o exception: return any errors or warnings in this structure. 13733% 13734*/ 13735MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13736 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13737{ 13738 char 13739 geometry[MaxTextExtent], 13740 visual_type[MaxTextExtent]; 13741 13742 int 13743 height, 13744 status, 13745 width; 13746 13747 RectangleInfo 13748 geometry_info; 13749 13750 static XPixelInfo 13751 pixel; 13752 13753 static XStandardColormap 13754 *map_info; 13755 13756 static XVisualInfo 13757 *visual_info = (XVisualInfo *) NULL; 13758 13759 static XWindowInfo 13760 window_info; 13761 13762 size_t 13763 delay; 13764 13765 Window 13766 root_window; 13767 13768 XGCValues 13769 context_values; 13770 13771 XResourceInfo 13772 resources; 13773 13774 XWindowAttributes 13775 window_attributes; 13776 13777 /* 13778 Determine target window. 13779 */ 13780 assert(image != (Image *) NULL); 13781 assert(image->signature == MagickSignature); 13782 if (image->debug != MagickFalse) 13783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13784 resources=(*resource_info); 13785 window_info.id=(Window) NULL; 13786 root_window=XRootWindow(display,XDefaultScreen(display)); 13787 if (LocaleCompare(resources.window_id,"root") == 0) 13788 window_info.id=root_window; 13789 else 13790 { 13791 if (isdigit((unsigned char) *resources.window_id) != 0) 13792 window_info.id=XWindowByID(display,root_window, 13793 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13794 if (window_info.id == (Window) NULL) 13795 window_info.id=XWindowByName(display,root_window,resources.window_id); 13796 } 13797 if (window_info.id == (Window) NULL) 13798 { 13799 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13800 resources.window_id); 13801 return(MagickFalse); 13802 } 13803 /* 13804 Determine window visual id. 13805 */ 13806 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13807 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13808 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13809 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13810 if (status != 0) 13811 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13812 XVisualIDFromVisual(window_attributes.visual)); 13813 if (visual_info == (XVisualInfo *) NULL) 13814 { 13815 /* 13816 Allocate standard colormap. 13817 */ 13818 map_info=XAllocStandardColormap(); 13819 if (map_info == (XStandardColormap *) NULL) 13820 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13821 image->filename); 13822 map_info->colormap=(Colormap) NULL; 13823 pixel.pixels=(unsigned long *) NULL; 13824 /* 13825 Initialize visual info. 13826 */ 13827 resources.map_type=(char *) NULL; 13828 resources.visual_type=visual_type; 13829 visual_info=XBestVisualInfo(display,map_info,&resources); 13830 if (visual_info == (XVisualInfo *) NULL) 13831 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13832 resources.visual_type); 13833 /* 13834 Initialize window info. 13835 */ 13836 window_info.ximage=(XImage *) NULL; 13837 window_info.matte_image=(XImage *) NULL; 13838 window_info.pixmap=(Pixmap) NULL; 13839 window_info.matte_pixmap=(Pixmap) NULL; 13840 } 13841 /* 13842 Free previous root colors. 13843 */ 13844 if (window_info.id == root_window) 13845 (void) XDestroyWindowColors(display,root_window); 13846 /* 13847 Initialize Standard Colormap. 13848 */ 13849 resources.colormap=SharedColormap; 13850 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13851 /* 13852 Graphic context superclass. 13853 */ 13854 context_values.background=pixel.background_color.pixel; 13855 context_values.foreground=pixel.foreground_color.pixel; 13856 pixel.annotate_context=XCreateGC(display,window_info.id, 13857 (size_t) (GCBackground | GCForeground),&context_values); 13858 if (pixel.annotate_context == (GC) NULL) 13859 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13860 image->filename); 13861 /* 13862 Initialize Image window attributes. 13863 */ 13864 window_info.name=AcquireString("\0"); 13865 window_info.icon_name=AcquireString("\0"); 13866 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13867 &resources,&window_info); 13868 /* 13869 Create the X image. 13870 */ 13871 window_info.width=(unsigned int) image->columns; 13872 window_info.height=(unsigned int) image->rows; 13873 if ((image->columns != window_info.width) || 13874 (image->rows != window_info.height)) 13875 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13876 image->filename); 13877 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13878 window_attributes.width,window_attributes.height); 13879 geometry_info.width=window_info.width; 13880 geometry_info.height=window_info.height; 13881 geometry_info.x=(ssize_t) window_info.x; 13882 geometry_info.y=(ssize_t) window_info.y; 13883 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13884 &geometry_info.width,&geometry_info.height); 13885 window_info.width=(unsigned int) geometry_info.width; 13886 window_info.height=(unsigned int) geometry_info.height; 13887 window_info.x=(int) geometry_info.x; 13888 window_info.y=(int) geometry_info.y; 13889 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13890 window_info.height,exception); 13891 if (status == MagickFalse) 13892 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13893 image->filename); 13894 window_info.x=0; 13895 window_info.y=0; 13896 if (image->debug != MagickFalse) 13897 { 13898 (void) LogMagickEvent(X11Event,GetMagickModule(), 13899 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13900 (double) image->columns,(double) image->rows); 13901 if (image->colors != 0) 13902 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13903 image->colors); 13904 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13905 } 13906 /* 13907 Adjust image dimensions as specified by backdrop or geometry options. 13908 */ 13909 width=(int) window_info.width; 13910 height=(int) window_info.height; 13911 if (resources.backdrop != MagickFalse) 13912 { 13913 /* 13914 Center image on window. 13915 */ 13916 window_info.x=(window_attributes.width/2)- 13917 (window_info.ximage->width/2); 13918 window_info.y=(window_attributes.height/2)- 13919 (window_info.ximage->height/2); 13920 width=window_attributes.width; 13921 height=window_attributes.height; 13922 } 13923 if ((resources.image_geometry != (char *) NULL) && 13924 (*resources.image_geometry != '\0')) 13925 { 13926 char 13927 default_geometry[MaxTextExtent]; 13928 13929 int 13930 flags, 13931 gravity; 13932 13933 XSizeHints 13934 *size_hints; 13935 13936 /* 13937 User specified geometry. 13938 */ 13939 size_hints=XAllocSizeHints(); 13940 if (size_hints == (XSizeHints *) NULL) 13941 ThrowXWindowFatalException(ResourceLimitFatalError, 13942 "MemoryAllocationFailed",image->filename); 13943 size_hints->flags=0L; 13944 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13945 width,height); 13946 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13947 default_geometry,window_info.border_width,size_hints,&window_info.x, 13948 &window_info.y,&width,&height,&gravity); 13949 if (flags & (XValue | YValue)) 13950 { 13951 width=window_attributes.width; 13952 height=window_attributes.height; 13953 } 13954 (void) XFree((void *) size_hints); 13955 } 13956 /* 13957 Create the X pixmap. 13958 */ 13959 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 13960 (unsigned int) height,window_info.depth); 13961 if (window_info.pixmap == (Pixmap) NULL) 13962 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 13963 image->filename); 13964 /* 13965 Display pixmap on the window. 13966 */ 13967 if (((unsigned int) width > window_info.width) || 13968 ((unsigned int) height > window_info.height)) 13969 (void) XFillRectangle(display,window_info.pixmap, 13970 window_info.annotate_context,0,0,(unsigned int) width, 13971 (unsigned int) height); 13972 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 13973 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 13974 window_info.width,(unsigned int) window_info.height); 13975 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 13976 (void) XClearWindow(display,window_info.id); 13977 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 13978 XDelay(display,delay == 0UL ? 10UL : delay); 13979 (void) XSync(display,MagickFalse); 13980 return(window_info.id == root_window ? MagickTrue : MagickFalse); 13981} 13982 13983/* 13984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13985% % 13986% % 13987% % 13988+ X D i s p l a y I m a g e % 13989% % 13990% % 13991% % 13992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13993% 13994% XDisplayImage() displays an image via X11. A new image is created and 13995% returned if the user interactively transforms the displayed image. 13996% 13997% The format of the XDisplayImage method is: 13998% 13999% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14000% char **argv,int argc,Image **image,size_t *state, 14001% ExceptionInfo *exception) 14002% 14003% A description of each parameter follows: 14004% 14005% o nexus: Method XDisplayImage returns an image when the 14006% user chooses 'Open Image' from the command menu or picks a tile 14007% from the image directory. Otherwise a null image is returned. 14008% 14009% o display: Specifies a connection to an X server; returned from 14010% XOpenDisplay. 14011% 14012% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14013% 14014% o argv: Specifies the application's argument list. 14015% 14016% o argc: Specifies the number of arguments. 14017% 14018% o image: Specifies an address to an address of an Image structure; 14019% 14020% o exception: return any errors or warnings in this structure. 14021% 14022*/ 14023MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14024 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14025{ 14026#define MagnifySize 256 /* must be a power of 2 */ 14027#define MagickMenus 10 14028#define MagickTitle "Commands" 14029 14030 static const char 14031 *CommandMenu[] = 14032 { 14033 "File", 14034 "Edit", 14035 "View", 14036 "Transform", 14037 "Enhance", 14038 "Effects", 14039 "F/X", 14040 "Image Edit", 14041 "Miscellany", 14042 "Help", 14043 (char *) NULL 14044 }, 14045 *FileMenu[] = 14046 { 14047 "Open...", 14048 "Next", 14049 "Former", 14050 "Select...", 14051 "Save...", 14052 "Print...", 14053 "Delete...", 14054 "New...", 14055 "Visual Directory...", 14056 "Quit", 14057 (char *) NULL 14058 }, 14059 *EditMenu[] = 14060 { 14061 "Undo", 14062 "Redo", 14063 "Cut", 14064 "Copy", 14065 "Paste", 14066 (char *) NULL 14067 }, 14068 *ViewMenu[] = 14069 { 14070 "Half Size", 14071 "Original Size", 14072 "Double Size", 14073 "Resize...", 14074 "Apply", 14075 "Refresh", 14076 "Restore", 14077 (char *) NULL 14078 }, 14079 *TransformMenu[] = 14080 { 14081 "Crop", 14082 "Chop", 14083 "Flop", 14084 "Flip", 14085 "Rotate Right", 14086 "Rotate Left", 14087 "Rotate...", 14088 "Shear...", 14089 "Roll...", 14090 "Trim Edges", 14091 (char *) NULL 14092 }, 14093 *EnhanceMenu[] = 14094 { 14095 "Hue...", 14096 "Saturation...", 14097 "Brightness...", 14098 "Gamma...", 14099 "Spiff", 14100 "Dull", 14101 "Contrast Stretch...", 14102 "Sigmoidal Contrast...", 14103 "Normalize", 14104 "Equalize", 14105 "Negate", 14106 "Grayscale", 14107 "Map...", 14108 "Quantize...", 14109 (char *) NULL 14110 }, 14111 *EffectsMenu[] = 14112 { 14113 "Despeckle", 14114 "Emboss", 14115 "Reduce Noise", 14116 "Add Noise...", 14117 "Sharpen...", 14118 "Blur...", 14119 "Threshold...", 14120 "Edge Detect...", 14121 "Spread...", 14122 "Shade...", 14123 "Raise...", 14124 "Segment...", 14125 (char *) NULL 14126 }, 14127 *FXMenu[] = 14128 { 14129 "Solarize...", 14130 "Sepia Tone...", 14131 "Swirl...", 14132 "Implode...", 14133 "Vignette...", 14134 "Wave...", 14135 "Oil Paint...", 14136 "Charcoal Draw...", 14137 (char *) NULL 14138 }, 14139 *ImageEditMenu[] = 14140 { 14141 "Annotate...", 14142 "Draw...", 14143 "Color...", 14144 "Matte...", 14145 "Composite...", 14146 "Add Border...", 14147 "Add Frame...", 14148 "Comment...", 14149 "Launch...", 14150 "Region of Interest...", 14151 (char *) NULL 14152 }, 14153 *MiscellanyMenu[] = 14154 { 14155 "Image Info", 14156 "Zoom Image", 14157 "Show Preview...", 14158 "Show Histogram", 14159 "Show Matte", 14160 "Background...", 14161 "Slide Show...", 14162 "Preferences...", 14163 (char *) NULL 14164 }, 14165 *HelpMenu[] = 14166 { 14167 "Overview", 14168 "Browse Documentation", 14169 "About Display", 14170 (char *) NULL 14171 }, 14172 *ShortCutsMenu[] = 14173 { 14174 "Next", 14175 "Former", 14176 "Open...", 14177 "Save...", 14178 "Print...", 14179 "Undo", 14180 "Restore", 14181 "Image Info", 14182 "Quit", 14183 (char *) NULL 14184 }, 14185 *VirtualMenu[] = 14186 { 14187 "Image Info", 14188 "Print", 14189 "Next", 14190 "Quit", 14191 (char *) NULL 14192 }; 14193 14194 static const char 14195 **Menus[MagickMenus] = 14196 { 14197 FileMenu, 14198 EditMenu, 14199 ViewMenu, 14200 TransformMenu, 14201 EnhanceMenu, 14202 EffectsMenu, 14203 FXMenu, 14204 ImageEditMenu, 14205 MiscellanyMenu, 14206 HelpMenu 14207 }; 14208 14209 static CommandType 14210 CommandMenus[] = 14211 { 14212 NullCommand, 14213 NullCommand, 14214 NullCommand, 14215 NullCommand, 14216 NullCommand, 14217 NullCommand, 14218 NullCommand, 14219 NullCommand, 14220 NullCommand, 14221 NullCommand, 14222 }, 14223 FileCommands[] = 14224 { 14225 OpenCommand, 14226 NextCommand, 14227 FormerCommand, 14228 SelectCommand, 14229 SaveCommand, 14230 PrintCommand, 14231 DeleteCommand, 14232 NewCommand, 14233 VisualDirectoryCommand, 14234 QuitCommand 14235 }, 14236 EditCommands[] = 14237 { 14238 UndoCommand, 14239 RedoCommand, 14240 CutCommand, 14241 CopyCommand, 14242 PasteCommand 14243 }, 14244 ViewCommands[] = 14245 { 14246 HalfSizeCommand, 14247 OriginalSizeCommand, 14248 DoubleSizeCommand, 14249 ResizeCommand, 14250 ApplyCommand, 14251 RefreshCommand, 14252 RestoreCommand 14253 }, 14254 TransformCommands[] = 14255 { 14256 CropCommand, 14257 ChopCommand, 14258 FlopCommand, 14259 FlipCommand, 14260 RotateRightCommand, 14261 RotateLeftCommand, 14262 RotateCommand, 14263 ShearCommand, 14264 RollCommand, 14265 TrimCommand 14266 }, 14267 EnhanceCommands[] = 14268 { 14269 HueCommand, 14270 SaturationCommand, 14271 BrightnessCommand, 14272 GammaCommand, 14273 SpiffCommand, 14274 DullCommand, 14275 ContrastStretchCommand, 14276 SigmoidalContrastCommand, 14277 NormalizeCommand, 14278 EqualizeCommand, 14279 NegateCommand, 14280 GrayscaleCommand, 14281 MapCommand, 14282 QuantizeCommand 14283 }, 14284 EffectsCommands[] = 14285 { 14286 DespeckleCommand, 14287 EmbossCommand, 14288 ReduceNoiseCommand, 14289 AddNoiseCommand, 14290 SharpenCommand, 14291 BlurCommand, 14292 ThresholdCommand, 14293 EdgeDetectCommand, 14294 SpreadCommand, 14295 ShadeCommand, 14296 RaiseCommand, 14297 SegmentCommand 14298 }, 14299 FXCommands[] = 14300 { 14301 SolarizeCommand, 14302 SepiaToneCommand, 14303 SwirlCommand, 14304 ImplodeCommand, 14305 VignetteCommand, 14306 WaveCommand, 14307 OilPaintCommand, 14308 CharcoalDrawCommand 14309 }, 14310 ImageEditCommands[] = 14311 { 14312 AnnotateCommand, 14313 DrawCommand, 14314 ColorCommand, 14315 MatteCommand, 14316 CompositeCommand, 14317 AddBorderCommand, 14318 AddFrameCommand, 14319 CommentCommand, 14320 LaunchCommand, 14321 RegionofInterestCommand 14322 }, 14323 MiscellanyCommands[] = 14324 { 14325 InfoCommand, 14326 ZoomCommand, 14327 ShowPreviewCommand, 14328 ShowHistogramCommand, 14329 ShowMatteCommand, 14330 BackgroundCommand, 14331 SlideShowCommand, 14332 PreferencesCommand 14333 }, 14334 HelpCommands[] = 14335 { 14336 HelpCommand, 14337 BrowseDocumentationCommand, 14338 VersionCommand 14339 }, 14340 ShortCutsCommands[] = 14341 { 14342 NextCommand, 14343 FormerCommand, 14344 OpenCommand, 14345 SaveCommand, 14346 PrintCommand, 14347 UndoCommand, 14348 RestoreCommand, 14349 InfoCommand, 14350 QuitCommand 14351 }, 14352 VirtualCommands[] = 14353 { 14354 InfoCommand, 14355 PrintCommand, 14356 NextCommand, 14357 QuitCommand 14358 }; 14359 14360 static CommandType 14361 *Commands[MagickMenus] = 14362 { 14363 FileCommands, 14364 EditCommands, 14365 ViewCommands, 14366 TransformCommands, 14367 EnhanceCommands, 14368 EffectsCommands, 14369 FXCommands, 14370 ImageEditCommands, 14371 MiscellanyCommands, 14372 HelpCommands 14373 }; 14374 14375 char 14376 command[MaxTextExtent], 14377 *directory, 14378 geometry[MaxTextExtent], 14379 resource_name[MaxTextExtent]; 14380 14381 CommandType 14382 command_type; 14383 14384 Image 14385 *display_image, 14386 *nexus; 14387 14388 int 14389 entry, 14390 id; 14391 14392 KeySym 14393 key_symbol; 14394 14395 MagickStatusType 14396 context_mask, 14397 status; 14398 14399 RectangleInfo 14400 geometry_info; 14401 14402 register int 14403 i; 14404 14405 static char 14406 working_directory[MaxTextExtent]; 14407 14408 static XPoint 14409 vid_info; 14410 14411 static XWindowInfo 14412 *magick_windows[MaxXWindows]; 14413 14414 static unsigned int 14415 number_windows; 14416 14417 struct stat 14418 attributes; 14419 14420 time_t 14421 timer, 14422 timestamp, 14423 update_time; 14424 14425 unsigned int 14426 height, 14427 width; 14428 14429 size_t 14430 delay; 14431 14432 WarningHandler 14433 warning_handler; 14434 14435 Window 14436 root_window; 14437 14438 XClassHint 14439 *class_hints; 14440 14441 XEvent 14442 event; 14443 14444 XFontStruct 14445 *font_info; 14446 14447 XGCValues 14448 context_values; 14449 14450 XPixelInfo 14451 *icon_pixel, 14452 *pixel; 14453 14454 XResourceInfo 14455 *icon_resources; 14456 14457 XStandardColormap 14458 *icon_map, 14459 *map_info; 14460 14461 XVisualInfo 14462 *icon_visual, 14463 *visual_info; 14464 14465 XWindowChanges 14466 window_changes; 14467 14468 XWindows 14469 *windows; 14470 14471 XWMHints 14472 *manager_hints; 14473 14474 assert(image != (Image **) NULL); 14475 assert((*image)->signature == MagickSignature); 14476 if ((*image)->debug != MagickFalse) 14477 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14478 display_image=(*image); 14479 warning_handler=(WarningHandler) NULL; 14480 windows=XSetWindows((XWindows *) ~0); 14481 if (windows != (XWindows *) NULL) 14482 { 14483 int 14484 status; 14485 14486 status=chdir(working_directory); 14487 if (status == -1) 14488 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14489 "UnableToOpenFile","%s",working_directory); 14490 warning_handler=resource_info->display_warnings ? 14491 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14492 warning_handler=resource_info->display_warnings ? 14493 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14494 } 14495 else 14496 { 14497 /* 14498 Allocate windows structure. 14499 */ 14500 resource_info->colors=display_image->colors; 14501 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14502 if (windows == (XWindows *) NULL) 14503 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14504 (*image)->filename); 14505 /* 14506 Initialize window id's. 14507 */ 14508 number_windows=0; 14509 magick_windows[number_windows++]=(&windows->icon); 14510 magick_windows[number_windows++]=(&windows->backdrop); 14511 magick_windows[number_windows++]=(&windows->image); 14512 magick_windows[number_windows++]=(&windows->info); 14513 magick_windows[number_windows++]=(&windows->command); 14514 magick_windows[number_windows++]=(&windows->widget); 14515 magick_windows[number_windows++]=(&windows->popup); 14516 magick_windows[number_windows++]=(&windows->magnify); 14517 magick_windows[number_windows++]=(&windows->pan); 14518 for (i=0; i < (int) number_windows; i++) 14519 magick_windows[i]->id=(Window) NULL; 14520 vid_info.x=0; 14521 vid_info.y=0; 14522 } 14523 /* 14524 Initialize font info. 14525 */ 14526 if (windows->font_info != (XFontStruct *) NULL) 14527 (void) XFreeFont(display,windows->font_info); 14528 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14529 if (windows->font_info == (XFontStruct *) NULL) 14530 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14531 resource_info->font); 14532 /* 14533 Initialize Standard Colormap. 14534 */ 14535 map_info=windows->map_info; 14536 icon_map=windows->icon_map; 14537 visual_info=windows->visual_info; 14538 icon_visual=windows->icon_visual; 14539 pixel=windows->pixel_info; 14540 icon_pixel=windows->icon_pixel; 14541 font_info=windows->font_info; 14542 icon_resources=windows->icon_resources; 14543 class_hints=windows->class_hints; 14544 manager_hints=windows->manager_hints; 14545 root_window=XRootWindow(display,visual_info->screen); 14546 nexus=NewImageList(); 14547 if (display_image->debug != MagickFalse) 14548 { 14549 (void) LogMagickEvent(X11Event,GetMagickModule(), 14550 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14551 (double) display_image->scene,(double) display_image->columns, 14552 (double) display_image->rows); 14553 if (display_image->colors != 0) 14554 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14555 display_image->colors); 14556 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14557 display_image->magick); 14558 } 14559 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14560 map_info,pixel); 14561 display_image->taint=MagickFalse; 14562 /* 14563 Initialize graphic context. 14564 */ 14565 windows->context.id=(Window) NULL; 14566 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14567 resource_info,&windows->context); 14568 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14569 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14570 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14571 manager_hints->flags=InputHint | StateHint; 14572 manager_hints->input=MagickFalse; 14573 manager_hints->initial_state=WithdrawnState; 14574 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14575 &windows->context); 14576 if (display_image->debug != MagickFalse) 14577 (void) LogMagickEvent(X11Event,GetMagickModule(), 14578 "Window id: 0x%lx (context)",windows->context.id); 14579 context_values.background=pixel->background_color.pixel; 14580 context_values.font=font_info->fid; 14581 context_values.foreground=pixel->foreground_color.pixel; 14582 context_values.graphics_exposures=MagickFalse; 14583 context_mask=(MagickStatusType) 14584 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14585 if (pixel->annotate_context != (GC) NULL) 14586 (void) XFreeGC(display,pixel->annotate_context); 14587 pixel->annotate_context=XCreateGC(display,windows->context.id, 14588 context_mask,&context_values); 14589 if (pixel->annotate_context == (GC) NULL) 14590 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14591 display_image->filename); 14592 context_values.background=pixel->depth_color.pixel; 14593 if (pixel->widget_context != (GC) NULL) 14594 (void) XFreeGC(display,pixel->widget_context); 14595 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14596 &context_values); 14597 if (pixel->widget_context == (GC) NULL) 14598 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14599 display_image->filename); 14600 context_values.background=pixel->foreground_color.pixel; 14601 context_values.foreground=pixel->background_color.pixel; 14602 context_values.plane_mask=context_values.background ^ 14603 context_values.foreground; 14604 if (pixel->highlight_context != (GC) NULL) 14605 (void) XFreeGC(display,pixel->highlight_context); 14606 pixel->highlight_context=XCreateGC(display,windows->context.id, 14607 (size_t) (context_mask | GCPlaneMask),&context_values); 14608 if (pixel->highlight_context == (GC) NULL) 14609 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14610 display_image->filename); 14611 (void) XDestroyWindow(display,windows->context.id); 14612 /* 14613 Initialize icon window. 14614 */ 14615 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14616 icon_resources,&windows->icon); 14617 windows->icon.geometry=resource_info->icon_geometry; 14618 XBestIconSize(display,&windows->icon,display_image); 14619 windows->icon.attributes.colormap=XDefaultColormap(display, 14620 icon_visual->screen); 14621 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14622 manager_hints->flags=InputHint | StateHint; 14623 manager_hints->input=MagickFalse; 14624 manager_hints->initial_state=IconicState; 14625 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14626 &windows->icon); 14627 if (display_image->debug != MagickFalse) 14628 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14629 windows->icon.id); 14630 /* 14631 Initialize graphic context for icon window. 14632 */ 14633 if (icon_pixel->annotate_context != (GC) NULL) 14634 (void) XFreeGC(display,icon_pixel->annotate_context); 14635 context_values.background=icon_pixel->background_color.pixel; 14636 context_values.foreground=icon_pixel->foreground_color.pixel; 14637 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14638 (size_t) (GCBackground | GCForeground),&context_values); 14639 if (icon_pixel->annotate_context == (GC) NULL) 14640 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14641 display_image->filename); 14642 windows->icon.annotate_context=icon_pixel->annotate_context; 14643 /* 14644 Initialize Image window. 14645 */ 14646 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14647 &windows->image); 14648 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14649 if (resource_info->use_shared_memory == MagickFalse) 14650 windows->image.shared_memory=MagickFalse; 14651 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14652 { 14653 char 14654 *title; 14655 14656 title=InterpretImageProperties(resource_info->image_info,display_image, 14657 resource_info->title,exception); 14658 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14659 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14660 title=DestroyString(title); 14661 } 14662 else 14663 { 14664 char 14665 filename[MaxTextExtent]; 14666 14667 /* 14668 Window name is the base of the filename. 14669 */ 14670 GetPathComponent(display_image->magick_filename,TailPath,filename); 14671 if (GetImageListLength(display_image) == 1) 14672 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14673 "%s: %s",MagickPackageName,filename); 14674 else 14675 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14676 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14677 (double) display_image->scene,(double) GetImageListLength( 14678 display_image)); 14679 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14680 } 14681 if (resource_info->immutable) 14682 windows->image.immutable=MagickTrue; 14683 windows->image.use_pixmap=resource_info->use_pixmap; 14684 windows->image.geometry=resource_info->image_geometry; 14685 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14686 XDisplayWidth(display,visual_info->screen), 14687 XDisplayHeight(display,visual_info->screen)); 14688 geometry_info.width=display_image->columns; 14689 geometry_info.height=display_image->rows; 14690 geometry_info.x=0; 14691 geometry_info.y=0; 14692 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14693 &geometry_info.width,&geometry_info.height); 14694 windows->image.width=(unsigned int) geometry_info.width; 14695 windows->image.height=(unsigned int) geometry_info.height; 14696 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14697 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14698 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14699 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14700 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14701 resource_info,&windows->backdrop); 14702 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14703 { 14704 /* 14705 Initialize backdrop window. 14706 */ 14707 windows->backdrop.x=0; 14708 windows->backdrop.y=0; 14709 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14710 windows->backdrop.flags=(size_t) (USSize | USPosition); 14711 windows->backdrop.width=(unsigned int) 14712 XDisplayWidth(display,visual_info->screen); 14713 windows->backdrop.height=(unsigned int) 14714 XDisplayHeight(display,visual_info->screen); 14715 windows->backdrop.border_width=0; 14716 windows->backdrop.immutable=MagickTrue; 14717 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14718 ButtonReleaseMask; 14719 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14720 StructureNotifyMask; 14721 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14722 manager_hints->icon_window=windows->icon.id; 14723 manager_hints->input=MagickTrue; 14724 manager_hints->initial_state=resource_info->iconic ? IconicState : 14725 NormalState; 14726 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14727 &windows->backdrop); 14728 if (display_image->debug != MagickFalse) 14729 (void) LogMagickEvent(X11Event,GetMagickModule(), 14730 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14731 (void) XMapWindow(display,windows->backdrop.id); 14732 (void) XClearWindow(display,windows->backdrop.id); 14733 if (windows->image.id != (Window) NULL) 14734 { 14735 (void) XDestroyWindow(display,windows->image.id); 14736 windows->image.id=(Window) NULL; 14737 } 14738 /* 14739 Position image in the center the backdrop. 14740 */ 14741 windows->image.flags|=USPosition; 14742 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14743 (windows->image.width/2); 14744 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14745 (windows->image.height/2); 14746 } 14747 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14748 manager_hints->icon_window=windows->icon.id; 14749 manager_hints->input=MagickTrue; 14750 manager_hints->initial_state=resource_info->iconic ? IconicState : 14751 NormalState; 14752 if (windows->group_leader.id != (Window) NULL) 14753 { 14754 /* 14755 Follow the leader. 14756 */ 14757 manager_hints->flags|=WindowGroupHint; 14758 manager_hints->window_group=windows->group_leader.id; 14759 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14760 if (display_image->debug != MagickFalse) 14761 (void) LogMagickEvent(X11Event,GetMagickModule(), 14762 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14763 } 14764 XMakeWindow(display, 14765 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14766 argv,argc,class_hints,manager_hints,&windows->image); 14767 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14768 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14769 if (windows->group_leader.id != (Window) NULL) 14770 (void) XSetTransientForHint(display,windows->image.id, 14771 windows->group_leader.id); 14772 if (display_image->debug != MagickFalse) 14773 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14774 windows->image.id); 14775 /* 14776 Initialize Info widget. 14777 */ 14778 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14779 &windows->info); 14780 (void) CloneString(&windows->info.name,"Info"); 14781 (void) CloneString(&windows->info.icon_name,"Info"); 14782 windows->info.border_width=1; 14783 windows->info.x=2; 14784 windows->info.y=2; 14785 windows->info.flags|=PPosition; 14786 windows->info.attributes.win_gravity=UnmapGravity; 14787 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14788 StructureNotifyMask; 14789 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14790 manager_hints->input=MagickFalse; 14791 manager_hints->initial_state=NormalState; 14792 manager_hints->window_group=windows->image.id; 14793 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14794 &windows->info); 14795 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14796 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14797 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14798 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14799 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14800 if (windows->image.mapped != MagickFalse) 14801 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14802 if (display_image->debug != MagickFalse) 14803 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14804 windows->info.id); 14805 /* 14806 Initialize Command widget. 14807 */ 14808 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14809 resource_info,&windows->command); 14810 windows->command.data=MagickMenus; 14811 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14812 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14813 resource_info->client_name); 14814 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14815 resource_name,"geometry",(char *) NULL); 14816 (void) CloneString(&windows->command.name,MagickTitle); 14817 windows->command.border_width=0; 14818 windows->command.flags|=PPosition; 14819 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14820 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14821 OwnerGrabButtonMask | StructureNotifyMask; 14822 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14823 manager_hints->input=MagickTrue; 14824 manager_hints->initial_state=NormalState; 14825 manager_hints->window_group=windows->image.id; 14826 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14827 &windows->command); 14828 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14829 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14830 HighlightHeight); 14831 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14832 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14833 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14834 if (windows->command.mapped != MagickFalse) 14835 (void) XMapRaised(display,windows->command.id); 14836 if (display_image->debug != MagickFalse) 14837 (void) LogMagickEvent(X11Event,GetMagickModule(), 14838 "Window id: 0x%lx (command)",windows->command.id); 14839 /* 14840 Initialize Widget window. 14841 */ 14842 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14843 resource_info,&windows->widget); 14844 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14845 resource_info->client_name); 14846 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14847 resource_name,"geometry",(char *) NULL); 14848 windows->widget.border_width=0; 14849 windows->widget.flags|=PPosition; 14850 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14851 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14852 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14853 StructureNotifyMask; 14854 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14855 manager_hints->input=MagickTrue; 14856 manager_hints->initial_state=NormalState; 14857 manager_hints->window_group=windows->image.id; 14858 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14859 &windows->widget); 14860 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14861 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14862 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14863 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14864 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14865 if (display_image->debug != MagickFalse) 14866 (void) LogMagickEvent(X11Event,GetMagickModule(), 14867 "Window id: 0x%lx (widget)",windows->widget.id); 14868 /* 14869 Initialize popup window. 14870 */ 14871 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14872 resource_info,&windows->popup); 14873 windows->popup.border_width=0; 14874 windows->popup.flags|=PPosition; 14875 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14876 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14877 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14878 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14879 manager_hints->input=MagickTrue; 14880 manager_hints->initial_state=NormalState; 14881 manager_hints->window_group=windows->image.id; 14882 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14883 &windows->popup); 14884 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14885 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14886 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14887 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14888 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14889 if (display_image->debug != MagickFalse) 14890 (void) LogMagickEvent(X11Event,GetMagickModule(), 14891 "Window id: 0x%lx (pop up)",windows->popup.id); 14892 /* 14893 Initialize Magnify window and cursor. 14894 */ 14895 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14896 resource_info,&windows->magnify); 14897 if (resource_info->use_shared_memory == MagickFalse) 14898 windows->magnify.shared_memory=MagickFalse; 14899 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14900 resource_info->client_name); 14901 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14902 resource_name,"geometry",(char *) NULL); 14903 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14904 resource_info->magnify); 14905 if (windows->magnify.cursor != (Cursor) NULL) 14906 (void) XFreeCursor(display,windows->magnify.cursor); 14907 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14908 map_info->colormap,resource_info->background_color, 14909 resource_info->foreground_color); 14910 if (windows->magnify.cursor == (Cursor) NULL) 14911 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14912 display_image->filename); 14913 windows->magnify.width=MagnifySize; 14914 windows->magnify.height=MagnifySize; 14915 windows->magnify.flags|=PPosition; 14916 windows->magnify.min_width=MagnifySize; 14917 windows->magnify.min_height=MagnifySize; 14918 windows->magnify.width_inc=MagnifySize; 14919 windows->magnify.height_inc=MagnifySize; 14920 windows->magnify.data=resource_info->magnify; 14921 windows->magnify.attributes.cursor=windows->magnify.cursor; 14922 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14923 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14924 StructureNotifyMask; 14925 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14926 manager_hints->input=MagickTrue; 14927 manager_hints->initial_state=NormalState; 14928 manager_hints->window_group=windows->image.id; 14929 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14930 &windows->magnify); 14931 if (display_image->debug != MagickFalse) 14932 (void) LogMagickEvent(X11Event,GetMagickModule(), 14933 "Window id: 0x%lx (magnify)",windows->magnify.id); 14934 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14935 /* 14936 Initialize panning window. 14937 */ 14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14939 resource_info,&windows->pan); 14940 (void) CloneString(&windows->pan.name,"Pan Icon"); 14941 windows->pan.width=windows->icon.width; 14942 windows->pan.height=windows->icon.height; 14943 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14944 resource_info->client_name); 14945 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14946 resource_name,"geometry",(char *) NULL); 14947 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14948 &windows->pan.width,&windows->pan.height); 14949 windows->pan.flags|=PPosition; 14950 windows->pan.immutable=MagickTrue; 14951 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14952 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14953 StructureNotifyMask; 14954 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14955 manager_hints->input=MagickFalse; 14956 manager_hints->initial_state=NormalState; 14957 manager_hints->window_group=windows->image.id; 14958 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14959 &windows->pan); 14960 if (display_image->debug != MagickFalse) 14961 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 14962 windows->pan.id); 14963 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 14964 if (windows->info.mapped != MagickFalse) 14965 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14966 if ((windows->image.mapped == MagickFalse) || 14967 (windows->backdrop.id != (Window) NULL)) 14968 (void) XMapWindow(display,windows->image.id); 14969 /* 14970 Set our progress monitor and warning handlers. 14971 */ 14972 if (warning_handler == (WarningHandler) NULL) 14973 { 14974 warning_handler=resource_info->display_warnings ? 14975 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14976 warning_handler=resource_info->display_warnings ? 14977 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14978 } 14979 /* 14980 Initialize Image and Magnify X images. 14981 */ 14982 windows->image.x=0; 14983 windows->image.y=0; 14984 windows->magnify.shape=MagickFalse; 14985 width=(unsigned int) display_image->columns; 14986 height=(unsigned int) display_image->rows; 14987 if ((display_image->columns != width) || (display_image->rows != height)) 14988 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14989 display_image->filename); 14990 status=XMakeImage(display,resource_info,&windows->image,display_image, 14991 width,height,exception); 14992 if (status == MagickFalse) 14993 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14994 display_image->filename); 14995 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 14996 windows->magnify.width,windows->magnify.height,exception); 14997 if (status == MagickFalse) 14998 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 14999 display_image->filename); 15000 if (windows->magnify.mapped != MagickFalse) 15001 (void) XMapRaised(display,windows->magnify.id); 15002 if (windows->pan.mapped != MagickFalse) 15003 (void) XMapRaised(display,windows->pan.id); 15004 windows->image.window_changes.width=(int) display_image->columns; 15005 windows->image.window_changes.height=(int) display_image->rows; 15006 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15007 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15008 (void) XSync(display,MagickFalse); 15009 /* 15010 Respond to events. 15011 */ 15012 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15013 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15014 update_time=0; 15015 if (resource_info->update != MagickFalse) 15016 { 15017 MagickBooleanType 15018 status; 15019 15020 /* 15021 Determine when file data was last modified. 15022 */ 15023 status=GetPathAttributes(display_image->filename,&attributes); 15024 if (status != MagickFalse) 15025 update_time=attributes.st_mtime; 15026 } 15027 *state&=(~FormerImageState); 15028 *state&=(~MontageImageState); 15029 *state&=(~NextImageState); 15030 do 15031 { 15032 /* 15033 Handle a window event. 15034 */ 15035 if (windows->image.mapped != MagickFalse) 15036 if ((display_image->delay != 0) || (resource_info->update != 0)) 15037 { 15038 if (timer < time((time_t *) NULL)) 15039 { 15040 if (resource_info->update == MagickFalse) 15041 *state|=NextImageState | ExitState; 15042 else 15043 { 15044 MagickBooleanType 15045 status; 15046 15047 /* 15048 Determine if image file was modified. 15049 */ 15050 status=GetPathAttributes(display_image->filename,&attributes); 15051 if (status != MagickFalse) 15052 if (update_time != attributes.st_mtime) 15053 { 15054 /* 15055 Redisplay image. 15056 */ 15057 (void) FormatLocaleString( 15058 resource_info->image_info->filename,MaxTextExtent, 15059 "%s:%s",display_image->magick, 15060 display_image->filename); 15061 nexus=ReadImage(resource_info->image_info, 15062 &display_image->exception); 15063 if (nexus != (Image *) NULL) 15064 { 15065 nexus=DestroyImage(nexus); 15066 *state|=NextImageState | ExitState; 15067 } 15068 } 15069 delay=display_image->delay/MagickMax( 15070 display_image->ticks_per_second,1L); 15071 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15072 } 15073 } 15074 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15075 { 15076 /* 15077 Do not block if delay > 0. 15078 */ 15079 XDelay(display,SuspendTime << 2); 15080 continue; 15081 } 15082 } 15083 timestamp=time((time_t *) NULL); 15084 (void) XNextEvent(display,&event); 15085 if (windows->image.stasis == MagickFalse) 15086 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15087 MagickTrue : MagickFalse; 15088 if (windows->magnify.stasis == MagickFalse) 15089 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15090 MagickTrue : MagickFalse; 15091 if (event.xany.window == windows->command.id) 15092 { 15093 /* 15094 Select a command from the Command widget. 15095 */ 15096 id=XCommandWidget(display,windows,CommandMenu,&event); 15097 if (id < 0) 15098 continue; 15099 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15100 command_type=CommandMenus[id]; 15101 if (id < MagickMenus) 15102 { 15103 /* 15104 Select a command from a pop-up menu. 15105 */ 15106 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15107 command); 15108 if (entry < 0) 15109 continue; 15110 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15111 command_type=Commands[id][entry]; 15112 } 15113 if (command_type != NullCommand) 15114 nexus=XMagickCommand(display,resource_info,windows,command_type, 15115 &display_image,exception); 15116 continue; 15117 } 15118 switch (event.type) 15119 { 15120 case ButtonPress: 15121 { 15122 if (display_image->debug != MagickFalse) 15123 (void) LogMagickEvent(X11Event,GetMagickModule(), 15124 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15125 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15126 if ((event.xbutton.button == Button3) && 15127 (event.xbutton.state & Mod1Mask)) 15128 { 15129 /* 15130 Convert Alt-Button3 to Button2. 15131 */ 15132 event.xbutton.button=Button2; 15133 event.xbutton.state&=(~Mod1Mask); 15134 } 15135 if (event.xbutton.window == windows->backdrop.id) 15136 { 15137 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15138 event.xbutton.time); 15139 break; 15140 } 15141 if (event.xbutton.window == windows->image.id) 15142 { 15143 switch (event.xbutton.button) 15144 { 15145 case Button1: 15146 { 15147 if (resource_info->immutable) 15148 { 15149 /* 15150 Select a command from the Virtual menu. 15151 */ 15152 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15153 command); 15154 if (entry >= 0) 15155 nexus=XMagickCommand(display,resource_info,windows, 15156 VirtualCommands[entry],&display_image,exception); 15157 break; 15158 } 15159 /* 15160 Map/unmap Command widget. 15161 */ 15162 if (windows->command.mapped != MagickFalse) 15163 (void) XWithdrawWindow(display,windows->command.id, 15164 windows->command.screen); 15165 else 15166 { 15167 (void) XCommandWidget(display,windows,CommandMenu, 15168 (XEvent *) NULL); 15169 (void) XMapRaised(display,windows->command.id); 15170 } 15171 break; 15172 } 15173 case Button2: 15174 { 15175 /* 15176 User pressed the image magnify button. 15177 */ 15178 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15179 &display_image,exception); 15180 XMagnifyImage(display,windows,&event); 15181 break; 15182 } 15183 case Button3: 15184 { 15185 if (resource_info->immutable) 15186 { 15187 /* 15188 Select a command from the Virtual menu. 15189 */ 15190 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15191 command); 15192 if (entry >= 0) 15193 nexus=XMagickCommand(display,resource_info,windows, 15194 VirtualCommands[entry],&display_image,exception); 15195 break; 15196 } 15197 if (display_image->montage != (char *) NULL) 15198 { 15199 /* 15200 Open or delete a tile from a visual image directory. 15201 */ 15202 nexus=XTileImage(display,resource_info,windows, 15203 display_image,&event,exception); 15204 if (nexus != (Image *) NULL) 15205 *state|=MontageImageState | NextImageState | ExitState; 15206 vid_info.x=(short int) windows->image.x; 15207 vid_info.y=(short int) windows->image.y; 15208 break; 15209 } 15210 /* 15211 Select a command from the Short Cuts menu. 15212 */ 15213 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15214 command); 15215 if (entry >= 0) 15216 nexus=XMagickCommand(display,resource_info,windows, 15217 ShortCutsCommands[entry],&display_image,exception); 15218 break; 15219 } 15220 case Button4: 15221 { 15222 /* 15223 Wheel up. 15224 */ 15225 XTranslateImage(display,windows,*image,XK_Up); 15226 break; 15227 } 15228 case Button5: 15229 { 15230 /* 15231 Wheel down. 15232 */ 15233 XTranslateImage(display,windows,*image,XK_Down); 15234 break; 15235 } 15236 default: 15237 break; 15238 } 15239 break; 15240 } 15241 if (event.xbutton.window == windows->magnify.id) 15242 { 15243 int 15244 factor; 15245 15246 static const char 15247 *MagnifyMenu[] = 15248 { 15249 "2", 15250 "4", 15251 "5", 15252 "6", 15253 "7", 15254 "8", 15255 "9", 15256 "3", 15257 (char *) NULL, 15258 }; 15259 15260 static KeySym 15261 MagnifyCommands[] = 15262 { 15263 XK_2, 15264 XK_4, 15265 XK_5, 15266 XK_6, 15267 XK_7, 15268 XK_8, 15269 XK_9, 15270 XK_3 15271 }; 15272 15273 /* 15274 Select a magnify factor from the pop-up menu. 15275 */ 15276 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15277 if (factor >= 0) 15278 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15279 break; 15280 } 15281 if (event.xbutton.window == windows->pan.id) 15282 { 15283 switch (event.xbutton.button) 15284 { 15285 case Button4: 15286 { 15287 /* 15288 Wheel up. 15289 */ 15290 XTranslateImage(display,windows,*image,XK_Up); 15291 break; 15292 } 15293 case Button5: 15294 { 15295 /* 15296 Wheel down. 15297 */ 15298 XTranslateImage(display,windows,*image,XK_Down); 15299 break; 15300 } 15301 default: 15302 { 15303 XPanImage(display,windows,&event); 15304 break; 15305 } 15306 } 15307 break; 15308 } 15309 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15310 1L); 15311 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15312 break; 15313 } 15314 case ButtonRelease: 15315 { 15316 if (display_image->debug != MagickFalse) 15317 (void) LogMagickEvent(X11Event,GetMagickModule(), 15318 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15319 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15320 break; 15321 } 15322 case ClientMessage: 15323 { 15324 if (display_image->debug != MagickFalse) 15325 (void) LogMagickEvent(X11Event,GetMagickModule(), 15326 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15327 event.xclient.message_type,event.xclient.format,(unsigned long) 15328 event.xclient.data.l[0]); 15329 if (event.xclient.message_type == windows->im_protocols) 15330 { 15331 if (*event.xclient.data.l == (long) windows->im_update_widget) 15332 { 15333 (void) CloneString(&windows->command.name,MagickTitle); 15334 windows->command.data=MagickMenus; 15335 (void) XCommandWidget(display,windows,CommandMenu, 15336 (XEvent *) NULL); 15337 break; 15338 } 15339 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15340 { 15341 /* 15342 Update graphic context and window colormap. 15343 */ 15344 for (i=0; i < (int) number_windows; i++) 15345 { 15346 if (magick_windows[i]->id == windows->icon.id) 15347 continue; 15348 context_values.background=pixel->background_color.pixel; 15349 context_values.foreground=pixel->foreground_color.pixel; 15350 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15351 context_mask,&context_values); 15352 (void) XChangeGC(display,magick_windows[i]->widget_context, 15353 context_mask,&context_values); 15354 context_values.background=pixel->foreground_color.pixel; 15355 context_values.foreground=pixel->background_color.pixel; 15356 context_values.plane_mask=context_values.background ^ 15357 context_values.foreground; 15358 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15359 (size_t) (context_mask | GCPlaneMask), 15360 &context_values); 15361 magick_windows[i]->attributes.background_pixel= 15362 pixel->background_color.pixel; 15363 magick_windows[i]->attributes.border_pixel= 15364 pixel->border_color.pixel; 15365 magick_windows[i]->attributes.colormap=map_info->colormap; 15366 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15367 (unsigned long) magick_windows[i]->mask, 15368 &magick_windows[i]->attributes); 15369 } 15370 if (windows->pan.mapped != MagickFalse) 15371 { 15372 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15373 windows->pan.pixmap); 15374 (void) XClearWindow(display,windows->pan.id); 15375 XDrawPanRectangle(display,windows); 15376 } 15377 if (windows->backdrop.id != (Window) NULL) 15378 (void) XInstallColormap(display,map_info->colormap); 15379 break; 15380 } 15381 if (*event.xclient.data.l == (long) windows->im_former_image) 15382 { 15383 *state|=FormerImageState | ExitState; 15384 break; 15385 } 15386 if (*event.xclient.data.l == (long) windows->im_next_image) 15387 { 15388 *state|=NextImageState | ExitState; 15389 break; 15390 } 15391 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15392 { 15393 *state|=RetainColorsState; 15394 break; 15395 } 15396 if (*event.xclient.data.l == (long) windows->im_exit) 15397 { 15398 *state|=ExitState; 15399 break; 15400 } 15401 break; 15402 } 15403 if (event.xclient.message_type == windows->dnd_protocols) 15404 { 15405 Atom 15406 selection, 15407 type; 15408 15409 int 15410 format, 15411 status; 15412 15413 unsigned char 15414 *data; 15415 15416 unsigned long 15417 after, 15418 length; 15419 15420 /* 15421 Display image named by the Drag-and-Drop selection. 15422 */ 15423 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15424 break; 15425 selection=XInternAtom(display,"DndSelection",MagickFalse); 15426 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15427 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15428 &length,&after,&data); 15429 if ((status != Success) || (length == 0)) 15430 break; 15431 if (*event.xclient.data.l == 2) 15432 { 15433 /* 15434 Offix DND. 15435 */ 15436 (void) CopyMagickString(resource_info->image_info->filename, 15437 (char *) data,MaxTextExtent); 15438 } 15439 else 15440 { 15441 /* 15442 XDND. 15443 */ 15444 if (strncmp((char *) data, "file:", 5) != 0) 15445 { 15446 (void) XFree((void *) data); 15447 break; 15448 } 15449 (void) CopyMagickString(resource_info->image_info->filename, 15450 ((char *) data)+5,MaxTextExtent); 15451 } 15452 nexus=ReadImage(resource_info->image_info, 15453 &display_image->exception); 15454 CatchException(&display_image->exception); 15455 if (nexus != (Image *) NULL) 15456 *state|=NextImageState | ExitState; 15457 (void) XFree((void *) data); 15458 break; 15459 } 15460 /* 15461 If client window delete message, exit. 15462 */ 15463 if (event.xclient.message_type != windows->wm_protocols) 15464 break; 15465 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15466 break; 15467 (void) XWithdrawWindow(display,event.xclient.window, 15468 visual_info->screen); 15469 if (event.xclient.window == windows->image.id) 15470 { 15471 *state|=ExitState; 15472 break; 15473 } 15474 if (event.xclient.window == windows->pan.id) 15475 { 15476 /* 15477 Restore original image size when pan window is deleted. 15478 */ 15479 windows->image.window_changes.width=windows->image.ximage->width; 15480 windows->image.window_changes.height=windows->image.ximage->height; 15481 (void) XConfigureImage(display,resource_info,windows, 15482 display_image,exception); 15483 } 15484 break; 15485 } 15486 case ConfigureNotify: 15487 { 15488 if (display_image->debug != MagickFalse) 15489 (void) LogMagickEvent(X11Event,GetMagickModule(), 15490 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15491 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15492 event.xconfigure.y,event.xconfigure.send_event); 15493 if (event.xconfigure.window == windows->image.id) 15494 { 15495 /* 15496 Image window has a new configuration. 15497 */ 15498 if (event.xconfigure.send_event != 0) 15499 { 15500 XWindowChanges 15501 window_changes; 15502 15503 /* 15504 Position the transient windows relative of the Image window. 15505 */ 15506 if (windows->command.geometry == (char *) NULL) 15507 if (windows->command.mapped == MagickFalse) 15508 { 15509 windows->command.x=event.xconfigure.x- 15510 windows->command.width-25; 15511 windows->command.y=event.xconfigure.y; 15512 XConstrainWindowPosition(display,&windows->command); 15513 window_changes.x=windows->command.x; 15514 window_changes.y=windows->command.y; 15515 (void) XReconfigureWMWindow(display,windows->command.id, 15516 windows->command.screen,(unsigned int) (CWX | CWY), 15517 &window_changes); 15518 } 15519 if (windows->widget.geometry == (char *) NULL) 15520 if (windows->widget.mapped == MagickFalse) 15521 { 15522 windows->widget.x=event.xconfigure.x+ 15523 event.xconfigure.width/10; 15524 windows->widget.y=event.xconfigure.y+ 15525 event.xconfigure.height/10; 15526 XConstrainWindowPosition(display,&windows->widget); 15527 window_changes.x=windows->widget.x; 15528 window_changes.y=windows->widget.y; 15529 (void) XReconfigureWMWindow(display,windows->widget.id, 15530 windows->widget.screen,(unsigned int) (CWX | CWY), 15531 &window_changes); 15532 } 15533 if (windows->magnify.geometry == (char *) NULL) 15534 if (windows->magnify.mapped == MagickFalse) 15535 { 15536 windows->magnify.x=event.xconfigure.x+ 15537 event.xconfigure.width+25; 15538 windows->magnify.y=event.xconfigure.y; 15539 XConstrainWindowPosition(display,&windows->magnify); 15540 window_changes.x=windows->magnify.x; 15541 window_changes.y=windows->magnify.y; 15542 (void) XReconfigureWMWindow(display,windows->magnify.id, 15543 windows->magnify.screen,(unsigned int) (CWX | CWY), 15544 &window_changes); 15545 } 15546 if (windows->pan.geometry == (char *) NULL) 15547 if (windows->pan.mapped == MagickFalse) 15548 { 15549 windows->pan.x=event.xconfigure.x+ 15550 event.xconfigure.width+25; 15551 windows->pan.y=event.xconfigure.y+ 15552 windows->magnify.height+50; 15553 XConstrainWindowPosition(display,&windows->pan); 15554 window_changes.x=windows->pan.x; 15555 window_changes.y=windows->pan.y; 15556 (void) XReconfigureWMWindow(display,windows->pan.id, 15557 windows->pan.screen,(unsigned int) (CWX | CWY), 15558 &window_changes); 15559 } 15560 } 15561 if ((event.xconfigure.width == (int) windows->image.width) && 15562 (event.xconfigure.height == (int) windows->image.height)) 15563 break; 15564 windows->image.width=(unsigned int) event.xconfigure.width; 15565 windows->image.height=(unsigned int) event.xconfigure.height; 15566 windows->image.x=0; 15567 windows->image.y=0; 15568 if (display_image->montage != (char *) NULL) 15569 { 15570 windows->image.x=vid_info.x; 15571 windows->image.y=vid_info.y; 15572 } 15573 if ((windows->image.mapped != MagickFalse) && 15574 (windows->image.stasis != MagickFalse)) 15575 { 15576 /* 15577 Update image window configuration. 15578 */ 15579 windows->image.window_changes.width=event.xconfigure.width; 15580 windows->image.window_changes.height=event.xconfigure.height; 15581 (void) XConfigureImage(display,resource_info,windows, 15582 display_image,exception); 15583 } 15584 /* 15585 Update pan window configuration. 15586 */ 15587 if ((event.xconfigure.width < windows->image.ximage->width) || 15588 (event.xconfigure.height < windows->image.ximage->height)) 15589 { 15590 (void) XMapRaised(display,windows->pan.id); 15591 XDrawPanRectangle(display,windows); 15592 } 15593 else 15594 if (windows->pan.mapped != MagickFalse) 15595 (void) XWithdrawWindow(display,windows->pan.id, 15596 windows->pan.screen); 15597 break; 15598 } 15599 if (event.xconfigure.window == windows->magnify.id) 15600 { 15601 unsigned int 15602 magnify; 15603 15604 /* 15605 Magnify window has a new configuration. 15606 */ 15607 windows->magnify.width=(unsigned int) event.xconfigure.width; 15608 windows->magnify.height=(unsigned int) event.xconfigure.height; 15609 if (windows->magnify.mapped == MagickFalse) 15610 break; 15611 magnify=1; 15612 while ((int) magnify <= event.xconfigure.width) 15613 magnify<<=1; 15614 while ((int) magnify <= event.xconfigure.height) 15615 magnify<<=1; 15616 magnify>>=1; 15617 if (((int) magnify != event.xconfigure.width) || 15618 ((int) magnify != event.xconfigure.height)) 15619 { 15620 window_changes.width=(int) magnify; 15621 window_changes.height=(int) magnify; 15622 (void) XReconfigureWMWindow(display,windows->magnify.id, 15623 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15624 &window_changes); 15625 break; 15626 } 15627 if ((windows->magnify.mapped != MagickFalse) && 15628 (windows->magnify.stasis != MagickFalse)) 15629 { 15630 status=XMakeImage(display,resource_info,&windows->magnify, 15631 display_image,windows->magnify.width,windows->magnify.height, 15632 exception); 15633 XMakeMagnifyImage(display,windows); 15634 } 15635 break; 15636 } 15637 if ((windows->magnify.mapped != MagickFalse) && 15638 (event.xconfigure.window == windows->pan.id)) 15639 { 15640 /* 15641 Pan icon window has a new configuration. 15642 */ 15643 if (event.xconfigure.send_event != 0) 15644 { 15645 windows->pan.x=event.xconfigure.x; 15646 windows->pan.y=event.xconfigure.y; 15647 } 15648 windows->pan.width=(unsigned int) event.xconfigure.width; 15649 windows->pan.height=(unsigned int) event.xconfigure.height; 15650 break; 15651 } 15652 if (event.xconfigure.window == windows->icon.id) 15653 { 15654 /* 15655 Icon window has a new configuration. 15656 */ 15657 windows->icon.width=(unsigned int) event.xconfigure.width; 15658 windows->icon.height=(unsigned int) event.xconfigure.height; 15659 break; 15660 } 15661 break; 15662 } 15663 case DestroyNotify: 15664 { 15665 /* 15666 Group leader has exited. 15667 */ 15668 if (display_image->debug != MagickFalse) 15669 (void) LogMagickEvent(X11Event,GetMagickModule(), 15670 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15671 if (event.xdestroywindow.window == windows->group_leader.id) 15672 { 15673 *state|=ExitState; 15674 break; 15675 } 15676 break; 15677 } 15678 case EnterNotify: 15679 { 15680 /* 15681 Selectively install colormap. 15682 */ 15683 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15684 if (event.xcrossing.mode != NotifyUngrab) 15685 XInstallColormap(display,map_info->colormap); 15686 break; 15687 } 15688 case Expose: 15689 { 15690 if (display_image->debug != MagickFalse) 15691 (void) LogMagickEvent(X11Event,GetMagickModule(), 15692 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15693 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15694 event.xexpose.y); 15695 /* 15696 Refresh windows that are now exposed. 15697 */ 15698 if ((event.xexpose.window == windows->image.id) && 15699 (windows->image.mapped != MagickFalse)) 15700 { 15701 XRefreshWindow(display,&windows->image,&event); 15702 delay=display_image->delay/MagickMax( 15703 display_image->ticks_per_second,1L); 15704 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15705 break; 15706 } 15707 if ((event.xexpose.window == windows->magnify.id) && 15708 (windows->magnify.mapped != MagickFalse)) 15709 { 15710 XMakeMagnifyImage(display,windows); 15711 break; 15712 } 15713 if (event.xexpose.window == windows->pan.id) 15714 { 15715 XDrawPanRectangle(display,windows); 15716 break; 15717 } 15718 if (event.xexpose.window == windows->icon.id) 15719 { 15720 XRefreshWindow(display,&windows->icon,&event); 15721 break; 15722 } 15723 break; 15724 } 15725 case KeyPress: 15726 { 15727 int 15728 length; 15729 15730 /* 15731 Respond to a user key press. 15732 */ 15733 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15734 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15735 *(command+length)='\0'; 15736 if (display_image->debug != MagickFalse) 15737 (void) LogMagickEvent(X11Event,GetMagickModule(), 15738 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15739 key_symbol,command); 15740 if (event.xkey.window == windows->image.id) 15741 { 15742 command_type=XImageWindowCommand(display,resource_info,windows, 15743 event.xkey.state,key_symbol,&display_image,exception); 15744 if (command_type != NullCommand) 15745 nexus=XMagickCommand(display,resource_info,windows,command_type, 15746 &display_image,exception); 15747 } 15748 if (event.xkey.window == windows->magnify.id) 15749 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15750 if (event.xkey.window == windows->pan.id) 15751 { 15752 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15753 (void) XWithdrawWindow(display,windows->pan.id, 15754 windows->pan.screen); 15755 else 15756 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15757 XTextViewWidget(display,resource_info,windows,MagickFalse, 15758 "Help Viewer - Image Pan",ImagePanHelp); 15759 else 15760 XTranslateImage(display,windows,*image,key_symbol); 15761 } 15762 delay=display_image->delay/MagickMax( 15763 display_image->ticks_per_second,1L); 15764 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15765 break; 15766 } 15767 case KeyRelease: 15768 { 15769 /* 15770 Respond to a user key release. 15771 */ 15772 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15773 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15774 if (display_image->debug != MagickFalse) 15775 (void) LogMagickEvent(X11Event,GetMagickModule(), 15776 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15777 break; 15778 } 15779 case LeaveNotify: 15780 { 15781 /* 15782 Selectively uninstall colormap. 15783 */ 15784 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15785 if (event.xcrossing.mode != NotifyUngrab) 15786 XUninstallColormap(display,map_info->colormap); 15787 break; 15788 } 15789 case MapNotify: 15790 { 15791 if (display_image->debug != MagickFalse) 15792 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15793 event.xmap.window); 15794 if (event.xmap.window == windows->backdrop.id) 15795 { 15796 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15797 CurrentTime); 15798 windows->backdrop.mapped=MagickTrue; 15799 break; 15800 } 15801 if (event.xmap.window == windows->image.id) 15802 { 15803 if (windows->backdrop.id != (Window) NULL) 15804 (void) XInstallColormap(display,map_info->colormap); 15805 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15806 { 15807 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15808 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15809 } 15810 if (((int) windows->image.width < windows->image.ximage->width) || 15811 ((int) windows->image.height < windows->image.ximage->height)) 15812 (void) XMapRaised(display,windows->pan.id); 15813 windows->image.mapped=MagickTrue; 15814 break; 15815 } 15816 if (event.xmap.window == windows->magnify.id) 15817 { 15818 XMakeMagnifyImage(display,windows); 15819 windows->magnify.mapped=MagickTrue; 15820 (void) XWithdrawWindow(display,windows->info.id, 15821 windows->info.screen); 15822 break; 15823 } 15824 if (event.xmap.window == windows->pan.id) 15825 { 15826 XMakePanImage(display,resource_info,windows,display_image, 15827 exception); 15828 windows->pan.mapped=MagickTrue; 15829 break; 15830 } 15831 if (event.xmap.window == windows->info.id) 15832 { 15833 windows->info.mapped=MagickTrue; 15834 break; 15835 } 15836 if (event.xmap.window == windows->icon.id) 15837 { 15838 MagickBooleanType 15839 taint; 15840 15841 /* 15842 Create an icon image. 15843 */ 15844 taint=display_image->taint; 15845 XMakeStandardColormap(display,icon_visual,icon_resources, 15846 display_image,icon_map,icon_pixel); 15847 (void) XMakeImage(display,icon_resources,&windows->icon, 15848 display_image,windows->icon.width,windows->icon.height, 15849 exception); 15850 display_image->taint=taint; 15851 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15852 windows->icon.pixmap); 15853 (void) XClearWindow(display,windows->icon.id); 15854 (void) XWithdrawWindow(display,windows->info.id, 15855 windows->info.screen); 15856 windows->icon.mapped=MagickTrue; 15857 break; 15858 } 15859 if (event.xmap.window == windows->command.id) 15860 { 15861 windows->command.mapped=MagickTrue; 15862 break; 15863 } 15864 if (event.xmap.window == windows->popup.id) 15865 { 15866 windows->popup.mapped=MagickTrue; 15867 break; 15868 } 15869 if (event.xmap.window == windows->widget.id) 15870 { 15871 windows->widget.mapped=MagickTrue; 15872 break; 15873 } 15874 break; 15875 } 15876 case MappingNotify: 15877 { 15878 (void) XRefreshKeyboardMapping(&event.xmapping); 15879 break; 15880 } 15881 case NoExpose: 15882 break; 15883 case PropertyNotify: 15884 { 15885 Atom 15886 type; 15887 15888 int 15889 format, 15890 status; 15891 15892 unsigned char 15893 *data; 15894 15895 unsigned long 15896 after, 15897 length; 15898 15899 if (display_image->debug != MagickFalse) 15900 (void) LogMagickEvent(X11Event,GetMagickModule(), 15901 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15902 event.xproperty.atom,event.xproperty.state); 15903 if (event.xproperty.atom != windows->im_remote_command) 15904 break; 15905 /* 15906 Display image named by the remote command protocol. 15907 */ 15908 status=XGetWindowProperty(display,event.xproperty.window, 15909 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15910 AnyPropertyType,&type,&format,&length,&after,&data); 15911 if ((status != Success) || (length == 0)) 15912 break; 15913 if (LocaleCompare((char *) data,"-quit") == 0) 15914 { 15915 XClientMessage(display,windows->image.id,windows->im_protocols, 15916 windows->im_exit,CurrentTime); 15917 (void) XFree((void *) data); 15918 break; 15919 } 15920 (void) CopyMagickString(resource_info->image_info->filename, 15921 (char *) data,MaxTextExtent); 15922 (void) XFree((void *) data); 15923 nexus=ReadImage(resource_info->image_info,&display_image->exception); 15924 CatchException(&display_image->exception); 15925 if (nexus != (Image *) NULL) 15926 *state|=NextImageState | ExitState; 15927 break; 15928 } 15929 case ReparentNotify: 15930 { 15931 if (display_image->debug != MagickFalse) 15932 (void) LogMagickEvent(X11Event,GetMagickModule(), 15933 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15934 event.xreparent.window); 15935 break; 15936 } 15937 case UnmapNotify: 15938 { 15939 if (display_image->debug != MagickFalse) 15940 (void) LogMagickEvent(X11Event,GetMagickModule(), 15941 "Unmap Notify: 0x%lx",event.xunmap.window); 15942 if (event.xunmap.window == windows->backdrop.id) 15943 { 15944 windows->backdrop.mapped=MagickFalse; 15945 break; 15946 } 15947 if (event.xunmap.window == windows->image.id) 15948 { 15949 windows->image.mapped=MagickFalse; 15950 break; 15951 } 15952 if (event.xunmap.window == windows->magnify.id) 15953 { 15954 windows->magnify.mapped=MagickFalse; 15955 break; 15956 } 15957 if (event.xunmap.window == windows->pan.id) 15958 { 15959 windows->pan.mapped=MagickFalse; 15960 break; 15961 } 15962 if (event.xunmap.window == windows->info.id) 15963 { 15964 windows->info.mapped=MagickFalse; 15965 break; 15966 } 15967 if (event.xunmap.window == windows->icon.id) 15968 { 15969 if (map_info->colormap == icon_map->colormap) 15970 XConfigureImageColormap(display,resource_info,windows, 15971 display_image); 15972 (void) XFreeStandardColormap(display,icon_visual,icon_map, 15973 icon_pixel); 15974 windows->icon.mapped=MagickFalse; 15975 break; 15976 } 15977 if (event.xunmap.window == windows->command.id) 15978 { 15979 windows->command.mapped=MagickFalse; 15980 break; 15981 } 15982 if (event.xunmap.window == windows->popup.id) 15983 { 15984 if (windows->backdrop.id != (Window) NULL) 15985 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15986 CurrentTime); 15987 windows->popup.mapped=MagickFalse; 15988 break; 15989 } 15990 if (event.xunmap.window == windows->widget.id) 15991 { 15992 if (windows->backdrop.id != (Window) NULL) 15993 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 15994 CurrentTime); 15995 windows->widget.mapped=MagickFalse; 15996 break; 15997 } 15998 break; 15999 } 16000 default: 16001 { 16002 if (display_image->debug != MagickFalse) 16003 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16004 event.type); 16005 break; 16006 } 16007 } 16008 } while (!(*state & ExitState)); 16009 if ((*state & ExitState) == 0) 16010 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16011 &display_image,exception); 16012 else 16013 if (resource_info->confirm_edit != MagickFalse) 16014 { 16015 /* 16016 Query user if image has changed. 16017 */ 16018 if ((resource_info->immutable == MagickFalse) && 16019 (display_image->taint != MagickFalse)) 16020 { 16021 int 16022 status; 16023 16024 status=XConfirmWidget(display,windows,"Your image changed.", 16025 "Do you want to save it"); 16026 if (status == 0) 16027 *state&=(~ExitState); 16028 else 16029 if (status > 0) 16030 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16031 &display_image,exception); 16032 } 16033 } 16034 if ((windows->visual_info->klass == GrayScale) || 16035 (windows->visual_info->klass == PseudoColor) || 16036 (windows->visual_info->klass == DirectColor)) 16037 { 16038 /* 16039 Withdraw pan and Magnify window. 16040 */ 16041 if (windows->info.mapped != MagickFalse) 16042 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16043 if (windows->magnify.mapped != MagickFalse) 16044 (void) XWithdrawWindow(display,windows->magnify.id, 16045 windows->magnify.screen); 16046 if (windows->command.mapped != MagickFalse) 16047 (void) XWithdrawWindow(display,windows->command.id, 16048 windows->command.screen); 16049 } 16050 if (windows->pan.mapped != MagickFalse) 16051 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16052 if (resource_info->backdrop == MagickFalse) 16053 if (windows->backdrop.mapped) 16054 { 16055 (void) XWithdrawWindow(display,windows->backdrop.id, 16056 windows->backdrop.screen); 16057 (void) XDestroyWindow(display,windows->backdrop.id); 16058 windows->backdrop.id=(Window) NULL; 16059 (void) XWithdrawWindow(display,windows->image.id, 16060 windows->image.screen); 16061 (void) XDestroyWindow(display,windows->image.id); 16062 windows->image.id=(Window) NULL; 16063 } 16064 XSetCursorState(display,windows,MagickTrue); 16065 XCheckRefreshWindows(display,windows); 16066 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16067 *state&=(~ExitState); 16068 if (*state & ExitState) 16069 { 16070 /* 16071 Free Standard Colormap. 16072 */ 16073 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16074 if (resource_info->map_type == (char *) NULL) 16075 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16076 /* 16077 Free X resources. 16078 */ 16079 if (resource_info->copy_image != (Image *) NULL) 16080 { 16081 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16082 resource_info->copy_image=NewImageList(); 16083 } 16084 DestroyXResources(); 16085 } 16086 (void) XSync(display,MagickFalse); 16087 /* 16088 Restore our progress monitor and warning handlers. 16089 */ 16090 (void) SetErrorHandler(warning_handler); 16091 (void) SetWarningHandler(warning_handler); 16092 /* 16093 Change to home directory. 16094 */ 16095 directory=getcwd(working_directory,MaxTextExtent); 16096 (void) directory; 16097 { 16098 int 16099 status; 16100 16101 status=chdir(resource_info->home_directory); 16102 if (status == -1) 16103 (void) ThrowMagickException(&display_image->exception,GetMagickModule(), 16104 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 16105 } 16106 *image=display_image; 16107 return(nexus); 16108} 16109#else 16110 16111/* 16112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16113% % 16114% % 16115% % 16116+ D i s p l a y I m a g e s % 16117% % 16118% % 16119% % 16120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16121% 16122% DisplayImages() displays an image sequence to any X window screen. It 16123% returns a value other than 0 if successful. Check the exception member 16124% of image to determine the reason for any failure. 16125% 16126% The format of the DisplayImages method is: 16127% 16128% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16129% Image *images,ExceptionInfo *exception) 16130% 16131% A description of each parameter follows: 16132% 16133% o image_info: the image info. 16134% 16135% o image: the image. 16136% 16137% o exception: return any errors or warnings in this structure. 16138% 16139*/ 16140MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16141 Image *image,ExceptionInfo *exception) 16142{ 16143 assert(image_info != (const ImageInfo *) NULL); 16144 assert(image_info->signature == MagickSignature); 16145 assert(image != (Image *) NULL); 16146 assert(image->signature == MagickSignature); 16147 if (image->debug != MagickFalse) 16148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16149 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16150 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16151 return(MagickFalse); 16152} 16153 16154/* 16155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16156% % 16157% % 16158% % 16159+ R e m o t e D i s p l a y C o m m a n d % 16160% % 16161% % 16162% % 16163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16164% 16165% RemoteDisplayCommand() encourages a remote display program to display the 16166% specified image filename. 16167% 16168% The format of the RemoteDisplayCommand method is: 16169% 16170% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16171% const char *window,const char *filename,ExceptionInfo *exception) 16172% 16173% A description of each parameter follows: 16174% 16175% o image_info: the image info. 16176% 16177% o window: Specifies the name or id of an X window. 16178% 16179% o filename: the name of the image filename to display. 16180% 16181% o exception: return any errors or warnings in this structure. 16182% 16183*/ 16184MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16185 const char *window,const char *filename,ExceptionInfo *exception) 16186{ 16187 assert(image_info != (const ImageInfo *) NULL); 16188 assert(image_info->signature == MagickSignature); 16189 assert(filename != (char *) NULL); 16190 (void) window; 16191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16192 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16193 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16194 return(MagickFalse); 16195} 16196#endif 16197